Home | History | Annotate | Download | only in pthread_cond_wait
      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 sample test aims to check the following assertion:
     18  * The function does not return an error code of EINTR
     19 
     20  * The steps are:
     21  *
     22  * -> Create a thread which wait in a condition for a small time.
     23  * -> Another thread will signal this condition from time to time.
     24  * -> Another thread which loops on sending a signal to the first thread.
     25  *
     26  */
     27 
     28  /* We are testing conformance to IEEE Std 1003.1, 2003 Edition */
     29 #define _POSIX_C_SOURCE 200112L
     30 
     31  /********************************************************************************************/
     32 /****************************** standard includes *****************************************/
     33 /********************************************************************************************/
     34 #include <pthread.h>
     35 #include <stdarg.h>
     36 #include <stdio.h>
     37 #include <stdlib.h>
     38 #include <unistd.h>
     39 
     40 #include <semaphore.h>
     41 #include <errno.h>
     42 #include <signal.h>
     43 #include <time.h>
     44 
     45 /********************************************************************************************/
     46 /******************************   Test framework   *****************************************/
     47 /********************************************************************************************/
     48 #include "../testfrmw/testfrmw.h"
     49 #include "../testfrmw/testfrmw.c"
     50  /* This header is responsible for defining the following macros:
     51   * UNRESOLVED(ret, descr);
     52   *    where descr is a description of the error and ret is an int (error code for example)
     53   * FAILED(descr);
     54   *    where descr is a short text saying why the test has failed.
     55   * PASSED();
     56   *    No parameter.
     57   *
     58   * Both three macros shall terminate the calling process.
     59   * The testcase shall not terminate in any other maneer.
     60   *
     61   * The other file defines the functions
     62   * void output_init()
     63   * void output(char * string, ...)
     64   *
     65   * Those may be used to output information.
     66   */
     67 
     68 /********************************************************************************************/
     69 /********************************** Configuration ******************************************/
     70 /********************************************************************************************/
     71 #define WITH_SYNCHRO
     72 #ifndef VERBOSE
     73 #define VERBOSE 2
     74 #endif
     75 
     76 #define INTERVAL (700)		/* ns, frequency (actually, period) for the condition signaling */
     77 
     78 /********************************************************************************************/
     79 /***********************************    Test case   *****************************************/
     80 /********************************************************************************************/
     81 
     82 char do_it = 1;
     83 char woken = 0;
     84 unsigned long count_cnd_sig = 0, count_cnd_wup = 0;
     85 #ifdef WITH_SYNCHRO
     86 sem_t semsig1;
     87 sem_t semsig2;
     88 unsigned long count_sig = 0;
     89 #endif
     90 
     91 sigset_t usersigs;
     92 
     93 typedef struct {
     94 	int sig;
     95 #ifdef WITH_SYNCHRO
     96 	sem_t *sem;
     97 #endif
     98 } thestruct;
     99 
    100 struct {
    101 	pthread_mutex_t mtx;
    102 	pthread_cond_t cnd;
    103 } data;
    104 
    105 /* the following function keeps on sending the signal to the process */
    106 void *sendsig(void *arg)
    107 {
    108 	thestruct *thearg = (thestruct *) arg;
    109 	int ret;
    110 	pid_t process;
    111 
    112 	process = getpid();
    113 
    114 	/* We block the signals SIGUSR1 and SIGUSR2 for this THREAD */
    115 	ret = pthread_sigmask(SIG_BLOCK, &usersigs, NULL);
    116 	if (ret != 0) {
    117 		UNRESOLVED(ret,
    118 			   "Unable to block SIGUSR1 and SIGUSR2 in signal thread");
    119 	}
    120 
    121 	while (do_it) {
    122 #ifdef WITH_SYNCHRO
    123 		if ((ret = sem_wait(thearg->sem))) {
    124 			UNRESOLVED(errno, "Sem_wait in sendsig");
    125 		}
    126 		count_sig++;
    127 #endif
    128 
    129 		ret = kill(process, thearg->sig);
    130 		if (ret != 0) {
    131 			UNRESOLVED(errno, "Kill in sendsig");
    132 		}
    133 
    134 	}
    135 
    136 	return NULL;
    137 }
    138 
    139 /* Next are the signal handlers. */
    140 /* This one is registered for signal SIGUSR1 */
    141 void sighdl1(int sig)
    142 {
    143 #ifdef WITH_SYNCHRO
    144 	if (sem_post(&semsig1)) {
    145 		UNRESOLVED(errno, "Sem_post in signal handler 1");
    146 	}
    147 #endif
    148 }
    149 
    150 /* This one is registered for signal SIGUSR2 */
    151 void sighdl2(int sig)
    152 {
    153 #ifdef WITH_SYNCHRO
    154 	if (sem_post(&semsig2)) {
    155 		UNRESOLVED(errno, "Sem_post in signal handler 2");
    156 	}
    157 #endif
    158 }
    159 
    160 /* The following function will wait on the cond
    161  * it does check that no error code of EINTR is returned */
    162 void *waiter(void *arg)
    163 {
    164 	int ret;
    165 
    166 	/* We don't block the signals SIGUSR1 and SIGUSR2 for this THREAD */
    167 	ret = pthread_sigmask(SIG_UNBLOCK, &usersigs, NULL);
    168 	if (ret != 0) {
    169 		UNRESOLVED(ret,
    170 			   "Unable to unblock SIGUSR1 and SIGUSR2 in worker thread");
    171 	}
    172 
    173 	ret = pthread_mutex_lock(&(data.mtx));
    174 	if (ret != 0) {
    175 		UNRESOLVED(ret, "Unable to lock mutex in waiter thread");
    176 	}
    177 
    178 	do {
    179 		ret = pthread_cond_wait(&(data.cnd), &(data.mtx));
    180 		count_cnd_wup++;
    181 	} while ((ret == 0) && (do_it != 0));
    182 
    183 	if (ret == EINTR) {
    184 		FAILED("pthread_cond_wait returned EINTR");
    185 	}
    186 
    187 	if (ret != 0) {
    188 		UNRESOLVED(ret,
    189 			   "pthread_cond_wait returned an unexpected error");
    190 	}
    191 
    192 	woken++;
    193 
    194 	ret = pthread_mutex_unlock(&(data.mtx));
    195 	if (ret != 0) {
    196 		UNRESOLVED(ret, "Unable to unlock mutex in waiter thread");
    197 	}
    198 
    199 	return NULL;
    200 }
    201 
    202 /* The next function will signal the condition at periodic interval */
    203 void *worker(void *arg)
    204 {
    205 	int ret = 0;
    206 
    207 	struct timespec ts, tsrem;
    208 	//initialisation is needed
    209 	ts.tv_sec = 0;
    210 
    211 	/* We block the signals SIGUSR1 and SIGUSR2 for this THREAD */
    212 	ret = pthread_sigmask(SIG_BLOCK, &usersigs, NULL);
    213 	if (ret != 0) {
    214 		UNRESOLVED(ret,
    215 			   "Unable to block SIGUSR1 and SIGUSR2 in signal thread");
    216 	}
    217 
    218 	ts.tv_sec = 0;
    219 	ts.tv_nsec = INTERVAL;
    220 	while (ts.tv_nsec >= 1000000000) {
    221 		ts.tv_nsec -= 1000000000;
    222 		ts.tv_sec += 1;
    223 	}
    224 
    225 	while (woken == 0) {
    226 		tsrem.tv_sec = ts.tv_sec;
    227 		tsrem.tv_nsec = ts.tv_nsec;
    228 
    229 		do {
    230 			ret = nanosleep(&tsrem, &tsrem);
    231 		}
    232 		while ((ret != 0) && (errno == EINTR));
    233 
    234 		ret = pthread_cond_signal(&(data.cnd));
    235 		if (ret != 0) {
    236 			UNRESOLVED(ret, "Failed to signal the condition");
    237 		}
    238 		count_cnd_sig++;
    239 	}
    240 
    241 	return NULL;
    242 }
    243 
    244 /* Main function */
    245 int main(void)
    246 {
    247 	int ret;
    248 	pthread_t th_waiter, th_worker, th_sig1, th_sig2;
    249 	thestruct arg1, arg2;
    250 	struct sigaction sa;
    251 
    252 	output_init();
    253 
    254 	/* We need to register the signal handlers for the PROCESS */
    255 	sigemptyset(&sa.sa_mask);
    256 	sa.sa_flags = 0;
    257 	sa.sa_handler = sighdl1;
    258 	if ((ret = sigaction(SIGUSR1, &sa, NULL))) {
    259 		UNRESOLVED(ret, "Unable to register signal handler1");
    260 	}
    261 	sa.sa_handler = sighdl2;
    262 	if ((ret = sigaction(SIGUSR2, &sa, NULL))) {
    263 		UNRESOLVED(ret, "Unable to register signal handler2");
    264 	}
    265 
    266 	/* We prepare a signal set which includes SIGUSR1 and SIGUSR2 */
    267 	sigemptyset(&usersigs);
    268 	ret = sigaddset(&usersigs, SIGUSR1);
    269 	ret |= sigaddset(&usersigs, SIGUSR2);
    270 	if (ret != 0) {
    271 		UNRESOLVED(ret, "Unable to add SIGUSR1 or 2 to a signal set");
    272 	}
    273 
    274 	/* We now block the signals SIGUSR1 and SIGUSR2 for this THREAD */
    275 	ret = pthread_sigmask(SIG_BLOCK, &usersigs, NULL);
    276 	if (ret != 0) {
    277 		UNRESOLVED(ret,
    278 			   "Unable to block SIGUSR1 and SIGUSR2 in main thread");
    279 	}
    280 #ifdef WITH_SYNCHRO
    281 	if (sem_init(&semsig1, 0, 1)) {
    282 		UNRESOLVED(errno, "Semsig1  init");
    283 	}
    284 	if (sem_init(&semsig2, 0, 1)) {
    285 		UNRESOLVED(errno, "Semsig2  init");
    286 	}
    287 #endif
    288 
    289 	if ((ret = pthread_create(&th_waiter, NULL, waiter, NULL))) {
    290 		UNRESOLVED(ret, "Waiter thread creation failed");
    291 	}
    292 
    293 	if ((ret = pthread_create(&th_worker, NULL, worker, NULL))) {
    294 		UNRESOLVED(ret, "Worker thread creation failed");
    295 	}
    296 
    297 	arg1.sig = SIGUSR1;
    298 	arg2.sig = SIGUSR2;
    299 #ifdef WITH_SYNCHRO
    300 	arg1.sem = &semsig1;
    301 	arg2.sem = &semsig2;
    302 #endif
    303 
    304 	if ((ret = pthread_create(&th_sig1, NULL, sendsig, (void *)&arg1))) {
    305 		UNRESOLVED(ret, "Signal 1 sender thread creation failed");
    306 	}
    307 	if ((ret = pthread_create(&th_sig2, NULL, sendsig, (void *)&arg2))) {
    308 		UNRESOLVED(ret, "Signal 2 sender thread creation failed");
    309 	}
    310 
    311 	/* Let's wait for a while now */
    312 	sleep(1);
    313 
    314 	/* Now stop the threads and join them */
    315 	do {
    316 		do_it = 0;
    317 	}
    318 	while (do_it);
    319 
    320 	if ((ret = pthread_join(th_sig1, NULL))) {
    321 		UNRESOLVED(ret, "Signal 1 sender thread join failed");
    322 	}
    323 	if ((ret = pthread_join(th_sig2, NULL))) {
    324 		UNRESOLVED(ret, "Signal 2 sender thread join failed");
    325 	}
    326 	if ((ret = pthread_join(th_waiter, NULL))) {
    327 		UNRESOLVED(ret, "Waiter thread join failed");
    328 	}
    329 	if ((ret = pthread_join(th_worker, NULL))) {
    330 		UNRESOLVED(ret, "Worker thread join failed");
    331 	}
    332 #if VERBOSE > 0
    333 	output("Test executed successfully.\n");
    334 	output("  Condition was signaled %d times.\n", count_cnd_sig);
    335 	output("  pthread_cond_wait exited %d times.\n", count_cnd_wup);
    336 #ifdef WITH_SYNCHRO
    337 	output("  %d signals were sent meanwhile.\n", count_sig);
    338 #endif
    339 #endif
    340 	PASSED;
    341 }
    342