Browse Source

Add a few PAL unit tests for Semaphores, fix some bugs, add documentation on semaphore/wait interfaces.

Don Porter 7 years ago
parent
commit
fffcb6a366

+ 25 - 0
Pal/regression/02_Semaphore.py

@@ -0,0 +1,25 @@
+#!/usr/bin/python
+
+import os, sys, mmap, random, string
+from regression import Regression
+
+loader = os.environ['PAL_LOADER']
+
+# Running Semaphore
+regression = Regression(loader, "Semaphore")
+
+regression.add_check(name="Semaphore: Timeout on Locked Semaphores",
+    check=lambda res: "Locked binary semaphore timed out (1000)." in res[0].log and
+                      "Locked non-binary semaphore timed out (1000)." in res[0].log and
+                      "Two locked semaphores timed out (1000)." in res[0].log and
+                      "Locked binary semaphore timed out (0)." in res[0].log and
+                      "Locked non-binary semaphore timed out (0)." in res[0].log and
+                      "Two locked semaphores timed out (0)." in res[0].log)
+
+regression.add_check(name="Semaphore: Acquire Unlocked Semaphores",
+    check=lambda res: "Locked binary semaphore successfully (-1)." in res[0].log and
+                      "Locked non-binary semaphore successfully (-1)." in res[0].log and
+                      "Locked binary semaphore successfully (0)." in res[0].log and
+                      "Locked non-binary semaphore successfully (0)." in res[0].log)
+
+regression.run_checks()

+ 100 - 0
Pal/regression/Semaphore.c

@@ -0,0 +1,100 @@
+/* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */
+/* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */
+
+#include "pal.h"
+#include "pal_debug.h"
+#include "api.h"
+
+void helper_timeout(PAL_NUM timeout) {
+    /* Create a binary semaphore */
+
+    PAL_HANDLE sem1 = DkSemaphoreCreate(1, 1);
+
+    if(!sem1) {
+        pal_printf("Failed to create a binary semaphore\n");
+        return;
+    }
+
+    /* Wait on the binary semaphore with a timeout */
+    PAL_HANDLE rv = DkObjectsWaitAny(1, &sem1, timeout);
+    if (rv == NULL)
+        pal_printf("Locked binary semaphore timed out (%d).\n", timeout);
+    else 
+        pal_printf("Acquired locked binary semaphore!?! Got back %p; sem1 is %p (%d)\n", rv, sem1, timeout);
+    
+    PAL_HANDLE sem2 = DkSemaphoreCreate(2, 2);
+
+    if(!sem2) {
+        pal_printf("Failed to create a non-binary semaphore\n");
+        return;
+    }
+
+    /* Wait on the non-binary semaphore with a timeout */
+    rv = DkObjectsWaitAny(1, &sem2, timeout);
+    if (rv == NULL)
+        pal_printf("Locked non-binary semaphore timed out (%d).\n", timeout);
+    else 
+        pal_printf("Acquired locked non-binary semaphore!?! Got back %p; sem2 is %p (%d)\n", rv, sem2, timeout);
+
+    /* Try waiting on both */
+    PAL_HANDLE hdls[2];
+    hdls[0] = sem1;
+    hdls[1] = sem2;
+
+    rv = DkObjectsWaitAny(2, hdls, timeout);
+    if (rv == NULL)
+        pal_printf("Two locked semaphores timed out (%d).\n", timeout);
+    else 
+        pal_printf("Somehow locked one of two locked semaphore handles? %p (%d)\n", rv, timeout);
+
+    DkObjectClose(sem1);
+    DkObjectClose(sem2);
+}
+
+void helper_success(PAL_NUM timeout) {
+    /* Create a binary semaphore */
+
+    PAL_HANDLE sem1 = DkSemaphoreCreate(0, 1);
+
+    if(!sem1) {
+        pal_printf("Failed to create a binary semaphore\n");
+        return;
+    }
+
+    /* Wait on the binary semaphore with a timeout */
+    PAL_HANDLE rv = DkObjectsWaitAny(1, &sem1, timeout);
+    if (rv == sem1)
+        pal_printf("Locked binary semaphore successfully (%d).\n", timeout);
+    else 
+        pal_printf("Failed to lock binary semaphore: Got back %p; sem1 is %p\n", rv, sem1);
+    
+    PAL_HANDLE sem2 = DkSemaphoreCreate(0, 2);
+
+    if(!sem2) {
+        pal_printf("Failed to create a non-binary semaphore\n");
+        return;
+    }
+
+    /* Wait on the non-binary semaphore with a timeout */
+    rv = DkObjectsWaitAny(1, &sem2, timeout);
+    if (rv == sem2)
+        pal_printf("Locked non-binary semaphore successfully (%d).\n", timeout);
+    else 
+        pal_printf("Failed to lock non-binary semaphore Got back %p; sem2 is %p\n", rv, sem2);
+
+    DkObjectClose(sem1);
+    DkObjectClose(sem2);
+}
+
+
+int main (int argc, char ** argv, char ** envp)
+{
+    helper_timeout(1000);
+    /* Try again with timeout 0 (trylock) */
+    helper_timeout(0);
+
+    /* Try cases that should succeed */
+    helper_success(NO_TIMEOUT);
+    helper_success(0);
+    return 0;
+}

