6-2.c revision 0dc076565f772bb1953209fb69ea150b494aaa40
10dc076565f772bb1953209fb69ea150b494aaa40robbiew/*
20dc076565f772bb1953209fb69ea150b494aaa40robbiew * Copyright (c) 2002, Intel Corporation. All rights reserved.
30dc076565f772bb1953209fb69ea150b494aaa40robbiew * This file is licensed under the GPL license.  For the full content
40dc076565f772bb1953209fb69ea150b494aaa40robbiew * 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)
70dc076565f772bb1953209fb69ea150b494aaa40robbiew *
80dc076565f772bb1953209fb69ea150b494aaa40robbiew * If a signal that causes a signal handler to be executed is delivered to
90dc076565f772bb1953209fb69ea150b494aaa40robbiew * a thread blocked on a read-write lock via a call to pthread_rwlock_timedrdlock( ),
100dc076565f772bb1953209fb69ea150b494aaa40robbiew * 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
170dc076565f772bb1953209fb69ea150b494aaa40robbiew * 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
200dc076565f772bb1953209fb69ea150b494aaa40robbiew *    for a period that the specified 'timeout' for pthread_rwlock_timedrdlock()
210dc076565f772bb1953209fb69ea150b494aaa40robbiew *    should have expired (timeout * 2)
220dc076565f772bb1953209fb69ea150b494aaa40robbiew * 6. While sig_thread sleeping in signal handler, main thread unlock 'rwlock'
230dc076565f772bb1953209fb69ea150b494aaa40robbiew * 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
380dc076565f772bb1953209fb69ea150b494aaa40robbiew/* thread_state indicates child thread state:
390dc076565f772bb1953209fb69ea150b494aaa40robbiew	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
580dc076565f772bb1953209fb69ea150b494aaa40robbiewstatic void sig_handler() {
590dc076565f772bb1953209fb69ea150b494aaa40robbiew
600dc076565f772bb1953209fb69ea150b494aaa40robbiew	struct timespec sleep_time_req;
610dc076565f772bb1953209fb69ea150b494aaa40robbiew
620dc076565f772bb1953209fb69ea150b494aaa40robbiew	sleep_time_req.tv_sec = TIMEOUT*2;
630dc076565f772bb1953209fb69ea150b494aaa40robbiew	sleep_time_req.tv_nsec = 0;
640dc076565f772bb1953209fb69ea150b494aaa40robbiew
650dc076565f772bb1953209fb69ea150b494aaa40robbiew	if(pthread_equal(pthread_self(), sig_thread))
660dc076565f772bb1953209fb69ea150b494aaa40robbiew	{
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 */
700dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("sig_handler: sleeping for %d seconds\n", (int)sleep_time_req.tv_sec);
710dc076565f772bb1953209fb69ea150b494aaa40robbiew		handler_state = 2;
720dc076565f772bb1953209fb69ea150b494aaa40robbiew		sleep((int)sleep_time_req.tv_sec);
730dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
740dc076565f772bb1953209fb69ea150b494aaa40robbiew	else
750dc076565f772bb1953209fb69ea150b494aaa40robbiew	{
760dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("sig_handler: signal is not handled by thread\n");
770dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
780dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
790dc076565f772bb1953209fb69ea150b494aaa40robbiew
800dc076565f772bb1953209fb69ea150b494aaa40robbiew	handler_state = 3;
810dc076565f772bb1953209fb69ea150b494aaa40robbiew}
820dc076565f772bb1953209fb69ea150b494aaa40robbiew
830dc076565f772bb1953209fb69ea150b494aaa40robbiewstatic void * th_fn(void *arg)
840dc076565f772bb1953209fb69ea150b494aaa40robbiew{
850dc076565f772bb1953209fb69ea150b494aaa40robbiew	struct sigaction act;
860dc076565f772bb1953209fb69ea150b494aaa40robbiew	struct timespec abs_timeout;
870dc076565f772bb1953209fb69ea150b494aaa40robbiew	int rc;
880dc076565f772bb1953209fb69ea150b494aaa40robbiew	handler_state = 2;
890dc076565f772bb1953209fb69ea150b494aaa40robbiew	expired = 0;
900dc076565f772bb1953209fb69ea150b494aaa40robbiew
910dc076565f772bb1953209fb69ea150b494aaa40robbiew	/* Set up handler for SIGUSR1 */
920dc076565f772bb1953209fb69ea150b494aaa40robbiew
930dc076565f772bb1953209fb69ea150b494aaa40robbiew	act.sa_flags = 0;
940dc076565f772bb1953209fb69ea150b494aaa40robbiew	act.sa_handler = sig_handler;
950dc076565f772bb1953209fb69ea150b494aaa40robbiew	/* block all the signal when hanlding SIGUSR1 */
960dc076565f772bb1953209fb69ea150b494aaa40robbiew	sigfillset(&act.sa_mask);
970dc076565f772bb1953209fb69ea150b494aaa40robbiew	sigaction(SIGUSR1, &act, 0);
980dc076565f772bb1953209fb69ea150b494aaa40robbiew
990dc076565f772bb1953209fb69ea150b494aaa40robbiew	gettimeofday(&before_wait, NULL);
1000dc076565f772bb1953209fb69ea150b494aaa40robbiew	abs_timeout.tv_sec = before_wait.tv_sec + TIMEOUT;
1010dc076565f772bb1953209fb69ea150b494aaa40robbiew	abs_timeout.tv_nsec = before_wait.tv_usec * 1000;
1020dc076565f772bb1953209fb69ea150b494aaa40robbiew
1030dc076565f772bb1953209fb69ea150b494aaa40robbiew	thread_state = ENTERED_THREAD;
1040dc076565f772bb1953209fb69ea150b494aaa40robbiew
1050dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("thread: attempt timed read lock, %d seconds\n", TIMEOUT);
1060dc076565f772bb1953209fb69ea150b494aaa40robbiew	rc = pthread_rwlock_timedrdlock(&rwlock, &abs_timeout);
1070dc076565f772bb1953209fb69ea150b494aaa40robbiew	if(rc == 0)
1080dc076565f772bb1953209fb69ea150b494aaa40robbiew	{
1090dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("thread: correctly acquired read lock\n");
1100dc076565f772bb1953209fb69ea150b494aaa40robbiew		expired = 0;
1110dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1120dc076565f772bb1953209fb69ea150b494aaa40robbiew	else if(rc == ETIMEDOUT)
1130dc076565f772bb1953209fb69ea150b494aaa40robbiew	{
1140dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("thread: timer expired, did not acquire read lock");
1150dc076565f772bb1953209fb69ea150b494aaa40robbiew		expired = 1;
1160dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1170dc076565f772bb1953209fb69ea150b494aaa40robbiew	else
1180dc076565f772bb1953209fb69ea150b494aaa40robbiew	{
1190dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error at pthread_rwlock_timedrdlock()");
1200dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
1210dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1220dc076565f772bb1953209fb69ea150b494aaa40robbiew
1230dc076565f772bb1953209fb69ea150b494aaa40robbiew	gettimeofday(&after_wait, NULL);
1240dc076565f772bb1953209fb69ea150b494aaa40robbiew
1250dc076565f772bb1953209fb69ea150b494aaa40robbiew	thread_state = EXITING_THREAD;
1260dc076565f772bb1953209fb69ea150b494aaa40robbiew	pthread_exit(0);
1270dc076565f772bb1953209fb69ea150b494aaa40robbiew	return NULL;
1280dc076565f772bb1953209fb69ea150b494aaa40robbiew}
1290dc076565f772bb1953209fb69ea150b494aaa40robbiew
1300dc076565f772bb1953209fb69ea150b494aaa40robbiewint main()
1310dc076565f772bb1953209fb69ea150b494aaa40robbiew{
1320dc076565f772bb1953209fb69ea150b494aaa40robbiew	int cnt;
1330dc076565f772bb1953209fb69ea150b494aaa40robbiew
1340dc076565f772bb1953209fb69ea150b494aaa40robbiew	if(pthread_rwlock_init(&rwlock, NULL) != 0)
1350dc076565f772bb1953209fb69ea150b494aaa40robbiew	{
1360dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error at pthread_rwlock_init()\n");
1370dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
1380dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1390dc076565f772bb1953209fb69ea150b494aaa40robbiew
1400dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("main: attempt write lock\n");
1410dc076565f772bb1953209fb69ea150b494aaa40robbiew	if(pthread_rwlock_wrlock(&rwlock) != 0)
1420dc076565f772bb1953209fb69ea150b494aaa40robbiew	{
1430dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("pthread_rwlock_wrlock()\n");
1440dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
1450dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1460dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("main: acquired write lock\n");
1470dc076565f772bb1953209fb69ea150b494aaa40robbiew
1480dc076565f772bb1953209fb69ea150b494aaa40robbiew	thread_state = NOT_CREATED_THREAD;
1490dc076565f772bb1953209fb69ea150b494aaa40robbiew	if(pthread_create(&sig_thread, NULL, th_fn, NULL) != 0)
1500dc076565f772bb1953209fb69ea150b494aaa40robbiew	{
1510dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error at pthread_create()\n");
1520dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
1530dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1540dc076565f772bb1953209fb69ea150b494aaa40robbiew
1550dc076565f772bb1953209fb69ea150b494aaa40robbiew	/* wait for the thread to get ready for handling signal */
1560dc076565f772bb1953209fb69ea150b494aaa40robbiew	cnt = 0;
1570dc076565f772bb1953209fb69ea150b494aaa40robbiew	do{
1580dc076565f772bb1953209fb69ea150b494aaa40robbiew		sleep(1);
1590dc076565f772bb1953209fb69ea150b494aaa40robbiew	}while(thread_state != ENTERED_THREAD && cnt++ < TIMEOUT);
1600dc076565f772bb1953209fb69ea150b494aaa40robbiew
1610dc076565f772bb1953209fb69ea150b494aaa40robbiew	if(thread_state != ENTERED_THREAD)
1620dc076565f772bb1953209fb69ea150b494aaa40robbiew	{
1630dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error: thread did not block when getting read lock\n");
1640dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
1650dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1660dc076565f772bb1953209fb69ea150b494aaa40robbiew
1670dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("main: fire SIGUSR1 to thread\n");
1680dc076565f772bb1953209fb69ea150b494aaa40robbiew	if(pthread_kill(sig_thread, SIGUSR1) != 0)
1690dc076565f772bb1953209fb69ea150b494aaa40robbiew	{
1700dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error in pthread_kill()");
1710dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
1720dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1730dc076565f772bb1953209fb69ea150b494aaa40robbiew
1740dc076565f772bb1953209fb69ea150b494aaa40robbiew	/* Wait for signal handler to sleep so that main can unlock the rwlock while
1750dc076565f772bb1953209fb69ea150b494aaa40robbiew	 * it is sleeping. (this way, the rwlock will be unlocked when the signal handler
1760dc076565f772bb1953209fb69ea150b494aaa40robbiew	 * returns, and control is given back to the thread) */
1770dc076565f772bb1953209fb69ea150b494aaa40robbiew
1780dc076565f772bb1953209fb69ea150b494aaa40robbiew	cnt = 0;
1790dc076565f772bb1953209fb69ea150b494aaa40robbiew	do{
1800dc076565f772bb1953209fb69ea150b494aaa40robbiew		sleep(TIMEOUT);
1810dc076565f772bb1953209fb69ea150b494aaa40robbiew	}while(handler_state !=2 && cnt++ < 2);
1820dc076565f772bb1953209fb69ea150b494aaa40robbiew
1830dc076565f772bb1953209fb69ea150b494aaa40robbiew	if(handler_state == 1)
1840dc076565f772bb1953209fb69ea150b494aaa40robbiew	{
1850dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error: signal handler did not get called\n");
1860dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
1870dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1880dc076565f772bb1953209fb69ea150b494aaa40robbiew	else if(handler_state == 3)
1890dc076565f772bb1953209fb69ea150b494aaa40robbiew	{
1900dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error: signal handler incorrectly exited\n");
1910dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
1920dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1930dc076565f772bb1953209fb69ea150b494aaa40robbiew
1940dc076565f772bb1953209fb69ea150b494aaa40robbiew	if(expired == 1)
1950dc076565f772bb1953209fb69ea150b494aaa40robbiew	{
1960dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error: thread timeout in sig_handler\n");
1970dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
1980dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1990dc076565f772bb1953209fb69ea150b494aaa40robbiew
2000dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("main: unlock write lock\n");
2010dc076565f772bb1953209fb69ea150b494aaa40robbiew	if(pthread_rwlock_unlock(&rwlock) != 0)
2020dc076565f772bb1953209fb69ea150b494aaa40robbiew	{
2030dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error at pthread_rwlock_unlock()\n");
2040dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
2050dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
2060dc076565f772bb1953209fb69ea150b494aaa40robbiew
2070dc076565f772bb1953209fb69ea150b494aaa40robbiew	/* wait at most 4*TIMEOUT seconds for thread to exit */
2080dc076565f772bb1953209fb69ea150b494aaa40robbiew	cnt = 0;
2090dc076565f772bb1953209fb69ea150b494aaa40robbiew	do{
2100dc076565f772bb1953209fb69ea150b494aaa40robbiew		sleep(1);
2110dc076565f772bb1953209fb69ea150b494aaa40robbiew	}while(thread_state != EXITING_THREAD && cnt++ < 4*TIMEOUT);
2120dc076565f772bb1953209fb69ea150b494aaa40robbiew
2130dc076565f772bb1953209fb69ea150b494aaa40robbiew
2140dc076565f772bb1953209fb69ea150b494aaa40robbiew	if(cnt >= 4*TIMEOUT)
2150dc076565f772bb1953209fb69ea150b494aaa40robbiew	{
2160dc076565f772bb1953209fb69ea150b494aaa40robbiew		/* thread blocked*/
2170dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Test FAILED: thread blocked even afer the abs_timeout expires\n");
2180dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_FAIL);
2190dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
2200dc076565f772bb1953209fb69ea150b494aaa40robbiew
2210dc076565f772bb1953209fb69ea150b494aaa40robbiew	if(expired == 1)
2220dc076565f772bb1953209fb69ea150b494aaa40robbiew	{
2230dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Test FAILED: thread should get the read lock\n");
2240dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_FAIL);
2250dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
2260dc076565f772bb1953209fb69ea150b494aaa40robbiew
2270dc076565f772bb1953209fb69ea150b494aaa40robbiew	if(pthread_join(sig_thread, NULL) != 0)
2280dc076565f772bb1953209fb69ea150b494aaa40robbiew	{
2290dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error at pthread_join()");
2300dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
2310dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
2320dc076565f772bb1953209fb69ea150b494aaa40robbiew
2330dc076565f772bb1953209fb69ea150b494aaa40robbiew	if(pthread_rwlock_destroy(&rwlock) != 0)
2340dc076565f772bb1953209fb69ea150b494aaa40robbiew	{
2350dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error at pthread_destroy()");
2360dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
2370dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
2380dc076565f772bb1953209fb69ea150b494aaa40robbiew
2390dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("Test PASSED\n");
2400dc076565f772bb1953209fb69ea150b494aaa40robbiew	return PTS_PASS;
2410dc076565f772bb1953209fb69ea150b494aaa40robbiew}
242