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