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