"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