[m-rev.] for review: Handle sem_wait, sem_timedwait being interrupted by signal handlers.

Peter Wang novalazy at gmail.com
Wed Jul 5 17:05:37 AEST 2017


sem_wait or sem_timedwait may be interrupted by signal handlers and
return an error. We must retry the call if errno is set to EINTR.

library/thread.m:
    Retry MR_SEM_WAIT if interrupted by a signal handler in
    ML_create_exclusive_thread.

    Call MR_fatal_error if MR_SEM_WAIT fails for any other reason.
    The only other documented error code is EINVAL if the semaphore is
    invalid; that should not happen.

runtime/mercury_context.c:
    Retry MR_SEM_WAIT if interrupted by a signal handler in
    MR_shutdown_ws_engines.

runtime/mercury_thread.h:
    Add the macro MR_SEM_IS_EINTR for checking if errno == EINTR
    after calling MR_SEM_WAIT or MR_SEM_TIMED_WAIT.
---
 library/thread.m          | 17 +++++++++++++----
 runtime/mercury_context.c |  6 +++++-
 runtime/mercury_thread.h  |  9 ++++++++-
 3 files changed, 26 insertions(+), 6 deletions(-)

diff --git a/library/thread.m b/library/thread.m
index 0d80e9b..4cfec3a 100644
--- a/library/thread.m
+++ b/library/thread.m
@@ -536,7 +536,7 @@ INIT mercury_sys_init_thread_modules
     ML_ThreadWrapperArgs    args;
     pthread_t               thread;
     pthread_attr_t          attrs;
-    int err;
+    int                     thread_err;
 
     ML_incr_thread_barrier_count();
 
@@ -549,11 +549,20 @@ INIT mercury_sys_init_thread_modules
 
     pthread_attr_init(&attrs);
     pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED);
-    err = pthread_create(&thread, &attrs, ML_exclusive_thread_wrapper, &args);
+    thread_err = pthread_create(&thread, &attrs, ML_exclusive_thread_wrapper, &args);
     pthread_attr_destroy(&attrs);
 
-    if (err == 0) {
-        MR_SEM_WAIT(&args.sem, ""ML_create_exclusive_thread"");
+    if (thread_err == 0) {
+        int sem_err;
+
+        do {
+            sem_err = MR_SEM_WAIT(&args.sem, ""ML_create_exclusive_thread"");
+        } while (sem_err == -1 && MR_SEM_IS_EINTR(errno));
+
+        if (sem_err != 0) {
+            MR_fatal_error(
+                ""ML_create_exclusive_thread: MR_SEM_WAIT error %d"", errno);
+        }
     }
 
     MR_sem_destroy(&args.sem);
diff --git a/runtime/mercury_context.c b/runtime/mercury_context.c
index ee1f6db..8bad7c9 100644
--- a/runtime/mercury_context.c
+++ b/runtime/mercury_context.c
@@ -1996,7 +1996,11 @@ MR_shutdown_ws_engines(void)
     }
 
     for (i = 0; i < (MR_num_ws_engines - 1); i++) {
-        MR_SEM_WAIT(&shutdown_ws_semaphore, "MR_shutdown_ws_engines");
+        int err;
+
+        do {
+            err = MR_SEM_WAIT(&shutdown_ws_semaphore, "MR_shutdown_ws_engines");
+        } while (err == -1 && MR_SEM_IS_EINTR(errno));
     }
 }
 
diff --git a/runtime/mercury_thread.h b/runtime/mercury_thread.h
index 32de40d..288abe7 100644
--- a/runtime/mercury_thread.h
+++ b/runtime/mercury_thread.h
@@ -74,13 +74,18 @@
     // generated code is considered stable, since the alternative versions do
     // the same thing, but with debugging support enabled.
 
+    // MR_SEM_IS_EINTR is used to test if MR_SEM_WAIT or MR_SEM_TIMED_WAIT was
+    // interrupted by a signal. We do not test errno when using libdispatch as
+    // the manual page for dispatch_semaphore_wait does not mention errno nor
+    // EINTR.
+
     #define MR_LOCK(lck, from)      pthread_mutex_lock((lck))
     #define MR_UNLOCK(lck, from)    pthread_mutex_unlock((lck))
 
     #define MR_COND_SIGNAL(cnd, from)    pthread_cond_signal((cnd))
     #define MR_COND_BROADCAST(cnd, from) pthread_cond_broadcast((cnd))
     #define MR_COND_WAIT(cnd, mtx, from) pthread_cond_wait((cnd), (mtx))
-    #define MR_COND_TIMED_WAIT(cond, mtx, abstime, from)                     \
+    #define MR_COND_TIMED_WAIT(cond, mtx, abstime, from)                \
         pthread_cond_timedwait((cond), (mtx), (abstime))
 
     #if defined(MR_USE_LIBDISPATCH)
@@ -89,11 +94,13 @@
       #define MR_SEM_POST(sem, from)  dispatch_semaphore_signal(*(sem))
       #define MR_SEM_TIMED_WAIT(sem, abstime, from)                     \
         dispatch_semaphore_wait(*(sem), dispatch_walltime((abstime), 0))
+      #define MR_SEM_IS_EINTR(errno)    MR_FALSE
     #else
       #define MR_SEM_WAIT(sem, from)  sem_wait((sem))
       #define MR_SEM_POST(sem, from)  sem_post((sem))
       #define MR_SEM_TIMED_WAIT(sem, abstime, from)                     \
         sem_timedwait((sem), (abstime))
+      #define MR_SEM_IS_EINTR(errno)  (errno == EINTR)
     #endif // !MR_USE_LIBDISPATCH
 
   #else // MR_DEBUG_THREADS
-- 
2.9.0



More information about the reviews mailing list