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 "higher 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() 29 * 6. Reader thread read lock 'rwlock', should block, since there is a higher 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 49static pthread_rwlock_t rwlock; 50static int rd_thread_state; 51static 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 63static 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 { 70 printf("Can't set policy to %d and prio to %d\n", 71 policy, prio); 72 exit(PTS_UNRESOLVED); 73 } 74 return 0; 75} 76 77static void* fn_rd(void *arg) 78{ 79 int rc = 0; 80 int priority; 81 rd_thread_state = ENTERED_THREAD; 82 83 priority = (long)arg; 84 set_priority(pthread_self(), TRD_POLICY, priority); 85 86 printf("rd_thread: attempt read lock\n"); 87 rc = pthread_rwlock_rdlock(&rwlock); 88 if(rc != 0) 89 { 90 printf("Test FAILED: rd_thread failed to get read lock, Error code:%d\n" 91 , rc); 92 exit(PTS_FAIL); 93 } else 94 printf("rd_thread: acquired read lock\n"); 95 96 97 sleep(1); 98 99 printf("rd_thread: unlock read lock\n"); 100 if(pthread_rwlock_unlock(&rwlock) != 0) 101 { 102 printf("rd_thread: Error at pthread_rwlock_unlock()\n"); 103 exit(PTS_UNRESOLVED); 104 } 105 rd_thread_state = EXITING_THREAD; 106 pthread_exit(0); 107 return NULL; 108} 109 110static void* fn_wr(void *arg) 111{ 112 int rc = 0; 113 int priority; 114 wr_thread_state = ENTERED_THREAD; 115 116 priority = (long)arg; 117 set_priority(pthread_self(), TRD_POLICY, priority); 118 119 printf("wr_thread: attempt write lock\n"); 120 rc = pthread_rwlock_wrlock(&rwlock); 121 if(rc != 0) 122 { 123 printf("Error: wr_thread failed to get write lock, Error code:%d\n" 124 , rc); 125 exit(PTS_UNRESOLVED); 126 } else 127 printf("wr_thread: acquired write lock\n"); 128 129 sleep(1); 130 131 printf("wr_thread: unlock write lock\n"); 132 if(pthread_rwlock_unlock(&rwlock) != 0) 133 { 134 printf("wr_thread: Error at pthread_rwlock_unlock()\n"); 135 exit(PTS_UNRESOLVED); 136 } 137 wr_thread_state = EXITING_THREAD; 138 pthread_exit(0); 139 return NULL; 140} 141 142int main() 143{ 144 #ifndef _POSIX_THREAD_PRIORITY_SCHEDULING 145 printf("Posix Thread Execution Scheduling not supported\n"); 146 return PTS_UNSUPPORTED; 147 #endif 148 149 int cnt = 0; 150 pthread_t rd_thread, wr_thread; 151 int priority; 152 153 /* main thread needs to have the highest priority*/ 154 priority = sched_get_priority_min(TRD_POLICY) + 2; 155 set_priority(pthread_self(), TRD_POLICY, priority); 156 printf("main: has priority: %d\n", priority); 157 158 if(pthread_rwlock_init(&rwlock, NULL) != 0) 159 { 160 printf("main: Error at pthread_rwlock_init()\n"); 161 return PTS_UNRESOLVED; 162 } 163 164 printf("main: attempt read lock\n"); 165 /* This read lock should succeed */ 166 if(pthread_rwlock_rdlock(&rwlock) != 0) 167 { 168 printf("Test FAILED: main cannot get read lock when no one owns the lock\n"); 169 return PTS_FAIL; 170 } else 171 printf("main: acquired read lock\n"); 172 173 wr_thread_state = NOT_CREATED_THREAD; 174 priority = sched_get_priority_min(TRD_POLICY) + 1; 175 printf("main: create wr_thread, with priority: %d\n", priority); 176 if(pthread_create(&wr_thread, NULL, fn_wr, (void*)(long)priority) != 0) 177 { 178 printf("main: Error at 1st pthread_create()\n"); 179 return PTS_UNRESOLVED; 180 } 181 182 /* If the shared data is not altered by child after 3 seconds, 183 we regard it as blocked */ 184 185 /* We expect the wr_thread to block */ 186 cnt = 0; 187 do{ 188 sleep(1); 189 }while (wr_thread_state !=EXITING_THREAD && cnt++ < 3); 190 191 if(wr_thread_state == EXITING_THREAD) 192 { 193 printf("wr_thread did not block on write lock, when a reader owns the lock\n"); 194 exit(PTS_UNRESOLVED); 195 } 196 else if(wr_thread_state != ENTERED_THREAD) 197 { 198 printf("Unexpected wr_thread state: %d\n", wr_thread_state); 199 exit(PTS_UNRESOLVED); 200 } 201 202 rd_thread_state = 1; 203 priority = sched_get_priority_min(TRD_POLICY); 204 printf("main: create rd_thread, with priority: %d\n", priority); 205 if(pthread_create(&rd_thread, NULL, fn_rd, (void*)(long)priority) != 0) 206 { 207 printf("main: failed at creating rd_thread\n"); 208 return PTS_UNRESOLVED; 209 } 210 211 /* We expect the rd_thread to block*/ 212 cnt = 0; 213 do{ 214 sleep(1); 215 }while (rd_thread_state !=EXITING_THREAD && cnt++ < 3); 216 217 if(rd_thread_state == EXITING_THREAD) 218 { 219 printf("Test FAILED: rd_thread did not block on read lock, when a reader owns the lock, and a higher priority writer is waiting for the lock\n"); 220 exit(PTS_FAIL); 221 } 222 else if(rd_thread_state != ENTERED_THREAD) 223 { 224 printf("Unexpected rd_thread state: %d\n", rd_thread_state); 225 exit(PTS_UNRESOLVED); 226 } 227 228 printf("main: unlock read lock\n"); 229 if(pthread_rwlock_unlock(&rwlock) != 0) 230 { 231 printf("main: failed to unlock read lock\n"); 232 exit(PTS_UNRESOLVED); 233 } 234 235 /* we expect the writer get the lock */ 236 cnt = 0; 237 do{ 238 sleep(1); 239 }while (wr_thread_state !=EXITING_THREAD && cnt++ < 3); 240 241 if(wr_thread_state == ENTERED_THREAD) 242 { 243 printf("Test FAILED: higher priority wr_thread still blocked on write lock, when a reader release the lock\n"); 244 exit(PTS_FAIL); 245 } 246 else if(wr_thread_state != EXITING_THREAD) 247 { 248 printf("Unexpected wr_thread state: %d\n", wr_thread_state); 249 exit(PTS_UNRESOLVED); 250 } 251 252 if(pthread_join(wr_thread, NULL) != 0) 253 { 254 printf("main: Error at 1st pthread_join()\n"); 255 exit(PTS_UNRESOLVED); 256 } 257 /* we expect the reader get the lock when writer has unlocked the lock*/ 258 cnt = 0; 259 do{ 260 sleep(1); 261 }while (rd_thread_state !=EXITING_THREAD && cnt++ < 3); 262 263 if(rd_thread_state == ENTERED_THREAD ) 264 { 265 printf("Test FAILED: rd_thread still block on read lock when the lock has no owner\n"); 266 exit(PTS_FAIL); 267 } 268 else if(rd_thread_state != EXITING_THREAD) 269 { 270 printf("Unexpected rd_thread state\n"); 271 exit(PTS_UNRESOLVED); 272 } 273 274 if(pthread_join(rd_thread, NULL) != 0) 275 { 276 printf("main: Error at 2nd pthread_join()\n"); 277 exit(PTS_UNRESOLVED); 278 } 279 280 if(pthread_rwlock_destroy(&rwlock) != 0) 281 { 282 printf("Error at pthread_rwlockattr_destroy()"); 283 return PTS_UNRESOLVED; 284 } 285 286 printf("Test PASSED\n"); 287 return PTS_PASS; 288} 289