Apache HTTPD
testlock.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_thread_proc.h"
18#include "apr_file_io.h"
19#include "apr_thread_mutex.h"
20#include "apr_thread_rwlock.h"
21#include "apr_thread_cond.h"
22#include "apr_errno.h"
23#include "apr_general.h"
24#include "apr_getopt.h"
25#include "apr_atomic.h"
26#include "testutil.h"
27
28#if APR_HAS_THREADS
29
30#define MAX_ITER 40000
31#define MAX_COUNTER 100000
32#define MAX_RETRY 5
33
39
41static apr_thread_rwlock_t *rwlock;
42static int i = 0, x = 0;
43
44static int buff[MAX_COUNTER];
45
46struct {
47 apr_thread_mutex_t *mutex;
48 int nput;
49 int nval;
50} put;
51
52struct {
53 apr_thread_mutex_t *mutex;
55 int nready;
56} nready;
57
60
62{
63 int exitLoop = 1;
64
65 while (1)
66 {
68 if (i == MAX_ITER)
69 exitLoop = 0;
71
72 if (!exitLoop)
73 break;
74
76 if (i != MAX_ITER)
77 {
78 i++;
79 x++;
80 }
82 }
83 return NULL;
84}
85
87{
88 int exitLoop = 1;
89
90 /* slight delay to allow things to settle */
91 apr_sleep (1);
92
93 while (1)
94 {
95 if (data) {
97 }
98 else {
100 }
101 if (i == MAX_ITER)
102 exitLoop = 0;
103 else
104 {
105 i++;
106 x++;
107 }
109
110 if (!exitLoop)
111 break;
112 }
113 return NULL;
114}
115
116/* Sleepy-loop until f_ value matches val: */
117#define wait_for_flag(f_, val) while (apr_atomic_read32(&(f_)) != val) apr_sleep(100000)
118
119/* Helper function. Passed (apr_uint32_t *) flag as data, sets flag
120 * to one, locks the timeout_mutex, waits for *flag to be set to zero
121 * and terminates. The co-ordination could also be done via mutexes
122 * but since we're timedlocking timeout_mutex it would look like a
123 * deadlock to a mutex implementation which detects deadlocks. */
125{
127 apr_status_t rv;
128
130 if (rv) {
131 fprintf(stderr, "testlock: failed to lock timeout mutex, errno %d\n", rv);
132 apr_thread_exit(thd, rv);
133 }
134
136
137 wait_for_flag(*flag, 0);
138
140
142 return NULL;
143}
144
146{
147 for (;;) {
148 apr_thread_mutex_lock(put.mutex);
149 if (put.nput >= MAX_COUNTER) {
150 apr_thread_mutex_unlock(put.mutex);
151 return NULL;
152 }
153 buff[put.nput] = put.nval;
154 put.nput++;
155 put.nval++;
156 apr_thread_mutex_unlock(put.mutex);
157
159 if (nready.nready == 0)
161 nready.nready++;
163
164 *((int *) data) += 1;
165 }
166
167 return NULL;
168}
169
171{
172 int i;
173
174 for (i = 0; i < MAX_COUNTER; i++) {
176 while (nready.nready == 0)
178 nready.nready--;
180
181 if (buff[i] != i)
182 printf("buff[%d] = %d\n", i, buff[i]);
183 }
184
185 return NULL;
186}
187
188static void test_thread_mutex(abts_case *tc, void *data)
189{
190 apr_thread_t *t1, *t2, *t3, *t4;
192
196
197 i = 0;
198 x = 0;
199
208
213
214 ABTS_INT_EQUAL(tc, MAX_ITER, x);
215}
216
217#if APR_HAS_TIMEDLOCKS
218static void test_thread_timedmutex(abts_case *tc, void *data)
219{
220 apr_thread_t *t1, *t2, *t3, *t4;
223
227
228 i = 0;
229 x = 0;
230
232
241
246
247 ABTS_INT_EQUAL(tc, MAX_ITER, x);
248}
249#endif
250
251static void test_thread_rwlock(abts_case *tc, void *data)
252{
253 apr_thread_t *t1, *t2, *t3, *t4;
255
256 s1 = apr_thread_rwlock_create(&rwlock, p);
257 if (s1 == APR_ENOTIMPL) {
258 ABTS_NOT_IMPL(tc, "rwlocks not implemented");
259 return;
260 }
261 APR_ASSERT_SUCCESS(tc, "rwlock_create", s1);
262 ABTS_PTR_NOTNULL(tc, rwlock);
263
264 i = 0;
265 x = 0;
266
268 APR_ASSERT_SUCCESS(tc, "create thread 1", s1);
270 APR_ASSERT_SUCCESS(tc, "create thread 2", s2);
272 APR_ASSERT_SUCCESS(tc, "create thread 3", s3);
274 APR_ASSERT_SUCCESS(tc, "create thread 4", s4);
275
280
281 ABTS_INT_EQUAL(tc, MAX_ITER, x);
282
284}
285
286static void test_cond(abts_case *tc, void *data)
287{
288 apr_thread_t *p1, *p2, *p3, *p4, *c1;
289 apr_status_t s0, s1, s2, s3, s4;
290 int count1, count2, count3, count4;
291 int sum;
292
293 APR_ASSERT_SUCCESS(tc, "create put mutex",
294 apr_thread_mutex_create(&put.mutex,
296 ABTS_PTR_NOTNULL(tc, put.mutex);
297
298 APR_ASSERT_SUCCESS(tc, "create nready mutex",
301 ABTS_PTR_NOTNULL(tc, nready.mutex);
302
303 APR_ASSERT_SUCCESS(tc, "create condvar",
305 ABTS_PTR_NOTNULL(tc, nready.cond);
306
307 count1 = count2 = count3 = count4 = 0;
308 put.nput = put.nval = 0;
309 nready.nready = 0;
310 i = 0;
311 x = 0;
312
323
328 apr_thread_join(&s4, c1);
329
330 APR_ASSERT_SUCCESS(tc, "destroy condvar",
332
333 sum = count1 + count2 + count3 + count4;
334 /*
335 printf("count1 = %d count2 = %d count3 = %d count4 = %d\n",
336 count1, count2, count3, count4);
337 */
339}
340
341static void test_timeoutcond(abts_case *tc, void *data)
342{
346 int i;
347
351
355
357
358 for (i = 0; i < MAX_RETRY; i++) {
360
363 end = apr_time_now();
365
366 if (s != APR_SUCCESS && !APR_STATUS_IS_TIMEUP(s)) {
367 continue;
368 }
370 ABTS_ASSERT(tc, "Timer returned too late", end - begin - timeout < 500000);
371 break;
372 }
373 ABTS_ASSERT(tc, "Too many retries", i < MAX_RETRY);
374 APR_ASSERT_SUCCESS(tc, "Unable to destroy the conditional",
376}
377
378/* Test whether _timedlock times out appropriately. Since
379 * double-locking a non-recursive mutex has undefined behaviour, and
380 * double-locking a recursive mutex succeeds immediately, a thread is
381 * spawned to hold the lock while this thread tests whether _timedlock
382 * times out. */
383#if APR_HAS_TIMEDLOCKS
384static void test_timeoutmutex(abts_case *tc, void *data)
385{
390 apr_uint32_t flag = 0;
391 int i;
392
398
401
402 wait_for_flag(flag, 1); /* the thread will set flag to 1 once the
403 * timeout_mutex is locked. */
404
406
407 for (i = 0; i < MAX_RETRY; i++) {
410 end = apr_time_now();
411
412 if (s != APR_SUCCESS && !APR_STATUS_IS_TIMEUP(s)) {
413 continue;
414 }
416 ABTS_ASSERT(tc, "Timer returned too late", end - begin - timeout < 1000000);
417 break;
418 }
419
420 apr_atomic_set32(&flag, 0); /* tell the thread to exit. */
421
422 APR_ASSERT_SUCCESS(tc, "join spawned thread", apr_thread_join(&s, th));
423 APR_ASSERT_SUCCESS(tc, "spawned thread terminated", s);
424
425 ABTS_ASSERT(tc, "Too many retries", i < MAX_RETRY);
426 APR_ASSERT_SUCCESS(tc, "Unable to destroy the timeout mutex",
428}
429#endif
430
431static void test_thread_nestedmutex(abts_case *tc, void *data)
432{
434 apr_status_t rv;
435
438 ABTS_PTR_NOTNULL(tc, m);
439
442
445 if (rv == APR_SUCCESS)
446 {
449 }
450
453}
454
455static void test_thread_unnestedmutex(abts_case *tc, void *data)
456{
458 apr_status_t rv;
459
462 ABTS_PTR_NOTNULL(tc, m);
463
466
468 ABTS_INT_EQUAL(tc, APR_EBUSY, rv);
469 if (rv == APR_SUCCESS)
470 {
473 }
474
477}
478
479#ifdef WIN32
480static void *APR_THREAD_FUNC
482{
483 apr_thread_mutex_t *mutex = data;
484 apr_status_t rv;
485
486 rv = apr_thread_mutex_lock(mutex);
487
488 /* exit from thread without unlocking mutex. */
489 apr_thread_exit(thd, rv);
490
491 return NULL;
492}
493
494static void test_win32_abandoned_mutex(abts_case *tc, void *data)
495{
496 apr_status_t rv;
497 apr_thread_t *thread;
498 apr_thread_mutex_t *mutex;
499
500 /* Create timed mutex: APR will create Win32 mutex object in this case. */
503
505 mutex, p);
507
508 apr_thread_join(&rv, thread);
510
511 rv = apr_thread_mutex_trylock(mutex);
513
514 rv = apr_thread_mutex_unlock (mutex);
516}
517
518#endif
519
520#endif /* !APR_HAS_THREADS */
521
522#if !APR_HAS_THREADS
523static void threads_not_impl(abts_case *tc, void *data)
524{
525 ABTS_NOT_IMPL(tc, "Threads not implemented on this platform");
526}
527#endif
528
529
531{
532 suite = ADD_SUITE(suite)
533
534#if !APR_HAS_THREADS
536#else
538#if APR_HAS_TIMEDLOCKS
540#endif
546#if APR_HAS_TIMEDLOCKS
548#endif
549#ifdef WIN32
551#endif
552#endif
553
554 return suite;
555}
556
const char * buff
Definition ap_regex.h:186
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_PTR_NOTNULL(a, b)
Definition abts.h:125
#define ABTS_NOT_IMPL(a, b)
Definition abts.h:129
#define ABTS_ASSERT(a, b, c)
Definition abts.h:130
#define ABTS_INT_EQUAL(a, b, c)
Definition abts.h:109
#define APR_ASSERT_SUCCESS(tc, ctxt, rv)
Definition testutil.h:58
APR Atomic Operations.
APR Error Codes.
APR File I/O Handling.
APR Miscellaneous library routines.
APR Command Arguments (getopt)
APR Condition Variable Routines.
APR Thread Mutex Routines.
APR Thread and Process Library.
APR Reader/Writer Lock Routines.
void apr_atomic_set32(volatile apr_uint32_t *mem, apr_uint32_t val)
Definition atomic.c:73
static apr_thread_mutex_t * timeout_mutex
Definition event.c:192
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_EBUSY
Definition apr_errno.h:480
#define APR_STATUS_IS_TIMEUP(s)
Definition apr_errno.h:534
apr_size_t size
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
const char apr_int32_t flag
void * data
const char char ** end
const char * s
Definition apr_strings.h:95
const void * m
apr_int64_t apr_interval_time_t
Definition apr_time.h:55
apr_int64_t apr_time_t
Definition apr_time.h:45
#define apr_time_from_sec(sec)
Definition apr_time.h:78
apr_pool_t * p
Definition md_event.c:32
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
apr_status_t apr_thread_exit(apr_thread_t *thd, apr_status_t retval)
Definition thread.c:157
apr_status_t apr_thread_join(apr_status_t *retval, apr_thread_t *thd)
Definition thread.c:166
apr_status_t apr_thread_create(apr_thread_t **new, apr_threadattr_t *attr, apr_thread_start_t func, void *data, apr_pool_t *pool)
Definition thread.c:73
#define MAX_COUNTER
#define MAX_ITER
static void threads_not_impl(abts_case *tc, void *data)
Definition testlock.c:523
abts_suite * testlock(abts_suite *suite)
Definition testlock.c:530
static apr_table_t * t1
Definition testtable.c:34
IN ULONG IN INT timeout