Переглянути джерело

[LibOS] Check for pending signals before sigsuspend/pause/nanosleep

Previously, sigsuspend(), pause(), and nanosleep() syscalls did not
check for pending signals before waiting on signals. This commit adds
this logic, similar to how this is implemented in Linux. This fixes data
races in regression tests relying on these syscalls (killXX in ltp).
Dmitrii Kuvaiskii 4 роки тому
батько
коміт
479d833e72
2 змінених файлів з 55 додано та 0 видалено
  1. 13 0
      LibOS/shim/src/sys/shim_sigaction.c
  2. 42 0
      LibOS/shim/src/sys/shim_sleep.c

+ 13 - 0
LibOS/shim/src/sys/shim_sigaction.c

@@ -205,6 +205,19 @@ int shim_do_sigsuspend (const __sigset_t * mask)
 
     lock(&cur->lock);
 
+    /* return immediately on some pending unblocked signal */
+    for (int sig = 1 ; sig <= NUM_SIGS ; sig++) {
+        if (atomic_read(&cur->signal_logs[sig - 1].head) !=
+            atomic_read(&cur->signal_logs[sig - 1].tail)) {
+            /* at least one signal of type sig... */
+            if (!__sigismember(mask, sig)) {
+                /* ...and this type is not blocked in supplied mask */
+                unlock(&cur->lock);
+                return -EINTR;
+            }
+        }
+    }
+
     old = get_sig_mask(cur);
     memcpy(&tmp, old, sizeof(__sigset_t));
     old = &tmp;

+ 42 - 0
LibOS/shim/src/sys/shim_sleep.c

@@ -25,14 +25,47 @@
 #include <shim_table.h>
 #include <shim_handle.h>
 #include <shim_vma.h>
+#include <shim_thread.h>
 
 #include <pal.h>
 #include <pal_error.h>
 
 #include <errno.h>
 
+static bool signal_pending (void)
+{
+    struct shim_thread* cur = get_cur_thread();
+    if (!cur)
+        return false;
+
+    lock(&cur->lock);
+
+    if (!cur->signal_logs || !cur->has_signal.counter) {
+        unlock(&cur->lock);
+        return false;
+    }
+
+    for (int sig = 1; sig <= NUM_SIGS; sig++) {
+        if (atomic_read(&cur->signal_logs[sig - 1].head) !=
+            atomic_read(&cur->signal_logs[sig - 1].tail)) {
+            /* at least one signal of type sig... */
+            if (!__sigismember(&cur->signal_mask, sig)) {
+                /* ...and this type is not blocked  */
+                unlock(&cur->lock);
+                return true;
+            }
+        }
+    }
+
+    unlock(&cur->lock);
+    return false;
+}
+
 int shim_do_pause (void)
 {
+    if (signal_pending())
+        return -EINTR;
+
     /* ~0ULL micro sec ~= 805675 years */
     DkThreadDelayExecution(~((PAL_NUM)0));
     return -EINTR;
@@ -44,6 +77,15 @@ int shim_do_nanosleep (const struct __kernel_timespec * rqtp,
     if (!rqtp)
         return -EFAULT;
 
+    if (signal_pending()) {
+        if (rmtp) {
+            /* no time elapsed, so copy time interval from rqtp to rmtp */
+            rmtp->tv_sec = rqtp->tv_sec;
+            rmtp->tv_nsec = rqtp->tv_nsec;
+        }
+        return -EINTR;
+    }
+
     unsigned long time = rqtp->tv_sec * 1000000L + rqtp->tv_nsec / 1000;
     unsigned long ret = DkThreadDelayExecution(time);