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 
      7  * Test that pthread_rwlock_timedrdlock(pthread_rwlock_t *rwlock)
      8  *
      9  *  The function shall apply a read lock to the read-write lock referenced by
     10  *  rwlock as in the pthread_rwlock_rdlock(). However, if the lock cannot be
     11  *  acquired with out waiting for other threads to unlock the lock, this wait
     12  *  shall be terminated when the specified timeout expires.
     13  *
     14  * Steps:
     15  * 1.  Initialize a pthread_rwlock_t object 'rwlock' with pthread_rwlock_init()
     16  * 2.  Main thread lock 'rwlock' for reading with pthread_rwlock_rdlock()
     17  * 3.  Create a child thread, the thread lock 'rwlock' for reading,
     18  *     using pthread_rwlock_timedrdlock(), should get read lock. Thread unlocks 'rwlock'.
     19  * 4.  Main thread unlock 'rwlock'
     20  * 5.  Main thread lock 'rwlock' for writing
     21  * 6.  Create child thread to lock 'rwlock' for reading,
     22  *     using pthread_rwlock_timedrdlock, should block
     23  *     but when the timer expires, the wait will be terminated
     24  * 7.  Main thread unlock 'rwlock'
     25  */
     26 #define _XOPEN_SOURCE 600
     27 #include <pthread.h>
     28 #include <stdio.h>
     29 #include <stdlib.h>
     30 #include <unistd.h>
     31 #include <errno.h>
     32 #include <sys/time.h>
     33 #include "posixtest.h"
     34 
     35 /* thread_state indicates child thread state:
     36 	1: not in child thread yet;
     37 	2: just enter child thread ;
     38 	3: just before child thread exit;
     39 */
     40 
     41 #define NOT_CREATED_THREAD 1
     42 #define ENTERED_THREAD 2
     43 #define EXITING_THREAD 3
     44 
     45 #define TIMEOUT 3
     46 
     47 static pthread_rwlock_t rwlock;
     48 static int thread_state;
     49 static struct timeval currsec1, currsec2;
     50 
     51 static void *fn_rd(void *arg)
     52 {
     53 
     54 	thread_state = ENTERED_THREAD;
     55 	struct timespec timeout;
     56 	int rc;
     57 
     58 	gettimeofday(&currsec1, NULL);
     59 
     60 	/* Absolute time, not relative. */
     61 	timeout.tv_sec = currsec1.tv_sec + TIMEOUT;
     62 	timeout.tv_nsec = currsec1.tv_usec * 1000;
     63 
     64 	printf("thread: attempt timed read lock, %d secs\n", TIMEOUT);
     65 	rc = pthread_rwlock_timedrdlock(&rwlock, &timeout);
     66 	if (rc == ETIMEDOUT)
     67 		printf("thread: timer expired\n");
     68 	else if (rc == 0) {
     69 		printf("thread: acquired read lock\n");
     70 		printf("thread: unlock read lock\n");
     71 		if (pthread_rwlock_unlock(&rwlock) != 0) {
     72 			exit(PTS_UNRESOLVED);
     73 		}
     74 	} else {
     75 		printf
     76 		    ("Error: thread: in pthread_rwlock_timedrdlock(), return code:%d\n",
     77 		     rc);
     78 		exit(PTS_UNRESOLVED);
     79 	}
     80 
     81 	/* Get time after the pthread_rwlock_timedrdlock() call. */
     82 	gettimeofday(&currsec2, NULL);
     83 	thread_state = EXITING_THREAD;
     84 	pthread_exit(0);
     85 	return NULL;
     86 }
     87 
     88 int main(void)
     89 {
     90 	int cnt = 0;
     91 	pthread_t rd_thread1, rd_thread2;
     92 
     93 	if (pthread_rwlock_init(&rwlock, NULL) != 0) {
     94 		printf("main: Error at pthread_rwlock_init()\n");
     95 		return PTS_UNRESOLVED;
     96 	}
     97 
     98 	printf("main: attempt read lock\n");
     99 	if (pthread_rwlock_rdlock(&rwlock) != 0) {
    100 		printf("main: Error at pthread_rwlock_rdlock()\n");
    101 		return PTS_UNRESOLVED;
    102 	}
    103 	printf("main: acquired read lock\n");
    104 
    105 	thread_state = NOT_CREATED_THREAD;
    106 
    107 	printf("main: create rd_thread1\n");
    108 	if (pthread_create(&rd_thread1, NULL, fn_rd, NULL) != 0) {
    109 		printf("main: Error when creating rd_thread1\n");
    110 		return PTS_UNRESOLVED;
    111 	}
    112 
    113 	/* If the shared data is not altered by child after 5 seconds,
    114 	   we regard it as blocked */
    115 
    116 	/* we expect the thread not to block */
    117 	cnt = 0;
    118 	do {
    119 		sleep(1);
    120 	} while (thread_state != EXITING_THREAD && cnt++ < 5);
    121 
    122 	if (thread_state == ENTERED_THREAD) {
    123 		/* the child thread started but blocked */
    124 		printf
    125 		    ("Test FAILED: rd_thread1 blocked on pthread_rwlock_timedrdlock()\n");
    126 		exit(PTS_FAIL);
    127 	} else if (thread_state != EXITING_THREAD) {
    128 		printf("Unexpected thread state %d\n", thread_state);
    129 		exit(PTS_UNRESOLVED);
    130 	}
    131 
    132 	if (pthread_join(rd_thread1, NULL) != 0) {
    133 		printf("main: Error when join rd_thread1\n");
    134 		exit(PTS_UNRESOLVED);
    135 	}
    136 
    137 	printf("main: unlock read lock\n");
    138 	if (pthread_rwlock_unlock(&rwlock) != 0) {
    139 		printf("main: Error when release read lock\n");
    140 		return PTS_UNRESOLVED;
    141 	}
    142 
    143 	printf("main: attempt write lock\n");
    144 	if (pthread_rwlock_wrlock(&rwlock) != 0) {
    145 		printf("main: Failed to get write lock\n");
    146 		return PTS_UNRESOLVED;
    147 	}
    148 	printf("main: acquired write lock\n");
    149 
    150 	thread_state = NOT_CREATED_THREAD;
    151 	printf("main: create rd_thread2\n");
    152 	if (pthread_create(&rd_thread2, NULL, fn_rd, NULL) != 0) {
    153 		printf("main: Failed to create rd_thread2\n");
    154 		return PTS_UNRESOLVED;
    155 	}
    156 
    157 	/* we expect rd_thread2 to block and timeout. */
    158 	cnt = 0;
    159 	do {
    160 		sleep(1);
    161 	} while (thread_state != EXITING_THREAD && cnt++ < 5);
    162 
    163 	if (thread_state == EXITING_THREAD) {
    164 		/* the child thread does not block, check the time interval */
    165 		struct timeval time_diff;
    166 		time_diff.tv_sec = currsec2.tv_sec - currsec1.tv_sec;
    167 		time_diff.tv_usec = currsec2.tv_usec - currsec1.tv_usec;
    168 		if (time_diff.tv_usec < 0) {
    169 			--time_diff.tv_sec;
    170 			time_diff.tv_usec += 1000000;
    171 		}
    172 		if (time_diff.tv_sec < TIMEOUT) {
    173 			printf
    174 			    ("Test FAILED: the timer expired and thread terminated, but the timeout is not correct: start time %ld.%06ld, end time %ld.%06ld\n",
    175 			     (long)currsec1.tv_sec, (long)currsec1.tv_usec,
    176 			     (long)currsec2.tv_sec, (long)currsec2.tv_usec);
    177 			exit(PTS_FAIL);
    178 		} else
    179 			printf("thread: read lock correctly timed out\n");
    180 	} else if (thread_state == ENTERED_THREAD) {
    181 		printf
    182 		    ("Test FAILED: read block was not terminated even when the timer expired\n");
    183 		exit(PTS_FAIL);
    184 	} else {
    185 		printf("Unexpected thread state %d\n", thread_state);
    186 		return PTS_UNRESOLVED;
    187 	}
    188 
    189 	printf("main: unlock write lock\n");
    190 	if (pthread_rwlock_unlock(&rwlock) != 0) {
    191 		printf("main: Failed to release write lock\n");
    192 		exit(PTS_UNRESOLVED);
    193 	}
    194 
    195 	if (pthread_rwlock_destroy(&rwlock) != 0) {
    196 		printf("Error at pthread_rwlockattr_destroy()\n");
    197 		exit(PTS_UNRESOLVED);
    198 	}
    199 
    200 	printf("Test PASSED\n");
    201 	return PTS_PASS;
    202 }
    203