[LibOS/regression] Multiple fixes for the futex test

- Loop on futex(WAKE) when no thread is awaken.
- Use pthread instead of raw clone() because clone() does not
  initialize Glibc TCB, thus any function call to Glibc results
  in SIGBUS.
This commit is contained in:
Isaku Yamahata
2019-11-12 19:46:43 -08:00
committed by Dmitrii Kuvaiskii
parent 5be9fbb689
commit dafdb1d47b
3 changed files with 28 additions and 43 deletions
+1
View File
@@ -23,6 +23,7 @@ CFLAGS-multi_pthread = -pthread
CFLAGS-exit_group = -pthread
CFLAGS-abort_multithread = -pthread
CFLAGS-eventfd = -pthread
CFLAGS-futex = -pthread
CFLAGS-spinlock += -I$(PALDIR)/../lib -pthread
%: %.c
+26 -43
View File
@@ -10,90 +10,73 @@
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <errno.h>
#include <pthread.h>
// 64kB stack
#define FIBER_STACK (1024 * 64)
#define THREADS 2
static int myfutex = 0;
struct atomic_int {
volatile int counter;
};
static struct atomic_int my_counter;
static inline void atomic_inc(struct atomic_int* v) {
asm volatile("lock; incl %0" : "+m"(v->counter));
}
static int futex(int* uaddr, int futex_op, int val, const struct timespec* timeout, int* uaddr2,
int val3) {
return syscall(SYS_futex, uaddr, futex_op, val, timeout, uaddr, val3);
}
int thread_function(void* argument) {
void* thread_function(void* argument) {
int* ptr = (int*)argument;
int rv;
atomic_inc(&my_counter);
// Sleep on the futex
rv = futex(&myfutex, FUTEX_WAIT_BITSET, 0, NULL, NULL, *ptr);
assert(rv == 0);
// printf("child thread %d awakened\n", getpid());
return 0;
return NULL;
}
int main(int argc, const char** argv) {
void* stacks[THREADS];
pid_t pids[THREADS];
int varx[THREADS];
my_counter.counter = 0;
pthread_t thread[THREADS];
static int varx[THREADS];
for (int i = 0; i < THREADS; i++) {
varx[i] = (1 << i);
// Allocate the stack
stacks[i] = malloc(FIBER_STACK);
if (stacks[i] == 0) {
perror("malloc: could not allocate stack");
_exit(1);
}
// Call the clone system call to create the child thread
pids[i] = clone(&thread_function, (void*)stacks[i] + FIBER_STACK,
CLONE_FS | CLONE_FILES | CLONE_SIGHAND | CLONE_VM | CLONE_THREAD, &varx[i]);
// printf("clone() creates new thread %d\n", pids[i]);
if (pids[i] == -1) {
perror("clone");
int ret = pthread_create(&thread[i], NULL, &thread_function, &varx[i]);
if (ret) {
errno = ret;
perror("pthread_create");
_exit(2);
}
}
// Make sure the threads are sleeping
do {
sleep(1);
} while (my_counter.counter != THREADS);
printf("Waking up kiddos\n");
/* Wake in reverse order */
for (int i = THREADS - 1; i >= 0; i--) {
pid_t pid;
int rv;
int var = (1 << i);
// Wake up the thread
rv = futex(&myfutex, FUTEX_WAKE_BITSET, 1, NULL, NULL, var);
do {
rv = futex(&myfutex, FUTEX_WAKE_BITSET, 1, NULL, NULL, var);
if (rv == 0) {
// the thread of thread_function() may not reach
// futex(FUTEX_WAIT_BITSET) yet.
// Wait for the thread to sleep and try again.
// Since synchronization primitive, futex, is being tested,
// futex can't be used here. resort to use sleep.
sleep(1);
}
} while (rv == 0);
printf("FUTEX_WAKE_BITSET i = %d rv = %d\n", i, rv);
assert(rv == 1);
// Wait for the child thread to exit
pid = waitpid(pids[i], NULL, __WALL);
if (pid == -1) {
perror("waitpid");
int ret = pthread_join(thread[i], NULL);
if (ret) {
errno = ret;
perror("pthread_join");
_exit(3);
}
// Free the stack
free(stacks[i]);
}
printf("Woke all kiddos\n");
@@ -18,4 +18,5 @@ net.rules.2 = 0.0.0.0:0-65535:127.0.0.1:8000
sgx.trusted_files.ld = file:../../../../Runtime/ld-linux-x86-64.so.2
sgx.trusted_files.libc = file:../../../../Runtime/libc.so.6
sgx.trusted_files.libpthread = file:../../../../Runtime/libpthread.so.0
sgx.thread_num = 4