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
35static pthread_barrier_t barrier;
36static int thread_state;
37static int sig_rcvd;
38
39#define NOT_CREATED_THREAD 1
40#define ENTERED_THREAD 2
41#define EXITING_THREAD 3
42
43void sig_handler()
44{
45	sig_rcvd = 1;
46	printf("thread: interrupted by SIGUSR1\n");
47}
48
49static 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
77int 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