mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-23 05:42:29 +00:00
Implement POSIX threads API
This commit is contained in:
parent
af24f21556
commit
9be364d40a
95 changed files with 6029 additions and 317 deletions
82
test/libc/intrin/pthread_barrier_wait_test.c
Normal file
82
test/libc/intrin/pthread_barrier_wait_test.c
Normal file
|
@ -0,0 +1,82 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/assert.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/thread/spawn.h"
|
||||
|
||||
int i, n;
|
||||
_Atomic(int) p, w;
|
||||
pthread_barrier_t barrier;
|
||||
|
||||
int Worker(void *arg, int tid) {
|
||||
int rc;
|
||||
rc = pthread_barrier_wait(&barrier);
|
||||
atomic_fetch_add(&w, 1);
|
||||
ASSERT_GE(rc, 0);
|
||||
if (rc == PTHREAD_BARRIER_SERIAL_THREAD) {
|
||||
atomic_fetch_add(&p, 1);
|
||||
ASSERT_EQ(0, barrier.popped);
|
||||
ASSERT_EQ(0, barrier.waits);
|
||||
ASSERT_EQ(n, barrier.count);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(pthread_barrier_init, test0_isInvalid) {
|
||||
__assert_disable = true;
|
||||
ASSERT_EQ(EINVAL, pthread_barrier_init(&barrier, 0, 0));
|
||||
__assert_disable = false;
|
||||
}
|
||||
|
||||
TEST(pthread_barrier_wait, test1) {
|
||||
struct spawn t;
|
||||
p = 0;
|
||||
w = 0;
|
||||
n = 1;
|
||||
ASSERT_EQ(0, pthread_barrier_init(&barrier, 0, n));
|
||||
ASSERT_SYS(0, 0, _spawn(Worker, 0, &t));
|
||||
EXPECT_SYS(0, 0, _join(&t));
|
||||
ASSERT_EQ(1, p);
|
||||
ASSERT_EQ(n, w);
|
||||
ASSERT_EQ(0, pthread_barrier_destroy(&barrier));
|
||||
}
|
||||
|
||||
TEST(pthread_barrier_wait, test32) {
|
||||
struct spawn *t;
|
||||
p = 0;
|
||||
w = 0;
|
||||
n = 32;
|
||||
t = gc(malloc(sizeof(struct spawn) * n));
|
||||
ASSERT_EQ(0, pthread_barrier_init(&barrier, 0, n));
|
||||
for (i = 0; i < n; ++i) {
|
||||
ASSERT_EQ(0, w);
|
||||
ASSERT_SYS(0, 0, _spawn(Worker, 0, t + i));
|
||||
}
|
||||
for (i = 0; i < n; ++i) {
|
||||
EXPECT_SYS(0, 0, _join(t + i));
|
||||
}
|
||||
ASSERT_EQ(1, p);
|
||||
ASSERT_EQ(n, w);
|
||||
ASSERT_EQ(0, pthread_barrier_destroy(&barrier));
|
||||
}
|
120
test/libc/intrin/pthread_cond_broadcast_test.c
Normal file
120
test/libc/intrin/pthread_cond_broadcast_test.c
Normal file
|
@ -0,0 +1,120 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/struct/timespec.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/kprintf.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/intrin/pthread2.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/thread/spawn.h"
|
||||
|
||||
_Atomic(int) bReady;
|
||||
pthread_cond_t bCond;
|
||||
pthread_mutex_t bMutex;
|
||||
|
||||
int BroadcastWorker(void *arg, int tid) {
|
||||
ASSERT_EQ(0, pthread_mutex_lock(&bMutex));
|
||||
atomic_fetch_add(&bReady, 1);
|
||||
ASSERT_EQ(0, pthread_cond_wait(&bCond, &bMutex));
|
||||
ASSERT_EQ(0, pthread_mutex_unlock(&bMutex));
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(pthread_cond_broadcast, test) {
|
||||
pthread_condattr_t cAttr;
|
||||
pthread_mutexattr_t mAttr;
|
||||
ASSERT_EQ(0, pthread_mutexattr_init(&mAttr));
|
||||
ASSERT_EQ(0, pthread_mutexattr_settype(&mAttr, PTHREAD_MUTEX_ERRORCHECK));
|
||||
ASSERT_EQ(0, pthread_mutex_init(&bMutex, &mAttr));
|
||||
ASSERT_EQ(0, pthread_condattr_init(&cAttr));
|
||||
ASSERT_EQ(0, pthread_condattr_setpshared(&cAttr, PTHREAD_PROCESS_PRIVATE));
|
||||
ASSERT_EQ(0, pthread_cond_init(&bCond, &cAttr));
|
||||
int i, n = 16;
|
||||
struct spawn *t = gc(malloc(sizeof(struct spawn) * n));
|
||||
for (i = 0; i < n; ++i) {
|
||||
ASSERT_SYS(0, 0, _spawn(BroadcastWorker, 0, t + i));
|
||||
}
|
||||
for (;;) {
|
||||
if (atomic_load_explicit(&bReady, memory_order_relaxed) == n) {
|
||||
break;
|
||||
} else {
|
||||
pthread_yield();
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(0, pthread_mutex_lock(&bMutex));
|
||||
ASSERT_EQ(0, pthread_cond_broadcast(&bCond));
|
||||
ASSERT_EQ(0, pthread_mutex_unlock(&bMutex));
|
||||
for (i = 0; i < n; ++i) {
|
||||
EXPECT_SYS(0, 0, _join(t + i));
|
||||
}
|
||||
ASSERT_EQ(0, pthread_mutex_destroy(&bMutex));
|
||||
ASSERT_EQ(0, pthread_cond_destroy(&bCond));
|
||||
}
|
||||
|
||||
TEST(pthread_cond_timedwait, testTimeoutInPast_timesOutImmediately) {
|
||||
struct timespec t = {100000};
|
||||
pthread_cond_t c = PTHREAD_COND_INITIALIZER;
|
||||
pthread_mutex_t m = {PTHREAD_MUTEX_ERRORCHECK};
|
||||
ASSERT_EQ(0, pthread_mutex_lock(&m));
|
||||
ASSERT_EQ(ETIMEDOUT, pthread_cond_timedwait(&c, &m, &t));
|
||||
ASSERT_EQ(0, pthread_mutex_unlock(&m));
|
||||
}
|
||||
|
||||
_Atomic(int) tReady;
|
||||
pthread_cond_t tCond;
|
||||
pthread_mutex_t tMutex;
|
||||
|
||||
int TimedWorker(void *arg, int tid) {
|
||||
struct timespec ts;
|
||||
ASSERT_EQ(0, pthread_mutex_lock(&tMutex));
|
||||
atomic_fetch_add(&tReady, 1);
|
||||
ts = _timespec_add(_timespec_mono(), _timespec_frommillis(30000));
|
||||
ASSERT_EQ(0, pthread_cond_timedwait(&tCond, &tMutex, &ts));
|
||||
ASSERT_EQ(0, pthread_mutex_unlock(&tMutex));
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(pthread_cond_timedwait, testThirtySeconds_doesntTimeOut) {
|
||||
pthread_condattr_t cAttr;
|
||||
pthread_mutexattr_t mAttr;
|
||||
ASSERT_EQ(0, pthread_mutexattr_init(&mAttr));
|
||||
ASSERT_EQ(0, pthread_mutexattr_settype(&mAttr, PTHREAD_MUTEX_ERRORCHECK));
|
||||
ASSERT_EQ(0, pthread_mutex_init(&tMutex, &mAttr));
|
||||
ASSERT_EQ(0, pthread_condattr_init(&cAttr));
|
||||
ASSERT_EQ(0, pthread_condattr_setpshared(&cAttr, PTHREAD_PROCESS_PRIVATE));
|
||||
ASSERT_EQ(0, pthread_cond_init(&tCond, &cAttr));
|
||||
struct spawn t;
|
||||
ASSERT_SYS(0, 0, _spawn(TimedWorker, 0, &t));
|
||||
for (;;) {
|
||||
if (atomic_load_explicit(&tReady, memory_order_relaxed)) {
|
||||
break;
|
||||
} else {
|
||||
pthread_yield();
|
||||
}
|
||||
}
|
||||
ASSERT_EQ(0, pthread_mutex_lock(&tMutex));
|
||||
ASSERT_EQ(0, pthread_cond_signal(&tCond));
|
||||
ASSERT_EQ(0, pthread_mutex_unlock(&tMutex));
|
||||
EXPECT_SYS(0, 0, _join(&t));
|
||||
ASSERT_EQ(0, pthread_mutex_destroy(&tMutex));
|
||||
ASSERT_EQ(0, pthread_cond_destroy(&tCond));
|
||||
}
|
|
@ -49,8 +49,8 @@
|
|||
int count;
|
||||
_Atomic(int) started;
|
||||
_Atomic(int) finished;
|
||||
_Alignas(64) char slock;
|
||||
pthread_mutex_t mylock;
|
||||
pthread_spinlock_t slock;
|
||||
struct spawn th[THREADS];
|
||||
|
||||
void SetUpOnce(void) {
|
||||
|
@ -188,19 +188,27 @@ int SpinlockWorker(void *p, int tid) {
|
|||
int i;
|
||||
++started;
|
||||
for (i = 0; i < ITERATIONS; ++i) {
|
||||
_spinlock(&slock);
|
||||
pthread_spin_lock(&slock);
|
||||
++count;
|
||||
_spunlock(&slock);
|
||||
pthread_spin_unlock(&slock);
|
||||
}
|
||||
++finished;
|
||||
STRACE("SpinlockWorker Finished %d", tid);
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(_spinlock, contention) {
|
||||
TEST(pthread_spin_lock, test) {
|
||||
int i;
|
||||
count = 0;
|
||||
started = 0;
|
||||
finished = 0;
|
||||
EXPECT_EQ(0, pthread_spin_init(&slock, 0));
|
||||
EXPECT_EQ(0, pthread_spin_trylock(&slock));
|
||||
EXPECT_EQ(EBUSY, pthread_spin_trylock(&slock));
|
||||
EXPECT_EQ(0, pthread_spin_unlock(&slock));
|
||||
EXPECT_EQ(0, pthread_spin_lock(&slock));
|
||||
EXPECT_EQ(EBUSY, pthread_spin_trylock(&slock));
|
||||
EXPECT_EQ(0, pthread_spin_unlock(&slock));
|
||||
for (i = 0; i < THREADS; ++i) {
|
||||
ASSERT_NE(-1, _spawn(SpinlockWorker, (void *)(intptr_t)i, th + i));
|
||||
}
|
||||
|
@ -210,12 +218,13 @@ TEST(_spinlock, contention) {
|
|||
EXPECT_EQ(THREADS, started);
|
||||
EXPECT_EQ(THREADS, finished);
|
||||
EXPECT_EQ(THREADS * ITERATIONS, count);
|
||||
EXPECT_EQ(0, pthread_spin_destroy(&slock));
|
||||
}
|
||||
|
||||
BENCH(pthread_mutex_lock, bench) {
|
||||
char schar = 0;
|
||||
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
EZBENCH2("_spinlock", donothing, _spinlock_contention());
|
||||
EZBENCH2("spin", donothing, pthread_spin_lock_test());
|
||||
EZBENCH2("normal", donothing, pthread_mutex_lock_contention());
|
||||
EZBENCH2("recursive", donothing, pthread_mutex_lock_rcontention());
|
||||
EZBENCH2("errorcheck", donothing, pthread_mutex_lock_econtention());
|
||||
|
|
54
test/libc/intrin/pthread_once_test.c
Normal file
54
test/libc/intrin/pthread_once_test.c
Normal file
|
@ -0,0 +1,54 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/atomic.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/thread/spawn.h"
|
||||
|
||||
int i, n;
|
||||
struct spawn *t;
|
||||
_Atomic(int) x, y;
|
||||
pthread_barrier_t b;
|
||||
|
||||
void InitFactory(void) {
|
||||
ASSERT_EQ(0, atomic_load(&x));
|
||||
atomic_fetch_add(&y, 1);
|
||||
}
|
||||
|
||||
int Worker(void *arg, int tid) {
|
||||
static pthread_once_t once = PTHREAD_ONCE_INIT;
|
||||
pthread_barrier_wait(&b);
|
||||
ASSERT_EQ(0, pthread_once(&once, InitFactory));
|
||||
ASSERT_EQ(1, atomic_load(&y));
|
||||
atomic_fetch_add(&x, 1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(pthread_once, test) {
|
||||
n = 32;
|
||||
x = y = 0;
|
||||
pthread_barrier_init(&b, 0, n);
|
||||
t = gc(malloc(sizeof(struct spawn) * n));
|
||||
for (i = 0; i < n; ++i) ASSERT_SYS(0, 0, _spawn(Worker, 0, t + i));
|
||||
for (i = 0; i < n; ++i) EXPECT_SYS(0, 0, _join(t + i));
|
||||
ASSERT_EQ(n, atomic_load(&x));
|
||||
ASSERT_EQ(1, atomic_load(&y));
|
||||
}
|
66
test/libc/intrin/pthread_rwlock_rdlock_test.c
Normal file
66
test/libc/intrin/pthread_rwlock_rdlock_test.c
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│
|
||||
│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│
|
||||
╞══════════════════════════════════════════════════════════════════════════════╡
|
||||
│ Copyright 2022 Justine Alexandra Roberts Tunney │
|
||||
│ │
|
||||
│ Permission to use, copy, modify, and/or distribute this software for │
|
||||
│ any purpose with or without fee is hereby granted, provided that the │
|
||||
│ above copyright notice and this permission notice appear in all copies. │
|
||||
│ │
|
||||
│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │
|
||||
│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │
|
||||
│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │
|
||||
│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │
|
||||
│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │
|
||||
│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │
|
||||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/mem/mem.h"
|
||||
#include "libc/runtime/gc.internal.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/thread/spawn.h"
|
||||
|
||||
#define ITERATIONS 50000
|
||||
#define READERS 8
|
||||
#define WRITERS 2
|
||||
|
||||
_Atomic(int) reads;
|
||||
_Atomic(int) writes;
|
||||
pthread_rwlock_t lock;
|
||||
pthread_barrier_t barrier;
|
||||
|
||||
int Reader(void *arg, int tid) {
|
||||
pthread_barrier_wait(&barrier);
|
||||
for (int i = 0; i < ITERATIONS; ++i) {
|
||||
pthread_rwlock_rdlock(&lock);
|
||||
++reads;
|
||||
pthread_rwlock_unlock(&lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Writer(void *arg, int tid) {
|
||||
pthread_barrier_wait(&barrier);
|
||||
for (int i = 0; i < ITERATIONS; ++i) {
|
||||
pthread_rwlock_wrlock(&lock);
|
||||
++writes;
|
||||
pthread_rwlock_unlock(&lock);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
TEST(pthread_rwlock_rdlock, test) {
|
||||
int i;
|
||||
struct spawn *t = gc(malloc(sizeof(struct spawn) * (READERS + WRITERS)));
|
||||
pthread_barrier_init(&barrier, 0, READERS + WRITERS);
|
||||
for (i = 0; i < READERS + WRITERS; ++i) {
|
||||
ASSERT_SYS(0, 0, _spawn(i < READERS ? Reader : Writer, 0, t + i));
|
||||
}
|
||||
for (i = 0; i < READERS + WRITERS; ++i) {
|
||||
EXPECT_SYS(0, 0, _join(t + i));
|
||||
}
|
||||
EXPECT_EQ(READERS * ITERATIONS, reads);
|
||||
EXPECT_EQ(WRITERS * ITERATIONS, writes);
|
||||
}
|
|
@ -44,8 +44,8 @@
|
|||
#define THREADS 8
|
||||
#define ENTRIES 1024
|
||||
|
||||
int ready;
|
||||
volatile uint64_t A[THREADS * ENTRIES];
|
||||
pthread_barrier_t barrier = PTHREAD_BARRIER_INITIALIZER;
|
||||
|
||||
void SetUpOnce(void) {
|
||||
__enable_threads();
|
||||
|
@ -62,9 +62,7 @@ dontinline void Generate(int i) {
|
|||
|
||||
int Thrasher(void *arg, int tid) {
|
||||
int i, id = (intptr_t)arg;
|
||||
while (!atomic_load(&ready)) {
|
||||
cthread_memory_wait32(&ready, 0, 0);
|
||||
}
|
||||
pthread_barrier_wait(&barrier);
|
||||
for (i = 0; i < ENTRIES; ++i) {
|
||||
Generate(id * ENTRIES + i);
|
||||
}
|
||||
|
@ -97,12 +95,10 @@ TEST(rand64, testThreadSafety_doesntProduceIdenticalValues) {
|
|||
sigemptyset(&ss);
|
||||
sigaddset(&ss, SIGCHLD);
|
||||
EXPECT_EQ(0, sigprocmask(SIG_BLOCK, &ss, &oldss));
|
||||
ready = false;
|
||||
pthread_barrier_init(&barrier, 0, THREADS);
|
||||
for (i = 0; i < THREADS; ++i) {
|
||||
ASSERT_SYS(0, 0, _spawn(Thrasher, (void *)(intptr_t)i, th + i));
|
||||
}
|
||||
atomic_store(&ready, 1);
|
||||
cthread_memory_wake32(&ready, INT_MAX);
|
||||
for (i = 0; i < THREADS; ++i) {
|
||||
ASSERT_SYS(0, 0, _join(th + i));
|
||||
}
|
||||
|
|
|
@ -16,18 +16,24 @@
|
|||
│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │
|
||||
│ PERFORMANCE OF THIS SOFTWARE. │
|
||||
╚─────────────────────────────────────────────────────────────────────────────*/
|
||||
#include "libc/calls/calls.h"
|
||||
#include "libc/errno.h"
|
||||
#include "libc/intrin/pthread.h"
|
||||
#include "libc/testlib/testlib.h"
|
||||
#include "libc/thread/thread.h"
|
||||
|
||||
/**
|
||||
* Yields current thread's remaining timeslice to operating system.
|
||||
* @return 0 on success, or error number on failure
|
||||
*/
|
||||
int pthread_yield(void) {
|
||||
if (sched_yield() != -1) {
|
||||
return 0;
|
||||
} else {
|
||||
return errno;
|
||||
}
|
||||
pthread_t thread;
|
||||
|
||||
static void *ReturnArg(void *arg) {
|
||||
return arg;
|
||||
}
|
||||
|
||||
TEST(pthread_create, testCreateReturnJoin) {
|
||||
void *exitcode;
|
||||
ASSERT_EQ(0, pthread_create(&thread, 0, ReturnArg, ReturnArg));
|
||||
ASSERT_EQ(0, pthread_join(thread, &exitcode));
|
||||
ASSERT_EQ(ReturnArg, exitcode);
|
||||
}
|
||||
|
||||
TEST(pthread_detach, testCreateReturn) {
|
||||
ASSERT_EQ(0, pthread_create(&thread, 0, ReturnArg, ReturnArg));
|
||||
ASSERT_EQ(0, pthread_detach(thread));
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue