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 pthread_rwlock_trywrlock(pthread_rwlock_t *rwlock)
80dc076565f772bb1953209fb69ea150b494aaa40robbiew *
92c28215423293e443469a07ae7011135d058b671Garrett Cooper * The function shall apply a write lock like the pthread_rwlock_wrlock(), with the exception
100dc076565f772bb1953209fb69ea150b494aaa40robbiew * that the funciton shall fail if any thread currently holds rwlock(for reading and writing).
110dc076565f772bb1953209fb69ea150b494aaa40robbiew *
120dc076565f772bb1953209fb69ea150b494aaa40robbiew * Steps:
130dc076565f772bb1953209fb69ea150b494aaa40robbiew * 1.  Initialize a pthread_rwlock_t object 'rwlock' with pthread_rwlock_init()
140dc076565f772bb1953209fb69ea150b494aaa40robbiew * 2.  Main thread lock 'rwlock' for reading with pthread_rwlock_rdlock()
152c28215423293e443469a07ae7011135d058b671Garrett Cooper * 3.  Create a child thread, the thread locks 'rwlock' for writing, using
160dc076565f772bb1953209fb69ea150b494aaa40robbiew *     pthread_rwlock_trywrlock(), should get EBUSY
170dc076565f772bb1953209fb69ea150b494aaa40robbiew * 4.  Main thread unlocks 'rwlock'
182c28215423293e443469a07ae7011135d058b671Garrett Cooper * 5.  Main thread locks 'rwlock' for writing, using pthread_rwlock_trywrlock(),
190dc076565f772bb1953209fb69ea150b494aaa40robbiew *     should get the lock successfully
202c28215423293e443469a07ae7011135d058b671Garrett Cooper * 6.  Create child thread to lock 'rwlock' for writing, with pthread_rwlock_trywrlock(),
210dc076565f772bb1953209fb69ea150b494aaa40robbiew *     should get EBUSY
220dc076565f772bb1953209fb69ea150b494aaa40robbiew * 7.  Main thread unlock 'rwlock'
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
320dc076565f772bb1953209fb69ea150b494aaa40robbiewstatic pthread_rwlock_t rwlock;
330dc076565f772bb1953209fb69ea150b494aaa40robbiewstatic int thread_state;
342c28215423293e443469a07ae7011135d058b671Garrett Cooperstatic int get_ebusy;
350dc076565f772bb1953209fb69ea150b494aaa40robbiew
362c28215423293e443469a07ae7011135d058b671Garrett Cooper/* thread_state indicates child thread state:
372c28215423293e443469a07ae7011135d058b671Garrett Cooper	1: not in child thread yet;
380dc076565f772bb1953209fb69ea150b494aaa40robbiew	2: just enter child thread ;
390dc076565f772bb1953209fb69ea150b494aaa40robbiew	3: just before child thread exit;
400dc076565f772bb1953209fb69ea150b494aaa40robbiew*/
410dc076565f772bb1953209fb69ea150b494aaa40robbiew
420dc076565f772bb1953209fb69ea150b494aaa40robbiew#define NOT_CREATED_THREAD 1
430dc076565f772bb1953209fb69ea150b494aaa40robbiew#define ENTERED_THREAD 2
440dc076565f772bb1953209fb69ea150b494aaa40robbiew#define EXITING_THREAD 3
450dc076565f772bb1953209fb69ea150b494aaa40robbiew
46354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic void *fn_wr(void *arg)
472c28215423293e443469a07ae7011135d058b671Garrett Cooper{
480dc076565f772bb1953209fb69ea150b494aaa40robbiew	thread_state = ENTERED_THREAD;
490dc076565f772bb1953209fb69ea150b494aaa40robbiew	int rc;
500dc076565f772bb1953209fb69ea150b494aaa40robbiew
512c28215423293e443469a07ae7011135d058b671Garrett Cooper	printf("thread: attempt pthread_rwlock_trywrlock()\n");
520dc076565f772bb1953209fb69ea150b494aaa40robbiew	rc = pthread_rwlock_trywrlock(&rwlock);
53354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (rc != EBUSY) {
540dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Test FAILED: thread: Expected EBUSY, got %d\n", rc);
550dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_FAIL);
560dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
570dc076565f772bb1953209fb69ea150b494aaa40robbiew	get_ebusy = 1;
580dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("thread: correctly got EBUSY\n");
590dc076565f772bb1953209fb69ea150b494aaa40robbiew	thread_state = EXITING_THREAD;
600dc076565f772bb1953209fb69ea150b494aaa40robbiew	pthread_exit(0);
610dc076565f772bb1953209fb69ea150b494aaa40robbiew	return NULL;
620dc076565f772bb1953209fb69ea150b494aaa40robbiew}
632c28215423293e443469a07ae7011135d058b671Garrett Cooper
644ca2bbdcd3003f3c8df4e6129e9c7b2bd1514f87Cyril Hrubisint main(void)
650dc076565f772bb1953209fb69ea150b494aaa40robbiew{
660dc076565f772bb1953209fb69ea150b494aaa40robbiew	int cnt = 0;
670dc076565f772bb1953209fb69ea150b494aaa40robbiew	int rc = 0;
680dc076565f772bb1953209fb69ea150b494aaa40robbiew	pthread_t thread1, thread2;
692c28215423293e443469a07ae7011135d058b671Garrett Cooper
700dc076565f772bb1953209fb69ea150b494aaa40robbiew	get_ebusy = 0;
712c28215423293e443469a07ae7011135d058b671Garrett Cooper
72354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_rwlock_init(&rwlock, NULL) != 0) {
730dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("main: Error at pthread_rwlock_init()\n");
740dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
750dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
762c28215423293e443469a07ae7011135d058b671Garrett Cooper
770dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("main: attempt read lock\n");
782c28215423293e443469a07ae7011135d058b671Garrett Cooper	/* We have no lock, this read lock should succeed */
79354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_rwlock_rdlock(&rwlock) != 0) {
800dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("main: Error at pthread_rwlock_rdlock()\n");
810dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
820dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
830dc076565f772bb1953209fb69ea150b494aaa40robbiew
840dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("main: acquired read lock\n");
850dc076565f772bb1953209fb69ea150b494aaa40robbiew	thread_state = NOT_CREATED_THREAD;
860dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("main: create thread1\n");
87354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_create(&thread1, NULL, fn_wr, NULL) != 0) {
880dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error creating thread1\n");
890dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
900dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
912c28215423293e443469a07ae7011135d058b671Garrett Cooper
920dc076565f772bb1953209fb69ea150b494aaa40robbiew	/* If the shared data is not altered by child after 3 seconds,
930dc076565f772bb1953209fb69ea150b494aaa40robbiew	   we regard it as blocked */
940dc076565f772bb1953209fb69ea150b494aaa40robbiew	/* We do no expect thread1 to block */
950dc076565f772bb1953209fb69ea150b494aaa40robbiew	cnt = 0;
96354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	do {
970dc076565f772bb1953209fb69ea150b494aaa40robbiew		sleep(1);
98354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} while (thread_state != EXITING_THREAD && cnt++ < 3);
992c28215423293e443469a07ae7011135d058b671Garrett Cooper
100354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (thread_state == ENTERED_THREAD) {
1010dc076565f772bb1953209fb69ea150b494aaa40robbiew		/* the child thread blocked */
102354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		printf
103354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    ("Test FAILED: thread1 should not block on pthread_rwlock_trywrlock()\n");
1040dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_FAIL);
105354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} else if (thread_state != EXITING_THREAD) {
106354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		printf("Unexpected thread state for thread1: %d\n",
107354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		       thread_state);
1080dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
1090dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1102c28215423293e443469a07ae7011135d058b671Garrett Cooper
111354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (get_ebusy != 1) {
1120dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Test FAILED: thread1 should get EBUSY\n");
1130dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_FAIL);
1140dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1150dc076565f772bb1953209fb69ea150b494aaa40robbiew
1160dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("main: unlock read lock\n");
117354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_rwlock_unlock(&rwlock) != 0) {
1180dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("main: Error releasing read lock\n");
1190dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
1200dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1212c28215423293e443469a07ae7011135d058b671Garrett Cooper
122354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_join(thread1, NULL) != 0) {
1230dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("main: Error joining thread1\n");
1240dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
1250dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1262c28215423293e443469a07ae7011135d058b671Garrett Cooper
1270dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("main: attempt pthread_rwlock_trywrlock()\n");
128354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	/* Should get the write lock */
1290dc076565f772bb1953209fb69ea150b494aaa40robbiew	rc = pthread_rwlock_trywrlock(&rwlock);
130354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (rc != 0) {
131354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		printf
132354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    ("Test FAILED: main failed at pthread_rwlock_trywrlock(), error code: %d\n",
133354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		     rc);
1342c28215423293e443469a07ae7011135d058b671Garrett Cooper		return PTS_FAIL;
1350dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1360dc076565f772bb1953209fb69ea150b494aaa40robbiew
1370dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("main: acquired write lock\n");
1380dc076565f772bb1953209fb69ea150b494aaa40robbiew
1390dc076565f772bb1953209fb69ea150b494aaa40robbiew	get_ebusy = 0;
1400dc076565f772bb1953209fb69ea150b494aaa40robbiew	thread_state = NOT_CREATED_THREAD;
1410dc076565f772bb1953209fb69ea150b494aaa40robbiew	cnt = 0;
1420dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("main: create thread2\n");
143354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_create(&thread2, NULL, fn_wr, NULL) != 0) {
1440dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("main: Error creating thread2\n");
1450dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
1460dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1472c28215423293e443469a07ae7011135d058b671Garrett Cooper
1480dc076565f772bb1953209fb69ea150b494aaa40robbiew	/* We do not expect thread2 to block */
149354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	do {
1500dc076565f772bb1953209fb69ea150b494aaa40robbiew		sleep(1);
151354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} while (thread_state != EXITING_THREAD && cnt++ < 3);
1522c28215423293e443469a07ae7011135d058b671Garrett Cooper
153354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (thread_state == ENTERED_THREAD) {
154354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		printf
155354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao		    ("Test FAILED: thread2 should not block on pthread_rwlock_trywrlock()\n");
1560dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_FAIL);
157354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	} else if (thread_state != EXITING_THREAD) {
1580dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Unexpected thread state: %d\n", thread_state);
1590dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
1600dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1610dc076565f772bb1953209fb69ea150b494aaa40robbiew
162354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (get_ebusy != 1) {
1630dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Test FAILED: thread2 should get EBUSY\n");
1640dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_FAIL);
1650dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1662c28215423293e443469a07ae7011135d058b671Garrett Cooper
1670dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("main: unlock write lock\n");
1680dc076565f772bb1953209fb69ea150b494aaa40robbiew	thread_state = 1;
169354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_rwlock_unlock(&rwlock) != 0) {
1700dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("main: Error at 2nd pthread_rwlock_unlock()\n");
1710dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
1720dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1730dc076565f772bb1953209fb69ea150b494aaa40robbiew
174354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_join(thread2, NULL) != 0) {
1750dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("main: Error at 2cn pthread_join()\n");
1760dc076565f772bb1953209fb69ea150b494aaa40robbiew		exit(PTS_UNRESOLVED);
1770dc076565f772bb1953209fb69ea150b494aaa40robbiew	}
1782c28215423293e443469a07ae7011135d058b671Garrett Cooper
179354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao	if (pthread_rwlock_destroy(&rwlock) != 0) {
1800dc076565f772bb1953209fb69ea150b494aaa40robbiew		printf("Error at pthread_rwlockattr_destroy()\n");
1810dc076565f772bb1953209fb69ea150b494aaa40robbiew		return PTS_UNRESOLVED;
1822c28215423293e443469a07ae7011135d058b671Garrett Cooper	}
1830dc076565f772bb1953209fb69ea150b494aaa40robbiew
1840dc076565f772bb1953209fb69ea150b494aaa40robbiew	printf("Test PASSED\n");
1850dc076565f772bb1953209fb69ea150b494aaa40robbiew	return PTS_PASS;
186ec6edca7aa42b6affd989ef91b5897f96795e40fChris Dearman}
187