1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/nsprpub/pr/tests/rwlocktest.c Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,209 @@ 1.4 +/* This Source Code Form is subject to the terms of the Mozilla Public 1.5 + * License, v. 2.0. If a copy of the MPL was not distributed with this 1.6 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 1.7 + 1.8 + 1.9 +/* 1.10 + * 1.11 + * RWLock tests 1.12 + * 1.13 + * Several threads are created to access and modify data arrays using 1.14 + * PRRWLocks for synchronization. Two data arrays, array_A and array_B, are 1.15 + * initialized with random data and a third array, array_C, is initialized 1.16 + * with the sum of the first 2 arrays. 1.17 + * 1.18 + * Each one of the threads acquires a read lock to verify that the sum of 1.19 + * the arrays A and B is equal to array C, and acquires a write lock to 1.20 + * consistently update arrays A and B so that their is equal to array C. 1.21 + * 1.22 + */ 1.23 + 1.24 +#include "nspr.h" 1.25 +#include "plgetopt.h" 1.26 +#include "prrwlock.h" 1.27 + 1.28 +static int _debug_on; 1.29 +static void rwtest(void *args); 1.30 +static PRInt32 *array_A,*array_B,*array_C; 1.31 +static void update_array(void); 1.32 +static void check_array(void); 1.33 + 1.34 +typedef struct thread_args { 1.35 + PRRWLock *rwlock; 1.36 + PRInt32 loop_cnt; 1.37 +} thread_args; 1.38 + 1.39 +PRFileDesc *output; 1.40 +PRFileDesc *errhandle; 1.41 + 1.42 +#define DEFAULT_THREAD_CNT 4 1.43 +#define DEFAULT_LOOP_CNT 100 1.44 +#define TEST_ARRAY_SIZE 100 1.45 + 1.46 +int main(int argc, char **argv) 1.47 +{ 1.48 + PRInt32 cnt; 1.49 + PRStatus rc; 1.50 + PRInt32 i; 1.51 + 1.52 + PRInt32 thread_cnt = DEFAULT_THREAD_CNT; 1.53 + PRInt32 loop_cnt = DEFAULT_LOOP_CNT; 1.54 + PRThread **threads; 1.55 + thread_args *params; 1.56 + PRRWLock *rwlock1; 1.57 + 1.58 + PLOptStatus os; 1.59 + PLOptState *opt = PL_CreateOptState(argc, argv, "dt:c:"); 1.60 + 1.61 + while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) 1.62 + { 1.63 + if (PL_OPT_BAD == os) continue; 1.64 + switch (opt->option) 1.65 + { 1.66 + case 'd': /* debug mode */ 1.67 + _debug_on = 1; 1.68 + break; 1.69 + case 't': /* thread count */ 1.70 + thread_cnt = atoi(opt->value); 1.71 + break; 1.72 + case 'c': /* loop count */ 1.73 + loop_cnt = atoi(opt->value); 1.74 + break; 1.75 + default: 1.76 + break; 1.77 + } 1.78 + } 1.79 + PL_DestroyOptState(opt); 1.80 + 1.81 + PR_SetConcurrency(4); 1.82 + 1.83 + output = PR_GetSpecialFD(PR_StandardOutput); 1.84 + errhandle = PR_GetSpecialFD(PR_StandardError); 1.85 + 1.86 + rwlock1 = PR_NewRWLock(0,"Lock 1"); 1.87 + if (rwlock1 == NULL) { 1.88 + PR_fprintf(errhandle, "PR_NewRWLock failed - error %d\n", 1.89 + PR_GetError()); 1.90 + return 1; 1.91 + } 1.92 + 1.93 + threads = (PRThread**) PR_CALLOC(sizeof(PRThread*) * thread_cnt); 1.94 + params = (thread_args *) PR_CALLOC(sizeof(thread_args) * thread_cnt); 1.95 + 1.96 + /* 1.97 + * allocate and initialize data arrays 1.98 + */ 1.99 + array_A =(PRInt32 *) PR_MALLOC(sizeof(PRInt32) * TEST_ARRAY_SIZE); 1.100 + array_B =(PRInt32 *) PR_MALLOC(sizeof(PRInt32) * TEST_ARRAY_SIZE); 1.101 + array_C =(PRInt32 *) PR_MALLOC(sizeof(PRInt32) * TEST_ARRAY_SIZE); 1.102 + cnt = 0; 1.103 + for (i=0; i < TEST_ARRAY_SIZE;i++) { 1.104 + array_A[i] = cnt++; 1.105 + array_B[i] = cnt++; 1.106 + array_C[i] = array_A[i] + array_B[i]; 1.107 + } 1.108 + 1.109 + if (_debug_on) 1.110 + PR_fprintf(output,"%s: thread_cnt = %d loop_cnt = %d\n", argv[0], 1.111 + thread_cnt, loop_cnt); 1.112 + for(cnt = 0; cnt < thread_cnt; cnt++) { 1.113 + PRThreadScope scope; 1.114 + 1.115 + params[cnt].rwlock = rwlock1; 1.116 + params[cnt].loop_cnt = loop_cnt; 1.117 + 1.118 + /* 1.119 + * create LOCAL and GLOBAL threads alternately 1.120 + */ 1.121 + if (cnt & 1) 1.122 + scope = PR_LOCAL_THREAD; 1.123 + else 1.124 + scope = PR_GLOBAL_THREAD; 1.125 + 1.126 + threads[cnt] = PR_CreateThread(PR_USER_THREAD, 1.127 + rwtest, ¶ms[cnt], 1.128 + PR_PRIORITY_NORMAL, 1.129 + scope, 1.130 + PR_JOINABLE_THREAD, 1.131 + 0); 1.132 + if (threads[cnt] == NULL) { 1.133 + PR_fprintf(errhandle, "PR_CreateThread failed - error %d\n", 1.134 + PR_GetError()); 1.135 + PR_ProcessExit(2); 1.136 + } 1.137 + if (_debug_on) 1.138 + PR_fprintf(output,"%s: created thread = %p\n", argv[0], 1.139 + threads[cnt]); 1.140 + } 1.141 + 1.142 + for(cnt = 0; cnt < thread_cnt; cnt++) { 1.143 + rc = PR_JoinThread(threads[cnt]); 1.144 + PR_ASSERT(rc == PR_SUCCESS); 1.145 + 1.146 + } 1.147 + 1.148 + PR_DELETE(threads); 1.149 + PR_DELETE(params); 1.150 + 1.151 + PR_DELETE(array_A); 1.152 + PR_DELETE(array_B); 1.153 + PR_DELETE(array_C); 1.154 + 1.155 + PR_DestroyRWLock(rwlock1); 1.156 + 1.157 + 1.158 + printf("PASS\n"); 1.159 + return 0; 1.160 +} 1.161 + 1.162 +static void rwtest(void *args) 1.163 +{ 1.164 + PRInt32 index; 1.165 + thread_args *arg = (thread_args *) args; 1.166 + 1.167 + 1.168 + for (index = 0; index < arg->loop_cnt; index++) { 1.169 + 1.170 + /* 1.171 + * verify sum, update arrays and verify sum again 1.172 + */ 1.173 + 1.174 + PR_RWLock_Rlock(arg->rwlock); 1.175 + check_array(); 1.176 + PR_RWLock_Unlock(arg->rwlock); 1.177 + 1.178 + PR_RWLock_Wlock(arg->rwlock); 1.179 + update_array(); 1.180 + PR_RWLock_Unlock(arg->rwlock); 1.181 + 1.182 + PR_RWLock_Rlock(arg->rwlock); 1.183 + check_array(); 1.184 + PR_RWLock_Unlock(arg->rwlock); 1.185 + } 1.186 + if (_debug_on) 1.187 + PR_fprintf(output, 1.188 + "Thread[0x%x] lock = 0x%x exiting\n", 1.189 + PR_GetCurrentThread(), arg->rwlock); 1.190 + 1.191 +} 1.192 + 1.193 +static void check_array(void) 1.194 +{ 1.195 +PRInt32 i; 1.196 + 1.197 + for (i=0; i < TEST_ARRAY_SIZE;i++) 1.198 + if (array_C[i] != (array_A[i] + array_B[i])) { 1.199 + PR_fprintf(output, "Error - data check failed\n"); 1.200 + PR_ProcessExit(1); 1.201 + } 1.202 +} 1.203 + 1.204 +static void update_array(void) 1.205 +{ 1.206 +PRInt32 i; 1.207 + 1.208 + for (i=0; i < TEST_ARRAY_SIZE;i++) { 1.209 + array_A[i] += i; 1.210 + array_B[i] -= i; 1.211 + } 1.212 +}