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_timedrdlock(pthread_rwlock_t *rwlock)
8 *
9 * The function shall apply a read lock to the read-write lock referenced by
10 * rwlock as in the pthread_rwlock_rdlock(). However, if the lock cannot be
11 * acquired with out waiting for other threads to unlock the lock, this wait
12 * shall be terminated when the specified timeout expires.
13 *
14 * Steps:
15 * 1. Initialize a pthread_rwlock_t object 'rwlock' with pthread_rwlock_init()
16 * 2. Main thread lock 'rwlock' for reading with pthread_rwlock_rdlock()
17 * 3. Create a child thread, the thread lock 'rwlock' for reading,
18 * using pthread_rwlock_timedrdlock(), should get read lock. Thread unlocks 'rwlock'.
19 * 4. Main thread unlock 'rwlock'
20 * 5. Main thread lock 'rwlock' for writing
21 * 6. Create child thread to lock 'rwlock' for reading,
22 * using pthread_rwlock_timedrdlock, should block
23 * but when the timer expires, the wait will be terminated
24 * 7. Main thread unlock 'rwlock'
25 */
26
27 /* Test for CLOCK_REALTIME */
28
29 #define _XOPEN_SOURCE 600
30 #include <pthread.h>
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <errno.h>
35 #include <sys/time.h>
36 #include "posixtest.h"
37
38 /* thread_state indicates child thread state:
39 1: not in child thread yet;
40 2: just enter child thread ;
41 3: just before child thread exit;
42 */
43
44 #define NOT_CREATED_THREAD 1
45 #define ENTERED_THREAD 2
46 #define EXITING_THREAD 3
47
48 #define TIMEOUT 3
49
50 static pthread_rwlock_t rwlock;
51 static int thread_state;
52 static struct timeval currsec1, currsec2;
53
fn_rd(void * arg)54 static void* fn_rd(void *arg)
55 {
56
57 thread_state = ENTERED_THREAD;
58 struct timespec timeout, ts;
59 int rc;
60 #ifdef CLOCK_REALTIME
61 printf("Test CLOCK_REALTIME\n");
62 clock_gettime(CLOCK_REALTIME, &ts);
63 currsec1.tv_sec = ts.tv_sec;
64 currsec1.tv_usec = ts.tv_nsec / 1000;
65 #else
66 gettimeofday(&currsec1, NULL);
67 #endif
68 /* Absolute time, not relative. */
69 timeout.tv_sec = currsec1.tv_sec + TIMEOUT;
70 timeout.tv_nsec = currsec1.tv_usec * 1000;
71
72 printf("thread: attempt timed read lock, %d secs\n", TIMEOUT);
73 rc = pthread_rwlock_timedrdlock(&rwlock, &timeout);
74 if(rc == ETIMEDOUT)
75 printf("thread: timer expired\n");
76 else if(rc == 0)
77 {
78 printf("thread: acquired read lock\n");
79 printf("thread: unlock read lock\n");
80 if(pthread_rwlock_unlock(&rwlock) != 0)
81 {
82 exit(PTS_UNRESOLVED);
83 }
84 }
85 else
86 {
87 printf("Error: thread: in pthread_rwlock_timedrdlock(), return code:%d\n", rc);
88 exit(PTS_UNRESOLVED);
89 }
90
91 /* Get time after the pthread_rwlock_timedrdlock() call. */
92 #ifdef CLOCK_REALTIME
93 clock_gettime(CLOCK_REALTIME, &ts);
94 currsec2.tv_sec = ts.tv_sec;
95 currsec2.tv_usec = ts.tv_nsec / 1000;
96 #else
97 gettimeofday(&currsec2, NULL);
98 #endif
99 thread_state = EXITING_THREAD;
100 pthread_exit(0);
101 return NULL;
102 }
103
main()104 int main()
105 {
106 int cnt = 0;
107 pthread_t rd_thread1, rd_thread2;
108
109 if(pthread_rwlock_init(&rwlock, NULL) != 0)
110 {
111 printf("main: Error at pthread_rwlock_init()\n");
112 return PTS_UNRESOLVED;
113 }
114
115 printf("main: attempt read lock\n");
116 if(pthread_rwlock_rdlock(&rwlock) != 0)
117 {
118 printf("main: Error at pthread_rwlock_rdlock()\n");
119 return PTS_UNRESOLVED;
120 }
121 printf("main: acquired read lock\n");
122
123 thread_state = NOT_CREATED_THREAD;
124
125 printf("main: create rd_thread1\n");
126 if(pthread_create(&rd_thread1, NULL, fn_rd, NULL) != 0)
127 {
128 printf("main: Error when creating rd_thread1\n");
129 return PTS_UNRESOLVED;
130 }
131
132 /* If the shared data is not altered by child after 5 seconds,
133 we regard it as blocked */
134
135 /* we expect the thread not to block */
136 cnt = 0;
137 do{
138 sleep(1);
139 }while (thread_state !=EXITING_THREAD && cnt++ < 5);
140
141 if(thread_state == ENTERED_THREAD)
142 {
143 /* the child thread started but blocked */
144 printf("Test FAILED: rd_thread1 blocked on pthread_rwlock_timedrdlock()\n");
145 exit(PTS_FAIL);
146 }
147 else if(thread_state != EXITING_THREAD)
148 {
149 printf("Unexpected thread state %d\n", thread_state);
150 exit(PTS_UNRESOLVED);
151 }
152
153 if(pthread_join(rd_thread1, NULL) != 0)
154 {
155 printf("main: Error when join rd_thread1\n");
156 exit(PTS_UNRESOLVED);
157 }
158
159 printf("main: unlock read lock\n");
160 if(pthread_rwlock_unlock(&rwlock) != 0)
161 {
162 printf("main: Error when release read lock\n");
163 return PTS_UNRESOLVED;
164 }
165
166 printf("main: attempt write lock\n");
167 if(pthread_rwlock_wrlock(&rwlock) != 0)
168 {
169 printf("main: Failed to get write lock\n");
170 return PTS_UNRESOLVED;
171 }
172 printf("main: acquired write lock\n");
173
174 thread_state = NOT_CREATED_THREAD;
175 printf("main: create rd_thread2\n");
176 if(pthread_create(&rd_thread2, NULL, fn_rd, NULL) != 0)
177 {
178 printf("main: Failed to create rd_thread2\n");
179 return PTS_UNRESOLVED;
180 }
181
182 /* we expect rd_thread2 to block and timeout. */
183 cnt = 0;
184 do{
185 sleep(1);
186 }while (thread_state !=EXITING_THREAD && cnt++ < 5);
187
188 if(thread_state == EXITING_THREAD)
189 {
190 /* the child thread does not block, check the time interval */
191 struct timeval time_diff;
192 time_diff.tv_sec = currsec2.tv_sec - currsec1.tv_sec;
193 time_diff.tv_usec = currsec2.tv_usec - currsec1.tv_usec;
194 if (time_diff.tv_usec < 0)
195 {
196 --time_diff.tv_sec;
197 time_diff.tv_usec += 1000000;
198 }
199 if(time_diff.tv_sec < TIMEOUT)
200 {
201 printf("Test FAILED: the timer expired and thread terminated, "
202 "but the timeout is not correct: "
203 "start time %ld.%06ld, end time %ld.%06ld\n",
204 (long) currsec1.tv_sec, (long) currsec1.tv_usec,
205 (long) currsec2.tv_sec, (long) currsec2.tv_usec);
206 exit(PTS_FAIL);
207 } else
208 printf("thread: read lock correctly timed out\n");
209 }
210 else if(thread_state == ENTERED_THREAD)
211 {
212 printf("Test FAILED: read block was not terminated even when the timer expired\n");
213 exit(PTS_FAIL);
214 }
215 else
216 {
217 printf("Unexpected thread state %d\n", thread_state);
218 return PTS_UNRESOLVED;
219 }
220
221 printf("main: unlock write lock\n");
222 if(pthread_rwlock_unlock(&rwlock) != 0)
223 {
224 printf("main: Failed to release write lock\n");
225 exit(PTS_UNRESOLVED);
226 }
227
228 if(pthread_rwlock_destroy(&rwlock) != 0)
229 {
230 printf("Error at pthread_rwlockattr_destroy()\n");
231 exit(PTS_UNRESOLVED);
232 }
233
234 printf("Test PASSED\n");
235 return PTS_PASS;
236 }
237