Home | History | Annotate | Download | only in float
      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 
     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 
     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 
     96 static void cleanup(void)
     97 {
     98 	tst_rmdir();
     99 }
    100 
    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 +-----------------------------------------------------------------------*/
    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  +----------------------------------------------------------------------*/
    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  */
    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