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 #define _XOPEN_SOURCE 600 27 #include <pthread.h> 28 #include <stdio.h> 29 #include <stdlib.h> 30 #include <unistd.h> 31 #include <errno.h> 32 #include <sys/time.h> 33 #include "posixtest.h" 34 35 /* thread_state indicates child thread state: 36 1: not in child thread yet; 37 2: just enter child thread ; 38 3: just before child thread exit; 39 */ 40 41 #define NOT_CREATED_THREAD 1 42 #define ENTERED_THREAD 2 43 #define EXITING_THREAD 3 44 45 #define TIMEOUT 3 46 47 static pthread_rwlock_t rwlock; 48 static int thread_state; 49 static struct timeval currsec1, currsec2; 50 51 static void *fn_rd(void *arg) 52 { 53 54 thread_state = ENTERED_THREAD; 55 struct timespec timeout; 56 int rc; 57 58 gettimeofday(&currsec1, NULL); 59 60 /* Absolute time, not relative. */ 61 timeout.tv_sec = currsec1.tv_sec + TIMEOUT; 62 timeout.tv_nsec = currsec1.tv_usec * 1000; 63 64 printf("thread: attempt timed read lock, %d secs\n", TIMEOUT); 65 rc = pthread_rwlock_timedrdlock(&rwlock, &timeout); 66 if (rc == ETIMEDOUT) 67 printf("thread: timer expired\n"); 68 else if (rc == 0) { 69 printf("thread: acquired read lock\n"); 70 printf("thread: unlock read lock\n"); 71 if (pthread_rwlock_unlock(&rwlock) != 0) { 72 exit(PTS_UNRESOLVED); 73 } 74 } else { 75 printf 76 ("Error: thread: in pthread_rwlock_timedrdlock(), return code:%d\n", 77 rc); 78 exit(PTS_UNRESOLVED); 79 } 80 81 /* Get time after the pthread_rwlock_timedrdlock() call. */ 82 gettimeofday(&currsec2, NULL); 83 thread_state = EXITING_THREAD; 84 pthread_exit(0); 85 return NULL; 86 } 87 88 int main(void) 89 { 90 int cnt = 0; 91 pthread_t rd_thread1, rd_thread2; 92 93 if (pthread_rwlock_init(&rwlock, NULL) != 0) { 94 printf("main: Error at pthread_rwlock_init()\n"); 95 return PTS_UNRESOLVED; 96 } 97 98 printf("main: attempt read lock\n"); 99 if (pthread_rwlock_rdlock(&rwlock) != 0) { 100 printf("main: Error at pthread_rwlock_rdlock()\n"); 101 return PTS_UNRESOLVED; 102 } 103 printf("main: acquired read lock\n"); 104 105 thread_state = NOT_CREATED_THREAD; 106 107 printf("main: create rd_thread1\n"); 108 if (pthread_create(&rd_thread1, NULL, fn_rd, NULL) != 0) { 109 printf("main: Error when creating rd_thread1\n"); 110 return PTS_UNRESOLVED; 111 } 112 113 /* If the shared data is not altered by child after 5 seconds, 114 we regard it as blocked */ 115 116 /* we expect the thread not to block */ 117 cnt = 0; 118 do { 119 sleep(1); 120 } while (thread_state != EXITING_THREAD && cnt++ < 5); 121 122 if (thread_state == ENTERED_THREAD) { 123 /* the child thread started but blocked */ 124 printf 125 ("Test FAILED: rd_thread1 blocked on pthread_rwlock_timedrdlock()\n"); 126 exit(PTS_FAIL); 127 } else if (thread_state != EXITING_THREAD) { 128 printf("Unexpected thread state %d\n", thread_state); 129 exit(PTS_UNRESOLVED); 130 } 131 132 if (pthread_join(rd_thread1, NULL) != 0) { 133 printf("main: Error when join rd_thread1\n"); 134 exit(PTS_UNRESOLVED); 135 } 136 137 printf("main: unlock read lock\n"); 138 if (pthread_rwlock_unlock(&rwlock) != 0) { 139 printf("main: Error when release read lock\n"); 140 return PTS_UNRESOLVED; 141 } 142 143 printf("main: attempt write lock\n"); 144 if (pthread_rwlock_wrlock(&rwlock) != 0) { 145 printf("main: Failed to get write lock\n"); 146 return PTS_UNRESOLVED; 147 } 148 printf("main: acquired write lock\n"); 149 150 thread_state = NOT_CREATED_THREAD; 151 printf("main: create rd_thread2\n"); 152 if (pthread_create(&rd_thread2, NULL, fn_rd, NULL) != 0) { 153 printf("main: Failed to create rd_thread2\n"); 154 return PTS_UNRESOLVED; 155 } 156 157 /* we expect rd_thread2 to block and timeout. */ 158 cnt = 0; 159 do { 160 sleep(1); 161 } while (thread_state != EXITING_THREAD && cnt++ < 5); 162 163 if (thread_state == EXITING_THREAD) { 164 /* the child thread does not block, check the time interval */ 165 struct timeval time_diff; 166 time_diff.tv_sec = currsec2.tv_sec - currsec1.tv_sec; 167 time_diff.tv_usec = currsec2.tv_usec - currsec1.tv_usec; 168 if (time_diff.tv_usec < 0) { 169 --time_diff.tv_sec; 170 time_diff.tv_usec += 1000000; 171 } 172 if (time_diff.tv_sec < TIMEOUT) { 173 printf 174 ("Test FAILED: the timer expired and thread terminated, but the timeout is not correct: start time %ld.%06ld, end time %ld.%06ld\n", 175 (long)currsec1.tv_sec, (long)currsec1.tv_usec, 176 (long)currsec2.tv_sec, (long)currsec2.tv_usec); 177 exit(PTS_FAIL); 178 } else 179 printf("thread: read lock correctly timed out\n"); 180 } else if (thread_state == ENTERED_THREAD) { 181 printf 182 ("Test FAILED: read block was not terminated even when the timer expired\n"); 183 exit(PTS_FAIL); 184 } else { 185 printf("Unexpected thread state %d\n", thread_state); 186 return PTS_UNRESOLVED; 187 } 188 189 printf("main: unlock write lock\n"); 190 if (pthread_rwlock_unlock(&rwlock) != 0) { 191 printf("main: Failed to release write lock\n"); 192 exit(PTS_UNRESOLVED); 193 } 194 195 if (pthread_rwlock_destroy(&rwlock) != 0) { 196 printf("Error at pthread_rwlockattr_destroy()\n"); 197 exit(PTS_UNRESOLVED); 198 } 199 200 printf("Test PASSED\n"); 201 return PTS_PASS; 202 } 203