Finding #4
This code didn't build, it could probably be removed.
Philippe
===
Fix: fix the parenthesis; limit the timeout to INT_MAX milliseconds as
the poll() version does; add descriptors through a new selectFd(),
which refuses (and reports once) those outside 0 to FD_SETSIZE-1 and
keeps track of the highest one; pass inputFd + 1 in +awakenedBefore:;
fix a format string (NSInteger printed with %d).
---
diff --git a/Source/unix/GSRunLoopCtxt.m b/Source/unix/GSRunLoopCtxt.m
index 3b4496410..d9d572eb1 100644
--- a/Source/unix/GSRunLoopCtxt.m
+++ b/Source/unix/GSRunLoopCtxt.m
@@ -723,6 +723,35 @@ static void setPollfd(int fd, int event, GSRunLoopCtxtUnix
*ctxt)
#else
+/* Add fd to the set and update the highest descriptor seen. A
+ * descriptor outside 0 to FD_SETSIZE-1 cannot be watched by select():
+ * FD_SET() would write outside the set, so it is refused (and reported
+ * once).
+ */
+static BOOL
+selectFd(int fd, fd_set *set, int *fdEnd)
+{
+ if (fd < 0 || fd >= FD_SETSIZE)
+ {
+ static BOOL warned = NO;
+
+ if (NO == warned && fd >= 0)
+ {
+ warned = YES;
+ NSLog(@"Run loop cannot watch descriptor %d with select()"
+ @" (FD_SETSIZE is %d): ignoring it and any others.",
+ fd, (int)FD_SETSIZE);
+ }
+ return NO;
+ }
+ FD_SET(fd, set);
+ if (fd > *fdEnd)
+ {
+ *fdEnd = fd;
+ }
+ return YES;
+}
+
- (BOOL) pollUntil: (int64_t)microseconds within: (NSArray*)contexts
{
GSRunLoopThreadInfo *threadInfo = loop->threadInfo;
@@ -735,7 +764,6 @@ static void setPollfd(int fd, int event, GSRunLoopCtxtUnix
*ctxt)
fd_set read_fds; // Mask for read-ready fds.
fd_set exception_fds; // Mask for exception fds.
fd_set write_fds; // Mask for write-ready fds.
- int fd;
int fdEnd = -1;
unsigned count;
unsigned i;
@@ -780,18 +808,12 @@ static void setPollfd(int fd, int event,
GSRunLoopCtxtUnix *ctxt)
/* Watch for signals from other threads.
*/
- fd = threadInfo->inputFd;
- if (fd > fdEnd)
- fdEnd = fd;
- FD_SET (fd, &read_fds);
+ selectFd(threadInfo->inputFd, &read_fds, &fdEnd);
#if GS_USE_LIBDISPATCH_RUNLOOP
if (loop->isMainThread && loop->dispatchHandle != NULL
&& (loop->commonModeMask & (UINT64_C(1) << modeIndex)))
{
- fd = (int)(intptr_t)loop->dispatchHandle;
- if (fd > fdEnd)
- fdEnd = fd;
- FD_SET (fd, &read_fds);
+ selectFd((int)(intptr_t)loop->dispatchHandle, &read_fds, &fdEnd);
}
#endif
@@ -836,26 +858,26 @@ static void setPollfd(int fd, int event,
GSRunLoopCtxtUnix *ctxt)
{
case ET_EDESC:
fd = (int)(intptr_t)info->data;
- if (fd > fdEnd)
- fdEnd = fd;
- FD_SET (fd, &exception_fds);
- NSMapInsert(_efdMap, (void*)(intptr_t)fd, info);
+ if (selectFd(fd, &exception_fds, &fdEnd))
+ {
+ NSMapInsert(_efdMap, (void*)(intptr_t)fd, info);
+ }
break;
case ET_RDESC:
fd = (int)(intptr_t)info->data;
- if (fd > fdEnd)
- fdEnd = fd;
- FD_SET (fd, &read_fds);
- NSMapInsert(_rfdMap, (void*)(intptr_t)fd, info);
+ if (selectFd(fd, &read_fds, &fdEnd))
+ {
+ NSMapInsert(_rfdMap, (void*)(intptr_t)fd, info);
+ }
break;
case ET_WDESC:
fd = (int)(intptr_t)info->data;
- if (fd > fdEnd)
- fdEnd = fd;
- FD_SET (fd, &write_fds);
- NSMapInsert(_wfdMap, (void*)(intptr_t)fd, info);
+ if (selectFd(fd, &write_fds, &fdEnd))
+ {
+ NSMapInsert(_wfdMap, (void*)(intptr_t)fd, info);
+ }
break;
case ET_RPORT:
@@ -875,15 +897,15 @@ static void setPollfd(int fd, int event,
GSRunLoopCtxtUnix *ctxt)
port_fd_array = malloc(sizeof(NSInteger)*port_fd_size);
[port getFds: port_fd_array count: &port_fd_count];
}
- NSDebugMLLog(@"NSRunLoop", @"listening to %d port sockets",
- port_fd_count);
+ NSDebugMLLog(@"NSRunLoop", @"listening to %ld port sockets",
+ (long)port_fd_count);
while (port_fd_count--)
{
fd = port_fd_array[port_fd_count];
- if (fd > fdEnd)
- fdEnd = fd;
- FD_SET (fd, &read_fds);
- NSMapInsert(_rfdMap, (void*)(intptr_t)fd, info);
+ if (selectFd(fd, &read_fds, &fdEnd))
+ {
+ NSMapInsert(_rfdMap, (void*)(intptr_t)fd, info);
+ }
}
if (port_fd_array != port_fd_buffer) free(port_fd_array);
}
@@ -901,7 +923,7 @@ static void setPollfd(int fd, int event, GSRunLoopCtxtUnix
*ctxt)
* we try an instantaneous select so that, if there is no input pending,
* we can service the queue.
*/
- if (GSPrivateCheckTasks() || GSPrivateNotifyMore(mode)) || immediate)
+ if (GSPrivateCheckTasks() || GSPrivateNotifyMore(mode) || immediate)
{
microseconds = 0;
}
@@ -913,6 +935,15 @@ static void setPollfd(int fd, int event, GSRunLoopCtxtUnix
*ctxt)
timeout.tv_sec = 0;
timeout.tv_usec = 0;
}
+ else if (microseconds / 1000000 >= INT_MAX / 1000)
+ {
+ /* Limit the wait as the poll() version does (to INT_MAX
+ * milliseconds): a larger value would overflow tv_sec, and
+ * select() fails with EINVAL for a negative timeout.
+ */
+ timeout.tv_sec = INT_MAX / 1000;
+ timeout.tv_usec = 0;
+ }
else
{
timeout.tv_sec = (int)(microseconds/1000000);
@@ -1173,7 +1204,10 @@ static void setPollfd(int fd, int event,
GSRunLoopCtxtUnix *ctxt)
timeout.tv_sec = milliseconds/1000;
timeout.tv_usec = (milliseconds - 1000 * timeout.tv_sec) * 1000;
FD_SET (threadInfo->inputFd, &read_fds);
- if (select (threadInfo->inputFd, &read_fds, &write_fds,
+ /* The first argument is the number of descriptors to look at,
+ * one more than the highest.
+ */
+ if (select (threadInfo->inputFd + 1, &read_fds, &write_fds,
&exception_fds, &timeout) > 0)
{
NSDebugMLLog(@"NSRunLoop", @"Fire perform on thread");
--
2.39.5