1 // by Jens Gustedt from http://www.openwall.com/lists/musl/2014/08/11/1
2 // c11 threads test was removed and t_error messages were added
3 // the test deadlocks with a broken cond var implementation so
4 // cond_waits were changed to cond_timedwaits with short timeout
14 # define VERSION "POSIX threads"
16 typedef pthread_mutex_t mutex
;
17 typedef pthread_cond_t condition
;
18 typedef pthread_t thread
;
19 typedef void* thread_ret
;
21 # define mutex_init(M) pthread_mutex_init((M), 0)
22 # define mutex_destroy pthread_mutex_destroy
23 # define mutex_lock pthread_mutex_lock
24 # define mutex_unlock pthread_mutex_unlock
26 # define condition_init(C) pthread_cond_init((C), 0)
27 # define condition_destroy pthread_cond_destroy
28 # define condition_wait pthread_cond_wait
29 # define condition_timedwait pthread_cond_timedwait
30 # define condition_signal pthread_cond_signal
31 # define condition_broadcast pthread_cond_broadcast
34 # define thread_create(ID, START, ARG) pthread_create(ID, 0, START, ARG)
35 # define thread_join pthread_join
37 # define gettime(TS) clock_gettime(CLOCK_REALTIME, (TS))
39 # define errorstring strerror
42 # define LIBRARY "glibc"
44 # define LIBRARY "unidentified"
47 #define trace2(L, ...) fprintf(stderr, __FILE__ ":" #L ": " __VA_ARGS__)
48 #define trace1(L, ...) trace2(L, __VA_ARGS__)
50 # define trace(...) trace1(__LINE__, __VA_ARGS__)
52 # define trace(...) do { if (0) trace1(__LINE__, __VA_ARGS__); } while (0)
55 //#define tell(...) trace1(__LINE__, __VA_ARGS__)
56 #define tell(...) trace(__VA_ARGS__)
63 static thread id
[threads
];
64 static unsigned args
[threads
];
66 static mutex mut
[phases
];
67 static unsigned inside
[phases
];
69 static condition cond_client
;
70 static condition cond_main
;
71 static unsigned volatile phase
;
73 static void settimeout(struct timespec
*ts
)
75 if (clock_gettime(CLOCK_REALTIME
, ts
))
76 t_error("clock_gettime failed: %s\n", strerror(errno
));
77 ts
->tv_nsec
+= 500*1000*1000;
78 if (ts
->tv_nsec
>= 1000*1000*1000) {
79 ts
->tv_nsec
-= 1000*1000*1000;
84 static thread_ret
client(void *arg
) {
86 unsigned * number
= arg
;
87 for (unsigned i
= 0; i
< phases
; ++i
) {
88 trace("thread %u in phase %u\n", *number
, i
);
91 if (inside
[i
] == threads
) {
92 trace("thread %u is last, signalling main\n", *number
);
93 int ret
= condition_signal(&cond_main
);
94 trace("thread %u is last, signalling main, %s\n", *number
, errorstring(ret
));
96 t_error("thread %u is last in phase %u, signalling main failed: %s\n", *number
, i
, errorstring(ret
));
99 tell("thread %u in phase %u (%u), waiting\n", *number
, i
, phase
);
101 int ret
= condition_timedwait(&cond_client
, &mut
[i
], &ts
);
102 trace("thread %u in phase %u (%u), finished, %s\n", *number
, i
, phase
, errorstring(ret
));
104 t_error("thread %u in phase %u (%u) finished waiting: %s\n", *number
, i
, phase
, errorstring(ret
));
108 int ret
= mutex_unlock(&mut
[i
]);
109 trace("thread %u in phase %u (%u), has unlocked mutex: %s\n", *number
, i
, phase
, errorstring(ret
));
111 t_error("thread %u in phase %u (%u), failed to unlock: %s\n", *number
, i
, phase
, errorstring(ret
));
120 tell("start up of main, using %s, library %s\n", VERSION
, LIBRARY
);
121 condition_init(&cond_client
);
122 condition_init(&cond_main
);
123 for (unsigned i
= 0; i
< phases
; ++i
) {
128 for (unsigned i
= 0; i
< threads
; ++i
) {
130 thread_create(&id
[i
], client
, &args
[i
]);
133 while (phase
< phases
) {
134 while (inside
[phase
] < threads
) {
135 trace("main seeing %u threads in phase %u, waiting\n", inside
[phase
], phase
);
137 int ret
= condition_timedwait(&cond_main
, &mut
[phase
], &ts
);
138 tell("main seeing %u threads in phase %u, %s\n", inside
[phase
], phase
, errorstring(ret
));
140 t_error("main thread in phase %u (%u threads inside), finished waiting: %s\n", phase
, inside
[phase
], errorstring(ret
));
144 /* now we know that everybody is waiting inside, lock the next
145 mutex, if any, such that nobody can enter the next phase
146 without our permission. */
147 if (phase
< phases
-1)
148 mutex_lock(&mut
[phase
+1]);
149 /* Now signal all clients, update the phase count and release the
150 mutex they are waiting for. */
151 int ret
= condition_broadcast(&cond_client
);
152 trace("main has broadcast to %u: %s\n", phase
, errorstring(ret
));
154 t_error("main broadcast in phase %u failed: %s\n", phase
, errorstring(ret
));
156 ret
= mutex_unlock(&mut
[phase
-1]);
157 trace("main has unlocked mutex %u: %s\n", phase
-1, errorstring(ret
));
159 t_error("main failed to unlock mutex %u: %s\n", phase
-1, errorstring(ret
));
164 trace("main finished loop\n");
166 for (unsigned i
= 0; i
< threads
; ++i
) {
167 trace("main joining thread %u\n", i
);
168 int ret
= thread_join(id
[i
], &(thread_ret
){0});
169 trace("main joining thread %u: %s\n", i
, errorstring(ret
));
171 t_error("main failed join thread %u: %s\n", i
, errorstring(ret
));
174 /* C functions to destroy the control structures don't return error
175 information, so we can't check for errors, here. */
176 for (unsigned i
= 0; i
< phases
; ++i
) {
177 mutex_destroy(&mut
[i
]);
179 condition_destroy(&cond_main
);
180 condition_destroy(&cond_client
);
182 tell("shut down of main, using %s, library %s\n", VERSION
, LIBRARY
);