From: Waldemar Kozaczuk <jwkozac...@gmail.com>
Committer: Nadav Har'El <n...@scylladb.com>
Branch: master

semaphores: fix sem_trywait

This patch fixes a subtle but critical bug in sem_trywait()
underlying implementation (semaphore.cc) which
for example prevented new version of Java 12 and above
hang on startup in infinite loop.

It also adds new unit test around sem_* functions.

Signed-off-by: Waldemar Kozaczuk <jwkozac...@gmail.com>
Message-Id: <20190810040911.13897-1-jwkozac...@gmail.com>

---
diff --git a/core/semaphore.cc b/core/semaphore.cc
--- a/core/semaphore.cc
+++ b/core/semaphore.cc
@@ -62,7 +62,7 @@ bool semaphore::trywait(unsigned units)
 {
     bool ok = false;
     WITH_LOCK(_mtx) {
-        if (_val > units) {
+        if (_val >= units) {
             _val -= units;
             ok = true;
         }
diff --git a/modules/tests/Makefile b/modules/tests/Makefile
--- a/modules/tests/Makefile
+++ b/modules/tests/Makefile
@@ -128,7 +128,7 @@ tests := tst-pthread.so misc-ramdisk.so tst-vblk.so tst-bsd-evh.so \
        tst-ttyname.so tst-pthread-barrier.so tst-feexcept.so tst-math.so \
        tst-sigaltstack.so tst-fread.so tst-tcp-cork.so tst-tcp-v6.so \
        tst-calloc.so tst-crypt.so tst-non-fpic.so tst-small-malloc.so \
-       tst-mmx-fpu.so tst-getopt.so tst-getopt-pie.so tst-non-pie.so
+ tst-mmx-fpu.so tst-getopt.so tst-getopt-pie.so tst-non-pie.so tst-semaphore.so
 #      libstatic-thread-variable.so tst-static-thread-variable.so \

 tests += testrunner.so
diff --git a/tests/tst-semaphore.c b/tests/tst-semaphore.c
--- a/tests/tst-semaphore.c
+++ b/tests/tst-semaphore.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2019 Waldemar Kozaczuk
+ *
+ * This work is open source software, licensed under the terms of the
+ * BSD license as described in the LICENSE file in the top-level directory.
+ */
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <semaphore.h>
+#include <assert.h>
+
+#define THREAD_NUMBER 10
+
+static sem_t sem_sync, sem_done;
+static int counter = 0;
+
+static void* threadfunc(void* arg) {
+    int *thread_number = (int*)arg;
+    for (int i = 0; i < 10; i++) {
+        assert(sem_wait(&sem_sync) == 0);
+        counter++;
+        assert(sem_post(&sem_sync) == 0);
+        printf("Thread %d: Incremented %dth\n", *thread_number, i + 1);
+ usleep(1000 * (counter % 5)); // Pseudo-randomly sleep between 0-4ms
+    }
+    assert(sem_post(&sem_done) == 0);
+    return NULL;
+}
+
+int main(void) {
+    pthread_t threads[THREAD_NUMBER];
+    int threads_numbers[THREAD_NUMBER];
+
+    assert(sem_init(&sem_sync, 0, 1) == 0);
+    assert(sem_init(&sem_done, 0, 0) == 0);
+
+    for (int t = 0; t < THREAD_NUMBER; t++) {
+        threads_numbers[t] = t + 1;
+ pthread_create(threads + t, NULL, &threadfunc, threads_numbers + t);
+    }
+
+    for (int t = 0; t < THREAD_NUMBER; t++) {
+        while(sem_trywait(&sem_done));
+    }
+
+    assert(counter == 10 * THREAD_NUMBER);
+
+    for (int t = 0; t < THREAD_NUMBER; t++) {
+        pthread_join(threads[t], NULL);
+    }
+
+    assert(sem_destroy(&sem_sync) == 0);
+    assert(sem_destroy(&sem_done) == 0);
+
+    return 0;
+}

--
You received this message because you are subscribed to the Google Groups "OSv 
Development" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to osv-dev+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/osv-dev/00000000000013d51c058fd66e4c%40google.com.

Reply via email to