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 "testglobalmutex.h"
18#include "apr_thread_proc.h"
19#include "apr_global_mutex.h"
20#include "apr_strings.h"
21#include "apr_errno.h"
22#include "testutil.h"
23
24static void launch_child(abts_case *tc, apr_lockmech_e mech,
25                         apr_proc_t *proc, apr_pool_t *p)
26{
27    apr_procattr_t *procattr;
28    const char *args[3];
29    apr_status_t rv;
30
31    rv = apr_procattr_create(&procattr, p);
32    APR_ASSERT_SUCCESS(tc, "Couldn't create procattr", rv);
33
34    rv = apr_procattr_io_set(procattr, APR_NO_PIPE, APR_NO_PIPE,
35            APR_NO_PIPE);
36    APR_ASSERT_SUCCESS(tc, "Couldn't set io in procattr", rv);
37
38    rv = apr_procattr_error_check_set(procattr, 1);
39    APR_ASSERT_SUCCESS(tc, "Couldn't set error check in procattr", rv);
40
41    args[0] = "globalmutexchild" EXTENSION;
42    args[1] = (const char*)apr_itoa(p, (int)mech);
43    args[2] = NULL;
44    rv = apr_proc_create(proc, TESTBINPATH "globalmutexchild" EXTENSION, args, NULL,
45            procattr, p);
46    APR_ASSERT_SUCCESS(tc, "Couldn't launch program", rv);
47}
48
49static int wait_child(abts_case *tc, apr_proc_t *proc)
50{
51    int exitcode;
52    apr_exit_why_e why;
53
54    ABTS_ASSERT(tc, "Error waiting for child process",
55            apr_proc_wait(proc, &exitcode, &why, APR_WAIT) == APR_CHILD_DONE);
56
57    ABTS_ASSERT(tc, "child didn't terminate normally", why == APR_PROC_EXIT);
58    return exitcode;
59}
60
61/* return symbolic name for a locking meechanism */
62static const char *mutexname(apr_lockmech_e mech)
63{
64    switch (mech) {
65    case APR_LOCK_FCNTL: return "fcntl";
66    case APR_LOCK_FLOCK: return "flock";
67    case APR_LOCK_SYSVSEM: return "sysvsem";
68    case APR_LOCK_PROC_PTHREAD: return "proc_pthread";
69    case APR_LOCK_POSIXSEM: return "posixsem";
70    case APR_LOCK_DEFAULT: return "default";
71    default: return "unknown";
72    }
73}
74
75static void test_exclusive(abts_case *tc, void *data)
76{
77    apr_lockmech_e mech = *(apr_lockmech_e *)data;
78    apr_proc_t p1, p2, p3, p4;
79    apr_status_t rv;
80    apr_global_mutex_t *global_lock;
81    int x = 0;
82    abts_log_message("lock mechanism is: ");
83    abts_log_message(mutexname(mech));
84
85    rv = apr_global_mutex_create(&global_lock, LOCKNAME, mech, p);
86    APR_ASSERT_SUCCESS(tc, "Error creating mutex", rv);
87
88    launch_child(tc, mech, &p1, p);
89    launch_child(tc, mech, &p2, p);
90    launch_child(tc, mech, &p3, p);
91    launch_child(tc, mech, &p4, p);
92
93    x += wait_child(tc, &p1);
94    x += wait_child(tc, &p2);
95    x += wait_child(tc, &p3);
96    x += wait_child(tc, &p4);
97
98    if (x != MAX_COUNTER) {
99        char buf[200];
100        sprintf(buf, "global mutex '%s' failed: %d not %d",
101                mutexname(mech), x, MAX_COUNTER);
102        abts_fail(tc, buf, __LINE__);
103    }
104}
105
106abts_suite *testglobalmutex(abts_suite *suite)
107{
108    apr_lockmech_e mech = APR_LOCK_DEFAULT;
109
110    suite = ADD_SUITE(suite)
111    abts_run_test(suite, test_exclusive, &mech);
112#if APR_HAS_POSIXSEM_SERIALIZE
113    mech = APR_LOCK_POSIXSEM;
114    abts_run_test(suite, test_exclusive, &mech);
115#endif
116#if APR_HAS_SYSVSEM_SERIALIZE
117    mech = APR_LOCK_SYSVSEM;
118    abts_run_test(suite, test_exclusive, &mech);
119#endif
120#if APR_HAS_PROC_PTHREAD_SERIALIZE
121    mech = APR_LOCK_PROC_PTHREAD;
122    abts_run_test(suite, test_exclusive, &mech);
123#endif
124#if APR_HAS_FCNTL_SERIALIZE
125    mech = APR_LOCK_FCNTL;
126    abts_run_test(suite, test_exclusive, &mech);
127#endif
128#if APR_HAS_FLOCK_SERIALIZE
129    mech = APR_LOCK_FLOCK;
130    abts_run_test(suite, test_exclusive, &mech);
131#endif
132
133    return suite;
134}
135
136