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
70dc076565f772bb1953209fb69ea150b494aaa40robbiew * Test that pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock)
80dc076565f772bb1953209fb69ea150b494aaa40robbiew *
92c28215423293e443469a07ae7011135d058b671Garrett Cooper *	Under no circumstances shall the function fail with a timeout if the lock can be
102c28215423293e443469a07ae7011135d058b671Garrett Cooper *	acquired immediately. The abs_timeout parameter need not be checked if the lock
110dc076565f772bb1953209fb69ea150b494aaa40robbiew *	can be immediately acquired.
120dc076565f772bb1953209fb69ea150b494aaa40robbiew *
130dc076565f772bb1953209fb69ea150b494aaa40robbiew * Steps:n
140dc076565f772bb1953209fb69ea150b494aaa40robbiew * 1.  Main thread create a thread.
152c28215423293e443469a07ae7011135d058b671Garrett Cooper * 2.  Child thread lock 'rwlock' for reading with pthread_rwlock_timedrdlock(),
160dc076565f772bb1953209fb69ea150b494aaa40robbiew *	should not fail with timeout
170dc076565f772bb1953209fb69ea150b494aaa40robbiew * 3.  The child thread unlocks the 'rwlock' and exits.
180dc076565f772bb1953209fb69ea150b494aaa40robbiew * 4.  Main thread create another thread.
192c28215423293e443469a07ae7011135d058b671Garrett Cooper * 4.  The child thread lock 'rwlock' for reading, with pthread_rwlock_timedrdlock(),
200dc076565f772bb1953209fb69ea150b494aaa40robbiew *	specifying a 'abs_timeout'. The thread sleeps until 'abs_timeout' expires.
210dc076565f772bb1953209fb69ea150b494aaa40robbiew * 5.  The thread call pthread_rwlock_timedrdlock(). Should _NOT_ get ETIMEDOUT.
220dc076565f772bb1953209fb69ea150b494aaa40robbiew */
230dc076565f772bb1953209fb69ea150b494aaa40robbiew
240dc076565f772bb1953209fb69ea150b494aaa40robbiew#define _XOPEN_SOURCE 600
250dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <pthread.h>
260dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <stdio.h>
270dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <stdlib.h>
280dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <unistd.h>
290dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <errno.h>
300dc076565f772bb1953209fb69ea150b494aaa40robbiew#include "posixtest.h"
310dc076565f772bb1953209fb69ea150b494aaa40robbiew
320dc076565f772bb1953209fb69ea150b494aaa40robbiew#define NOT_CREATED_THREAD 1
330dc076565f772bb1953209fb69ea150b494aaa40robbiew#define ENTERED_THREAD 2
340dc076565f772bb1953209fb69ea150b494aaa40robbiew#define EXITING_THREAD 3
350dc076565f772bb1953209fb69ea150b494aaa40robbiew
360dc076565f772bb1953209fb69ea150b494aaa40robbiew#define TIMEOUT 1
372c28215423293e443469a07ae7011135d058b671Garrett Cooperstatic int thread_state;
380dc076565f772bb1953209fb69ea150b494aaa40robbiewstatic int currsec1;
390dc076565f772bb1953209fb69ea150b494aaa40robbiewstatic int expired;
400dc076565f772bb1953209fb69ea150b494aaa40robbiew
41354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic void *fn_rd_1(void *arg)
422c28215423293e443469a07ae7011135d058b671Garrett Cooper{
430dc076565f772bb1953209fb69ea150b494aaa40robbiew	thread_state = ENTERED_THREAD;
440dc076565f772bb1953209fb69ea150b494aaa40robbiew	struct timespec abs_timeout;
450dc076565f772bb1953209fb69ea150b494aaa40robbiew	int rc;
460dc076565f772bb1953209fb69ea150b494aaa40robbiew	pthread_rwlock_t rwlock;
470dc076565f772bb1953209fb69ea150b494aaa40robbiew
48354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_rwlock_init(&rwlock, NULL) != 0) {
490dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("thread1: Error at pthread_rwlock_init\n");
500dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
510dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
520dc076565f772bb1953209fb69ea150b494aaa40robbiew
530dc076565f772bb1953209fb69ea150b494aaa40robbiew	currsec1 = time(NULL);
540dc076565f772bb1953209fb69ea150b494aaa40robbiew
550dc076565f772bb1953209fb69ea150b494aaa40robbiew	/* Absolute time, not relative. */
560dc076565f772bb1953209fb69ea150b494aaa40robbiew	abs_timeout.tv_sec = currsec1 + TIMEOUT;
572c28215423293e443469a07ae7011135d058b671Garrett Cooper	abs_timeout.tv_nsec = 0;
580dc076565f772bb1953209fb69ea150b494aaa40robbiew
592c28215423293e443469a07ae7011135d058b671Garrett Cooper	printf("thread1: attempt timed read-lock\n");
600dc076565f772bb1953209fb69ea150b494aaa40robbiew	rc = pthread_rwlock_timedrdlock(&rwlock, &abs_timeout);
61354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (rc == ETIMEDOUT) {
620dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("thread1: timed read-lock expired\n");
630dc076565f772bb1953209fb69ea150b494aaa40robbiew		expired = 1;
64354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} else if (rc == 0) {
650dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("thread1: acquired read lock\n");
660dc076565f772bb1953209fb69ea150b494aaa40robbiew		expired = 0;
670dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("thread1: unlock read lock\n");
68354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (pthread_rwlock_unlock(&rwlock) != 0) {
692c28215423293e443469a07ae7011135d058b671Garrett Cooper			printf("thread1: failed to release read lock\n");
700dc076565f772bb1953209fb69ea150b494aaa40robbiew			exit(PTS_UNRESOLVED);
710dc076565f772bb1953209fb69ea150b494aaa40robbiew		}
72354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} else {
730dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("thread1: Error in pthread_rwlock_timedrdlock().\n");
740dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
750dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
762c28215423293e443469a07ae7011135d058b671Garrett Cooper
77354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_rwlock_destroy(&rwlock) != 0) {
780dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("thread1: Error at pthread_rwlockattr_destroy()");
790dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
802c28215423293e443469a07ae7011135d058b671Garrett Cooper	}
810dc076565f772bb1953209fb69ea150b494aaa40robbiew	thread_state = EXITING_THREAD;
820dc076565f772bb1953209fb69ea150b494aaa40robbiew	pthread_exit(0);
830dc076565f772bb1953209fb69ea150b494aaa40robbiew	return NULL;
840dc076565f772bb1953209fb69ea150b494aaa40robbiew}
852c28215423293e443469a07ae7011135d058b671Garrett Cooper
86354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic void *fn_rd_2(void *arg)
872c28215423293e443469a07ae7011135d058b671Garrett Cooper{
880dc076565f772bb1953209fb69ea150b494aaa40robbiew	thread_state = ENTERED_THREAD;
890dc076565f772bb1953209fb69ea150b494aaa40robbiew	struct timespec abs_timeout;
900dc076565f772bb1953209fb69ea150b494aaa40robbiew	int rc;
910dc076565f772bb1953209fb69ea150b494aaa40robbiew	pthread_rwlock_t rwlock;
920dc076565f772bb1953209fb69ea150b494aaa40robbiew
93354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_rwlock_init(&rwlock, NULL) != 0) {
940dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("thread2: Error at pthread_rwlock_init\n");
950dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
960dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
970dc076565f772bb1953209fb69ea150b494aaa40robbiew	currsec1 = time(NULL);
980dc076565f772bb1953209fb69ea150b494aaa40robbiew
990dc076565f772bb1953209fb69ea150b494aaa40robbiew	/* Ensure that the abs_timeout has passed by _subtracting_ the timeout value of 1
1000dc076565f772bb1953209fb69ea150b494aaa40robbiew	 * from the current time. */
1010dc076565f772bb1953209fb69ea150b494aaa40robbiew	abs_timeout.tv_sec = currsec1 - TIMEOUT;
1022c28215423293e443469a07ae7011135d058b671Garrett Cooper	abs_timeout.tv_nsec = 0;
1032c28215423293e443469a07ae7011135d058b671Garrett Cooper
1042c28215423293e443469a07ae7011135d058b671Garrett Cooper	printf("thread2: attempt timed read-lock\n");
1050dc076565f772bb1953209fb69ea150b494aaa40robbiew	rc = pthread_rwlock_timedrdlock(&rwlock, &abs_timeout);
106354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (rc == ETIMEDOUT) {
1070dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("thread2: timed read-lock expired\n");
1080dc076565f772bb1953209fb69ea150b494aaa40robbiew		expired = 1;
109354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} else if (rc == 0) {
1100dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("thread2: acquired read lock\n");
1110dc076565f772bb1953209fb69ea150b494aaa40robbiew		expired = 0;
1120dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("thread2: unlock read lock\n");
113354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (pthread_rwlock_unlock(&rwlock) != 0) {
1140dc076565f772bb1953209fb69ea150b494aaa40robbiew			printf("thread2: failed to release read lock\n");
1150dc076565f772bb1953209fb69ea150b494aaa40robbiew			exit(PTS_UNRESOLVED);
1160dc076565f772bb1953209fb69ea150b494aaa40robbiew		}
117354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} else {
1180dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("thread2: Error in pthread_rwlock_timedrdlock().\n");
1190dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
1200dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1212c28215423293e443469a07ae7011135d058b671Garrett Cooper
122354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_rwlock_destroy(&rwlock) != 0) {
1230dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("thread2: Error at pthread_rwlockattr_destroy()\n");
1240dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
1252c28215423293e443469a07ae7011135d058b671Garrett Cooper	}
1260dc076565f772bb1953209fb69ea150b494aaa40robbiew	thread_state = EXITING_THREAD;
1270dc076565f772bb1953209fb69ea150b494aaa40robbiew	pthread_exit(0);
1280dc076565f772bb1953209fb69ea150b494aaa40robbiew	return NULL;
1290dc076565f772bb1953209fb69ea150b494aaa40robbiew}
1300dc076565f772bb1953209fb69ea150b494aaa40robbiew
1314ca2bbdcd3003f3c8df4e6129e9c7b2bd1514f87Cyril Hrubisint main(void)
1320dc076565f772bb1953209fb69ea150b494aaa40robbiew{
1330dc076565f772bb1953209fb69ea150b494aaa40robbiew	int cnt = 0;
1342c28215423293e443469a07ae7011135d058b671Garrett Cooper
1350dc076565f772bb1953209fb69ea150b494aaa40robbiew	pthread_t thread1, thread2;
1362c28215423293e443469a07ae7011135d058b671Garrett Cooper
1370dc076565f772bb1953209fb69ea150b494aaa40robbiew	thread_state = NOT_CREATED_THREAD;
1380dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("main: create thread1\n");
139354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_create(&thread1, NULL, fn_rd_1, NULL) != 0) {
1400dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error when creating thread1\n");
1410dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
1420dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1432c28215423293e443469a07ae7011135d058b671Garrett Cooper
1440dc076565f772bb1953209fb69ea150b494aaa40robbiew	/* If the shared data is not altered by child after 5 seconds,
1450dc076565f772bb1953209fb69ea150b494aaa40robbiew	   we regard it as blocked */
1462c28215423293e443469a07ae7011135d058b671Garrett Cooper
1470dc076565f772bb1953209fb69ea150b494aaa40robbiew	/* we expect thread1 NOT to block, but rather for the timed read-lock to expire */
1480dc076565f772bb1953209fb69ea150b494aaa40robbiew	cnt = 0;
149354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	do {
1500dc076565f772bb1953209fb69ea150b494aaa40robbiew		sleep(1);
151354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} while (thread_state != EXITING_THREAD && cnt++ < 5);
1522c28215423293e443469a07ae7011135d058b671Garrett Cooper
153354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (thread_state == EXITING_THREAD) {
1540dc076565f772bb1953209fb69ea150b494aaa40robbiew		/* the child thread does not block, check the time expired or not */
155354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (expired == 1) {
156354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			printf
157354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			    ("Test FAILED: thread1 incorrectly received ETIMEDOUT\n");
1580dc076565f772bb1953209fb69ea150b494aaa40robbiew			return PTS_FAIL;
1590dc076565f772bb1953209fb69ea150b494aaa40robbiew		}
160354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} else if (thread_state == ENTERED_THREAD) {
161354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		printf
162354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    ("Test FAILED: thread1 incorrectly blocked for reading rwlock\n");
1630dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_FAIL;
164354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} else {
1650dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Unexpected state for thread1 %d\n", thread_state);
1660dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
1670dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1682c28215423293e443469a07ae7011135d058b671Garrett Cooper
169354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_join(thread1, NULL) != 0) {
1700dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error when joining thread1\n");
1710dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
1720dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1730dc076565f772bb1953209fb69ea150b494aaa40robbiew
1740dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("main: create thread2\n");
1750dc076565f772bb1953209fb69ea150b494aaa40robbiew	thread_state = NOT_CREATED_THREAD;
176354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_create(&thread2, NULL, fn_rd_2, NULL) != 0) {
1770dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error when creating thread2\n");
1780dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
1790dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1802c28215423293e443469a07ae7011135d058b671Garrett Cooper
1810dc076565f772bb1953209fb69ea150b494aaa40robbiew	/* If the shared data is not altered by child after 5 seconds,
1820dc076565f772bb1953209fb69ea150b494aaa40robbiew	   we regard it as blocked */
1832c28215423293e443469a07ae7011135d058b671Garrett Cooper
1840dc076565f772bb1953209fb69ea150b494aaa40robbiew	/* we expect thread2 NOT to block */
1850dc076565f772bb1953209fb69ea150b494aaa40robbiew	cnt = 0;
186354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	do {
1870dc076565f772bb1953209fb69ea150b494aaa40robbiew		sleep(1);
188354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} while (thread_state != EXITING_THREAD && cnt++ < 5);
1892c28215423293e443469a07ae7011135d058b671Garrett Cooper
190354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (thread_state == EXITING_THREAD) {
1910dc076565f772bb1953209fb69ea150b494aaa40robbiew		/* the child thread does not block, check the time expired or not */
192354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		if (expired == 1) {
193354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			printf
194354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao			    ("Test FAILED: thread2 incorrectly received ETIMEDOUT\n");
1950dc076565f772bb1953209fb69ea150b494aaa40robbiew			return PTS_FAIL;
1960dc076565f772bb1953209fb69ea150b494aaa40robbiew		}
197354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} else if (thread_state == ENTERED_THREAD) {
198354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		printf
199354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    ("Test FAILED: thread2 incorrectly blocked for reading rwlock\n");
2000dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_FAIL;
201354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} else {
2020dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Unexpected state for thread2 %d\n", thread_state);
2030dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
2040dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
2052c28215423293e443469a07ae7011135d058b671Garrett Cooper
206354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_join(thread2, NULL) != 0) {
2070dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error when join thread2\n");
2080dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
2090dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
2100dc076565f772bb1953209fb69ea150b494aaa40robbiew
2110dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("Test PASSED\n");
2120dc076565f772bb1953209fb69ea150b494aaa40robbiew	return PTS_PASS;
213ec6edca7aa42b6affd989ef91b5897f96795e40fChris Dearman}
214