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_thread_proc.h"
18#include "apr_thread_mutex.h"
19#include "apr_thread_rwlock.h"
20#include "apr_file_io.h"
21#include "apr_errno.h"
22#include "apr_general.h"
23#include "apr_getopt.h"
24#include "errno.h"
25#include <stdio.h>
26#include <stdlib.h>
27#include "testutil.h"
28
29#if !APR_HAS_THREADS
30int main(void)
31{
32    printf("This program won't work on this platform because there is no "
33           "support for threads.\n");
34    return 0;
35}
36#else /* !APR_HAS_THREADS */
37
38#define MAX_COUNTER 1000000
39#define MAX_THREADS 6
40
41static int verbose = 0;
42static long mutex_counter;
43
44static apr_thread_mutex_t *thread_lock;
45void * APR_THREAD_FUNC thread_mutex_func(apr_thread_t *thd, void *data);
46apr_status_t test_thread_mutex(int num_threads); /* apr_thread_mutex_t */
47
48static apr_thread_rwlock_t *thread_rwlock;
49void * APR_THREAD_FUNC thread_rwlock_func(apr_thread_t *thd, void *data);
50apr_status_t test_thread_rwlock(int num_threads); /* apr_thread_rwlock_t */
51
52int test_thread_mutex_nested(int num_threads);
53
54apr_pool_t *pool;
55int i = 0, x = 0;
56
57void * APR_THREAD_FUNC thread_mutex_func(apr_thread_t *thd, void *data)
58{
59    int i;
60
61    for (i = 0; i < MAX_COUNTER; i++) {
62        apr_thread_mutex_lock(thread_lock);
63        mutex_counter++;
64        apr_thread_mutex_unlock(thread_lock);
65    }
66    return NULL;
67}
68
69void * APR_THREAD_FUNC thread_rwlock_func(apr_thread_t *thd, void *data)
70{
71    int i;
72
73    for (i = 0; i < MAX_COUNTER; i++) {
74        apr_thread_rwlock_wrlock(thread_rwlock);
75        mutex_counter++;
76        apr_thread_rwlock_unlock(thread_rwlock);
77    }
78    return NULL;
79}
80
81int test_thread_mutex(int num_threads)
82{
83    apr_thread_t *t[MAX_THREADS];
84    apr_status_t s[MAX_THREADS];
85    apr_time_t time_start, time_stop;
86    int i;
87
88    mutex_counter = 0;
89
90    printf("apr_thread_mutex_t Tests\n");
91    printf("%-60s", "    Initializing the apr_thread_mutex_t (UNNESTED)");
92    s[0] = apr_thread_mutex_create(&thread_lock, APR_THREAD_MUTEX_UNNESTED, pool);
93    if (s[0] != APR_SUCCESS) {
94        printf("Failed!\n");
95        return s[0];
96    }
97    printf("OK\n");
98
99    apr_thread_mutex_lock(thread_lock);
100    /* set_concurrency(4)? -aaron */
101    printf("    Starting %d threads    ", num_threads);
102    for (i = 0; i < num_threads; ++i) {
103        s[i] = apr_thread_create(&t[i], NULL, thread_mutex_func, NULL, pool);
104        if (s[i] != APR_SUCCESS) {
105            printf("Failed!\n");
106            return s[i];
107        }
108    }
109    printf("OK\n");
110
111    time_start = apr_time_now();
112    apr_thread_mutex_unlock(thread_lock);
113
114    /* printf("%-60s", "    Waiting for threads to exit"); */
115    for (i = 0; i < num_threads; ++i) {
116        apr_thread_join(&s[i], t[i]);
117    }
118    /* printf("OK\n"); */
119
120    time_stop = apr_time_now();
121    printf("microseconds: %" APR_INT64_T_FMT " usec\n",
122           (time_stop - time_start));
123    if (mutex_counter != MAX_COUNTER * num_threads)
124        printf("error: counter = %ld\n", mutex_counter);
125
126    return APR_SUCCESS;
127}
128
129int test_thread_mutex_nested(int num_threads)
130{
131    apr_thread_t *t[MAX_THREADS];
132    apr_status_t s[MAX_THREADS];
133    apr_time_t time_start, time_stop;
134    int i;
135
136    mutex_counter = 0;
137
138    printf("apr_thread_mutex_t Tests\n");
139    printf("%-60s", "    Initializing the apr_thread_mutex_t (NESTED)");
140    s[0] = apr_thread_mutex_create(&thread_lock, APR_THREAD_MUTEX_NESTED, pool);
141    if (s[0] != APR_SUCCESS) {
142        printf("Failed!\n");
143        return s[0];
144    }
145    printf("OK\n");
146
147    apr_thread_mutex_lock(thread_lock);
148    /* set_concurrency(4)? -aaron */
149    printf("    Starting %d threads    ", num_threads);
150    for (i = 0; i < num_threads; ++i) {
151        s[i] = apr_thread_create(&t[i], NULL, thread_mutex_func, NULL, pool);
152        if (s[i] != APR_SUCCESS) {
153            printf("Failed!\n");
154            return s[i];
155        }
156    }
157    printf("OK\n");
158
159    time_start = apr_time_now();
160    apr_thread_mutex_unlock(thread_lock);
161
162    /* printf("%-60s", "    Waiting for threads to exit"); */
163    for (i = 0; i < num_threads; ++i) {
164        apr_thread_join(&s[i], t[i]);
165    }
166    /* printf("OK\n"); */
167
168    time_stop = apr_time_now();
169    printf("microseconds: %" APR_INT64_T_FMT " usec\n",
170           (time_stop - time_start));
171    if (mutex_counter != MAX_COUNTER * num_threads)
172        printf("error: counter = %ld\n", mutex_counter);
173
174    return APR_SUCCESS;
175}
176
177int test_thread_rwlock(int num_threads)
178{
179    apr_thread_t *t[MAX_THREADS];
180    apr_status_t s[MAX_THREADS];
181    apr_time_t time_start, time_stop;
182    int i;
183
184    mutex_counter = 0;
185
186    printf("apr_thread_rwlock_t Tests\n");
187    printf("%-60s", "    Initializing the apr_thread_rwlock_t");
188    s[0] = apr_thread_rwlock_create(&thread_rwlock, pool);
189    if (s[0] != APR_SUCCESS) {
190        printf("Failed!\n");
191        return s[0];
192    }
193    printf("OK\n");
194
195    apr_thread_rwlock_wrlock(thread_rwlock);
196    /* set_concurrency(4)? -aaron */
197    printf("    Starting %d threads    ", num_threads);
198    for (i = 0; i < num_threads; ++i) {
199        s[i] = apr_thread_create(&t[i], NULL, thread_rwlock_func, NULL, pool);
200        if (s[i] != APR_SUCCESS) {
201            printf("Failed!\n");
202            return s[i];
203        }
204    }
205    printf("OK\n");
206
207    time_start = apr_time_now();
208    apr_thread_rwlock_unlock(thread_rwlock);
209
210    /* printf("%-60s", "    Waiting for threads to exit"); */
211    for (i = 0; i < num_threads; ++i) {
212        apr_thread_join(&s[i], t[i]);
213    }
214    /* printf("OK\n"); */
215
216    time_stop = apr_time_now();
217    printf("microseconds: %" APR_INT64_T_FMT " usec\n",
218           (time_stop - time_start));
219    if (mutex_counter != MAX_COUNTER * num_threads)
220        printf("error: counter = %ld\n", mutex_counter);
221
222    return APR_SUCCESS;
223}
224
225int main(int argc, const char * const *argv)
226{
227    apr_status_t rv;
228    char errmsg[200];
229    apr_getopt_t *opt;
230    char optchar;
231    const char *optarg;
232
233    printf("APR Lock Performance Test\n==============\n\n");
234
235    apr_initialize();
236    atexit(apr_terminate);
237
238    if (apr_pool_create(&pool, NULL) != APR_SUCCESS)
239        exit(-1);
240
241    if ((rv = apr_getopt_init(&opt, pool, argc, argv)) != APR_SUCCESS) {
242        fprintf(stderr, "Could not set up to parse options: [%d] %s\n",
243                rv, apr_strerror(rv, errmsg, sizeof errmsg));
244        exit(-1);
245    }
246
247    while ((rv = apr_getopt(opt, "v", &optchar, &optarg)) == APR_SUCCESS) {
248        if (optchar == 'v') {
249            verbose = 1;
250        }
251    }
252
253    if (rv != APR_SUCCESS && rv != APR_EOF) {
254        fprintf(stderr, "Could not parse options: [%d] %s\n",
255                rv, apr_strerror(rv, errmsg, sizeof errmsg));
256        exit(-1);
257    }
258
259    for (i = 1; i <= MAX_THREADS; ++i) {
260        if ((rv = test_thread_mutex(i)) != APR_SUCCESS) {
261            fprintf(stderr,"thread_mutex test failed : [%d] %s\n",
262                    rv, apr_strerror(rv, (char*)errmsg, 200));
263            exit(-3);
264        }
265
266        if ((rv = test_thread_mutex_nested(i)) != APR_SUCCESS) {
267            fprintf(stderr,"thread_mutex (NESTED) test failed : [%d] %s\n",
268                    rv, apr_strerror(rv, (char*)errmsg, 200));
269            exit(-4);
270        }
271
272        if ((rv = test_thread_rwlock(i)) != APR_SUCCESS) {
273            fprintf(stderr,"thread_rwlock test failed : [%d] %s\n",
274                    rv, apr_strerror(rv, (char*)errmsg, 200));
275            exit(-6);
276        }
277    }
278
279    return 0;
280}
281
282#endif /* !APR_HAS_THREADS */
283