From 5cbe6cfdcb2c8ef75f1f3461fc22d4193f43bf6c Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Wed, 25 Jun 2014 09:28:39 +0100 Subject: [PATCH] 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 --- racket/src/racket/src/port.c | 21 ++++++++++++++++----- racket/src/racket/src/thread.c | 2 +- 2 files changed, 17 insertions(+), 6 deletions(-) diff --git a/racket/src/racket/src/port.c b/racket/src/racket/src/port.c index 22837cda9e..346710acc5 100644 --- a/racket/src/racket/src/port.c +++ b/racket/src/racket/src/port.c @@ -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 diff --git a/racket/src/racket/src/thread.c b/racket/src/racket/src/thread.c index fbd201289e..2b56ba6f16 100644 --- a/racket/src/racket/src/thread.c +++ b/racket/src/racket/src/thread.c @@ -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) {