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, ¶ms[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