work around bug(?) in Mac OS X select()

Using select() to check whether a pipe is ready for writing seems to
fail on Mac OS X 10.8 and 10.9. See the PR for a small C program to
demonstrate. It's possible that the small program is broken and
there's no bug, but the program works on Linux and on Mac OS X 10.7
and 10.6.

Although poll() seems to work, switching completely to poll() is not a
good option on Mac OS X, since poll() does not support devices on that
platform.

The kqueue() facility seems to handle pipes and writing ok, so work
around the bug by enabling the use of kqueue() on pipes.

Closes PR 14596
This commit is contained in:
Matthew Flatt 2014-06-25 09:28:39 +01:00
parent 94a5c6e3fb
commit 5cbe6cfdcb
2 changed files with 17 additions and 6 deletions

View File

@ -6280,7 +6280,9 @@ static void filesystem_change_evt_need_wakeup (Scheme_Object *evt, void *fds)
}
#endif
int scheme_fd_regular_file(intptr_t fd, int dir_ok)
int scheme_fd_regular_file(intptr_t fd, int or_other)
/* or_other == 1 => directory
or_other == 2 => directory or fifo */
{
#if defined(USE_FD_PORTS) && !defined(DOS_FILE_SYSTEM)
int ok;
@ -6290,11 +6292,16 @@ int scheme_fd_regular_file(intptr_t fd, int dir_ok)
ok = fstat(fd, &buf);
} while ((ok == -1) && (errno == EINTR));
if (!S_ISREG(buf.st_mode)
&& (!dir_ok || !S_ISDIR(buf.st_mode)))
return 0;
if (S_ISREG(buf.st_mode))
return 1;
if ((or_other >= 1) && S_ISDIR(buf.st_mode))
return 1;
if ((or_other >= 2) && S_ISFIFO(buf.st_mode))
return 1;
return 1;
return 0;
#else
return 0;
#endif
@ -7669,6 +7676,10 @@ fd_write_ready (Scheme_Object *port)
MZ_FD_SET(fop->fd, exnfds);
do {
/* Mac OS X 10.8 and 10.9: select() seems to claim that a pipe
is always ready for output. To work around that problem,
kqueue() support is enabled for pipes, so we shouldn't get
here much for pipes. */
sr = select(fop->fd + 1, NULL, writefds, exnfds, &time);
} while ((sr == -1) && (errno == EINTR));
#endif

View File

@ -3723,7 +3723,7 @@ Scheme_Object *scheme_fd_to_semaphore(intptr_t fd, int mode, int is_socket)
# ifdef HAVE_KQUEUE_SYSCALL
if (!is_socket) {
if (!scheme_fd_regular_file(fd, 10))
if (!scheme_fd_regular_file(fd, 2))
return NULL; /* kqueue() might not work on devices, such as ttys */
}
if (scheme_semaphore_fd_kqueue < 0) {