1 /*
2 * Copyright (C) Bull S.A. 2001
3 * Copyright (c) International Business Machines Corp., 2001
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13 * the GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 /******************************************************************************/
21 /* */
22 /* Dec-03-2001 Created: Jacky Malcles & Jean Noel Cordenner */
23 /* These tests are adapted from AIX float PVT tests. */
24 /* */
25 /******************************************************************************/
26 #include "tfloat.h"
27
28 #include "test.h"
29
30 #define SAFE_FREE(p) { if (p) { free(p); (p)=NULL; } }
31 /* LTP status reporting */
32 char *TCID; /* Test program identifier. */
33 int TST_TOTAL = 1; /* Total number of test cases. */
34
35 /* To avoid extensive modifications to the code, use this bodge */
36 #define exit(x) myexit(x)
37
myexit(int x)38 void myexit(int x)
39 {
40 if (x)
41 tst_resm(TFAIL, "Test failed");
42 else
43 tst_resm(TPASS, "Test passed");
44 tst_exit();
45 }
46
47 TH_DATA *pcom;
48 TH_DATA **tabcom;
49 TH_DATA **tabcour;
50 #ifndef PATH_MAX
51 #define PATH_MAX 1024
52 #endif
53 char datadir[PATH_MAX]; /* DATA directory */
54
55 #ifndef PTHREAD_THREADS_MAX
56 #define PTHREAD_THREADS_MAX 1024
57 #endif
58 #define DEFAULT_NUM_THREADS 20
59 int num_threads = DEFAULT_NUM_THREADS;
60 int num_loops = 500;
61
62 int sig_cancel = 0; /* flag set by handle_signals to tell initial thread
63 to stop creating new threads (signal caught) */
64
65 int indice = 0; /* # of threads created, to be canceled by handle_signals
66 or waited for by initial thread */
67
68 pthread_mutex_t sig_mutex;
69 pthread_t *threads;
70
71 int debug = 0;
72 int true = 1;
73
74 static void *handle_signals(void *);
75
76 static void sys_error(const char *, int);
77
78 const double EPS = 0.1e-300;
79
80 const int nb_func = NB_FUNC;
81
generate(char * datadir,char * bin_path)82 int generate(char *datadir, char *bin_path)
83 {
84 char *cmdline;
85 char *fmt = "cd %s; %s/%s %s";
86
87 cmdline = malloc(2 * strlen(bin_path) + strlen(datadir) + strlen(GENERATOR) + strlen(fmt));
88 if (cmdline == NULL)
89 return (1);
90 sprintf(cmdline, fmt, datadir, bin_path, GENERATOR, bin_path);
91 system(cmdline);
92 free(cmdline);
93 return (0);
94 }
95
cleanup(void)96 static void cleanup(void)
97 {
98 tst_rmdir();
99 }
100
main(int argc,char * argv[])101 int main(int argc, char *argv[])
102 {
103 int opt = 0;
104 pid_t pid;
105
106 char *bin_path, *ltproot;
107 void *exit_value;
108 pthread_attr_t newattr;
109 pthread_t sig_hand;
110 size_t stacksize = 2093056;
111 int th_num;
112 int retvalend = 0;
113 int retval = 0;
114 int error = 0;
115 /*int time=1; */
116 int i;
117
118 /* Generate test ID from invocation name */
119 if ((TCID = strrchr(argv[0], '/')) != NULL)
120 TCID++;
121 else
122 TCID = argv[0];
123 ltproot = getenv("LTPROOT");
124 if (ltproot == NULL || strlen(ltproot) == 0) {
125 tst_brkm(TBROK, NULL,
126 "You must set $LTPROOT before executing this test");
127 }
128 bin_path = malloc(strlen(ltproot) + 16);
129 if (bin_path == NULL) {
130 tst_brkm(TBROK | TERRNO, NULL, "malloc failed");
131 }
132 sprintf(bin_path, "%s/testcases/bin", ltproot);
133
134 tst_tmpdir();
135
136 setbuf(stdout, NULL);
137 setbuf(stderr, NULL);
138 datadir[0] = '.';
139 datadir[1] = '\0';
140
141 if (argc != 1) {
142 while ((opt = getopt(argc, argv, "vn:l:D:?")) != EOF) {
143 switch (opt) {
144 case 'D':
145 strncpy(datadir, optarg, PATH_MAX);
146 break;
147 case 'l':
148 num_loops = atoi(optarg);
149 break;
150 case 'n':
151 num_threads = atoi(optarg);
152 break;
153 case 'v':
154 ++debug; /* verbose mode */
155 break;
156 default:
157 fprintf(stderr,
158 "usage: %s [-n number_of_threads] [-v]\n",
159 argv[0]);
160 fprintf(stderr, "[-l number_of_loops] ");
161 fprintf(stderr, "[-D DATAs absolute path]\n");
162 exit(1);
163 }
164 }
165 }
166 switch (pid = fork()) {
167 case -1:
168 tst_brkm(TBROK | TERRNO, cleanup, "fork failed");
169 case 0:
170 generate(datadir, bin_path);
171 exit(0);
172 default:
173 waitpid(pid, NULL, 0);
174 }
175 SAFE_FREE(bin_path);
176
177 if (debug) {
178 tst_resm(TINFO,
179 "%s: will run for %d loops; using %s as a data directory",
180 argv[0], num_loops, datadir);
181 }
182 if (num_threads <= 0) {
183 tst_resm(TWARN,
184 "num_threads undefined or incorrect, using \"1\"");
185 num_threads = 1;
186 }
187
188 if (nb_func * num_threads > PTHREAD_THREADS_MAX - 2)
189 while (nb_func * num_threads > PTHREAD_THREADS_MAX - 2)
190 num_threads--;
191 if (debug)
192 tst_resm(TINFO,
193 "%s: will run %d functions, %d threads per function",
194 argv[0], nb_func, num_threads);
195
196 retval = pthread_mutex_init(&sig_mutex, NULL);
197 if (retval != 0)
198 sys_error("main : mutex_init(&sig_mutex) FAILED", __LINE__);
199
200 retval = pthread_create(&sig_hand, NULL, handle_signals, NULL);
201 if (retval != 0)
202 sys_error("main : create(&sig_hand) FAILED", __LINE__);
203
204 /*
205 * Start all calculation threads...
206 */
207 threads = malloc(nb_func * num_threads * sizeof(pthread_t));
208 if (threads == NULL)
209 tst_brkm(TFAIL | TERRNO, cleanup, "malloc failed");
210
211 tabcom = malloc((sizeof(TH_DATA *) * nb_func * num_threads));
212 if (!tabcom)
213 tst_brkm(TFAIL | TERRNO, cleanup, "malloc failed");
214 tabcour = tabcom;
215
216 retval = pthread_attr_init(&newattr);
217 if (retval != 0)
218 sys_error("main : attr_init(&newattr) FAILED", __LINE__);
219
220 if (pthread_attr_setstacksize(&newattr, stacksize))
221 sys_error("main: pthread_attr_setstacksize failed", __LINE__);
222
223 retval = pthread_attr_setdetachstate(&newattr, PTHREAD_CREATE_JOINABLE);
224 if (retval != 0)
225 sys_error("main : attr_setdetachstate(&newattr) FAILED",
226 __LINE__);
227
228 /* run the nb_func functions on num_threads */
229
230 indice = 0;
231 for (i = 0; i < nb_func; i++) {
232
233 for (th_num = 0; th_num < num_threads; th_num++) {
234
235 /* allocate struct of commucation with the thread */
236 pcom = calloc(1, sizeof(TH_DATA));
237 if (pcom == NULL)
238 tst_brkm(TFAIL | TERRNO, cleanup,
239 "calloc failed");
240 *tabcour = (TH_DATA *) pcom;
241 tabcour++;
242 /*
243 * update structure of communication
244 */
245 pcom->th_num = th_num;
246 pcom->th_func = th_func[i];
247
248 pthread_mutex_lock(&sig_mutex);
249
250 if (sig_cancel) { /* stop processing right now! */
251 pthread_mutex_unlock(&sig_mutex);
252 goto finished;
253 }
254 retval = pthread_create(&threads[indice], &newattr,
255 thread_code, (void *)pcom);
256 if (retval != 0)
257 sys_error("main : create FAILED", __LINE__);
258 indice++;
259 pthread_mutex_unlock(&sig_mutex);
260
261 } /* num_threads */
262 } /* for i */
263
264 /*alarm(60*time); *//* start all threads for TEST_time */
265
266 /*
267 * Wait for the threads finish their task
268 * pthread_join () will block
269 */
270
271 finished:
272 if (debug) {
273 tst_resm(TINFO,
274 "initial thread: Waiting for %d threads to finish",
275 indice);
276 }
277 tabcour = tabcom;
278
279 for (th_num = 0; th_num < indice; th_num++) {
280 retvalend = pthread_join(threads[th_num], &exit_value);
281 if (retvalend != 0)
282 sys_error("finish : join FAILED", __LINE__);
283
284 /* test the result in TH_DATA : communication buffer */
285 pcom = *tabcour++;
286 if (pcom->th_result != 0) {
287 error++;
288 tst_resm(TFAIL,
289 "thread %d (%s) terminated unsuccessfully %d "
290 "errors/%d loops\n%s",
291 th_num, pcom->th_func.fident, pcom->th_nerror,
292 pcom->th_nloop, pcom->detail_data);
293 } else if (debug) {
294 tst_resm(TINFO,
295 "thread %d (%s) terminated successfully %d loops",
296 th_num, pcom->th_func.fident,
297 pcom->th_nloop - 1);
298 }
299 SAFE_FREE(pcom);
300
301 }
302 SAFE_FREE(tabcom);
303 SAFE_FREE(threads);
304 tst_rmdir();
305 if (error)
306 exit(1);
307 else
308 exit(0);
309 return 0;
310 }
311
312 /*----------------------------------------------------------------------+
313 | handle_signals () |
314 | ======================================================================|
315 | |
316 | Function: .... |
317 | If SIGALRM or SIGUSR1 or SIGINT : cancel threads |
318 | |
319 | Updates: .... |
320 | |
321 +-----------------------------------------------------------------------*/
handle_signals(void * arg)322 static void *handle_signals(void *arg)
323 {
324 sigset_t signals_set;
325 int thd;
326 int sig;
327 int retvalsig = 0;
328
329 if (debug)
330 tst_resm(TINFO, "signal handler %lu started", pthread_self());
331 /*
332 * Set up the signals that we want to handle...
333 */
334 sigemptyset(&signals_set);
335 sigaddset(&signals_set, SIGINT);
336 sigaddset(&signals_set, SIGQUIT);
337 sigaddset(&signals_set, SIGTERM);
338 sigaddset(&signals_set, SIGUSR1);
339 sigaddset(&signals_set, SIGALRM);
340 while (1) {
341 if (debug)
342 tst_resm(TINFO, "Signal handler starts waiting...");
343
344 sigwait(&signals_set, &sig);
345 if (debug)
346 tst_resm(TINFO, "Signal handler caught signal %d", sig);
347
348 switch (sig) {
349 case SIGALRM:
350 case SIGUSR1:
351 case SIGINT:
352 if (sig_cancel)
353 tst_resm(TINFO,
354 "Signal handler: already finished; "
355 "ignoring signal");
356 else {
357 /*
358 * Have to signal all non started threads...
359 */
360
361 retvalsig = pthread_mutex_lock(&sig_mutex);
362 if (retvalsig != 0)
363 sys_error
364 ("handle_signal : mutex_lock(&sig_mutex) FAILED",
365 __LINE__);
366
367 sig_cancel = 1;
368 retvalsig = pthread_mutex_unlock(&sig_mutex);
369 if (retvalsig != 0)
370 sys_error
371 ("handle_signal : mutex_unlock(&sig_mutex) FAILED",
372 __LINE__);
373
374 /*
375 * ......... and all started
376 */
377 for (thd = 0; thd < indice; thd++) {
378 if (debug)
379 tst_resm(TINFO,
380 "signal handler: "
381 "cancelling thread (%d of "
382 "%d)", thd, indice);
383 retvalsig =
384 pthread_cancel(threads[thd]);
385 if (retvalsig != 0)
386 sys_error
387 ("handle_signal : cancel FAILED",
388 __LINE__);
389 }
390 }
391 break;
392 case SIGQUIT:
393 tst_resm(TINFO,
394 "Signal handler: Caught SIGQUIT; doing nothing");
395 break;
396 case SIGTERM:
397 tst_resm(TINFO,
398 "Signal handler: Caught SIGTERM; doing nothing");
399 break;
400 default:
401 exit(1);
402 }
403 }
404 return NULL;
405 }
406
407 /*----------------------------------------------------------------------+
408 | error () |
409 | =====================================================================|
410 | |
411 | Function: Prints out message and exits... |
412 | |
413 +----------------------------------------------------------------------*/
error(const char * msg,int line)414 static void error(const char *msg, int line)
415 {
416 tst_brkm(TFAIL, cleanup, "ERROR [line: %d] %s", line, msg);
417 }
418
419 /*----------------------------------------------------------------------+
420 | sys_error () |
421 | =====================================================================|
422 | |
423 | Function: Creates system error message and calls error () |
424 | |
425 +----------------------------------------------------------------------*/
426 /*
427 * XXX (garrcoop): the way that this is being called is just plain wrong.
428 * pthread(5) returns 0 or errnos, not necessarily sets errno to a sensible
429 * value.
430 */
sys_error(const char * msg,int line)431 static void sys_error(const char *msg, int line)
432 {
433 char syserr_msg[256];
434
435 sprintf(syserr_msg, "%s: %s", msg, strerror(errno));
436 error(syserr_msg, line);
437 }
438