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