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