"Fossies" - the Fresh Open Source Software Archive 
Member "apr-1.7.0/test/testatomic.c" (17 Sep 2018, 24155 Bytes) of package /linux/www/apr-1.7.0.tar.bz2:
As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style:
standard) with prefixed line numbers and
code folding option.
Alternatively you can here
view or
download the uninterpreted source code file.
See also the latest
Fossies "Diffs" side-by-side code changes report for "testatomic.c":
1.6.5_vs_1.7.0.
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 "testutil.h"
18 #include "apr_strings.h"
19 #include "apr_thread_proc.h"
20 #include "apr_errno.h"
21 #include "apr_general.h"
22 #include "apr_atomic.h"
23 #include "apr_time.h"
24
25 /* Use pthread_setconcurrency where it is available and not a nullop,
26 * i.e. platforms using M:N or M:1 thread models: */
27 #if APR_HAS_THREADS && \
28 ((defined(SOLARIS2) && SOLARIS2 > 6) || defined(_AIX))
29 /* also HP-UX, IRIX? ... */
30 #define HAVE_PTHREAD_SETCONCURRENCY
31 #endif
32
33 #ifdef HAVE_PTHREAD_SETCONCURRENCY
34 #include <pthread.h>
35 #endif
36
37 static void test_init(abts_case *tc, void *data)
38 {
39 APR_ASSERT_SUCCESS(tc, "Could not initliaze atomics", apr_atomic_init(p));
40 }
41
42 static void test_set32(abts_case *tc, void *data)
43 {
44 apr_uint32_t y32;
45 apr_atomic_set32(&y32, 2);
46 ABTS_INT_EQUAL(tc, 2, y32);
47 }
48
49 static void test_read32(abts_case *tc, void *data)
50 {
51 apr_uint32_t y32;
52 apr_atomic_set32(&y32, 2);
53 ABTS_INT_EQUAL(tc, 2, apr_atomic_read32(&y32));
54 }
55
56 static void test_dec32(abts_case *tc, void *data)
57 {
58 apr_uint32_t y32;
59 int rv;
60
61 apr_atomic_set32(&y32, 2);
62
63 rv = apr_atomic_dec32(&y32);
64 ABTS_INT_EQUAL(tc, 1, y32);
65 ABTS_ASSERT(tc, "atomic_dec returned zero when it shouldn't", rv != 0);
66
67 rv = apr_atomic_dec32(&y32);
68 ABTS_INT_EQUAL(tc, 0, y32);
69 ABTS_ASSERT(tc, "atomic_dec didn't returned zero when it should", rv == 0);
70 }
71
72 static void test_xchg32(abts_case *tc, void *data)
73 {
74 apr_uint32_t oldval;
75 apr_uint32_t y32;
76
77 apr_atomic_set32(&y32, 100);
78 oldval = apr_atomic_xchg32(&y32, 50);
79
80 ABTS_INT_EQUAL(tc, 100, oldval);
81 ABTS_INT_EQUAL(tc, 50, y32);
82 }
83
84 static void test_xchgptr(abts_case *tc, void *data)
85 {
86 int a;
87 void *ref = "little piggy";
88 volatile void *target_ptr = ref;
89 void *old_ptr;
90
91 old_ptr = apr_atomic_xchgptr(&target_ptr, &a);
92 ABTS_PTR_EQUAL(tc, ref, old_ptr);
93 ABTS_PTR_EQUAL(tc, &a, (void *) target_ptr);
94 }
95
96 static void test_cas_equal(abts_case *tc, void *data)
97 {
98 apr_uint32_t casval = 0;
99 apr_uint32_t oldval;
100
101 oldval = apr_atomic_cas32(&casval, 12, 0);
102 ABTS_INT_EQUAL(tc, 0, oldval);
103 ABTS_INT_EQUAL(tc, 12, casval);
104 }
105
106 static void test_cas_equal_nonnull(abts_case *tc, void *data)
107 {
108 apr_uint32_t casval = 12;
109 apr_uint32_t oldval;
110
111 oldval = apr_atomic_cas32(&casval, 23, 12);
112 ABTS_INT_EQUAL(tc, 12, oldval);
113 ABTS_INT_EQUAL(tc, 23, casval);
114 }
115
116 static void test_cas_notequal(abts_case *tc, void *data)
117 {
118 apr_uint32_t casval = 12;
119 apr_uint32_t oldval;
120
121 oldval = apr_atomic_cas32(&casval, 23, 2);
122 ABTS_INT_EQUAL(tc, 12, oldval);
123 ABTS_INT_EQUAL(tc, 12, casval);
124 }
125
126 static void test_casptr_equal(abts_case *tc, void *data)
127 {
128 int a;
129 volatile void *target_ptr = NULL;
130 void *old_ptr;
131
132 old_ptr = apr_atomic_casptr(&target_ptr, &a, NULL);
133 ABTS_PTR_EQUAL(tc, NULL, old_ptr);
134 ABTS_PTR_EQUAL(tc, &a, (void *) target_ptr);
135 }
136
137 static void test_casptr_equal_nonnull(abts_case *tc, void *data)
138 {
139 int a, b;
140 volatile void *target_ptr = &a;
141 void *old_ptr;
142
143 old_ptr = apr_atomic_casptr(&target_ptr, &b, &a);
144 ABTS_PTR_EQUAL(tc, &a, old_ptr);
145 ABTS_PTR_EQUAL(tc, &b, (void *) target_ptr);
146 }
147
148 static void test_casptr_notequal(abts_case *tc, void *data)
149 {
150 int a, b;
151 volatile void *target_ptr = &a;
152 void *old_ptr;
153
154 old_ptr = apr_atomic_casptr(&target_ptr, &a, &b);
155 ABTS_PTR_EQUAL(tc, &a, old_ptr);
156 ABTS_PTR_EQUAL(tc, &a, (void *) target_ptr);
157 }
158
159 static void test_add32(abts_case *tc, void *data)
160 {
161 apr_uint32_t oldval;
162 apr_uint32_t y32;
163
164 apr_atomic_set32(&y32, 23);
165 oldval = apr_atomic_add32(&y32, 4);
166 ABTS_INT_EQUAL(tc, 23, oldval);
167 ABTS_INT_EQUAL(tc, 27, y32);
168 }
169
170 static void test_add32_neg(abts_case *tc, void *data)
171 {
172 apr_uint32_t oldval;
173 apr_uint32_t y32;
174
175 apr_atomic_set32(&y32, 23);
176 oldval = apr_atomic_add32(&y32, -10);
177 ABTS_INT_EQUAL(tc, 23, oldval);
178 ABTS_INT_EQUAL(tc, 13, y32);
179 }
180
181 static void test_inc32(abts_case *tc, void *data)
182 {
183 apr_uint32_t oldval;
184 apr_uint32_t y32;
185
186 apr_atomic_set32(&y32, 23);
187 oldval = apr_atomic_inc32(&y32);
188 ABTS_INT_EQUAL(tc, 23, oldval);
189 ABTS_INT_EQUAL(tc, 24, y32);
190 }
191
192 static void test_set_add_inc_sub(abts_case *tc, void *data)
193 {
194 apr_uint32_t y32;
195
196 apr_atomic_set32(&y32, 0);
197 apr_atomic_add32(&y32, 20);
198 apr_atomic_inc32(&y32);
199 apr_atomic_sub32(&y32, 10);
200
201 ABTS_INT_EQUAL(tc, 11, y32);
202 }
203
204 static void test_wrap_zero(abts_case *tc, void *data)
205 {
206 apr_uint32_t y32;
207 apr_uint32_t rv;
208 apr_uint32_t minus1 = (apr_uint32_t)-1;
209 char *str;
210
211 apr_atomic_set32(&y32, 0);
212 rv = apr_atomic_dec32(&y32);
213
214 ABTS_ASSERT(tc, "apr_atomic_dec32 on zero returned zero.", rv != 0);
215 str = apr_psprintf(p, "zero wrap failed: 0 - 1 = %d", y32);
216 ABTS_ASSERT(tc, str, y32 == minus1);
217 }
218
219 static void test_inc_neg1(abts_case *tc, void *data)
220 {
221 apr_uint32_t y32 = (apr_uint32_t)-1;
222 apr_uint32_t minus1 = (apr_uint32_t)-1;
223 apr_uint32_t rv;
224 char *str;
225
226 rv = apr_atomic_inc32(&y32);
227
228 ABTS_ASSERT(tc, "apr_atomic_inc32 didn't return the old value.", rv == minus1);
229 str = apr_psprintf(p, "zero wrap failed: -1 + 1 = %d", y32);
230 ABTS_ASSERT(tc, str, y32 == 0);
231 }
232
233 static void test_set64(abts_case *tc, void *data)
234 {
235 apr_uint64_t y64;
236 apr_atomic_set64(&y64, 2);
237 ABTS_INT_EQUAL(tc, 2, y64);
238 }
239
240 static void test_read64(abts_case *tc, void *data)
241 {
242 apr_uint64_t y64;
243 apr_atomic_set64(&y64, 2);
244 ABTS_INT_EQUAL(tc, 2, apr_atomic_read64(&y64));
245 }
246
247 static void test_dec64(abts_case *tc, void *data)
248 {
249 apr_uint64_t y64;
250 int rv;
251
252 apr_atomic_set64(&y64, 2);
253
254 rv = apr_atomic_dec64(&y64);
255 ABTS_INT_EQUAL(tc, 1, y64);
256 ABTS_ASSERT(tc, "atomic_dec returned zero when it shouldn't", rv != 0);
257
258 rv = apr_atomic_dec64(&y64);
259 ABTS_INT_EQUAL(tc, 0, y64);
260 ABTS_ASSERT(tc, "atomic_dec didn't returned zero when it should", rv == 0);
261 }
262
263 static void test_xchg64(abts_case *tc, void *data)
264 {
265 apr_uint64_t oldval;
266 apr_uint64_t y64;
267
268 apr_atomic_set64(&y64, 100);
269 oldval = apr_atomic_xchg64(&y64, 50);
270
271 ABTS_INT_EQUAL(tc, 100, oldval);
272 ABTS_INT_EQUAL(tc, 50, y64);
273 }
274
275 static void test_add64(abts_case *tc, void *data)
276 {
277 apr_uint64_t oldval;
278 apr_uint64_t y64;
279
280 apr_atomic_set64(&y64, 23);
281 oldval = apr_atomic_add64(&y64, 4);
282 ABTS_INT_EQUAL(tc, 23, oldval);
283 ABTS_INT_EQUAL(tc, 27, y64);
284 }
285
286 static void test_add64_neg(abts_case *tc, void *data)
287 {
288 apr_uint64_t oldval;
289 apr_uint64_t y64;
290
291 apr_atomic_set64(&y64, 23);
292 oldval = apr_atomic_add64(&y64, -10);
293 ABTS_INT_EQUAL(tc, 23, oldval);
294 ABTS_INT_EQUAL(tc, 13, y64);
295 }
296
297 static void test_inc64(abts_case *tc, void *data)
298 {
299 apr_uint64_t oldval;
300 apr_uint64_t y64;
301
302 apr_atomic_set64(&y64, 23);
303 oldval = apr_atomic_inc64(&y64);
304 ABTS_INT_EQUAL(tc, 23, oldval);
305 ABTS_INT_EQUAL(tc, 24, y64);
306 }
307
308 static void test_set_add_inc_sub64(abts_case *tc, void *data)
309 {
310 apr_uint64_t y64;
311
312 apr_atomic_set64(&y64, 0);
313 apr_atomic_add64(&y64, 20);
314 apr_atomic_inc64(&y64);
315 apr_atomic_sub64(&y64, 10);
316
317 ABTS_INT_EQUAL(tc, 11, y64);
318 }
319
320 static void test_wrap_zero64(abts_case *tc, void *data)
321 {
322 apr_uint64_t y64;
323 apr_uint64_t rv;
324 apr_uint64_t minus1 = (apr_uint64_t)-1;
325 char *str;
326
327 apr_atomic_set64(&y64, 0);
328 rv = apr_atomic_dec64(&y64);
329
330 ABTS_ASSERT(tc, "apr_atomic_dec64 on zero returned zero.", rv != 0);
331 str = apr_psprintf(p, "zero wrap failed: 0 - 1 = %lu", y64);
332 ABTS_ASSERT(tc, str, y64 == minus1);
333 }
334
335 static void test_inc_neg164(abts_case *tc, void *data)
336 {
337 apr_uint64_t y64 = (apr_uint64_t)-1;
338 apr_uint64_t minus1 = (apr_uint64_t)-1;
339 apr_uint64_t rv;
340 char *str;
341
342 rv = apr_atomic_inc64(&y64);
343
344 ABTS_ASSERT(tc, "apr_atomic_inc64 didn't return the old value.", rv == minus1);
345 str = apr_psprintf(p, "zero wrap failed: -1 + 1 = %lu", y64);
346 ABTS_ASSERT(tc, str, y64 == 0);
347 }
348
349
350 #if APR_HAS_THREADS
351
352 void *APR_THREAD_FUNC thread_func_mutex(apr_thread_t *thd, void *data);
353 void *APR_THREAD_FUNC thread_func_mutex64(apr_thread_t *thd, void *data);
354 void *APR_THREAD_FUNC thread_func_atomic(apr_thread_t *thd, void *data);
355 void *APR_THREAD_FUNC thread_func_atomic64(apr_thread_t *thd, void *data);
356
357 apr_thread_mutex_t *thread_lock;
358 apr_thread_mutex_t *thread_lock64;
359 volatile apr_uint32_t mutex_locks = 0;
360 volatile apr_uint64_t mutex_locks64 = 0;
361 volatile apr_uint32_t atomic_ops = 0;
362 volatile apr_uint64_t atomic_ops64 = 0;
363 apr_status_t exit_ret_val = 123; /* just some made up number to check on later */
364
365 #define NUM_THREADS 40
366 #define NUM_ITERATIONS 20000
367
368 void *APR_THREAD_FUNC thread_func_mutex(apr_thread_t *thd, void *data)
369 {
370 int i;
371
372 for (i = 0; i < NUM_ITERATIONS; i++) {
373 apr_thread_mutex_lock(thread_lock);
374 mutex_locks++;
375 apr_thread_mutex_unlock(thread_lock);
376 }
377 apr_thread_exit(thd, exit_ret_val);
378 return NULL;
379 }
380
381 void *APR_THREAD_FUNC thread_func_atomic(apr_thread_t *thd, void *data)
382 {
383 int i;
384
385 for (i = 0; i < NUM_ITERATIONS ; i++) {
386 apr_atomic_inc32(&atomic_ops);
387 apr_atomic_add32(&atomic_ops, 2);
388 apr_atomic_dec32(&atomic_ops);
389 apr_atomic_dec32(&atomic_ops);
390 }
391 apr_thread_exit(thd, exit_ret_val);
392 return NULL;
393 }
394
395 static void test_atomics_threaded(abts_case *tc, void *data)
396 {
397 apr_thread_t *t1[NUM_THREADS];
398 apr_thread_t *t2[NUM_THREADS];
399 apr_status_t rv;
400 int i;
401
402 #ifdef HAVE_PTHREAD_SETCONCURRENCY
403 pthread_setconcurrency(8);
404 #endif
405
406 rv = apr_thread_mutex_create(&thread_lock, APR_THREAD_MUTEX_DEFAULT, p);
407 APR_ASSERT_SUCCESS(tc, "Could not create lock", rv);
408
409 for (i = 0; i < NUM_THREADS; i++) {
410 apr_status_t r1, r2;
411 r1 = apr_thread_create(&t1[i], NULL, thread_func_mutex, NULL, p);
412 r2 = apr_thread_create(&t2[i], NULL, thread_func_atomic, NULL, p);
413 ABTS_ASSERT(tc, "Failed creating threads", !r1 && !r2);
414 }
415
416 for (i = 0; i < NUM_THREADS; i++) {
417 apr_status_t s1, s2;
418 apr_thread_join(&s1, t1[i]);
419 apr_thread_join(&s2, t2[i]);
420
421 ABTS_ASSERT(tc, "Invalid return value from thread_join",
422 s1 == exit_ret_val && s2 == exit_ret_val);
423 }
424
425 ABTS_INT_EQUAL(tc, NUM_THREADS * NUM_ITERATIONS, mutex_locks);
426 ABTS_INT_EQUAL(tc, NUM_THREADS * NUM_ITERATIONS,
427 apr_atomic_read32(&atomic_ops));
428
429 rv = apr_thread_mutex_destroy(thread_lock);
430 ABTS_ASSERT(tc, "Failed creating threads", rv == APR_SUCCESS);
431 }
432
433 #undef NUM_THREADS
434 #define NUM_THREADS 7
435
436 typedef struct tbox_t tbox_t;
437 typedef struct tbox_t64 tbox_t64;
438
439 struct tbox_t {
440 abts_case *tc;
441 apr_uint32_t *mem;
442 apr_uint32_t preval;
443 apr_uint32_t postval;
444 apr_uint32_t loop;
445 void (*func)(tbox_t *box);
446 };
447
448 static APR_INLINE void busyloop_read32(tbox_t *tbox)
449 {
450 apr_uint32_t val;
451
452 do {
453 val = apr_atomic_read32(tbox->mem);
454
455 if (val != tbox->preval)
456 apr_thread_yield();
457 else
458 break;
459 } while (1);
460 }
461
462 static void busyloop_set32(tbox_t *tbox)
463 {
464 do {
465 busyloop_read32(tbox);
466 apr_atomic_set32(tbox->mem, tbox->postval);
467 } while (--tbox->loop);
468 }
469
470 static void busyloop_add32(tbox_t *tbox)
471 {
472 apr_uint32_t val;
473
474 do {
475 busyloop_read32(tbox);
476 val = apr_atomic_add32(tbox->mem, tbox->postval);
477 apr_thread_mutex_lock(thread_lock);
478 ABTS_INT_EQUAL(tbox->tc, val, tbox->preval);
479 apr_thread_mutex_unlock(thread_lock);
480 } while (--tbox->loop);
481 }
482
483 static void busyloop_sub32(tbox_t *tbox)
484 {
485 do {
486 busyloop_read32(tbox);
487 apr_atomic_sub32(tbox->mem, tbox->postval);
488 } while (--tbox->loop);
489 }
490
491 static void busyloop_inc32(tbox_t *tbox)
492 {
493 apr_uint32_t val;
494
495 do {
496 busyloop_read32(tbox);
497 val = apr_atomic_inc32(tbox->mem);
498 apr_thread_mutex_lock(thread_lock);
499 ABTS_INT_EQUAL(tbox->tc, val, tbox->preval);
500 apr_thread_mutex_unlock(thread_lock);
501 } while (--tbox->loop);
502 }
503
504 static void busyloop_dec32(tbox_t *tbox)
505 {
506 apr_uint32_t val;
507
508 do {
509 busyloop_read32(tbox);
510 val = apr_atomic_dec32(tbox->mem);
511 apr_thread_mutex_lock(thread_lock);
512 ABTS_INT_NEQUAL(tbox->tc, 0, val);
513 apr_thread_mutex_unlock(thread_lock);
514 } while (--tbox->loop);
515 }
516
517 static void busyloop_cas32(tbox_t *tbox)
518 {
519 apr_uint32_t val;
520
521 do {
522 do {
523 val = apr_atomic_cas32(tbox->mem, tbox->postval, tbox->preval);
524
525 if (val != tbox->preval)
526 apr_thread_yield();
527 else
528 break;
529 } while (1);
530 } while (--tbox->loop);
531 }
532
533 static void busyloop_xchg32(tbox_t *tbox)
534 {
535 apr_uint32_t val;
536
537 do {
538 busyloop_read32(tbox);
539 val = apr_atomic_xchg32(tbox->mem, tbox->postval);
540 apr_thread_mutex_lock(thread_lock);
541 ABTS_INT_EQUAL(tbox->tc, val, tbox->preval);
542 apr_thread_mutex_unlock(thread_lock);
543 } while (--tbox->loop);
544 }
545
546 static void *APR_THREAD_FUNC thread_func_busyloop(apr_thread_t *thd, void *data)
547 {
548 tbox_t *tbox = data;
549
550 tbox->func(tbox);
551
552 apr_thread_exit(thd, 0);
553
554 return NULL;
555 }
556
557 static void test_atomics_busyloop_threaded(abts_case *tc, void *data)
558 {
559 unsigned int i;
560 apr_status_t rv;
561 apr_uint32_t count = 0;
562 tbox_t tbox[NUM_THREADS];
563 apr_thread_t *thread[NUM_THREADS];
564
565 rv = apr_thread_mutex_create(&thread_lock, APR_THREAD_MUTEX_DEFAULT, p);
566 APR_ASSERT_SUCCESS(tc, "Could not create lock", rv);
567
568 /* get ready */
569 for (i = 0; i < NUM_THREADS; i++) {
570 tbox[i].tc = tc;
571 tbox[i].mem = &count;
572 tbox[i].loop = 50;
573 }
574
575 tbox[0].preval = 98;
576 tbox[0].postval = 3891;
577 tbox[0].func = busyloop_add32;
578
579 tbox[1].preval = 3989;
580 tbox[1].postval = 1010;
581 tbox[1].func = busyloop_sub32;
582
583 tbox[2].preval = 2979;
584 tbox[2].postval = 0; /* not used */
585 tbox[2].func = busyloop_inc32;
586
587 tbox[3].preval = 2980;
588 tbox[3].postval = 16384;
589 tbox[3].func = busyloop_set32;
590
591 tbox[4].preval = 16384;
592 tbox[4].postval = 0; /* not used */
593 tbox[4].func = busyloop_dec32;
594
595 tbox[5].preval = 16383;
596 tbox[5].postval = 1048576;
597 tbox[5].func = busyloop_cas32;
598
599 tbox[6].preval = 1048576;
600 tbox[6].postval = 98; /* goto tbox[0] */
601 tbox[6].func = busyloop_xchg32;
602
603 /* get set */
604 for (i = 0; i < NUM_THREADS; i++) {
605 rv = apr_thread_create(&thread[i], NULL, thread_func_busyloop,
606 &tbox[i], p);
607 ABTS_ASSERT(tc, "Failed creating thread", rv == APR_SUCCESS);
608 }
609
610 /* go! */
611 apr_atomic_set32(tbox->mem, 98);
612
613 for (i = 0; i < NUM_THREADS; i++) {
614 apr_status_t retval;
615 rv = apr_thread_join(&retval, thread[i]);
616 ABTS_ASSERT(tc, "Thread join failed", rv == APR_SUCCESS);
617 ABTS_ASSERT(tc, "Invalid return value from thread_join", retval == 0);
618 }
619
620 ABTS_INT_EQUAL(tbox->tc, 98, count);
621
622 rv = apr_thread_mutex_destroy(thread_lock);
623 ABTS_ASSERT(tc, "Failed creating threads", rv == APR_SUCCESS);
624 }
625
626 void *APR_THREAD_FUNC thread_func_mutex64(apr_thread_t *thd, void *data)
627 {
628 int i;
629
630 for (i = 0; i < NUM_ITERATIONS; i++) {
631 apr_thread_mutex_lock(thread_lock64);
632 mutex_locks64++;
633 apr_thread_mutex_unlock(thread_lock64);
634 }
635 apr_thread_exit(thd, exit_ret_val);
636 return NULL;
637 }
638
639
640 void *APR_THREAD_FUNC thread_func_atomic64(apr_thread_t *thd, void *data)
641 {
642 int i;
643
644 for (i = 0; i < NUM_ITERATIONS ; i++) {
645 apr_atomic_inc64(&atomic_ops64);
646 apr_atomic_add64(&atomic_ops64, 2);
647 apr_atomic_dec64(&atomic_ops64);
648 apr_atomic_dec64(&atomic_ops64);
649 }
650 apr_thread_exit(thd, exit_ret_val);
651 return NULL;
652 }
653
654 static void test_atomics_threaded64(abts_case *tc, void *data)
655 {
656 apr_thread_t *t1[NUM_THREADS];
657 apr_thread_t *t2[NUM_THREADS];
658 apr_status_t rv;
659 int i;
660
661 #ifdef HAVE_PTHREAD_SETCONCURRENCY
662 pthread_setconcurrency(8);
663 #endif
664
665 rv = apr_thread_mutex_create(&thread_lock64, APR_THREAD_MUTEX_DEFAULT, p);
666 APR_ASSERT_SUCCESS(tc, "Could not create lock", rv);
667
668 for (i = 0; i < NUM_THREADS; i++) {
669 apr_status_t r1, r2;
670 r1 = apr_thread_create(&t1[i], NULL, thread_func_mutex64, NULL, p);
671 r2 = apr_thread_create(&t2[i], NULL, thread_func_atomic64, NULL, p);
672 ABTS_ASSERT(tc, "Failed creating threads", !r1 && !r2);
673 }
674
675 for (i = 0; i < NUM_THREADS; i++) {
676 apr_status_t s1, s2;
677 apr_thread_join(&s1, t1[i]);
678 apr_thread_join(&s2, t2[i]);
679
680 ABTS_ASSERT(tc, "Invalid return value from thread_join",
681 s1 == exit_ret_val && s2 == exit_ret_val);
682 }
683
684 ABTS_INT_EQUAL(tc, NUM_THREADS * NUM_ITERATIONS, mutex_locks64);
685 ABTS_INT_EQUAL(tc, NUM_THREADS * NUM_ITERATIONS,
686 apr_atomic_read64(&atomic_ops64));
687
688 rv = apr_thread_mutex_destroy(thread_lock64);
689 ABTS_ASSERT(tc, "Failed creating threads", rv == APR_SUCCESS);
690 }
691
692 struct tbox_t64 {
693 abts_case *tc;
694 apr_uint64_t *mem;
695 apr_uint64_t preval;
696 apr_uint64_t postval;
697 apr_uint64_t loop;
698 void (*func)(tbox_t64 *box);
699 };
700
701 static APR_INLINE void busyloop_read64(tbox_t64 *tbox)
702 {
703 apr_uint64_t val;
704
705 do {
706 val = apr_atomic_read64(tbox->mem);
707
708 if (val != tbox->preval)
709 apr_thread_yield();
710 else
711 break;
712 } while (1);
713 }
714
715 static void busyloop_set64(tbox_t64 *tbox)
716 {
717 do {
718 busyloop_read64(tbox);
719 apr_atomic_set64(tbox->mem, tbox->postval);
720 } while (--tbox->loop);
721 }
722
723 static void busyloop_add64(tbox_t64 *tbox)
724 {
725 apr_uint64_t val;
726
727 do {
728 busyloop_read64(tbox);
729 val = apr_atomic_add64(tbox->mem, tbox->postval);
730 apr_thread_mutex_lock(thread_lock64);
731 ABTS_INT_EQUAL(tbox->tc, val, tbox->preval);
732 apr_thread_mutex_unlock(thread_lock64);
733 } while (--tbox->loop);
734 }
735
736 static void busyloop_sub64(tbox_t64 *tbox)
737 {
738 do {
739 busyloop_read64(tbox);
740 apr_atomic_sub64(tbox->mem, tbox->postval);
741 } while (--tbox->loop);
742 }
743
744 static void busyloop_inc64(tbox_t64 *tbox)
745 {
746 apr_uint64_t val;
747
748 do {
749 busyloop_read64(tbox);
750 val = apr_atomic_inc64(tbox->mem);
751 apr_thread_mutex_lock(thread_lock64);
752 ABTS_INT_EQUAL(tbox->tc, val, tbox->preval);
753 apr_thread_mutex_unlock(thread_lock64);
754 } while (--tbox->loop);
755 }
756
757 static void busyloop_dec64(tbox_t64 *tbox)
758 {
759 apr_uint64_t val;
760
761 do {
762 busyloop_read64(tbox);
763 val = apr_atomic_dec64(tbox->mem);
764 apr_thread_mutex_lock(thread_lock64);
765 ABTS_INT_NEQUAL(tbox->tc, 0, val);
766 apr_thread_mutex_unlock(thread_lock64);
767 } while (--tbox->loop);
768 }
769
770 static void busyloop_cas64(tbox_t64 *tbox)
771 {
772 apr_uint64_t val;
773
774 do {
775 do {
776 val = apr_atomic_cas64(tbox->mem, tbox->postval, tbox->preval);
777
778 if (val != tbox->preval)
779 apr_thread_yield();
780 else
781 break;
782 } while (1);
783 } while (--tbox->loop);
784 }
785
786 static void busyloop_xchg64(tbox_t64 *tbox)
787 {
788 apr_uint64_t val;
789
790 do {
791 busyloop_read64(tbox);
792 val = apr_atomic_xchg64(tbox->mem, tbox->postval);
793 apr_thread_mutex_lock(thread_lock64);
794 ABTS_INT_EQUAL(tbox->tc, val, tbox->preval);
795 apr_thread_mutex_unlock(thread_lock64);
796 } while (--tbox->loop);
797 }
798
799 static void *APR_THREAD_FUNC thread_func_busyloop64(apr_thread_t *thd, void *data)
800 {
801 tbox_t64 *tbox = data;
802
803 tbox->func(tbox);
804
805 apr_thread_exit(thd, 0);
806
807 return NULL;
808 }
809
810 static void test_atomics_busyloop_threaded64(abts_case *tc, void *data)
811 {
812 unsigned int i;
813 apr_status_t rv;
814 apr_uint64_t count = 0;
815 tbox_t64 tbox[NUM_THREADS];
816 apr_thread_t *thread[NUM_THREADS];
817
818 rv = apr_thread_mutex_create(&thread_lock64, APR_THREAD_MUTEX_DEFAULT, p);
819 APR_ASSERT_SUCCESS(tc, "Could not create lock", rv);
820
821 /* get ready */
822 for (i = 0; i < NUM_THREADS; i++) {
823 tbox[i].tc = tc;
824 tbox[i].mem = &count;
825 tbox[i].loop = 50;
826 }
827
828 tbox[0].preval = 98;
829 tbox[0].postval = 3891;
830 tbox[0].func = busyloop_add64;
831
832 tbox[1].preval = 3989;
833 tbox[1].postval = 1010;
834 tbox[1].func = busyloop_sub64;
835
836 tbox[2].preval = 2979;
837 tbox[2].postval = 0; /* not used */
838 tbox[2].func = busyloop_inc64;
839
840 tbox[3].preval = 2980;
841 tbox[3].postval = 16384;
842 tbox[3].func = busyloop_set64;
843
844 tbox[4].preval = 16384;
845 tbox[4].postval = 0; /* not used */
846 tbox[4].func = busyloop_dec64;
847
848 tbox[5].preval = 16383;
849 tbox[5].postval = 1048576;
850 tbox[5].func = busyloop_cas64;
851
852 tbox[6].preval = 1048576;
853 tbox[6].postval = 98; /* goto tbox[0] */
854 tbox[6].func = busyloop_xchg64;
855
856 /* get set */
857 for (i = 0; i < NUM_THREADS; i++) {
858 rv = apr_thread_create(&thread[i], NULL, thread_func_busyloop64,
859 &tbox[i], p);
860 ABTS_ASSERT(tc, "Failed creating thread", rv == APR_SUCCESS);
861 }
862
863 /* go! */
864 apr_atomic_set64(tbox->mem, 98);
865
866 for (i = 0; i < NUM_THREADS; i++) {
867 apr_status_t retval;
868 rv = apr_thread_join(&retval, thread[i]);
869 ABTS_ASSERT(tc, "Thread join failed", rv == APR_SUCCESS);
870 ABTS_ASSERT(tc, "Invalid return value from thread_join", retval == 0);
871 }
872
873 ABTS_INT_EQUAL(tbox->tc, 98, count);
874
875 rv = apr_thread_mutex_destroy(thread_lock64);
876 ABTS_ASSERT(tc, "Failed creating threads", rv == APR_SUCCESS);
877 }
878
879 #endif /* !APR_HAS_THREADS */
880
881 abts_suite *testatomic(abts_suite *suite)
882 {
883 suite = ADD_SUITE(suite)
884
885 abts_run_test(suite, test_init, NULL);
886 abts_run_test(suite, test_set32, NULL);
887 abts_run_test(suite, test_read32, NULL);
888 abts_run_test(suite, test_dec32, NULL);
889 abts_run_test(suite, test_xchg32, NULL);
890 abts_run_test(suite, test_xchgptr, NULL);
891 abts_run_test(suite, test_cas_equal, NULL);
892 abts_run_test(suite, test_cas_equal_nonnull, NULL);
893 abts_run_test(suite, test_cas_notequal, NULL);
894 abts_run_test(suite, test_casptr_equal, NULL);
895 abts_run_test(suite, test_casptr_equal_nonnull, NULL);
896 abts_run_test(suite, test_casptr_notequal, NULL);
897 abts_run_test(suite, test_add32, NULL);
898 abts_run_test(suite, test_add32_neg, NULL);
899 abts_run_test(suite, test_inc32, NULL);
900 abts_run_test(suite, test_set_add_inc_sub, NULL);
901 abts_run_test(suite, test_wrap_zero, NULL);
902 abts_run_test(suite, test_inc_neg1, NULL);
903 abts_run_test(suite, test_set64, NULL);
904 abts_run_test(suite, test_read64, NULL);
905 abts_run_test(suite, test_dec64, NULL);
906 abts_run_test(suite, test_xchg64, NULL);
907 abts_run_test(suite, test_add64, NULL);
908 abts_run_test(suite, test_add64_neg, NULL);
909 abts_run_test(suite, test_inc64, NULL);
910 abts_run_test(suite, test_set_add_inc_sub64, NULL);
911 abts_run_test(suite, test_wrap_zero64, NULL);
912 abts_run_test(suite, test_inc_neg164, NULL);
913
914 #if APR_HAS_THREADS
915 abts_run_test(suite, test_atomics_threaded, NULL);
916 abts_run_test(suite, test_atomics_threaded64, NULL);
917 abts_run_test(suite, test_atomics_busyloop_threaded, NULL);
918 abts_run_test(suite, test_atomics_busyloop_threaded64, NULL);
919 #endif
920
921 return suite;
922 }
923