Home | History | Annotate | Download | only in pthread_barrier_wait
      1 /*
      2  * Copyright (c) 2002, Intel Corporation. All rights reserved.
      3  * This file is licensed under the GPL license.  For the full content
      4  * of this license, see the COPYING file at the top level of this
      5  * source tree.
      6  *
      7  * pthread_barrier_wait()
      8  *
      9  * If a signal is delivered to a thread blocked on a barrier, upon return
     10  * from the signal handler the thread shall resume waiting at the barrier
     11  * if the barrier wait has not completed (that is, if the
     12  * required number of threads have not arrived at the barrier
     13  * during the execution of the signal handler);
     14  *
     15  * Steps:
     16  * 1. Main initialize barrier with count 2
     17  * 2. Main create a child thread
     18  * 3. Child thread call pthread_barrier_wait(), should block
     19  * 4. While child thread is blocking, send SIGUSR1 to child
     20  * 5. The signal handler did nothing just print a messge
     21  * 6. After return from the signal handler, child should resume blocking
     22  * 7. Main call pthread_barrier_wait(), child and main should all return
     23  *    from pthread_barrier_wait()
     24  */
     25 
     26 #define _XOPEN_SOURCE 600
     27 #include <pthread.h>
     28 #include <stdio.h>
     29 #include <stdlib.h>
     30 #include <unistd.h>
     31 #include <signal.h>
     32 #include <string.h>
     33 #include "posixtest.h"
     34 
     35 static pthread_barrier_t barrier;
     36 static int thread_state;
     37 static int sig_rcvd;
     38 
     39 #define NOT_CREATED_THREAD 1
     40 #define ENTERED_THREAD 2
     41 #define EXITING_THREAD 3
     42 
     43 void sig_handler()
     44 {
     45 	sig_rcvd = 1;
     46 	printf("thread: interrupted by SIGUSR1\n");
     47 }
     48 
     49 static void *fn_chld(void *arg)
     50 {
     51 	int rc = 0;
     52 	struct sigaction act;
     53 
     54 	thread_state = ENTERED_THREAD;
     55 
     56 	/* Set up thread to handle SIGUSR1 */
     57 	act.sa_flags = 0;
     58 	act.sa_handler = sig_handler;
     59 	sigfillset(&act.sa_mask);
     60 	sigaction(SIGUSR1, &act, 0);
     61 
     62 	printf("thread: call barrier wait\n");
     63 	rc = pthread_barrier_wait(&barrier);
     64 	if (rc != 0 && rc != PTHREAD_BARRIER_SERIAL_THREAD) {
     65 		printf
     66 		    ("Test FAILED: child: pthread_barrier_wait() got unexpected "
     67 		     "return code : %d\n", rc);
     68 		exit(PTS_FAIL);
     69 	} else if (rc == PTHREAD_BARRIER_SERIAL_THREAD)
     70 		printf("thread: get PTHREAD_BARRIER_SERIAL_THREAD\n");
     71 
     72 	thread_state = EXITING_THREAD;
     73 	pthread_exit(0);
     74 	return NULL;
     75 }
     76 
     77 int main(void)
     78 {
     79 	int cnt = 0;
     80 	int rc;
     81 	pthread_t child_thread;
     82 	sig_rcvd = 0;
     83 
     84 	printf("Initialize barrier with count = 2\n");
     85 	if (pthread_barrier_init(&barrier, NULL, 2) != 0) {
     86 		printf("main: Error at pthread_barrier_init()\n");
     87 		return PTS_UNRESOLVED;
     88 	}
     89 
     90 	printf("main: create child thread\n");
     91 	thread_state = NOT_CREATED_THREAD;
     92 	if (pthread_create(&child_thread, NULL, fn_chld, NULL) != 0) {
     93 		printf("main: Error at pthread_create()\n");
     94 		return PTS_UNRESOLVED;
     95 	}
     96 
     97 	/* Expect the child to block */
     98 	cnt = 0;
     99 	do {
    100 		sleep(1);
    101 	} while (thread_state != EXITING_THREAD && cnt++ < 2);
    102 
    103 	if (thread_state == EXITING_THREAD) {
    104 		/* child thread did not block */
    105 		printf("Test FAILED: child thread did not block on "
    106 		       "pthread_barrier_wait()\n");
    107 		exit(PTS_FAIL);
    108 	} else if (thread_state != ENTERED_THREAD) {
    109 		printf("Unexpected thread state: %d\n", thread_state);
    110 		exit(PTS_UNRESOLVED);
    111 	}
    112 
    113 	printf("main: send SIGUSR1 to child thread\n");
    114 	if (pthread_kill(child_thread, SIGUSR1) != 0) {
    115 		printf("main: Error at pthread_kill()\n");
    116 		exit(PTS_UNRESOLVED);
    117 	}
    118 
    119 	/* Expect the child to continue blocking */
    120 	cnt = 0;
    121 	do {
    122 		sleep(1);
    123 	} while (thread_state != EXITING_THREAD && cnt++ < 2);
    124 
    125 	if (sig_rcvd != 1) {
    126 		printf("child did not handle SIGUSR1\n");
    127 		exit(PTS_UNRESOLVED);
    128 	}
    129 
    130 	if (thread_state == EXITING_THREAD) {
    131 		/* child thread did not block */
    132 		printf("Test FAILED: child thread should still block on "
    133 		       "pthread_barrier_wait() when interrupted by signal\n");
    134 		exit(PTS_FAIL);
    135 	} else if (thread_state != ENTERED_THREAD) {
    136 		printf("Unexpected thread state: %d\n", thread_state);
    137 		exit(PTS_UNRESOLVED);
    138 	}
    139 	printf("main: thread continued blocking after handling SIGUSR1\n");
    140 
    141 	printf("main: call barrier wait\n");
    142 	rc = pthread_barrier_wait(&barrier);
    143 
    144 	if (rc != 0 && rc != PTHREAD_BARRIER_SERIAL_THREAD) {
    145 		printf
    146 		    ("Test FAILED: main: pthread_barrier_wait() got unexpected "
    147 		     "return code : %d\n", rc);
    148 		exit(PTS_FAIL);
    149 	} else if (rc == PTHREAD_BARRIER_SERIAL_THREAD)
    150 		printf("main: get PTHREAD_BARRIER_SERIAL_THREAD\n");
    151 
    152 	/* We expected the child returned from barrier wait */
    153 	cnt = 0;
    154 	do {
    155 		sleep(1);
    156 	} while (thread_state != EXITING_THREAD && cnt++ < 3);
    157 
    158 	if (thread_state == ENTERED_THREAD) {
    159 		printf("Test FAILED: child thread still blocked on "
    160 		       "barrier wait\n");
    161 		return PTS_FAIL;
    162 	} else if (thread_state != EXITING_THREAD) {
    163 		printf("main: Unexpected thread state: %d\n", thread_state);
    164 		return PTS_UNRESOLVED;
    165 	}
    166 
    167 	if (pthread_join(child_thread, NULL) != 0) {
    168 		printf("main: Error at pthread_join()\n");
    169 		exit(PTS_UNRESOLVED);
    170 	}
    171 
    172 	if (pthread_barrier_destroy(&barrier) != 0) {
    173 		printf("Error at pthread_barrier_destroy()");
    174 		return PTS_UNRESOLVED;
    175 	}
    176 
    177 	printf("Test PASSED\n");
    178 	return PTS_PASS;
    179 }
    180