* 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.
*/
/*
* 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);
}
/*
- * 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)
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)
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;