|
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 |
|
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) continue; |
|
61 switch (opt->option) |
|
62 { |
|
63 case 'd': /* debug mode */ |
|
64 _debug_on = 1; |
|
65 break; |
|
66 case 't': /* thread count */ |
|
67 thread_cnt = atoi(opt->value); |
|
68 break; |
|
69 case 'c': /* loop count */ |
|
70 loop_cnt = atoi(opt->value); |
|
71 break; |
|
72 default: |
|
73 break; |
|
74 } |
|
75 } |
|
76 PL_DestroyOptState(opt); |
|
77 |
|
78 PR_SetConcurrency(4); |
|
79 |
|
80 output = PR_GetSpecialFD(PR_StandardOutput); |
|
81 errhandle = PR_GetSpecialFD(PR_StandardError); |
|
82 |
|
83 rwlock1 = PR_NewRWLock(0,"Lock 1"); |
|
84 if (rwlock1 == NULL) { |
|
85 PR_fprintf(errhandle, "PR_NewRWLock failed - error %d\n", |
|
86 PR_GetError()); |
|
87 return 1; |
|
88 } |
|
89 |
|
90 threads = (PRThread**) PR_CALLOC(sizeof(PRThread*) * thread_cnt); |
|
91 params = (thread_args *) PR_CALLOC(sizeof(thread_args) * thread_cnt); |
|
92 |
|
93 /* |
|
94 * allocate and initialize data arrays |
|
95 */ |
|
96 array_A =(PRInt32 *) PR_MALLOC(sizeof(PRInt32) * TEST_ARRAY_SIZE); |
|
97 array_B =(PRInt32 *) PR_MALLOC(sizeof(PRInt32) * TEST_ARRAY_SIZE); |
|
98 array_C =(PRInt32 *) PR_MALLOC(sizeof(PRInt32) * TEST_ARRAY_SIZE); |
|
99 cnt = 0; |
|
100 for (i=0; i < TEST_ARRAY_SIZE;i++) { |
|
101 array_A[i] = cnt++; |
|
102 array_B[i] = cnt++; |
|
103 array_C[i] = array_A[i] + array_B[i]; |
|
104 } |
|
105 |
|
106 if (_debug_on) |
|
107 PR_fprintf(output,"%s: thread_cnt = %d loop_cnt = %d\n", argv[0], |
|
108 thread_cnt, loop_cnt); |
|
109 for(cnt = 0; cnt < thread_cnt; cnt++) { |
|
110 PRThreadScope scope; |
|
111 |
|
112 params[cnt].rwlock = rwlock1; |
|
113 params[cnt].loop_cnt = loop_cnt; |
|
114 |
|
115 /* |
|
116 * create LOCAL and GLOBAL threads alternately |
|
117 */ |
|
118 if (cnt & 1) |
|
119 scope = PR_LOCAL_THREAD; |
|
120 else |
|
121 scope = PR_GLOBAL_THREAD; |
|
122 |
|
123 threads[cnt] = PR_CreateThread(PR_USER_THREAD, |
|
124 rwtest, ¶ms[cnt], |
|
125 PR_PRIORITY_NORMAL, |
|
126 scope, |
|
127 PR_JOINABLE_THREAD, |
|
128 0); |
|
129 if (threads[cnt] == NULL) { |
|
130 PR_fprintf(errhandle, "PR_CreateThread failed - error %d\n", |
|
131 PR_GetError()); |
|
132 PR_ProcessExit(2); |
|
133 } |
|
134 if (_debug_on) |
|
135 PR_fprintf(output,"%s: created thread = %p\n", argv[0], |
|
136 threads[cnt]); |
|
137 } |
|
138 |
|
139 for(cnt = 0; cnt < thread_cnt; cnt++) { |
|
140 rc = PR_JoinThread(threads[cnt]); |
|
141 PR_ASSERT(rc == PR_SUCCESS); |
|
142 |
|
143 } |
|
144 |
|
145 PR_DELETE(threads); |
|
146 PR_DELETE(params); |
|
147 |
|
148 PR_DELETE(array_A); |
|
149 PR_DELETE(array_B); |
|
150 PR_DELETE(array_C); |
|
151 |
|
152 PR_DestroyRWLock(rwlock1); |
|
153 |
|
154 |
|
155 printf("PASS\n"); |
|
156 return 0; |
|
157 } |
|
158 |
|
159 static void rwtest(void *args) |
|
160 { |
|
161 PRInt32 index; |
|
162 thread_args *arg = (thread_args *) args; |
|
163 |
|
164 |
|
165 for (index = 0; index < arg->loop_cnt; index++) { |
|
166 |
|
167 /* |
|
168 * verify sum, update arrays and verify sum again |
|
169 */ |
|
170 |
|
171 PR_RWLock_Rlock(arg->rwlock); |
|
172 check_array(); |
|
173 PR_RWLock_Unlock(arg->rwlock); |
|
174 |
|
175 PR_RWLock_Wlock(arg->rwlock); |
|
176 update_array(); |
|
177 PR_RWLock_Unlock(arg->rwlock); |
|
178 |
|
179 PR_RWLock_Rlock(arg->rwlock); |
|
180 check_array(); |
|
181 PR_RWLock_Unlock(arg->rwlock); |
|
182 } |
|
183 if (_debug_on) |
|
184 PR_fprintf(output, |
|
185 "Thread[0x%x] lock = 0x%x exiting\n", |
|
186 PR_GetCurrentThread(), arg->rwlock); |
|
187 |
|
188 } |
|
189 |
|
190 static void check_array(void) |
|
191 { |
|
192 PRInt32 i; |
|
193 |
|
194 for (i=0; i < TEST_ARRAY_SIZE;i++) |
|
195 if (array_C[i] != (array_A[i] + array_B[i])) { |
|
196 PR_fprintf(output, "Error - data check failed\n"); |
|
197 PR_ProcessExit(1); |
|
198 } |
|
199 } |
|
200 |
|
201 static void update_array(void) |
|
202 { |
|
203 PRInt32 i; |
|
204 |
|
205 for (i=0; i < TEST_ARRAY_SIZE;i++) { |
|
206 array_A[i] += i; |
|
207 array_B[i] -= i; |
|
208 } |
|
209 } |