12c28215423293e443469a07ae7011135d058b671Garrett Cooper/*
20dc076565f772bb1953209fb69ea150b494aaa40robbiew * Copyright (c) 2002, Intel Corporation. All rights reserved.
30dc076565f772bb1953209fb69ea150b494aaa40robbiew * This file is licensed under the GPL license.  For the full content
42c28215423293e443469a07ae7011135d058b671Garrett Cooper * of this license, see the COPYING file at the top level of this
50dc076565f772bb1953209fb69ea150b494aaa40robbiew * source tree.
60dc076565f772bb1953209fb69ea150b494aaa40robbiew * Test pthread_rwlock_timedrdlock(pthread_rwlock_t * rwlock)
72c28215423293e443469a07ae7011135d058b671Garrett Cooper *
82c28215423293e443469a07ae7011135d058b671Garrett Cooper * If a signal that causes a signal handler to be executed is delivered to
9e9410dfd93b8e415ecbe3f7e09a085462b27836eGarrett Cooper * a thread blocked on a read-write lock via a call to pthread_rwlock_timedrdlock(),
102c28215423293e443469a07ae7011135d058b671Garrett Cooper * upon return from the signal handler the thread shall resume waiting for the lock
110dc076565f772bb1953209fb69ea150b494aaa40robbiew * as if it was not interrupted.
120dc076565f772bb1953209fb69ea150b494aaa40robbiew *
130dc076565f772bb1953209fb69ea150b494aaa40robbiew * Steps:
140dc076565f772bb1953209fb69ea150b494aaa40robbiew * 1. main thread  create read-write lock 'rwlock', and lock it for writing
150dc076565f772bb1953209fb69ea150b494aaa40robbiew * 2. main thread create a thread sig_thread, the thread is set to handle SIGUSR1
160dc076565f772bb1953209fb69ea150b494aaa40robbiew * 3. sig_thread timed lock 'rwlock' for reading, but blocked
172c28215423293e443469a07ae7011135d058b671Garrett Cooper * 4. While the sig_thread is waiting(not expried yet), main thread send SIGUSR1
180dc076565f772bb1953209fb69ea150b494aaa40robbiew *    to sig_thread via pthread_kill
190dc076565f772bb1953209fb69ea150b494aaa40robbiew * 5. test that thread handler is called, inside the handler, make the thread sleep
202c28215423293e443469a07ae7011135d058b671Garrett Cooper *    for a period that the specified 'timeout' for pthread_rwlock_timedrdlock()
212c28215423293e443469a07ae7011135d058b671Garrett Cooper *    should have expired (timeout * 2)
222c28215423293e443469a07ae7011135d058b671Garrett Cooper * 6. While sig_thread sleeping in signal handler, main thread unlock 'rwlock'
232c28215423293e443469a07ae7011135d058b671Garrett Cooper * 7. check that when thread handler returns, sig_thread get the read lock without
240dc076565f772bb1953209fb69ea150b494aaa40robbiew *    getting ETIMEDOUT.
250dc076565f772bb1953209fb69ea150b494aaa40robbiew */
260dc076565f772bb1953209fb69ea150b494aaa40robbiew
270dc076565f772bb1953209fb69ea150b494aaa40robbiew#define _XOPEN_SOURCE 600
280dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <pthread.h>
290dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <stdio.h>
300dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <stdlib.h>
310dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <signal.h>
320dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <errno.h>
330dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <unistd.h>
340dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <time.h>
350dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <sys/time.h>
360dc076565f772bb1953209fb69ea150b494aaa40robbiew#include "posixtest.h"
370dc076565f772bb1953209fb69ea150b494aaa40robbiew
382c28215423293e443469a07ae7011135d058b671Garrett Cooper/* thread_state indicates child thread state:
392c28215423293e443469a07ae7011135d058b671Garrett Cooper	1: not in child thread yet;
400dc076565f772bb1953209fb69ea150b494aaa40robbiew	2: just enter child thread ;
410dc076565f772bb1953209fb69ea150b494aaa40robbiew	3: just before child thread exit;
420dc076565f772bb1953209fb69ea150b494aaa40robbiew*/
430dc076565f772bb1953209fb69ea150b494aaa40robbiew
440dc076565f772bb1953209fb69ea150b494aaa40robbiew#define NOT_CREATED_THREAD 1
450dc076565f772bb1953209fb69ea150b494aaa40robbiew#define ENTERED_THREAD 2
460dc076565f772bb1953209fb69ea150b494aaa40robbiew#define EXITING_THREAD 3
470dc076565f772bb1953209fb69ea150b494aaa40robbiew
480dc076565f772bb1953209fb69ea150b494aaa40robbiew#define TIMEOUT 2
490dc076565f772bb1953209fb69ea150b494aaa40robbiew
500dc076565f772bb1953209fb69ea150b494aaa40robbiewstatic pthread_t sig_thread;
510dc076565f772bb1953209fb69ea150b494aaa40robbiewstatic pthread_rwlock_t rwlock;
520dc076565f772bb1953209fb69ea150b494aaa40robbiew
530dc076565f772bb1953209fb69ea150b494aaa40robbiewstatic int thread_state;
540dc076565f772bb1953209fb69ea150b494aaa40robbiewstatic int handler_state;
550dc076565f772bb1953209fb69ea150b494aaa40robbiewstatic int expired;
560dc076565f772bb1953209fb69ea150b494aaa40robbiewstatic struct timeval before_wait, after_wait;
570dc076565f772bb1953209fb69ea150b494aaa40robbiew
58354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic void sig_handler()
59354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao{
600dc076565f772bb1953209fb69ea150b494aaa40robbiew
610dc076565f772bb1953209fb69ea150b494aaa40robbiew	struct timespec sleep_time_req;
622c28215423293e443469a07ae7011135d058b671Garrett Cooper
63354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	sleep_time_req.tv_sec = TIMEOUT * 2;
640dc076565f772bb1953209fb69ea150b494aaa40robbiew	sleep_time_req.tv_nsec = 0;
652c28215423293e443469a07ae7011135d058b671Garrett Cooper
66354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_equal(pthread_self(), sig_thread)) {
670dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("sig_handler: signal is handled by thread\n");
680dc076565f772bb1953209fb69ea150b494aaa40robbiew		/* sig_handler will not sleep 2 times more than the timeout for the
690dc076565f772bb1953209fb69ea150b494aaa40robbiew		 * pthread_rwlock_timerdlock is waiting for */
70354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		printf("sig_handler: sleeping for %d seconds\n",
71354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		       (int)sleep_time_req.tv_sec);
720dc076565f772bb1953209fb69ea150b494aaa40robbiew		handler_state = 2;
730dc076565f772bb1953209fb69ea150b494aaa40robbiew		sleep((int)sleep_time_req.tv_sec);
74354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} else {
750dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("sig_handler: signal is not handled by thread\n");
760dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
770dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
780dc076565f772bb1953209fb69ea150b494aaa40robbiew
790dc076565f772bb1953209fb69ea150b494aaa40robbiew	handler_state = 3;
800dc076565f772bb1953209fb69ea150b494aaa40robbiew}
810dc076565f772bb1953209fb69ea150b494aaa40robbiew
82354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic void *th_fn(void *arg)
830dc076565f772bb1953209fb69ea150b494aaa40robbiew{
840dc076565f772bb1953209fb69ea150b494aaa40robbiew	struct sigaction act;
850dc076565f772bb1953209fb69ea150b494aaa40robbiew	struct timespec abs_timeout;
860dc076565f772bb1953209fb69ea150b494aaa40robbiew	int rc;
870dc076565f772bb1953209fb69ea150b494aaa40robbiew	handler_state = 2;
880dc076565f772bb1953209fb69ea150b494aaa40robbiew	expired = 0;
890dc076565f772bb1953209fb69ea150b494aaa40robbiew
900dc076565f772bb1953209fb69ea150b494aaa40robbiew	/* Set up handler for SIGUSR1 */
912c28215423293e443469a07ae7011135d058b671Garrett Cooper
920dc076565f772bb1953209fb69ea150b494aaa40robbiew	act.sa_flags = 0;
930dc076565f772bb1953209fb69ea150b494aaa40robbiew	act.sa_handler = sig_handler;
940dc076565f772bb1953209fb69ea150b494aaa40robbiew	/* block all the signal when hanlding SIGUSR1 */
950dc076565f772bb1953209fb69ea150b494aaa40robbiew	sigfillset(&act.sa_mask);
960dc076565f772bb1953209fb69ea150b494aaa40robbiew	sigaction(SIGUSR1, &act, 0);
972c28215423293e443469a07ae7011135d058b671Garrett Cooper
980dc076565f772bb1953209fb69ea150b494aaa40robbiew	gettimeofday(&before_wait, NULL);
990dc076565f772bb1953209fb69ea150b494aaa40robbiew	abs_timeout.tv_sec = before_wait.tv_sec + TIMEOUT;
1000dc076565f772bb1953209fb69ea150b494aaa40robbiew	abs_timeout.tv_nsec = before_wait.tv_usec * 1000;
1012c28215423293e443469a07ae7011135d058b671Garrett Cooper
1020dc076565f772bb1953209fb69ea150b494aaa40robbiew	thread_state = ENTERED_THREAD;
1032c28215423293e443469a07ae7011135d058b671Garrett Cooper
1040dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("thread: attempt timed read lock, %d seconds\n", TIMEOUT);
1050dc076565f772bb1953209fb69ea150b494aaa40robbiew	rc = pthread_rwlock_timedrdlock(&rwlock, &abs_timeout);
106354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (rc == 0) {
1070dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("thread: correctly acquired read lock\n");
1082c28215423293e443469a07ae7011135d058b671Garrett Cooper		expired = 0;
109354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} else if (rc == ETIMEDOUT) {
1100dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("thread: timer expired, did not acquire read lock");
1110dc076565f772bb1953209fb69ea150b494aaa40robbiew		expired = 1;
112354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} else {
1130dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error at pthread_rwlock_timedrdlock()");
1140dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
1150dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1160dc076565f772bb1953209fb69ea150b494aaa40robbiew
1170dc076565f772bb1953209fb69ea150b494aaa40robbiew	gettimeofday(&after_wait, NULL);
1180dc076565f772bb1953209fb69ea150b494aaa40robbiew
1190dc076565f772bb1953209fb69ea150b494aaa40robbiew	thread_state = EXITING_THREAD;
1200dc076565f772bb1953209fb69ea150b494aaa40robbiew	pthread_exit(0);
1210dc076565f772bb1953209fb69ea150b494aaa40robbiew	return NULL;
1220dc076565f772bb1953209fb69ea150b494aaa40robbiew}
1230dc076565f772bb1953209fb69ea150b494aaa40robbiew
1244ca2bbdcd3003f3c8df4e6129e9c7b2bd1514f87Cyril Hrubisint main(void)
1250dc076565f772bb1953209fb69ea150b494aaa40robbiew{
1260dc076565f772bb1953209fb69ea150b494aaa40robbiew	int cnt;
1270dc076565f772bb1953209fb69ea150b494aaa40robbiew
128354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_rwlock_init(&rwlock, NULL) != 0) {
1290dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error at pthread_rwlock_init()\n");
1300dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
1310dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1322c28215423293e443469a07ae7011135d058b671Garrett Cooper
1330dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("main: attempt write lock\n");
134354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_rwlock_wrlock(&rwlock) != 0) {
1350dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("pthread_rwlock_wrlock()\n");
1360dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
1370dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1380dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("main: acquired write lock\n");
1390dc076565f772bb1953209fb69ea150b494aaa40robbiew
1400dc076565f772bb1953209fb69ea150b494aaa40robbiew	thread_state = NOT_CREATED_THREAD;
141354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_create(&sig_thread, NULL, th_fn, NULL) != 0) {
1420dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error at pthread_create()\n");
1430dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
1440dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1450dc076565f772bb1953209fb69ea150b494aaa40robbiew
1462c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* wait for the thread to get ready for handling signal */
1470dc076565f772bb1953209fb69ea150b494aaa40robbiew	cnt = 0;
148354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	do {
1490dc076565f772bb1953209fb69ea150b494aaa40robbiew		sleep(1);
150354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} while (thread_state != ENTERED_THREAD && cnt++ < TIMEOUT);
1512c28215423293e443469a07ae7011135d058b671Garrett Cooper
152354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (thread_state != ENTERED_THREAD) {
1530dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error: thread did not block when getting read lock\n");
1540dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
1550dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1560dc076565f772bb1953209fb69ea150b494aaa40robbiew
1570dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("main: fire SIGUSR1 to thread\n");
158354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_kill(sig_thread, SIGUSR1) != 0) {
1590dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error in pthread_kill()");
1600dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
1610dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1622c28215423293e443469a07ae7011135d058b671Garrett Cooper
1630dc076565f772bb1953209fb69ea150b494aaa40robbiew	/* Wait for signal handler to sleep so that main can unlock the rwlock while
1640dc076565f772bb1953209fb69ea150b494aaa40robbiew	 * it is sleeping. (this way, the rwlock will be unlocked when the signal handler
1650dc076565f772bb1953209fb69ea150b494aaa40robbiew	 * returns, and control is given back to the thread) */
1660dc076565f772bb1953209fb69ea150b494aaa40robbiew
1670dc076565f772bb1953209fb69ea150b494aaa40robbiew	cnt = 0;
168354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	do {
1690dc076565f772bb1953209fb69ea150b494aaa40robbiew		sleep(TIMEOUT);
170354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} while (handler_state != 2 && cnt++ < 2);
1710dc076565f772bb1953209fb69ea150b494aaa40robbiew
172354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (handler_state == 1) {
1730dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error: signal handler did not get called\n");
1740dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
175354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} else if (handler_state == 3) {
1760dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error: signal handler incorrectly exited\n");
1772c28215423293e443469a07ae7011135d058b671Garrett Cooper		exit(PTS_UNRESOLVED);
1780dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1790dc076565f772bb1953209fb69ea150b494aaa40robbiew
180354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (expired == 1) {
1810dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error: thread timeout in sig_handler\n");
1820dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
1830dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1840dc076565f772bb1953209fb69ea150b494aaa40robbiew
1850dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("main: unlock write lock\n");
186354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_rwlock_unlock(&rwlock) != 0) {
1870dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error at pthread_rwlock_unlock()\n");
1880dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
1890dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1902c28215423293e443469a07ae7011135d058b671Garrett Cooper
1910dc076565f772bb1953209fb69ea150b494aaa40robbiew	/* wait at most 4*TIMEOUT seconds for thread to exit */
1920dc076565f772bb1953209fb69ea150b494aaa40robbiew	cnt = 0;
193354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	do {
1940dc076565f772bb1953209fb69ea150b494aaa40robbiew		sleep(1);
195354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} while (thread_state != EXITING_THREAD && cnt++ < 4 * TIMEOUT);
1962c28215423293e443469a07ae7011135d058b671Garrett Cooper
197354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (cnt >= 4 * TIMEOUT) {
198354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		/* thread blocked */
199354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		printf
200354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    ("Test FAILED: thread blocked even afer the abs_timeout expires\n");
2012c28215423293e443469a07ae7011135d058b671Garrett Cooper		exit(PTS_FAIL);
2020dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
2032c28215423293e443469a07ae7011135d058b671Garrett Cooper
204354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (expired == 1) {
2050dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Test FAILED: thread should get the read lock\n");
2060dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_FAIL);
2070dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
2082c28215423293e443469a07ae7011135d058b671Garrett Cooper
209354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_join(sig_thread, NULL) != 0) {
2100dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error at pthread_join()");
2110dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
2120dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
2132c28215423293e443469a07ae7011135d058b671Garrett Cooper
214354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_rwlock_destroy(&rwlock) != 0) {
2150dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error at pthread_destroy()");
2160dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
2170dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
2182c28215423293e443469a07ae7011135d058b671Garrett Cooper
2190dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("Test PASSED\n");
2202c28215423293e443469a07ae7011135d058b671Garrett Cooper	return PTS_PASS;
221ec6edca7aa42b6affd989ef91b5897f96795e40fChris Dearman}
222