Skip to content

Commit

Permalink
semaphores: fix sem_trywait
Browse files Browse the repository at this point in the history
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 <[email protected]>
Message-Id: <[email protected]>
  • Loading branch information
wkozaczuk authored and nyh committed Aug 11, 2019
1 parent ef56fde commit 6b459dd
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 2 deletions.
2 changes: 1 addition & 1 deletion core/semaphore.cc
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
2 changes: 1 addition & 1 deletion modules/tests/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
59 changes: 59 additions & 0 deletions tests/tst-semaphore.c
Original file line number Diff line number Diff line change
@@ -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;
}

0 comments on commit 6b459dd

Please sign in to comment.