1 /*
2  * Copyright (c) 2002, Intel Corporation. All rights reserved.
3  * This file is licensed under the GPL license.  For the full content
4  * of this license, see the COPYING file at the top level of this
5  * source tree.
6 
7  * Test that pthread_rwlock_unlock(pthread_rwlock_t *rwlock)
8  *
9  *	It 'may' fail if:
10  *	[EINVAL]  rwlock doesn't refer to an initialized read-write lock
11  *	[EPERM]  the current thread doesn't hold the lock on the rwlock
12  *
13  *	Testing EPERM in this test.
14  *
15  *
16  * Steps:
17  * 1.  Initialize a pthread_rwlock_t object 'rwlock' with pthread_rwlock_init()
18  * 2.  Main thread read lock 'rwlock'
19  * 3.  Create a child thread, the thread should try to unlock the 'rwlock'
20  * 4. The test will pass even if it returns 0, but with a note stating that the standard
21  *     states it 'may' fail.
22  */
23 
24 #include <pthread.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <errno.h>
29 #include "posixtest.h"
30 
31 static pthread_rwlock_t rwlock;
32 static int rc, thread_state;
33 
34 /* thread_state indicates child thread state:
35 	1: not in child thread yet;
36 	2: just enter child thread ;
37 	3: just before child thread exit;
38 */
39 
40 #define NOT_CREATED_THREAD 1
41 #define ENTERED_THREAD 2
42 #define EXITING_THREAD 3
43 
fn_unlk(void * arg PTS_ATTRIBUTE_UNUSED)44 static void *fn_unlk(void *arg PTS_ATTRIBUTE_UNUSED)
45 {
46 	thread_state = ENTERED_THREAD;
47 	printf("un_thread: unlock read lock\n");
48 	rc = pthread_rwlock_unlock(&rwlock);
49 	thread_state = EXITING_THREAD;
50 	return NULL;
51 }
52 
main(void)53 int main(void)
54 {
55 	int cnt = 0;
56 
57 	pthread_t un_thread;
58 
59 #ifdef __linux__
60 	printf("Unlocking rwlock in different thread is undefined on Linux\n");
61 	return PTS_UNSUPPORTED;
62 #endif
63 
64 	if (pthread_rwlock_init(&rwlock, NULL) != 0) {
65 		printf("main: Error at pthread_rwlock_init()\n");
66 		return PTS_UNRESOLVED;
67 	}
68 
69 	printf("main: attempt read lock\n");
70 
71 	if (pthread_rwlock_rdlock(&rwlock) != 0) {
72 		printf("main: Error at pthread_rwlock_rdlock()\n");
73 		return PTS_UNRESOLVED;
74 	}
75 	printf("main: acquired read lock\n");
76 
77 	thread_state = NOT_CREATED_THREAD;
78 
79 	printf("main: create un_thread\n");
80 	if (pthread_create(&un_thread, NULL, fn_unlk, NULL) != 0) {
81 		printf("main: Error at pthread_create()\n");
82 		return PTS_UNRESOLVED;
83 	}
84 
85 	/* Wait for child to exit */
86 	cnt = 0;
87 	do {
88 		sleep(1);
89 	} while (thread_state != EXITING_THREAD && cnt++ < 3);
90 
91 	if (thread_state != EXITING_THREAD) {
92 		printf("Unexpected thread state %d\n", thread_state);
93 		exit(PTS_UNRESOLVED);
94 	}
95 
96 	if (pthread_join(un_thread, NULL) != 0) {
97 		printf("Error at pthread_join()\n");
98 		exit(PTS_UNRESOLVED);
99 	}
100 
101 	/* Cleaning up */
102 	pthread_rwlock_unlock(&rwlock);
103 	if (pthread_rwlock_destroy(&rwlock) != 0) {
104 		printf("error at pthread_rwlock_destroy()\n");
105 		return PTS_UNRESOLVED;
106 	}
107 
108 	/* Test the return code of un_thread when it attempt to unlock the rwlock it didn't
109 	 * own in the first place. */
110 
111 	if (rc != 0) {
112 		if (rc == EPERM) {
113 			printf("Test PASSED\n");
114 			return PTS_PASS;
115 		}
116 
117 		printf
118 		    ("Test FAILED: Incorrect error code, expected 0 or EPERM, got %d\n",
119 		     rc);
120 		return PTS_FAIL;
121 	}
122 
123 	printf
124 	    ("Test PASSED: Note*: Returned 0 instead of EPERM, but standard specified _may_ fail.\n");
125 	return PTS_PASS;
126 }
127