[newlib-cygwin/main] Cygwin: add _Fork() system call per POSIX.1-2024
Corinna Vinschen via Cygwin-cvs <[email protected]> Tue, 31 Mar 2026 15:12:36 +0000 (GMT)
| Newsgroups | gmane.os.cygwin.cvs |
|---|---|
| Message-ID | <[email protected]> |
https://sourceware.org/git/gitweb.cgi?p=3Dnewlib-cygwin.git;h=3D5f515cf3d6e= 338e062ba25e93abccd5b6eb1d596 commit 5f515cf3d6e338e062ba25e93abccd5b6eb1d596 Author: Corinna Vinschen <[email protected]> AuthorDate: Mon Mar 30 16:24:07 2026 +0200 Commit: Corinna Vinschen <[email protected]> CommitDate: Tue Mar 31 12:12:08 2026 +0200 Cygwin: add _Fork() system call per POSIX.1-2024 =20 The _Fork() function shall be equivalent to fork(), except that fork handlers established by means of the pthread_atfork() function shall not be called and _Fork() shall be async-signal-safe. Our fork() already is async-signal-safe, so just make sure the pthread_atfork() handlers are not called. =20 Signed-off-by: Corinna Vinschen <[email protected]> Diff: --- newlib/libc/include/sys/unistd.h | 3 +++ winsup/cygwin/cygwin.din | 1 + winsup/cygwin/fork.cc | 40 ++++++++++++++++++++++++++----= ---- winsup/cygwin/include/cygwin/version.h | 3 ++- winsup/cygwin/local_includes/sigproc.h | 13 +++++++++-- winsup/cygwin/release/3.7.0 | 1 + 6 files changed, 49 insertions(+), 12 deletions(-) diff --git a/newlib/libc/include/sys/unistd.h b/newlib/libc/include/sys/uni= std.h index 4cf9f0636276..d1c9126e53ab 100644 --- a/newlib/libc/include/sys/unistd.h +++ b/newlib/libc/include/sys/unistd.h @@ -96,6 +96,9 @@ int fchownat (int __dirfd, const char *__path, uid_t __ow= ner, gid_t __group, int int fexecve (int __fd, char * const __argv[], char * const __envp[]); #endif pid_t fork (void); +#if __POSIX_VISIBLE >=3D 202405 +pid_t _Fork (void); +#endif long fpathconf (int __fd, int __name); int fsync (int __fd); #if __POSIX_VISIBLE >=3D 199309 diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din index 7709a0653eb9..76477bb4aec2 100644 --- a/winsup/cygwin/cygwin.din +++ b/winsup/cygwin/cygwin.din @@ -147,6 +147,7 @@ __xpg_strerror_r SIGFE _dll_crt0 NOSIGFE _Exit SIGFE _exit SIGFE +_Fork SIGFE _feinitialise NOSIGFE _fscanf_r SIGFE _get_osfhandle SIGFE diff --git a/winsup/cygwin/fork.cc b/winsup/cygwin/fork.cc index 48e8b7557d00..722d21bdb023 100644 --- a/winsup/cygwin/fork.cc +++ b/winsup/cygwin/fork.cc @@ -31,7 +31,7 @@ details. */ /* FIXME: Once things stabilize, bump up to a few minutes. */ #define FORK_WAIT_TIMEOUT (300 * 1000) /* 300 seconds */ =20 -static int dofork (void **proc, bool *with_forkables); +static int dofork (void **proc, bool do_atfork_handlers, bool *with_forkab= les); class frok { frok (bool *forkables) @@ -47,7 +47,7 @@ class frok int parent (volatile char * volatile here); int child (volatile char * volatile here); bool error (const char *fmt, ...); - friend int dofork (void **proc, bool *with_forkables); + friend int dofork (void **, bool, bool *); }; =20 static void @@ -201,7 +201,6 @@ frok::child (volatile char * volatile here) CloseHandle (hParent); hParent =3D NULL; cygwin_finished_initializing =3D true; - pthread::atforkchild (); return 0; } =20 @@ -609,15 +608,33 @@ extern "C" int fork () { bool with_forkables =3D false; /* do not force hardlinks on first try */ - int res =3D dofork (NULL, &with_forkables); + int res =3D dofork (NULL, false, &with_forkables); if (res >=3D 0) return res; if (with_forkables) return res; /* no need for second try when already enabled */ with_forkables =3D true; /* enable hardlinks for second try */ - return dofork (NULL, &with_forkables); + return dofork (NULL, false, &with_forkables); } =20 +/* POSIX.1-2024: + + The _Fork() function shall be equivalent to fork(), except that fork + handlers established by means of the pthread_atfork() function shall + not be called and _Fork() shall be async-signal-safe. Our fork() + already is async-signal-safe. */ +extern "C" int +_Fork () +{ + bool with_forkables =3D false; /* do not force hardlinks on first try */ + int res =3D dofork (NULL, true, &with_forkables); + if (res >=3D 0) + return res; + if (with_forkables) + return res; /* no need for second try when already enabled */ + with_forkables =3D true; /* enable hardlinks for second try */ + return dofork (NULL, true, &with_forkables); +} =20 /* __posix_spawn_fork is called from newlib's posix_spawn implementation. The original code in newlib has been taken from FreeBSD, and the core @@ -628,17 +645,17 @@ extern "C" int __posix_spawn_fork (void **proc) { bool with_forkables =3D false; /* do not force hardlinks on first try */ - int res =3D dofork (proc, &with_forkables); + int res =3D dofork (proc, false, &with_forkables); if (res >=3D 0) return res; if (with_forkables) return res; /* no need for second try when already enabled */ with_forkables =3D true; /* enable hardlinks for second try */ - return dofork (proc, &with_forkables); + return dofork (proc, false, &with_forkables); } =20 static int -dofork (void **proc, bool *with_forkables) +dofork (void **proc, bool do_atfork_handlers, bool *with_forkables) { frok grouped (with_forkables); =20 @@ -659,7 +676,7 @@ dofork (void **proc, bool *with_forkables) } =20 { - hold_everything held_everything (ischild); + hold_everything held_everything (ischild, do_atfork_handlers); /* This tmp_pathbuf constructor is required here because the below set= jmp magic will otherwise not restore the original buffer count values in the thread-local storage. A process forking too deeply will run in= to @@ -695,6 +712,11 @@ dofork (void **proc, bool *with_forkables) else { res =3D grouped.child (stackp); + /* So far pthread::atforkchild() was called as last function + from inside frok::child(). Move the call here, so we don't have + to propagate the do_atfork_handlers variable to frok::child(). */ + if (!do_atfork_handlers) + pthread::atforkchild (); __in_forkee =3D FORKED; ischild =3D true; /* might have been reset by fork mem copy */ } diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include= /cygwin/version.h index ef552ffcba9c..695477bec265 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -500,12 +500,13 @@ details. */ acl_is_trivial_np, acl_set_fd_np, acl_set_link_np, acl_strip_np. 359: Export wrappers for C++14 and C++17 new and delete overloads. 360: Add RLIMIT_NPROC. + 361: Export _Fork. =20 Note that we forgot to bump the api for ualarm, strtoll, strtoull, sigaltstack, sethostname. */ =20 #define CYGWIN_VERSION_API_MAJOR 0 -#define CYGWIN_VERSION_API_MINOR 360 +#define CYGWIN_VERSION_API_MINOR 361 =20 /* There is also a compatibity version number associated with the shared m= emory regions. It is incremented when incompatible changes are made to the s= hared diff --git a/winsup/cygwin/local_includes/sigproc.h b/winsup/cygwin/local_i= ncludes/sigproc.h index ce7263338f0a..92cda94dcbb8 100644 --- a/winsup/cygwin/local_includes/sigproc.h +++ b/winsup/cygwin/local_includes/sigproc.h @@ -131,7 +131,8 @@ class lock_pthread { bool bother; public: - lock_pthread (): bother (1) + lock_pthread (): bother (1) {} + void prepare () { pthread::atforkprepare (); } @@ -165,7 +166,15 @@ class hold_everything lock_process process; =20 public: - hold_everything (bool& x): ischild (x) {} + hold_everything (bool& x, bool do_atfork_handlers): ischild (x) + { + /* POSIX.1-2024: _Fork() does not call any handler established + by pthread_atfork(). */ + if (do_atfork_handlers) + pthread.dont_bother (); + else + pthread.prepare (); + } operator int () const {return signals;} =20 ~hold_everything() diff --git a/winsup/cygwin/release/3.7.0 b/winsup/cygwin/release/3.7.0 index 4736fd17c3f4..d5b63b0586a9 100644 --- a/winsup/cygwin/release/3.7.0 +++ b/winsup/cygwin/release/3.7.0 @@ -11,3 +11,4 @@ What's new: - Improved support for soft and hard limits in setrlimit(2), support RLIMIT_NPROC. =20 +- New API: _Fork.