diff --git a/include/empthread.h b/include/empthread.h index 840192e5..d06efb10 100644 --- a/include/empthread.h +++ b/include/empthread.h @@ -160,8 +160,8 @@ void empth_yield(void); * If FLAGS & EMPTH_FD_WRITE, wake up if FD is ready for output. * At most one thread may sleep on the same file descriptor. * TIMEOUT, if non-null, limits the sleep time. - * Return one when the FD is ready, zero on timeout, -1 on error with - * errno set. + * Return one when the FD is ready, zero on timeout or early wakeup by + * empth_wakeup(), -1 on error with errno set. * Note: Currently, Empire sleeps only on network I/O, i.e. FD is a * socket. Implementations should not rely on that. */ @@ -169,7 +169,7 @@ int empth_select(int fd, int flags, struct timeval *timeout); /* * Awaken THREAD if it is sleeping in empth_select() or empth_sleep(). - * Note: This must not awaken threads sleeping in other functions. + * This does not awaken threads sleeping in other functions. * Does not yield the processor. */ void empth_wakeup(empth_t *thread); diff --git a/src/lib/empthread/io.c b/src/lib/empthread/io.c index 5e2984ee..5bbce8d9 100644 --- a/src/lib/empthread/io.c +++ b/src/lib/empthread/io.c @@ -110,11 +110,11 @@ io_close(struct iop *iop) } /* - * Return number of bytes read on success, zero on timeout or EOF, -1 - * on error, with errno set appropriately. In particular, return -1 - * with errno set to EAGAIN or EWOULDBLOCK when no data is available - * for non-blocking input (WAITFORINPUT false). Use io_eof() to - * distinguish timeout from EOF. + * Return number of bytes read on success, zero on timeout, early + * wakeup or EOF, -1 on error, with errno set appropriately. In + * particular, return -1 with errno set to EAGAIN or EWOULDBLOCK when + * no data is available for non-blocking input (WAITFORINPUT false). + * Use io_eof() to distinguish timeout and early wakeup from EOF. */ int io_input(struct iop *iop, int waitforinput) diff --git a/src/lib/empthread/pthread.c b/src/lib/empthread/pthread.c index 9c1163ff..fb1e09a9 100644 --- a/src/lib/empthread/pthread.c +++ b/src/lib/empthread/pthread.c @@ -280,11 +280,13 @@ empth_select(int fd, int flags, struct timeval *timeout) fd_set writemask; struct timeval tv; int n; + empth_t *ctx; int res = 0; pthread_mutex_unlock(&mtx_ctxsw); empth_status("select on %d for %d", fd, flags); +again: FD_ZERO(&readmask); FD_ZERO(&writemask); if (flags & EMPTH_FD_READ) @@ -292,18 +294,21 @@ empth_select(int fd, int flags, struct timeval *timeout) if (flags & EMPTH_FD_WRITE) FD_SET(fd, &writemask); - if (timeout) { + if (timeout) tv = *timeout; - timeout = &tv; - } - n = select(fd + 1, &readmask, &writemask, NULL, timeout); - + n = select(fd + 1, &readmask, &writemask, NULL, timeout ? &tv : NULL); if (n < 0) { - if (errno == EINTR) /* go handle the signal */ + ctx = pthread_getspecific(ctx_key); + if (ctx->wakeup) { + empth_status("select woken up"); + res = 0; + } else if (errno == EINTR) { empth_status("select broken by signal"); - else + goto again; + } else { empth_status("select failed (%s)", strerror(errno)); - res = -1; + res = -1; + } } else if (n == 0) { empth_status("select timed out"); res = 0;