12c28215423293e443469a07ae7011135d058b671Garrett Cooper/* 20dc076565f772bb1953209fb69ea150b494aaa40robbiew * Copyright (c) 2002, Intel Corporation. All rights reserved. 30dc076565f772bb1953209fb69ea150b494aaa40robbiew * This file is licensed under the GPL license. For the full content 42c28215423293e443469a07ae7011135d058b671Garrett Cooper * of this license, see the COPYING file at the top level of this 50dc076565f772bb1953209fb69ea150b494aaa40robbiew * source tree. 60dc076565f772bb1953209fb69ea150b494aaa40robbiew * Test pthread_rwlock_timedwrlock(pthread_rwlock_t * rwlock) 72c28215423293e443469a07ae7011135d058b671Garrett Cooper * 82c28215423293e443469a07ae7011135d058b671Garrett Cooper * If a signal that causes a signal handler to be executed is delivered to 9e9410dfd93b8e415ecbe3f7e09a085462b27836eGarrett Cooper * a thread blocked on a read-write lock via a call to pthread_rwlock_timedwrlock(), 102c28215423293e443469a07ae7011135d058b671Garrett Cooper * upon return from the signal handler the thread shall resume waiting for the lock 110dc076565f772bb1953209fb69ea150b494aaa40robbiew * as if it was not interrupted. 120dc076565f772bb1953209fb69ea150b494aaa40robbiew * 130dc076565f772bb1953209fb69ea150b494aaa40robbiew * Test that after returning from a signal handler, the reader will continue 142c28215423293e443469a07ae7011135d058b671Garrett Cooper * to wait with timedrdlock as long as the specified 'timeout' does not expire (the 150dc076565f772bb1953209fb69ea150b494aaa40robbiew * time spent in signal handler is longer than the specifed 'timeout'). 160dc076565f772bb1953209fb69ea150b494aaa40robbiew * 170dc076565f772bb1953209fb69ea150b494aaa40robbiew * Steps: 180dc076565f772bb1953209fb69ea150b494aaa40robbiew * 1. main thread create and write lock 'rwlock' 190dc076565f772bb1953209fb69ea150b494aaa40robbiew * 2. main thread create a thread sig_thread, the thread is set to handle SIGUSR1 200dc076565f772bb1953209fb69ea150b494aaa40robbiew * 3. sig_thread timed write-lock 'rwlock' for writing, it should block 212c28215423293e443469a07ae7011135d058b671Garrett Cooper * 4. While the sig_thread is waiting (not expired yet), main thread sends SIGUSR1 220dc076565f772bb1953209fb69ea150b494aaa40robbiew * to sig_thread via pthread_kill 230dc076565f772bb1953209fb69ea150b494aaa40robbiew * 5. Check that when thread handler returns, sig_thread resume block 240dc076565f772bb1953209fb69ea150b494aaa40robbiew * 7. When the wait is terminated, check that the thread wait for a proper period before 252c28215423293e443469a07ae7011135d058b671Garrett Cooper * expiring. 260dc076565f772bb1953209fb69ea150b494aaa40robbiew * 270dc076565f772bb1953209fb69ea150b494aaa40robbiew */ 280dc076565f772bb1953209fb69ea150b494aaa40robbiew 290dc076565f772bb1953209fb69ea150b494aaa40robbiew#define _XOPEN_SOURCE 600 300dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <pthread.h> 310dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <stdio.h> 320dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <stdlib.h> 330dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <signal.h> 340dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <errno.h> 350dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <unistd.h> 360dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <time.h> 370dc076565f772bb1953209fb69ea150b494aaa40robbiew#include <sys/time.h> 380dc076565f772bb1953209fb69ea150b494aaa40robbiew#include "posixtest.h" 390dc076565f772bb1953209fb69ea150b494aaa40robbiew 400dc076565f772bb1953209fb69ea150b494aaa40robbiewstatic pthread_t sig_thread; 410dc076565f772bb1953209fb69ea150b494aaa40robbiewstatic pthread_rwlock_t rwlock; 420dc076565f772bb1953209fb69ea150b494aaa40robbiew 430dc076565f772bb1953209fb69ea150b494aaa40robbiewstatic int thread_state; 440dc076565f772bb1953209fb69ea150b494aaa40robbiewstatic int handler_called; 450dc076565f772bb1953209fb69ea150b494aaa40robbiewstatic struct timeval before_wait, after_wait; 460dc076565f772bb1953209fb69ea150b494aaa40robbiew 472c28215423293e443469a07ae7011135d058b671Garrett Cooper/* thread_state indicates child thread state: 482c28215423293e443469a07ae7011135d058b671Garrett Cooper 1: not in child thread yet; 490dc076565f772bb1953209fb69ea150b494aaa40robbiew 2: just enter child thread ; 500dc076565f772bb1953209fb69ea150b494aaa40robbiew 3: just before child thread exit; 510dc076565f772bb1953209fb69ea150b494aaa40robbiew*/ 520dc076565f772bb1953209fb69ea150b494aaa40robbiew 530dc076565f772bb1953209fb69ea150b494aaa40robbiew#define NOT_CREATED_THREAD 1 540dc076565f772bb1953209fb69ea150b494aaa40robbiew#define ENTERED_THREAD 2 550dc076565f772bb1953209fb69ea150b494aaa40robbiew#define EXITING_THREAD 3 560dc076565f772bb1953209fb69ea150b494aaa40robbiew 570dc076565f772bb1953209fb69ea150b494aaa40robbiew#define TIMEOUT 5 580dc076565f772bb1953209fb69ea150b494aaa40robbiew 590dc076565f772bb1953209fb69ea150b494aaa40robbiew/* Signal handler called by the thread when SIGUSR1 is received */ 60354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic void sig_handler() 61354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao{ 620dc076565f772bb1953209fb69ea150b494aaa40robbiew 63354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (pthread_equal(pthread_self(), sig_thread)) { 640dc076565f772bb1953209fb69ea150b494aaa40robbiew printf("sig_handler: signal is handled by sig_thread\n"); 650dc076565f772bb1953209fb69ea150b494aaa40robbiew handler_called = 1; 662c28215423293e443469a07ae7011135d058b671Garrett Cooper 67354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao } else { 680dc076565f772bb1953209fb69ea150b494aaa40robbiew printf("sig_handler: signal is not handled by sig_thread\n"); 690dc076565f772bb1953209fb69ea150b494aaa40robbiew exit(PTS_UNRESOLVED); 700dc076565f772bb1953209fb69ea150b494aaa40robbiew } 710dc076565f772bb1953209fb69ea150b494aaa40robbiew} 720dc076565f772bb1953209fb69ea150b494aaa40robbiew 73354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gaostatic void *th_fn(void *arg) 740dc076565f772bb1953209fb69ea150b494aaa40robbiew{ 750dc076565f772bb1953209fb69ea150b494aaa40robbiew struct sigaction act; 760dc076565f772bb1953209fb69ea150b494aaa40robbiew struct timespec abs_timeout; 770dc076565f772bb1953209fb69ea150b494aaa40robbiew int rc = 0; 782c28215423293e443469a07ae7011135d058b671Garrett Cooper 790dc076565f772bb1953209fb69ea150b494aaa40robbiew handler_called = 0; 800dc076565f772bb1953209fb69ea150b494aaa40robbiew 812c28215423293e443469a07ae7011135d058b671Garrett Cooper /* Set up signal handler for SIGUSR1 */ 820dc076565f772bb1953209fb69ea150b494aaa40robbiew 830dc076565f772bb1953209fb69ea150b494aaa40robbiew act.sa_flags = 0; 840dc076565f772bb1953209fb69ea150b494aaa40robbiew act.sa_handler = sig_handler; 850dc076565f772bb1953209fb69ea150b494aaa40robbiew /* block all the signal when hanlding SIGUSR1 */ 860dc076565f772bb1953209fb69ea150b494aaa40robbiew sigfillset(&act.sa_mask); 870dc076565f772bb1953209fb69ea150b494aaa40robbiew sigaction(SIGUSR1, &act, 0); 882c28215423293e443469a07ae7011135d058b671Garrett Cooper 890dc076565f772bb1953209fb69ea150b494aaa40robbiew gettimeofday(&before_wait, NULL); 900dc076565f772bb1953209fb69ea150b494aaa40robbiew abs_timeout.tv_sec = before_wait.tv_sec + TIMEOUT; 910dc076565f772bb1953209fb69ea150b494aaa40robbiew abs_timeout.tv_nsec = before_wait.tv_usec * 1000; 922c28215423293e443469a07ae7011135d058b671Garrett Cooper 930dc076565f772bb1953209fb69ea150b494aaa40robbiew printf("thread: attempt timed write lock, %d seconds\n", TIMEOUT); 940dc076565f772bb1953209fb69ea150b494aaa40robbiew thread_state = ENTERED_THREAD; 950dc076565f772bb1953209fb69ea150b494aaa40robbiew rc = pthread_rwlock_timedwrlock(&rwlock, &abs_timeout); 96354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (rc != ETIMEDOUT) { 97354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao printf("sig_thread: pthread_rwlock_timedwrlock returns %d\n", 98354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao rc); 990dc076565f772bb1953209fb69ea150b494aaa40robbiew exit(PTS_FAIL); 1000dc076565f772bb1953209fb69ea150b494aaa40robbiew } 101354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao printf("thread: timer correctly expired\n"); 1020dc076565f772bb1953209fb69ea150b494aaa40robbiew gettimeofday(&after_wait, NULL); 1030dc076565f772bb1953209fb69ea150b494aaa40robbiew 1040dc076565f772bb1953209fb69ea150b494aaa40robbiew thread_state = EXITING_THREAD; 1050dc076565f772bb1953209fb69ea150b494aaa40robbiew pthread_exit(0); 1060dc076565f772bb1953209fb69ea150b494aaa40robbiew return NULL; 1070dc076565f772bb1953209fb69ea150b494aaa40robbiew} 1080dc076565f772bb1953209fb69ea150b494aaa40robbiew 1094ca2bbdcd3003f3c8df4e6129e9c7b2bd1514f87Cyril Hrubisint main(void) 1100dc076565f772bb1953209fb69ea150b494aaa40robbiew{ 1110dc076565f772bb1953209fb69ea150b494aaa40robbiew int cnt; 1120dc076565f772bb1953209fb69ea150b494aaa40robbiew struct timeval time_diff; 1130dc076565f772bb1953209fb69ea150b494aaa40robbiew 114354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (pthread_rwlock_init(&rwlock, NULL) != 0) { 1150dc076565f772bb1953209fb69ea150b494aaa40robbiew printf("Error at pthread_rwlock_init()\n"); 1160dc076565f772bb1953209fb69ea150b494aaa40robbiew return PTS_UNRESOLVED; 1170dc076565f772bb1953209fb69ea150b494aaa40robbiew } 1182c28215423293e443469a07ae7011135d058b671Garrett Cooper 1190dc076565f772bb1953209fb69ea150b494aaa40robbiew printf("main: attempt write lock\n"); 120354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (pthread_rwlock_wrlock(&rwlock) != 0) { 1210dc076565f772bb1953209fb69ea150b494aaa40robbiew printf("main: Error at pthread_rwlock_wrlock()\n"); 1220dc076565f772bb1953209fb69ea150b494aaa40robbiew return PTS_UNRESOLVED; 1230dc076565f772bb1953209fb69ea150b494aaa40robbiew } 1240dc076565f772bb1953209fb69ea150b494aaa40robbiew printf("main: acquired write lock\n"); 1250dc076565f772bb1953209fb69ea150b494aaa40robbiew 1260dc076565f772bb1953209fb69ea150b494aaa40robbiew thread_state = NOT_CREATED_THREAD; 127354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (pthread_create(&sig_thread, NULL, th_fn, NULL) != 0) { 1280dc076565f772bb1953209fb69ea150b494aaa40robbiew printf("Error at pthread_create()\n"); 1290dc076565f772bb1953209fb69ea150b494aaa40robbiew return PTS_UNRESOLVED; 1300dc076565f772bb1953209fb69ea150b494aaa40robbiew } 1312c28215423293e443469a07ae7011135d058b671Garrett Cooper 1320dc076565f772bb1953209fb69ea150b494aaa40robbiew /* Wait for the thread to get ready for handling signal (the thread should 1332c28215423293e443469a07ae7011135d058b671Garrett Cooper * be block on rwlock since main() has the write lock at this point) */ 1340dc076565f772bb1953209fb69ea150b494aaa40robbiew cnt = 0; 135354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao do { 1360dc076565f772bb1953209fb69ea150b494aaa40robbiew sleep(1); 137354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao } while (thread_state != ENTERED_THREAD && cnt++ < TIMEOUT); 1382c28215423293e443469a07ae7011135d058b671Garrett Cooper 139354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (thread_state != ENTERED_THREAD) { 1400dc076565f772bb1953209fb69ea150b494aaa40robbiew printf("Unexpected thread state %d\n", thread_state); 1410dc076565f772bb1953209fb69ea150b494aaa40robbiew exit(PTS_UNRESOLVED); 1420dc076565f772bb1953209fb69ea150b494aaa40robbiew } 1430dc076565f772bb1953209fb69ea150b494aaa40robbiew 1440dc076565f772bb1953209fb69ea150b494aaa40robbiew printf("main: fire SIGUSR1 to thread\n"); 145354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (pthread_kill(sig_thread, SIGUSR1) != 0) { 1460dc076565f772bb1953209fb69ea150b494aaa40robbiew printf("main: Error at pthread_kill()\n"); 1470dc076565f772bb1953209fb69ea150b494aaa40robbiew exit(PTS_UNRESOLVED); 1480dc076565f772bb1953209fb69ea150b494aaa40robbiew } 1492c28215423293e443469a07ae7011135d058b671Garrett Cooper 1500dc076565f772bb1953209fb69ea150b494aaa40robbiew /* wait at most 2*TIMEOUT seconds */ 1510dc076565f772bb1953209fb69ea150b494aaa40robbiew cnt = 0; 152354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao do { 1530dc076565f772bb1953209fb69ea150b494aaa40robbiew sleep(1); 154354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao } while (thread_state != EXITING_THREAD && cnt++ < 2 * TIMEOUT); 1552c28215423293e443469a07ae7011135d058b671Garrett Cooper 156354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (cnt >= 2 * TIMEOUT) { 157354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao /* thread blocked */ 158354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao printf 159354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao ("Test FAILED: thread blocked even afer the abs_timeout expired\n"); 1602c28215423293e443469a07ae7011135d058b671Garrett Cooper exit(PTS_FAIL); 1610dc076565f772bb1953209fb69ea150b494aaa40robbiew } 1622c28215423293e443469a07ae7011135d058b671Garrett Cooper 163354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (handler_called != 1) { 1640dc076565f772bb1953209fb69ea150b494aaa40robbiew printf("The handler for SIGUSR1 did not get called\n"); 1650dc076565f772bb1953209fb69ea150b494aaa40robbiew exit(PTS_UNRESOLVED); 1662c28215423293e443469a07ae7011135d058b671Garrett Cooper } 1672c28215423293e443469a07ae7011135d058b671Garrett Cooper 1680dc076565f772bb1953209fb69ea150b494aaa40robbiew /* Test that the thread block for the correct TIMOUT time */ 1690dc076565f772bb1953209fb69ea150b494aaa40robbiew time_diff.tv_sec = after_wait.tv_sec - before_wait.tv_sec; 1700dc076565f772bb1953209fb69ea150b494aaa40robbiew time_diff.tv_usec = after_wait.tv_usec - before_wait.tv_usec; 171354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (time_diff.tv_usec < 0) { 1720dc076565f772bb1953209fb69ea150b494aaa40robbiew --time_diff.tv_sec; 1730dc076565f772bb1953209fb69ea150b494aaa40robbiew time_diff.tv_usec += 1000000; 1740dc076565f772bb1953209fb69ea150b494aaa40robbiew } 175354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (time_diff.tv_sec < TIMEOUT) { 176354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao printf 177354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao ("Test FAILED: Timeout was for %d seconds, but waited for %ld.%06ld seconds instead\n", 178354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao TIMEOUT, (long)time_diff.tv_sec, (long)time_diff.tv_usec); 1790dc076565f772bb1953209fb69ea150b494aaa40robbiew exit(PTS_FAIL); 1800dc076565f772bb1953209fb69ea150b494aaa40robbiew } 1810dc076565f772bb1953209fb69ea150b494aaa40robbiew 1820dc076565f772bb1953209fb69ea150b494aaa40robbiew printf("main: unlock write lock\n"); 183354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (pthread_rwlock_unlock(&rwlock) != 0) { 1840dc076565f772bb1953209fb69ea150b494aaa40robbiew printf("main: Error at pthread_rwlock_unlock()\n"); 1850dc076565f772bb1953209fb69ea150b494aaa40robbiew return PTS_UNRESOLVED; 1860dc076565f772bb1953209fb69ea150b494aaa40robbiew } 1872c28215423293e443469a07ae7011135d058b671Garrett Cooper 188354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (pthread_join(sig_thread, NULL) != 0) { 1890dc076565f772bb1953209fb69ea150b494aaa40robbiew printf("main: Error at pthread_join()\n"); 1900dc076565f772bb1953209fb69ea150b494aaa40robbiew return PTS_UNRESOLVED; 1910dc076565f772bb1953209fb69ea150b494aaa40robbiew } 1922c28215423293e443469a07ae7011135d058b671Garrett Cooper 193354ebb48db8e66a853a58379a4808d5dcd1ceac3Wanlong Gao if (pthread_rwlock_destroy(&rwlock) != 0) { 1940dc076565f772bb1953209fb69ea150b494aaa40robbiew printf("Error at pthread_destroy()\n"); 1950dc076565f772bb1953209fb69ea150b494aaa40robbiew return PTS_UNRESOLVED; 1960dc076565f772bb1953209fb69ea150b494aaa40robbiew } 1970dc076565f772bb1953209fb69ea150b494aaa40robbiew 1982c28215423293e443469a07ae7011135d058b671Garrett Cooper printf("Test PASSED\n"); 1992c28215423293e443469a07ae7011135d058b671Garrett Cooper return PTS_PASS; 200ec6edca7aa42b6affd989ef91b5897f96795e40fChris Dearman} 201