+ 1 - 2
Pal/src/host/Linux-SGX/db_semaphore.c

@@ -182,8 +182,7 @@ int _DkSemaphoreAcquireTimeout (PAL_HANDLE sem, int count, int timeout)
         atomic_add (count, (struct atomic_int *) value);
 
     if (!timeout)
-        // BUG: Really? shouldn't we fail if we didn't get the lock?
-        return 0;
+        return -PAL_ERROR_TRYAGAIN;
 
     unsigned long waittime = timeout;
     int ret = 0;

+ 8 - 3
Pal/src/host/Linux/db_object.c

@@ -42,7 +42,10 @@
 #define DEFAULT_QUANTUM 500
 
 /* internally to wait for one object. Also used as a shortcut to wait
-   on events and semaphores */
+ *  on events and semaphores.
+ *
+ *  Returns 0 on success, negative value on failure (e.g., -PAL_ERROR_TRYAGAIN)
+ */
 static int _DkObjectWaitOne (PAL_HANDLE handle, int timeout)
 {
     /* only for all these handle which has a file descriptor, or
@@ -130,8 +133,10 @@ int _DkObjectsWaitAny (int count, PAL_HANDLE * handleArray, int timeout,
         return 0;
 
     if (count == 1) {
-        *polled = handleArray[0];
-        return _DkObjectWaitOne(handleArray[0], timeout);
+        int rv = _DkObjectWaitOne(handleArray[0], timeout);
+        if (rv == 0)
+            *polled = handleArray[0];
+        return rv;
     }
 
     int i, j, ret, maxfds = 0, nfds = 0;

+ 2 - 3
Pal/src/host/Linux/db_semaphore.c

@@ -160,8 +160,7 @@ int _DkSemaphoreAcquireTimeout (PAL_HANDLE sem, int count, int timeout)
     /* optimization: use it as a mutex */
     if (sem->semaphore.max_value == 1) {
         struct mutex_handle * mut = & sem->semaphore.value.mut;
-        _DkMutexLockTimeout(mut, timeout);
-        return 0;
+        return _DkMutexLockTimeout(mut, timeout);
     }
 
     if (count > sem->semaphore.max_value)
@@ -188,7 +187,7 @@ int _DkSemaphoreAcquireTimeout (PAL_HANDLE sem, int count, int timeout)
         atomic_add (count, value);
 
     if (!timeout)
-        return 0;
+        return -PAL_ERROR_TRYAGAIN;
 
     struct timespec waittime;
     long sec = timeout / 1000000;

+ 5 - 1
Pal/src/pal.h

@@ -427,7 +427,10 @@ void DkExceptionReturn (PAL_PTR event);
  * We may want to replace it with a PAL_HANDLE. Ideally, either use PAL_HANDLE
  * or threadHandle.
  */
-
+/* maxcount sets the number of threads allowed to hold the semaphore
+ * at once.  For 1, this becomes a mutex.
+ * initialCount of 0 is totally unlocked; an initialCount that
+ * equals maxCount means that all resources are taken. */ 
 PAL_HANDLE
 DkSemaphoreCreate (PAL_NUM initialCount, PAL_NUM maxCount);
 
@@ -464,6 +467,7 @@ DkEventClear (PAL_HANDLE eventHandle);
 #define NO_TIMEOUT      ((PAL_NUM) -1)
 
 /* assuming timeout to be in microseconds */
+/* Returns: NULL if the call times out, the ready handle on success */
 PAL_HANDLE
 DkObjectsWaitAny (PAL_NUM count, PAL_HANDLE * handleArray, PAL_NUM timeout);
 

+ 5 - 1
Pal/src/pal_internal.h

@@ -103,7 +103,11 @@ struct handle_ops {
        the attributes of a stream handle */
     int (*attrsetbyhdl) (PAL_HANDLE handle, PAL_STREAM_ATTR * attr);
 
-    /* 'wait' is used for synchronous wait */
+    /* 'wait' is used for synchronous wait.
+     * Returns 0 on success, a negative value on failure.
+     * Timeout: -PAL_ERROR_TRYAGAIN
+     * Positive return values are undefined.
+     */
     int (*wait) (PAL_HANDLE handle, int time);
 
     /* 'rename' is used to change name of a stream, or reset its share