Skip to content

Various missing constants (and some functions) #1325

Open

Description

@KaiErikNiermann

hi again, I have some more super fun things to report

as a short preamble, fixing the missing constants seems to be mostly just a continuation of the work in #193 also i apologize if this should really be multiple issues, I did it all in one bc I thought it would've felt needlessly spammy since the majority of the work here is more or less the same thing even if concerns different upstream files. also same as before I'm just reporting this here bc the most immediate issues is (aside from the generally missing RDS_* macros) for y'all. I also wrote some patches just to examine ig if it rly is just continuing the existing work and it unsurprisingly does seem to be, the same nuances apply for avoiding header clashes but aside from that seems to be all the same thing more or less.

The tldr is in terms of missing constants is as follows

  • #ifdef const: exported under #ifdef NAME, so the build's libc headers must define the name.
  • #ifdef group (X): exported without its own guard, inside a block guarded by X, so it is missing because X is.
  • glibc include: the header CPython takes it from only exists in newer glibc, so the include itself is skipped.
  • #ifdef const (argument): an argument that raises NotImplementedError unless its C macro is defined.
  • configure link test: an argument that needs a glibc wrapper function, detected by linking at configure time.

Process and timers (os)

Constant glibc Why missing Notes
POSIX_SPAWN_SETSID 2.26 #ifdef const (argument) Not exported. os.posix_spawn(setsid=True) raises NotImplementedError (posixmodule.c:7658-7677), as documented in os.rst:5436-5439. With the macro defined, a runtime glibc older than 2.26 gives OSError(EINVAL) instead.
PIDFD_NONBLOCK 2.36 glibc include Taken from <sys/pidfd.h> (HAVE_SYS_PIDFD_H, posixmodule.c:64-66), then #ifdef at posixmodule.c:18470. #127583 / #127593 fixed it for glibc 2.36+ only; RHEL 9 and Ubuntu 22.04 builds still lack it. Docs promise "Linux >= 5.10". Value is O_NONBLOCK.
TFD_TIMER_CANCEL_ON_SET 2.26 #ifdef const posixmodule.c:18438. <sys/timerfd.h> itself is old (glibc 2.8); only the constant is new.

Vectored I/O flags (os.preadv / os.pwritev)

Constant glibc Why missing Notes
flags= argument 2.26 configure link test HAVE_PREADV2 / HAVE_PWRITEV2 link preadv2()/pwritev2(); without them any non-zero flags raises NotImplementedError (posixmodule.c:12418-12423, 13124-13129). Docs promise "Linux >= 4.6". The syscalls need no glibc support, as for copy_file_range in #155520.
RWF_DSYNC 2.26 #ifdef const posixmodule.c:18516. Docs promise "Linux >= 4.7".
RWF_HIPRI 2.26 #ifdef const #13980 made test_posix skip when the constant exists but preadv2 does not; that skip is why CI never saw the missing flags.
RWF_SYNC 2.26 #ifdef const test_pwritev_flags is gated on it but has never run.
RWF_NOWAIT 2.26 #ifdef const
RWF_APPEND 2.28 #ifdef const Added after the abandoned #13735.
RWF_ATOMIC 2.41 #ifdef const Missing from any build on glibc < 2.41 (Ubuntu 24.04, Debian 12), not only pbs.

