"Fossies" - the Fresh Open Source Software Archive 
Member "apr-1.7.0/test/testprocmutex.c" (19 Apr 2017, 8950 Bytes) of package /linux/www/apr-1.7.0.tar.bz2:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
See also the latest
Fossies "Diffs" side-by-side code changes report for "testprocmutex.c":
1.6.5_vs_1.7.0.
1 /* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "apr_shm.h"
18 #include "apr_thread_proc.h"
19 #include "apr_file_io.h"
20 #include "apr_proc_mutex.h"
21 #include "apr_errno.h"
22 #include "apr_general.h"
23 #include "apr_strings.h"
24 #include "apr_getopt.h"
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include "testutil.h"
28
29 #if APR_HAS_FORK
30
31 #define MAX_ITER 200
32 #define CHILDREN 6
33 #define MAX_COUNTER (MAX_ITER * CHILDREN)
34 #define MAX_WAIT_USEC (1000*1000)
35
36 static apr_proc_mutex_t *proc_lock;
37 static volatile int *x;
38
39 typedef struct lockmech {
40 apr_lockmech_e num;
41 const char *name;
42 } lockmech_t;
43
44 /* a slower more racy way to implement (*x)++ */
45 static int increment(int n)
46 {
47 apr_sleep(1);
48 return n+1;
49 }
50
51 static void make_child(abts_case *tc, int trylock, apr_proc_t **proc, apr_pool_t *p)
52 {
53 apr_status_t rv;
54
55 *proc = apr_pcalloc(p, sizeof(**proc));
56
57 /* slight delay to allow things to settle */
58 apr_sleep (1);
59
60 rv = apr_proc_fork(*proc, p);
61 if (rv == APR_INCHILD) {
62 int i = 0;
63 /* The parent process has setup all processes to call apr_terminate
64 * at exit. But, that means that all processes must also call
65 * apr_initialize at startup. You cannot have an unequal number
66 * of apr_terminate and apr_initialize calls. If you do, bad things
67 * will happen. In this case, the bad thing is that if the mutex
68 * is a semaphore, it will be destroyed before all of the processes
69 * die. That means that the test will most likely fail.
70 */
71 apr_initialize();
72
73 if (apr_proc_mutex_child_init(&proc_lock, NULL, p))
74 exit(1);
75
76 do {
77 if (trylock > 0) {
78 int wait_usec = 0;
79
80 while ((rv = apr_proc_mutex_trylock(proc_lock))) {
81 if (!APR_STATUS_IS_EBUSY(rv))
82 exit(1);
83 if (++wait_usec >= MAX_WAIT_USEC)
84 exit(1);
85 apr_sleep(1);
86 }
87 }
88 else if (trylock < 0) {
89 int wait_usec = 0;
90
91 while ((rv = apr_proc_mutex_timedlock(proc_lock, 1))) {
92 if (!APR_STATUS_IS_TIMEUP(rv))
93 exit(1);
94 if (++wait_usec >= MAX_WAIT_USEC)
95 exit(1);
96 }
97 }
98 else {
99 if (apr_proc_mutex_lock(proc_lock))
100 exit(1);
101 }
102
103 i++;
104 *x = increment(*x);
105 if (apr_proc_mutex_unlock(proc_lock))
106 exit(1);
107 } while (i < MAX_ITER);
108 exit(0);
109 }
110
111 ABTS_ASSERT(tc, "fork failed", rv == APR_INPARENT);
112 }
113
114 /* Wait for a child process and check it terminated with success. */
115 static void await_child(abts_case *tc, apr_proc_t *proc)
116 {
117 int code;
118 apr_exit_why_e why;
119 apr_status_t rv;
120
121 rv = apr_proc_wait(proc, &code, &why, APR_WAIT);
122 ABTS_ASSERT(tc, "child did not terminate with success",
123 rv == APR_CHILD_DONE && why == APR_PROC_EXIT && code == 0);
124 }
125
126 static void test_exclusive(abts_case *tc, const char *lockname,
127 lockmech_t *mech)
128 {
129 apr_proc_t *child[CHILDREN];
130 apr_status_t rv;
131 int n;
132
133 rv = apr_proc_mutex_create(&proc_lock, lockname, mech->num, p);
134 if (rv == APR_ENOTIMPL) {
135 /* MacOS lacks TIMED implementation, so don't fail for ENOTIMPL */
136 fprintf(stderr, "method %s not implemented, ", mech->name);
137 return;
138 }
139 APR_ASSERT_SUCCESS(tc, "create the mutex", rv);
140
141 for (n = 0; n < CHILDREN; n++)
142 make_child(tc, 0, &child[n], p);
143
144 for (n = 0; n < CHILDREN; n++)
145 await_child(tc, child[n]);
146
147 ABTS_ASSERT(tc, "Locks don't appear to work", *x == MAX_COUNTER);
148
149 rv = apr_proc_mutex_trylock(proc_lock);
150 if (rv == APR_ENOTIMPL) {
151 fprintf(stderr, "%s_trylock() not implemented, ", mech->name);
152 ABTS_ASSERT(tc, "Default timed trylock not implemented",
153 mech->num != APR_LOCK_DEFAULT &&
154 mech->num != APR_LOCK_DEFAULT_TIMED);
155 }
156 else {
157 APR_ASSERT_SUCCESS(tc, "check for trylock", rv);
158
159 for (n = 0; n < 2; n++) {
160 rv = apr_proc_mutex_trylock(proc_lock);
161 /* Some mech (eg. flock or fcntl) may succeed when the
162 * lock is re-acquired in the same process.
163 */
164 if (rv != APR_SUCCESS) {
165 ABTS_ASSERT(tc,
166 apr_psprintf(p, "%s_trylock() should be busy => %pm",
167 mech->name, &rv),
168 APR_STATUS_IS_EBUSY(rv));
169 }
170 }
171
172 rv = apr_proc_mutex_unlock(proc_lock);
173 APR_ASSERT_SUCCESS(tc, "unlock after trylock check", rv);
174
175 *x = 0;
176
177 for (n = 0; n < CHILDREN; n++)
178 make_child(tc, 1, &child[n], p);
179
180 for (n = 0; n < CHILDREN; n++)
181 await_child(tc, child[n]);
182
183 ABTS_ASSERT(tc, "Locks don't appear to work with trylock",
184 *x == MAX_COUNTER);
185 }
186
187 #if APR_HAS_TIMEDLOCKS
188 rv = apr_proc_mutex_timedlock(proc_lock, 1);
189 if (rv == APR_ENOTIMPL) {
190 fprintf(stderr, "%s_timedlock() not implemented, ", mech->name);
191 ABTS_ASSERT(tc, "Default timed timedlock not implemented",
192 mech->num != APR_LOCK_DEFAULT_TIMED);
193 }
194 else {
195 APR_ASSERT_SUCCESS(tc, "check for timedlock", rv);
196
197 for (n = 0; n < 2; n++) {
198 rv = apr_proc_mutex_timedlock(proc_lock, 1);
199 /* Some mech (eg. flock or fcntl) may succeed when the
200 * lock is re-acquired in the same process.
201 */
202 if (rv != APR_SUCCESS) {
203 ABTS_ASSERT(tc,
204 apr_psprintf(p, "%s_timedlock() should time out => %pm",
205 mech->name, &rv),
206 APR_STATUS_IS_TIMEUP(rv));
207 }
208 }
209
210 rv = apr_proc_mutex_unlock(proc_lock);
211 APR_ASSERT_SUCCESS(tc, "unlock after timedlock check", rv);
212
213 *x = 0;
214
215 for (n = 0; n < CHILDREN; n++)
216 make_child(tc, -1, &child[n], p);
217
218 for (n = 0; n < CHILDREN; n++)
219 await_child(tc, child[n]);
220
221 ABTS_ASSERT(tc, "Locks don't appear to work with timedlock",
222 *x == MAX_COUNTER);
223 }
224 #endif /* APR_HAS_TIMEDLOCKS */
225 }
226
227 static void proc_mutex(abts_case *tc, void *data)
228 {
229 apr_status_t rv;
230 const char *shmname = "tpm.shm";
231 apr_shm_t *shm;
232
233 /* Use anonymous shm if available. */
234 rv = apr_shm_create(&shm, sizeof(int), NULL, p);
235 if (rv == APR_ENOTIMPL) {
236 apr_file_remove(shmname, p);
237 rv = apr_shm_create(&shm, sizeof(int), shmname, p);
238 }
239
240 APR_ASSERT_SUCCESS(tc, "create shm segment", rv);
241 if (rv != APR_SUCCESS)
242 return;
243
244 x = apr_shm_baseaddr_get(shm);
245 test_exclusive(tc, NULL, data);
246 rv = apr_shm_destroy(shm);
247 APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv);
248 }
249
250
251 abts_suite *testprocmutex(abts_suite *suite)
252 {
253 lockmech_t lockmechs[] = {
254 {APR_LOCK_DEFAULT, "default"}
255 #if APR_HAS_FLOCK_SERIALIZE
256 ,{APR_LOCK_FLOCK, "flock"}
257 #endif
258 #if APR_HAS_SYSVSEM_SERIALIZE
259 ,{APR_LOCK_SYSVSEM, "sysvsem"}
260 #endif
261 #if APR_HAS_POSIXSEM_SERIALIZE
262 ,{APR_LOCK_POSIXSEM, "posix"}
263 #endif
264 #if APR_HAS_FCNTL_SERIALIZE
265 ,{APR_LOCK_FCNTL, "fcntl"}
266 #endif
267 #if APR_HAS_PROC_PTHREAD_SERIALIZE
268 ,{APR_LOCK_PROC_PTHREAD, "proc_pthread"}
269 #endif
270 ,{APR_LOCK_DEFAULT_TIMED, "default_timed"}
271 };
272 int i;
273
274 suite = ADD_SUITE(suite)
275 for (i = 0; i < sizeof(lockmechs) / sizeof(lockmechs[0]); i++) {
276 abts_run_test(suite, proc_mutex, &lockmechs[i]);
277 }
278 return suite;
279 }
280
281 #else /* APR_HAS_FORK */
282
283 static void proc_mutex(abts_case *tc, void *data)
284 {
285 ABTS_NOT_IMPL(tc, "APR lacks fork() support");
286 }
287
288 abts_suite *testprocmutex(abts_suite *suite)
289 {
290 suite = ADD_SUITE(suite);
291 abts_run_test(suite, proc_mutex, NULL);
292 return suite;
293 }
294 #endif /* APR_HAS_FORK */