michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: michael@0: /* michael@0: * michael@0: * RWLock tests michael@0: * michael@0: * Several threads are created to access and modify data arrays using michael@0: * PRRWLocks for synchronization. Two data arrays, array_A and array_B, are michael@0: * initialized with random data and a third array, array_C, is initialized michael@0: * with the sum of the first 2 arrays. michael@0: * michael@0: * Each one of the threads acquires a read lock to verify that the sum of michael@0: * the arrays A and B is equal to array C, and acquires a write lock to michael@0: * consistently update arrays A and B so that their is equal to array C. michael@0: * michael@0: */ michael@0: michael@0: #include "nspr.h" michael@0: #include "plgetopt.h" michael@0: #include "prrwlock.h" michael@0: michael@0: static int _debug_on; michael@0: static void rwtest(void *args); michael@0: static PRInt32 *array_A,*array_B,*array_C; michael@0: static void update_array(void); michael@0: static void check_array(void); michael@0: michael@0: typedef struct thread_args { michael@0: PRRWLock *rwlock; michael@0: PRInt32 loop_cnt; michael@0: } thread_args; michael@0: michael@0: PRFileDesc *output; michael@0: PRFileDesc *errhandle; michael@0: michael@0: #define DEFAULT_THREAD_CNT 4 michael@0: #define DEFAULT_LOOP_CNT 100 michael@0: #define TEST_ARRAY_SIZE 100 michael@0: michael@0: int main(int argc, char **argv) michael@0: { michael@0: PRInt32 cnt; michael@0: PRStatus rc; michael@0: PRInt32 i; michael@0: michael@0: PRInt32 thread_cnt = DEFAULT_THREAD_CNT; michael@0: PRInt32 loop_cnt = DEFAULT_LOOP_CNT; michael@0: PRThread **threads; michael@0: thread_args *params; michael@0: PRRWLock *rwlock1; michael@0: michael@0: PLOptStatus os; michael@0: PLOptState *opt = PL_CreateOptState(argc, argv, "dt:c:"); michael@0: michael@0: while (PL_OPT_EOL != (os = PL_GetNextOpt(opt))) michael@0: { michael@0: if (PL_OPT_BAD == os) continue; michael@0: switch (opt->option) michael@0: { michael@0: case 'd': /* debug mode */ michael@0: _debug_on = 1; michael@0: break; michael@0: case 't': /* thread count */ michael@0: thread_cnt = atoi(opt->value); michael@0: break; michael@0: case 'c': /* loop count */ michael@0: loop_cnt = atoi(opt->value); michael@0: break; michael@0: default: michael@0: break; michael@0: } michael@0: } michael@0: PL_DestroyOptState(opt); michael@0: michael@0: PR_SetConcurrency(4); michael@0: michael@0: output = PR_GetSpecialFD(PR_StandardOutput); michael@0: errhandle = PR_GetSpecialFD(PR_StandardError); michael@0: michael@0: rwlock1 = PR_NewRWLock(0,"Lock 1"); michael@0: if (rwlock1 == NULL) { michael@0: PR_fprintf(errhandle, "PR_NewRWLock failed - error %d\n", michael@0: PR_GetError()); michael@0: return 1; michael@0: } michael@0: michael@0: threads = (PRThread**) PR_CALLOC(sizeof(PRThread*) * thread_cnt); michael@0: params = (thread_args *) PR_CALLOC(sizeof(thread_args) * thread_cnt); michael@0: michael@0: /* michael@0: * allocate and initialize data arrays michael@0: */ michael@0: array_A =(PRInt32 *) PR_MALLOC(sizeof(PRInt32) * TEST_ARRAY_SIZE); michael@0: array_B =(PRInt32 *) PR_MALLOC(sizeof(PRInt32) * TEST_ARRAY_SIZE); michael@0: array_C =(PRInt32 *) PR_MALLOC(sizeof(PRInt32) * TEST_ARRAY_SIZE); michael@0: cnt = 0; michael@0: for (i=0; i < TEST_ARRAY_SIZE;i++) { michael@0: array_A[i] = cnt++; michael@0: array_B[i] = cnt++; michael@0: array_C[i] = array_A[i] + array_B[i]; michael@0: } michael@0: michael@0: if (_debug_on) michael@0: PR_fprintf(output,"%s: thread_cnt = %d loop_cnt = %d\n", argv[0], michael@0: thread_cnt, loop_cnt); michael@0: for(cnt = 0; cnt < thread_cnt; cnt++) { michael@0: PRThreadScope scope; michael@0: michael@0: params[cnt].rwlock = rwlock1; michael@0: params[cnt].loop_cnt = loop_cnt; michael@0: michael@0: /* michael@0: * create LOCAL and GLOBAL threads alternately michael@0: */ michael@0: if (cnt & 1) michael@0: scope = PR_LOCAL_THREAD; michael@0: else michael@0: scope = PR_GLOBAL_THREAD; michael@0: michael@0: threads[cnt] = PR_CreateThread(PR_USER_THREAD, michael@0: rwtest, ¶ms[cnt], michael@0: PR_PRIORITY_NORMAL, michael@0: scope, michael@0: PR_JOINABLE_THREAD, michael@0: 0); michael@0: if (threads[cnt] == NULL) { michael@0: PR_fprintf(errhandle, "PR_CreateThread failed - error %d\n", michael@0: PR_GetError()); michael@0: PR_ProcessExit(2); michael@0: } michael@0: if (_debug_on) michael@0: PR_fprintf(output,"%s: created thread = %p\n", argv[0], michael@0: threads[cnt]); michael@0: } michael@0: michael@0: for(cnt = 0; cnt < thread_cnt; cnt++) { michael@0: rc = PR_JoinThread(threads[cnt]); michael@0: PR_ASSERT(rc == PR_SUCCESS); michael@0: michael@0: } michael@0: michael@0: PR_DELETE(threads); michael@0: PR_DELETE(params); michael@0: michael@0: PR_DELETE(array_A); michael@0: PR_DELETE(array_B); michael@0: PR_DELETE(array_C); michael@0: michael@0: PR_DestroyRWLock(rwlock1); michael@0: michael@0: michael@0: printf("PASS\n"); michael@0: return 0; michael@0: } michael@0: michael@0: static void rwtest(void *args) michael@0: { michael@0: PRInt32 index; michael@0: thread_args *arg = (thread_args *) args; michael@0: michael@0: michael@0: for (index = 0; index < arg->loop_cnt; index++) { michael@0: michael@0: /* michael@0: * verify sum, update arrays and verify sum again michael@0: */ michael@0: michael@0: PR_RWLock_Rlock(arg->rwlock); michael@0: check_array(); michael@0: PR_RWLock_Unlock(arg->rwlock); michael@0: michael@0: PR_RWLock_Wlock(arg->rwlock); michael@0: update_array(); michael@0: PR_RWLock_Unlock(arg->rwlock); michael@0: michael@0: PR_RWLock_Rlock(arg->rwlock); michael@0: check_array(); michael@0: PR_RWLock_Unlock(arg->rwlock); michael@0: } michael@0: if (_debug_on) michael@0: PR_fprintf(output, michael@0: "Thread[0x%x] lock = 0x%x exiting\n", michael@0: PR_GetCurrentThread(), arg->rwlock); michael@0: michael@0: } michael@0: michael@0: static void check_array(void) michael@0: { michael@0: PRInt32 i; michael@0: michael@0: for (i=0; i < TEST_ARRAY_SIZE;i++) michael@0: if (array_C[i] != (array_A[i] + array_B[i])) { michael@0: PR_fprintf(output, "Error - data check failed\n"); michael@0: PR_ProcessExit(1); michael@0: } michael@0: } michael@0: michael@0: static void update_array(void) michael@0: { michael@0: PRInt32 i; michael@0: michael@0: for (i=0; i < TEST_ARRAY_SIZE;i++) { michael@0: array_A[i] += i; michael@0: array_B[i] -= i; michael@0: } michael@0: }