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_timedwrlock(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_timedwrlock(),
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 * Test that after returning from a signal handler, the reader will continue
142c28215423293e443469a07ae7011135d058b671Garrett Cooper * to wait with timedrdlock as long as the specified 'timeout' does not expire (the
150dc076565f772bb1953209fb69ea150b494aaa40robbiew * time spent in signal handler is longer than the specifed 'timeout').
160dc076565f772bb1953209fb69ea150b494aaa40robbiew *
170dc076565f772bb1953209fb69ea150b494aaa40robbiew * Steps:
180dc076565f772bb1953209fb69ea150b494aaa40robbiew * 1. main thread  create and write lock 'rwlock'
190dc076565f772bb1953209fb69ea150b494aaa40robbiew * 2. main thread create a thread sig_thread, the thread is set to handle SIGUSR1
200dc076565f772bb1953209fb69ea150b494aaa40robbiew * 3. sig_thread timed write-lock 'rwlock' for writing, it should block
212c28215423293e443469a07ae7011135d058b671Garrett Cooper * 4. While the sig_thread is waiting (not expired yet), main thread sends SIGUSR1
220dc076565f772bb1953209fb69ea150b494aaa40robbiew *    to sig_thread via pthread_kill
230dc076565f772bb1953209fb69ea150b494aaa40robbiew * 5. Check that when thread handler returns, sig_thread resume block
240dc076565f772bb1953209fb69ea150b494aaa40robbiew * 7. When the wait is terminated, check that the thread wait for a proper period before
252c28215423293e443469a07ae7011135d058b671Garrett Cooper *    expiring.
260dc076565f772bb1953209fb69ea150b494aaa40robbiew *
270dc076565f772bb1953209fb69ea150b494aaa40robbiew */
280dc076565f772bb1953209fb69ea150b494aaa40robbiew
290dc076565f772bb1953209fb69ea150b494aaa40robbiew#define _XOPEN_SOURCE 600
300dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <pthread.h>
310dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <stdio.h>
320dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <stdlib.h>
330dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <signal.h>
340dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <errno.h>
350dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <unistd.h>
360dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <time.h>
370dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <sys/time.h>
380dc076565f772bb1953209fb69ea150b494aaa40robbiew#include "posixtest.h"
390dc076565f772bb1953209fb69ea150b494aaa40robbiew
400dc076565f772bb1953209fb69ea150b494aaa40robbiewstatic pthread_t sig_thread;
410dc076565f772bb1953209fb69ea150b494aaa40robbiewstatic pthread_rwlock_t rwlock;
420dc076565f772bb1953209fb69ea150b494aaa40robbiew
430dc076565f772bb1953209fb69ea150b494aaa40robbiewstatic int thread_state;
440dc076565f772bb1953209fb69ea150b494aaa40robbiewstatic int handler_called;
450dc076565f772bb1953209fb69ea150b494aaa40robbiewstatic struct timeval before_wait, after_wait;
460dc076565f772bb1953209fb69ea150b494aaa40robbiew
472c28215423293e443469a07ae7011135d058b671Garrett Cooper/* thread_state indicates child thread state:
482c28215423293e443469a07ae7011135d058b671Garrett Cooper	1: not in child thread yet;
490dc076565f772bb1953209fb69ea150b494aaa40robbiew	2: just enter child thread ;
500dc076565f772bb1953209fb69ea150b494aaa40robbiew	3: just before child thread exit;
510dc076565f772bb1953209fb69ea150b494aaa40robbiew*/
520dc076565f772bb1953209fb69ea150b494aaa40robbiew
530dc076565f772bb1953209fb69ea150b494aaa40robbiew#define NOT_CREATED_THREAD 1
540dc076565f772bb1953209fb69ea150b494aaa40robbiew#define ENTERED_THREAD 2
550dc076565f772bb1953209fb69ea150b494aaa40robbiew#define EXITING_THREAD 3
560dc076565f772bb1953209fb69ea150b494aaa40robbiew
570dc076565f772bb1953209fb69ea150b494aaa40robbiew#define TIMEOUT 5
580dc076565f772bb1953209fb69ea150b494aaa40robbiew
590dc076565f772bb1953209fb69ea150b494aaa40robbiew/* Signal handler called by the thread when SIGUSR1 is received */
60354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic void sig_handler()
61354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao{
620dc076565f772bb1953209fb69ea150b494aaa40robbiew
63354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_equal(pthread_self(), sig_thread)) {
640dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("sig_handler: signal is handled by sig_thread\n");
650dc076565f772bb1953209fb69ea150b494aaa40robbiew		handler_called = 1;
662c28215423293e443469a07ae7011135d058b671Garrett Cooper
67354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} else {
680dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("sig_handler: signal is not handled by sig_thread\n");
690dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
700dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
710dc076565f772bb1953209fb69ea150b494aaa40robbiew}
720dc076565f772bb1953209fb69ea150b494aaa40robbiew
73354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic void *th_fn(void *arg)
740dc076565f772bb1953209fb69ea150b494aaa40robbiew{
750dc076565f772bb1953209fb69ea150b494aaa40robbiew	struct sigaction act;
760dc076565f772bb1953209fb69ea150b494aaa40robbiew	struct timespec abs_timeout;
770dc076565f772bb1953209fb69ea150b494aaa40robbiew	int rc = 0;
782c28215423293e443469a07ae7011135d058b671Garrett Cooper
790dc076565f772bb1953209fb69ea150b494aaa40robbiew	handler_called = 0;
800dc076565f772bb1953209fb69ea150b494aaa40robbiew
812c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* Set up signal handler for SIGUSR1 */
820dc076565f772bb1953209fb69ea150b494aaa40robbiew
830dc076565f772bb1953209fb69ea150b494aaa40robbiew	act.sa_flags = 0;
840dc076565f772bb1953209fb69ea150b494aaa40robbiew	act.sa_handler = sig_handler;
850dc076565f772bb1953209fb69ea150b494aaa40robbiew	/* block all the signal when hanlding SIGUSR1 */
860dc076565f772bb1953209fb69ea150b494aaa40robbiew	sigfillset(&act.sa_mask);
870dc076565f772bb1953209fb69ea150b494aaa40robbiew	sigaction(SIGUSR1, &act, 0);
882c28215423293e443469a07ae7011135d058b671Garrett Cooper
890dc076565f772bb1953209fb69ea150b494aaa40robbiew	gettimeofday(&before_wait, NULL);
900dc076565f772bb1953209fb69ea150b494aaa40robbiew	abs_timeout.tv_sec = before_wait.tv_sec + TIMEOUT;
910dc076565f772bb1953209fb69ea150b494aaa40robbiew	abs_timeout.tv_nsec = before_wait.tv_usec * 1000;
922c28215423293e443469a07ae7011135d058b671Garrett Cooper
930dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("thread: attempt timed write lock, %d seconds\n", TIMEOUT);
940dc076565f772bb1953209fb69ea150b494aaa40robbiew	thread_state = ENTERED_THREAD;
950dc076565f772bb1953209fb69ea150b494aaa40robbiew	rc = pthread_rwlock_timedwrlock(&rwlock, &abs_timeout);
96354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (rc != ETIMEDOUT) {
97354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		printf("sig_thread: pthread_rwlock_timedwrlock returns %d\n",
98354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		       rc);
990dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_FAIL);
1000dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
101354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	printf("thread: timer correctly expired\n");
1020dc076565f772bb1953209fb69ea150b494aaa40robbiew	gettimeofday(&after_wait, NULL);
1030dc076565f772bb1953209fb69ea150b494aaa40robbiew
1040dc076565f772bb1953209fb69ea150b494aaa40robbiew	thread_state = EXITING_THREAD;
1050dc076565f772bb1953209fb69ea150b494aaa40robbiew	pthread_exit(0);
1060dc076565f772bb1953209fb69ea150b494aaa40robbiew	return NULL;
1070dc076565f772bb1953209fb69ea150b494aaa40robbiew}
1080dc076565f772bb1953209fb69ea150b494aaa40robbiew
1094ca2bbdcd3003f3c8df4e6129e9c7b2bd1514f87Cyril Hrubisint main(void)
1100dc076565f772bb1953209fb69ea150b494aaa40robbiew{
1110dc076565f772bb1953209fb69ea150b494aaa40robbiew	int cnt;
1120dc076565f772bb1953209fb69ea150b494aaa40robbiew	struct timeval time_diff;
1130dc076565f772bb1953209fb69ea150b494aaa40robbiew
114354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_rwlock_init(&rwlock, NULL) != 0) {
1150dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error at pthread_rwlock_init()\n");
1160dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
1170dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1182c28215423293e443469a07ae7011135d058b671Garrett Cooper
1190dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("main: attempt write lock\n");
120354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_rwlock_wrlock(&rwlock) != 0) {
1210dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("main: Error at pthread_rwlock_wrlock()\n");
1220dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
1230dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1240dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("main: acquired write lock\n");
1250dc076565f772bb1953209fb69ea150b494aaa40robbiew
1260dc076565f772bb1953209fb69ea150b494aaa40robbiew	thread_state = NOT_CREATED_THREAD;
127354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_create(&sig_thread, NULL, th_fn, NULL) != 0) {
1280dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error at pthread_create()\n");
1290dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
1300dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1312c28215423293e443469a07ae7011135d058b671Garrett Cooper
1320dc076565f772bb1953209fb69ea150b494aaa40robbiew	/* Wait for the thread to get ready for handling signal (the thread should
1332c28215423293e443469a07ae7011135d058b671Garrett Cooper	 * be block on rwlock since main() has the write lock at this point) */
1340dc076565f772bb1953209fb69ea150b494aaa40robbiew	cnt = 0;
135354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	do {
1360dc076565f772bb1953209fb69ea150b494aaa40robbiew		sleep(1);
137354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} while (thread_state != ENTERED_THREAD && cnt++ < TIMEOUT);
1382c28215423293e443469a07ae7011135d058b671Garrett Cooper
139354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (thread_state != ENTERED_THREAD) {
1400dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Unexpected thread state %d\n", thread_state);
1410dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
1420dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1430dc076565f772bb1953209fb69ea150b494aaa40robbiew
1440dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("main: fire SIGUSR1 to thread\n");
145354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_kill(sig_thread, SIGUSR1) != 0) {
1460dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("main: Error at pthread_kill()\n");
1470dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
1480dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1492c28215423293e443469a07ae7011135d058b671Garrett Cooper
1500dc076565f772bb1953209fb69ea150b494aaa40robbiew	/* wait at most 2*TIMEOUT seconds */
1510dc076565f772bb1953209fb69ea150b494aaa40robbiew	cnt = 0;
152354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	do {
1530dc076565f772bb1953209fb69ea150b494aaa40robbiew		sleep(1);
154354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} while (thread_state != EXITING_THREAD && cnt++ < 2 * TIMEOUT);
1552c28215423293e443469a07ae7011135d058b671Garrett Cooper
156354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (cnt >= 2 * TIMEOUT) {
157354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		/* thread blocked */
158354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		printf
159354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    ("Test FAILED: thread blocked even afer the abs_timeout expired\n");
1602c28215423293e443469a07ae7011135d058b671Garrett Cooper		exit(PTS_FAIL);
1610dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1622c28215423293e443469a07ae7011135d058b671Garrett Cooper
163354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (handler_called != 1) {
1640dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("The handler for SIGUSR1 did not get called\n");
1650dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
1662c28215423293e443469a07ae7011135d058b671Garrett Cooper	}
1672c28215423293e443469a07ae7011135d058b671Garrett Cooper
1680dc076565f772bb1953209fb69ea150b494aaa40robbiew	/* Test that the thread block for the correct TIMOUT time */
1690dc076565f772bb1953209fb69ea150b494aaa40robbiew	time_diff.tv_sec = after_wait.tv_sec - before_wait.tv_sec;
1700dc076565f772bb1953209fb69ea150b494aaa40robbiew	time_diff.tv_usec = after_wait.tv_usec - before_wait.tv_usec;
171354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (time_diff.tv_usec < 0) {
1720dc076565f772bb1953209fb69ea150b494aaa40robbiew		--time_diff.tv_sec;
1730dc076565f772bb1953209fb69ea150b494aaa40robbiew		time_diff.tv_usec += 1000000;
1740dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
175354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (time_diff.tv_sec < TIMEOUT) {
176354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		printf
177354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    ("Test FAILED: Timeout was for %d seconds, but waited for %ld.%06ld seconds instead\n",
178354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		     TIMEOUT, (long)time_diff.tv_sec, (long)time_diff.tv_usec);
1790dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_FAIL);
1800dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1810dc076565f772bb1953209fb69ea150b494aaa40robbiew
1820dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("main: unlock write lock\n");
183354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_rwlock_unlock(&rwlock) != 0) {
1840dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("main: Error at pthread_rwlock_unlock()\n");
1850dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
1860dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1872c28215423293e443469a07ae7011135d058b671Garrett Cooper
188354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_join(sig_thread, NULL) != 0) {
1890dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("main: Error at pthread_join()\n");
1900dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
1910dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1922c28215423293e443469a07ae7011135d058b671Garrett Cooper
193354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_rwlock_destroy(&rwlock) != 0) {
1940dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error at pthread_destroy()\n");
1950dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
1960dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1970dc076565f772bb1953209fb69ea150b494aaa40robbiew
1982c28215423293e443469a07ae7011135d058b671Garrett Cooper	printf("Test PASSED\n");
1992c28215423293e443469a07ae7011135d058b671Garrett Cooper	return PTS_PASS;
200ec6edca7aa42b6affd989ef91b5897f96795e40fChris Dearman}
201