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