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 * Test pthread_rwlock_rdlock(pthread_rwlock_t * rwlock)
7 *
8 * If a signal is delivered to a thread waiting for a read-write lock for reading, upon
9 * return from the signal handler the thread resumes waiting for the read-write lock for
10 * reading as if it was not interrupted.
11 *
12 * Steps:
13 * 1. main thread  create read-write lock 'rwlock', and lock it for writing
14 * 2. main thread create a thread sig_thread, the thread is set to handle SIGUSR1
15 * 3. sig_thread try to lock 'rwlock' for reading but will block
16 * 4. main thread sends SIGUSR1 to sig_thread via pthread_kill
17 * 5. test that thread handler is called
18 * 6. check that when thread handler returns, sig_thread resumes blocking for rwlock
19 * 7. main thread unlock 'rwlock', sig_thread should get the lock
20 */
21
22#define _XOPEN_SOURCE 600
23#include <pthread.h>
24#include <stdio.h>
25#include <stdlib.h>
26#include <signal.h>
27#include <errno.h>
28#include <unistd.h>
29#include "posixtest.h"
30
31static pthread_t sig_thread;
32static pthread_rwlock_t rwlock;
33
34static int thread_state;
35static int handler_called;
36
37/* thread_state indicates child thread state:
38	1: not in child thread yet;
39	2: just enter child thread ;
40	3: just before child thread exit;
41*/
42
43#define NOT_CREATED_THREAD 1
44#define ENTERED_THREAD 2
45#define EXITING_THREAD 3
46
47static void sig_handler()
48{
49	if (pthread_equal(pthread_self(), sig_thread)) {
50		printf("sig_handler: handled signal SIGUSR1\n");
51		handler_called = 1;
52	} else {
53		printf("signal is not handled by sig_thread\n");
54		exit(PTS_UNRESOLVED);
55	}
56}
57
58static void *th_fn(void *arg)
59{
60	struct sigaction act;
61	int rc = 0;
62
63	act.sa_flags = 0;
64	act.sa_handler = sig_handler;
65	/* Try to block all signals when handling SIGUSR1 */
66	sigfillset(&act.sa_mask);
67	sigaction(SIGUSR1, &act, 0);
68
69	thread_state = ENTERED_THREAD;
70	printf("sig_thread: attemp read lock\n");
71	rc = pthread_rwlock_rdlock(&rwlock);
72	if (rc != 0) {
73		printf
74		    ("Test FAILED: sig_thread: Error at pthread_rwlock_rdlock(), Error code=%d\n",
75		     rc);
76		exit(PTS_FAIL);
77	} else
78		printf("sig_thread: acquired read lock\n");
79
80	printf("sig_thread: unlock read lock\n");
81	if (pthread_rwlock_unlock(&rwlock) != 0) {
82		printf("sig_thread: Error release readlock\n");
83		exit(PTS_UNRESOLVED);
84	}
85	thread_state = EXITING_THREAD;
86	pthread_exit(0);
87	return NULL;
88}
89
90int main(void)
91{
92	int cnt;
93	handler_called = 0;
94
95	if (pthread_rwlock_init(&rwlock, NULL) != 0) {
96		printf("main: Error at pthread_rwlock_init()\n");
97		return PTS_UNRESOLVED;
98	}
99
100	printf("main: attempt write lock\n");
101	if (pthread_rwlock_wrlock(&rwlock) != 0) {
102		printf("main: Error at pthread_rwlock_wrlock()\n");
103		return PTS_UNRESOLVED;
104	} else
105		printf("main: acquired write lock\n");
106
107	thread_state = NOT_CREATED_THREAD;
108	if (pthread_create(&sig_thread, NULL, th_fn, NULL) != 0) {
109		printf("main: Error at pthread_create()\n");
110		return PTS_UNRESOLVED;
111	}
112
113	/* wait at most 3 seconds for sig_thread to block */
114	cnt = 0;
115	do {
116		sleep(1);
117	} while (thread_state != EXITING_THREAD && cnt++ < 3);
118
119	if (thread_state == EXITING_THREAD) {
120		printf
121		    ("Test FAILED: thread did not block on read lock when a writer holds the lock\n");
122		exit(PTS_FAIL);
123	} else if (thread_state != ENTERED_THREAD) {
124		printf("Unexpected thread state: %d\n", thread_state);
125		exit(PTS_UNRESOLVED);
126	}
127
128	/* sig_thread is blocking */
129	printf("main: fire SIGUSR1 to sig_thread\n");
130	if (pthread_kill(sig_thread, SIGUSR1) != 0) {
131		printf("main: failed to send SIGUSER to sig_thread\n");
132		exit(PTS_UNRESOLVED);
133	}
134
135	/* wait at most 3 seconds for the signal to be handled */
136	cnt = 0;
137	do {
138		sleep(1);
139	} while (handler_called == 0 && cnt++ < 3);
140
141	if (handler_called != 1) {
142		printf("SIGUSR1 was not caught by sig_thread\n");
143		exit(PTS_UNRESOLVED);
144	}
145
146	/* sig_thread resume to block? */
147	cnt = 0;
148	do {
149		sleep(1);
150	} while (thread_state != EXITING_THREAD && cnt++ < 3);
151
152	if (thread_state == EXITING_THREAD) {
153		printf
154		    ("Test FAILED: upon return from signal handler, sig_thread does not resume to block\n");
155		exit(PTS_FAIL);
156	} else if (thread_state != ENTERED_THREAD) {
157		printf("Unexpected thread state: %d\n", thread_state);
158		exit(PTS_UNRESOLVED);
159	}
160
161	printf
162	    ("sig_thread: correctly still blocking after signal handler returns\n");
163	printf("main: unlock write lock\n");
164	if (pthread_rwlock_unlock(&rwlock) != 0) {
165		printf("main: Failed to release write lock\n");
166		exit(PTS_UNRESOLVED);
167	}
168
169	/* sig_thread got the read lock? */
170	cnt = 0;
171	do {
172		sleep(1);
173	} while (thread_state != EXITING_THREAD && cnt++ < 3);
174
175	if (thread_state == ENTERED_THREAD) {
176		printf
177		    ("Test FAILED: sig_thread blocked on read lock when writer release the lock\n");
178		exit(PTS_FAIL);
179	} else if (thread_state != EXITING_THREAD) {
180		printf("Unexpected thread state: %d\n", thread_state);
181		exit(PTS_UNRESOLVED);
182	}
183
184	if (pthread_join(sig_thread, NULL) != 0) {
185		printf("main: failed at pthread_join()\n");
186		exit(PTS_UNRESOLVED);
187	}
188
189	if (pthread_rwlock_destroy(&rwlock) != 0) {
190		printf("main: failed at pthread_rwlock_destroy()\n");
191		exit(PTS_UNRESOLVED);
192	}
193
194	printf("Test PASSED\n");
195	return PTS_PASS;
196}
197