6-1.c revision 2c28215423293e443469a07ae7011135d058b671
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_timedwrlock(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_timedwrlock(), 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 write-lock 'rwlock' for writing, 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 40static pthread_t sig_thread; 41static pthread_rwlock_t rwlock; 42 43static int thread_state; 44static int handler_called; 45static 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 */ 60static void sig_handler() { 61 62 if (pthread_equal(pthread_self(), sig_thread)) 63 { 64 printf("sig_handler: signal is handled by sig_thread\n"); 65 handler_called = 1; 66 67 } 68 else 69 { 70 printf("sig_handler: signal is not handled by sig_thread\n"); 71 exit(PTS_UNRESOLVED); 72 } 73} 74 75static void * th_fn(void *arg) 76{ 77 struct sigaction act; 78 struct timespec abs_timeout; 79 int rc = 0; 80 81 handler_called = 0; 82 83 /* Set up signal handler for SIGUSR1 */ 84 85 act.sa_flags = 0; 86 act.sa_handler = sig_handler; 87 /* block all the signal when hanlding SIGUSR1 */ 88 sigfillset(&act.sa_mask); 89 sigaction(SIGUSR1, &act, 0); 90 91 gettimeofday(&before_wait, NULL); 92 abs_timeout.tv_sec = before_wait.tv_sec + TIMEOUT; 93 abs_timeout.tv_nsec = before_wait.tv_usec * 1000; 94 95 printf("thread: attempt timed write lock, %d seconds\n", TIMEOUT); 96 thread_state = ENTERED_THREAD; 97 rc = pthread_rwlock_timedwrlock(&rwlock, &abs_timeout); 98 if (rc != ETIMEDOUT) 99 { 100 printf("sig_thread: pthread_rwlock_timedwrlock returns %d\n", rc); 101 exit(PTS_FAIL); 102 } 103 printf("thread: timer correctly expired\n"); 104 gettimeofday(&after_wait, NULL); 105 106 thread_state = EXITING_THREAD; 107 pthread_exit(0); 108 return NULL; 109} 110 111int main() 112{ 113 int cnt; 114 struct timeval time_diff; 115 116 if (pthread_rwlock_init(&rwlock, NULL) != 0) 117 { 118 printf("Error at pthread_rwlock_init()\n"); 119 return PTS_UNRESOLVED; 120 } 121 122 printf("main: attempt write lock\n"); 123 if (pthread_rwlock_wrlock(&rwlock) != 0) 124 { 125 printf("main: Error at pthread_rwlock_wrlock()\n"); 126 return PTS_UNRESOLVED; 127 } 128 printf("main: acquired write lock\n"); 129 130 thread_state = NOT_CREATED_THREAD; 131 if (pthread_create(&sig_thread, NULL, th_fn, NULL) != 0) 132 { 133 printf("Error at pthread_create()\n"); 134 return PTS_UNRESOLVED; 135 } 136 137 /* Wait for the thread to get ready for handling signal (the thread should 138 * be block on rwlock since main() has the write lock at this point) */ 139 cnt = 0; 140 do{ 141 sleep(1); 142 }while (thread_state != ENTERED_THREAD && cnt++ < TIMEOUT); 143 144 if (thread_state != ENTERED_THREAD) 145 { 146 printf("Unexpected thread state %d\n", thread_state); 147 exit(PTS_UNRESOLVED); 148 } 149 150 printf("main: fire SIGUSR1 to thread\n"); 151 if (pthread_kill(sig_thread, SIGUSR1) != 0) 152 { 153 printf("main: Error at pthread_kill()\n"); 154 exit(PTS_UNRESOLVED); 155 } 156 157 /* wait at most 2*TIMEOUT seconds */ 158 cnt = 0; 159 do{ 160 sleep(1); 161 }while (thread_state != EXITING_THREAD && cnt++ < 2*TIMEOUT); 162 163 if (cnt >= 2*TIMEOUT) 164 { 165 /* thread blocked*/ 166 printf("Test FAILED: thread blocked even afer the abs_timeout expired\n"); 167 exit(PTS_FAIL); 168 } 169 170 if (handler_called != 1) 171 { 172 printf("The handler for SIGUSR1 did not get called\n"); 173 exit(PTS_UNRESOLVED); 174 } 175 176 /* Test that the thread block for the correct TIMOUT time */ 177 time_diff.tv_sec = after_wait.tv_sec - before_wait.tv_sec; 178 time_diff.tv_usec = after_wait.tv_usec - before_wait.tv_usec; 179 if (time_diff.tv_usec < 0) 180 { 181 --time_diff.tv_sec; 182 time_diff.tv_usec += 1000000; 183 } 184 if (time_diff.tv_sec < TIMEOUT) 185 { 186 printf("Test FAILED: Timeout was for %d seconds, but waited for %ld.%06ld seconds instead\n", 187 TIMEOUT, (long)time_diff.tv_sec, (long)time_diff.tv_usec); 188 exit(PTS_FAIL); 189 } 190 191 printf("main: unlock write lock\n"); 192 if (pthread_rwlock_unlock(&rwlock) != 0) 193 { 194 printf("main: Error at pthread_rwlock_unlock()\n"); 195 return PTS_UNRESOLVED; 196 } 197 198 if (pthread_join(sig_thread, NULL) != 0) 199 { 200 printf("main: Error at pthread_join()\n"); 201 return PTS_UNRESOLVED; 202 } 203 204 if (pthread_rwlock_destroy(&rwlock) != 0) 205 { 206 printf("Error at pthread_destroy()\n"); 207 return PTS_UNRESOLVED; 208 } 209 210 printf("Test PASSED\n"); 211 return PTS_PASS; 212}