xref: /third_party/ltp/testcases/misc/math/float/main.c (revision f08c3bdf)
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 */
32char *TCID;			/* Test program identifier.    */
33int 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
38void 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
47TH_DATA *pcom;
48TH_DATA **tabcom;
49TH_DATA **tabcour;
50#ifndef	PATH_MAX
51#define PATH_MAX		1024
52#endif
53char 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
59int num_threads = DEFAULT_NUM_THREADS;
60int num_loops = 500;
61
62int sig_cancel = 0;		/* flag set by handle_signals to tell initial thread
63				   to stop creating new threads (signal caught) */
64
65int indice = 0;			/* # of threads created, to be canceled by handle_signals
66				   or waited for by initial thread */
67
68pthread_mutex_t sig_mutex;
69pthread_t *threads;
70
71int debug = 0;
72int true = 1;
73
74static void *handle_signals(void *);
75
76static void sys_error(const char *, int);
77
78const double EPS = 0.1e-300;
79
80const int nb_func = NB_FUNC;
81
82int 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
96static void cleanup(void)
97{
98	tst_rmdir();
99}
100
101int 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
271finished:
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+-----------------------------------------------------------------------*/
322static 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 +----------------------------------------------------------------------*/
414static 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 */
431static 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