Apache HTTPD
testprocmutex.c
Go to the documentation of this file.
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
37static volatile int *x;
38
39typedef struct lockmech {
41 const char *name;
43
44/* a slower more racy way to implement (*x)++ */
45static int increment(int n)
46{
47 apr_sleep(1);
48 return n+1;
49}
50
51static 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 */
72
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 {
100 exit(1);
101 }
102
103 i++;
104 *x = increment(*x);
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. */
115static void await_child(abts_case *tc, apr_proc_t *proc)
116{
117 int code;
119 apr_status_t rv;
120
122 ABTS_ASSERT(tc, "child did not terminate with success",
123 rv == APR_CHILD_DONE && why == APR_PROC_EXIT && code == 0);
124}
125
126static void test_exclusive(abts_case *tc, const char *lockname,
128{
129 apr_proc_t *child[CHILDREN];
130 apr_status_t rv;
131 int n;
132
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
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 &&
155 }
156 else {
157 APR_ASSERT_SUCCESS(tc, "check for trylock", rv);
158
159 for (n = 0; n < 2; n++) {
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),
169 }
170 }
171
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
189 if (rv == APR_ENOTIMPL) {
190 fprintf(stderr, "%s_timedlock() not implemented, ", mech->name);
191 ABTS_ASSERT(tc, "Default timed timedlock not implemented",
193 }
194 else {
195 APR_ASSERT_SUCCESS(tc, "check for timedlock", rv);
196
197 for (n = 0; n < 2; n++) {
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),
207 }
208 }
209
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
227static 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) {
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
246 rv = apr_shm_destroy(shm);
247 APR_ASSERT_SUCCESS(tc, "Error destroying shared memory block", rv);
248}
249
250
252{
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++) {
277 }
278 return suite;
279}
280
281#else /* APR_HAS_FORK */
282
283static void proc_mutex(abts_case *tc, void *data)
284{
285 ABTS_NOT_IMPL(tc, "APR lacks fork() support");
286}
287
289{
290 suite = ADD_SUITE(suite);
292 return suite;
293}
294#endif /* APR_HAS_FORK */
int n
Definition ap_regex.h:278
void abts_run_test(abts_suite *ts, test_func f, void *value)
Definition abts.c:175
#define ADD_SUITE(suite)
Definition abts.h:67
#define ABTS_NOT_IMPL(a, b)
Definition abts.h:129
#define ABTS_ASSERT(a, b, c)
Definition abts.h:130
#define APR_ASSERT_SUCCESS(tc, ctxt, rv)
Definition testutil.h:58
APR Error Codes.
APR File I/O Handling.
APR Miscellaneous library routines.
APR Command Arguments (getopt)
APR Process Locking Routines.
APR Shared Memory Routines.
APR Strings library.
APR Thread and Process Library.
static int make_child(server_rec *s, int slot, int bucket)
Definition event.c:2740
#define APR_CHILD_DONE
Definition apr_errno.h:446
#define APR_INCHILD
Definition apr_errno.h:438
#define APR_INPARENT
Definition apr_errno.h:440
#define APR_ENOTIMPL
Definition apr_errno.h:476
const char apr_lockmech_e mech
#define APR_STATUS_IS_TIMEUP(s)
Definition apr_errno.h:534
#define APR_STATUS_IS_EBUSY(s)
Definition apr_errno.h:628
apr_size_t size
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
void * data
apr_interval_time_t apr_int32_t * num
Definition apr_poll.h:273
#define apr_pcalloc(p, size)
Definition apr_pools.h:465
apr_shm_t * shm
apr_lockmech_e
@ APR_LOCK_FLOCK
@ APR_LOCK_SYSVSEM
@ APR_LOCK_POSIXSEM
@ APR_LOCK_DEFAULT_TIMED
@ APR_LOCK_PROC_PTHREAD
@ APR_LOCK_FCNTL
@ APR_LOCK_DEFAULT
apr_proc_t * proc
apr_exit_why_e
@ APR_WAIT
@ APR_PROC_EXIT
apr_pool_t * p
Definition md_event.c:32
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
char * name
static void test_exclusive(abts_case *tc, void *data)
#define MAX_COUNTER
#define MAX_ITER
static void proc_mutex(abts_case *tc, void *data)
abts_suite * testprocmutex(abts_suite *suite)