@@ -11882,9 +11882,12 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable)
1188211882 /* dup3() is available on Linux 2.6.27+ and glibc 2.9 and macOS 27.0;
1188311883 * it needs runtime detection for the case of running on older kernels.
1188411884 * Values: -1: unknown; 0: doesn't work; 1: works
11885+ * For thread safety, use a process-global with one read & one store,
11886+ * both relaxed. (It's fine if two threads race and do the detection
11887+ * simultaneously; they should get the same result.)
1188511888 */
11886- static int dup3_works = -1;
11887- (void) dup3_works ; // unused on some platforms
11889+ static int dup3_works_atomic = -1;
11890+ (void) dup3_works_atomic ; // unused on some platforms
1188811891
1188911892 /* dup2() can fail with EINTR if the target FD is already open, because it
1189011893 * then has to be closed. See os_close_impl() for why we don't handle EINTR
@@ -11923,6 +11926,7 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable)
1192311926#else
1192411927
1192511928#ifdef HAVE_DUP3
11929+ int dup3_works = FT_ATOMIC_LOAD_INT_RELAXED(dup3_works_atomic);
1192611930 if (!inheritable && dup3_works != 0) {
1192711931 if (HAVE_DUP3_RUNTIME) {
1192811932 Py_BEGIN_ALLOW_THREADS
@@ -11931,6 +11935,7 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable)
1193111935 if (res < 0) {
1193211936 if (dup3_works == -1) {
1193311937 dup3_works = (errno != ENOSYS);
11938+ FT_ATOMIC_STORE_INT_RELAXED(dup3_works_atomic, dup3_works);
1193411939 }
1193511940 if (dup3_works) {
1193611941 posix_error();
@@ -11940,6 +11945,7 @@ os_dup2_impl(PyObject *module, int fd, int fd2, int inheritable)
1194011945 }
1194111946 else {
1194211947 dup3_works = 0;
11948+ FT_ATOMIC_STORE_INT_RELAXED(dup3_works_atomic, dup3_works);
1194311949 }
1194411950 }
1194511951
@@ -12784,11 +12790,10 @@ os_pipe_impl(PyObject *module)
1278412790 int res = -1;
1278512791
1278612792 /* pipe2() is available on some newer linux/glibc & macOS;
12787- * it needs runtime detection for the case of running on older kernels.
12788- * Values: -1: unknown; 0: doesn't work; 1: works
12793+ * use the same runtime detection as for dup3 above.
1278912794 */
12790- static int pipe2_works = -1;
12791- (void) pipe2_works ; // unused on some platforms
12795+ static int pipe2_works_atomic = -1;
12796+ (void) pipe2_works_atomic ; // unused on some platforms
1279212797#endif
1279312798
1279412799#ifdef MS_WINDOWS
@@ -12814,6 +12819,7 @@ os_pipe_impl(PyObject *module)
1281412819#else
1281512820
1281612821#ifdef HAVE_PIPE2
12822+ int pipe2_works = FT_ATOMIC_LOAD_INT_RELAXED(pipe2_works_atomic);
1281712823 if (pipe2_works != 0) {
1281812824 if (HAVE_PIPE2_RUNTIME) {
1281912825 Py_BEGIN_ALLOW_THREADS
@@ -12827,10 +12833,12 @@ os_pipe_impl(PyObject *module)
1282712833 // pipe2 is present but this call failed
1282812834 pipe2_works = 1;
1282912835 }
12836+ FT_ATOMIC_STORE_INT_RELAXED(pipe2_works_atomic, pipe2_works);
1283012837 }
1283112838 }
1283212839 else {
1283312840 pipe2_works = 0;
12841+ FT_ATOMIC_STORE_INT_RELAXED(pipe2_works_atomic, pipe2_works);
1283412842 }
1283512843 }
1283612844
0 commit comments