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