]> git.saurik.com Git - apple/libpthread.git/blob - tests/rwlock-signal.c
libpthread-218.1.3.tar.gz
[apple/libpthread.git] / tests / rwlock-signal.c
1 #include <assert.h>
2 #include <pthread.h>
3 #include <signal.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <string.h>
7 #include <unistd.h>
8 #include <stdbool.h>
9 #include <errno.h>
10
11 struct context {
12 pthread_rwlock_t rwlock;
13 long value;
14 long count;
15 };
16
17 void mask_signals(bool masked, bool perthread)
18 {
19 sigset_t mask;
20
21 if (masked) {
22 sigfillset(&mask);
23 sigdelset(&mask, SIGINT);
24 } else {
25 sigemptyset(&mask);
26 sigaddset(&mask, SIGWINCH);
27 }
28
29 int action = (masked ? SIG_BLOCK : SIG_UNBLOCK);
30 if (perthread) {
31 pthread_sigmask(action, &mask, NULL);
32 } else {
33 sigprocmask(action, &mask, NULL);
34 }
35 }
36
37 void test_signal(int signo)
38 {
39 /* nothing */
40 }
41
42 void *test_signal_thread(void *ptr)
43 {
44 sigset_t mask;
45 sigfillset(&mask);
46 sigdelset(&mask, SIGWINCH);
47 pthread_sigmask(SIG_BLOCK, &mask, NULL);
48
49 struct context *context = ptr;
50 do {
51 usleep(100);
52 kill(getpid(), SIGWINCH);
53 } while (context->count > 0);
54
55 return NULL;
56 }
57
58 void *test_thread(void *ptr) {
59 int res;
60 long old;
61 struct context *context = ptr;
62
63 int i = 0;
64 char *str;
65
66 mask_signals(false, true);
67
68 do {
69 bool try = i & 1;
70 bool exclusive = i & 2;
71 switch (i++ & 3) {
72 case 0:
73 str = "pthread_rwlock_rdlock";
74 res = pthread_rwlock_rdlock(&context->rwlock);
75 break;
76 case 1:
77 str = "pthread_rwlock_tryrdlock";
78 res = pthread_rwlock_tryrdlock(&context->rwlock);
79 break;
80 case 2:
81 str = "pthread_rwlock_wrlock";
82 res = pthread_rwlock_wrlock(&context->rwlock);
83 break;
84 case 3:
85 str = "pthread_rwlock_trywrlock";
86 res = pthread_rwlock_trywrlock(&context->rwlock);
87 break;
88 }
89 if (res != 0) {
90 if (try && res == EBUSY) {
91 continue;
92 }
93 fprintf(stderr, "[%ld] %s: %s\n", context->count, str, strerror(res));
94 abort();
95 }
96
97 if (exclusive) {
98 old = __sync_fetch_and_or(&context->value, 1);
99 if ((old & 1) != 0) {
100 fprintf(stderr, "[%ld] OR %lx\n", context->count, old);
101 abort();
102 }
103 }
104
105 old = __sync_fetch_and_and(&context->value, 0);
106 if ((old & 1) != (exclusive ? 1 : 0)) {
107 fprintf(stderr, "[%ld] AND %lx\n", context->count, old);
108 abort();
109 }
110
111 res = pthread_rwlock_unlock(&context->rwlock);
112 if (res) {
113 fprintf(stderr, "[%ld] pthread_rwlock_unlock: %s\n", context->count, strerror(res));
114 abort();
115 }
116 } while (__sync_fetch_and_sub(&context->count, 1) > 0);
117
118 return NULL;
119 }
120
121 int main(int argc, char *argv[])
122 {
123 struct context context = {
124 .rwlock = PTHREAD_RWLOCK_INITIALIZER,
125 .value = 0,
126 .count = 5000000,
127 };
128 int i;
129 int res;
130 int threads = 16;
131 pthread_t p[threads+1];
132
133 mask_signals(true, false);
134 signal(SIGWINCH, test_signal);
135
136 for (i = 0; i < threads; ++i) {
137 res = pthread_create(&p[i], NULL, test_thread, &context);
138 assert(res == 0);
139 }
140
141 pthread_create(&p[threads], NULL, test_signal_thread, &context);
142 assert(res == 0);
143
144 for (i = 0; i < threads; ++i) {
145 res = pthread_join(p[i], NULL);
146 assert(res == 0);
147 }
148 res = pthread_join(p[threads], NULL);
149 assert(res == 0);
150
151 return 0;
152 }