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 <[email protected]> ref: <[email protected]> --- cmogstored.h | 2 +- mnt.c | 6 +++++- 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 { diff --git a/mnt.c b/mnt.c index 0de0bb9..ca4bdf8 100644 --- a/mnt.c +++ b/mnt.c @@ -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; } diff --git a/sig.c b/sig.c index c04117a..cfbffc2 100644 --- a/sig.c +++ b/sig.c @@ -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); } -- EW
