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