diff --git a/src/common/compat_pthreads.c b/src/common/compat_pthreads.c index f43480539f..188a91f68d 100644 --- a/src/common/compat_pthreads.c +++ b/src/common/compat_pthreads.c @@ -196,23 +196,37 @@ tor_cond_uninit(tor_cond_t *cond) int tor_cond_wait(tor_cond_t *cond, tor_mutex_t *mutex, const struct timeval *tv) { + int r; if (tv == NULL) { - return pthread_cond_wait(&cond->cond, &mutex->mutex) ? -1 : 0; + while (1) { + r = pthread_cond_wait(&cond->cond, &mutex->mutex); + if (r == EINTR) { + /* EINTR should be impossible according to POSIX, but POSIX, like the + * Pirate's Code, is apparently treated "more like what you'd call + * guidelines than actual rules." */ + continue; + } + return r ? -1 : 0; + } } else { struct timespec ts; struct timeval tvnow, tvsum; - int r; - gettimeofday(&tvnow, NULL); - timeradd(tv, &tvnow, &tvsum); - ts.tv_sec = tvsum.tv_sec; - ts.tv_nsec = tvsum.tv_usec * 1000; - r = pthread_cond_timedwait(&cond->cond, &mutex->mutex, &ts); - if (r == 0) - return 0; - else if (r == ETIMEDOUT) - return 1; - else - return -1; + while (1) { + gettimeofday(&tvnow, NULL); + timeradd(tv, &tvnow, &tvsum); + ts.tv_sec = tvsum.tv_sec; + ts.tv_nsec = tvsum.tv_usec * 1000; + + r = pthread_cond_timedwait(&cond->cond, &mutex->mutex, &ts); + if (r == 0) + return 0; + else if (r == ETIMEDOUT) + return 1; + else if (r == EINTR) + continue; + else + return -1; + } } } /** Wake up one of the waiters on cond. */ diff --git a/src/common/compat_threads.c b/src/common/compat_threads.c index 79440070a2..3b79292cdb 100644 --- a/src/common/compat_threads.c +++ b/src/common/compat_threads.c @@ -88,12 +88,59 @@ in_main_thread(void) return main_thread_id == tor_get_thread_id(); } +#if defined(HAVE_EVENTFD) || defined(HAVE_PIPE) +/* non-interruptable versions */ +static int +write_ni(int fd, const void *buf, size_t n) +{ + int r; + again: + r = write(fd, buf, n); + if (r < 0 && errno == EINTR) + goto again; + return r; +} +static int +read_ni(int fd, void *buf, size_t n) +{ + int r; + again: + r = read(fd, buf, n); + if (r < 0 && errno == EINTR) + goto again; + return r; +} +#endif + +/* non-interruptable versions */ +static int +send_ni(int fd, const void *buf, size_t n, int flags) +{ + int r; + again: + r = send(fd, buf, n, flags); + if (r < 0 && errno == EINTR) + goto again; + return r; +} + +static int +recv_ni(int fd, void *buf, size_t n, int flags) +{ + int r; + again: + r = recv(fd, buf, n, flags); + if (r < 0 && errno == EINTR) + goto again; + return r; +} + #ifdef HAVE_EVENTFD static int eventfd_alert(int fd) { uint64_t u = 1; - int r = write(fd, (void*)&u, sizeof(u)); + int r = write_ni(fd, (void*)&u, sizeof(u)); if (r < 0 && errno != EAGAIN) return -1; return 0; @@ -103,7 +150,7 @@ static int eventfd_drain(int fd) { uint64_t u = 0; - int r = read(fd, (void*)&u, sizeof(u)); + int r = read_ni(fd, (void*)&u, sizeof(u)); if (r < 0 && errno != EAGAIN) return -1; return 0; @@ -136,7 +183,7 @@ pipe_drain(int fd) static int sock_alert(tor_socket_t fd) { - ssize_t r = send(fd, "x", 1, 0); + ssize_t r = send_ni(fd, "x", 1, 0); if (r < 0 && !ERRNO_IS_EAGAIN(tor_socket_errno(fd))) return -1; return 0; @@ -147,7 +194,7 @@ sock_drain(tor_socket_t fd) { char buf[32]; ssize_t r; - while ((r = recv(fd, buf, sizeof(buf), 0)) >= 0) + while ((r = recv_ni(fd, buf, sizeof(buf), 0)) >= 0) ; if (r == 0 || !ERRNO_IS_EAGAIN(tor_socket_errno(fd))) return -1;