1 /*
2 * Copyright (c) 2004, Bull S.A.. All rights reserved.
3 * Created by: Sebastien Decugis
4
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of version 2 of the GNU General Public License as
7 * published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope that it would be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16
17 * This stress test aims to test the following assertion:
18 * -> pthread_self() returns the thread ID of the calling thread.
19 * Therefore, it never returns the same value for 2 different running threads.
20
21 * The steps are:
22 * -> Create some threads with different parameters
23 * -> Get the threads IDs
24 * -> Compare all the threads IDs to find duplicates.
25
26 */
27
28 /********************************************************************************************/
29 /****************************** standard includes *****************************************/
30 /********************************************************************************************/
31 #include <pthread.h>
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37
38 #include <semaphore.h>
39 #include <errno.h>
40 #include <signal.h>
41
42 /********************************************************************************************/
43 /****************************** Test framework *****************************************/
44 /********************************************************************************************/
45 #include "testfrmw.h"
46 #include "testfrmw.c"
47 /* This header is responsible for defining the following macros:
48 * UNRESOLVED(ret, descr);
49 * where descr is a description of the error and ret is an int (error code for example)
50 * FAILED(descr);
51 * where descr is a short text saying why the test has failed.
52 * PASSED();
53 * No parameter.
54 *
55 * Both three macros shall terminate the calling process.
56 * The testcase shall not terminate in any other maneer.
57 *
58 * The other file defines the functions
59 * void output_init()
60 * void output(char * string, ...)
61 *
62 * Those may be used to output information.
63 */
64
65 /********************************************************************************************/
66 /********************************** Configuration ******************************************/
67 /********************************************************************************************/
68 #ifndef VERBOSE
69 #define VERBOSE 1
70 #endif
71
72 /********************************************************************************************/
73 /*********************************** Test cases *****************************************/
74 /********************************************************************************************/
75
76 #include "threads_scenarii.c"
77
78 /* This file will define the following objects:
79 * scenarii: array of struct __scenario type.
80 * NSCENAR : macro giving the total # of scenarii
81 * scenar_init(): function to call before use the scenarii array.
82 * scenar_fini(): function to call after end of use of the scenarii array.
83 */
84
85 /********************************************************************************************/
86 /*********************************** Real Test *****************************************/
87 /********************************************************************************************/
88
89 char do_it = 1;
90 long long iterations = 0;
91
92 /* Handler for user request to terminate */
sighdl(int sig)93 void sighdl(int sig)
94 {
95 /* do_it = 0 */
96 do {
97 do_it = 0;
98 }
99 while (do_it);
100 }
101
102 /* Protect concurrent access to the shared data */
103 pthread_mutex_t m_synchro = PTHREAD_MUTEX_INITIALIZER;
104
105 /* Signaled when all threads are running */
106 pthread_cond_t c_synchro = PTHREAD_COND_INITIALIZER;
107 int c_boolean;
108
109 /* Thread ID returned by pthread_self */
110 pthread_t running[NSCENAR];
111
112 /* Thread function */
threaded(void * arg)113 void *threaded(void *arg)
114 {
115 int ret = 0;
116 int me = *(int *)arg;
117
118 #if VERBOSE > 6
119 output("[child%d] starting\n", me);
120 #endif
121 /* Wait for all threads being created */
122 ret = pthread_mutex_lock(&m_synchro);
123 if (ret != 0) {
124 UNRESOLVED(ret, "Mutex lock failed");
125 }
126 #if VERBOSE > 6
127 output("[child%d] got mutex\n", me);
128 #endif
129
130 running[me] = pthread_self();
131
132 /* Signal we're running */
133 do {
134 ret = sem_post(&scenarii[me].sem);
135 }
136 while ((ret == -1) && (errno == EINTR));
137 if (ret == -1) {
138 UNRESOLVED(errno, "Failed to post the semaphore");
139 }
140 #if VERBOSE > 6
141 output("[child%d] posted semaphore %p\n", me, &scenarii[me].sem);
142 #endif
143
144 while (!c_boolean) {
145 ret = pthread_cond_wait(&c_synchro, &m_synchro);
146 if (ret != 0) {
147 UNRESOLVED(ret, "Failed to wait the condvar");
148 }
149 #if VERBOSE > 6
150 output("[child%d] awaken\n", me);
151 #endif
152 }
153
154 ret = pthread_mutex_unlock(&m_synchro);
155 if (ret != 0) {
156 UNRESOLVED(ret, "Mutex unlock failed");
157 }
158 #if VERBOSE > 6
159 output("[child%d] exiting\n", me);
160 #endif
161
162 return arg;
163 }
164
165 /* Main function */
main(int argc,char * argv[])166 int main(int argc, char *argv[])
167 {
168 int ret = 0;
169 struct sigaction sa;
170
171 pthread_t creation[NSCENAR]; /* Thread ID returned in pthread_create */
172 int status[NSCENAR]; /* Status of thread creation */
173 int ids[NSCENAR];
174
175 int i;
176
177 for (sc = 0; sc < NSCENAR; sc++)
178 ids[sc] = sc;
179
180 /* Initialize output routine */
181 output_init();
182
183 /* Initialize thread attribute objects */
184 scenar_init();
185
186 /* Register the signal handler for SIGUSR1 */
187 sigemptyset(&sa.sa_mask);
188 sa.sa_flags = 0;
189 sa.sa_handler = sighdl;
190 if ((ret = sigaction(SIGUSR1, &sa, NULL))) {
191 UNRESOLVED(ret, "Unable to register signal handler");
192 }
193 if ((ret = sigaction(SIGALRM, &sa, NULL))) {
194 UNRESOLVED(ret, "Unable to register signal handler");
195 }
196 #if VERBOSE > 1
197 output("[parent] Signal handler registered\n");
198 #endif
199
200 while (do_it) {
201 /* Initialize the shared data */
202 c_boolean = 0;
203
204 /* Create all the threads */
205 for (sc = 0; sc < NSCENAR; sc++) {
206 /* Create the thread */
207 status[sc] =
208 pthread_create(&creation[sc], &scenarii[sc].ta,
209 threaded, &ids[sc]);
210
211 /* Check creation status */
212 switch (scenarii[sc].result) {
213 case 0: /* Operation was expected to succeed */
214 if (status[sc] != 0) {
215 UNRESOLVED(ret,
216 "Failed to create this thread");
217 }
218 break;
219
220 case 1: /* Operation was expected to fail */
221 if (status[sc] == 0) {
222 UNRESOLVED(-1,
223 "An error was expected but the thread creation succeeded");
224 }
225 break;
226
227 case 2: /* We did not know the expected result */
228 default:
229 /* Nothing */
230 ;
231 }
232 }
233 #if VERBOSE > 6
234 output("[parent] threads created\n");
235 #endif
236
237 /* Now wait that all threads are running */
238 for (sc = 0; sc < NSCENAR; sc++) {
239 if (status[sc] == 0) { /* The new thread is running */
240 #if VERBOSE > 6
241 output("[parent] Waiting for thread %d: %p\n",
242 sc, &scenarii[sc].sem);
243 #endif
244 do {
245 ret = sem_wait(&scenarii[sc].sem);
246 }
247 while ((ret == -1) && (errno == EINTR));
248 if (ret == -1) {
249 UNRESOLVED(errno,
250 "Failed to wait for the semaphore");
251 }
252 }
253 }
254
255 #if VERBOSE > 6
256 output("[parent] Locking the mutex\n");
257 #endif
258
259 ret = pthread_mutex_lock(&m_synchro);
260 if (ret != 0) {
261 UNRESOLVED(ret, "Mutex lock failed");
262 }
263
264 /* Now, we've got all shared data set, so we can seek for duplicates */
265 for (sc = 0; sc < NSCENAR; sc++) {
266 if (status[sc] != 0) /* The new thread is running */
267 continue;
268
269 if (pthread_equal(creation[sc], running[sc]) == 0) {
270 output("pthread_create returned an ID of %p\n",
271 creation[sc]);
272 output
273 ("pthread_self in the thread returned %p\n",
274 running[sc]);
275 FAILED("Error: Values mismatch");
276 }
277
278 for (i = sc + 1; i < NSCENAR; i++) {
279 if (status[i] != 0)
280 continue;
281
282 if (pthread_equal(creation[sc], creation[i])) {
283 FAILED
284 ("Two different running threads have the same ID");
285 }
286 }
287 }
288 #if VERBOSE > 6
289 output("[parent] No duplicate found\n");
290 #endif
291
292 /* We're done, we can terminate the threads */
293 c_boolean = 1;
294 ret = pthread_mutex_unlock(&m_synchro);
295 if (ret != 0) {
296 UNRESOLVED(ret, "Mutex unlock failed");
297 }
298
299 ret = pthread_cond_broadcast(&c_synchro);
300 if (ret != 0) {
301 UNRESOLVED(ret, "Failed to broadcast the cond");
302 }
303 #if VERBOSE > 6
304 output("[parent] Cond broadcasted\n");
305 #endif
306
307 /* Join the joinable threads */
308 for (sc = 0; sc < NSCENAR; sc++) {
309 if (status[sc] != 0) /* The new thread is running */
310 continue;
311
312 if (scenarii[sc].detached == 0) {
313 #if VERBOSE > 6
314 output("[parent] Joining %d\n", sc);
315 #endif
316 ret = pthread_join(creation[sc], NULL);
317 if (ret != 0) {
318 UNRESOLVED(ret,
319 "Unalbe to join a thread");
320 }
321 #if VERBOSE > 6
322 output("[parent] Joined %d\n", sc);
323 #endif
324 }
325
326 }
327 iterations++;
328 }
329
330 /* We've been asked to stop */
331
332 scenar_fini();
333
334 output("pthread_exit stress test PASSED -- %llu iterations\n",
335 iterations);
336
337 PASSED;
338 }
339