• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 	pthread_cancel(sig_hand);
303 	pthread_join(sig_hand, NULL);
304 	SAFE_FREE(tabcom);
305 	SAFE_FREE(threads);
306 	tst_rmdir();
307 	if (error)
308 		exit(1);
309 	else
310 		exit(0);
311 	return 0;
312 }
313 
314 /*----------------------------------------------------------------------+
315 |			    handle_signals ()				|
316 | ======================================================================|
317 |									|
318 | Function:  ....							|
319 |	    If SIGALRM or SIGUSR1 or SIGINT : cancel threads		|
320 |									|
321 | Updates:   ....							|
322 |									|
323 +-----------------------------------------------------------------------*/
handle_signals(void * arg)324 static void *handle_signals(void *arg)
325 {
326 	sigset_t signals_set;
327 	int thd;
328 	int sig;
329 	int retvalsig = 0;
330 
331 	if (debug)
332 		tst_resm(TINFO, "signal handler %lu started", pthread_self());
333 	/*
334 	 * Set up the signals that we want to handle...
335 	 */
336 	sigemptyset(&signals_set);
337 	sigaddset(&signals_set, SIGINT);
338 	sigaddset(&signals_set, SIGQUIT);
339 	sigaddset(&signals_set, SIGTERM);
340 	sigaddset(&signals_set, SIGUSR1);
341 	sigaddset(&signals_set, SIGALRM);
342 	while (1) {
343 		if (debug)
344 			tst_resm(TINFO, "Signal handler starts waiting...");
345 
346 		sigwait(&signals_set, &sig);
347 		if (debug)
348 			tst_resm(TINFO, "Signal handler caught signal %d", sig);
349 
350 		switch (sig) {
351 		case SIGALRM:
352 		case SIGUSR1:
353 		case SIGINT:
354 			if (sig_cancel)
355 				tst_resm(TINFO,
356 					 "Signal handler: already finished; "
357 					 "ignoring signal");
358 			else {
359 				/*
360 				 * Have to signal all non started threads...
361 				 */
362 
363 				retvalsig = pthread_mutex_lock(&sig_mutex);
364 				if (retvalsig != 0)
365 					sys_error
366 					    ("handle_signal : mutex_lock(&sig_mutex) FAILED",
367 					     __LINE__);
368 
369 				sig_cancel = 1;
370 				retvalsig = pthread_mutex_unlock(&sig_mutex);
371 				if (retvalsig != 0)
372 					sys_error
373 					    ("handle_signal : mutex_unlock(&sig_mutex) FAILED",
374 					     __LINE__);
375 
376 				/*
377 				 * ......... and all started
378 				 */
379 				for (thd = 0; thd < indice; thd++) {
380 					if (debug)
381 						tst_resm(TINFO,
382 							 "signal handler: "
383 							 "cancelling thread (%d of "
384 							 "%d)", thd, indice);
385 					retvalsig =
386 					    pthread_cancel(threads[thd]);
387 					if (retvalsig != 0)
388 						sys_error
389 						    ("handle_signal : cancel FAILED",
390 						     __LINE__);
391 				}
392 			}
393 			break;
394 		case SIGQUIT:
395 			tst_resm(TINFO,
396 				 "Signal handler: Caught SIGQUIT; doing nothing");
397 			break;
398 		case SIGTERM:
399 			tst_resm(TINFO,
400 				 "Signal handler: Caught SIGTERM; doing nothing");
401 			break;
402 		default:
403 			exit(1);
404 		}
405 	}
406 	return NULL;
407 }
408 
409 /*----------------------------------------------------------------------+
410  |				error ()				|
411  | =====================================================================|
412  |									|
413  | Function:  Prints out message and exits...				|
414  |									|
415  +----------------------------------------------------------------------*/
error(const char * msg,int line)416 static void error(const char *msg, int line)
417 {
418 	tst_brkm(TFAIL, cleanup, "ERROR [line: %d] %s", line, msg);
419 }
420 
421 /*----------------------------------------------------------------------+
422  |			     sys_error ()				|
423  | =====================================================================|
424  |									|
425  | Function:  Creates system error message and calls error ()		|
426  |									|
427  +----------------------------------------------------------------------*/
428 /*
429  * XXX (garrcoop): the way that this is being called is just plain wrong.
430  * pthread(5) returns 0 or errnos, not necessarily sets errno to a sensible
431  * value.
432  */
sys_error(const char * msg,int line)433 static void sys_error(const char *msg, int line)
434 {
435 	char syserr_msg[256];
436 
437 	sprintf(syserr_msg, "%s: %s", msg, strerror(errno));
438 	error(syserr_msg, line);
439 }
440