浏览代码

[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);