Procházet zdrojové kódy

[LibOS] Emulate pause() by sleeping for a very long time

Before, pause() was emulated by sleeping for 1s in a loop until
signal interrupted it. If signal arrived in-between these invocations
then pause() could never return. Also, pause() incorrectly returned 0
instead of -1 and errno=EINTR.

This patch emulates pause() by sleeping for a very long time (years).
Also, it correctly returns EINTR.
Isaku Yamahata před 5 roky
rodič
revize
f72cd48ee5

+ 3 - 10
LibOS/shim/src/sys/shim_sleep.c

@@ -34,18 +34,11 @@
 
 #include <errno.h>
 
-#define SHIM_DEFAULT_SLEEP 1000
-
 int shim_do_pause (void)
 {
-    while (1) {
-        unsigned long ret = DkThreadDelayExecution(SHIM_DEFAULT_SLEEP);
-
-        if (!ret)
-            break;
-    }
-
-    return 0;
+    /* ~0ULL micro sec ~= 805675 years */
+    DkThreadDelayExecution(~((PAL_NUM)0));
+    return -EINTR;
 }
 
 int shim_do_nanosleep (const struct __kernel_timespec * rqtp,

+ 27 - 0
LibOS/shim/test/native/pause.c

@@ -0,0 +1,27 @@
+#include <assert.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+void handler(int signal)
+{
+    printf("hello world\n");
+}
+
+int main(int argc, char ** argv)
+{
+    if (signal(SIGALRM, &handler) < 0)
+        return EXIT_FAILURE;
+
+    if (alarm(1) < 0)
+        return EXIT_FAILURE;
+
+    int ret = pause();
+    assert(ret == -1);
+    assert(errno == EINTR);
+
+    printf("good bye\n");
+    return 0;
+}

+ 9 - 5
Pal/src/host/FreeBSD/db_threading.c

@@ -85,11 +85,15 @@ int _DkThreadDelayExecution (unsigned long * duration)
     struct timespec sleeptime;
     struct timespec remainingtime;
 
-    long sec = (unsigned long) *duration / 1000000;
-    long microsec = (unsigned long) *duration - (sec * 1000000);
-
-    sleeptime.tv_sec = sec;
-    sleeptime.tv_nsec = microsec * 1000;
+#define VERY_LONG_TIME_IN_US    (1000000L * 60 * 60 * 24 * 365 * 128)
+    if (*duration > VERY_LONG_TIME_IN_US) {
+        /* avoid overflow with time_t */
+        sleeptime.tv_sec  = VERY_LONG_TIME_IN_US / 1000000;
+        sleeptime.tv_nsec = 0;
+    } else {
+        sleeptime.tv_sec = *duration / 1000000;
+        sleeptime.tv_nsec = (*duration - sleeptime.tv_sec * 1000000) * 1000;
+    }
 
     int ret = INLINE_SYSCALL(nanosleep, 2, &sleeptime, &remainingtime);
 

+ 12 - 3
Pal/src/host/Linux-SGX/sgx_enclave.c

@@ -593,11 +593,20 @@ static int sgx_ocall_sleep(void * pms)
         return 0;
     }
     struct timespec req, rem;
-    req.tv_sec  = ms->ms_microsec / 1000000;
-    req.tv_nsec = (ms->ms_microsec - req.tv_sec * 1000000) * 1000;
+    unsigned long microsec = ms->ms_microsec;
+#define VERY_LONG_TIME_IN_US    (1000000L * 60 * 60 * 24 * 365 * 128)
+    if (ms->ms_microsec > VERY_LONG_TIME_IN_US) {
+        /* avoid overflow with time_t */
+        req.tv_sec  = VERY_LONG_TIME_IN_US / 1000000;
+        req.tv_nsec = 0;
+    } else {
+        req.tv_sec = ms->ms_microsec / 1000000;
+        req.tv_nsec = (microsec - req.tv_sec * 1000000) * 1000;
+    }
+
     ret = INLINE_SYSCALL(nanosleep, 2, &req, &rem);
     if (IS_ERR(ret) && ERRNO(ret) == EINTR)
-        ms->ms_microsec = rem.tv_sec * 1000000 + rem.tv_nsec / 1000;
+        ms->ms_microsec = rem.tv_sec * 1000000UL + rem.tv_nsec / 1000UL;
     return ret;
 }
 

+ 9 - 5
Pal/src/host/Linux/db_threading.c

@@ -139,11 +139,15 @@ int _DkThreadDelayExecution (unsigned long * duration)
     struct timespec sleeptime;
     struct timespec remainingtime;
 
-    long sec = (unsigned long) *duration / 1000000;
-    long microsec = (unsigned long) *duration - (sec * 1000000);
-
-    sleeptime.tv_sec = sec;
-    sleeptime.tv_nsec = microsec * 1000;
+#define VERY_LONG_TIME_IN_US    (1000000L * 60 * 60 * 24 * 365 * 128)
+    if (*duration > VERY_LONG_TIME_IN_US) {
+        /* avoid overflow with time_t */
+        sleeptime.tv_sec  = VERY_LONG_TIME_IN_US / 1000000;
+        sleeptime.tv_nsec = 0;
+    } else {
+        sleeptime.tv_sec = *duration / 1000000;
+        sleeptime.tv_nsec = (*duration - sleeptime.tv_sec * 1000000) * 1000;
+    }
 
     int ret = INLINE_SYSCALL(nanosleep, 2, &sleeptime, &remainingtime);