regex memory corruption regression test
[libc-test] / src / regression / pthread_cond-smasher.c
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
5 #include <stdio.h>
6 #include <string.h>
7 #include <time.h>
8 #include <stdlib.h>
9 #include <errno.h>
10 #include "test.h"
11
12 # include <pthread.h>
13
14 # define VERSION "POSIX threads"
15
16 typedef pthread_mutex_t mutex;
17 typedef pthread_cond_t condition;
18 typedef pthread_t thread;
19 typedef void* thread_ret;
20
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
25
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
32
33
34 # define thread_create(ID, START, ARG) pthread_create(ID, 0, START, ARG)
35 # define thread_join pthread_join
36
37 # define gettime(TS) clock_gettime(CLOCK_REALTIME, (TS))
38
39 # define errorstring strerror
40
41 #ifdef __GLIBC__
42 # define LIBRARY "glibc"
43 #else
44 # define LIBRARY "unidentified"
45 #endif
46
47 #define trace2(L, ...) fprintf(stderr, __FILE__ ":" #L ": " __VA_ARGS__)
48 #define trace1(L, ...) trace2(L, __VA_ARGS__)
49 #ifdef DEBUG
50 # define trace(...) trace1(__LINE__, __VA_ARGS__)
51 #else
52 # define trace(...) do { if (0) trace1(__LINE__, __VA_ARGS__); } while (0)
53 #endif
54
55 //#define tell(...) trace1(__LINE__, __VA_ARGS__)
56 #define tell(...) trace(__VA_ARGS__)
57
58 enum {
59   phases = 10,
60   threads = 10,
61 };
62
63 static thread id[threads];
64 static unsigned args[threads];
65
66 static mutex mut[phases];
67 static unsigned inside[phases];
68
69 static condition cond_client;
70 static condition cond_main;
71 static unsigned volatile phase;
72
73 static void settimeout(struct timespec *ts)
74 {
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;
80     ts->tv_sec++;
81   }
82 }
83
84 static thread_ret client(void *arg) {
85   struct timespec ts;
86   unsigned * number = arg;
87   for (unsigned i = 0; i < phases; ++i) {
88     trace("thread %u in phase %u\n", *number, i);
89     mutex_lock(&mut[i]);
90     ++inside[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));
95       if (ret)
96         t_error("thread %u is last in phase %u, signalling main failed: %s\n", *number, i, errorstring(ret));
97     }
98     while (i == phase) {
99       tell("thread %u in phase %u (%u), waiting\n", *number, i, phase);
100       settimeout(&ts);
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));
103       if (ret) {
104         t_error("thread %u in phase %u (%u) finished waiting: %s\n", *number, i, phase, errorstring(ret));
105         exit(t_status);
106       }
107     }
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));
110     if (ret)
111       t_error("thread %u in phase %u (%u), failed to unlock: %s\n", *number, i, phase, errorstring(ret));
112   }
113   return 0;
114 }
115
116
117 int main(void) {
118   struct timespec ts;
119
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) {
124     mutex_init(&mut[i]);
125   }
126   mutex_lock(&mut[0]);
127
128   for (unsigned i = 0; i < threads; ++i) {
129     args[i] = i;
130     thread_create(&id[i], client, &args[i]);
131   }
132
133   while (phase < phases) {
134     while (inside[phase] < threads) {
135       trace("main seeing %u threads in phase %u, waiting\n", inside[phase], phase);
136       settimeout(&ts);
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));
139       if (ret) {
140         t_error("main thread in phase %u (%u threads inside), finished waiting: %s\n", phase, inside[phase], errorstring(ret));
141         return t_status;
142       }
143     }
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));
153     if (ret)
154       t_error("main broadcast in phase %u failed: %s\n", phase, errorstring(ret));
155     ++phase;
156     ret = mutex_unlock(&mut[phase-1]);
157     trace("main has unlocked mutex %u: %s\n", phase-1, errorstring(ret));
158     if (ret)
159       t_error("main failed to unlock mutex %u: %s\n", phase-1, errorstring(ret));
160   }
161
162
163
164   trace("main finished loop\n");
165
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));
170     if (ret)
171       t_error("main failed join thread %u: %s\n", i, errorstring(ret));
172   }
173
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]);
178   }
179   condition_destroy(&cond_main);
180   condition_destroy(&cond_client);
181
182   tell("shut down of main, using %s, library %s\n", VERSION, LIBRARY);
183
184   return t_status;
185 }