Home | History | Annotate | Download | only in pthread_rwlock_timedrdlock
      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