1212#include <structmember.h>
1313
1414#ifdef HAVE_SYS_DEVPOLL_H
15- #include <sys/resource.h>
16- #include <sys/devpoll.h>
17- #include <sys/types.h>
18- #include <sys/stat.h>
19- #include <fcntl.h>
15+ # include <sys/resource.h>
16+ # include <sys/devpoll.h>
17+ # include <sys/types.h>
18+ # include <sys/stat.h>
19+ # include <fcntl.h>
20+ #endif
21+ #ifdef __APPLE__
22+ # include <sys/utsname.h> /* select_have_broken_poll() */
2023#endif
2124
2225#ifdef __APPLE__
@@ -1182,10 +1185,27 @@ select_devpoll(PyObject *self, PyObject *unused)
11821185 */
11831186static int select_have_broken_poll (void )
11841187{
1185- int poll_test ;
11861188 int filedes [2 ];
1187-
1189+ struct utsname u ;
11881190 struct pollfd poll_struct = { 0 , POLLIN |POLLPRI |POLLOUT , 0 };
1191+ int res ;
1192+ const char * release ;
1193+
1194+ res = uname (& u );
1195+ if (res < 0 ) {
1196+ /* unlikely uname() failure: disable poll() */
1197+ return 1 ;
1198+ }
1199+
1200+ release = u .release ;
1201+ /* bpo-28087: macOS 16.0.x-16.5.x has a broken poll().
1202+ * poll() with no file descriptors registered returns immediately,
1203+ * regardless of the timeout. */
1204+ if (strncmp (release , "16." , 3 ) == 0
1205+ && '0' <= release [3 ] && release [3 ] <= '5'
1206+ && release [4 ] == '.' ) {
1207+ return 1 ;
1208+ }
11891209
11901210 /* Create a file descriptor to make invalid */
11911211 if (pipe (filedes ) < 0 ) {
@@ -1194,10 +1214,12 @@ static int select_have_broken_poll(void)
11941214 poll_struct .fd = filedes [0 ];
11951215 close (filedes [0 ]);
11961216 close (filedes [1 ]);
1197- poll_test = poll (& poll_struct , 1 , 0 );
1198- if (poll_test < 0 ) {
1217+
1218+ res = poll (& poll_struct , 1 , 0 );
1219+ if (res < 0 ) {
11991220 return 1 ;
1200- } else if (poll_test == 0 && poll_struct .revents != POLLNVAL ) {
1221+ }
1222+ else if (res == 0 && poll_struct .revents != POLLNVAL ) {
12011223 return 1 ;
12021224 }
12031225 return 0 ;
0 commit comments