cosmopolitan/test/posix/mutex_async_signal_safety_test.c
2024-07-22 16:35:29 -07:00

82 lines
1.6 KiB
C

#include <pthread.h>
#include <signal.h>
#include <stdatomic.h>
#include <stdbool.h>
#include <stdlib.h>
#include <unistd.h>
// tests that recursive mutexes are implemented atomically
//
// glibc fails this test
atomic_bool done;
atomic_bool ready;
pthread_mutex_t lock;
void hand(int sig) {
if (pthread_mutex_lock(&lock))
_Exit(50);
if (pthread_mutex_unlock(&lock))
_Exit(51);
}
void* work(void* arg) {
ready = true;
while (!done) {
if (pthread_mutex_lock(&lock))
_Exit(60);
if (pthread_mutex_unlock(&lock))
_Exit(61);
}
return 0;
}
int main() {
struct sigaction sa;
sa.sa_handler = hand;
sa.sa_flags = SA_NODEFER;
sigemptyset(&sa.sa_mask);
if (sigaction(SIGUSR1, &sa, 0))
_Exit(1);
pthread_mutexattr_t attr;
if (pthread_mutexattr_init(&attr))
_Exit(2);
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
_Exit(3);
if (pthread_mutex_init(&lock, &attr))
_Exit(4);
if (pthread_mutexattr_destroy(&attr))
_Exit(5);
pthread_t th;
pthread_attr_t tattr;
if (pthread_attr_init(&tattr))
_Exit(6);
if (pthread_attr_setstacksize(&tattr, 8 * 1024 * 1024))
_Exit(7);
if (pthread_attr_setguardsize(&tattr, 64 * 1024))
_Exit(8);
if (pthread_create(&th, &tattr, work, 0))
_Exit(9);
if (pthread_attr_destroy(&tattr))
_Exit(10);
for (;;)
if (ready)
break;
for (int i = 0; i < 100; ++i) {
if (pthread_kill(th, SIGUSR1))
_Exit(11);
if (pthread_kill(th, SIGUSR1))
_Exit(12);
usleep(1);
}
done = true;
if (pthread_join(th, 0))
_Exit(13);
if (pthread_mutex_destroy(&lock))
_Exit(14);
}