rwlocktest.c (4877B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 /* 6 * 7 * RWLock tests 8 * 9 * Several threads are created to access and modify data arrays using 10 * PRRWLocks for synchronization. Two data arrays, array_A and array_B, are 11 * initialized with random data and a third array, array_C, is initialized 12 * with the sum of the first 2 arrays. 13 * 14 * Each one of the threads acquires a read lock to verify that the sum of 15 * the arrays A and B is equal to array C, and acquires a write lock to 16 * consistently update arrays A and B so that their is equal to array C. 17 * 18 */ 19 20 #include "nspr.h" 21 #include "plgetopt.h" 22 #include "prrwlock.h" 23 24 static int _debug_on; 25 static void rwtest(void* args); 26 static PRInt32 *array_A, *array_B, *array_C; 27 static void update_array(void); 28 static void check_array(void); 29 30 typedef struct thread_args { 31 PRRWLock* rwlock; 32 PRInt32 loop_cnt; 33 } thread_args; 34 35 PRFileDesc* output; 36 PRFileDesc* errhandle; 37 38 #define DEFAULT_THREAD_CNT 4 39 #define DEFAULT_LOOP_CNT 100 40 #define TEST_ARRAY_SIZE 100 41 42 int main(int argc, char** argv) { 43 PRInt32 cnt; 44 PRStatus rc; 45 PRInt32 i; 46 47 PRInt32 thread_cnt = DEFAULT_THREAD_CNT; 48 PRInt32 loop_cnt = DEFAULT_LOOP_CNT; 49 PRThread** threads; 50 thread_args* params; 51 PRRWLock* rwlock1; 52 53 PLOptStatus os; 54 PLOptState* opt = PL_CreateOptState(argc, argv, "dt:c:"); 55 56 while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) { 57 if (PL_OPT_BAD == os) { 58 continue; 59 } 60 switch (opt->option) { 61 case 'd': /* debug mode */ 62 _debug_on = 1; 63 break; 64 case 't': /* thread count */ 65 thread_cnt = atoi(opt->value); 66 break; 67 case 'c': /* loop count */ 68 loop_cnt = atoi(opt->value); 69 break; 70 default: 71 break; 72 } 73 } 74 PL_DestroyOptState(opt); 75 76 PR_SetConcurrency(4); 77 78 output = PR_GetSpecialFD(PR_StandardOutput); 79 errhandle = PR_GetSpecialFD(PR_StandardError); 80 81 rwlock1 = PR_NewRWLock(0, "Lock 1"); 82 if (rwlock1 == NULL) { 83 PR_fprintf(errhandle, "PR_NewRWLock failed - error %d\n", PR_GetError()); 84 return 1; 85 } 86 87 threads = (PRThread**)PR_CALLOC(sizeof(PRThread*) * thread_cnt); 88 params = (thread_args*)PR_CALLOC(sizeof(thread_args) * thread_cnt); 89 90 /* 91 * allocate and initialize data arrays 92 */ 93 array_A = (PRInt32*)PR_MALLOC(sizeof(PRInt32) * TEST_ARRAY_SIZE); 94 array_B = (PRInt32*)PR_MALLOC(sizeof(PRInt32) * TEST_ARRAY_SIZE); 95 array_C = (PRInt32*)PR_MALLOC(sizeof(PRInt32) * TEST_ARRAY_SIZE); 96 cnt = 0; 97 for (i = 0; i < TEST_ARRAY_SIZE; i++) { 98 array_A[i] = cnt++; 99 array_B[i] = cnt++; 100 array_C[i] = array_A[i] + array_B[i]; 101 } 102 103 if (_debug_on) 104 PR_fprintf(output, "%s: thread_cnt = %d loop_cnt = %d\n", argv[0], 105 thread_cnt, loop_cnt); 106 for (cnt = 0; cnt < thread_cnt; cnt++) { 107 PRThreadScope scope; 108 109 params[cnt].rwlock = rwlock1; 110 params[cnt].loop_cnt = loop_cnt; 111 112 /* 113 * create LOCAL and GLOBAL threads alternately 114 */ 115 if (cnt & 1) { 116 scope = PR_LOCAL_THREAD; 117 } else { 118 scope = PR_GLOBAL_THREAD; 119 } 120 121 threads[cnt] = 122 PR_CreateThread(PR_USER_THREAD, rwtest, ¶ms[cnt], 123 PR_PRIORITY_NORMAL, scope, PR_JOINABLE_THREAD, 0); 124 if (threads[cnt] == NULL) { 125 PR_fprintf(errhandle, "PR_CreateThread failed - error %d\n", 126 PR_GetError()); 127 PR_ProcessExit(2); 128 } 129 if (_debug_on) 130 PR_fprintf(output, "%s: created thread = %p\n", argv[0], threads[cnt]); 131 } 132 133 for (cnt = 0; cnt < thread_cnt; cnt++) { 134 rc = PR_JoinThread(threads[cnt]); 135 PR_ASSERT(rc == PR_SUCCESS); 136 } 137 138 PR_DELETE(threads); 139 PR_DELETE(params); 140 141 PR_DELETE(array_A); 142 PR_DELETE(array_B); 143 PR_DELETE(array_C); 144 145 PR_DestroyRWLock(rwlock1); 146 147 printf("PASS\n"); 148 return 0; 149 } 150 151 static void rwtest(void* args) { 152 PRInt32 index; 153 thread_args* arg = (thread_args*)args; 154 155 for (index = 0; index < arg->loop_cnt; index++) { 156 /* 157 * verify sum, update arrays and verify sum again 158 */ 159 160 PR_RWLock_Rlock(arg->rwlock); 161 check_array(); 162 PR_RWLock_Unlock(arg->rwlock); 163 164 PR_RWLock_Wlock(arg->rwlock); 165 update_array(); 166 PR_RWLock_Unlock(arg->rwlock); 167 168 PR_RWLock_Rlock(arg->rwlock); 169 check_array(); 170 PR_RWLock_Unlock(arg->rwlock); 171 } 172 if (_debug_on) 173 PR_fprintf(output, "Thread[0x%x] lock = 0x%x exiting\n", 174 PR_GetCurrentThread(), arg->rwlock); 175 } 176 177 static void check_array(void) { 178 PRInt32 i; 179 180 for (i = 0; i < TEST_ARRAY_SIZE; i++) 181 if (array_C[i] != (array_A[i] + array_B[i])) { 182 PR_fprintf(output, "Error - data check failed\n"); 183 PR_ProcessExit(1); 184 } 185 } 186 187 static void update_array(void) { 188 PRInt32 i; 189 190 for (i = 0; i < TEST_ARRAY_SIZE; i++) { 191 array_A[i] += i; 192 array_B[i] -= i; 193 } 194 }