Skip to content

Commit fdab49b

Browse files
committed
Demonstrate signal safety of recursive mutexes
1 parent 135d538 commit fdab49b

File tree

2 files changed

+112
-0
lines changed

2 files changed

+112
-0
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#include <pthread.h>
2+
#include <stdatomic.h>
3+
#include <stdbool.h>
4+
#include <stdlib.h>
5+
6+
atomic_bool ready;
7+
8+
void* work(void* arg) {
9+
pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, 0);
10+
ready = true;
11+
pthread_exit(0);
12+
}
13+
14+
int main() {
15+
16+
for (int i = 0; i < 1000; ++i) {
17+
pthread_t th;
18+
if (pthread_create(&th, 0, work, 0))
19+
_Exit(1);
20+
for (;;)
21+
if (ready)
22+
break;
23+
pthread_cancel(th);
24+
if (pthread_join(th, 0))
25+
_Exit(3);
26+
}
27+
28+
while (!pthread_orphan_np())
29+
pthread_decimate_np();
30+
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
#include <pthread.h>
2+
#include <signal.h>
3+
#include <stdatomic.h>
4+
#include <stdbool.h>
5+
#include <stdlib.h>
6+
#include <unistd.h>
7+
8+
// tests that recursive mutexes are implemented atomically
9+
//
10+
// glibc fails this test
11+
12+
atomic_bool done;
13+
atomic_bool ready;
14+
pthread_mutex_t lock;
15+
16+
void hand(int sig) {
17+
if (pthread_mutex_lock(&lock))
18+
_Exit(50);
19+
if (pthread_mutex_unlock(&lock))
20+
_Exit(51);
21+
}
22+
23+
void* work(void* arg) {
24+
ready = true;
25+
while (!done) {
26+
if (pthread_mutex_lock(&lock))
27+
_Exit(60);
28+
if (pthread_mutex_unlock(&lock))
29+
_Exit(61);
30+
}
31+
return 0;
32+
}
33+
34+
int main() {
35+
36+
struct sigaction sa;
37+
sa.sa_handler = hand;
38+
sa.sa_flags = SA_NODEFER;
39+
sigemptyset(&sa.sa_mask);
40+
if (sigaction(SIGUSR1, &sa, 0))
41+
_Exit(1);
42+
43+
pthread_mutexattr_t attr;
44+
if (pthread_mutexattr_init(&attr))
45+
_Exit(2);
46+
if (pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE))
47+
_Exit(3);
48+
if (pthread_mutex_init(&lock, &attr))
49+
_Exit(4);
50+
if (pthread_mutexattr_destroy(&attr))
51+
_Exit(5);
52+
53+
pthread_t th;
54+
pthread_attr_t tattr;
55+
if (pthread_attr_init(&tattr))
56+
_Exit(6);
57+
if (pthread_attr_setstacksize(&tattr, 8 * 1024 * 1024))
58+
_Exit(7);
59+
if (pthread_attr_setguardsize(&tattr, 64 * 1024))
60+
_Exit(8);
61+
if (pthread_create(&th, &tattr, work, 0))
62+
_Exit(9);
63+
if (pthread_attr_destroy(&tattr))
64+
_Exit(10);
65+
for (;;)
66+
if (ready)
67+
break;
68+
69+
for (int i = 0; i < 1000; ++i) {
70+
if (pthread_kill(th, SIGUSR1))
71+
_Exit(11);
72+
if (pthread_kill(th, SIGUSR1))
73+
_Exit(12);
74+
usleep(1);
75+
}
76+
77+
done = true;
78+
if (pthread_join(th, 0))
79+
_Exit(13);
80+
if (pthread_mutex_destroy(&lock))
81+
_Exit(14);
82+
}

0 commit comments

Comments
 (0)