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 <assert.h>
18#include <errno.h>
19#include <stdio.h>
20#include <stdlib.h>
21
22#include "apr.h"
23#include "apr_general.h"
24#include "apr_proc_mutex.h"
25#include "apr_global_mutex.h"
26#include "apr_thread_proc.h"
27
28#if !APR_HAS_THREADS
29int main(void)
30{
31    printf("This test requires APR thread support.\n");
32    return 0;
33}
34
35#else /* APR_HAS_THREADS */
36
37static apr_thread_mutex_t *thread_mutex;
38static apr_proc_mutex_t *proc_mutex;
39static apr_global_mutex_t *global_mutex;
40static apr_pool_t *p;
41static volatile int counter;
42typedef enum {TEST_GLOBAL, TEST_PROC} test_mode_e;
43
44static void lock_init(apr_lockmech_e mech, test_mode_e test_mode)
45{
46    if (test_mode == TEST_PROC) {
47        assert(apr_proc_mutex_create(&proc_mutex,
48                                     NULL,
49                                     mech,
50                                     p) == APR_SUCCESS);
51    }
52    else {
53        assert(apr_global_mutex_create(&global_mutex,
54                                       NULL,
55                                       mech,
56                                       p) == APR_SUCCESS);
57    }
58}
59
60static void lock_destroy(test_mode_e test_mode)
61{
62    if (test_mode == TEST_PROC) {
63        assert(apr_proc_mutex_destroy(proc_mutex) == APR_SUCCESS);
64    }
65    else {
66        assert(apr_global_mutex_destroy(global_mutex) == APR_SUCCESS);
67    }
68}
69
70static void lock_grab(test_mode_e test_mode)
71{
72    if (test_mode == TEST_PROC) {
73        assert(apr_proc_mutex_lock(proc_mutex) == APR_SUCCESS);
74    }
75    else {
76        assert(apr_global_mutex_lock(global_mutex) == APR_SUCCESS);
77    }
78}
79
80static void lock_release(test_mode_e test_mode)
81{
82    if (test_mode == TEST_PROC) {
83        assert(apr_proc_mutex_unlock(proc_mutex) == APR_SUCCESS);
84    }
85    else {
86        assert(apr_global_mutex_unlock(global_mutex) == APR_SUCCESS);
87    }
88}
89
90static void * APR_THREAD_FUNC eachThread(apr_thread_t *id, void *p)
91{
92    test_mode_e test_mode = (test_mode_e)p;
93
94    lock_grab(test_mode);
95    ++counter;
96    assert(apr_thread_mutex_lock(thread_mutex) == APR_SUCCESS);
97    assert(apr_thread_mutex_unlock(thread_mutex) == APR_SUCCESS);
98    lock_release(test_mode);
99    apr_thread_exit(id, 0);
100    return NULL;
101}
102
103static void test_mech_mode(apr_lockmech_e mech, const char *mech_name,
104                           test_mode_e test_mode)
105{
106  apr_thread_t *threads[20];
107  int numThreads = 5;
108  int i;
109  apr_status_t rv;
110
111  printf("Trying %s mutexes with mechanism `%s'...\n",
112         test_mode == TEST_GLOBAL ? "global" : "proc", mech_name);
113
114  assert(numThreads <= sizeof(threads) / sizeof(threads[0]));
115
116  assert(apr_pool_create(&p, NULL) == APR_SUCCESS);
117
118  assert(apr_thread_mutex_create(&thread_mutex, 0, p) == APR_SUCCESS);
119  assert(apr_thread_mutex_lock(thread_mutex) == APR_SUCCESS);
120
121  lock_init(mech, test_mode);
122
123  counter = 0;
124
125  i = 0;
126  while (i < numThreads)
127  {
128    rv = apr_thread_create(&threads[i],
129                           NULL,
130                           eachThread,
131                           (void *)test_mode,
132                           p);
133    if (rv != APR_SUCCESS) {
134      fprintf(stderr, "apr_thread_create->%d\n", rv);
135      exit(1);
136    }
137    ++i;
138  }
139
140  apr_sleep(apr_time_from_sec(5));
141
142  if (test_mode == TEST_PROC) {
143      printf("  Mutex mechanism `%s' is %sglobal in scope on this platform.\n",
144             mech_name, counter == 1 ? "" : "not ");
145  }
146  else {
147      if (counter != 1) {
148          fprintf(stderr, "\n!!!apr_global_mutex operations are broken on this "
149                  "platform for mutex mechanism `%s'!\n"
150                  "They don't block out threads within the same process.\n",
151                  mech_name);
152          fprintf(stderr, "counter value: %d\n", counter);
153          exit(1);
154      }
155      else {
156          printf("  no problems encountered...\n");
157      }
158  }
159
160  assert(apr_thread_mutex_unlock(thread_mutex) == APR_SUCCESS);
161
162  i = 0;
163  while (i < numThreads)
164  {
165    apr_status_t ignored;
166
167    rv = apr_thread_join(&ignored,
168                         threads[i]);
169    assert(rv == APR_SUCCESS);
170    ++i;
171  }
172
173  lock_destroy(test_mode);
174  apr_thread_mutex_destroy(thread_mutex);
175  apr_pool_destroy(p);
176}
177
178static void test_mech(apr_lockmech_e mech, const char *mech_name)
179{
180    test_mech_mode(mech, mech_name, TEST_PROC);
181    test_mech_mode(mech, mech_name, TEST_GLOBAL);
182}
183
184int main(void)
185{
186    struct {
187        apr_lockmech_e mech;
188        const char *mech_name;
189    } lockmechs[] = {
190        {APR_LOCK_DEFAULT, "default"}
191#if APR_HAS_FLOCK_SERIALIZE
192        ,{APR_LOCK_FLOCK, "flock"}
193#endif
194#if APR_HAS_SYSVSEM_SERIALIZE
195        ,{APR_LOCK_SYSVSEM, "sysvsem"}
196#endif
197#if APR_HAS_POSIXSEM_SERIALIZE
198        ,{APR_LOCK_POSIXSEM, "posix"}
199#endif
200#if APR_HAS_FCNTL_SERIALIZE
201        ,{APR_LOCK_FCNTL, "fcntl"}
202#endif
203#if APR_HAS_PROC_PTHREAD_SERIALIZE
204        ,{APR_LOCK_PROC_PTHREAD, "proc_pthread"}
205#endif
206    };
207    int i;
208
209    assert(apr_initialize() == APR_SUCCESS);
210
211    for (i = 0; i < sizeof(lockmechs) / sizeof(lockmechs[0]); i++) {
212        test_mech(lockmechs[i].mech, lockmechs[i].mech_name);
213    }
214
215    apr_terminate();
216    return 0;
217}
218
219#endif /* APR_HAS_THREADS */
220