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 * Test pthread_rwlock_timedrdlock(pthread_rwlock_t * rwlock) 7 * 8 * If a signal that causes a signal handler to be executed is delivered to 9 * a thread blocked on a read-write lock via a call to pthread_rwlock_timedrdlock(), 10 * upon return from the signal handler the thread shall resume waiting for the lock 11 * as if it was not interrupted. 12 * 13 * Test that after returning from a signal handler, the reader will continue 14 * to wait with timedrdlock as long as the specified 'timeout' does not expire (the 15 * time spent in signal handler is longer than the specifed 'timeout'). 16 * 17 * Steps: 18 * 1. main thread create and write lock 'rwlock' 19 * 2. main thread create a thread sig_thread, the thread is set to handle SIGUSR1 20 * 3. sig_thread timed read-lock 'rwlock' for reading, it should block 21 * 4. While the sig_thread is waiting (not expired yet), main thread sends SIGUSR1 22 * to sig_thread via pthread_kill 23 * 5. Check that when thread handler returns, sig_thread resume block 24 * 7. When the wait is terminated, check that the thread wait for a proper period before 25 * expiring. 26 * 27 */ 28 29 #define _XOPEN_SOURCE 600 30 #include <pthread.h> 31 #include <stdio.h> 32 #include <stdlib.h> 33 #include <signal.h> 34 #include <errno.h> 35 #include <unistd.h> 36 #include <time.h> 37 #include <sys/time.h> 38 #include "posixtest.h" 39 40 static pthread_t sig_thread; 41 static pthread_rwlock_t rwlock; 42 43 static int thread_state; 44 static int handler_called; 45 static struct timeval before_wait, after_wait; 46 47 /* thread_state indicates child thread state: 48 1: not in child thread yet; 49 2: just enter child thread ; 50 3: just before child thread exit; 51 */ 52 53 #define NOT_CREATED_THREAD 1 54 #define ENTERED_THREAD 2 55 #define EXITING_THREAD 3 56 57 #define TIMEOUT 5 58 59 /* Signal handler called by the thread when SIGUSR1 is received */ 60 static void sig_handler() 61 { 62 63 if (pthread_equal(pthread_self(), sig_thread)) { 64 printf("sig_handler: signal is handled by sig_thread\n"); 65 handler_called = 1; 66 67 } else { 68 printf("sig_handler: signal is not handled by sig_thread\n"); 69 exit(PTS_UNRESOLVED); 70 } 71 } 72 73 static void *th_fn(void *arg) 74 { 75 struct sigaction act; 76 struct timespec abs_timeout; 77 int rc = 0; 78 79 handler_called = 0; 80 81 /* Set up signal handler for SIGUSR1 */ 82 83 act.sa_flags = 0; 84 act.sa_handler = sig_handler; 85 /* block all the signal when hanlding SIGUSR1 */ 86 sigfillset(&act.sa_mask); 87 sigaction(SIGUSR1, &act, 0); 88 89 gettimeofday(&before_wait, NULL); 90 abs_timeout.tv_sec = before_wait.tv_sec; 91 abs_timeout.tv_nsec = before_wait.tv_usec * 1000; 92 abs_timeout.tv_sec += TIMEOUT; 93 94 printf("thread: attempt timed read lock, %d seconds\n", TIMEOUT); 95 thread_state = ENTERED_THREAD; 96 rc = pthread_rwlock_timedrdlock(&rwlock, &abs_timeout); 97 if (rc != ETIMEDOUT) { 98 printf("sig_thread: pthread_rwlock_timedlock returns %d\n", rc); 99 exit(PTS_FAIL); 100 } 101 printf("thread: timer correctly expired\n"); 102 gettimeofday(&after_wait, NULL); 103 104 thread_state = EXITING_THREAD; 105 pthread_exit(0); 106 return NULL; 107 } 108 109 int main(void) 110 { 111 int cnt; 112 struct timeval wait_time; 113 114 if (pthread_rwlock_init(&rwlock, NULL) != 0) { 115 printf("Error at pthread_rwlock_init()\n"); 116 return PTS_UNRESOLVED; 117 } 118 119 printf("main: attempt write lock\n"); 120 if (pthread_rwlock_wrlock(&rwlock) != 0) { 121 printf("main: Error at pthread_rwlock_wrlock()\n"); 122 return PTS_UNRESOLVED; 123 } 124 printf("main: acquired write lock\n"); 125 126 thread_state = NOT_CREATED_THREAD; 127 if (pthread_create(&sig_thread, NULL, th_fn, NULL) != 0) { 128 printf("Error at pthread_create()\n"); 129 return PTS_UNRESOLVED; 130 } 131 132 /* Wait for the thread to get ready for handling signal (the thread should 133 * be block on rwlock since main() has the write lock at this point) */ 134 cnt = 0; 135 do { 136 sleep(1); 137 } while (thread_state != ENTERED_THREAD && cnt++ < TIMEOUT); 138 139 if (thread_state != ENTERED_THREAD) { 140 printf("Unexpected thread state %d\n", thread_state); 141 exit(PTS_UNRESOLVED); 142 } 143 144 printf("main: fire SIGUSR1 to thread\n"); 145 if (pthread_kill(sig_thread, SIGUSR1) != 0) { 146 printf("main: Error at pthread_kill()\n"); 147 exit(PTS_UNRESOLVED); 148 } 149 150 /* wait at most 2*TIMEOUT seconds */ 151 cnt = 0; 152 do { 153 sleep(1); 154 } while (thread_state != EXITING_THREAD && cnt++ < 2 * TIMEOUT); 155 156 if (cnt >= 2 * TIMEOUT) { 157 /* thread blocked */ 158 printf 159 ("Test FAILED: thread blocked even afer the abs_timeout expired\n"); 160 exit(PTS_FAIL); 161 } 162 163 if (handler_called != 1) { 164 printf("The handler for SIGUSR1 did not get called\n"); 165 exit(PTS_UNRESOLVED); 166 } 167 168 /* Test that the thread block for the correct TIMOUT time */ 169 wait_time.tv_sec = after_wait.tv_sec - before_wait.tv_sec; 170 wait_time.tv_usec = after_wait.tv_usec - before_wait.tv_usec; 171 if (wait_time.tv_usec < 0) { 172 --wait_time.tv_sec; 173 wait_time.tv_usec += 1000000; 174 } 175 if (wait_time.tv_sec < TIMEOUT) { 176 printf 177 ("Test FAILED: Timeout was for %d seconds, but waited for %ld.%06ld seconds instead\n", 178 TIMEOUT, (long int)wait_time.tv_sec, 179 (long int)wait_time.tv_usec); 180 exit(PTS_FAIL); 181 } 182 183 printf("main: unlock write lock\n"); 184 if (pthread_rwlock_unlock(&rwlock) != 0) { 185 printf("main: Error at pthread_rwlock_unlock()\n"); 186 return PTS_UNRESOLVED; 187 } 188 189 if (pthread_join(sig_thread, NULL) != 0) { 190 printf("main: Error at pthread_join()\n"); 191 return PTS_UNRESOLVED; 192 } 193 194 if (pthread_rwlock_destroy(&rwlock) != 0) { 195 printf("Error at pthread_destroy()\n"); 196 return PTS_UNRESOLVED; 197 } 198 199 printf("Test PASSED\n"); 200 return PTS_PASS; 201 } 202