9a9b91c940
It's finally done.. Signed-off-by: kaguya <vpshinomiya@protonmail.com>
109 lines
2.8 KiB
C
109 lines
2.8 KiB
C
#include <assert.h>
|
|
#include <errno.h>
|
|
#include <pthread.h>
|
|
#include <unistd.h>
|
|
|
|
_Atomic int waiting, should_exit;
|
|
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
|
|
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
static void *worker(void *arg) {
|
|
(void)arg;
|
|
pthread_mutex_lock(&mtx);
|
|
++waiting;
|
|
while (!should_exit)
|
|
pthread_cond_wait(&cond, &mtx);
|
|
pthread_mutex_unlock(&mtx);
|
|
return NULL;
|
|
}
|
|
|
|
static void test_broadcast_wakes_all() {
|
|
pthread_t t1, t2;
|
|
pthread_create(&t1, NULL, &worker, NULL);
|
|
pthread_create(&t2, NULL, &worker, NULL);
|
|
|
|
// Wait until the workers have actually entered the cond_wait
|
|
// before doing a broadcast.
|
|
while (waiting != 2 || pthread_mutex_trylock(&mtx) == EBUSY)
|
|
usleep(150000); // 150ms
|
|
|
|
should_exit = 1;
|
|
assert(!pthread_cond_broadcast(&cond));
|
|
pthread_mutex_unlock(&mtx);
|
|
|
|
pthread_join(t1, NULL);
|
|
pthread_join(t2, NULL);
|
|
}
|
|
|
|
static void test_timedwait_timedout() {
|
|
// Use CLOCK_MONOTONIC.
|
|
pthread_condattr_t attr;
|
|
pthread_condattr_init(&attr);
|
|
assert(!pthread_condattr_setclock(&attr, CLOCK_MONOTONIC));
|
|
|
|
struct timespec before_now;
|
|
assert(!clock_gettime(CLOCK_MONOTONIC, &before_now));
|
|
before_now.tv_nsec -= 10000;
|
|
|
|
pthread_mutex_lock(&mtx);
|
|
int e = pthread_cond_timedwait(&cond, &mtx, &before_now);
|
|
assert(e == ETIMEDOUT);
|
|
pthread_mutex_unlock(&mtx);
|
|
|
|
long nanos_per_second = 1000000000;
|
|
struct timespec after_now;
|
|
assert(!clock_gettime(CLOCK_MONOTONIC, &after_now));
|
|
after_now.tv_nsec += nanos_per_second / 10; // 100ms
|
|
if (after_now.tv_nsec >= nanos_per_second) {
|
|
after_now.tv_nsec -= nanos_per_second;
|
|
after_now.tv_sec++;
|
|
}
|
|
|
|
pthread_mutex_lock(&mtx);
|
|
e = pthread_cond_timedwait(&cond, &mtx, &after_now);
|
|
assert(e == ETIMEDOUT);
|
|
pthread_mutex_unlock(&mtx);
|
|
|
|
after_now.tv_nsec += nanos_per_second;
|
|
pthread_mutex_lock(&mtx);
|
|
e = pthread_cond_timedwait(&cond, &mtx, &after_now);
|
|
assert(e == EINVAL);
|
|
pthread_mutex_unlock(&mtx);
|
|
}
|
|
|
|
static void test_attr() {
|
|
pthread_condattr_t attr;
|
|
pthread_condattr_init(&attr);
|
|
|
|
clockid_t clock;
|
|
assert(!pthread_condattr_getclock(&attr, &clock));
|
|
assert(clock == CLOCK_REALTIME);
|
|
assert(!pthread_condattr_setclock(&attr, CLOCK_MONOTONIC));
|
|
assert(!pthread_condattr_getclock(&attr, &clock));
|
|
assert(clock == CLOCK_MONOTONIC);
|
|
|
|
int pshared;
|
|
assert(!pthread_condattr_getpshared(&attr, &pshared));
|
|
assert(pshared == PTHREAD_PROCESS_PRIVATE);
|
|
assert(!pthread_condattr_setpshared(&attr, PTHREAD_PROCESS_SHARED));
|
|
assert(!pthread_condattr_getpshared(&attr, &pshared));
|
|
assert(pshared == PTHREAD_PROCESS_SHARED);
|
|
|
|
pthread_condattr_destroy(&attr);
|
|
pthread_condattr_init(&attr);
|
|
|
|
// Make sure that we can create a pthread_cond_t with an attr.
|
|
pthread_cond_t cond;
|
|
pthread_cond_init(&cond, &attr);
|
|
pthread_cond_destroy(&cond);
|
|
pthread_condattr_destroy(&attr);
|
|
}
|
|
|
|
int main() {
|
|
test_attr();
|
|
test_broadcast_wakes_all();
|
|
test_timedwait_timedout();
|
|
|
|
return 0;
|
|
}
|