Later flags (#139090 RWF_DONTCACHE, #153856 RWF_NOSIGNAL) will follow the same pattern: posixmodule does not include <linux/fs.h>, so they only appear once glibc's headers have them.

Clocks, polling and memory (time, select, mmap)

Constant glibc Why missing Notes
CLOCK_TAI 2.21 #ifdef const timemodule.c:2134. Added in #19096. CentOS 7's backported "2.17" has it.
EPOLLEXCLUSIVE 2.24 #ifdef const selectmodule.c:2774. #89114 (open) asks for it in selectors.
MADV_FREE 2.24 #ifdef const mmapmodule.c:2394. <linux/mman.h> can be included alongside the libc headers.

File locks and descriptors (fcntl)

Constant glibc Why missing Notes
F_OFD_GETLK 2.20 #ifdef const fcntlmodule.c:600-608. Docs: "On Linux(>=3.15) ... exposes F_OFD_GETLK". hasattr checks for it fall back to process-associated locks. CentOS 7's "2.17" has it.
F_OFD_SETLK 2.20 #ifdef const As F_OFD_GETLK. The integer value works on a pbs build (repro).
F_OFD_SETLKW 2.20 #ifdef const As F_OFD_GETLK.
F_DUPFD_QUERY 2.41 #ifdef const fcntlmodule.c:656. Missing from any build on glibc < 2.41, not only pbs.

File sealing (fcntl)

Constant glibc Why missing Notes
F_ADD_SEALS 2.27 #ifdef const fcntlmodule.c:817-828 guards the whole group. Sealing is for memfd_create(), which pbs does provide (through its patch), so the function is there and its constants are not.
F_GET_SEALS 2.27 #ifdef group (F_ADD_SEALS)
F_SEAL_SEAL 2.27 #ifdef group (F_ADD_SEALS)
F_SEAL_SHRINK 2.27 #ifdef group (F_ADD_SEALS)
F_SEAL_GROW 2.27 #ifdef group (F_ADD_SEALS)
F_SEAL_WRITE 2.27 #ifdef group (F_ADD_SEALS)
F_SEAL_FUTURE_WRITE 2.30 #ifdef const, inside #ifdef group (F_ADD_SEALS) fcntlmodule.c:825. Added in #114061.

Write-life hints (fcntl)

Constant glibc Why missing Notes
F_GET_RW_HINT 2.27 #ifdef const fcntlmodule.c:693-708 guards the whole group.
F_SET_RW_HINT 2.27 #ifdef group (F_GET_RW_HINT)
F_GET_FILE_RW_HINT 2.27 #ifdef group (F_GET_RW_HINT) Still in the headers, but the kernel rejects it (EINVAL on 7.2.3).
F_SET_FILE_RW_HINT 2.27 #ifdef group (F_GET_RW_HINT) As F_GET_FILE_RW_HINT.
RWH_WRITE_LIFE_NOT_SET 2.32 #ifdef group (F_GET_RW_HINT) glibc 2.27-2.31 only have the kernel's misspelling RWF_WRITE_LIFE_NOT_SET, which CPython maps (fcntlmodule.c:699-701), so in practice it is exported from 2.27.
RWH_WRITE_LIFE_NONE 2.27 #ifdef group (F_GET_RW_HINT)
RWH_WRITE_LIFE_SHORT 2.27 #ifdef group (F_GET_RW_HINT)
RWH_WRITE_LIFE_MEDIUM 2.27 #ifdef group (F_GET_RW_HINT)
RWH_WRITE_LIFE_LONG 2.27 #ifdef group (F_GET_RW_HINT)
RWH_WRITE_LIFE_EXTREME 2.27 #ifdef group (F_GET_RW_HINT)

TCP options (socket)

All are guarded one by one in socketmodule.c:9155-9193 and come from glibc's <netinet/tcp.h>; <linux/tcp.h> cannot be included next to it.

Constant glibc Why missing Notes
TCP_NOTSENT_LOWAT 2.23 #ifdef const The integer value works on a pbs build (repro). #19402 tried a hardcoded fallback for the same gap in macOS builds; closed without review.
TCP_CC_INFO 2.23 #ifdef const
TCP_SAVE_SYN 2.23 #ifdef const
TCP_SAVED_SYN 2.23 #ifdef const
TCP_REPAIR_WINDOW 2.25 #ifdef const
TCP_FASTOPEN_CONNECT 2.26 #ifdef const
TCP_ULP 2.27 #ifdef const
TCP_MD5SIG_EXT 2.27 #ifdef const
TCP_FASTOPEN_KEY 2.28 #ifdef const
TCP_FASTOPEN_NO_COOKIE 2.28 #ifdef const
TCP_ZEROCOPY_RECEIVE 2.29 #ifdef const
TCP_INQ 2.29 #ifdef const
TCP_TX_DELAY 2.31 #ifdef const

Protocols, address families and socket levels (socket)

Constant glibc Why missing Notes
IPPROTO_MPTCP 2.32 #ifdef const socketmodule.c:8820. Added in #24946. The integer value works on a pbs build (repro). <linux/in.h> can be included.
SOL_RDS 2.24 #ifdef const socketmodule.c:8678. <linux/rds.h> can be included.
AF_QIPCRTR 2.25 #ifdef const socketmodule.c:7896. Also needs <linux/qrtr.h>: without it socketmodule.h #undefs the name (socketmodule.h:114-121). Added in #3706.

Missing functions

preadv()/pwritev() refuse any non-zero flags #ifndef HAVE_PREADV2 / HAVE_PWRITEV2 (posixmodule.c:12418-12423, 13124-13129) through argument_unavailable_error(). HAVE_PREADV2 is configure's link test for the glibc 2.26 wrapper, which a 2.19 sysroot fails. Here the existing syscall fallback strat should work. i.e. just

#if defined(HAVE_PREADV2) || (defined(__linux__) && defined(__NR_preadv2))
#  define _Py_HAVE_PREADV2
#endif
#if defined(HAVE_PWRITEV2) || (defined(__linux__) && defined(__NR_pwritev2))
#  define _Py_HAVE_PWRITEV2
#endif
#ifdef __linux__
// Mirroring `LO_HI_LONG(val)` from (sysdeps/unix/sysv/linux/sysdep.h:93-95)
#  define _Py_LO_HI_LONG(off) (long)(off), (long)((uint64_t)(off) >> 32)
#endif

and then at the HAVE_{PREADV2/PWRITEV2} sites the approaches reduces to just

#ifndef _Py_HAVE_*V2
   // arg unavail error for nonzero flags 
#else
#ifdef _Py_HAVE_*V2
    // syscall avail on non-zero flags, yippeee!
#endif

The usual point applies that these changes mean for older host libc's or kernels OSError's would be raised with these fixes applied.

Related upstream issues/notes

  • test_pwritev_flags has never run: it is gated on hasattr(posix, 'os.RWF_SYNC'), always False since bpo-31368 (2018), bc it should be 'RWF_SYNC' and its expected data is wrong (b'xxtest1tt2' instead of b'xxtest1tt2t3' validated against just calling it directly).
  • I think it would make sense to probably add tests to CPython to assert that these macros are actually present i.e. the fallbacks correctly trigger when building against lacking libc, unsure if there is any prior instance of this kind of testing but I assume it might be nice even if it is basically just testing like basic preprocessor semantics. One example that motivates it would be the addition of PIDFD_NONBLOCK, was added in 2022 but nothing CPython included actually defined it so it was always just gone untill 2 years later the actual header file was added to make it work, I would assume had this been given like a presence check it would've raised the error.
  • I was curious if the PIDFD_NONBLOCK defect ,i.e. the missing header for macro defs, appeared anywhere else and I found that the full RDS_* group here which comes from rds.h exhibits the same issue i.e. its missing rds.h, there's one related open issue based on what I can tell virtually nobody uses these constants hence why this has gone essentially unreported since they were added in 2011; turns out CPython does a namespace pollution lint test this might complicate adding the header, (could use __has_include (C23, alrdy used in some places) maybe?), but again low prio. There is also MADV_SOFT_OFFLINE defined in <asm-generic/mman-common.h> at mmapmodule.c:2379-2381 but header is missing.

Activity

  1. zanieb commented on Oct 27, 2026

    @zanieb
    Member

    Thanks for the comprehensive issue!

  2. self-assigned this
    on Oct 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions