handle EINTR in compat_*threads.c

This commit is contained in:
Nick Mathewson 2015-01-21 12:18:11 -05:00
parent a52e549124
commit ac5b70c700
2 changed files with 78 additions and 17 deletions

View File

@ -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 <b>cond</b>. */

View File

@ -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;