Home | History | Annotate | Download | only in pthread_rwlock_rdlock
      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_rdlock(pthread_rwlock_t *rwlock)
      8  *
      9  * 	If the Thread Execution Scheduling option is supported,
     10  *	and the threads involved in the lock are executing with the
     11  *	scheduling policies SCHED_FIFO or SCHED_RR, the calling thread shall not
     12  *	acquire the lock if a writer holds the lock or if writers of
     13  *	higher or equal priority are blocked on the lock;
     14  *	otherwise, the calling thread shall acquire the lock.
     15  *
     16  * In this case, we test "equal priority writer block"
     17  *
     18  Steps:
     19  * We have three threads, main(also a reader), writer, reader
     20  *
     21  * 1.  Main thread set its shcedule policy as "SCHED_FIFO", with highest priority
     22  *     the three: sched_get_priority_min()+2.
     23  * 2.  Main thread read lock 'rwlock'
     24  * 3.  Create a writer thread, with schedule policy as "SCHED_FIFO", and priority
     25  * 	using sched_get_priority_min()+1.
     26  * 4.  The thread write lock 'rwlock', should block.
     27  * 5.  Main thread create a reader thread, with schedule policy as "SCHED_FIFO", and
     28  *     priority sched_get_priority_min()+1
     29  * 6.  Reader thread read lock 'rwlock', should block, since there is an equal  priority
     30  *     writer blocked on 'rwlock'
     31  * 7.  Main thread release the 'rwlock', the writer should get the lock first
     32  */
     33 
     34 /* NOTE: The test result is UNSUPPORTED if Thread Execution Scheduling option
     35  * 	 is not supported.
     36  */
     37 
     38 #define _XOPEN_SOURCE 600
     39 #include <pthread.h>
     40 #include <stdio.h>
     41 #include <stdlib.h>
     42 #include <unistd.h>
     43 #include <string.h>
     44 #include <sched.h>
     45 #include "posixtest.h"
     46 
     47 #define TRD_POLICY SCHED_FIFO
     48 
     49 static pthread_rwlock_t rwlock;
     50 static int rd_thread_state;
     51 static int wr_thread_state;
     52 
     53 /* thread states:
     54 	1: not in child thread yet;
     55 	2: just enter child thread ;
     56 	3: just before child thread exit;
     57 */
     58 
     59 #define NOT_CREATED_THREAD 1
     60 #define ENTERED_THREAD 2
     61 #define EXITING_THREAD 3
     62 
     63 static int set_priority(pthread_t pid, unsigned policy, unsigned prio)
     64 {
     65 	struct sched_param sched_param;
     66 	memset(&sched_param, 0, sizeof(sched_param));
     67 	sched_param.sched_priority = prio;
     68 	if (pthread_setschedparam(pid, policy, &sched_param) == -1) {
     69 		printf("Can't set policy to %d and prio to %d\n", policy, prio);
     70 		exit(PTS_UNRESOLVED);
     71 	}
     72 	return 0;
     73 }
     74 
     75 static void *fn_rd(void *arg)
     76 {
     77 	int rc = 0;
     78 	int priority;
     79 	rd_thread_state = ENTERED_THREAD;
     80 
     81 	priority = (long)arg;
     82 	set_priority(pthread_self(), TRD_POLICY, priority);
     83 
     84 	printf("rd_thread: attempt read lock\n");
     85 	rc = pthread_rwlock_rdlock(&rwlock);
     86 	if (rc != 0) {
     87 		printf
     88 		    ("Test fail: rd_thread failed to get read lock, Error code:%d\n",
     89 		     rc);
     90 		exit(PTS_FAIL);
     91 	} else
     92 		printf("rd_thread: acquired read lock\n");
     93 
     94 	sleep(1);
     95 
     96 	printf("rd_thread: unlock read lock\n");
     97 	if (pthread_rwlock_unlock(&rwlock) != 0) {
     98 		printf("rd_thread: Error at pthread_rwlock_unlock()\n");
     99 		exit(PTS_UNRESOLVED);
    100 	}
    101 	rd_thread_state = EXITING_THREAD;
    102 	pthread_exit(0);
    103 	return NULL;
    104 }
    105 
    106 static void *fn_wr(void *arg)
    107 {
    108 	int rc = 0;
    109 	int priority;
    110 	wr_thread_state = ENTERED_THREAD;
    111 
    112 	priority = (long)arg;
    113 	set_priority(pthread_self(), TRD_POLICY, priority);
    114 
    115 	printf("wr_thread: attempt write lock\n");
    116 	rc = pthread_rwlock_wrlock(&rwlock);
    117 	if (rc != 0) {
    118 		printf
    119 		    ("Test fail: wr_thread failed to get write lock, Error code:%d\n",
    120 		     rc);
    121 		exit(PTS_UNRESOLVED);
    122 	} else
    123 		printf("wr_thread: acquired write lock\n");
    124 
    125 	sleep(1);
    126 
    127 	printf("wr_thread: unlock write lock\n");
    128 	if (pthread_rwlock_unlock(&rwlock) != 0) {
    129 		printf("wr_thread: Error at pthread_rwlock_unlock()\n");
    130 		exit(PTS_UNRESOLVED);
    131 	}
    132 	wr_thread_state = EXITING_THREAD;
    133 	pthread_exit(0);
    134 	return NULL;
    135 }
    136 
    137 int main(void)
    138 {
    139 #ifndef _POSIX_THREAD_PRIORITY_SCHEDULING
    140 	printf("Posix Thread Execution Scheduling not supported\n");
    141 	return PTS_UNSUPPORTED;
    142 #endif
    143 
    144 	int cnt = 0;
    145 	pthread_t rd_thread, wr_thread;
    146 	int priority;
    147 
    148 	/* main thread needs to have the highest priority */
    149 	priority = sched_get_priority_min(TRD_POLICY) + 2;
    150 	set_priority(pthread_self(), TRD_POLICY, priority);
    151 
    152 	if (pthread_rwlock_init(&rwlock, NULL) != 0) {
    153 		printf("main: Error at pthread_rwlock_init()\n");
    154 		return PTS_UNRESOLVED;
    155 	}
    156 
    157 	printf("main: attempt read lock\n");
    158 	/* We have no lock, this read lock should succeed */
    159 	if (pthread_rwlock_rdlock(&rwlock) != 0) {
    160 		printf
    161 		    ("Test FAILED: main cannot get read lock when no one owns the lock\n");
    162 		return PTS_FAIL;
    163 	} else
    164 		printf("main: acquired read lock\n");
    165 
    166 	wr_thread_state = NOT_CREATED_THREAD;
    167 	priority = sched_get_priority_min(TRD_POLICY) + 1;
    168 	printf("main: create wr_thread, with priority: %d\n", priority);
    169 	if (pthread_create(&wr_thread, NULL, fn_wr, (void *)(long)priority) !=
    170 	    0) {
    171 		printf("main: Error at 1st pthread_create()\n");
    172 		return PTS_UNRESOLVED;
    173 	}
    174 
    175 	/* If the shared data is not altered by child after 3 seconds,
    176 	   we regard it as blocked */
    177 
    178 	/* We expect the wr_thread to block */
    179 	cnt = 0;
    180 	do {
    181 		sleep(1);
    182 	} while (wr_thread_state != EXITING_THREAD && cnt++ < 3);
    183 
    184 	if (wr_thread_state == EXITING_THREAD) {
    185 		printf
    186 		    ("wr_thread did not block on write lock, when a reader owns the lock\n");
    187 		exit(PTS_UNRESOLVED);
    188 	} else if (wr_thread_state != ENTERED_THREAD) {
    189 		printf("Unexpected wr_thread state: %d\n", wr_thread_state);
    190 		exit(PTS_UNRESOLVED);
    191 	}
    192 
    193 	rd_thread_state = NOT_CREATED_THREAD;
    194 	priority = sched_get_priority_min(TRD_POLICY) + 1;
    195 	printf("main: create rd_thread, with priority: %d\n", priority);
    196 	if (pthread_create(&rd_thread, NULL, fn_rd, (void *)(long)priority) !=
    197 	    0) {
    198 		printf("main: failed at creating rd_thread\n");
    199 		return PTS_UNRESOLVED;
    200 	}
    201 
    202 	/* We expect the rd_thread to block */
    203 	cnt = 0;
    204 	do {
    205 		sleep(1);
    206 	} while (rd_thread_state != EXITING_THREAD && cnt++ < 3);
    207 
    208 	if (rd_thread_state == EXITING_THREAD) {
    209 		printf
    210 		    ("Test FAILED: rd_thread did not block on read lock, when a reader owns the lock, and an equal priority writer is waiting for the lock\n");
    211 		exit(PTS_FAIL);
    212 	} else if (rd_thread_state != ENTERED_THREAD) {
    213 		printf("Unexpected rd_thread state: %d\n", rd_thread_state);
    214 		exit(PTS_UNRESOLVED);
    215 	}
    216 
    217 	printf("main: unlock read lock\n");
    218 	if (pthread_rwlock_unlock(&rwlock) != 0) {
    219 		printf("main: failed to release read lock\n");
    220 		exit(PTS_UNRESOLVED);
    221 	}
    222 
    223 	/* we expect the writer get the lock */
    224 	cnt = 0;
    225 	do {
    226 		sleep(1);
    227 	} while (wr_thread_state != EXITING_THREAD && cnt++ < 3);
    228 
    229 	if (wr_thread_state == ENTERED_THREAD) {
    230 		printf
    231 		    ("Test FAILED: higher priority wr_thread still blocked on write lock, when a reader released the lock\n");
    232 		exit(PTS_FAIL);
    233 	} else if (wr_thread_state != EXITING_THREAD) {
    234 		printf("Unexpected wr_thread state: %d\n", wr_thread_state);
    235 		exit(PTS_UNRESOLVED);
    236 	}
    237 
    238 	if (pthread_join(wr_thread, NULL) != 0) {
    239 		printf("main: Error at 1st pthread_join()\n");
    240 		exit(PTS_UNRESOLVED);
    241 	}
    242 	/* we expect the reader get the lock when writer has release the lock */
    243 	cnt = 0;
    244 	do {
    245 		sleep(1);
    246 	} while (rd_thread_state != EXITING_THREAD && cnt++ < 3);
    247 
    248 	if (rd_thread_state == ENTERED_THREAD) {
    249 		printf
    250 		    ("Test FAILED: rd_thread still blocked on read lock when the lock has no owner\n");
    251 		exit(PTS_FAIL);
    252 	} else if (rd_thread_state != EXITING_THREAD) {
    253 		printf("Unexpected rd_thread state: %d\n", rd_thread_state);
    254 		exit(PTS_UNRESOLVED);
    255 	}
    256 
    257 	if (pthread_join(rd_thread, NULL) != 0) {
    258 		printf("main: Error at 2nd pthread_join()\n");
    259 		exit(PTS_UNRESOLVED);
    260 	}
    261 
    262 	if (pthread_rwlock_destroy(&rwlock) != 0) {
    263 		printf("Error at pthread_rwlockattr_destroy()");
    264 		return PTS_UNRESOLVED;
    265 	}
    266 
    267 	printf("Test PASSED\n");
    268 	return PTS_PASS;
    269 }
    270