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_rdlock(pthread_rwlock_t * rwlock) 7 * 8 * If a signal is delivered to a thread waiting for a read-write lock for reading, upon 9 * return from the signal handler the thread resumes waiting for the read-write lock for 10 * reading as if it was not interrupted. 11 * 12 * Steps: 13 * 1. main thread create read-write lock 'rwlock', and lock it for writing 14 * 2. main thread create a thread sig_thread, the thread is set to handle SIGUSR1 15 * 3. sig_thread try to lock 'rwlock' for reading but will block 16 * 4. main thread sends SIGUSR1 to sig_thread via pthread_kill 17 * 5. test that thread handler is called 18 * 6. check that when thread handler returns, sig_thread resumes blocking for rwlock 19 * 7. main thread unlock 'rwlock', sig_thread should get the lock 20 */ 21 22#define _XOPEN_SOURCE 600 23#include <pthread.h> 24#include <stdio.h> 25#include <stdlib.h> 26#include <signal.h> 27#include <errno.h> 28#include <unistd.h> 29#include "posixtest.h" 30 31static pthread_t sig_thread; 32static pthread_rwlock_t rwlock; 33 34static int thread_state; 35static int handler_called; 36 37/* thread_state indicates child thread state: 38 1: not in child thread yet; 39 2: just enter child thread ; 40 3: just before child thread exit; 41*/ 42 43#define NOT_CREATED_THREAD 1 44#define ENTERED_THREAD 2 45#define EXITING_THREAD 3 46 47static void sig_handler() 48{ 49 if (pthread_equal(pthread_self(), sig_thread)) { 50 printf("sig_handler: handled signal SIGUSR1\n"); 51 handler_called = 1; 52 } else { 53 printf("signal is not handled by sig_thread\n"); 54 exit(PTS_UNRESOLVED); 55 } 56} 57 58static void *th_fn(void *arg) 59{ 60 struct sigaction act; 61 int rc = 0; 62 63 act.sa_flags = 0; 64 act.sa_handler = sig_handler; 65 /* Try to block all signals when handling SIGUSR1 */ 66 sigfillset(&act.sa_mask); 67 sigaction(SIGUSR1, &act, 0); 68 69 thread_state = ENTERED_THREAD; 70 printf("sig_thread: attemp read lock\n"); 71 rc = pthread_rwlock_rdlock(&rwlock); 72 if (rc != 0) { 73 printf 74 ("Test FAILED: sig_thread: Error at pthread_rwlock_rdlock(), Error code=%d\n", 75 rc); 76 exit(PTS_FAIL); 77 } else 78 printf("sig_thread: acquired read lock\n"); 79 80 printf("sig_thread: unlock read lock\n"); 81 if (pthread_rwlock_unlock(&rwlock) != 0) { 82 printf("sig_thread: Error release readlock\n"); 83 exit(PTS_UNRESOLVED); 84 } 85 thread_state = EXITING_THREAD; 86 pthread_exit(0); 87 return NULL; 88} 89 90int main(void) 91{ 92 int cnt; 93 handler_called = 0; 94 95 if (pthread_rwlock_init(&rwlock, NULL) != 0) { 96 printf("main: Error at pthread_rwlock_init()\n"); 97 return PTS_UNRESOLVED; 98 } 99 100 printf("main: attempt write lock\n"); 101 if (pthread_rwlock_wrlock(&rwlock) != 0) { 102 printf("main: Error at pthread_rwlock_wrlock()\n"); 103 return PTS_UNRESOLVED; 104 } else 105 printf("main: acquired write lock\n"); 106 107 thread_state = NOT_CREATED_THREAD; 108 if (pthread_create(&sig_thread, NULL, th_fn, NULL) != 0) { 109 printf("main: Error at pthread_create()\n"); 110 return PTS_UNRESOLVED; 111 } 112 113 /* wait at most 3 seconds for sig_thread to block */ 114 cnt = 0; 115 do { 116 sleep(1); 117 } while (thread_state != EXITING_THREAD && cnt++ < 3); 118 119 if (thread_state == EXITING_THREAD) { 120 printf 121 ("Test FAILED: thread did not block on read lock when a writer holds the lock\n"); 122 exit(PTS_FAIL); 123 } else if (thread_state != ENTERED_THREAD) { 124 printf("Unexpected thread state: %d\n", thread_state); 125 exit(PTS_UNRESOLVED); 126 } 127 128 /* sig_thread is blocking */ 129 printf("main: fire SIGUSR1 to sig_thread\n"); 130 if (pthread_kill(sig_thread, SIGUSR1) != 0) { 131 printf("main: failed to send SIGUSER to sig_thread\n"); 132 exit(PTS_UNRESOLVED); 133 } 134 135 /* wait at most 3 seconds for the signal to be handled */ 136 cnt = 0; 137 do { 138 sleep(1); 139 } while (handler_called == 0 && cnt++ < 3); 140 141 if (handler_called != 1) { 142 printf("SIGUSR1 was not caught by sig_thread\n"); 143 exit(PTS_UNRESOLVED); 144 } 145 146 /* sig_thread resume to block? */ 147 cnt = 0; 148 do { 149 sleep(1); 150 } while (thread_state != EXITING_THREAD && cnt++ < 3); 151 152 if (thread_state == EXITING_THREAD) { 153 printf 154 ("Test FAILED: upon return from signal handler, sig_thread does not resume to block\n"); 155 exit(PTS_FAIL); 156 } else if (thread_state != ENTERED_THREAD) { 157 printf("Unexpected thread state: %d\n", thread_state); 158 exit(PTS_UNRESOLVED); 159 } 160 161 printf 162 ("sig_thread: correctly still blocking after signal handler returns\n"); 163 printf("main: unlock write lock\n"); 164 if (pthread_rwlock_unlock(&rwlock) != 0) { 165 printf("main: Failed to release write lock\n"); 166 exit(PTS_UNRESOLVED); 167 } 168 169 /* sig_thread got the read lock? */ 170 cnt = 0; 171 do { 172 sleep(1); 173 } while (thread_state != EXITING_THREAD && cnt++ < 3); 174 175 if (thread_state == ENTERED_THREAD) { 176 printf 177 ("Test FAILED: sig_thread blocked on read lock when writer release the lock\n"); 178 exit(PTS_FAIL); 179 } else if (thread_state != EXITING_THREAD) { 180 printf("Unexpected thread state: %d\n", thread_state); 181 exit(PTS_UNRESOLVED); 182 } 183 184 if (pthread_join(sig_thread, NULL) != 0) { 185 printf("main: failed at pthread_join()\n"); 186 exit(PTS_UNRESOLVED); 187 } 188 189 if (pthread_rwlock_destroy(&rwlock) != 0) { 190 printf("main: failed at pthread_rwlock_destroy()\n"); 191 exit(PTS_UNRESOLVED); 192 } 193 194 printf("Test PASSED\n"); 195 return PTS_PASS; 196} 197