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..
     10  * otherwise, the thread shall continue as normal from the completed barrier wait. Until
     11  * the thread in the signal handler returns from it, it is unspecified whether other threads may
     12  * proceed past the barrier once they have all reached it.
     13  *
     14  * Steps:
     15  * 1. Main initialize barrier with count 2
     16  * 2. Main create a child thread
     17  * 3. Child thread call pthread_barrier_wait(), should block
     18  * 4. While child thread is blocking, send SIGUSR1 to child
     19  * 5. While child thread is in the signal handler, main thread call pthread_barrier_wait()
     20  * 6. After return from the signal handler, the child thread should continue as normal
     21  */
     22 
     23 #define _XOPEN_SOURCE 600
     24 #include <pthread.h>
     25 #include <stdio.h>
     26 #include <stdlib.h>
     27 #include <unistd.h>
     28 #include <signal.h>
     29 #include <string.h>
     30 #include <time.h>
     31 #include "posixtest.h"
     32 
     33 static pthread_barrier_t barrier;
     34 static int thread_state;
     35 static int sig_rcvd;
     36 static int barrier_waited;
     37 
     38 #define NOT_CREATED_THREAD 1
     39 #define ENTERED_THREAD 2
     40 #define EXITING_THREAD 3
     41 
     42 void sig_handler()
     43 {
     44 	struct timespec ts;
     45 	sig_rcvd = 1;
     46 	printf("thread: interrupted by SIGUSR1\n");
     47 
     48 	ts.tv_sec = 1;
     49 	ts.tv_nsec = 0;
     50 	while (barrier_waited != 1) {
     51 		nanosleep(&ts, NULL);
     52 	}
     53 }
     54 
     55 static void *fn_chld(void *arg)
     56 {
     57 	int rc = 0;
     58 	struct sigaction act;
     59 
     60 	thread_state = ENTERED_THREAD;
     61 
     62 	/* Set up thread to handle SIGUSR1 */
     63 	act.sa_flags = 0;
     64 	act.sa_handler = sig_handler;
     65 	sigfillset(&act.sa_mask);
     66 	sigaction(SIGUSR1, &act, 0);
     67 
     68 	printf("thread: call barrier wait\n");
     69 	rc = pthread_barrier_wait(&barrier);
     70 	if (rc != 0 && rc != PTHREAD_BARRIER_SERIAL_THREAD) {
     71 		printf
     72 		    ("Test FAILED: child: pthread_barrier_wait() got unexpected "
     73 		     "return code : %d\n", rc);
     74 		exit(PTS_FAIL);
     75 	} else if (rc == PTHREAD_BARRIER_SERIAL_THREAD)
     76 		printf("thread: got PTHREAD_BARRIER_SERIAL_THREAD\n");
     77 
     78 	thread_state = EXITING_THREAD;
     79 	pthread_exit(0);
     80 	return NULL;
     81 }
     82 
     83 int main(void)
     84 {
     85 	int cnt = 0;
     86 	int rc;
     87 	pthread_t child_thread;
     88 	sig_rcvd = 0;
     89 	barrier_waited = 0;
     90 
     91 	printf("Initialize barrier with count = 2\n");
     92 	if (pthread_barrier_init(&barrier, NULL, 2) != 0) {
     93 		printf("main: Error at pthread_barrier_init()\n");
     94 		return PTS_UNRESOLVED;
     95 	}
     96 
     97 	printf("main: create child thread\n");
     98 	thread_state = NOT_CREATED_THREAD;
     99 	if (pthread_create(&child_thread, NULL, fn_chld, NULL) != 0) {
    100 		printf("main: Error at pthread_create()\n");
    101 		return PTS_UNRESOLVED;
    102 	}
    103 
    104 	/* Expect the child to block */
    105 	cnt = 0;
    106 	do {
    107 		sleep(1);
    108 	} while (thread_state != EXITING_THREAD && cnt++ < 2);
    109 
    110 	if (thread_state == EXITING_THREAD) {
    111 		/* child thread did not block */
    112 		printf("Test FAILED: child thread did not block on "
    113 		       "pthread_barrier_wait()\n");
    114 		exit(PTS_FAIL);
    115 	} else if (thread_state != ENTERED_THREAD) {
    116 		printf("Unexpected thread state\n");
    117 		exit(PTS_UNRESOLVED);
    118 	}
    119 
    120 	printf("main: send SIGUSR1 to child thread\n");
    121 	if (pthread_kill(child_thread, SIGUSR1) != 0) {
    122 		printf("main: Error at pthread_kill()\n");
    123 		exit(PTS_UNRESOLVED);
    124 	}
    125 
    126 	/* Wait for thread to receive the signal */
    127 	while (sig_rcvd != 1) {
    128 		sleep(1);
    129 	}
    130 
    131 	printf("main: call barrier wait\n");
    132 	rc = pthread_barrier_wait(&barrier);
    133 
    134 	if (rc != 0 && rc != PTHREAD_BARRIER_SERIAL_THREAD) {
    135 		printf
    136 		    ("Test FAILED: main: pthread_barrier_wait() got unexpected "
    137 		     "return code : %d\n", rc);
    138 		exit(PTS_FAIL);
    139 	} else if (rc == PTHREAD_BARRIER_SERIAL_THREAD)
    140 		printf("main: got PTHREAD_BARRIER_SERIAL_THREAD\n");
    141 
    142 	barrier_waited = 1;
    143 
    144 	/* We expected the child returned from barrier wait */
    145 	cnt = 0;
    146 	do {
    147 		sleep(1);
    148 	} while (thread_state != EXITING_THREAD && cnt++ < 3);
    149 
    150 	if (thread_state == ENTERED_THREAD) {
    151 		printf("Test FAILED: child thread still blocked on "
    152 		       "barrier wait\n");
    153 		return PTS_FAIL;
    154 	} else if (thread_state != EXITING_THREAD) {
    155 		printf("main: Unexpected thread state\n");
    156 		return PTS_UNRESOLVED;
    157 	}
    158 
    159 	if (pthread_join(child_thread, NULL) != 0) {
    160 		printf("main: Error at pthread_join()\n");
    161 		exit(PTS_UNRESOLVED);
    162 	}
    163 
    164 	if (pthread_barrier_destroy(&barrier) != 0) {
    165 		printf("Error at pthread_barrier_destroy()");
    166 		return PTS_UNRESOLVED;
    167 	}
    168 
    169 	printf("Test PASSED\n");
    170 	return PTS_PASS;
    171 }
    172