diff options
author | Eric Wong <e@80x24.org> | 2015-03-09 20:22:23 +0000 |
---|---|---|
committer | Eric Wong <e@80x24.org> | 2015-03-09 20:39:10 +0000 |
commit | c659acbb8d7a6b0c8098646981124a47f15cceae (patch) | |
tree | 41667f3f21e4870cbfed41f89944921637779134 | |
parent | 1a7f32d0d8a48b9f26f595d0fa9f5db0c657bc3a (diff) | |
download | cmogstored-c659acbb8d7a6b0c8098646981124a47f15cceae.tar.gz |
During the initial device scan, it is possible for the waiter to be interrupted while awaiting cancellation. We must account for this on all platforms regardless of whether pselect or ppoll is used. Reported-by: Mykola Golub <trociny@FreeBSD.org>
-rw-r--r-- | cmogstored.h | 2 | ||||
-rw-r--r-- | mnt.c | 6 | ||||
-rw-r--r-- | sig.c | 26 |
3 files changed, 24 insertions, 10 deletions
diff --git a/cmogstored.h b/cmogstored.h index c6c5291..a7309b5 100644 --- a/cmogstored.h +++ b/cmogstored.h @@ -291,7 +291,7 @@ struct mog_file { extern sigset_t mog_emptyset; void mog_intr_disable(void); void mog_intr_enable(void); -void mog_sleep(long seconds); +int mog_sleep(long seconds); #include "selfwake.h" enum mog_fd_type { @@ -122,6 +122,7 @@ skip: static void * init_once(void *ptr) { struct init_args *ia = ptr; + int err; CHECK(int, 0, pthread_mutex_lock(&by_dev_lock) ); assert(by_dev == NULL && @@ -135,7 +136,10 @@ static void * init_once(void *ptr) CHECK(int, 0, pthread_cond_signal(&ia->cond)); CHECK(int, 0, pthread_mutex_unlock(&ia->cond_lock)); - mog_sleep(-1); /* wait for cancellation */ + /* wait for cancellation, mog_sleep may return ENOMEM or EINTR */ + do { + err = mog_sleep(-1); + } while (err == EINTR || err == ENOMEM); assert(0 && "init_once did not get cancelled"); return NULL; } @@ -32,23 +32,33 @@ void mog_intr_enable(void) * would increase the size of the executable */ #ifdef HAVE_PPOLL -static void sleeper(struct timespec *tsp, const sigset_t *sigmask) +static int sleeper(struct timespec *tsp, const sigset_t *sigmask) { - if (ppoll(NULL, 0, tsp, sigmask) < 0) - assert((errno == EINTR || errno == ENOMEM) && + int err = 0; + + if (ppoll(NULL, 0, tsp, sigmask) < 0) { + err = errno; + assert((err == EINTR || err == ENOMEM) && "BUG in ppoll usage"); + } + return err; } #else /* PSELECT */ -static void sleeper(struct timespec *tsp, const sigset_t *sigmask) +static int sleeper(struct timespec *tsp, const sigset_t *sigmask) { - if (pselect(0, NULL, NULL, NULL, tsp, sigmask) < 0) - assert((errno == EINTR || errno == ENOMEM) && + int err = 0; + + if (pselect(0, NULL, NULL, NULL, tsp, sigmask) < 0) { + err = errno; + assert((err == EINTR || err == ENOMEM) && "BUG in pselect usage"); + } + return err; } #endif /* PSELECT */ /* thread-safe, interruptible sleep, negative seconds -> sleep forever */ -void mog_sleep(long seconds) +int mog_sleep(long seconds) { struct timespec ts; struct timespec *tsp; @@ -61,5 +71,5 @@ void mog_sleep(long seconds) tsp = &ts; } - sleeper(tsp, &mog_emptyset); + return sleeper(tsp, &mog_emptyset); } |