"Fossies" - the Fresh Open Source Software Archive

Member "openpa-1.0.4/test/test_primitives.c" (11 Jan 2013, 166246 Bytes) of package /linux/misc/openpa-1.0.4.tar.gz:


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.

    1 /* -*- Mode: C; c-basic-offset:4 ; indent-tabs-mode:nil ; -*- */
    2 /*
    3  *  (C) 2008 by Argonne National Laboratory.
    4  *      See COPYRIGHT in top-level directory.
    5  */
    6 
    7 /*
    8  * Uncomment this definition to disable the OPA library and instead use naive
    9  * (non-atomic) operations.  This should cause failures.
   10  */
   11 /*
   12 #define OPA_TEST_NAIVE
   13 */
   14 
   15 #include "opa_test.h"
   16 
   17 /* Definitions for test_threaded_loadstore_int */
   18 /* LOADSTORE_INT_DIFF is the difference between the unique values of successive
   19  * threads.  This value contains 0's in the top half of the int and 1's in the
   20  * bottom half.  Therefore, for 4 byte ints the sequence of unique values is:
   21  * 0x00000000, 0x0000FFFF, 0x0001FFFE, 0x0002FFFD, etc. */
   22 #define LOADSTORE_INT_DIFF ((1 << (sizeof(int) * CHAR_BIT / 2)) - 1)
   23 #define LOADSTORE_INT_NITER (4000000 / iter_reduction[curr_test])
   24 typedef struct {
   25     OPA_int_t   *shared_val;    /* Shared int being read/written by all threads */
   26     int         unique_val;     /* This thread's unique value to store in shared_val */
   27     int         nerrors;        /* Number of errors */
   28     int         master_thread;  /* Whether this is the master thread */
   29 } loadstore_int_t;
   30 
   31 /* Definitions for test_threaded_loadstore_ptr */
   32 #define LOADSTORE_PTR_DIFF (((unsigned long) 1 << (sizeof(void *) * CHAR_BIT / 2)) - 1)
   33 #define LOADSTORE_PTR_NITER (4000000 / iter_reduction[curr_test])
   34 typedef struct {
   35     OPA_ptr_t   *shared_val;    /* Shared int being read/written by all threads */
   36     void        *unique_val;    /* This thread's unique value to store in shared_val */
   37     int         nerrors;        /* Number of errors */
   38     int         master_thread;  /* Whether this is the master thread */
   39 } loadstore_ptr_t;
   40 
   41 /* Definitions for test_threaded_add */
   42 #define ADD_EXPECTED ADD_NITER
   43 #define ADD_NITER (2000000 / iter_reduction[curr_test])
   44 typedef struct {
   45     OPA_int_t   *shared_val;    /* Shared int being added to by all threads */
   46     int         unique_val;     /* This thread's unique value to add to shared_val */
   47     int         master_thread;  /* Whether this is the master thread */
   48 } add_t;
   49 
   50 /* Definitions for test_threaded_incr_decr */
   51 #define INCR_DECR_EXPECTED INCR_DECR_NITER
   52 #define INCR_DECR_NITER (2000000 / iter_reduction[curr_test])
   53 typedef struct {
   54     OPA_int_t   *shared_val;    /* Shared int being manipulated by all threads */
   55     int         master_thread;  /* Whether this is the master thread */
   56 } incr_decr_t;
   57 
   58 /* Definitions for test_threaded_decr_and_test */
   59 #define DECR_AND_TEST_NITER_INNER 20            /* *Must* be even */
   60 #define DECR_AND_TEST_NITER_OUTER (10000 / iter_reduction[curr_test])
   61 typedef struct {
   62     OPA_int_t   *shared_val;    /* Shared int being decr and tested by all threads */
   63     unsigned    ntrue;          /* # of times decr_and_test returned true */
   64     int         master_thread;  /* Whether this is the master thread */
   65 } decr_test_t;
   66 
   67 /* Definitions for test_threaded_faa */
   68 /* Uses definitions from test_threaded_add */
   69 
   70 /* Definitions for test_threaded_faa_ret */
   71 #define FAA_RET_EXPECTED (-((nthreads - 1) * FAA_RET_NITER))
   72 #define FAA_RET_NITER (2000000 / iter_reduction[curr_test])
   73 typedef struct {
   74     OPA_int_t   *shared_val;    /* Shared int being added to by all threads */
   75     int         nerrors;        /* Number of errors */
   76     int         n1;             /* # of times faa returned 1 */
   77     int         master_thread;  /* Whether this is the master thread */
   78 } faa_ret_t;
   79 
   80 /* Definitions for test_threaded_fai_fad */
   81 /* Uses definitions from test_threaded_incr_decr */
   82 
   83 /* Definitions for test_threaded_fai_ret */
   84 #define FAI_RET_EXPECTED ((nthreads - 1) * FAA_RET_NITER)
   85 #define FAI_RET_NITER (2000000 / iter_reduction[curr_test])
   86 typedef struct {
   87     OPA_int_t   *shared_val;    /* Shared int being added to by all threads */
   88     int         nerrors;        /* Number of errors */
   89     int         nm1;            /* # of times faa returned -1 */
   90     int         master_thread;  /* Whether this is the master thread */
   91 } fai_ret_t;
   92 
   93 /* Definitions for test_threaded_fad_red */
   94 /* Uses definitions from test_threaded_faa_ret */
   95 
   96 /* Definitions for test_threaded_cas_int */
   97 #define CAS_INT_NITER (5000000 / iter_reduction[curr_test])
   98 typedef struct {
   99     OPA_int_t   *shared_val;    /* Shared int being manipulated by all threads */
  100     int         threadno;       /* Unique thread number */
  101     int         nsuccess;       /* # of times cas succeeded */
  102     int         master_thread;  /* Whether this is the master thread */
  103 } cas_int_t;
  104 
  105 /* Definitions for test_threaded_cas_ptr */
  106 #define CAS_PTR_NITER (5000000 / iter_reduction[curr_test])
  107 typedef struct {
  108     OPA_ptr_t   *shared_val;    /* Shared ptr being manipulated by all threads */
  109     int         *threadno;      /* Unique thread number */
  110     int         *max_threadno;  /* Maximum unique thread number */
  111     int         nsuccess;       /* # of times cas succeeded */
  112     int         master_thread;  /* Whether this is the master thread */
  113 } cas_ptr_t;
  114 
  115 /* Definitions for test_grouped_cas_int */
  116 #define GROUPED_CAS_INT_NITER (5000000 / iter_reduction[curr_test])
  117 #define GROUPED_CAS_INT_TPG 4
  118 typedef struct {
  119     OPA_int_t   *shared_val;    /* Shared int being manipulated by all threads */
  120     int         groupno;        /* Unique group number */
  121     int         ngroups;        /* Number of groups */
  122     int         nsuccess;       /* # of times cas succeeded */
  123     int         master_thread;  /* Whether this is the master thread */
  124 } grouped_cas_int_t;
  125 
  126 /* Definitions for test_grouped_cas_ptr */
  127 #define GROUPED_CAS_PTR_NITER (5000000 / iter_reduction[curr_test])
  128 #define GROUPED_CAS_PTR_TPG 4
  129 typedef struct {
  130     OPA_ptr_t   *shared_val;    /* Shared ptr being manipulated by all threads */
  131     int         *groupno;       /* Unique group number */
  132     int         *max_groupno;   /* Maximum unique group number */
  133     int         nsuccess;       /* # of times cas succeeded */
  134     int         master_thread;  /* Whether this is the master thread */
  135 } grouped_cas_ptr_t;
  136 
  137 /* Definitions for test_threaded_cas_int_fairness */
  138 #define CAS_INT_FAIRNESS_MIN_SUCCESS (100 / iter_reduction[curr_test])
  139 #define CAS_INT_FAIRNESS_MAX_ITER (10000000 / iter_reduction[curr_test])
  140 typedef struct {
  141     OPA_int_t   *shared_val;    /* Shared int being manipulated by all threads */
  142     int         nerrors;        /* Number of errors */
  143     int         threadno;       /* Unique thread number */
  144     int         nthreads;       /* Number of threads */
  145     OPA_int_t   *successful_threads; /* # of threads that have completed */
  146     int         terminated;     /* Whether this thread was terminated by MAX_ITER */
  147     int         master_thread;  /* Whether this is the master thread */
  148 } cas_int_fairness_t;
  149 
  150 /* Definitions for test_threaded_cas_ptr_fairness */
  151 #define CAS_PTR_FAIRNESS_MIN_SUCCESS (100 / iter_reduction[curr_test])
  152 #define CAS_PTR_FAIRNESS_MAX_ITER (10000000 / iter_reduction[curr_test])
  153 typedef struct {
  154     OPA_ptr_t   *shared_val;    /* Shared ptr being manipulated by all threads */
  155     int         nerrors;        /* Number of errors */
  156     int         *threadno;      /* Unique thread number */
  157     int         nthreads;       /* Number of threads */
  158     OPA_int_t   *successful_threads; /* # of threads that have completed */
  159     int         terminated;     /* Whether this thread was terminated by MAX_ITER */
  160     int         master_thread;  /* Whether this is the master thread */
  161 } cas_ptr_fairness_t;
  162 
  163 /* Definitions for test_threaded_swap_int */
  164 #define SWAP_INT_NITER (2000000 / iter_reduction[curr_test])
  165 typedef struct {
  166     OPA_int_t   *shared_val;    /* Shared int being manipulated by all threads */
  167     int         local_val;      /* Local int value for this thread */
  168     int         master_thread;  /* Whether this is the master thread */
  169 } swap_int_t;
  170 
  171 /* Definitions for test_threaded_swap_ptr */
  172 #define SWAP_PTR_NITER (2000000 / iter_reduction[curr_test])
  173 typedef struct {
  174     OPA_ptr_t   *shared_val;    /* Shared ptr being manipulated by all threads */
  175     void        *local_val;     /* Local ptr value for this thread */
  176     unsigned    threadno;       /* Thread number */
  177     int         master_thread;  /* Whether this is the master thread */
  178 } swap_ptr_t;
  179 
  180 /* Definitions for test_threaded_llsc_int_aba */
  181 #define LLSC_INT_ABA_NITER 2000000
  182 typedef struct {
  183     char        padding1[OPA_TEST_CACHELINE_PADDING];
  184     OPA_int_t   shared_val;     /* Shared value being manipulated by both threads */
  185     char        padding2[OPA_TEST_CACHELINE_PADDING - sizeof(OPA_int_t)];
  186     OPA_int_t   pass_point_0;   /* Whether we have passed point 0 */
  187     OPA_int_t   pass_point_1;   /* Whether we have passed point 1 */
  188     OPA_int_t   pass_point_2;   /* Whether we have passed point 2 */
  189     OPA_int_t   change_val;     /* Whether we will change/have changed shared_val */
  190     int         false_positives; /* Number of times SC failed unnecessarily */
  191     int         nunchanged_val; /* Number of times change_val was false */
  192 } llsc_int_aba_t;
  193 
  194 /* Definitions for test_threaded_llsc_ptr_aba */
  195 #define LLSC_PTR_ABA_NITER 2000000
  196 typedef struct {
  197     char        padding1[OPA_TEST_CACHELINE_PADDING];
  198     OPA_ptr_t   shared_val;     /* Shared value being manipulated by both threads */
  199     char        padding2[OPA_TEST_CACHELINE_PADDING - sizeof(OPA_ptr_t)];
  200     OPA_int_t   pass_point_0;   /* Whether we have passed point 0 */
  201     OPA_int_t   pass_point_1;   /* Whether we have passed point 1 */
  202     OPA_int_t   pass_point_2;   /* Whether we have passed point 2 */
  203     OPA_int_t   change_val;     /* Whether we will change/have changed shared_val */
  204     int         false_positives; /* Number of times SC failed unnecessarily */
  205     int         nunchanged_val; /* Number of times change_val was false */
  206 } llsc_ptr_aba_t;
  207 
  208 /* Definitions for test_threaded_llsc_int_stack */
  209 #define LLSC_INT_STACK_NITER (100000 / iter_reduction[curr_test])
  210 #define LLSC_INT_STACK_NLOOP 100000
  211 #define LLSC_INT_STACK_TPG 3
  212 typedef struct {
  213     OPA_int_t   on_stack;       /* Whether this object is on the stack */
  214     OPA_int_t   next;           /* Index of next object in stack */
  215 } llsc_int_stack_obj_t;
  216 typedef struct {
  217     OPA_int_t   *head;          /* Head of stack (index into objs) */
  218     llsc_int_stack_obj_t **objs; /* Array of pointers to objects */
  219     int         obj;            /* Object for currect pusher thread (index into objs) */
  220     OPA_int_t   *npushers;      /* Number of pusher threads running */
  221     int         nsuccess;       /* Number of successful pops or pushes */
  222     int         nerrors;        /* Number of errors */
  223     OPA_int_t   *failed;        /* Whether the test has failed and should be terminated */
  224     int         master_thread;  /* Whether this is the master thread */
  225 } llsc_int_stack_t;
  226 
  227 /* Definitions for test_threaded_llsc_ptr_stack */
  228 #define LLSC_PTR_STACK_NITER (100000 / iter_reduction[curr_test])
  229 #define LLSC_PTR_STACK_NLOOP 100000
  230 #define LLSC_PTR_STACK_TPG 3
  231 typedef struct {
  232     OPA_int_t   on_stack;       /* Whether this object is on the stack */
  233     OPA_ptr_t   next;           /* Next object in stack */
  234 } llsc_ptr_stack_obj_t;
  235 typedef struct {
  236     OPA_ptr_t   *head;          /* Head of stack (index into objs) */
  237     llsc_ptr_stack_obj_t *obj;  /* Object for currect pusher thread */
  238     OPA_int_t   *npushers;      /* Number of pusher threads running */
  239     int         nsuccess;       /* Number of successful pops or pushes */
  240     int         nerrors;        /* Number of errors */
  241     OPA_int_t   *failed;        /* Whether the test has failed and should be terminated */
  242     int         master_thread;  /* Whether this is the master thread */
  243 } llsc_ptr_stack_t;
  244 
  245 
  246 /*-------------------------------------------------------------------------
  247  * Function: test_simple_loadstore_int
  248  *
  249  * Purpose: Tests basic functionality of OPA_load_int and OPA_store_int with a
  250  *          single thread.  Does not test atomicity of operations.
  251  *
  252  * Return: Success: 0
  253  *         Failure: 1
  254  *
  255  * Programmer: Neil Fortner
  256  *             Thursday, March 19, 2009
  257  *
  258  * Modifications:
  259  *
  260  *-------------------------------------------------------------------------
  261  */
  262 static int test_simple_loadstore_int(void)
  263 {
  264     OPA_int_t   a, b;
  265 
  266     TESTING("simple integer load/store functionality", 0);
  267 
  268     /* Store 0 in a, -1 in b.  Verify that these values are returned by
  269      * OPA_load_int. */
  270     OPA_store_int(&a, 0);
  271     if(0 != OPA_load_int(&a)) TEST_ERROR;
  272     OPA_store_int(&b, -1);
  273     if(-1 != OPA_load_int(&b)) TEST_ERROR;
  274     if(0 != OPA_load_int(&a)) TEST_ERROR;
  275     if(-1 != OPA_load_int(&b)) TEST_ERROR;
  276 
  277     /* Store INT_MIN in a and INT_MAX in b.  Verify that these values are
  278      * returned by OPA_load_int. */
  279     OPA_store_int(&a, INT_MIN);
  280     if(INT_MIN != OPA_load_int(&a)) TEST_ERROR;
  281     OPA_store_int(&b, INT_MAX);
  282     if(INT_MAX != OPA_load_int(&b)) TEST_ERROR;
  283     if(INT_MIN != OPA_load_int(&a)) TEST_ERROR;
  284     if(INT_MAX != OPA_load_int(&b)) TEST_ERROR;
  285 
  286     PASSED();
  287     return 0;
  288 
  289 error:
  290     return 1;
  291 } /* end test_simple_loadstore_int() */
  292 
  293 
  294 #if defined(OPA_HAVE_PTHREAD_H)
  295 /*-------------------------------------------------------------------------
  296  * Function: threaded_loadstore_int_helper
  297  *
  298  * Purpose: Helper (thread) routine for test_threaded_loadstore_int
  299  *
  300  * Return: Success: NULL
  301  *         Failure: non-NULL
  302  *
  303  * Programmer: Neil Fortner
  304  *             Thursday, March 19, 2009
  305  *
  306  * Modifications:
  307  *
  308  *-------------------------------------------------------------------------
  309  */
  310 static void *threaded_loadstore_int_helper(void *_udata)
  311 {
  312     loadstore_int_t     *udata = (loadstore_int_t *)_udata;
  313     int                 loaded_val;
  314     unsigned            niter = LOADSTORE_INT_NITER;
  315     unsigned            i;
  316 
  317     /* Main loop */
  318     for(i=0; i<niter; i++) {
  319         /* Store the unique value into the shared value */
  320         OPA_store_int(udata->shared_val, udata->unique_val);
  321 
  322         /* Load the shared_value, and check if it is valid */
  323         if((loaded_val = OPA_load_int(udata->shared_val)) % LOADSTORE_INT_DIFF) {
  324             printf("    Unexpected load: %d is not a multiple of %d\n",
  325                     loaded_val, LOADSTORE_INT_DIFF);
  326             udata->nerrors++;
  327         } /* end if */
  328     } /* end for */
  329 
  330     /* Exit */
  331     if(udata->master_thread)
  332         return(NULL);
  333     else
  334         pthread_exit(NULL);
  335 } /* end threaded_loadstore_int_helper() */
  336 #endif /* OPA_HAVE_PTHREAD_H */
  337 
  338 
  339 /*-------------------------------------------------------------------------
  340  * Function: test_threaded_loadstore_int
  341  *
  342  * Purpose: Tests atomicity of OPA_load_int and OPA_store_int.  Launches nthreads
  343  *          threads, each of which repeatedly loads and stores a shared
  344  *          variable.
  345  *
  346  * Return: Success: 0
  347  *         Failure: 1
  348  *
  349  * Programmer: Neil Fortner
  350  *             Thursday, March 19, 2009
  351  *
  352  * Modifications:
  353  *
  354  *-------------------------------------------------------------------------
  355  */
  356 static int test_threaded_loadstore_int(void)
  357 {
  358 #if defined(OPA_HAVE_PTHREAD_H)
  359     pthread_t           *threads = NULL; /* Threads */
  360     pthread_attr_t      ptattr;         /* Thread attributes */
  361     loadstore_int_t     *thread_data = NULL; /* User data structs for each thread */
  362     OPA_int_t           shared_int;     /* Integer shared between threads */
  363     unsigned            nthreads = num_threads[curr_test];
  364     unsigned            nerrors = 0;    /* number of errors */
  365     unsigned            i;
  366 
  367     TESTING("integer load/store", nthreads);
  368 
  369     /* Allocate array of threads */
  370     if(NULL == (threads = (pthread_t *) malloc((nthreads - 1) * sizeof(pthread_t))))
  371         TEST_ERROR;
  372 
  373     /* Allocate array of thread data */
  374     if(NULL == (thread_data = (loadstore_int_t *) calloc(nthreads,
  375             sizeof(loadstore_int_t)))) TEST_ERROR;
  376 
  377     /* Set threads to be joinable */
  378     pthread_attr_init(&ptattr);
  379     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
  380 
  381     /* Initialize thread data structs */
  382     for(i=0; i<nthreads; i++) {
  383         thread_data[i].shared_val = &shared_int;
  384         thread_data[i].unique_val = i * LOADSTORE_INT_DIFF;;
  385     } /* end for */
  386     thread_data[nthreads-1].master_thread = 1;
  387 
  388     /* Create the threads */
  389     for(i=0; i<(nthreads - 1); i++)
  390         if(pthread_create(&threads[i], &ptattr, threaded_loadstore_int_helper,
  391                 &thread_data[i])) TEST_ERROR;
  392     (void)threaded_loadstore_int_helper(&thread_data[i]);
  393 
  394     /* Free the attribute */
  395     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
  396 
  397     /* Join the threads */
  398     for (i=0; i<(nthreads - 1); i++)
  399         if(pthread_join(threads[i], NULL)) TEST_ERROR;
  400 
  401     /* Check for errors */
  402     for(i=0; i<nthreads; i++)
  403         nerrors += thread_data[i].nerrors;
  404     if(nerrors)
  405         FAIL_OP_ERROR(printf("    %d unexpected return%s from OPA_load_int\n", nerrors,
  406                 nerrors == 1 ? "" : "s"));
  407 
  408     /* Free memory */
  409     free(threads);
  410     free(thread_data);
  411 
  412     PASSED();
  413 
  414 #else /* OPA_HAVE_PTHREAD_H */
  415     TESTING("integer load/store", 0);
  416     SKIPPED();
  417     puts("    pthread.h not available");
  418 #endif /* OPA_HAVE_PTHREAD_H */
  419 
  420     return 0;
  421 
  422 #if defined(OPA_HAVE_PTHREAD_H)
  423 error:
  424     if(threads) free(threads);
  425     if(thread_data) free(thread_data);
  426     return 1;
  427 #endif /* OPA_HAVE_PTHREAD_H */
  428 } /* end test_threaded_loadstore_int() */
  429 
  430 
  431 /*-------------------------------------------------------------------------
  432  * Function: test_simple_loadstore_ptr
  433  *
  434  * Purpose: Tests basic functionality of OPA_load_int and OPA_store_int with a
  435  *          single thread.  Does not test atomicity of operations.
  436  *
  437  * Return: Success: 0
  438  *         Failure: 1
  439  *
  440  * Programmer: Neil Fortner
  441  *             Thursday, March 20, 2009
  442  *
  443  * Modifications:
  444  *
  445  *-------------------------------------------------------------------------
  446  */
  447 static int test_simple_loadstore_ptr(void)
  448 {
  449     OPA_ptr_t   a, b;
  450 
  451     TESTING("simple pointer load/store functionality", 0);
  452 
  453     /* Store 0 in a, 1 in b.  Verify that these values are returned by
  454      * OPA_load_int. */
  455     OPA_store_ptr(&a, (void *) 0);
  456     if((void *) 0 != OPA_load_ptr(&a)) TEST_ERROR;
  457     OPA_store_ptr(&b, (void *) 1);
  458     if((void *) 1 != OPA_load_ptr(&b)) TEST_ERROR;
  459     if((void *) 0 != OPA_load_ptr(&a)) TEST_ERROR;
  460     if((void *) 1 != OPA_load_ptr(&b)) TEST_ERROR;
  461 
  462     /* Store -1 in a and -2 in b.  Verify that these values are returned by
  463      * OPA_load_int. */
  464     OPA_store_ptr(&a, (void *) -2);
  465     if((void *) -2 != OPA_load_ptr(&a)) TEST_ERROR;
  466     OPA_store_ptr(&b, (void *) -1);
  467     if((void *) -1 != OPA_load_ptr(&b)) TEST_ERROR;
  468     if((void *) -2 != OPA_load_ptr(&a)) TEST_ERROR;
  469     if((void *) -1 != OPA_load_ptr(&b)) TEST_ERROR;
  470 
  471     PASSED();
  472     return 0;
  473 
  474 error:
  475     return 1;
  476 } /* end test_simple_loadstore_ptr() */
  477 
  478 
  479 #if defined(OPA_HAVE_PTHREAD_H)
  480 /*-------------------------------------------------------------------------
  481  * Function: threaded_loadstore_ptr_helper
  482  *
  483  * Purpose: Helper (thread) routine for test_threaded_loadstore_ptr
  484  *
  485  * Return: Success: NULL
  486  *         Failure: non-NULL
  487  *
  488  * Programmer: Neil Fortner
  489  *             Thursday, March 20, 2009
  490  *
  491  * Modifications:
  492  *
  493  *-------------------------------------------------------------------------
  494  */
  495 static void *threaded_loadstore_ptr_helper(void *_udata)
  496 {
  497     loadstore_ptr_t     *udata = (loadstore_ptr_t *)_udata;
  498     unsigned long       loaded_val;
  499     int                 niter = LOADSTORE_PTR_NITER;
  500     unsigned            i;
  501 
  502     /* Main loop */
  503     for(i=0; i<niter; i++) {
  504         /* Store the unique value into the shared value */
  505         OPA_store_ptr(udata->shared_val, udata->unique_val);
  506 
  507         /* Load the shared_value, and check if it is valid */
  508         if((loaded_val = (unsigned long) OPA_load_ptr(udata->shared_val)) % LOADSTORE_PTR_DIFF) {
  509             printf("    Unexpected load: %lu is not a multiple of %lu\n",
  510                     loaded_val, LOADSTORE_PTR_DIFF);
  511             udata->nerrors++;
  512         } /* end if */
  513     } /* end for */
  514 
  515     /* Exit */
  516     if(udata->master_thread)
  517         return(NULL);
  518     else
  519         pthread_exit(NULL);
  520 } /* end threaded_loadstore_ptr_helper() */
  521 #endif /* OPA_HAVE_PTHREAD_H */
  522 
  523 
  524 /*-------------------------------------------------------------------------
  525  * Function: test_threaded_loadstore_ptr
  526  *
  527  * Purpose: Tests atomicity of OPA_load_int and OPA_store_int.  Launches nthreads
  528  *          threads, each of which repeatedly loads and stores a shared
  529  *          variable.
  530  *
  531  * Return: Success: 0
  532  *         Failure: 1
  533  *
  534  * Programmer: Neil Fortner
  535  *             Thursday, March 20, 2009
  536  *
  537  * Modifications:
  538  *
  539  *-------------------------------------------------------------------------
  540  */
  541 static int test_threaded_loadstore_ptr(void)
  542 {
  543 #if defined(OPA_HAVE_PTHREAD_H)
  544     pthread_t           *threads = NULL; /* Threads */
  545     pthread_attr_t      ptattr;         /* Thread attributes */
  546     loadstore_ptr_t     *thread_data = NULL; /* User data structs for each thread */
  547     OPA_ptr_t           shared_ptr;     /* Integer shared between threads */
  548     unsigned            nthreads = num_threads[curr_test];
  549     unsigned            nerrors = 0;    /* number of errors */
  550     unsigned            i;
  551 
  552     TESTING("pointer load/store", nthreads);
  553 
  554     /* Allocate array of threads */
  555     if(NULL == (threads = (pthread_t *) malloc((nthreads - 1) * sizeof(pthread_t))))
  556         TEST_ERROR;
  557 
  558     /* Allocate array of thread data */
  559     if(NULL == (thread_data = (loadstore_ptr_t *) calloc(nthreads,
  560             sizeof(loadstore_ptr_t)))) TEST_ERROR;
  561 
  562     /* Set threads to be joinable */
  563     pthread_attr_init(&ptattr);
  564     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
  565 
  566     /* Initialize thread data structs */
  567     for(i=0; i<nthreads; i++) {
  568         thread_data[i].shared_val = &shared_ptr;
  569         thread_data[i].unique_val = (void *) ((unsigned long) i * LOADSTORE_PTR_DIFF);
  570     } /* end for */
  571     thread_data[nthreads-1].master_thread = 1;
  572 
  573     /* Create the threads */
  574     for(i=0; i<(nthreads - 1); i++)
  575         if(pthread_create(&threads[i], &ptattr, threaded_loadstore_ptr_helper,
  576                 &thread_data[i])) TEST_ERROR;
  577     (void)threaded_loadstore_ptr_helper(&thread_data[i]);
  578 
  579     /* Free the attribute */
  580     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
  581 
  582     /* Join the threads */
  583     for (i=0; i<(nthreads - 1); i++)
  584         if(pthread_join(threads[i], NULL)) TEST_ERROR;
  585 
  586 
  587     /* Check for errors */
  588     for(i=0; i<nthreads; i++)
  589         nerrors += thread_data[i].nerrors;
  590     if(nerrors)
  591         FAIL_OP_ERROR(printf("    %d unexpected return%s from OPA_load_ptr\n", nerrors,
  592                 nerrors == 1 ? "" : "s"));
  593 
  594     /* Free memory */
  595     free(threads);
  596     free(thread_data);
  597 
  598     PASSED();
  599 
  600 #else /* OPA_HAVE_PTHREAD_H */
  601     TESTING("pointer load/store", 0);
  602     SKIPPED();
  603     puts("    pthread.h not available");
  604 #endif /* OPA_HAVE_PTHREAD_H */
  605 
  606     return 0;
  607 
  608 #if defined(OPA_HAVE_PTHREAD_H)
  609 error:
  610     if(threads) free(threads);
  611     if(thread_data) free(thread_data);
  612     return 1;
  613 #endif /* OPA_HAVE_PTHREAD_H */
  614 } /* end test_threaded_loadstore_ptr() */
  615 
  616 
  617 /*-------------------------------------------------------------------------
  618  * Function: test_simple_add_incr_decr
  619  *
  620  * Purpose: Tests basic functionality of OPA_add_int, OPA_incr_int and
  621  *          OPA_decr_int with a single thread.  Does not test atomicity
  622  *          of operations.
  623  *
  624  * Return: Success: 0
  625  *         Failure: 1
  626  *
  627  * Programmer: Neil Fortner
  628  *             Thursday, March 20, 2009
  629  *
  630  * Modifications:
  631  *
  632  *-------------------------------------------------------------------------
  633  */
  634 static int test_simple_add_incr_decr(void)
  635 {
  636     OPA_int_t   a;
  637 
  638     TESTING("simple add/incr/decr functionality", 0);
  639 
  640     /* Store 0 in a */
  641     OPA_store_int(&a, 0);
  642 
  643     /* Add INT_MIN */
  644     OPA_add_int(&a, INT_MIN);
  645 
  646     /* Increment */
  647     OPA_incr_int(&a);
  648 
  649     /* Add INT_MAX */
  650     OPA_add_int(&a, INT_MAX);
  651 
  652     /* Decrement */
  653     OPA_decr_int(&a);
  654 
  655     /* Load the result, verify it is correct */
  656     if(OPA_load_int(&a) != INT_MIN + 1 + INT_MAX - 1) TEST_ERROR;
  657 
  658     /* Store 0 in a */
  659     OPA_store_int(&a, 0);
  660 
  661     /* Add INT_MAX */
  662     OPA_add_int(&a, INT_MAX);
  663 
  664     /* Decrement */
  665     OPA_decr_int(&a);
  666 
  667     /* Add INT_MIN */
  668     OPA_add_int(&a, INT_MIN);
  669 
  670     /* Increment */
  671     OPA_incr_int(&a);
  672 
  673     /* Load the result, verify it is correct */
  674     if(OPA_load_int(&a) != INT_MAX - 1 + INT_MIN + 1) TEST_ERROR;
  675 
  676     PASSED();
  677     return 0;
  678 
  679 error:
  680     return 1;
  681 } /* end test_simple_add_incr_decr() */
  682 
  683 
  684 #if defined(OPA_HAVE_PTHREAD_H)
  685 /*-------------------------------------------------------------------------
  686  * Function: threaded_add_helper
  687  *
  688  * Purpose: Helper (thread) routine for test_threaded_add
  689  *
  690  * Return: NULL
  691  *
  692  * Programmer: Neil Fortner
  693  *             Thursday, March 20, 2009
  694  *
  695  * Modifications:
  696  *
  697  *-------------------------------------------------------------------------
  698  */
  699 static void *threaded_add_helper(void *_udata)
  700 {
  701     add_t               *udata = (add_t *)_udata;
  702     unsigned            niter = ADD_NITER;
  703     unsigned            i;
  704 
  705     /* Main loop */
  706     for(i=0; i<niter; i++)
  707         /* Add the unique value to the shared value */
  708         OPA_add_int(udata->shared_val, udata->unique_val);
  709 
  710     /* Exit */
  711     if(udata->master_thread)
  712         return(NULL);
  713     else
  714         pthread_exit(NULL);
  715 } /* end threaded_add_helper() */
  716 #endif /* OPA_HAVE_PTHREAD_H */
  717 
  718 
  719 /*-------------------------------------------------------------------------
  720  * Function: test_threaded_add
  721  *
  722  * Purpose: Tests atomicity of OPA_add_int.  Launches nthreads threads
  723  *          each of which repeatedly adds a unique number to a shared
  724  *          variable.
  725  *
  726  * Return: Success: 0
  727  *         Failure: 1
  728  *
  729  * Programmer: Neil Fortner
  730  *             Thursday, March 20, 2009
  731  *
  732  * Modifications:
  733  *
  734  *-------------------------------------------------------------------------
  735  */
  736 static int test_threaded_add(void)
  737 {
  738 #if defined(OPA_HAVE_PTHREAD_H)
  739     pthread_t           *threads = NULL; /* Threads */
  740     pthread_attr_t      ptattr;         /* Thread attributes */
  741     add_t               *thread_data = NULL; /* User data structs for each thread */
  742     OPA_int_t           shared_val;     /* Integer shared between threads */
  743     unsigned            nthreads = num_threads[curr_test];
  744     unsigned            i;
  745 
  746     TESTING("add", nthreads);
  747 
  748     /* Allocate array of threads */
  749     if(NULL == (threads = (pthread_t *) malloc((nthreads - 1) * sizeof(pthread_t))))
  750         TEST_ERROR;
  751 
  752     /* Allocate array of thread data */
  753     if(NULL == (thread_data = (add_t *) calloc(nthreads, sizeof(add_t))))
  754         TEST_ERROR;
  755 
  756     /* Initialize thread data structs.  All the unique values must add up to
  757      * 0. */
  758     OPA_store_int(&shared_val, 0);
  759     for(i=0; i<nthreads; i++) {
  760         thread_data[i].shared_val = &shared_val;
  761         thread_data[i].unique_val = i - (nthreads - 1) / 2
  762                 - (!(nthreads % 2) && (i >= nthreads / 2))
  763                 + (i == nthreads - 1);
  764     } /* end for */
  765     thread_data[nthreads-1].master_thread = 1;
  766 
  767     /* Set threads to be joinable */
  768     pthread_attr_init(&ptattr);
  769     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
  770 
  771     /* Create the threads */
  772     for(i=0; i<(nthreads - 1); i++)
  773         if(pthread_create(&threads[i], &ptattr, threaded_add_helper,
  774                 &thread_data[i])) TEST_ERROR;
  775     (void)threaded_add_helper(&thread_data[i]);
  776 
  777     /* Free the attribute */
  778     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
  779 
  780     /* Join the threads */
  781     for (i=0; i<(nthreads - 1); i++)
  782         if(pthread_join(threads[i], NULL)) TEST_ERROR;
  783 
  784     /* Verify that the shared value contains the expected result (0) */
  785     if(OPA_load_int(&shared_val) != ADD_EXPECTED)
  786         FAIL_OP_ERROR(printf("    Unexpected result: %d expected: %d\n",
  787                 OPA_load_int(&shared_val), ADD_EXPECTED));
  788 
  789     /* Free memory */
  790     free(threads);
  791     free(thread_data);
  792 
  793     PASSED();
  794 
  795 #else /* OPA_HAVE_PTHREAD_H */
  796     TESTING("add", 0);
  797     SKIPPED();
  798     puts("    pthread.h not available");
  799 #endif /* OPA_HAVE_PTHREAD_H */
  800 
  801     return 0;
  802 
  803 #if defined(OPA_HAVE_PTHREAD_H)
  804 error:
  805     if(threads) free(threads);
  806     if(thread_data) free(thread_data);
  807     return 1;
  808 #endif /* OPA_HAVE_PTHREAD_H */
  809 } /* end test_threaded_add() */
  810 
  811 
  812 #if defined(OPA_HAVE_PTHREAD_H)
  813 /*-------------------------------------------------------------------------
  814  * Function: threaded_incr_helper
  815  *
  816  * Purpose: Helper (thread) routine for test_threaded_incr_decr
  817  *
  818  * Return: NULL
  819  *
  820  * Programmer: Neil Fortner
  821  *             Tuesday, April 21, 2009
  822  *
  823  * Modifications:
  824  *
  825  *-------------------------------------------------------------------------
  826  */
  827 static void *threaded_incr_helper(void *_udata)
  828 {
  829     incr_decr_t         *udata = (incr_decr_t *)_udata;
  830     unsigned            niter = INCR_DECR_NITER;
  831     unsigned            i;
  832 
  833     /* Main loop */
  834     for(i=0; i<niter; i++)
  835         /* Increment the shared value */
  836         OPA_incr_int(udata->shared_val);
  837 
  838     /* Exit */
  839     if(udata->master_thread)
  840         return(NULL);
  841     else
  842         pthread_exit(NULL);
  843 } /* end threaded_incr_helper() */
  844 
  845 
  846 /*-------------------------------------------------------------------------
  847  * Function: threaded_decr_helper
  848  *
  849  * Purpose: Helper (thread) routine for test_threaded_incr_decr
  850  *
  851  * Return: NULL
  852  *
  853  * Programmer: Neil Fortner
  854  *             Tuesday, April 21, 2009
  855  *
  856  * Modifications:
  857  *
  858  *-------------------------------------------------------------------------
  859  */
  860 static void *threaded_decr_helper(void *_udata)
  861 {
  862     incr_decr_t         *udata = (incr_decr_t *)_udata;
  863     unsigned            niter = INCR_DECR_NITER;
  864     unsigned            i;
  865 
  866     /* Main loop */
  867     for(i=0; i<niter; i++)
  868         /* Decrement the shared value */
  869         OPA_decr_int(udata->shared_val);
  870 
  871     /* Exit */
  872     if(udata->master_thread)
  873         return(NULL);
  874     else
  875         pthread_exit(NULL);
  876 } /* end threaded_decr_helper() */
  877 #endif /* OPA_HAVE_PTHREAD_H */
  878 
  879 
  880 /*-------------------------------------------------------------------------
  881  * Function: test_threaded_incr_decr
  882  *
  883  * Purpose: Tests atomicity of OPA_incr_int and OPA_decr_int.  Launches
  884  *          nthreads threads, each of which repeatedly either increments
  885  *          or decrements a shared variable.
  886  *
  887  * Return: Success: 0
  888  *         Failure: 1
  889  *
  890  * Programmer: Neil Fortner
  891  *             Tuesday, April 21, 2009
  892  *
  893  * Modifications:
  894  *
  895  *-------------------------------------------------------------------------
  896  */
  897 static int test_threaded_incr_decr(void)
  898 {
  899 #if defined(OPA_HAVE_PTHREAD_H)
  900     pthread_t           *threads = NULL; /* Threads */
  901     pthread_attr_t      ptattr;         /* Thread attributes */
  902     incr_decr_t         *thread_data = NULL; /* User data structs for each thread */
  903     OPA_int_t           shared_val;     /* Integer shared between threads */
  904     unsigned            nthreads = num_threads[curr_test];
  905     unsigned            i;
  906 
  907     /* Must use an odd number of threads */
  908     if(!(nthreads & 1))
  909         nthreads--;
  910 
  911     TESTING("incr and decr", nthreads);
  912 
  913     /* Allocate array of threads */
  914     if(NULL == (threads = (pthread_t *) malloc(nthreads * sizeof(pthread_t))))
  915         TEST_ERROR;
  916 
  917     /* Allocate array of thread data */
  918     if(NULL == (thread_data = (incr_decr_t *) calloc(nthreads, sizeof(incr_decr_t))))
  919         TEST_ERROR;
  920 
  921     /* Initialize thread data structs */
  922     OPA_store_int(&shared_val, 0);
  923     for(i=0; i<nthreads; i++)
  924         thread_data[i].shared_val = &shared_val;
  925     thread_data[nthreads-1].master_thread = 1;
  926 
  927     /* Set threads to be joinable */
  928     pthread_attr_init(&ptattr);
  929     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
  930 
  931     /* Set the initial state of the shared value (0) */
  932     OPA_store_int(&shared_val, 0);
  933 
  934     /* Create the threads.  All the unique values must add up to 0. */
  935     for(i=0; i<(nthreads - 1); i++) {
  936         if(i & 1) {
  937             if(pthread_create(&threads[i], &ptattr, threaded_decr_helper,
  938                     &thread_data[i])) TEST_ERROR;
  939         } else
  940             if(pthread_create(&threads[i], &ptattr, threaded_incr_helper,
  941                     &thread_data[i])) TEST_ERROR;
  942     } /* end for */
  943     if(i & 1)
  944         (void)threaded_decr_helper(&thread_data[i]);
  945     else
  946         (void)threaded_incr_helper(&thread_data[i]);
  947 
  948     /* Free the attribute */
  949     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
  950 
  951     /* Join the threads */
  952     for (i=0; i<(nthreads - 1); i++)
  953         if(pthread_join(threads[i], NULL)) TEST_ERROR;
  954 
  955     /* Verify that the shared value contains the expected result (0) */
  956     if(OPA_load_int(&shared_val) != INCR_DECR_EXPECTED)
  957         FAIL_OP_ERROR(printf("    Unexpected result: %d expected: %d\n",
  958                 OPA_load_int(&shared_val), INCR_DECR_EXPECTED));
  959 
  960     /* Free memory */
  961     free(threads);
  962     free(thread_data);
  963 
  964     PASSED();
  965 
  966 #else /* OPA_HAVE_PTHREAD_H */
  967     TESTING("incr and decr", 0);
  968     SKIPPED();
  969     puts("    pthread.h not available");
  970 #endif /* OPA_HAVE_PTHREAD_H */
  971 
  972     return 0;
  973 
  974 #if defined(OPA_HAVE_PTHREAD_H)
  975 error:
  976     if(threads) free(threads);
  977     if(thread_data) free(thread_data);
  978     return 1;
  979 #endif /* OPA_HAVE_PTHREAD_H */
  980 } /* end test_threaded_incr_decr() */
  981 
  982 
  983 /*-------------------------------------------------------------------------
  984  * Function: test_simple_decr_and_test
  985  *
  986  * Purpose: Tests basic functionality of OPA_decr_and_test_int with a
  987  *          single thread.  Does not test atomicity of operations.
  988  *
  989  * Return: Success: 0
  990  *         Failure: 1
  991  *
  992  * Programmer: Neil Fortner
  993  *             Wednesday, April 22, 2009
  994  *
  995  * Modifications:
  996  *
  997  *-------------------------------------------------------------------------
  998  */
  999 static int test_simple_decr_and_test(void)
 1000 {
 1001     OPA_int_t   a;
 1002     int         i;
 1003 
 1004     TESTING("simple decr and test functionality", 0);
 1005 
 1006     /* Store 10 in a */
 1007     OPA_store_int(&a, 10);
 1008 
 1009     for(i = 0; i<20; i++)
 1010         if(OPA_decr_and_test_int(&a))
 1011             if(i != 9) TEST_ERROR;
 1012 
 1013     if(OPA_load_int(&a) != -10) TEST_ERROR;
 1014 
 1015     PASSED();
 1016     return 0;
 1017 
 1018 error:
 1019     return 1;
 1020 } /* end test_simple_decr_and_test() */
 1021 
 1022 
 1023 #if defined(OPA_HAVE_PTHREAD_H)
 1024 /*-------------------------------------------------------------------------
 1025  * Function: threaded_decr_and_test_helper
 1026  *
 1027  * Purpose: Helper (thread) routine for test_threaded_decr_and_test
 1028  *
 1029  * Return: NULL
 1030  *
 1031  * Programmer: Neil Fortner
 1032  *             Wednesday, April 22, 2009
 1033  *
 1034  * Modifications:
 1035  *
 1036  *-------------------------------------------------------------------------
 1037  */
 1038 static void *threaded_decr_and_test_helper(void *_udata)
 1039 {
 1040     decr_test_t         *udata = (decr_test_t *)_udata;
 1041     unsigned            i;
 1042 
 1043     /* Main loop */
 1044     for(i=0; i<DECR_AND_TEST_NITER_INNER; i++)
 1045         /* Add the unique value to the shared value */
 1046         if(OPA_decr_and_test_int(udata->shared_val))
 1047             udata->ntrue++;
 1048 
 1049     /* Exit */
 1050     if(udata->master_thread)
 1051         return(NULL);
 1052     else
 1053         pthread_exit(NULL);
 1054 } /* end threaded_decr_and_test_helper() */
 1055 #endif /* OPA_HAVE_PTHREAD_H */
 1056 
 1057 
 1058 /*-------------------------------------------------------------------------
 1059  * Function: test_threaded_decr_and_test
 1060  *
 1061  * Purpose: Tests atomicity of OPA_decr_and_test_int.  Launches nthreads
 1062  *          threads, each of which repeatedly adds a unique number to a
 1063  *          shared variable.
 1064  *
 1065  * Return: Success: 0
 1066  *         Failure: 1
 1067  *
 1068  * Programmer: Neil Fortner
 1069  *             Tuesday, April 21, 2009
 1070  *
 1071  * Modifications:
 1072  *
 1073  *-------------------------------------------------------------------------
 1074  */
 1075 static int test_threaded_decr_and_test(void)
 1076 {
 1077 #if defined(OPA_HAVE_PTHREAD_H)
 1078     pthread_t           *threads = NULL; /* Threads */
 1079     pthread_attr_t      ptattr;         /* Thread attributes */
 1080     decr_test_t         *thread_data = NULL; /* User data structs for each thread */
 1081     OPA_int_t           shared_val;     /* Integer shared between threads */
 1082     unsigned            ntrue_total;
 1083     int                 starting_val;
 1084     unsigned            niter = DECR_AND_TEST_NITER_OUTER;
 1085     unsigned            nthreads = num_threads[curr_test];
 1086     unsigned            nerrors = 0;
 1087     unsigned            i, j;
 1088 
 1089     TESTING("decr and test", nthreads);
 1090 
 1091     /* Allocate array of threads */
 1092     if(NULL == (threads = (pthread_t *) malloc((nthreads - 1) * sizeof(pthread_t))))
 1093         TEST_ERROR;
 1094 
 1095     /* Allocate array of thread data */
 1096     if(NULL == (thread_data = (decr_test_t *) calloc(nthreads, sizeof(decr_test_t))))
 1097         TEST_ERROR;
 1098 
 1099     /* Initialize the "shared_val" and "master thread" fields (ntrue will be
 1100      * initialized in the loop) */
 1101     for(i=0; i<nthreads; i++)
 1102         thread_data[i].shared_val = &shared_val;
 1103     thread_data[nthreads-1].master_thread = 1;
 1104 
 1105     /* Calculate the starting value for the shared int */
 1106     starting_val = DECR_AND_TEST_NITER_INNER * nthreads / 2;
 1107 
 1108     /* Set threads to be joinable */
 1109     pthread_attr_init(&ptattr);
 1110     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
 1111 
 1112     /* Outer loop (perform the threaded test multiple times */
 1113     for(i=0; i<niter; i++) {
 1114         /* Initialize thread data structs */
 1115         OPA_store_int(&shared_val, starting_val);
 1116         for(j=0; j<nthreads; j++)
 1117             thread_data[j].ntrue = 0;
 1118 
 1119         /* Create the threads */
 1120         for(j=0; j<(nthreads - 1); j++)
 1121             if(pthread_create(&threads[j], &ptattr, threaded_decr_and_test_helper,
 1122                     &thread_data[j])) TEST_ERROR;
 1123         (void)threaded_decr_and_test_helper(&thread_data[j]);
 1124 
 1125         /* Join the threads */
 1126         for (j=0; j<(nthreads - 1); j++)
 1127             if(pthread_join(threads[j], NULL)) TEST_ERROR;
 1128 
 1129         /* Verify the results */
 1130         ntrue_total = 0;
 1131         for (j=0; j<nthreads; j++) {
 1132             /* Verify that OPA_decr_and_test_int returned true at most once */
 1133             if(thread_data[j].ntrue > 1) {
 1134                 printf("\n    Unexpected return from thread %u: OPA_decr_and_test_int returned true %u times",
 1135                         j, thread_data[j].ntrue);
 1136                 nerrors++;
 1137             } /* end if */
 1138 
 1139             /* Update ntrue_total */
 1140             ntrue_total += thread_data[j].ntrue;
 1141         } /* end for */
 1142 
 1143         /* Verify that OPA_decr_and_test_int returned true exactly once over all
 1144          * the threads. */
 1145         if(ntrue_total != 1) {
 1146             printf("\n    Unexpected result: OPA_decr_and_test_int returned true %u times total",
 1147                     ntrue_total);
 1148             nerrors++;
 1149         } /* end if */
 1150 
 1151         /* Verify that the shared value contains the expected result */
 1152         if(OPA_load_int(&shared_val) != -starting_val) {
 1153             printf("\n    Unexpected result: %d expected: %d",
 1154                     OPA_load_int(&shared_val), -starting_val);
 1155             nerrors++;
 1156         } /* end if */
 1157     } /* end for */
 1158 
 1159     /* Free the attribute */
 1160     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
 1161 
 1162     if(nerrors) {
 1163         puts("");
 1164         TEST_ERROR;
 1165     } /* end if */
 1166 
 1167     /* Free memory */
 1168     free(threads);
 1169     free(thread_data);
 1170 
 1171     PASSED();
 1172 
 1173 #else /* OPA_HAVE_PTHREAD_H */
 1174     TESTING("decr and test", 0);
 1175     SKIPPED();
 1176     puts("    pthread.h not available");
 1177 #endif /* OPA_HAVE_PTHREAD_H */
 1178 
 1179     return 0;
 1180 
 1181 #if defined(OPA_HAVE_PTHREAD_H)
 1182 error:
 1183     if(threads) free(threads);
 1184     if(thread_data) free(thread_data);
 1185     return 1;
 1186 #endif /* OPA_HAVE_PTHREAD_H */
 1187 } /* end test_threaded_decr_and_test() */
 1188 
 1189 
 1190 /*-------------------------------------------------------------------------
 1191  * Function: test_simple_faa_fai_fad
 1192  *
 1193  * Purpose: Tests basic functionality of OPA_fetch_and_add_int,
 1194  *          OPA_fetch_and_incr_int and OPA_fetch_and_decr_int with a 
 1195  *          single thread.  Does not test atomicity of operations.
 1196  *
 1197  * Return: Success: 0
 1198  *         Failure: 1
 1199  *
 1200  * Programmer: Neil Fortner
 1201  *             Thursday, April 23, 2009
 1202  *
 1203  * Modifications:
 1204  *
 1205  *-------------------------------------------------------------------------
 1206  */
 1207 static int test_simple_faa_fai_fad(void)
 1208 {
 1209     OPA_int_t   a;
 1210     int         result, expected;
 1211 
 1212     TESTING("simple fetch and add/incr/decr functionality", 0);
 1213 
 1214     /* Store 0 in a */
 1215     OPA_store_int(&a, 0);
 1216     expected = 0;
 1217 
 1218     /* Add INT_MIN */
 1219     result = OPA_fetch_and_add_int(&a, INT_MIN);
 1220     if(result != expected) TEST_ERROR;
 1221     expected += INT_MIN;
 1222 
 1223     /* Increment */
 1224     result = OPA_fetch_and_incr_int(&a);
 1225     if(result != expected) TEST_ERROR;
 1226     expected++;
 1227 
 1228     /* Add INT_MAX */
 1229     result = OPA_fetch_and_add_int(&a, INT_MAX);
 1230     if(result != expected) TEST_ERROR;
 1231     expected += INT_MAX;
 1232 
 1233     /* Decrement */
 1234     result = OPA_fetch_and_decr_int(&a);
 1235     if(result != expected) TEST_ERROR;
 1236     expected--;
 1237 
 1238     /* Load the result, verify it is correct */
 1239     if(OPA_load_int(&a) != INT_MIN + 1 + INT_MAX - 1) TEST_ERROR;
 1240 
 1241     /* Store 0 in a */
 1242     OPA_store_int(&a, 0);
 1243     expected = 0;
 1244 
 1245     /* Add INT_MAX */
 1246     result = OPA_fetch_and_add_int(&a, INT_MAX);
 1247     if(result != expected) TEST_ERROR;
 1248     expected += INT_MAX;
 1249 
 1250     /* Decrement */
 1251     result = OPA_fetch_and_decr_int(&a);
 1252     if(result != expected) TEST_ERROR;
 1253     expected--;
 1254 
 1255     /* Add INT_MIN */
 1256     result = OPA_fetch_and_add_int(&a, INT_MIN);
 1257     if(result != expected) TEST_ERROR;
 1258     expected += INT_MIN;
 1259 
 1260     /* Increment */
 1261     result = OPA_fetch_and_incr_int(&a);
 1262     if(result != expected) TEST_ERROR;
 1263     expected++;
 1264 
 1265     /* Load the result, verify it is correct */
 1266     if(OPA_load_int(&a) != INT_MAX - 1 + INT_MIN + 1) TEST_ERROR;
 1267 
 1268     PASSED();
 1269     return 0;
 1270 
 1271 error:
 1272     return 1;
 1273 } /* end test_simple_faa_fai_fad() */
 1274 
 1275 
 1276 #if defined(OPA_HAVE_PTHREAD_H)
 1277 /*-------------------------------------------------------------------------
 1278  * Function: threaded_faa_helper
 1279  *
 1280  * Purpose: Helper (thread) routine for test_threaded_faa
 1281  *
 1282  * Return: NULL
 1283  *
 1284  * Programmer: Neil Fortner
 1285  *             Thursday, April 23, 2009
 1286  *
 1287  * Modifications:
 1288  *
 1289  *-------------------------------------------------------------------------
 1290  */
 1291 static void *threaded_faa_helper(void *_udata)
 1292 {
 1293     add_t               *udata = (add_t *)_udata;
 1294     unsigned            niter = ADD_NITER;
 1295     unsigned            i;
 1296 
 1297     /* Main loop */
 1298     for(i=0; i<niter; i++)
 1299         /* Add the unique value to the shared value */
 1300         (void) OPA_fetch_and_add_int(udata->shared_val, udata->unique_val);
 1301 
 1302     /* Exit */
 1303     if(udata->master_thread)
 1304         return(NULL);
 1305     else
 1306         pthread_exit(NULL);
 1307 } /* end threaded_add_helper() */
 1308 #endif /* OPA_HAVE_PTHREAD_H */
 1309 
 1310 
 1311 /*-------------------------------------------------------------------------
 1312  * Function: test_threaded_faa
 1313  *
 1314  * Purpose: Tests atomicity of OPA_fetch_and_add_int.  Launches nthreads
 1315  *          threads, each of which repeatedly adds a unique number to a
 1316  *          shared variable.  Does not test return value of
 1317  *          OPA_fetch_and_add_int.  This is basically a copy of
 1318  *          test_threaded_add.
 1319  *
 1320  * Return: Success: 0
 1321  *         Failure: 1
 1322  *
 1323  * Programmer: Neil Fortner
 1324  *             Thursday, April 23, 2009
 1325  *
 1326  * Modifications:
 1327  *
 1328  *-------------------------------------------------------------------------
 1329  */
 1330 static int test_threaded_faa(void)
 1331 {
 1332 #if defined(OPA_HAVE_PTHREAD_H)
 1333     pthread_t           *threads = NULL; /* Threads */
 1334     pthread_attr_t      ptattr;         /* Thread attributes */
 1335     add_t               *thread_data = NULL; /* User data structs for each thread */
 1336     OPA_int_t           shared_val;     /* Integer shared between threads */
 1337     unsigned            nthreads = num_threads[curr_test];
 1338     unsigned            i;
 1339 
 1340     TESTING("fetch and add", nthreads);
 1341 
 1342     /* Allocate array of threads */
 1343     if(NULL == (threads = (pthread_t *) malloc((nthreads - 1) * sizeof(pthread_t))))
 1344         TEST_ERROR;
 1345 
 1346     /* Allocate array of thread data */
 1347     if(NULL == (thread_data = (add_t *) calloc(nthreads, sizeof(add_t))))
 1348         TEST_ERROR;
 1349 
 1350     /* Initialize thread data structs.  All the unique values must add up to
 1351      * 0. */
 1352     OPA_store_int(&shared_val, 0);
 1353     for(i=0; i<nthreads; i++) {
 1354         thread_data[i].shared_val = &shared_val;
 1355         thread_data[i].unique_val = i - (nthreads - 1) / 2
 1356                 - (!(nthreads % 2) && (i >= nthreads / 2))
 1357                 + (i == nthreads - 1);
 1358     } /* end for */
 1359     thread_data[nthreads-1].master_thread = 1;
 1360 
 1361     /* Set threads to be joinable */
 1362     pthread_attr_init(&ptattr);
 1363     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
 1364 
 1365     /* Create the threads */
 1366     for(i=0; i<(nthreads - 1); i++)
 1367         if(pthread_create(&threads[i], &ptattr, threaded_faa_helper,
 1368                 &thread_data[i])) TEST_ERROR;
 1369     (void)threaded_faa_helper(&thread_data[i]);
 1370 
 1371     /* Free the attribute */
 1372     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
 1373 
 1374     /* Join the threads */
 1375     for (i=0; i<(nthreads - 1); i++)
 1376         if(pthread_join(threads[i], NULL)) TEST_ERROR;
 1377 
 1378     /* Verify that the shared value contains the expected result (0) */
 1379     if(OPA_load_int(&shared_val) != ADD_EXPECTED)
 1380         FAIL_OP_ERROR(printf("    Unexpected result: %d expected: %d\n",
 1381                 OPA_load_int(&shared_val), ADD_EXPECTED));
 1382 
 1383     /* Free memory */
 1384     free(threads);
 1385     free(thread_data);
 1386 
 1387     PASSED();
 1388 
 1389 #else /* OPA_HAVE_PTHREAD_H */
 1390     TESTING("fetch and add", 0);
 1391     SKIPPED();
 1392     puts("    pthread.h not available");
 1393 #endif /* OPA_HAVE_PTHREAD_H */
 1394 
 1395     return 0;
 1396 
 1397 #if defined(OPA_HAVE_PTHREAD_H)
 1398 error:
 1399     if(threads) free(threads);
 1400     if(thread_data) free(thread_data);
 1401     return 1;
 1402 #endif /* OPA_HAVE_PTHREAD_H */
 1403 } /* end test_threaded_faa() */
 1404 
 1405 
 1406 #if defined(OPA_HAVE_PTHREAD_H)
 1407 /*-------------------------------------------------------------------------
 1408  * Function: threaded_faa_ret_helper
 1409  *
 1410  * Purpose: Helper (thread) routine for test_threaded_faa_ret
 1411  *
 1412  * Return: NULL
 1413  *
 1414  * Programmer: Neil Fortner
 1415  *             Thursday, April 23, 2009
 1416  *
 1417  * Modifications:
 1418  *
 1419  *-------------------------------------------------------------------------
 1420  */
 1421 static void *threaded_faa_ret_helper(void *_udata)
 1422 {
 1423     faa_ret_t           *udata = (faa_ret_t *)_udata;
 1424     int                 ret, prev = INT_MAX;
 1425     unsigned            niter = FAA_RET_NITER;
 1426     unsigned            i;
 1427 
 1428     /* Main loop */
 1429     for(i=0; i<niter; i++) {
 1430         /* Add -1 to the shared value */
 1431         ret = OPA_fetch_and_add_int(udata->shared_val, -1);
 1432 
 1433         /* Verify that the value returned is less than the previous return */
 1434         if(ret >= prev) {
 1435             printf("\n    Unexpected return: %d is not less than %d  ", ret, prev);
 1436             (udata->nerrors)++;
 1437         } /* end if */
 1438 
 1439         /* Check if the return value is 1 */
 1440         if(ret == 1)
 1441             (udata->n1)++;
 1442 
 1443         /* update prev */
 1444         prev = ret;
 1445     } /* end for */
 1446 
 1447     /* Exit */
 1448     if(udata->master_thread)
 1449         return(NULL);
 1450     else
 1451         pthread_exit(NULL);
 1452 } /* end threaded_faa_ret_helper() */
 1453 #endif /* OPA_HAVE_PTHREAD_H */
 1454 
 1455 
 1456 /*-------------------------------------------------------------------------
 1457  * Function: test_threaded_faa_ret
 1458  *
 1459  * Purpose: Tests atomicity of OPA_fetch_and_add_int.  Launches nthreads
 1460  *          threads, each of which repeatedly adds -1 to a shared
 1461  *          variable.  Verifies that the value returned is always
 1462  *          decreasing, and that it returns 1 exactly once.
 1463  *
 1464  * Return: Success: 0
 1465  *         Failure: 1
 1466  *
 1467  * Programmer: Neil Fortner
 1468  *             Thursday, April 23, 2009
 1469  *
 1470  * Modifications:
 1471  *
 1472  *-------------------------------------------------------------------------
 1473  */
 1474 static int test_threaded_faa_ret(void)
 1475 {
 1476 #if defined(OPA_HAVE_PTHREAD_H)
 1477     pthread_t           *threads = NULL; /* Threads */
 1478     pthread_attr_t      ptattr;         /* Thread attributes */
 1479     faa_ret_t           *thread_data = NULL; /* User data structs for threads */
 1480     OPA_int_t           shared_val;     /* Integer shared between threads */
 1481     int                 nerrors = 0;    /* Number of errors */
 1482     int                 n1 = 0;         /* # of times faa returned 1 */
 1483     unsigned            nthreads = num_threads[curr_test];
 1484     unsigned            i;
 1485 
 1486     TESTING("fetch and add return values", nthreads);
 1487 
 1488     /* Allocate array of threads */
 1489     if(NULL == (threads = (pthread_t *) malloc((nthreads - 1) * sizeof(pthread_t))))
 1490         TEST_ERROR;
 1491 
 1492     /* Allocate array of thread data */
 1493     if(NULL == (thread_data = (faa_ret_t *) calloc(nthreads, sizeof(faa_ret_t))))
 1494         TEST_ERROR;
 1495 
 1496     /* Initialize thread data structs */
 1497     OPA_store_int(&shared_val, FAA_RET_NITER);
 1498     for(i=0; i<nthreads; i++)
 1499         thread_data[i].shared_val = &shared_val;
 1500     thread_data[nthreads-1].master_thread = 1;
 1501 
 1502     /* Set threads to be joinable */
 1503     pthread_attr_init(&ptattr);
 1504     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
 1505 
 1506     /* Create the threads */
 1507     for(i=0; i<(nthreads - 1); i++)
 1508         if(pthread_create(&threads[i], &ptattr, threaded_faa_ret_helper,
 1509                 &thread_data[i])) TEST_ERROR;
 1510     (void)threaded_faa_ret_helper(&thread_data[i]);
 1511 
 1512     /* Free the attribute */
 1513     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
 1514 
 1515     /* Join the threads */
 1516     for (i=0; i<(nthreads - 1); i++)
 1517         if(pthread_join(threads[i], NULL)) TEST_ERROR;
 1518 
 1519     /* Count number of errors and number of times 1 was returned */
 1520     for(i=0; i<nthreads; i++) {
 1521         nerrors += thread_data[i].nerrors;
 1522         n1 += thread_data[i].n1;
 1523     } /* end for */
 1524 
 1525     /* Verify that no errors were reported */
 1526     if(nerrors)
 1527         FAIL_OP_ERROR(printf("    %d unexpected return%s from OPA_fetch_and_add_int\n",
 1528                 nerrors, nerrors == 1 ? "" : "s"));
 1529 
 1530     /* Verify that OPA_fetch_and_add_int returned 1 expactly once */
 1531     if(n1 != 1)
 1532         FAIL_OP_ERROR(printf("    OPA_fetch_and_add_int returned 1 %d times.  Expected: 1\n",
 1533                 n1));
 1534 
 1535     /* Verify that the shared value contains the expected result (0) */
 1536     if(OPA_load_int(&shared_val) != FAA_RET_EXPECTED)
 1537         FAIL_OP_ERROR(printf("    Unexpected result: %d expected: %d\n",
 1538                 OPA_load_int(&shared_val), FAA_RET_EXPECTED));
 1539 
 1540     /* Free memory */
 1541     free(threads);
 1542     free(thread_data);
 1543 
 1544     PASSED();
 1545 
 1546 #else /* OPA_HAVE_PTHREAD_H */
 1547     TESTING("fetch and add return values", 0);
 1548     SKIPPED();
 1549     puts("    pthread.h not available");
 1550 #endif /* OPA_HAVE_PTHREAD_H */
 1551 
 1552     return 0;
 1553 
 1554 #if defined(OPA_HAVE_PTHREAD_H)
 1555 error:
 1556     if(threads) free(threads);
 1557     if(thread_data) free(thread_data);
 1558     return 1;
 1559 #endif /* OPA_HAVE_PTHREAD_H */
 1560 } /* end test_threaded_faa_ret() */
 1561 
 1562 
 1563 #if defined(OPA_HAVE_PTHREAD_H)
 1564 /*-------------------------------------------------------------------------
 1565  * Function: threaded_fai_helper
 1566  *
 1567  * Purpose: Helper (thread) routine for test_threaded_fai_fad
 1568  *
 1569  * Return: NULL
 1570  *
 1571  * Programmer: Neil Fortner
 1572  *             Friday, May 8, 2009
 1573  *
 1574  * Modifications:
 1575  *
 1576  *-------------------------------------------------------------------------
 1577  */
 1578 static void *threaded_fai_helper(void *_shared_val)
 1579 {
 1580     OPA_int_t           *shared_val = (OPA_int_t *)_shared_val;
 1581     unsigned            niter = INCR_DECR_NITER;
 1582     unsigned            i;
 1583 
 1584     /* Main loop */
 1585     for(i=0; i<niter; i++)
 1586         /* Add the unique value to the shared value */
 1587         (void) OPA_fetch_and_incr_int(shared_val);
 1588 
 1589     /* Exit */
 1590     pthread_exit(NULL);
 1591 } /* end threaded_fai_helper() */
 1592 
 1593 
 1594 /*-------------------------------------------------------------------------
 1595  * Function: threaded_fad_helper
 1596  *
 1597  * Purpose: Helper (thread) routine for test_threaded_fai_fad
 1598  *
 1599  * Return: NULL
 1600  *
 1601  * Programmer: Neil Fortner
 1602  *             Friday, May 8, 2009
 1603  *
 1604  * Modifications:
 1605  *
 1606  *-------------------------------------------------------------------------
 1607  */
 1608 static void *threaded_fad_helper(void *_shared_val)
 1609 {
 1610     OPA_int_t           *shared_val = (OPA_int_t *)_shared_val;
 1611     unsigned            niter = INCR_DECR_NITER;
 1612     unsigned            i;
 1613 
 1614     /* Main loop */
 1615     for(i=0; i<niter; i++)
 1616         /* Add the unique value to the shared value */
 1617         (void) OPA_fetch_and_decr_int(shared_val);
 1618 
 1619     /* Exit */
 1620     pthread_exit(NULL);
 1621 } /* end threaded_fad_helper() */
 1622 #endif /* OPA_HAVE_PTHREAD_H */
 1623 
 1624 
 1625 /*-------------------------------------------------------------------------
 1626  * Function: test_threaded_fai_fad
 1627  *
 1628  * Purpose: Tests atomicity of OPA_fetch_and_incr_int and
 1629  *          OPA_fetch_and_decr_int.  Launches nthreads threads, each of
 1630  *          which repeatedly either increments or decrements a shared
 1631  *          variable.  Does not test return values.
 1632  *
 1633  * Return: Success: 0
 1634  *         Failure: 1
 1635  *
 1636  * Programmer: Neil Fortner
 1637  *             Friday, May 8, 2009
 1638  *
 1639  * Modifications:
 1640  *
 1641  *-------------------------------------------------------------------------
 1642  */
 1643 static int test_threaded_fai_fad(void)
 1644 {
 1645 #if defined(OPA_HAVE_PTHREAD_H)
 1646     pthread_t           *threads = NULL; /* Threads */
 1647     pthread_attr_t      ptattr;         /* Thread attributes */
 1648     OPA_int_t           shared_val;     /* Integer shared between threads */
 1649     unsigned            nthreads = num_threads[curr_test];
 1650     unsigned            i;
 1651 
 1652     /* Must use an odd number of threads */
 1653     if(!(nthreads & 1))
 1654         nthreads--;
 1655 
 1656     TESTING("fetch and incr/decr", nthreads);
 1657 
 1658     /* Allocate array of threads */
 1659     if(NULL == (threads = (pthread_t *) malloc(nthreads * sizeof(pthread_t))))
 1660         TEST_ERROR;
 1661 
 1662     /* Set threads to be joinable */
 1663     pthread_attr_init(&ptattr);
 1664     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
 1665 
 1666     /* Set the initial state of the shared value (0) */
 1667     OPA_store_int(&shared_val, 0);
 1668 
 1669     /* Create the threads.  All the unique values must add up to 0. */
 1670     for(i=0; i<nthreads; i++) {
 1671         if(i & 1) {
 1672             if(pthread_create(&threads[i], &ptattr, threaded_fad_helper,
 1673                     (void *)&shared_val)) TEST_ERROR;
 1674         } else
 1675             if(pthread_create(&threads[i], &ptattr, threaded_fai_helper,
 1676                     (void *)&shared_val)) TEST_ERROR;
 1677     } /* end for */
 1678 
 1679     /* Free the attribute */
 1680     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
 1681 
 1682     /* Join the threads */
 1683     for (i=0; i<nthreads; i++)
 1684         if(pthread_join(threads[i], NULL)) TEST_ERROR;
 1685 
 1686     /* Verify that the shared value contains the expected result (0) */
 1687     if(OPA_load_int(&shared_val) != INCR_DECR_EXPECTED)
 1688         FAIL_OP_ERROR(printf("    Unexpected result: %d expected: %d\n",
 1689                 OPA_load_int(&shared_val), INCR_DECR_EXPECTED));
 1690 
 1691     /* Free memory */
 1692     free(threads);
 1693 
 1694     PASSED();
 1695 
 1696 #else /* OPA_HAVE_PTHREAD_H */
 1697     TESTING("fetch and incr/decr", 0);
 1698     SKIPPED();
 1699     puts("    pthread.h not available");
 1700 #endif /* OPA_HAVE_PTHREAD_H */
 1701 
 1702     return 0;
 1703 
 1704 #if defined(OPA_HAVE_PTHREAD_H)
 1705 error:
 1706     if(threads) free(threads);
 1707     return 1;
 1708 #endif /* OPA_HAVE_PTHREAD_H */
 1709 } /* end test_threaded_fai_fad() */
 1710 
 1711 
 1712 #if defined(OPA_HAVE_PTHREAD_H)
 1713 /*-------------------------------------------------------------------------
 1714  * Function: threaded_fai_ret_helper
 1715  *
 1716  * Purpose: Helper (thread) routine for test_threaded_fai_ret
 1717  *
 1718  * Return: NULL
 1719  *
 1720  * Programmer: Neil Fortner
 1721  *             Friday, June 5, 2009
 1722  *
 1723  * Modifications:
 1724  *
 1725  *-------------------------------------------------------------------------
 1726  */
 1727 static void *threaded_fai_ret_helper(void *_udata)
 1728 {
 1729     fai_ret_t           *udata = (fai_ret_t *)_udata;
 1730     int                 ret, prev = INT_MIN;
 1731     unsigned            niter = FAI_RET_NITER;
 1732     unsigned            i;
 1733 
 1734     /* Main loop */
 1735     for(i=0; i<niter; i++) {
 1736         /* Add -1 to the shared value */
 1737         ret = OPA_fetch_and_incr_int(udata->shared_val);
 1738 
 1739         /* Verify that the value returned is greater than the previous return */
 1740         if(ret <= prev) {
 1741             printf("\n    Unexpected return: %d is not greater than %d  ", ret, prev);
 1742             (udata->nerrors)++;
 1743         } /* end if */
 1744 
 1745         /* Check if the return value is -1 */
 1746         if(ret == -1)
 1747             (udata->nm1)++;
 1748 
 1749         /* update prev */
 1750         prev = ret;
 1751     } /* end for */
 1752 
 1753     /* Exit */
 1754     if(udata->master_thread)
 1755         return(NULL);
 1756     else
 1757         pthread_exit(NULL);
 1758 } /* end threaded_fai_ret_helper() */
 1759 #endif /* OPA_HAVE_PTHREAD_H */
 1760 
 1761 
 1762 /*-------------------------------------------------------------------------
 1763  * Function: test_threaded_fai_ret
 1764  *
 1765  * Purpose: Tests atomicity of OPA_fetch_and_incr_int.  Launches nthreads
 1766  *          threads, each of which repeatedly adds -1 to a shared
 1767  *          variable.  Verifies that the value returned is always
 1768  *          decreasing, and that it returns 1 exactly once.
 1769  *
 1770  * Return: Success: 0
 1771  *         Failure: 1
 1772  *
 1773  * Programmer: Neil Fortner
 1774  *             Friday, June 5, 2009
 1775  *
 1776  * Modifications:
 1777  *
 1778  *-------------------------------------------------------------------------
 1779  */
 1780 static int test_threaded_fai_ret(void)
 1781 {
 1782 #if defined(OPA_HAVE_PTHREAD_H)
 1783     pthread_t           *threads = NULL; /* Threads */
 1784     pthread_attr_t      ptattr;         /* Thread attributes */
 1785     fai_ret_t           *thread_data = NULL; /* User data structs for threads */
 1786     OPA_int_t           shared_val;     /* Integer shared between threads */
 1787     int                 nerrors = 0;    /* Number of errors */
 1788     int                 n1 = 0;         /* # of times fai returned 1 */
 1789     unsigned            nthreads = num_threads[curr_test];
 1790     unsigned            i;
 1791 
 1792     TESTING("fetch and incr return values", nthreads);
 1793 
 1794     /* Allocate array of threads */
 1795     if(NULL == (threads = (pthread_t *) malloc((nthreads - 1) * sizeof(pthread_t))))
 1796         TEST_ERROR;
 1797 
 1798     /* Allocate array of thread data */
 1799     if(NULL == (thread_data = (fai_ret_t *) calloc(nthreads, sizeof(fai_ret_t))))
 1800         TEST_ERROR;
 1801 
 1802     /* Initialize thread data structs */
 1803     OPA_store_int(&shared_val, -FAI_RET_NITER);
 1804     for(i=0; i<nthreads; i++)
 1805         thread_data[i].shared_val = &shared_val;
 1806     thread_data[nthreads-1].master_thread = 1;
 1807 
 1808     /* Set threads to be joinable */
 1809     pthread_attr_init(&ptattr);
 1810     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
 1811 
 1812     /* Create the threads */
 1813     for(i=0; i<(nthreads - 1); i++)
 1814         if(pthread_create(&threads[i], &ptattr, threaded_fai_ret_helper,
 1815                 &thread_data[i])) TEST_ERROR;
 1816     (void)threaded_fai_ret_helper(&thread_data[i]);
 1817 
 1818     /* Free the attribute */
 1819     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
 1820 
 1821     /* Join the threads */
 1822     for (i=0; i<(nthreads - 1); i++)
 1823         if(pthread_join(threads[i], NULL)) TEST_ERROR;
 1824 
 1825     /* Count number of errors and number of times 1 was returned */
 1826     for(i=0; i<nthreads; i++) {
 1827         nerrors += thread_data[i].nerrors;
 1828         n1 += thread_data[i].nm1;
 1829     } /* end for */
 1830 
 1831     /* Verify that no errors were reported */
 1832     if(nerrors)
 1833         FAIL_OP_ERROR(printf("    %d unexpected return%s from OPA_fetch_and_incr_int\n",
 1834                 nerrors, nerrors == 1 ? "" : "s"));
 1835 
 1836     /* Verify that OPA_fetch_and_add_int returned 1 expactly once */
 1837     if(n1 != 1)
 1838         FAIL_OP_ERROR(printf("    OPA_fetch_and_add_int returned -1 %d times.  Expected: 1\n",
 1839                 n1));
 1840 
 1841     /* Verify that the shared value contains the expected result (0) */
 1842     if(OPA_load_int(&shared_val) != FAI_RET_EXPECTED)
 1843         FAIL_OP_ERROR(printf("    Unexpected result: %d expected: %d\n",
 1844                 OPA_load_int(&shared_val), FAI_RET_EXPECTED));
 1845 
 1846     /* Free memory */
 1847     free(threads);
 1848     free(thread_data);
 1849 
 1850     PASSED();
 1851 
 1852 #else /* OPA_HAVE_PTHREAD_H */
 1853     TESTING("fetch and incr return values", 0);
 1854     SKIPPED();
 1855     puts("    pthread.h not available");
 1856 #endif /* OPA_HAVE_PTHREAD_H */
 1857 
 1858     return 0;
 1859 
 1860 #if defined(OPA_HAVE_PTHREAD_H)
 1861 error:
 1862     if(threads) free(threads);
 1863     if(thread_data) free(thread_data);
 1864     return 1;
 1865 #endif /* OPA_HAVE_PTHREAD_H */
 1866 } /* end test_threaded_fai_ret() */
 1867 
 1868 
 1869 #if defined(OPA_HAVE_PTHREAD_H)
 1870 /*-------------------------------------------------------------------------
 1871  * Function: threaded_fad_ret_helper
 1872  *
 1873  * Purpose: Helper (thread) routine for test_threaded_fad_ret
 1874  *
 1875  * Return: NULL
 1876  *
 1877  * Programmer: Neil Fortner
 1878  *             Friday, June 5, 2009
 1879  *
 1880  * Modifications:
 1881  *
 1882  *-------------------------------------------------------------------------
 1883  */
 1884 static void *threaded_fad_ret_helper(void *_udata)
 1885 {
 1886     faa_ret_t           *udata = (faa_ret_t *)_udata;
 1887     int                 ret, prev = INT_MAX;
 1888     unsigned            niter = FAA_RET_NITER;
 1889     unsigned            i;
 1890 
 1891     /* Main loop */
 1892     for(i=0; i<niter; i++) {
 1893         /* Add -1 to the shared value */
 1894         ret = OPA_fetch_and_decr_int(udata->shared_val);
 1895 
 1896         /* Verify that the value returned is less than the previous return */
 1897         if(ret >= prev) {
 1898             printf("\n    Unexpected return: %d is not less than %d  ", ret, prev);
 1899             (udata->nerrors)++;
 1900         } /* end if */
 1901 
 1902         /* Check if the return value is 1 */
 1903         if(ret == 1)
 1904             (udata->n1)++;
 1905 
 1906         /* update prev */
 1907         prev = ret;
 1908     } /* end for */
 1909 
 1910     /* Exit */
 1911     if(udata->master_thread)
 1912         return(NULL);
 1913     else
 1914         pthread_exit(NULL);
 1915 } /* end threaded_fad_ret_helper() */
 1916 #endif /* OPA_HAVE_PTHREAD_H */
 1917 
 1918 
 1919 /*-------------------------------------------------------------------------
 1920  * Function: test_threaded_fad_ret
 1921  *
 1922  * Purpose: Tests atomicity of OPA_fetch_and_decr_int.  Launches nthreads
 1923  *          threads, each of which repeatedly adds -1 to a shared
 1924  *          variable.  Verifies that the value returned is always
 1925  *          decreasing, and that it returns 1 exactly once.
 1926  *
 1927  * Return: Success: 0
 1928  *         Failure: 1
 1929  *
 1930  * Programmer: Neil Fortner
 1931  *             Friday, June 5, 2009
 1932  *
 1933  * Modifications:
 1934  *
 1935  *-------------------------------------------------------------------------
 1936  */
 1937 static int test_threaded_fad_ret(void)
 1938 {
 1939 #if defined(OPA_HAVE_PTHREAD_H)
 1940     pthread_t           *threads = NULL; /* Threads */
 1941     pthread_attr_t      ptattr;         /* Thread attributes */
 1942     faa_ret_t           *thread_data = NULL; /* User data structs for threads */
 1943     OPA_int_t           shared_val;     /* Integer shared between threads */
 1944     int                 nerrors = 0;    /* Number of errors */
 1945     int                 n1 = 0;         /* # of times faa returned 1 */
 1946     unsigned            nthreads = num_threads[curr_test];
 1947     unsigned            i;
 1948 
 1949     TESTING("fetch and decr return values", nthreads);
 1950 
 1951     /* Allocate array of threads */
 1952     if(NULL == (threads = (pthread_t *) malloc((nthreads - 1) * sizeof(pthread_t))))
 1953         TEST_ERROR;
 1954 
 1955     /* Allocate array of thread data */
 1956     if(NULL == (thread_data = (faa_ret_t *) calloc(nthreads, sizeof(faa_ret_t))))
 1957         TEST_ERROR;
 1958 
 1959     /* Initialize thread data structs */
 1960     OPA_store_int(&shared_val, FAA_RET_NITER);
 1961     for(i=0; i<nthreads; i++)
 1962         thread_data[i].shared_val = &shared_val;
 1963     thread_data[nthreads-1].master_thread = 1;
 1964 
 1965 
 1966     /* Set threads to be joinable */
 1967     pthread_attr_init(&ptattr);
 1968     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
 1969 
 1970     /* Create the threads */
 1971     for(i=0; i<(nthreads - 1); i++)
 1972         if(pthread_create(&threads[i], &ptattr, threaded_fad_ret_helper,
 1973                 &thread_data[i])) TEST_ERROR;
 1974     (void)threaded_fad_ret_helper(&thread_data[i]);
 1975 
 1976     /* Free the attribute */
 1977     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
 1978 
 1979     /* Join the threads */
 1980     for (i=0; i<(nthreads - 1); i++)
 1981         if(pthread_join(threads[i], NULL)) TEST_ERROR;
 1982 
 1983     /* Count number of errors and number of times 1 was returned */
 1984     for(i=0; i<nthreads; i++) {
 1985         nerrors += thread_data[i].nerrors;
 1986         n1 += thread_data[i].n1;
 1987     } /* end for */
 1988 
 1989     /* Verify that no errors were reported */
 1990     if(nerrors)
 1991         FAIL_OP_ERROR(printf("    %d unexpected return%s from OPA_fetch_and_decr_int\n",
 1992                 nerrors, nerrors == 1 ? "" : "s"));
 1993 
 1994     /* Verify that OPA_fetch_and_add_int returned 1 expactly once */
 1995     if(n1 != 1)
 1996         FAIL_OP_ERROR(printf("    OPA_fetch_and_add_int returned 1 %d times.  Expected: 1\n",
 1997                 n1));
 1998 
 1999     /* Verify that the shared value contains the expected result (0) */
 2000     if(OPA_load_int(&shared_val) != FAA_RET_EXPECTED)
 2001         FAIL_OP_ERROR(printf("    Unexpected result: %d expected: %d\n",
 2002                 OPA_load_int(&shared_val), FAA_RET_EXPECTED));
 2003 
 2004     /* Free memory */
 2005     free(threads);
 2006     free(thread_data);
 2007 
 2008     PASSED();
 2009 
 2010 #else /* OPA_HAVE_PTHREAD_H */
 2011     TESTING("fetch and decr return values", 0);
 2012     SKIPPED();
 2013     puts("    pthread.h not available");
 2014 #endif /* OPA_HAVE_PTHREAD_H */
 2015 
 2016     return 0;
 2017 
 2018 #if defined(OPA_HAVE_PTHREAD_H)
 2019 error:
 2020     if(threads) free(threads);
 2021     if(thread_data) free(thread_data);
 2022     return 1;
 2023 #endif /* OPA_HAVE_PTHREAD_H */
 2024 } /* end test_threaded_fad_ret() */
 2025 
 2026 
 2027 /*-------------------------------------------------------------------------
 2028  * Function: test_simple_cas_int
 2029  *
 2030  * Purpose: Tests basic functionality of OPA_cas_int with a single thread.
 2031  *          Does not test atomicity of operations.
 2032  *
 2033  * Return: Success: 0
 2034  *         Failure: 1
 2035  *
 2036  * Programmer: Neil Fortner
 2037  *             Tuesday, June 9, 2009
 2038  *
 2039  * Modifications:
 2040  *
 2041  *-------------------------------------------------------------------------
 2042  */
 2043 static int test_simple_cas_int(void)
 2044 {
 2045     OPA_int_t   a;
 2046 
 2047     TESTING("simple integer compare-and-swap functionality", 0);
 2048 
 2049     /* Store 0 in a */
 2050     OPA_store_int(&a, 0);
 2051 
 2052     /* Compare and swap multiple times, verify return value and final result */
 2053     if(0 != OPA_cas_int(&a, 1, INT_MAX)) TEST_ERROR;
 2054     if(0 != OPA_cas_int(&a, 0, INT_MAX)) TEST_ERROR;
 2055     if(INT_MAX != OPA_cas_int(&a, INT_MAX, INT_MIN)) TEST_ERROR;
 2056     if(INT_MIN != OPA_cas_int(&a, INT_MAX, 1)) TEST_ERROR;
 2057     if(INT_MIN != OPA_cas_int(&a, INT_MIN, 1)) TEST_ERROR;
 2058     if(1 != OPA_load_int(&a)) TEST_ERROR;
 2059 
 2060     PASSED();
 2061     return 0;
 2062 
 2063 error:
 2064     return 1;
 2065 } /* end test_simple_cas_int() */
 2066 
 2067 
 2068 /*-------------------------------------------------------------------------
 2069  * Function: test_simple_cas_ptr
 2070  *
 2071  * Purpose: Tests basic functionality of OPA_cas_ptr with a single thread.
 2072  *          Does not test atomicity of operations.
 2073  *
 2074  * Return: Success: 0
 2075  *         Failure: 1
 2076  *
 2077  * Programmer: Neil Fortner
 2078  *             Tuesday, June 9, 2009
 2079  *
 2080  * Modifications:
 2081  *
 2082  *-------------------------------------------------------------------------
 2083  */
 2084 static int test_simple_cas_ptr(void)
 2085 {
 2086     OPA_ptr_t   a;
 2087     void        *ptr1 = malloc(1);      /* Pointers to assign to a */
 2088     void        *ptr2 = malloc(1);
 2089     void        *ptr3 = malloc(1);
 2090     void        *ptr4 = malloc(1);
 2091 
 2092     TESTING("simple pointer compare-and-swap functionality", 0);
 2093 
 2094     /* Store ptr1 in a */
 2095     OPA_store_ptr(&a, ptr1);
 2096 
 2097     /* Compare and swap multiple times, verify return value and final result */
 2098     if(ptr1 != OPA_cas_ptr(&a, ptr2, ptr3)) TEST_ERROR;
 2099     if(ptr1 != OPA_cas_ptr(&a, ptr1, ptr3)) TEST_ERROR;
 2100     if(ptr3 != OPA_cas_ptr(&a, ptr3, ptr4)) TEST_ERROR;
 2101     if(ptr4 != OPA_cas_ptr(&a, ptr3, ptr2)) TEST_ERROR;
 2102     if(ptr4 != OPA_cas_ptr(&a, ptr4, ptr2)) TEST_ERROR;
 2103     if(ptr2 != OPA_load_ptr(&a)) TEST_ERROR;
 2104 
 2105     if(ptr1) free(ptr1);
 2106     if(ptr2) free(ptr2);
 2107     if(ptr3) free(ptr3);
 2108     if(ptr4) free(ptr4);
 2109 
 2110     PASSED();
 2111     return 0;
 2112 
 2113 error:
 2114     if(ptr1) free(ptr1);
 2115     if(ptr2) free(ptr2);
 2116     if(ptr3) free(ptr3);
 2117     if(ptr4) free(ptr4);
 2118 
 2119     return 1;
 2120 } /* end test_simple_cas_ptr() */
 2121 
 2122 
 2123 #if defined(OPA_HAVE_PTHREAD_H)
 2124 /*-------------------------------------------------------------------------
 2125  * Function: threaded_cas_int_helper
 2126  *
 2127  * Purpose: Helper (thread) routine for test_threaded_cas_int
 2128  *
 2129  * Return: NULL
 2130  *
 2131  * Programmer: Neil Fortner
 2132  *             Tuesday, June 9, 2009
 2133  *
 2134  * Modifications:
 2135  *
 2136  *-------------------------------------------------------------------------
 2137  */
 2138 static void *threaded_cas_int_helper(void *_udata)
 2139 {
 2140     cas_int_t           *udata = (cas_int_t *)_udata;
 2141     int                 thread_id = udata->threadno;
 2142     int                 next_id = (thread_id + 1) % num_threads[curr_test];
 2143     unsigned            niter = CAS_INT_NITER;
 2144     unsigned            i;
 2145 
 2146     /* Main loop */
 2147     for(i=0; i<niter; i++)
 2148         if(OPA_cas_int(udata->shared_val, thread_id, next_id) == thread_id)
 2149             udata->nsuccess++;
 2150 
 2151     /* Exit */
 2152     if(udata->master_thread)
 2153         return(NULL);
 2154     else
 2155         pthread_exit(NULL);
 2156 } /* end threaded_cas_int_helper() */
 2157 #endif /* OPA_HAVE_PTHREAD_H */
 2158 
 2159 
 2160 /*-------------------------------------------------------------------------
 2161  * Function: test_threaded_cas_int
 2162  *
 2163  * Purpose: Tests atomicity of OPA_cas_int.  Launches nthreads threads,
 2164  *          each of which continually tries to compare-and-swap a shared
 2165  *          value with its thread id (oldv) and thread id + 1 % n (newv).
 2166  *
 2167  * Return: Success: 0
 2168  *         Failure: 1
 2169  *
 2170  * Programmer: Neil Fortner
 2171  *             Tuesday, June 9, 2009
 2172  *
 2173  * Modifications:
 2174  *
 2175  *-------------------------------------------------------------------------
 2176  */
 2177 static int test_threaded_cas_int(void)
 2178 {
 2179 #if defined(OPA_HAVE_PTHREAD_H)
 2180     pthread_t           *threads = NULL; /* Threads */
 2181     pthread_attr_t      ptattr;         /* Thread attributes */
 2182     cas_int_t           *thread_data = NULL; /* User data structs for threads */
 2183     OPA_int_t           shared_val;     /* Integer shared between threads */
 2184     unsigned            nthreads = num_threads[curr_test];
 2185     unsigned            i;
 2186 
 2187     TESTING("integer compare-and-swap", nthreads);
 2188 
 2189     /* Allocate array of threads */
 2190     if(NULL == (threads = (pthread_t *) malloc((nthreads - 1) * sizeof(pthread_t))))
 2191         TEST_ERROR;
 2192 
 2193     /* Allocate array of thread data */
 2194     if(NULL == (thread_data = (cas_int_t *) calloc(nthreads, sizeof(cas_int_t))))
 2195         TEST_ERROR;
 2196 
 2197     /* Initialize thread data structs */
 2198     OPA_store_int(&shared_val, 0);
 2199     for(i=0; i<nthreads; i++) {
 2200         thread_data[i].shared_val = &shared_val;
 2201         thread_data[i].threadno = i;
 2202     } /* end for */
 2203     thread_data[nthreads-1].master_thread = 1;
 2204 
 2205     /* Set threads to be joinable */
 2206     pthread_attr_init(&ptattr);
 2207     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
 2208 
 2209     /* Create the threads */
 2210     for(i=0; i<(nthreads - 1); i++)
 2211         if(pthread_create(&threads[i], &ptattr, threaded_cas_int_helper,
 2212                 &thread_data[i])) TEST_ERROR;
 2213     (void)threaded_cas_int_helper(&thread_data[i]);
 2214 
 2215     /* Free the attribute */
 2216     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
 2217 
 2218     /* Join the threads */
 2219     for (i=0; i<(nthreads - 1); i++)
 2220         if(pthread_join(threads[i], NULL)) TEST_ERROR;
 2221 
 2222     /* Verify that cas succeeded at least once */
 2223     if(thread_data[0].nsuccess == 0)
 2224         FAIL_OP_ERROR(printf("    Compare-and-swap never succeeded\n"));
 2225 
 2226     /* Verify that the number of successes does not increase with increasing
 2227      * thread number, and also that the shared value's final value is consistent
 2228      * with the numbers of successes */
 2229     if(nthreads > 1)
 2230         for(i=1; i<nthreads; i++) {
 2231             if(thread_data[i].nsuccess > thread_data[i-1].nsuccess)
 2232                 FAIL_OP_ERROR(printf("    Thread %d succeeded more times than thread %d\n",
 2233                         i, i-1));
 2234 
 2235             if((thread_data[i].nsuccess < thread_data[i-1].nsuccess)
 2236                     && (OPA_load_int(&shared_val) != i))
 2237                 FAIL_OP_ERROR(printf("    Number of successes is inconsistent\n"));
 2238         } /* end for */
 2239     if((thread_data[0].nsuccess == thread_data[nthreads-1].nsuccess)
 2240             && (OPA_load_int(&shared_val) != 0))
 2241         FAIL_OP_ERROR(printf("    Number of successes is inconsistent\n"));
 2242 
 2243     /* Verify that the number of successes for the first threads is equal to or
 2244      * one greater than the number of successes for the last thread.  Have
 2245      * already determined that it is not less in the previous test. */
 2246     if(thread_data[0].nsuccess > (thread_data[nthreads-1].nsuccess + 1))
 2247         FAIL_OP_ERROR(printf("    Thread 0 succeeded %d times more than thread %d\n",
 2248                 thread_data[0].nsuccess - thread_data[nthreads-1].nsuccess,
 2249                 nthreads - 1));
 2250 
 2251     /* Free memory */
 2252     free(threads);
 2253     free(thread_data);
 2254 
 2255     PASSED();
 2256 
 2257 #else /* OPA_HAVE_PTHREAD_H */
 2258     TESTING("integer compare-and-swap", 0);
 2259     SKIPPED();
 2260     puts("    pthread.h not available");
 2261 #endif /* OPA_HAVE_PTHREAD_H */
 2262 
 2263     return 0;
 2264 
 2265 #if defined(OPA_HAVE_PTHREAD_H)
 2266 error:
 2267     if(threads) free(threads);
 2268     if(thread_data) free(thread_data);
 2269     return 1;
 2270 #endif /* OPA_HAVE_PTHREAD_H */
 2271 } /* end test_threaded_cas_int() */
 2272 
 2273 
 2274 #if defined(OPA_HAVE_PTHREAD_H)
 2275 /*-------------------------------------------------------------------------
 2276  * Function: threaded_cas_ptr_helper
 2277  *
 2278  * Purpose: Helper (thread) routine for test_threaded_cas_ptr
 2279  *
 2280  * Return: NULL
 2281  *
 2282  * Programmer: Neil Fortner
 2283  *             Monday, August 3, 2009
 2284  *
 2285  * Modifications:
 2286  *
 2287  *-------------------------------------------------------------------------
 2288  */
 2289 static void *threaded_cas_ptr_helper(void *_udata)
 2290 {
 2291     cas_ptr_t           *udata = (cas_ptr_t *)_udata;
 2292     int                 *thread_id = udata->threadno;
 2293     int                 *next_id = thread_id + 1;
 2294     unsigned            niter = CAS_PTR_NITER;
 2295     unsigned            i;
 2296 
 2297     /* This is the equivalent of the "modulus" operation, but for pointers */
 2298     if(next_id > udata->max_threadno)
 2299         next_id = (int *) 0;
 2300 
 2301     /* Main loop */
 2302     for(i=0; i<niter; i++)
 2303         if(OPA_cas_ptr(udata->shared_val, (void *) thread_id, (void *) next_id) == (void *) thread_id)
 2304             udata->nsuccess++;
 2305 
 2306     /* Exit */
 2307     if(udata->master_thread)
 2308         return(NULL);
 2309     else
 2310         pthread_exit(NULL);
 2311 } /* end threaded_cas_ptr_helper() */
 2312 #endif /* OPA_HAVE_PTHREAD_H */
 2313 
 2314 
 2315 /*-------------------------------------------------------------------------
 2316  * Function: test_threaded_cas_ptr
 2317  *
 2318  * Purpose: Tests atomicity of OPA_cas_ptr.  Launches nthreads threads,
 2319  *          each of which continually tries to compare-and-swap a shared
 2320  *          value with its thread id (oldv) and thread id + 1 % n (newv).
 2321  *
 2322  * Return: Success: 0
 2323  *         Failure: 1
 2324  *
 2325  * Programmer: Neil Fortner
 2326  *             Monday, August 3, 2009
 2327  *
 2328  * Modifications:
 2329  *
 2330  *-------------------------------------------------------------------------
 2331  */
 2332 static int test_threaded_cas_ptr(void)
 2333 {
 2334 #if defined(OPA_HAVE_PTHREAD_H)
 2335     pthread_t           *threads = NULL; /* Threads */
 2336     pthread_attr_t      ptattr;         /* Thread attributes */
 2337     cas_ptr_t           *thread_data = NULL; /* User data structs for threads */
 2338     OPA_ptr_t           shared_val;     /* Integer shared between threads */
 2339     unsigned            nthreads = num_threads[curr_test];
 2340     unsigned            i;
 2341 
 2342     TESTING("pointer compare-and-swap", nthreads);
 2343 
 2344     /* Allocate array of threads */
 2345     if(NULL == (threads = (pthread_t *) malloc((nthreads - 1) * sizeof(pthread_t))))
 2346         TEST_ERROR;
 2347 
 2348     /* Allocate array of thread data */
 2349     if(NULL == (thread_data = (cas_ptr_t *) calloc(nthreads, sizeof(cas_ptr_t))))
 2350         TEST_ERROR;
 2351 
 2352     /* Initialize thread data structs */
 2353     OPA_store_ptr(&shared_val, (void *) 0);
 2354     thread_data[0].shared_val = &shared_val;
 2355     thread_data[0].threadno = (int *) 0;
 2356     for(i=1; i<nthreads; i++) {
 2357         thread_data[i].shared_val = &shared_val;
 2358         thread_data[i].threadno = (int *) 0 + i;
 2359     } /* end for */
 2360     thread_data[nthreads-1].master_thread = 1;
 2361     for(i=0; i<nthreads; i++)
 2362         thread_data[i].max_threadno = thread_data[nthreads-1].threadno;
 2363 
 2364     /* Set threads to be joinable */
 2365     pthread_attr_init(&ptattr);
 2366     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
 2367 
 2368     /* Create the threads */
 2369     for(i=0; i<(nthreads - 1); i++)
 2370         if(pthread_create(&threads[i], &ptattr, threaded_cas_ptr_helper,
 2371                 &thread_data[i])) TEST_ERROR;
 2372     (void)threaded_cas_ptr_helper(&thread_data[i]);
 2373 
 2374     /* Free the attribute */
 2375     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
 2376 
 2377     /* Join the threads */
 2378     for (i=0; i<(nthreads - 1); i++)
 2379         if(pthread_join(threads[i], NULL)) TEST_ERROR;
 2380 
 2381     /* Verify that cas succeeded at least once */
 2382     if(thread_data[0].nsuccess == 0)
 2383         FAIL_OP_ERROR(printf("    Compare-and-swap never succeeded\n"));
 2384 
 2385     /* Verify that the number of successes does not increase with increasing
 2386      * thread number, and also that the shared value's final value is consistent
 2387      * with the numbers of successes */
 2388     if(nthreads > 1)
 2389         for(i=1; i<nthreads; i++) {
 2390             if(thread_data[i].nsuccess > thread_data[i-1].nsuccess)
 2391                 FAIL_OP_ERROR(printf("    Thread %d succeeded more times than thread %d\n",
 2392                         i, i-1));
 2393 
 2394             if((thread_data[i].nsuccess < thread_data[i-1].nsuccess)
 2395                     && (OPA_load_ptr(&shared_val) != thread_data[i].threadno))
 2396                 FAIL_OP_ERROR(printf("    Number of successes is inconsistent\n"));
 2397         } /* end for */
 2398     if((thread_data[0].nsuccess == thread_data[nthreads-1].nsuccess)
 2399             && (OPA_load_ptr(&shared_val) != (void *) 0))
 2400         FAIL_OP_ERROR(printf("    Number of successes is inconsistent\n"));
 2401 
 2402     /* Verify that the number of successes for the first threads is equal to or
 2403      * one greater than the number of successes for the last thread.  Have
 2404      * already determined that it is not less in the previous test. */
 2405     if(thread_data[0].nsuccess > (thread_data[nthreads-1].nsuccess + 1))
 2406         FAIL_OP_ERROR(printf("    Thread 0 succeeded %d times more than thread %d\n",
 2407                 thread_data[0].nsuccess - thread_data[nthreads-1].nsuccess,
 2408                 nthreads - 1));
 2409 
 2410     /* Free memory */
 2411     free(threads);
 2412     free(thread_data);
 2413 
 2414     PASSED();
 2415 
 2416 #else /* OPA_HAVE_PTHREAD_H */
 2417     TESTING("pointer compare-and-swap", 0);
 2418     SKIPPED();
 2419     puts("    pthread.h not available");
 2420 #endif /* OPA_HAVE_PTHREAD_H */
 2421 
 2422     return 0;
 2423 
 2424 #if defined(OPA_HAVE_PTHREAD_H)
 2425 error:
 2426     if(threads) free(threads);
 2427     if(thread_data) free(thread_data);
 2428     return 1;
 2429 #endif /* OPA_HAVE_PTHREAD_H */
 2430 } /* end test_threaded_cas_ptr() */
 2431 
 2432 
 2433 #if defined(OPA_HAVE_PTHREAD_H)
 2434 /*-------------------------------------------------------------------------
 2435  * Function: grouped_cas_int_helper
 2436  *
 2437  * Purpose: Helper (thread) routine for test_grouped_cas_int
 2438  *
 2439  * Return: NULL
 2440  *
 2441  * Programmer: Neil Fortner
 2442  *             Tuesday, August 4, 2009
 2443  *
 2444  * Modifications:
 2445  *
 2446  *-------------------------------------------------------------------------
 2447  */
 2448 static void *grouped_cas_int_helper(void *_udata)
 2449 {
 2450     grouped_cas_int_t   *udata = (grouped_cas_int_t *)_udata;
 2451     int                 group_id = udata->groupno;
 2452     int                 next_id = (group_id + 1) % udata->ngroups;
 2453     unsigned            niter = GROUPED_CAS_INT_NITER;
 2454     unsigned            i;
 2455 
 2456     /* Main loop */
 2457     for(i=0; i<niter; i++)
 2458         if(OPA_cas_int(udata->shared_val, group_id, next_id) == group_id)
 2459             udata->nsuccess++;
 2460 
 2461     /* Exit */
 2462     if(udata->master_thread)
 2463         return(NULL);
 2464     else
 2465         pthread_exit(NULL);
 2466 } /* end grouped_cas_int_helper() */
 2467 #endif /* OPA_HAVE_PTHREAD_H */
 2468 
 2469 
 2470 /*-------------------------------------------------------------------------
 2471  * Function: test_grouped_cas_int
 2472  *
 2473  * Purpose: Tests atomicity of OPA_cas_int.  Launches nthreads threads,
 2474  *          subdivided into nthreads/4 or 2 groups, whichever is greater.
 2475  *          Each thread continually tries to compare-and-swap a shared
 2476  *          value with its group id (oldv) and group id + 1 % ngroups
 2477  *          (newv).
 2478  *
 2479  * Return: Success: 0
 2480  *         Failure: 1
 2481  *
 2482  * Programmer: Neil Fortner
 2483  *             Tuesday, August 4, 2009
 2484  *
 2485  * Modifications:
 2486  *
 2487  *-------------------------------------------------------------------------
 2488  */
 2489 static int test_grouped_cas_int(void)
 2490 {
 2491 #if defined(OPA_HAVE_PTHREAD_H)
 2492     pthread_t           *threads = NULL; /* Threads */
 2493     pthread_attr_t      ptattr;         /* Thread attributes */
 2494     grouped_cas_int_t   *thread_data = NULL; /* User data structs for threads */
 2495     OPA_int_t           shared_val;     /* Integer shared between threads */
 2496     int                 ngroups;        /* Number of groups of threads */
 2497     int                 threads_per_group; /* Threads per group */
 2498     int                 *group_success = NULL; /* Number of successes for each group */
 2499     unsigned            nthreads = num_threads[curr_test];
 2500     unsigned            i;
 2501 
 2502     TESTING("grouped integer compare-and-swap", nthreads);
 2503 
 2504     /* Allocate array of threads */
 2505     if(NULL == (threads = (pthread_t *) malloc((nthreads - 1) * sizeof(pthread_t))))
 2506         TEST_ERROR;
 2507 
 2508     /* Allocate array of thread data */
 2509     if(NULL == (thread_data =
 2510             (grouped_cas_int_t *) calloc(nthreads, sizeof(grouped_cas_int_t))))
 2511         TEST_ERROR;
 2512 
 2513     /* Calculate number of groups and threads per group */
 2514     if((nthreads / GROUPED_CAS_INT_TPG) >= 2)
 2515         threads_per_group = GROUPED_CAS_INT_TPG;
 2516     else
 2517         threads_per_group = (nthreads + 1) / 2;
 2518     ngroups = (nthreads + threads_per_group - 1) / threads_per_group;
 2519 
 2520     /* Initialize thread data structs */
 2521     OPA_store_int(&shared_val, 0);
 2522     for(i=0; i<nthreads; i++) {
 2523         thread_data[i].shared_val = &shared_val;
 2524         thread_data[i].groupno = i / threads_per_group;
 2525         thread_data[i].ngroups = ngroups;
 2526     } /* end for */
 2527     thread_data[nthreads-1].master_thread = 1;
 2528 
 2529     /* Set threads to be joinable */
 2530     pthread_attr_init(&ptattr);
 2531     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
 2532 
 2533     /* Create the threads */
 2534     for(i=0; i<(nthreads - 1); i++)
 2535         if(pthread_create(&threads[i], &ptattr, grouped_cas_int_helper,
 2536                 &thread_data[i])) TEST_ERROR;
 2537     (void)grouped_cas_int_helper(&thread_data[i]);
 2538 
 2539     /* Free the attribute */
 2540     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
 2541 
 2542     /* Join the threads */
 2543     for (i=0; i<(nthreads - 1); i++)
 2544         if(pthread_join(threads[i], NULL)) TEST_ERROR;
 2545 
 2546     /* Calculate the total number of successes for each group */
 2547     if(NULL == (group_success = (int *) calloc(ngroups, sizeof(int))))
 2548         TEST_ERROR;
 2549     for(i=0; i<nthreads; i++)
 2550         group_success[thread_data[i].groupno] += thread_data[i].nsuccess;
 2551 
 2552     /* Verify that cas succeeded at least once */
 2553     if(group_success[0] == 0)
 2554         FAIL_OP_ERROR(printf("    Compare-and-swap never succeeded\n"));
 2555 
 2556     /* Verify that the number of successes does not increase with increasing
 2557      * group number, and also that the shared value's final value is consistent
 2558      * with the numbers of successes */
 2559     if(nthreads > 1)
 2560         for(i=1; i<ngroups; i++) {
 2561             if(group_success[i] > group_success[i-1])
 2562                 FAIL_OP_ERROR(printf("    Group %d succeeded more times than group %d\n",
 2563                         i, i-1));
 2564 
 2565             if((group_success[i] < group_success[i-1])
 2566                     && (OPA_load_int(&shared_val) != i))
 2567                 FAIL_OP_ERROR(printf("    Number of successes is inconsistent\n"));
 2568         } /* end for */
 2569     if((group_success[0] == group_success[ngroups-1])
 2570             && (OPA_load_int(&shared_val) != 0))
 2571         FAIL_OP_ERROR(printf("    Number of successes is inconsistent\n"));
 2572 
 2573     /* Verify that the number of successes for the first threads is equal to or
 2574      * one greater than the number of successes for the last thread.  Have
 2575      * already determined that it is not less in the previous test. */
 2576     if(group_success[0] > (group_success[ngroups-1] + 1))
 2577         FAIL_OP_ERROR(printf("    Group 0 succeeded %d times more than group %d\n",
 2578                 thread_data[0].nsuccess - thread_data[nthreads-1].nsuccess,
 2579                 nthreads - 1));
 2580 
 2581     /* Free memory */
 2582     free(threads);
 2583     free(thread_data);
 2584     free(group_success);
 2585 
 2586     PASSED();
 2587 
 2588 #else /* OPA_HAVE_PTHREAD_H */
 2589     TESTING("grouped integer compare-and-swap", 0);
 2590     SKIPPED();
 2591     puts("    pthread.h not available");
 2592 #endif /* OPA_HAVE_PTHREAD_H */
 2593 
 2594     return 0;
 2595 
 2596 #if defined(OPA_HAVE_PTHREAD_H)
 2597 error:
 2598     if(threads) free(threads);
 2599     if(thread_data) free(thread_data);
 2600     if(group_success) free(group_success);
 2601     return 1;
 2602 #endif /* OPA_HAVE_PTHREAD_H */
 2603 } /* end test_grouped_cas_int() */
 2604 
 2605 
 2606 #if defined(OPA_HAVE_PTHREAD_H)
 2607 /*-------------------------------------------------------------------------
 2608  * Function: grouped_cas_ptr_helper
 2609  *
 2610  * Purpose: Helper (thread) routine for test_grouped_cas_ptr
 2611  *
 2612  * Return: NULL
 2613  *
 2614  * Programmer: Neil Fortner
 2615  *             Monday, August 10, 2009
 2616  *
 2617  * Modifications:
 2618  *
 2619  *-------------------------------------------------------------------------
 2620  */
 2621 static void *grouped_cas_ptr_helper(void *_udata)
 2622 {
 2623     grouped_cas_ptr_t   *udata = (grouped_cas_ptr_t *)_udata;
 2624     int                 *group_id = udata->groupno;
 2625     int                 *next_id = group_id + 1;
 2626     unsigned            niter = GROUPED_CAS_PTR_NITER;
 2627     unsigned            i;
 2628 
 2629     /* This is the equivalent of the "modulus" operation, but for pointers */
 2630     if(next_id > udata->max_groupno)
 2631         next_id = (int *) 0;
 2632 
 2633     /* Main loop */
 2634     for(i=0; i<niter; i++)
 2635         if(OPA_cas_ptr(udata->shared_val, (void *) group_id, (void *) next_id) == (void *) group_id)
 2636             udata->nsuccess++;
 2637 
 2638     /* Exit */
 2639     if(udata->master_thread)
 2640         return(NULL);
 2641     else
 2642         pthread_exit(NULL);
 2643 } /* end grouped_cas_ptr_helper() */
 2644 #endif /* OPA_HAVE_PTHREAD_H */
 2645 
 2646 
 2647 /*-------------------------------------------------------------------------
 2648  * Function: test_grouped_cas_ptr
 2649  *
 2650  * Purpose: Tests atomicity of OPA_cas_ptr.  Launches nthreads threads,
 2651  *          subdivided into nthreads/4 or 2 groups, whichever is greater.
 2652  *          Each thread continually tries to compare-and-swap a shared
 2653  *          value with its group id (oldv) and group id + 1 % ngroups
 2654  *          (newv).
 2655  *
 2656  * Return: Success: 0
 2657  *         Failure: 1
 2658  *
 2659  * Programmer: Neil Fortner
 2660  *             Monday, August 10, 2009
 2661  *
 2662  * Modifications:
 2663  *
 2664  *-------------------------------------------------------------------------
 2665  */
 2666 static int test_grouped_cas_ptr(void)
 2667 {
 2668 #if defined(OPA_HAVE_PTHREAD_H)
 2669     pthread_t           *threads = NULL; /* Threads */
 2670     pthread_attr_t      ptattr;         /* Thread attributes */
 2671     grouped_cas_ptr_t   *thread_data = NULL; /* User data structs for threads */
 2672     OPA_ptr_t           shared_val;     /* Integer shared between threads */
 2673     int                 ngroups;        /* Number of groups of threads */
 2674     int                 threads_per_group; /* Threads per group */
 2675     int                 *group_success = NULL; /* Number of successes for each group */
 2676     unsigned            nthreads = num_threads[curr_test];
 2677     unsigned            i;
 2678 
 2679     TESTING("grouped pointer compare-and-swap", nthreads);
 2680 
 2681     /* Allocate array of threads */
 2682     if(NULL == (threads = (pthread_t *) malloc((nthreads - 1) * sizeof(pthread_t))))
 2683         TEST_ERROR;
 2684 
 2685     /* Allocate array of thread data */
 2686     if(NULL == (thread_data =
 2687             (grouped_cas_ptr_t *) calloc(nthreads, sizeof(grouped_cas_ptr_t))))
 2688         TEST_ERROR;
 2689 
 2690     /* Calculate number of groups and threads per group */
 2691     if((nthreads / GROUPED_CAS_PTR_TPG) >= 2)
 2692         threads_per_group = GROUPED_CAS_PTR_TPG;
 2693     else
 2694         threads_per_group = (nthreads + 1) / 2;
 2695     ngroups = (nthreads + threads_per_group - 1) / threads_per_group;
 2696 
 2697     /* Initialize thread data structs */
 2698     OPA_store_ptr(&shared_val, (void *) 0);
 2699     for(i=0; i<nthreads; i++) {
 2700         thread_data[i].shared_val = &shared_val;
 2701         thread_data[i].groupno = (int *) 0 + (i / threads_per_group);
 2702     } /* end for */
 2703     thread_data[nthreads-1].master_thread = 1;
 2704     for(i=0; i<nthreads; i++)
 2705         thread_data[i].max_groupno = thread_data[nthreads-1].groupno;
 2706 
 2707     /* Set threads to be joinable */
 2708     pthread_attr_init(&ptattr);
 2709     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
 2710 
 2711     /* Create the threads */
 2712     for(i=0; i<(nthreads - 1); i++)
 2713         if(pthread_create(&threads[i], &ptattr, grouped_cas_ptr_helper,
 2714                 &thread_data[i])) TEST_ERROR;
 2715     (void)grouped_cas_ptr_helper(&thread_data[i]);
 2716 
 2717     /* Free the attribute */
 2718     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
 2719 
 2720     /* Join the threads */
 2721     for (i=0; i<(nthreads - 1); i++)
 2722         if(pthread_join(threads[i], NULL)) TEST_ERROR;
 2723 
 2724     /* Calculate the total number of successes for each group */
 2725     if(NULL == (group_success = (int *) calloc(ngroups, sizeof(int))))
 2726         TEST_ERROR;
 2727     for(i=0; i<nthreads; i++)
 2728         group_success[(int) (thread_data[i].groupno - (int *) 0)] +=
 2729                 thread_data[i].nsuccess;
 2730 
 2731     /* Verify that cas succeeded at least once */
 2732     if(group_success[0] == 0)
 2733         FAIL_OP_ERROR(printf("    Compare-and-swap never succeeded\n"));
 2734 
 2735     /* Verify that the number of successes does not increase with increasing
 2736      * group number, and also that the shared value's final value is consistent
 2737      * with the numbers of successes */
 2738     if(nthreads > 1)
 2739         for(i=1; i<ngroups; i++) {
 2740             if(group_success[i] > group_success[i-1])
 2741                 FAIL_OP_ERROR(printf("    Group %d succeeded more times than group %d\n",
 2742                         i, i-1));
 2743 
 2744             if((group_success[i] < group_success[i-1])
 2745                     && (OPA_load_ptr(&shared_val) != ((int *) 0) + i))
 2746                 FAIL_OP_ERROR(printf("    Number of successes is inconsistent\n"));
 2747         } /* end for */
 2748     if((group_success[0] == group_success[ngroups-1])
 2749             && (OPA_load_ptr(&shared_val) != (int *) 0))
 2750         FAIL_OP_ERROR(printf("    Number of successes is inconsistent\n"));
 2751 
 2752     /* Verify that the number of successes for the first threads is equal to or
 2753      * one greater than the number of successes for the last thread.  Have
 2754      * already determined that it is not less in the previous test. */
 2755     if(group_success[0] > (group_success[ngroups-1] + 1))
 2756         FAIL_OP_ERROR(printf("    Group 0 succeeded %d times more than group %d\n",
 2757                 thread_data[0].nsuccess - thread_data[nthreads-1].nsuccess,
 2758                 nthreads - 1));
 2759 
 2760     /* Free memory */
 2761     free(threads);
 2762     free(thread_data);
 2763     free(group_success);
 2764 
 2765     PASSED();
 2766 
 2767 #else /* OPA_HAVE_PTHREAD_H */
 2768     TESTING("grouped pointer compare-and-swap", 0);
 2769     SKIPPED();
 2770     puts("    pthread.h not available");
 2771 #endif /* OPA_HAVE_PTHREAD_H */
 2772 
 2773     return 0;
 2774 
 2775 #if defined(OPA_HAVE_PTHREAD_H)
 2776 error:
 2777     if(threads) free(threads);
 2778     if(thread_data) free(thread_data);
 2779     if(group_success) free(group_success);
 2780     return 1;
 2781 #endif /* OPA_HAVE_PTHREAD_H */
 2782 } /* end test_grouped_cas_ptr() */
 2783 
 2784 
 2785 #if defined(OPA_HAVE_PTHREAD_H)
 2786 /*-------------------------------------------------------------------------
 2787  * Function: threaded_cas_int_fairness_helper
 2788  *
 2789  * Purpose: Helper (thread) routine for test_threaded_cas_int_fairness
 2790  *
 2791  * Return: NULL
 2792  *
 2793  * Programmer: Neil Fortner
 2794  *             Tuesday, June 9, 2009
 2795  *
 2796  * Modifications:
 2797  *
 2798  *-------------------------------------------------------------------------
 2799  */
 2800 static void *threaded_cas_int_fairness_helper(void *_udata)
 2801 {
 2802     cas_int_fairness_t  *udata = (cas_int_fairness_t *)_udata;
 2803     int                 thread_id = udata->threadno;
 2804     unsigned            nsuccess = 0;
 2805     unsigned            min_success = CAS_INT_FAIRNESS_MIN_SUCCESS;
 2806     unsigned            max_iter = CAS_INT_FAIRNESS_MAX_ITER;
 2807     unsigned            i;
 2808 
 2809     /* Main loop */
 2810     for(i=0; i<max_iter; i++) {
 2811         /* Attempt to set the shared value to the thread id */
 2812         if(OPA_cas_int(udata->shared_val, -1, thread_id) == -1) {
 2813 
 2814             /* Increment success counter */
 2815             nsuccess++;
 2816 
 2817             /* Check for completion */
 2818             if(nsuccess == min_success)
 2819                 OPA_incr_int(udata->successful_threads);
 2820 
 2821             /* Reset shared value */
 2822             if(OPA_cas_int(udata->shared_val, thread_id, -1) != thread_id)
 2823                 udata->nerrors++;
 2824         } /* end if */
 2825 
 2826         /* Check for global completion */
 2827         if(udata->nthreads == OPA_load_int(udata->successful_threads))
 2828             break;
 2829 
 2830         /* Yield if we are not performing strict fairness checks.  This gives
 2831          * other threads a chance and reduces the probability of a thread being
 2832          * stopped for a long period of time after succeeding but before
 2833          * resetting the shared value, preventing forward progress. */
 2834 #ifndef OPA_HAVE_STRICT_FAIRNESS_CHECKS
 2835         OPA_TEST_YIELD();
 2836 #endif /* OPA_HAVE_STRICT_FAIRNESS_CHECKS */
 2837     } /* end for */
 2838 
 2839     /* Check if the loop was terminated due to hitting the MAX_ITER barrier,
 2840      * throw a warning if it was */
 2841     if(i == max_iter)
 2842         udata->terminated = 1;
 2843 
 2844     /* Exit */
 2845     if(udata->master_thread)
 2846         return(NULL);
 2847     else
 2848         pthread_exit(NULL);
 2849 } /* end threaded_cas_int_fairness_helper() */
 2850 #endif /* OPA_HAVE_PTHREAD_H */
 2851 
 2852 
 2853 /*-------------------------------------------------------------------------
 2854  * Function: test_threaded_cas_int_fairness
 2855  *
 2856  * Purpose: Tests fairness of OPA_cas_int.  Launches nthreads threads,
 2857  *          each of which continually tries to compare-and-swap a shared
 2858  *          value with -1 (oldv) and thread id(newv), then sets it back to
 2859  *          -1.  Each thread continues until all threads have succeeded
 2860  *          CAS_INT_FAIRNESS_MIN_SUCCESS times.
 2861  *
 2862  * Return: Success: 0
 2863  *         Failure: 1
 2864  *
 2865  * Programmer: Neil Fortner
 2866  *             Tuesday, August 11, 2009
 2867  *
 2868  * Modifications:
 2869  *
 2870  *-------------------------------------------------------------------------
 2871  */
 2872 static int test_threaded_cas_int_fairness(void)
 2873 {
 2874 #if defined(OPA_HAVE_PTHREAD_H)
 2875     pthread_t           *threads = NULL; /* Threads */
 2876     pthread_attr_t      ptattr;         /* Thread attributes */
 2877     cas_int_fairness_t  *thread_data = NULL; /* User data structs for threads */
 2878     OPA_int_t           shared_val;     /* Integer shared between threads */
 2879     OPA_int_t           successful_threads; /* Number of threads that have succeeded */
 2880     int                 succeeded = 0;  /* Whether all threads succeeded */
 2881     int                 terminated = 0; /* Number of threads that were terminated */
 2882     int                 nerrors = 0;    /* Number of errors */
 2883     unsigned            nthreads = num_threads[curr_test];
 2884     unsigned            i;
 2885 
 2886     TESTING("integer compare-and-swap fairness", nthreads);
 2887 
 2888     /* Allocate array of threads */
 2889     if(NULL == (threads = (pthread_t *) malloc((nthreads - 1) * sizeof(pthread_t))))
 2890         TEST_ERROR;
 2891 
 2892     /* Allocate array of thread data */
 2893     if(NULL == (thread_data = (cas_int_fairness_t *) calloc(nthreads, sizeof(cas_int_fairness_t))))
 2894         TEST_ERROR;
 2895 
 2896     /* Initialize thread data structs */
 2897     OPA_store_int(&shared_val, -1);
 2898     OPA_store_int(&successful_threads, 0);
 2899     for(i=0; i<nthreads; i++) {
 2900         thread_data[i].shared_val = &shared_val;
 2901         thread_data[i].threadno = i;
 2902         thread_data[i].nthreads = (int) nthreads;
 2903         thread_data[i].successful_threads = &successful_threads;
 2904     } /* end for */
 2905     thread_data[nthreads-1].master_thread = 1;
 2906 
 2907     /* Set threads to be joinable */
 2908     pthread_attr_init(&ptattr);
 2909     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
 2910 
 2911     /* Create the threads */
 2912     for(i=0; i<(nthreads - 1); i++)
 2913         if(pthread_create(&threads[i], &ptattr, threaded_cas_int_fairness_helper,
 2914                 &thread_data[i])) TEST_ERROR;
 2915     (void)threaded_cas_int_fairness_helper(&thread_data[i]);
 2916 
 2917     /* Free the attribute */
 2918     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
 2919 
 2920     /* Join the threads */
 2921     for (i=0; i<(nthreads - 1); i++)
 2922         if(pthread_join(threads[i], NULL)) TEST_ERROR;
 2923 
 2924     /* Check if any errors were reported by the threads */
 2925     for(i=0; i<nthreads; i++)
 2926         nerrors += thread_data[i].nerrors;
 2927     if(nerrors)
 2928         FAIL_OP_ERROR(printf("    %d unexpected return%s from OPA_cas_int\n",
 2929                 nerrors, nerrors == 1 ? "" : "s"));
 2930 
 2931     /* Verify that all threads succeeded */
 2932     if(OPA_load_int(&successful_threads) == (int) nthreads)
 2933         succeeded = 1;
 2934 
 2935     /* Check if any threads were terminated before succeeding */
 2936     for(i=0; i<nthreads; i++)
 2937         terminated += thread_data[i].terminated;
 2938 
 2939     /* If no threads were terminated, but not all succeeded, something is very
 2940      * wrong... */
 2941     if(!succeeded && !terminated)
 2942         FAIL_OP_ERROR(printf("    Not all threads succeeded, but none were terminated\n"));
 2943 
 2944     /* Otherwise, throw a warning if any threads were terminated */
 2945     if(terminated)
 2946     {
 2947         WARNING();
 2948         if(succeeded)
 2949             printf("    %d thread%s were terminated before succeeding: there may be an issue with\n    fairness\n",
 2950                     terminated, terminated == 1 ? "" : "s");
 2951         else {
 2952             i = nthreads - OPA_load_int(&successful_threads);
 2953             printf("    %d thread%s did not succeed: there may be an issue with fairness\n",
 2954                     i, i == 1 ? "" : "s");
 2955         } /* end else */
 2956     } /* end if */
 2957 
 2958     /* Free memory */
 2959     free(threads);
 2960     free(thread_data);
 2961 
 2962     if(!terminated)
 2963         PASSED();
 2964 
 2965 #else /* OPA_HAVE_PTHREAD_H */
 2966     TESTING("integer compare-and-swap fairness", 0);
 2967     SKIPPED();
 2968     puts("    pthread.h not available");
 2969 #endif /* OPA_HAVE_PTHREAD_H */
 2970 
 2971     return 0;
 2972 
 2973 #if defined(OPA_HAVE_PTHREAD_H)
 2974 error:
 2975     if(threads) free(threads);
 2976     if(thread_data) free(thread_data);
 2977     return 1;
 2978 #endif /* OPA_HAVE_PTHREAD_H */
 2979 } /* end test_threaded_cas_int_fairness() */
 2980 
 2981 
 2982 #if defined(OPA_HAVE_PTHREAD_H)
 2983 /*-------------------------------------------------------------------------
 2984  * Function: threaded_cas_ptr_fairness_helper
 2985  *
 2986  * Purpose: Helper (thread) routine for test_threaded_cas_ptr_fairness
 2987  *
 2988  * Return: NULL
 2989  *
 2990  * Programmer: Neil Fortner
 2991  *             Tuesday, June 9, 2009
 2992  *
 2993  * Modifications:
 2994  *
 2995  *-------------------------------------------------------------------------
 2996  */
 2997 static void *threaded_cas_ptr_fairness_helper(void *_udata)
 2998 {
 2999     cas_ptr_fairness_t  *udata = (cas_ptr_fairness_t *)_udata;
 3000     int                 *thread_id = udata->threadno;
 3001     unsigned            nsuccess = 0;
 3002     unsigned            min_success = CAS_PTR_FAIRNESS_MIN_SUCCESS;
 3003     unsigned            max_iter = CAS_PTR_FAIRNESS_MAX_ITER;
 3004     unsigned            i;
 3005 
 3006     /* Main loop */
 3007     for(i=0; i<max_iter; i++) {
 3008         /* Attempt to set the shared value to the thread id */
 3009         if(OPA_cas_ptr(udata->shared_val, (void *) 0, thread_id) == (void *) 0) {
 3010 
 3011             /* Increment success counter */
 3012             nsuccess++;
 3013 
 3014             /* Check for completion */
 3015             if(nsuccess == min_success)
 3016                 OPA_incr_int(udata->successful_threads);
 3017 
 3018             /* Reset shared value */
 3019             if(OPA_cas_ptr(udata->shared_val, thread_id, (void *) 0) != (void *) thread_id)
 3020                 udata->nerrors++;
 3021         } /* end if */
 3022 
 3023         /* Check for global completion */
 3024         if(udata->nthreads == OPA_load_int(udata->successful_threads))
 3025             break;
 3026 
 3027         /* Yield if we are not performing strict fairness checks.  This gives
 3028          * other threads a chance and reduces the probability of a thread being
 3029          * stopped for a long period of time after succeeding but before
 3030          * resetting the shared value, preventing forward progress. */
 3031 #ifndef OPA_HAVE_STRICT_FAIRNESS_CHECKS
 3032         OPA_TEST_YIELD();
 3033 #endif /* OPA_HAVE_STRICT_FAIRNESS_CHECKS */
 3034     } /* end for */
 3035 
 3036     /* Check if the loop was terminated due to hitting the MAX_ITER barrier,
 3037      * throw a warning if it was */
 3038     if(i == max_iter)
 3039         udata->terminated = 1;
 3040 
 3041     /* Exit */
 3042     if(udata->master_thread)
 3043         return(NULL);
 3044     else
 3045         pthread_exit(NULL);
 3046 } /* end threaded_cas_ptr_fairness_helper() */
 3047 #endif /* OPA_HAVE_PTHREAD_H */
 3048 
 3049 
 3050 /*-------------------------------------------------------------------------
 3051  * Function: test_threaded_cas_ptr_fairness
 3052  *
 3053  * Purpose: Tests fairness of OPA_cas_int.  Launches nthreads threads,
 3054  *          each of which continually tries to compare-and-swap a shared
 3055  *          value with -1 (oldv) and thread id(newv), then sets it back to
 3056  *          -1.  Each thread continues until all threads have succeeded
 3057  *          CAS_INT_FAIRNESS_MIN_SUCCESS times.
 3058  *
 3059  * Return: Success: 0
 3060  *         Failure: 1
 3061  *
 3062  * Programmer: Neil Fortner
 3063  *             Tuesday, August 11, 2009
 3064  *
 3065  * Modifications:
 3066  *
 3067  *-------------------------------------------------------------------------
 3068  */
 3069 static int test_threaded_cas_ptr_fairness(void)
 3070 {
 3071 #if defined(OPA_HAVE_PTHREAD_H)
 3072     pthread_t           *threads = NULL; /* Threads */
 3073     pthread_attr_t      ptattr;         /* Thread attributes */
 3074     cas_ptr_fairness_t  *thread_data = NULL; /* User data structs for threads */
 3075     OPA_ptr_t           shared_val;     /* Integer shared between threads */
 3076     OPA_int_t           successful_threads; /* Number of threads that have succeeded */
 3077     int                 succeeded = 0;  /* Whether all threads succeeded */
 3078     int                 terminated = 0; /* Number of threads that were terminated */
 3079     int                 nerrors = 0;    /* Number of errors */
 3080     unsigned            nthreads = num_threads[curr_test];
 3081     unsigned            i;
 3082 
 3083     TESTING("pointer compare-and-swap fairness", nthreads);
 3084 
 3085     /* Allocate array of threads */
 3086     if(NULL == (threads = (pthread_t *) malloc((nthreads - 1) * sizeof(pthread_t))))
 3087         TEST_ERROR;
 3088 
 3089     /* Allocate array of thread data */
 3090     if(NULL == (thread_data = (cas_ptr_fairness_t *) calloc(nthreads, sizeof(cas_ptr_fairness_t))))
 3091         TEST_ERROR;
 3092 
 3093     /* Initialize thread data structs */
 3094     OPA_store_ptr(&shared_val, (void *) 0);
 3095     OPA_store_int(&successful_threads, 0);
 3096     for(i=0; i<nthreads; i++) {
 3097         thread_data[i].shared_val = &shared_val;
 3098         thread_data[i].threadno = (void *) 0 + i + 1;
 3099         thread_data[i].nthreads = (int) nthreads;
 3100         thread_data[i].successful_threads = &successful_threads;
 3101     } /* end for */
 3102     thread_data[nthreads-1].master_thread = 1;
 3103 
 3104     /* Set threads to be joinable */
 3105     pthread_attr_init(&ptattr);
 3106     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
 3107 
 3108     /* Create the threads */
 3109     for(i=0; i<(nthreads - 1); i++)
 3110         if(pthread_create(&threads[i], &ptattr, threaded_cas_ptr_fairness_helper,
 3111                 &thread_data[i])) TEST_ERROR;
 3112     (void)threaded_cas_ptr_fairness_helper(&thread_data[i]);
 3113 
 3114     /* Free the attribute */
 3115     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
 3116 
 3117     /* Join the threads */
 3118     for (i=0; i<(nthreads - 1); i++)
 3119         if(pthread_join(threads[i], NULL)) TEST_ERROR;
 3120 
 3121     /* Check if any errors were reported by the threads */
 3122     for(i=0; i<nthreads; i++)
 3123         nerrors += thread_data[i].nerrors;
 3124     if(nerrors)
 3125         FAIL_OP_ERROR(printf("    %d unexpected return%s from OPA_cas_ptr\n",
 3126                 nerrors, nerrors == 1 ? "" : "s"));
 3127 
 3128     /* Verify that all threads succeeded */
 3129     if(OPA_load_int(&successful_threads) == (int) nthreads)
 3130         succeeded = 1;
 3131 
 3132     /* Check if any threads were terminated before succeeding */
 3133     for(i=0; i<nthreads; i++)
 3134         terminated += thread_data[i].terminated;
 3135 
 3136     /* If no threads were terminated, but not all succeeded, something is very
 3137      * wrong... */
 3138     if(!succeeded && !terminated)
 3139         FAIL_OP_ERROR(printf("    Not all threads succeeded, but none were terminated\n"));
 3140 
 3141     /* Otherwise, throw a warning if any threads were terminated */
 3142     if(terminated)
 3143     {
 3144         WARNING();
 3145         if(succeeded)
 3146             printf("    %d thread%s were terminated before succeeding: there may be an issue with\n    fairness\n",
 3147                     terminated, terminated == 1 ? "" : "s");
 3148         else {
 3149             i = nthreads - OPA_load_int(&successful_threads);
 3150             printf("    %d thread%s did not succeed: there may be an issue with fairness\n",
 3151                     i, i == 1 ? "" : "s");
 3152         } /* end else */
 3153     } /* end if */
 3154 
 3155     /* Free memory */
 3156     free(threads);
 3157     free(thread_data);
 3158 
 3159     if(!terminated)
 3160         PASSED();
 3161 
 3162 #else /* OPA_HAVE_PTHREAD_H */
 3163     TESTING("pointer compare-and-swap fairness", 0);
 3164     SKIPPED();
 3165     puts("    pthread.h not available");
 3166 #endif /* OPA_HAVE_PTHREAD_H */
 3167 
 3168     return 0;
 3169 
 3170 #if defined(OPA_HAVE_PTHREAD_H)
 3171 error:
 3172     if(threads) free(threads);
 3173     if(thread_data) free(thread_data);
 3174     return 1;
 3175 #endif /* OPA_HAVE_PTHREAD_H */
 3176 } /* end test_threaded_cas_ptr_fairness() */
 3177 
 3178 
 3179 /*-------------------------------------------------------------------------
 3180  * Function: test_simple_swap_int
 3181  *
 3182  * Purpose: Tests basic functionality of OPA_swap_int with a single
 3183  *          thread.  Does not test atomicity of operations.
 3184  *
 3185  * Return: Success: 0
 3186  *         Failure: 1
 3187  *
 3188  * Programmer: Neil Fortner
 3189  *             Wednesday, March 24, 2010
 3190  *
 3191  * Modifications:
 3192  *
 3193  *-------------------------------------------------------------------------
 3194  */
 3195 static int test_simple_swap_int(void)
 3196 {
 3197     OPA_int_t   a;
 3198 
 3199     TESTING("simple integer swap functionality", 0);
 3200 
 3201     /* Store 0 in a */
 3202     OPA_store_int(&a, 0);
 3203 
 3204     /* Compare and swap multiple times, verify return value and final result */
 3205     if(0 != OPA_swap_int(&a, INT_MAX)) TEST_ERROR;
 3206     if(INT_MAX != OPA_swap_int(&a, INT_MIN)) TEST_ERROR;
 3207     if(INT_MIN != OPA_swap_int(&a, 1)) TEST_ERROR;
 3208     if(1 != OPA_load_int(&a)) TEST_ERROR;
 3209 
 3210     PASSED();
 3211     return 0;
 3212 
 3213 error:
 3214     return 1;
 3215 } /* end test_simple_swap_int() */
 3216 
 3217 
 3218 /*-------------------------------------------------------------------------
 3219  * Function: test_simple_swap_ptr
 3220  *
 3221  * Purpose: Tests basic functionality of OPA_swap_ptr with a single
 3222  *          thread.  Does not test atomicity of operations.
 3223  *
 3224  * Return: Success: 0
 3225  *         Failure: 1
 3226  *
 3227  * Programmer: Neil Fortner
 3228  *             Wednesday, March 24, 2010
 3229  *
 3230  * Modifications:
 3231  *
 3232  *-------------------------------------------------------------------------
 3233  */
 3234 static int test_simple_swap_ptr(void)
 3235 {
 3236     OPA_ptr_t   a;
 3237     void        *ptr1 = malloc(1);      /* Pointers to assign to a */
 3238     void        *ptr2 = malloc(1);
 3239     void        *ptr3 = malloc(1);
 3240     void        *ptr4 = malloc(1);
 3241 
 3242     TESTING("simple pointer swap functionality", 0);
 3243 
 3244     /* Store ptr1 in a */
 3245     OPA_store_ptr(&a, ptr1);
 3246 
 3247     /* Compare and swap multiple times, verify return value and final result */
 3248     if(ptr1 != OPA_swap_ptr(&a, ptr3)) TEST_ERROR;
 3249     if(ptr3 != OPA_swap_ptr(&a, ptr4)) TEST_ERROR;
 3250     if(ptr4 != OPA_swap_ptr(&a, ptr2)) TEST_ERROR;
 3251     if(ptr2 != OPA_load_ptr(&a)) TEST_ERROR;
 3252 
 3253     if(ptr1) free(ptr1);
 3254     if(ptr2) free(ptr2);
 3255     if(ptr3) free(ptr3);
 3256     if(ptr4) free(ptr4);
 3257 
 3258     PASSED();
 3259     return 0;
 3260 
 3261 error:
 3262     if(ptr1) free(ptr1);
 3263     if(ptr2) free(ptr2);
 3264     if(ptr3) free(ptr3);
 3265     if(ptr4) free(ptr4);
 3266 
 3267     return 1;
 3268 } /* end test_simple_swap_ptr() */
 3269 
 3270 
 3271 #if defined(OPA_HAVE_PTHREAD_H)
 3272 /*-------------------------------------------------------------------------
 3273  * Function: threaded_swap_int_helper
 3274  *
 3275  * Purpose: Helper (thread) routine for test_threaded_swap_int
 3276  *
 3277  * Return: NULL
 3278  *
 3279  * Programmer: Neil Fortner
 3280  *             Wednesday, March 24, 2010
 3281  *
 3282  * Modifications:
 3283  *
 3284  *-------------------------------------------------------------------------
 3285  */
 3286 static void *threaded_swap_int_helper(void *_udata)
 3287 {
 3288     swap_int_t          *udata = (swap_int_t *)_udata;
 3289     unsigned            niter = SWAP_INT_NITER;
 3290     unsigned            i;
 3291 
 3292     /* Main loop */
 3293     for(i=0; i<niter; i++)
 3294         udata->local_val = OPA_swap_int(udata->shared_val, udata->local_val);
 3295 
 3296     /* Exit */
 3297     if(udata->master_thread)
 3298         return(NULL);
 3299     else
 3300         pthread_exit(NULL);
 3301 } /* end threaded_swap_int_helper() */
 3302 #endif /* OPA_HAVE_PTHREAD_H */
 3303 
 3304 
 3305 /*-------------------------------------------------------------------------
 3306  * Function: test_threaded_swap_int
 3307  *
 3308  * Purpose: Tests atomicity of OPA_swap_int.  Launches nthreads threads,
 3309  *          each of which continually swaps a shared value with a local
 3310  *          variable whose initial value is the thread id.  Afterwards,
 3311  *          Verifies that each thread id is present exactly once in all of
 3312  *          the thread local values, and the shared value.  The initial
 3313  *          state of the shared value must also be present exactly once in
 3314  *          these places.
 3315  *
 3316  * Return: Success: 0
 3317  *         Failure: 1
 3318  *
 3319  * Programmer: Neil Fortner
 3320  *             Tuesday, June 9, 2009
 3321  *
 3322  * Modifications:
 3323  *
 3324  *-------------------------------------------------------------------------
 3325  */
 3326 static int test_threaded_swap_int(void)
 3327 {
 3328 #if defined(OPA_HAVE_PTHREAD_H)
 3329     pthread_t           *threads = NULL; /* Threads */
 3330     pthread_attr_t      ptattr;         /* Thread attributes */
 3331     swap_int_t          *thread_data = NULL; /* User data structs for threads */
 3332     OPA_int_t           shared_val;     /* Integer shared between threads */
 3333     unsigned            *vals = NULL;   /* Local values found */
 3334     unsigned            nthreads = num_threads[curr_test];
 3335     unsigned            i;
 3336 
 3337     TESTING("integer swap", nthreads);
 3338 
 3339     /* Allocate array of threads */
 3340     if(NULL == (threads = (pthread_t *) malloc((nthreads - 1) * sizeof(pthread_t))))
 3341         TEST_ERROR;
 3342 
 3343     /* Allocate array of thread data */
 3344     if(NULL == (thread_data = (swap_int_t *) calloc(nthreads, sizeof(swap_int_t))))
 3345         TEST_ERROR;
 3346 
 3347     /* Initialize thread data structs */
 3348     OPA_store_int(&shared_val, nthreads);
 3349     for(i=0; i<nthreads; i++) {
 3350         thread_data[i].shared_val = &shared_val;
 3351         thread_data[i].local_val = i;
 3352     } /* end for */
 3353     thread_data[nthreads-1].master_thread = 1;
 3354 
 3355     /* Set threads to be joinable */
 3356     pthread_attr_init(&ptattr);
 3357     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
 3358 
 3359     /* Create the threads */
 3360     for(i=0; i<(nthreads - 1); i++)
 3361         if(pthread_create(&threads[i], &ptattr, threaded_swap_int_helper,
 3362                 &thread_data[i])) TEST_ERROR;
 3363     (void)threaded_swap_int_helper(&thread_data[i]);
 3364 
 3365     /* Free the attribute */
 3366     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
 3367 
 3368     /* Join the threads */
 3369     for (i=0; i<(nthreads - 1); i++)
 3370         if(pthread_join(threads[i], NULL)) TEST_ERROR;
 3371 
 3372     /* Allocate the array of local values found.  These number 0 to nthreads
 3373      * (1 for each thread id, and nthreads was the original value) */
 3374     if(NULL == (vals = (unsigned *) calloc(nthreads + 1, sizeof(unsigned))))
 3375         TEST_ERROR;
 3376 
 3377     /* Loop over all local values and the shared value, and total up the number
 3378      * of times each value was found */
 3379     for(i=0; i<nthreads; i++) {
 3380         /* Verify that the value is in range */
 3381         if((thread_data[i].local_val < 0)
 3382                 || (thread_data[i].local_val > nthreads))
 3383             FAIL_OP_ERROR(printf("    Local value for thread %u is out of range: %d\n",
 3384                     i, thread_data[i].local_val));
 3385 
 3386         /* Increment the number of times local_val was encountered */
 3387         vals[thread_data[i].local_val]++;
 3388     } /* end for */
 3389     if((OPA_load_int(&shared_val) < 0)
 3390             || (OPA_load_int(&shared_val) > nthreads))
 3391         FAIL_OP_ERROR(printf("    Shared value is out of range: %d\n",
 3392                 OPA_load_int(&shared_val)));
 3393     vals[OPA_load_int(&shared_val)]++;
 3394 
 3395     /* Verify that each possible value was encountered exactly once */
 3396     for(i=0; i<nthreads; i++)
 3397         if(vals[i] != 1)
 3398             FAIL_OP_ERROR(printf("    Value %u was encountered %u times.  Expected: 1\n",
 3399                     i, vals[i]));
 3400 
 3401     /* Free memory */
 3402     free(threads);
 3403     free(thread_data);
 3404     free(vals);
 3405 
 3406     PASSED();
 3407 
 3408 #else /* OPA_HAVE_PTHREAD_H */
 3409     TESTING("integer swap", 0);
 3410     SKIPPED();
 3411     puts("    pthread.h not available");
 3412 #endif /* OPA_HAVE_PTHREAD_H */
 3413 
 3414     return 0;
 3415 
 3416 #if defined(OPA_HAVE_PTHREAD_H)
 3417 error:
 3418     if(threads) free(threads);
 3419     if(thread_data) free(thread_data);
 3420     if(vals) free(vals);
 3421     return 1;
 3422 #endif /* OPA_HAVE_PTHREAD_H */
 3423 } /* end test_threaded_swap_int() */
 3424 
 3425 
 3426 #if defined(OPA_HAVE_PTHREAD_H)
 3427 /*-------------------------------------------------------------------------
 3428  * Function: threaded_swap_ptr_helper
 3429  *
 3430  * Purpose: Helper (thread) routine for test_threaded_swap_ptr
 3431  *
 3432  * Return: NULL
 3433  *
 3434  * Programmer: Neil Fortner
 3435  *             Wednesday, March 24, 2010
 3436  *
 3437  * Modifications:
 3438  *
 3439  *-------------------------------------------------------------------------
 3440  */
 3441 static void *threaded_swap_ptr_helper(void *_udata)
 3442 {
 3443     swap_ptr_t          *udata = (swap_ptr_t *)_udata;
 3444     unsigned            niter = SWAP_PTR_NITER;
 3445     unsigned            i;
 3446 
 3447     /* Main loop */
 3448     for(i=0; i<niter; i++)
 3449         udata->local_val = OPA_swap_ptr(udata->shared_val, udata->local_val);
 3450 
 3451     /* Exit */
 3452     if(udata->master_thread)
 3453         return(NULL);
 3454     else
 3455         pthread_exit(NULL);
 3456 } /* end threaded_swap_ptr_helper() */
 3457 #endif /* OPA_HAVE_PTHREAD_H */
 3458 
 3459 
 3460 /*-------------------------------------------------------------------------
 3461  * Function: test_threaded_swap_ptr
 3462  *
 3463  * Purpose: Tests atomicity of OPA_swap_ptr.  Launches nthreads threads,
 3464  *          each of which continually swaps a shared value with a local
 3465  *          variable whose initial value is the thread id.  Afterwards,
 3466  *          Verifies that each thread id is present exactly once in all of
 3467  *          the thread local values, and the shared value.  The initial
 3468  *          state of the shared value must also be present exactly once in
 3469  *          these places.
 3470  *
 3471  * Return: Success: 0
 3472  *         Failure: 1
 3473  *
 3474  * Programmer: Neil Fortner
 3475  *             Tuesday, June 9, 2009
 3476  *
 3477  * Modifications:
 3478  *
 3479  *-------------------------------------------------------------------------
 3480  */
 3481 static int test_threaded_swap_ptr(void)
 3482 {
 3483 #if defined(OPA_HAVE_PTHREAD_H)
 3484     pthread_t           *threads = NULL; /* Threads */
 3485     pthread_attr_t      ptattr;         /* Thread attributes */
 3486     swap_ptr_t          *thread_data = NULL; /* User data structs for threads */
 3487     OPA_ptr_t           shared_val;     /* Pointer shared between threads */
 3488     unsigned            *vals = NULL;   /* Local values found */
 3489     unsigned            nthreads = num_threads[curr_test];
 3490     unsigned            i;
 3491 
 3492     TESTING("pointer swap", nthreads);
 3493 
 3494     /* Allocate array of threads */
 3495     if(NULL == (threads = (pthread_t *) malloc((nthreads - 1) * sizeof(pthread_t))))
 3496         TEST_ERROR;
 3497 
 3498     /* Allocate array of thread data */
 3499     if(NULL == (thread_data = (swap_ptr_t *) calloc(nthreads, sizeof(swap_ptr_t))))
 3500         TEST_ERROR;
 3501 
 3502     /* Initialize thread data structs.  Each local_val points to an element in
 3503      * thread_data, or NULL (original value) */
 3504     OPA_store_ptr(&shared_val, NULL);
 3505     for(i=0; i<nthreads; i++) {
 3506         thread_data[i].shared_val = &shared_val;
 3507         thread_data[i].local_val = &(thread_data[i]);
 3508         thread_data[i].threadno = i;
 3509     } /* end for */
 3510     thread_data[nthreads-1].master_thread = 1;
 3511 
 3512     /* Set threads to be joinable */
 3513     pthread_attr_init(&ptattr);
 3514     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
 3515 
 3516     /* Create the threads */
 3517     for(i=0; i<(nthreads - 1); i++)
 3518         if(pthread_create(&threads[i], &ptattr, threaded_swap_ptr_helper,
 3519                 &thread_data[i])) TEST_ERROR;
 3520     (void)threaded_swap_ptr_helper(&thread_data[i]);
 3521 
 3522     /* Free the attribute */
 3523     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
 3524 
 3525     /* Join the threads */
 3526     for (i=0; i<(nthreads - 1); i++)
 3527         if(pthread_join(threads[i], NULL)) TEST_ERROR;
 3528 
 3529     /* Allocate the array of local values found.  These number 0 to nthreads
 3530      * (1 for each thread id, and nthreads was the original value) */
 3531     if(NULL == (vals = (unsigned *) calloc(nthreads + 1, sizeof(unsigned))))
 3532         TEST_ERROR;
 3533 
 3534     /* Loop over all local values and the shared value, and total up the number
 3535      * of times each value was found */
 3536     for(i=0; i<nthreads; i++) {
 3537         /* Increment the number of times local_val was encountered.  Use the
 3538          * threadno of the target thread_data element as the index into vals.
 3539          * If local_val is NULL, use nthreads as the index. */
 3540         if(thread_data[i].local_val)
 3541             vals[((swap_ptr_t *)thread_data[i].local_val)->threadno]++;
 3542         else
 3543             vals[nthreads]++;
 3544     } /* end for */
 3545     if(OPA_load_ptr(&shared_val))
 3546         vals[((swap_ptr_t *)OPA_load_ptr(&shared_val))->threadno]++;
 3547     else
 3548         vals[nthreads]++;
 3549 
 3550     /* Verify that each possible value was encountered exactly once */
 3551     for(i=0; i<nthreads; i++)
 3552         if(vals[i] != 1)
 3553             FAIL_OP_ERROR(printf("    Value %d was encountered %d times.  Expected: 1\n",
 3554                     i, vals[i]));
 3555 
 3556     /* Free memory */
 3557     free(threads);
 3558     free(thread_data);
 3559     free(vals);
 3560 
 3561     PASSED();
 3562 
 3563 #else /* OPA_HAVE_PTHREAD_H */
 3564     TESTING("pointer swap", 0);
 3565     SKIPPED();
 3566     puts("    pthread.h not available");
 3567 #endif /* OPA_HAVE_PTHREAD_H */
 3568 
 3569     return 0;
 3570 
 3571 #if defined(OPA_HAVE_PTHREAD_H)
 3572 error:
 3573     if(threads) free(threads);
 3574     if(thread_data) free(thread_data);
 3575     if(vals) free(vals);
 3576     return 1;
 3577 #endif /* OPA_HAVE_PTHREAD_H */
 3578 } /* end test_threaded_swap_ptr() */
 3579 
 3580 
 3581 /*-------------------------------------------------------------------------
 3582  * Function: test_simple_llsc_int
 3583  *
 3584  * Purpose: Tests basic functionality of OPA_LL_int and OPA_SC_int with a
 3585  *          single thread.  Does not test atomicity of operations.
 3586  *
 3587  * Return: Success: 0
 3588  *         Failure: 1
 3589  *
 3590  * Programmer: Neil Fortner
 3591  *             Tuesday, June 15, 2010
 3592  *
 3593  * Modifications:
 3594  *
 3595  *-------------------------------------------------------------------------
 3596  */
 3597 static int test_simple_llsc_int(void)
 3598 {
 3599 #if defined(OPA_LL_SC_SUPPORTED)
 3600     OPA_int_t   a;
 3601     int         warned = 0;     /* Whether a warning message has been issued */
 3602 
 3603     TESTING("simple integer load-linked/store-conditional functionality", 0);
 3604 
 3605     /* Store 0 in a */
 3606     OPA_store_int(&a, 0);
 3607 
 3608     /* Load linked a */
 3609     if(0 != OPA_LL_int(&a)) TEST_ERROR;
 3610 
 3611     /* Store conditional INT_MAX in a - should succeed */
 3612     if(!OPA_SC_int(&a, INT_MAX) && !warned) {
 3613         WARNING();
 3614         printf("    Unexpected failure of OPA_SC_int.  LL/SC may be weak\n");
 3615         warned = 1;
 3616         OPA_store_int(&a, INT_MAX);
 3617     } /* end if */
 3618 
 3619     /* Load linked a */
 3620     if(INT_MAX != OPA_LL_int(&a)) TEST_ERROR;
 3621 
 3622     /* Store conditional INT_MIN in a - should succeed */
 3623     if(!OPA_SC_int(&a, INT_MIN) && !warned) {
 3624         WARNING();
 3625         printf("    Unexpected failure of OPA_SC_int.  LL/SC may be weak\n");
 3626         warned = 1;
 3627         OPA_store_int(&a, INT_MIN);
 3628     } /* end if */
 3629 
 3630     /* Load linked a */
 3631     if(INT_MIN != OPA_LL_int(&a)) TEST_ERROR;
 3632 
 3633     /* Store conditional 0 in a - should succeed */
 3634     if(!OPA_SC_int(&a, 0) && !warned) {
 3635         WARNING();
 3636         printf("    Unexpected failure of OPA_SC_int.  LL/SC may be weak\n");
 3637         warned = 1;
 3638         OPA_store_int(&a, 0);
 3639     } /* end if */
 3640 
 3641     /* Make sure a contains 0 */
 3642     if(0 != OPA_load_int(&a)) TEST_ERROR;
 3643 
 3644     if(!warned)
 3645         PASSED();
 3646 
 3647 #else /* OPA_LL_SC_SUPPORTED */
 3648     TESTING("simple integer load-linked/store-conditional functionality", 0);
 3649     SKIPPED();
 3650     puts("    LL/SC not available");
 3651 #endif /* OPA_LL_SC_SUPPORTED */
 3652 
 3653     return 0;
 3654 
 3655 #if defined(OPA_LL_SC_SUPPORTED)
 3656 error:
 3657     return 1;
 3658 #endif /* OPA_LL_SC_SUPPORTED */
 3659 } /* end test_simple_llsc_int() */
 3660 
 3661 
 3662 /*-------------------------------------------------------------------------
 3663  * Function: test_simple_llsc_ptr
 3664  *
 3665  * Purpose: Tests basic functionality of OPA_LL_ptr and OPA_SC_ptr with a
 3666  *          single thread.  Does not test atomicity of operations.
 3667  *
 3668  * Return: Success: 0
 3669  *         Failure: 1
 3670  *
 3671  * Programmer: Neil Fortner
 3672  *             Tuesday, June 15, 2010
 3673  *
 3674  * Modifications:
 3675  *
 3676  *-------------------------------------------------------------------------
 3677  */
 3678 static int test_simple_llsc_ptr(void)
 3679 {
 3680 #if defined(OPA_LL_SC_SUPPORTED)
 3681     OPA_ptr_t   a;
 3682     void        *ptr1 = malloc(1);      /* Pointers to assign to a */
 3683     void        *ptr2 = malloc(1);
 3684     void        *ptr3 = malloc(1);
 3685     int         warned = 0;             /* Whether a warning message has been issued */
 3686 
 3687     TESTING("simple pointer load-linked/store-conditional functionality", 0);
 3688 
 3689     /* Store ptr1 in a */
 3690     OPA_store_ptr(&a, ptr1);
 3691 
 3692     /* Load linked a */
 3693     if(ptr1 != OPA_LL_ptr(&a)) TEST_ERROR;
 3694 
 3695     /* Store conditional ptr2 in a - should succeed */
 3696     if(!OPA_SC_ptr(&a, ptr2) && !warned) {
 3697         WARNING();
 3698         printf("    Unexpected failure of OPA_SC_ptr.  LL/SC may be weak\n");
 3699         warned = 1;
 3700         OPA_store_ptr(&a, ptr2);
 3701     } /* end if */
 3702 
 3703     /* Load linked a */
 3704     if(ptr2 != OPA_LL_ptr(&a)) TEST_ERROR;
 3705 
 3706     /* Store conditional ptr3 in a - should succeed */
 3707     if(!OPA_SC_ptr(&a, ptr3) && !warned) {
 3708         WARNING();
 3709         printf("    Unexpected failure of OPA_SC_ptr.  LL/SC may be weak\n");
 3710         warned = 1;
 3711         OPA_store_ptr(&a, ptr3);
 3712     } /* end if */
 3713 
 3714     /* Load linked a */
 3715     if(ptr3 != OPA_LL_ptr(&a)) TEST_ERROR;
 3716 
 3717     /* Store conditional ptr1 in a - should succeed */
 3718     if(!OPA_SC_ptr(&a, ptr1) && !warned) {
 3719         WARNING();
 3720         printf("    Unexpected failure of OPA_SC_ptr.  LL/SC may be weak\n");
 3721         warned = 1;
 3722         OPA_store_ptr(&a, ptr1);
 3723     } /* end if */
 3724 
 3725     /* Make sure a contains ptr1 */
 3726     if(ptr1 != OPA_load_ptr(&a)) TEST_ERROR;
 3727 
 3728     if(ptr1) free(ptr1);
 3729     if(ptr2) free(ptr2);
 3730     if(ptr3) free(ptr3);
 3731 
 3732     if(!warned)
 3733         PASSED();
 3734 
 3735 #else /* OPA_LL_SC_SUPPORTED */
 3736     TESTING("simple pointer load-linked/store-conditional functionality", 0);
 3737     SKIPPED();
 3738     puts("    LL/SC not available");
 3739 #endif /* OPA_LL_SC_SUPPORTED */
 3740 
 3741     return 0;
 3742 
 3743 #if defined(OPA_LL_SC_SUPPORTED)
 3744 error:
 3745     if(ptr1) free(ptr1);
 3746     if(ptr2) free(ptr2);
 3747     if(ptr3) free(ptr3);
 3748 
 3749     return 1;
 3750 #endif /* OPA_LL_SC_SUPPORTED */
 3751 } /* end test_simple_llsc_ptr() */
 3752 
 3753 
 3754 #if defined(OPA_HAVE_PTHREAD_H) && defined(OPA_LL_SC_SUPPORTED)
 3755 /*-------------------------------------------------------------------------
 3756  * Function: threaded_llsc_int_aba_helper_0
 3757  *
 3758  * Purpose: Helper (thread) routine 0 for test_threaded_llsc_int_aba
 3759  *
 3760  * Return: Number of errors
 3761  *
 3762  * Programmer: Neil Fortner
 3763  *             Monday, June 21, 2010
 3764  *
 3765  * Modifications:
 3766  *
 3767  *-------------------------------------------------------------------------
 3768  */
 3769 static int threaded_llsc_int_aba_helper_0(llsc_int_aba_t *udata)
 3770 {
 3771     unsigned            niter = LLSC_PTR_ABA_NITER;
 3772     int                 nerrors = 0;    /* Number of errors */
 3773     unsigned            i;
 3774 
 3775     /* Main loop */
 3776     for(i=0; i<niter; i++) {
 3777         /* Initialize the shared value to 0 */
 3778         OPA_store_int(&udata->shared_val, 0);
 3779 
 3780         /* Load linked the shared value, and verify that it returns 0 */
 3781         if(0 != OPA_LL_int(&udata->shared_val)) {
 3782             OP_SUPPRESS(printf("    Unexpected return from OPA_LL_int\n"), nerrors, 20);
 3783             nerrors++;
 3784         } /* end if */
 3785 
 3786         /* Make sure shared_val is initialized before passing point 0 */
 3787         OPA_write_barrier();
 3788 
 3789         /* Point 0 */
 3790         OPA_store_int(&udata->pass_point_0, 1);
 3791 
 3792         /* Wait until thread 1 passes point 1 */
 3793         while(!OPA_load_int(&udata->pass_point_1));
 3794 
 3795         /* Make sure that change_val is loaded after passing point 1 */
 3796         OPA_read_barrier();
 3797 
 3798         /* Store conditional 1 to the shared value */
 3799         if(OPA_SC_int(&udata->shared_val, 1)) {
 3800             /* SC succeeded, make sure that the shared value was not changed by
 3801              * thread 1 */
 3802             if(OPA_load_int(&udata->change_val)) {
 3803                 OP_SUPPRESS(printf("    Unexpected success of OPA_SC_int\n"), nerrors, 20);
 3804                 nerrors++;
 3805             } else
 3806                 udata->nunchanged_val++;
 3807 
 3808             /* Verify that the shared value contains 1 */
 3809             if(1 != OPA_load_int(&udata->shared_val)) {
 3810                 OP_SUPPRESS(printf("    Unexpected return from OPA_load_int after OPA_SC_int success\n"), nerrors, 20);
 3811                 nerrors++;
 3812             } /* end if */
 3813         } else {
 3814             /* SC failed, check if it was a false positive */
 3815             if(!OPA_load_int(&udata->change_val)) {
 3816                 udata->false_positives++;
 3817                 udata->nunchanged_val++;
 3818             } /* end if */
 3819 
 3820             /* Verify that the shared value contains 0 */
 3821             if(0 != OPA_load_int(&udata->shared_val)) {
 3822                 OP_SUPPRESS(printf("    Unexpected return from OPA_load_int after OPA_SC_int failure\n"), nerrors, 20);
 3823                 nerrors++;
 3824             } /* end if */
 3825         } /* end else */
 3826 
 3827         /* Reset pass_point_1 */
 3828         OPA_store_int(&udata->pass_point_1, 0);
 3829 
 3830         /* Read/write barrier to make sure we are done before we allow thread 1
 3831          * to continue */
 3832         OPA_read_write_barrier();
 3833 
 3834         /* Point 2 */
 3835         OPA_store_int(&udata->pass_point_2, 1);
 3836     } /* end for */
 3837 
 3838     /* Exit */
 3839     return(nerrors);
 3840 } /* end threaded_llsc_int_aba_helper_0() */
 3841 
 3842 
 3843 /*-------------------------------------------------------------------------
 3844  * Function: threaded_llsc_int_aba_helper_1
 3845  *
 3846  * Purpose: Helper (thread) routine 1 for test_threaded_llsc_int_aba
 3847  *
 3848  * Return: NULL
 3849  *
 3850  * Programmer: Neil Fortner
 3851  *             Tuesday, June 22, 2010
 3852  *
 3853  * Modifications:
 3854  *
 3855  *-------------------------------------------------------------------------
 3856  */
 3857 static void *threaded_llsc_int_aba_helper_1(void *_udata)
 3858 {
 3859     llsc_int_aba_t      *udata = (llsc_int_aba_t *)_udata;
 3860     unsigned            niter = LLSC_PTR_ABA_NITER;
 3861     unsigned            i;
 3862 
 3863     /* Main loop */
 3864     for(i=0; i<niter; i++) {
 3865         /* Decide if we are changing the shared value in this iteration */
 3866         OPA_store_int(&udata->change_val, rand() % 2);
 3867 
 3868         /* Wait until thread 0 passes point 0 */
 3869         while(!OPA_load_int(&udata->pass_point_0));
 3870 
 3871         /* Reset pass_point_0 */
 3872         OPA_store_int(&udata->pass_point_0, 0);
 3873 
 3874         if(OPA_load_int(&udata->change_val)) {
 3875             /* Set the shared value to 1 then back to 0.  This is the "ABA" part
 3876              * of this test */
 3877             OPA_store_int(&udata->shared_val, 1);
 3878             OPA_store_int(&udata->shared_val, 0);
 3879         } /* end if */
 3880 
 3881         /* Write barrier to make sure the shared_val (if appropriate) and
 3882          * change_val are actually updated before we mark point 1 as passed */
 3883         OPA_write_barrier();
 3884 
 3885         /* Point 1 */
 3886         OPA_store_int(&udata->pass_point_1, 1);
 3887 
 3888         /* Wait until thread 0 passes point 2 */
 3889         while(!OPA_load_int(&udata->pass_point_2));
 3890 
 3891         /* Reset pass_point_2 */
 3892         OPA_store_int(&udata->pass_point_2, 0);
 3893     } /* end for */
 3894 
 3895     /* Exit */
 3896     pthread_exit(NULL);
 3897 } /* end threaded_llsc_int_aba_helper_1() */
 3898 #endif /* OPA_HAVE_PTHREAD_H && OPA_LL_SC_SUPPORTED */
 3899 
 3900 
 3901 /*-------------------------------------------------------------------------
 3902  * Function: test_threaded_llsc_int_aba
 3903  *
 3904  * Purpose: Tests functionality of OPA_LL_int and OPA_SC_int.  Launches 2
 3905  *          threads, which manipulate a shared value in such a way that it
 3906  *          is changed to a new value then back to the original value
 3907  *          before the other thread can call OPA_SC_int.
 3908  *
 3909  * Return: Success: 0
 3910  *         Failure: 1
 3911  *
 3912  * Programmer: Neil Fortner
 3913  *             Tuesday, June 22, 2010
 3914  *
 3915  * Modifications:
 3916  *
 3917  *-------------------------------------------------------------------------
 3918  */
 3919 static int test_threaded_llsc_int_aba(void)
 3920 {
 3921 #if defined(OPA_HAVE_PTHREAD_H) && defined(OPA_LL_SC_SUPPORTED)
 3922     pthread_t           thread;         /* Thread */
 3923     pthread_attr_t      ptattr;         /* Thread attributes */
 3924     llsc_int_aba_t      thread_data;    /* User data struct for threads */
 3925     int                 nerrors = 0;    /* Number of errors */
 3926     unsigned            i;
 3927 
 3928     TESTING("integer LL/SC ABA", 2);
 3929 
 3930     /* Initialize thread data struct */
 3931     OPA_store_int(&thread_data.shared_val, 0);
 3932     OPA_store_int(&thread_data.pass_point_0, 0);
 3933     OPA_store_int(&thread_data.pass_point_1, 0);
 3934     OPA_store_int(&thread_data.pass_point_2, 0);
 3935     OPA_store_int(&thread_data.change_val, 0);
 3936     thread_data.false_positives = 0;
 3937     thread_data.nunchanged_val = 0;
 3938 
 3939     /* Set threads to be joinable */
 3940     pthread_attr_init(&ptattr);
 3941     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
 3942 
 3943     /* Create the threads */
 3944     if(pthread_create(&thread, &ptattr, threaded_llsc_int_aba_helper_1,
 3945             &thread_data)) TEST_ERROR;
 3946     nerrors = threaded_llsc_int_aba_helper_0(&thread_data);
 3947 
 3948     /* Free the attribute */
 3949     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
 3950 
 3951     /* Join thread 1 */
 3952     if(pthread_join(thread, NULL)) TEST_ERROR;
 3953 
 3954     /* Check if thread 0 returned any errors */
 3955     if(nerrors) TEST_ERROR;
 3956 
 3957     /* Print a warning if OPA_SC_int never succeeded, otherwise pass */
 3958     if(thread_data.false_positives == thread_data.nunchanged_val) {
 3959         WARNING();
 3960         printf("    OPA_SC_int never succeeded.  LL/SC appears to be weak.\n");
 3961     } else
 3962         PASSED();
 3963 
 3964     /* Report the number of false positives */
 3965     printf("    False positives: %d / %d\n", thread_data.false_positives,
 3966             thread_data.nunchanged_val);
 3967 
 3968 #else /* OPA_HAVE_PTHREAD_H && OPA_LL_SC_SUPPORTED */
 3969     TESTING("integer LL/SC ABA", 0);
 3970     SKIPPED();
 3971 #  if !defined(OPA_HAVE_PTHREAD_H)
 3972     puts("    pthread.h not available");
 3973 #  else /* OPA_HAVE_PTHREAD_H */
 3974     puts("    LL/SC not available");
 3975 #  endif /* OPA_HAVE_PTHREAD_H */
 3976 #endif /* OPA_HAVE_PTHREAD_H && OPA_LL_SC_SUPPORTED */
 3977 
 3978     return 0;
 3979 
 3980 #if defined(OPA_HAVE_PTHREAD_H) && defined(OPA_LL_SC_SUPPORTED)
 3981 error:
 3982     printf("    False positives: %d / %d\n", thread_data.false_positives,
 3983             thread_data.nunchanged_val);
 3984     return 1;
 3985 #endif /* OPA_HAVE_PTHREAD_H && OPA_LL_SC_SUPPORTED */
 3986 } /* end test_threaded_llsc_int_aba() */
 3987 
 3988 
 3989 #if defined(OPA_HAVE_PTHREAD_H) && defined(OPA_LL_SC_SUPPORTED)
 3990 /*-------------------------------------------------------------------------
 3991  * Function: threaded_llsc_ptr_aba_helper_0
 3992  *
 3993  * Purpose: Helper (thread) routine 0 for test_threaded_llsc_ptr_aba
 3994  *
 3995  * Return: Number of errors
 3996  *
 3997  * Programmer: Neil Fortner
 3998  *             Tuesday, June 22, 2010
 3999  *
 4000  * Modifications:
 4001  *
 4002  *-------------------------------------------------------------------------
 4003  */
 4004 static int threaded_llsc_ptr_aba_helper_0(llsc_ptr_aba_t *udata)
 4005 {
 4006     unsigned            niter = LLSC_INT_ABA_NITER;
 4007     int                 nerrors = 0;    /* Number of errors */
 4008     unsigned            i;
 4009 
 4010     /* Main loop */
 4011     for(i=0; i<niter; i++) {
 4012         /* Initialize the shared value to 0 */
 4013         OPA_store_ptr(&udata->shared_val, (void *) 0);
 4014 
 4015         /* Load linked the shared value, and verify that it returns 0 */
 4016         if((void *) 0 != OPA_LL_ptr(&udata->shared_val)) {
 4017             OP_SUPPRESS(printf("    Unexpected return from OPA_LL_ptr\n"), nerrors, 20);
 4018             nerrors++;
 4019         } /* end if */
 4020 
 4021         /* Make sure shared_val is initialized before passing point 0 */
 4022         OPA_write_barrier();
 4023 
 4024         /* Point 0 */
 4025         OPA_store_int(&udata->pass_point_0, 1);
 4026 
 4027         /* Wait until thread 1 passes point 1 */
 4028         while(!OPA_load_int(&udata->pass_point_1));
 4029 
 4030         /* Make sure that change_val is loaded after passing point 1 */
 4031         OPA_read_barrier();
 4032 
 4033         /* Store conditional 1 to the shared value */
 4034         if(OPA_SC_ptr(&udata->shared_val, (void *) ((int *) 0 + 1))) {
 4035             /* SC succeeded, make sure that the shared value was not changed by
 4036              * thread 1 */
 4037             if(OPA_load_int(&udata->change_val)) {
 4038                 OP_SUPPRESS(printf("    Unexpected success of OPA_SC_ptr\n"), nerrors, 20);
 4039                 nerrors++;
 4040             } else
 4041                 udata->nunchanged_val++;
 4042 
 4043             /* Verify that the shared value contains 1 */
 4044             if((void *) ((int *) 0 + 1) != OPA_load_ptr(&udata->shared_val)) {
 4045                 OP_SUPPRESS(printf("    Unexpected return from OPA_load_ptr after OPA_SC_int success\n"), nerrors, 20);
 4046                 nerrors++;
 4047             } /* end if */
 4048         } else {
 4049             /* SC failed, check if it was a false positive */
 4050             if(!OPA_load_int(&udata->change_val)) {
 4051                 udata->false_positives++;
 4052                 udata->nunchanged_val++;
 4053             } /* end if */
 4054 
 4055             /* Verify that the shared value contains 0 */
 4056             if((void *) 0 != OPA_load_ptr(&udata->shared_val)) {
 4057                 OP_SUPPRESS(printf("    Unexpected return from OPA_load_ptr after OPA_SC_int failure\n"), nerrors, 20);
 4058                 nerrors++;
 4059             } /* end if */
 4060         } /* end else */
 4061 
 4062         /* Reset pass_point_1 */
 4063         OPA_store_int(&udata->pass_point_1, 0);
 4064 
 4065         /* Read/write barrier to make sure we are done before we allow thread 1
 4066          * to continue */
 4067         OPA_read_write_barrier();
 4068 
 4069         /* Point 2 */
 4070         OPA_store_int(&udata->pass_point_2, 1);
 4071     } /* end for */
 4072 
 4073     /* Exit */
 4074     return(nerrors);
 4075 } /* end threaded_llsc_ptr_aba_helper_0() */
 4076 
 4077 
 4078 /*-------------------------------------------------------------------------
 4079  * Function: threaded_llsc_ptr_aba_helper_1
 4080  *
 4081  * Purpose: Helper (thread) routine 1 for test_threaded_llsc_ptr_aba
 4082  *
 4083  * Return: NULL
 4084  *
 4085  * Programmer: Neil Fortner
 4086  *             Tuesday, June 22, 2010
 4087  *
 4088  * Modifications:
 4089  *
 4090  *-------------------------------------------------------------------------
 4091  */
 4092 static void *threaded_llsc_ptr_aba_helper_1(void *_udata)
 4093 {
 4094     llsc_ptr_aba_t      *udata = (llsc_ptr_aba_t *)_udata;
 4095     unsigned            niter = LLSC_INT_ABA_NITER;
 4096     unsigned            i;
 4097 
 4098     /* Main loop */
 4099     for(i=0; i<niter; i++) {
 4100         /* Decide if we are changing the shared value in this iteration */
 4101         OPA_store_int(&udata->change_val, rand() % 2);
 4102 
 4103         /* Wait until thread 0 passes point 0 */
 4104         while(!OPA_load_int(&udata->pass_point_0));
 4105 
 4106         /* Reset pass_point_0 */
 4107         OPA_store_int(&udata->pass_point_0, 0);
 4108 
 4109         if(OPA_load_int(&udata->change_val)) {
 4110             /* Set the shared value to 1 then back to 0.  This is the "ABA" part
 4111              * of this test */
 4112             OPA_store_ptr(&udata->shared_val, (void *) ((int *) 0 + 1));
 4113             OPA_store_ptr(&udata->shared_val, (void *) 0);
 4114         } /* end if */
 4115 
 4116         /* Write barrier to make sure the shared_val (if appropriate) and
 4117          * change_val are actually updated before we mark point 1 as passed */
 4118         OPA_write_barrier();
 4119 
 4120         /* Point 1 */
 4121         OPA_store_int(&udata->pass_point_1, 1);
 4122 
 4123         /* Wait until thread 0 passes point 2 */
 4124         while(!OPA_load_int(&udata->pass_point_2));
 4125 
 4126         /* Reset pass_point_2 */
 4127         OPA_store_int(&udata->pass_point_2, 0);
 4128     } /* end for */
 4129 
 4130     /* Exit */
 4131     pthread_exit(NULL);
 4132 } /* end threaded_llsc_ptr_aba_helper_1() */
 4133 #endif /* OPA_HAVE_PTHREAD_H && OPA_LL_SC_SUPPORTED */
 4134 
 4135 
 4136 /*-------------------------------------------------------------------------
 4137  * Function: test_threaded_llsc_ptr_aba
 4138  *
 4139  * Purpose: Tests functionality of OPA_LL_ptr and OPA_SC_ptr.  Launches 2
 4140  *          threads, which manipulate a shared value in such a way that it
 4141  *          is changed to a new value then back to the original value
 4142  *          before the other thread can call OPA_SC_ptr.
 4143  *
 4144  * Return: Success: 0
 4145  *         Failure: 1
 4146  *
 4147  * Programmer: Neil Fortner
 4148  *             Tuesday, June 22, 2010
 4149  *
 4150  * Modifications:
 4151  *
 4152  *-------------------------------------------------------------------------
 4153  */
 4154 static int test_threaded_llsc_ptr_aba(void)
 4155 {
 4156 #if defined(OPA_HAVE_PTHREAD_H) && defined(OPA_LL_SC_SUPPORTED)
 4157     pthread_t           thread;         /* Thread */
 4158     pthread_attr_t      ptattr;         /* Thread attributes */
 4159     llsc_ptr_aba_t      thread_data;    /* User data struct for threads */
 4160     int                 nerrors = 0;    /* Number of errors */
 4161     unsigned            i;
 4162 
 4163     TESTING("pointer LL/SC ABA", 2);
 4164 
 4165     /* Initialize thread data struct */
 4166     OPA_store_ptr(&thread_data.shared_val, (void *) 0);
 4167     OPA_store_int(&thread_data.pass_point_0, 0);
 4168     OPA_store_int(&thread_data.pass_point_1, 0);
 4169     OPA_store_int(&thread_data.pass_point_2, 0);
 4170     OPA_store_int(&thread_data.change_val, 0);
 4171     thread_data.false_positives = 0;
 4172     thread_data.nunchanged_val = 0;
 4173 
 4174     /* Set threads to be joinable */
 4175     pthread_attr_init(&ptattr);
 4176     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
 4177 
 4178     /* Create the threads */
 4179     if(pthread_create(&thread, &ptattr, threaded_llsc_ptr_aba_helper_1,
 4180             &thread_data)) TEST_ERROR;
 4181     nerrors = threaded_llsc_ptr_aba_helper_0(&thread_data);
 4182 
 4183     /* Free the attribute */
 4184     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
 4185 
 4186     /* Join thread 1 */
 4187     if(pthread_join(thread, NULL)) TEST_ERROR;
 4188 
 4189     /* Check if thread 0 returned any errors */
 4190     if(nerrors) TEST_ERROR;
 4191 
 4192     /* Print a warning if OPA_SC_int never succeeded, otherwise pass */
 4193     if(thread_data.false_positives == thread_data.nunchanged_val) {
 4194         WARNING();
 4195         printf("    OPA_SC_ptr never succeeded.  LL/SC appears to be weak.\n");
 4196     } else
 4197         PASSED();
 4198 
 4199     /* Report the number of false positives */
 4200     printf("    False positives: %d / %d\n", thread_data.false_positives,
 4201             thread_data.nunchanged_val);
 4202 
 4203 #else /* OPA_HAVE_PTHREAD_H && OPA_LL_SC_SUPPORTED */
 4204     TESTING("pointer LL/SC ABA", 0);
 4205     SKIPPED();
 4206 #  if !defined(OPA_HAVE_PTHREAD_H)
 4207     puts("    pthread.h not available");
 4208 #  else /* OPA_HAVE_PTHREAD_H */
 4209     puts("    LL/SC not available");
 4210 #  endif /* OPA_HAVE_PTHREAD_H */
 4211 #endif /* OPA_HAVE_PTHREAD_H && OPA_LL_SC_SUPPORTED */
 4212 
 4213     return 0;
 4214 
 4215 #if defined(OPA_HAVE_PTHREAD_H) && defined(OPA_LL_SC_SUPPORTED)
 4216 error:
 4217     printf("    False positives: %d / %d\n", thread_data.false_positives,
 4218             thread_data.nunchanged_val);
 4219     return 1;
 4220 #endif /* OPA_HAVE_PTHREAD_H && OPA_LL_SC_SUPPORTED */
 4221 } /* end test_threaded_llsc_ptr_aba() */
 4222 
 4223 
 4224 #if defined(OPA_HAVE_PTHREAD_H) && defined(OPA_LL_SC_SUPPORTED)
 4225 /*-------------------------------------------------------------------------
 4226  * Function: threaded_llsc_int_stack_push
 4227  *
 4228  * Purpose: "Push" routine for test_threaded_llsc_int_stack
 4229  *
 4230  * Return: NULL
 4231  *
 4232  * Programmer: Neil Fortner
 4233  *             Wednesday, June 23, 2010
 4234  *
 4235  * Modifications:
 4236  *
 4237  *-------------------------------------------------------------------------
 4238  */
 4239 static void *threaded_llsc_int_stack_push(void *_udata)
 4240 {
 4241     llsc_int_stack_t    *udata = (llsc_int_stack_t *)_udata;
 4242     llsc_int_stack_obj_t *obj = udata->objs[udata->obj];
 4243     int                 tmp_head;
 4244     unsigned            niter = LLSC_INT_STACK_NITER;
 4245     unsigned            i, j;
 4246 
 4247     /* Main loop */
 4248     for(i=0; i<niter && !OPA_load_int(udata->failed); i++) {
 4249         /* Acquire object */
 4250         j = 0;
 4251         while(OPA_cas_int(&obj->on_stack, 0, 1)) {
 4252             OPA_TEST_YIELD();
 4253             if(++j == LLSC_INT_STACK_NLOOP)
 4254                 break;
 4255         } /* end while */
 4256 
 4257         /* Check if we failed to acquire the object */
 4258         if(j == LLSC_INT_STACK_NLOOP)
 4259             continue;
 4260 
 4261         /* Push object onto stack */
 4262         do {
 4263             tmp_head = OPA_load_int(udata->head);
 4264             OPA_store_int(&obj->next, tmp_head);
 4265             /* don't let the "on_stack" CAS or the "next" store pass the "head" CAS */
 4266             OPA_write_barrier();
 4267         } while(tmp_head != OPA_cas_int(udata->head, tmp_head, udata->obj));
 4268 
 4269         /* Increment the number of successful pushes */
 4270         udata->nsuccess++;
 4271     } /* end for */
 4272 
 4273     /* don't allow npusher's decr to be perceived as happening before the pushes
 4274      * are visible */
 4275     OPA_write_barrier();
 4276 
 4277     /* Mark this thread as having completed */
 4278     OPA_decr_int(udata->npushers);
 4279 
 4280     /* Exit */
 4281     if(udata->master_thread)
 4282         return(NULL);
 4283     else
 4284         pthread_exit(NULL);
 4285 } /* end threaded_llsc_int_stack_push() */
 4286 
 4287 /*-------------------------------------------------------------------------
 4288  * Function: threaded_llsc_int_stack_pop
 4289  *
 4290  * Purpose: "Pop" routine for test_threaded_llsc_int_stack
 4291  *
 4292  * Return: NULL
 4293  *
 4294  * Programmer: Neil Fortner
 4295  *             Wednesday, June 23, 2010
 4296  *
 4297  * Modifications:
 4298  *
 4299  *-------------------------------------------------------------------------
 4300  */
 4301 static void *threaded_llsc_int_stack_pop(void *_udata)
 4302 {
 4303     llsc_int_stack_t    *udata = (llsc_int_stack_t *)_udata;
 4304     llsc_int_stack_obj_t *obj = NULL;
 4305     int                 tmp_obj;
 4306     unsigned            i;
 4307 
 4308     /* Main loop */
 4309     do {
 4310         /* Load-linked the object */
 4311         if(-1 == (tmp_obj = OPA_LL_int(udata->head))) {
 4312             OPA_TEST_YIELD();
 4313             continue;
 4314         } /* end if */
 4315         obj = udata->objs[tmp_obj];
 4316 
 4317         /* Get the next object */
 4318         tmp_obj = OPA_load_int(&obj->next);
 4319 
 4320         /* Store conditional the "next" object as the new head */
 4321         if(OPA_SC_int(udata->head, tmp_obj)) {
 4322             /* ensure that the head data is perceived as stored before reading
 4323              * the on_stack variable */
 4324             OPA_read_write_barrier();
 4325 
 4326             /* Make sure this object was marked as on the stack */
 4327             if(!OPA_load_int(&obj->on_stack)) {
 4328                 OP_SUPPRESS(printf("    Popped object was not on the stack\n"),
 4329                         udata->nerrors, 20);
 4330                 udata->nerrors++;
 4331 
 4332                 if(udata->nerrors >= 1000000) {
 4333                     /* Cause all threads to break out so the test fails in a
 4334                      * reasonable amount of time */
 4335                     OPA_store_int(udata->failed, 1);
 4336                     break;
 4337                 } /* end if */
 4338             } /* end if */
 4339 
 4340             /* Mark the object as off the stack, release for pushing */
 4341             OPA_store_int(&obj->on_stack, 0);
 4342 
 4343             /* Increment the number of successful pops */
 4344             udata->nsuccess++;
 4345         } /* end if */
 4346 
 4347         /* We could include a read_write_barrier here to enforce ordering
 4348          * between pop attempt above and the npushers load below, but leaving it
 4349          * out is safe because npushers starts at max and monotonically
 4350          * decreases.  Worst case is a few extra iterations. */
 4351     } while(OPA_load_int(udata->npushers) && !OPA_load_int(udata->failed));
 4352 
 4353     pthread_exit(NULL);
 4354 } /* end threaded_llsc_int_stack_pop() */
 4355 #endif /* OPA_HAVE_PTHREAD_H && OPA_LL_SC_SUPPORTED */
 4356 
 4357 
 4358 /*-------------------------------------------------------------------------
 4359  * Function: test_threaded_llsc_int_stack
 4360  *
 4361  * Purpose: Tests atomicity of OPA_LL_int and OPA_SC_int.  Launches
 4362  *          nthreads threads, subdivided into nthreads/3 or 2 groups,
 4363  *          whichever is greater.  One group of threads continually tries
 4364  *          to pop objects off a shared stack using LL/SC, while the
 4365  *          other groups all try to push objects onto the stack.  The
 4366  *          algorithm of the pop routine is such that LL/SC must be able
 4367  *          to detect ABA conditions, or the wrong object might be marked
 4368  *          as the head of the stack.
 4369  *
 4370  * Return: Success: 0
 4371  *         Failure: 1
 4372  *
 4373  * Programmer: Neil Fortner
 4374  *             Wednesday, June 23, 2010
 4375  *
 4376  * Modifications:
 4377  *
 4378  *-------------------------------------------------------------------------
 4379  */
 4380 static int test_threaded_llsc_int_stack(void)
 4381 {
 4382 #if defined(OPA_HAVE_PTHREAD_H) && defined(OPA_LL_SC_SUPPORTED)
 4383     pthread_t           *threads = NULL; /* Threads */
 4384     pthread_attr_t      ptattr;         /* Thread attributes */
 4385     llsc_int_stack_t    *thread_data = NULL; /* User data structs for threads */
 4386     llsc_int_stack_obj_t **objs = NULL; /* Array of pointers to objects to put on stack */
 4387     int                 nobjs;          /* Number of objects */
 4388     OPA_int_t           head;           /* The head of the stack */
 4389     OPA_int_t           npushers;       /* Number of "push" threads running */
 4390     OPA_int_t           failed;         /* Whether the test has failed and must be terminated */
 4391     int                 threads_per_group; /* Threads per group */
 4392     int                 npops = 0;      /* Total number of times an object was popped */
 4393     int                 npushes = 0;    /* Total number of times an object was pushed */
 4394     int                 non_stack = 0;  /* Number of objects on the stack */
 4395     int                 nerrors = 0;    /* Number of errors returned from threads */
 4396     int                 warned = 0;     /* Whether a warning message has been issued */
 4397     unsigned            nthreads = num_threads[curr_test];
 4398     int                 i;
 4399 
 4400     /* Don't test with only 1 thread */
 4401     if(nthreads < 2)
 4402         return 0;
 4403 
 4404     TESTING("integer LL/SC stack", nthreads);
 4405 
 4406     /* Allocate array of threads */
 4407     if(NULL == (threads = (pthread_t *) malloc((nthreads - 1) * sizeof(pthread_t))))
 4408         TEST_ERROR;
 4409 
 4410     /* Allocate array of thread data */
 4411     if(NULL == (thread_data =
 4412             (llsc_int_stack_t *) calloc(nthreads, sizeof(llsc_int_stack_t))))
 4413         TEST_ERROR;
 4414 
 4415     /* Calculate number of groups and threads per group */
 4416     if((nthreads / LLSC_INT_STACK_TPG) >= 2)
 4417         threads_per_group = LLSC_INT_STACK_TPG;
 4418     else
 4419         threads_per_group = (nthreads + 1) / 2;
 4420     nobjs = (nthreads - 1) / threads_per_group;
 4421     OPA_store_int(&npushers, nthreads - threads_per_group);
 4422 
 4423     /* Allocate objects.  Allocate each object individually instead of one large
 4424      * array to add a random component to which objects share a cache line.  The
 4425      * "objs" array is also used to allow integers to function as "pointers" to
 4426      * objects, by being an index into this array. */
 4427     if(NULL == (objs = (llsc_int_stack_obj_t **) malloc(nobjs * sizeof(llsc_int_stack_obj_t *))))
 4428         TEST_ERROR;
 4429     for(i=0; i<nobjs; i++) {
 4430         if(NULL == (objs[i] = (llsc_int_stack_obj_t *) malloc(sizeof(llsc_int_stack_obj_t))))
 4431             TEST_ERROR;
 4432         OPA_store_int(&objs[i]->on_stack, 0);
 4433         OPA_store_int(&objs[i]->next, -1);
 4434     } /* end for */
 4435 
 4436     /* Initialize thread data structs */
 4437     OPA_store_int(&head, -1);
 4438     OPA_store_int(&failed, 0);
 4439     for(i=0; i<nthreads; i++) {
 4440         thread_data[i].head = &head;
 4441         thread_data[i].objs = objs;
 4442         thread_data[i].obj = (i / threads_per_group) - 1;
 4443         thread_data[i].npushers = &npushers;
 4444         thread_data[i].failed = &failed;
 4445     } /* end for */
 4446     thread_data[nthreads-1].master_thread = 1;
 4447 
 4448     /* Set threads to be joinable */
 4449     pthread_attr_init(&ptattr);
 4450     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
 4451 
 4452     /* Create the threads */
 4453     for(i=0; i<(nthreads - 1); i++) {
 4454         if(i < threads_per_group) {
 4455             if(pthread_create(&threads[i], &ptattr, threaded_llsc_int_stack_pop,
 4456                     &thread_data[i])) TEST_ERROR;
 4457         } else
 4458             if(pthread_create(&threads[i], &ptattr, threaded_llsc_int_stack_push,
 4459                     &thread_data[i])) TEST_ERROR;
 4460     } /* end for */
 4461     (void)threaded_llsc_int_stack_push(&thread_data[i]);
 4462 
 4463     /* Free the attribute */
 4464     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
 4465 
 4466     /* Join the threads */
 4467     for (i=0; i<(nthreads - 1); i++)
 4468         if(pthread_join(threads[i], NULL)) TEST_ERROR;
 4469 
 4470     /* Check for any errors returned from any threads */
 4471     for(i=0; i<nthreads; i++)
 4472         nerrors += thread_data[i].nerrors;
 4473     if(nerrors)
 4474         FAIL_OP_ERROR(printf("    %d error%s encountered in thread routines\n", nerrors,
 4475                 nerrors == 1 ? "" : "s"));
 4476 
 4477     /* Walk the stack, and make sure it is consistent */
 4478     i = OPA_load_int(&head);
 4479     while(i >= 0 && i < nobjs) {
 4480         /* Make sure it is marked as "on_stack" */
 4481         if(1 != OPA_load_int(&objs[i]->on_stack))
 4482             FAIL_OP_ERROR(printf("    Unexpected value of \"on stack\" for object %d: %d Expected: 1\n",
 4483                     i, OPA_load_int(&objs[i]->on_stack)));
 4484 
 4485         /* Change "on_stack" to 2, so if it appears again it will fail */
 4486         OPA_store_int(&objs[i]->on_stack, 2);
 4487 
 4488         /* Advance to next object in stack */
 4489         non_stack++;
 4490         i = OPA_load_int(&objs[i]->next);
 4491     } /* end while */
 4492 
 4493     /* Make sure the last "next" pointer was -1 */
 4494     if(i != -1)
 4495         FAIL_OP_ERROR(printf("    Last \"next\" pointer was %d Expected: -1\n", i));
 4496 
 4497     /* Walk through all of the objects and make sure that they are all either
 4498      * off the stack or have been encountered by walking the stack */
 4499     for(i=0; i<nobjs; i++)
 4500         if(OPA_load_int(&objs[i]->on_stack) != 0
 4501                 && OPA_load_int(&objs[i]->on_stack) != 2)
 4502             FAIL_OP_ERROR(printf("    After walking the stack, object %d's \"on_stack\" set to %d Expected: 0 or 2\n",
 4503                     i, OPA_load_int(&objs[i]->on_stack)));
 4504 
 4505     /* Make sure the number of successessful pops is consistent with the number
 4506      * of pushes */
 4507     for(i=0; i<threads_per_group; i++)
 4508         npops += thread_data[i].nsuccess;
 4509     for(i=threads_per_group; i<nthreads; i++)
 4510         npushes += thread_data[i].nsuccess;
 4511     if(npops != npushes - non_stack)
 4512         FAIL_OP_ERROR(printf("    Unexpected number of pops: %d Expected: %d\n",
 4513                 npops, npushes - non_stack));
 4514 
 4515     /* Check if there were any failed pushes (this is a warning, not an error)
 4516      */
 4517     if(npushes != (nthreads - threads_per_group) * LLSC_INT_STACK_NITER) {
 4518         WARNING();
 4519         printf("    Only %d/%d pushes succeeded.  There may be an issue with fairness.\n",
 4520                 npushes, (nthreads - threads_per_group) * LLSC_INT_STACK_NITER);
 4521         warned = 1;
 4522     } /* end if */
 4523 
 4524     /* Free memory */
 4525     for(i=0; i<nobjs; i++)
 4526         free(objs[i]);
 4527     free(objs);
 4528     free(threads);
 4529     free(thread_data);
 4530 
 4531     if(!warned)
 4532         PASSED();
 4533 
 4534 #else /* OPA_HAVE_PTHREAD_H && OPA_LL_SC_SUPPORTED */
 4535     TESTING("integer LL/SC stack", 0);
 4536     SKIPPED();
 4537 #  if !defined(OPA_HAVE_PTHREAD_H)
 4538     puts("    pthread.h not available");
 4539 #  else /* OPA_HAVE_PTHREAD_H */
 4540     puts("    LL/SC not available");
 4541 #  endif /* OPA_HAVE_PTHREAD_H */
 4542 #endif /* OPA_HAVE_PTHREAD_H && OPA_LL_SC_SUPPORTED */
 4543 
 4544     return 0;
 4545 
 4546 #if defined(OPA_HAVE_PTHREAD_H) && defined(OPA_LL_SC_SUPPORTED)
 4547 error:
 4548     if(objs) {
 4549         for(i=0; i<nobjs; i++)
 4550             if(objs[i])
 4551                 free(objs[i]);
 4552         free(objs);
 4553     } /* end if */
 4554     if(threads) free(threads);
 4555     if(thread_data) free(thread_data);
 4556     return 1;
 4557 #endif /* OPA_HAVE_PTHREAD_H && OPA_LL_SC_SUPPORTED */
 4558 } /* end test_threaded_llsc_int_stack() */
 4559 
 4560 
 4561 #if defined(OPA_HAVE_PTHREAD_H) && defined(OPA_LL_SC_SUPPORTED)
 4562 /*-------------------------------------------------------------------------
 4563  * Function: threaded_llsc_ptr_stack_push
 4564  *
 4565  * Purpose: "Push" routine for test_threaded_llsc_ptr_stack
 4566  *
 4567  * Return: NULL
 4568  *
 4569  * Programmer: Neil Fortner
 4570  *             Friday, June 25, 2010
 4571  *
 4572  * Modifications:
 4573  *
 4574  *-------------------------------------------------------------------------
 4575  */
 4576 static void *threaded_llsc_ptr_stack_push(void *_udata)
 4577 {
 4578     llsc_ptr_stack_t    *udata = (llsc_ptr_stack_t *)_udata;
 4579     llsc_ptr_stack_obj_t *obj = udata->obj;
 4580     llsc_ptr_stack_obj_t *tmp_head = NULL;
 4581     unsigned            niter = LLSC_PTR_STACK_NITER;
 4582     unsigned            i, j;
 4583 
 4584     /* Main loop */
 4585     for(i=0; i<niter && !OPA_load_int(udata->failed); i++) {
 4586         /* Acquire object */
 4587         j = 0;
 4588         while(OPA_cas_int(&obj->on_stack, 0, 1)) {
 4589             OPA_TEST_YIELD();
 4590             if(++j == LLSC_PTR_STACK_NLOOP)
 4591                 break;
 4592         } /* end while */
 4593 
 4594         /* Check if we failed to acquire the object */
 4595         if(j == LLSC_PTR_STACK_NLOOP)
 4596             continue;
 4597 
 4598         /* Push object onto stack */
 4599         do {
 4600             tmp_head = OPA_load_ptr(udata->head);
 4601             OPA_store_ptr(&obj->next, tmp_head);
 4602             /* don't let the "on_stack" CAS or the "next" store pass the "head" CAS */
 4603             OPA_write_barrier();
 4604         } while(tmp_head != OPA_cas_ptr(udata->head, tmp_head, obj));
 4605 
 4606         /* Increment the number of successful pushes */
 4607         udata->nsuccess++;
 4608     } /* end for */
 4609 
 4610     /* don't allow npusher's decr to be perceived as happening before the pushes
 4611      * are visible */
 4612     OPA_write_barrier();
 4613 
 4614     /* Mark this thread as having completed */
 4615     OPA_decr_int(udata->npushers);
 4616 
 4617     /* Exit */
 4618     if(udata->master_thread)
 4619         return(NULL);
 4620     else
 4621         pthread_exit(NULL);
 4622 } /* end threaded_llsc_ptr_stack_push() */
 4623 
 4624 /*-------------------------------------------------------------------------
 4625  * Function: threaded_llsc_ptr_stack_pop
 4626  *
 4627  * Purpose: "Pop" routine for test_threaded_llsc_ptr_stack
 4628  *
 4629  * Return: NULL
 4630  *
 4631  * Programmer: Neil Fortner
 4632  *             Friday, June 25, 2010
 4633  *
 4634  * Modifications:
 4635  *
 4636  *-------------------------------------------------------------------------
 4637  */
 4638 static void *threaded_llsc_ptr_stack_pop(void *_udata)
 4639 {
 4640     llsc_ptr_stack_t    *udata = (llsc_ptr_stack_t *)_udata;
 4641     llsc_ptr_stack_obj_t *obj = NULL;
 4642     llsc_ptr_stack_obj_t *next = NULL;
 4643     unsigned            i;
 4644 
 4645     /* Main loop */
 4646     do {
 4647         /* Load-linked the object */
 4648         if(NULL == (obj = OPA_LL_ptr(udata->head))) {
 4649             OPA_TEST_YIELD();
 4650             continue;
 4651         } /* end if */
 4652 
 4653         /* Get the next object */
 4654         next = OPA_load_ptr(&obj->next);
 4655 
 4656         /* Store conditional the "next" object as the new head */
 4657         if(OPA_SC_ptr(udata->head, next)) {
 4658             /* ensure that the head data is perceived as stored before reading
 4659              * the on_stack variable */
 4660             OPA_read_write_barrier();
 4661 
 4662             /* Make sure this object was marked as on the stack */
 4663             if(!OPA_load_int(&obj->on_stack)) {
 4664                 OP_SUPPRESS(printf("    Popped object was not on the stack\n"),
 4665                         udata->nerrors, 20);
 4666                 udata->nerrors++;
 4667 
 4668                 if(udata->nerrors >= 1000000) {
 4669                     /* Cause all threads to break out so the test fails in a
 4670                      * reasonable amount of time */
 4671                     OPA_store_int(udata->failed, 1);
 4672                     break;
 4673                 } /* end if */
 4674             } /* end if */
 4675 
 4676             /* Mark the object as off the stack, release for pushing */
 4677             OPA_store_int(&obj->on_stack, 0);
 4678 
 4679             /* Increment the number of successful pops */
 4680             udata->nsuccess++;
 4681         } /* end if */
 4682 
 4683         /* We could include a read_write_barrier here to enforce ordering
 4684          * between pop attempt above and the npushers load below, but leaving it
 4685          * out is safe because npushers starts at max and monotonically
 4686          * decreases.  Worst case is a few extra iterations. */
 4687     } while(OPA_load_int(udata->npushers) && !OPA_load_int(udata->failed));
 4688 
 4689     pthread_exit(NULL);
 4690 } /* end threaded_llsc_ptr_stack_pop() */
 4691 #endif /* OPA_HAVE_PTHREAD_H && OPA_LL_SC_SUPPORTED */
 4692 
 4693 
 4694 /*-------------------------------------------------------------------------
 4695  * Function: test_threaded_llsc_ptr_stack
 4696  *
 4697  * Purpose: Tests atomicity of OPA_LL_ptr and OPA_SC_ptr.  Launches
 4698  *          nthreads threads, subdivided into nthreads/3 or 2 groups,
 4699  *          whichever is greater.  One group of threads continually tries
 4700  *          to pop objects off a shared stack using LL/SC, while the
 4701  *          other groups all try to push objects onto the stack.  The
 4702  *          algorithm of the pop routine is such that LL/SC must be able
 4703  *          to detect ABA conditions, or the wrong object might be marked
 4704  *          as the head of the stack.
 4705  *
 4706  * Return: Success: 0
 4707  *         Failure: 1
 4708  *
 4709  * Programmer: Neil Fortner
 4710  *             Friday, June 25, 2010
 4711  *
 4712  * Modifications:
 4713  *
 4714  *-------------------------------------------------------------------------
 4715  */
 4716 static int test_threaded_llsc_ptr_stack(void)
 4717 {
 4718 #if defined(OPA_HAVE_PTHREAD_H) && defined(OPA_LL_SC_SUPPORTED)
 4719     pthread_t           *threads = NULL; /* Threads */
 4720     pthread_attr_t      ptattr;         /* Thread attributes */
 4721     llsc_ptr_stack_t    *thread_data = NULL; /* User data structs for threads */
 4722     llsc_ptr_stack_obj_t **objs = NULL; /* Array of pointers to objects to put on stack */
 4723     llsc_ptr_stack_obj_t *obj = NULL;   /* Object on stack (used while walking the stack) */
 4724     int                 nobjs;          /* Number of objects */
 4725     OPA_ptr_t           head;           /* The head of the stack */
 4726     OPA_int_t           npushers;       /* Number of "push" threads running */
 4727     OPA_int_t           failed;         /* Whether the test has failed and must be terminated */
 4728     int                 threads_per_group; /* Threads per group */
 4729     int                 npops = 0;      /* Total number of times an object was popped */
 4730     int                 npushes = 0;    /* Total number of times an object was pushed */
 4731     int                 non_stack = 0;  /* Number of objects on the stack */
 4732     int                 nerrors = 0;    /* Number of errors returned from threads */
 4733     int                 warned = 0;     /* Whether a warning message has been issued */
 4734     unsigned            nthreads = num_threads[curr_test];
 4735     int                 i;
 4736 
 4737     /* Don't test with only 1 thread */
 4738     if(nthreads < 2)
 4739         return 0;
 4740 
 4741     TESTING("pointer LL/SC stack", nthreads);
 4742 
 4743     /* Allocate array of threads */
 4744     if(NULL == (threads = (pthread_t *) malloc((nthreads - 1) * sizeof(pthread_t))))
 4745         TEST_ERROR;
 4746 
 4747     /* Allocate array of thread data */
 4748     if(NULL == (thread_data =
 4749             (llsc_ptr_stack_t *) calloc(nthreads, sizeof(llsc_ptr_stack_t))))
 4750         TEST_ERROR;
 4751 
 4752     /* Calculate number of groups and threads per group */
 4753     if((nthreads / LLSC_PTR_STACK_TPG) >= 2)
 4754         threads_per_group = LLSC_PTR_STACK_TPG;
 4755     else
 4756         threads_per_group = (nthreads + 1) / 2;
 4757     nobjs = (nthreads - 1) / threads_per_group;
 4758     OPA_store_int(&npushers, nthreads - threads_per_group);
 4759 
 4760     /* Allocate objects.  Allocate each object individually instead of one large
 4761      * array to add a random component to which objects share a cache line.  The
 4762      * "objs" array is also used to allow integers to function as "pointers" to
 4763      * objects, by being an index into this array. */
 4764     if(NULL == (objs = (llsc_ptr_stack_obj_t **) malloc(nobjs * sizeof(llsc_ptr_stack_obj_t *))))
 4765         TEST_ERROR;
 4766     for(i=0; i<nobjs; i++) {
 4767         if(NULL == (objs[i] = (llsc_ptr_stack_obj_t *) malloc(sizeof(llsc_ptr_stack_obj_t))))
 4768             TEST_ERROR;
 4769         OPA_store_int(&objs[i]->on_stack, 0);
 4770         OPA_store_ptr(&objs[i]->next, NULL);
 4771     } /* end for */
 4772 
 4773     /* Initialize thread data structs */
 4774     OPA_store_ptr(&head, NULL);
 4775     OPA_store_int(&failed, 0);
 4776     for(i=0; i<nthreads; i++) {
 4777         thread_data[i].head = &head;
 4778         if(i >= threads_per_group)
 4779             thread_data[i].obj = objs[(i / threads_per_group) - 1];
 4780         thread_data[i].npushers = &npushers;
 4781         thread_data[i].failed = &failed;
 4782     } /* end for */
 4783     thread_data[nthreads-1].master_thread = 1;
 4784 
 4785     /* Set threads to be joinable */
 4786     pthread_attr_init(&ptattr);
 4787     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
 4788 
 4789     /* Create the threads */
 4790     for(i=0; i<(nthreads - 1); i++) {
 4791         if(i < threads_per_group) {
 4792             if(pthread_create(&threads[i], &ptattr, threaded_llsc_ptr_stack_pop,
 4793                     &thread_data[i])) TEST_ERROR;
 4794         } else
 4795             if(pthread_create(&threads[i], &ptattr, threaded_llsc_ptr_stack_push,
 4796                     &thread_data[i])) TEST_ERROR;
 4797     } /* end for */
 4798     (void)threaded_llsc_ptr_stack_push(&thread_data[i]);
 4799 
 4800     /* Free the attribute */
 4801     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
 4802 
 4803     /* Join the threads */
 4804     for (i=0; i<(nthreads - 1); i++)
 4805         if(pthread_join(threads[i], NULL)) TEST_ERROR;
 4806 
 4807     /* Check for any errors returned from any threads */
 4808     for(i=0; i<nthreads; i++)
 4809         nerrors += thread_data[i].nerrors;
 4810     if(nerrors)
 4811         FAIL_OP_ERROR(printf("    %d error%s encountered in thread routines\n", nerrors,
 4812                 nerrors == 1 ? "" : "s"));
 4813 
 4814     /* Walk the stack, and make sure it is consistent */
 4815     obj = OPA_load_ptr(&head);
 4816     while(obj) {
 4817         /* Make sure it is marked as "on_stack" */
 4818         if(1 != OPA_load_int(&obj->on_stack))
 4819             FAIL_OP_ERROR(printf("    Unexpected value of \"on stack\" for object %d: %d Expected: 1\n",
 4820                     i, OPA_load_int(&obj->on_stack)));
 4821 
 4822         /* Change "on_stack" to 2, so if it appears again it will fail */
 4823         OPA_store_int(&obj->on_stack, 2);
 4824 
 4825         /* Advance to next object in stack */
 4826         non_stack++;
 4827         obj = OPA_load_ptr(&obj->next);
 4828     } /* end while */
 4829 
 4830     /* Walk through all of the objects and make sure that they are all either
 4831      * off the stack or have been encountered by walking the stack */
 4832     for(i=0; i<nobjs; i++)
 4833         if(OPA_load_int(&objs[i]->on_stack) != 0
 4834                 && OPA_load_int(&objs[i]->on_stack) != 2)
 4835             FAIL_OP_ERROR(printf("    After walking the stack, object %d's \"on_stack\" set to %d Expected: 0 or 2\n",
 4836                     i, OPA_load_int(&objs[i]->on_stack)));
 4837 
 4838     /* Make sure the number of successessful pops is consistent with the number
 4839      * of pushes */
 4840     for(i=0; i<threads_per_group; i++)
 4841         npops += thread_data[i].nsuccess;
 4842     for(i=threads_per_group; i<nthreads; i++)
 4843         npushes += thread_data[i].nsuccess;
 4844     if(npops != npushes - non_stack)
 4845         FAIL_OP_ERROR(printf("    Unexpected number of pops: %d Expected: %d\n",
 4846                 npops, npushes - non_stack));
 4847 
 4848     /* Check if there were any failed pushes (this is a warning, not an error)
 4849      */
 4850     if(npushes != (nthreads - threads_per_group) * LLSC_PTR_STACK_NITER) {
 4851         WARNING();
 4852         printf("    Only %d/%d pushes succeeded.  There may be an issue with fairness.\n",
 4853                 npushes, (nthreads - threads_per_group) * LLSC_PTR_STACK_NITER);
 4854         warned = 1;
 4855     } /* end if */
 4856 
 4857     /* Free memory */
 4858     for(i=0; i<nobjs; i++)
 4859         free(objs[i]);
 4860     free(objs);
 4861     free(threads);
 4862     free(thread_data);
 4863 
 4864     if(!warned)
 4865         PASSED();
 4866 
 4867 #else /* OPA_HAVE_PTHREAD_H && OPA_LL_SC_SUPPORTED */
 4868     TESTING("pointer LL/SC stack", 0);
 4869     SKIPPED();
 4870 #  if !defined(OPA_HAVE_PTHREAD_H)
 4871     puts("    pthread.h not available");
 4872 #  else /* OPA_HAVE_PTHREAD_H */
 4873     puts("    LL/SC not available");
 4874 #  endif /* OPA_HAVE_PTHREAD_H */
 4875 #endif /* OPA_HAVE_PTHREAD_H && OPA_LL_SC_SUPPORTED */
 4876 
 4877     return 0;
 4878 
 4879 #if defined(OPA_HAVE_PTHREAD_H) && defined(OPA_LL_SC_SUPPORTED)
 4880 error:
 4881     if(objs) {
 4882         for(i=0; i<nobjs; i++)
 4883             if(objs[i])
 4884                 free(objs[i]);
 4885         free(objs);
 4886     } /* end if */
 4887     if(threads) free(threads);
 4888     if(thread_data) free(thread_data);
 4889     return 1;
 4890 #endif /* OPA_HAVE_PTHREAD_H && OPA_LL_SC_SUPPORTED */
 4891 } /* end test_threaded_llsc_ptr_stack() */
 4892 
 4893 
 4894 /*-------------------------------------------------------------------------
 4895  * Function:    main
 4896  *
 4897  * Purpose:     Tests the opa primitives
 4898  *
 4899  * Return:      Success:        exit(0)
 4900  *
 4901  *              Failure:        exit(1)
 4902  *
 4903  * Programmer:  Neil Fortner
 4904  *              Thursday, March 19, 2009
 4905  *
 4906  * Modifications:
 4907  *
 4908  *-------------------------------------------------------------------------
 4909  */
 4910 int main(int argc, char **argv)
 4911 {
 4912     unsigned nerrors = 0;
 4913 #if defined(OPA_USE_LOCK_BASED_PRIMITIVES)
 4914     OPA_emulation_ipl_t shm_lock;
 4915     OPA_Interprocess_lock_init(&shm_lock, 1/*isLeader*/);
 4916 #endif
 4917 
 4918     srand((unsigned)time(NULL));
 4919 
 4920     /* Simple tests */
 4921     nerrors += test_simple_loadstore_int();
 4922     nerrors += test_simple_loadstore_ptr();
 4923     nerrors += test_simple_add_incr_decr();
 4924     nerrors += test_simple_decr_and_test();
 4925     nerrors += test_simple_faa_fai_fad();
 4926     nerrors += test_simple_cas_int();
 4927     nerrors += test_simple_cas_ptr();
 4928     nerrors += test_simple_swap_int();
 4929     nerrors += test_simple_swap_ptr();
 4930     nerrors += test_simple_llsc_int();
 4931     nerrors += test_simple_llsc_ptr();
 4932 
 4933     /* Threaded tests with a fixed number of threads */
 4934     nerrors += test_threaded_llsc_int_aba();
 4935     nerrors += test_threaded_llsc_ptr_aba();
 4936 
 4937     /* Loop over test configurations */
 4938     for(curr_test=0; curr_test<num_thread_tests; curr_test++) {
 4939         /* Threaded tests */
 4940         nerrors += test_threaded_loadstore_int();
 4941         nerrors += test_threaded_loadstore_ptr();
 4942         nerrors += test_threaded_add();
 4943         nerrors += test_threaded_incr_decr();
 4944         nerrors += test_threaded_decr_and_test();
 4945         nerrors += test_threaded_faa();
 4946         nerrors += test_threaded_faa_ret();
 4947         nerrors += test_threaded_fai_fad();
 4948         nerrors += test_threaded_fai_ret();
 4949         nerrors += test_threaded_fad_ret();
 4950         nerrors += test_threaded_cas_int();
 4951         nerrors += test_threaded_cas_ptr();
 4952         nerrors += test_grouped_cas_int();
 4953         nerrors += test_grouped_cas_ptr();
 4954         nerrors += test_threaded_cas_int_fairness();
 4955         nerrors += test_threaded_cas_ptr_fairness();
 4956         nerrors += test_threaded_swap_int();
 4957         nerrors += test_threaded_swap_ptr();
 4958         nerrors += test_threaded_llsc_int_stack();
 4959         nerrors += test_threaded_llsc_ptr_stack();
 4960     } /* end for */
 4961 
 4962     if(nerrors)
 4963         goto error;
 4964     printf("All primitives tests passed.\n");
 4965 
 4966     return 0;
 4967 
 4968 error:
 4969     if(!nerrors)
 4970         nerrors = 1;
 4971     printf("***** %d PRIMITIVES TEST%s FAILED! *****\n",
 4972             nerrors, 1 == nerrors ? "" : "S");
 4973     return 1;
 4974 } /* end main() */
 4975