"Fossies" - the Fresh Open Source Software Archive

Member "openpa-1.0.4/test/test_barriers.c" (5 Dec 2012, 25431 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 /*
   18  * Uncomment these lines to disable only memory barriers, while leaving the rest
   19  * of the OPA functions intact.
   20  */
   21 /*
   22 #ifdef OPA_write_barrier
   23 #undef OPA_write_barrier
   24 #endif
   25 #define OPA_write_barrier() ((void) 0)
   26 #ifdef OPA_read_barrier
   27 #undef OPA_read_barrier
   28 #endif
   29 #define OPA_read_barrier() ((void) 0)
   30 #ifdef OPA_read_write_barrier
   31 #undef OPA_read_write_barrier
   32 #endif
   33 #define OPA_read_write_barrier() ((void) 0)
   34 */
   35 
   36 /* Definitions for test_barriers_linear_array */
   37 #define LINEAR_ARRAY_NITER 4000000
   38 #define LINEAR_ARRAY_LEN 100
   39 typedef struct {
   40     OPA_int_t *shared_array;
   41     int       master_thread;  /* Whether this is the master thread */
   42 } linear_array_t;
   43 
   44 /* Definitions for test_barriers_variables */
   45 #define VARIABLES_NITER 4000000
   46 #define VARIABLES_NVAR 10
   47 typedef struct {
   48     OPA_int_t *v_0;
   49     OPA_int_t *v_1;
   50     OPA_int_t *v_2;
   51     OPA_int_t *v_3;
   52     OPA_int_t *v_4;
   53     OPA_int_t *v_5;
   54     OPA_int_t *v_6;
   55     OPA_int_t *v_7;
   56     OPA_int_t *v_8;
   57     OPA_int_t *v_9;
   58     int       master_thread;  /* Whether this is the master thread */
   59 } variables_t;
   60 
   61 /* Definitions for test_barriers_scattered_array */
   62 #define SCATTERED_ARRAY_SIZE 100000
   63 #define SCATTERED_ARRAY_LOCS {254, 85920, 255, 35529, 75948, 75947, 253, 99999, 11111, 11112}
   64 
   65 
   66 /*-------------------------------------------------------------------------
   67  * Function: test_barriers_sanity
   68  *
   69  * Purpose: Essentially tests that memory barriers don't interfere with
   70  *          normal single threaded operations.  If this fails then
   71  *          something is *very* wrong.
   72  *
   73  * Return: Success: 0
   74  *         Failure: 1
   75  *
   76  * Programmer: Neil Fortner
   77  *             Wednesday, April 1, 2009
   78  *
   79  * Modifications:
   80  *     goodell@, December 1, 2011: load-acquire/store-release sanity test
   81  *
   82  *-------------------------------------------------------------------------
   83  */
   84 static int test_barriers_sanity(void)
   85 {
   86     OPA_int_t   a;
   87     int         b;
   88     OPA_ptr_t   op;
   89     void       *p;
   90     struct {int i;} obj = {0xabcdef};
   91 
   92     TESTING("memory barrier sanity", 0);
   93 
   94     /* Store 0 in a and b */
   95     OPA_store_int(&a, 0);
   96     OPA_write_barrier();
   97     b = 0;
   98 
   99     OPA_read_write_barrier();
  100 
  101     /* Add INT_MIN */
  102     OPA_add_int(&a, INT_MIN);
  103     OPA_read_write_barrier();
  104     b += INT_MIN;
  105 
  106     OPA_read_write_barrier();
  107 
  108     /* Increment */
  109     OPA_incr_int(&a);
  110     OPA_read_write_barrier();
  111     b++;
  112 
  113     OPA_read_write_barrier();
  114 
  115     /* Add INT_MAX */
  116     OPA_add_int(&a, INT_MAX);
  117     OPA_read_write_barrier();
  118     b += INT_MAX;
  119 
  120     OPA_read_write_barrier();
  121 
  122     /* Decrement */
  123     OPA_decr_int(&a);
  124     OPA_read_write_barrier();
  125     b--;
  126 
  127     OPA_read_write_barrier();
  128 
  129     /* Load the result, verify it is correct */
  130     if(OPA_load_int(&a) != INT_MIN + 1 + INT_MAX - 1) TEST_ERROR;
  131     OPA_read_barrier();
  132     if(b != OPA_load_int(&a)) TEST_ERROR;
  133 
  134     OPA_read_write_barrier();
  135 
  136     /* Barriers are now the opposite of what they were before */
  137 
  138     /* Store 0 in a */
  139     OPA_store_int(&a, 0);
  140     OPA_read_barrier();
  141     b = 0;
  142 
  143     /* Add INT_MAX */
  144     OPA_add_int(&a, INT_MAX);
  145     b += INT_MAX;
  146 
  147     /* Decrement */
  148     OPA_decr_int(&a);
  149     b--;
  150 
  151     /* Add INT_MIN */
  152     OPA_add_int(&a, INT_MIN);
  153     b += INT_MIN;
  154 
  155     /* Increment */
  156     OPA_incr_int(&a);
  157     b++;
  158 
  159     /* Load the result, verify it is correct */
  160     if(OPA_load_int(&a) != INT_MAX - 1 + INT_MIN + 1) TEST_ERROR;
  161     OPA_write_barrier();
  162     if(b != OPA_load_int(&a)) TEST_ERROR;
  163 
  164     /* now provide a quick sanity check that the load-acquire/store-release code
  165      * works (as in, successfully compiles and runs single-threaded, no
  166      * multithreading is checked here) */
  167 
  168     OPA_store_int(&a, 5);
  169     b = OPA_load_acquire_int(&a);
  170     if (b != 5) TEST_ERROR;
  171     OPA_store_release_int(&a, 0);
  172     b = OPA_load_acquire_int(&a);
  173     if (b != 0) TEST_ERROR;
  174 
  175     OPA_store_ptr(&op, &obj);
  176     p = OPA_load_acquire_ptr(&op);
  177     if (p != &obj) TEST_ERROR;
  178     OPA_store_release_ptr(&op, NULL);
  179     p = OPA_load_acquire_ptr(&op);
  180     if (p != NULL) TEST_ERROR;
  181 
  182     PASSED();
  183     return 0;
  184 
  185 error:
  186     return 1;
  187 } /* end test_barriers_sanity() */
  188 
  189 
  190 #if defined(OPA_HAVE_PTHREAD_H)
  191 /*-------------------------------------------------------------------------
  192  * Function: test_barriers_linear_array_write
  193  *
  194  * Purpose: Helper (write thread) routine for test_barriers_linear_array.
  195  *          Writes successive increments to the shared array with memory
  196  *          barriers between each increment.
  197  *
  198  * Return: NULL
  199  *
  200  * Programmer: Neil Fortner
  201  *             Wednesday, April 1, 2009
  202  *
  203  * Modifications:
  204  *
  205  *-------------------------------------------------------------------------
  206  */
  207 static void *test_barriers_linear_array_write(void *_udata)
  208 {
  209     linear_array_t      *udata = (linear_array_t *)_udata;
  210     OPA_int_t           *shared_array = udata->shared_array;
  211     int                 niter = LINEAR_ARRAY_NITER / LINEAR_ARRAY_LEN
  212                                 / iter_reduction[curr_test];
  213     int                 i, j;
  214 
  215     /* Main loop */
  216     for(i=0; i<niter; i++)
  217         for(j=0; j<LINEAR_ARRAY_LEN; j++) {
  218             /* Increment the value in the array */
  219             OPA_incr_int(&shared_array[j]);
  220 
  221             /* Write barrier */
  222             OPA_write_barrier();
  223         } /* end for */
  224 
  225     /* Exit */
  226     if(udata->master_thread)
  227         return(NULL);
  228     else
  229         pthread_exit(NULL);
  230 } /* end test_barriers_linear_array_write() */
  231 
  232 
  233 /*-------------------------------------------------------------------------
  234  * Function: test_barriers_linear_array_read
  235  *
  236  * Purpose: Helper (read thread) routine for test_barriers_linear_array.
  237  *          Reads successive increments from the shared array in reverse
  238  *          order with memory barriers between each read.
  239  *
  240  * Return: Success: NULL
  241  *         Failure: non-NULL
  242  *
  243  * Programmer: Neil Fortner
  244  *             Wednesday, April 1, 2009
  245  *
  246  * Modifications:
  247  *
  248  *-------------------------------------------------------------------------
  249  */
  250 static void *test_barriers_linear_array_read(void *_udata)
  251 {
  252     linear_array_t      *udata = (linear_array_t *)_udata;
  253     OPA_int_t           *shared_array = udata->shared_array;
  254     int                 read_buffer[LINEAR_ARRAY_LEN];
  255     int                 niter = LINEAR_ARRAY_NITER / LINEAR_ARRAY_LEN
  256                                 / iter_reduction[curr_test];
  257     int                 nerrors = 0;    /* Number of errors */
  258     int                 i, j;
  259 
  260     /* Main loop */
  261     for(i=0; i<niter; i++) {
  262         /* Load the values from the array into the read buffer in reverse
  263          * order */
  264         for(j = LINEAR_ARRAY_LEN - 1; j >= 0; j--) {
  265             read_buffer[j] = OPA_load_int(&shared_array[j]);
  266 
  267             /* Read barrier */
  268             OPA_read_barrier();
  269         } /* end for */
  270 
  271         /* Verify that the values never increase when read back in forward
  272         * order */
  273          for(j=1; j<LINEAR_ARRAY_LEN; j++)
  274             if(read_buffer[j-1] < read_buffer[j]) {
  275                 printf("    Unexpected load: %d is less than %d\n",
  276                         read_buffer[j-1], read_buffer[j]);
  277                 nerrors++;
  278             } /* end if */
  279     } /* end for */
  280 
  281     /* Any non-NULL exit value indicates an error, we use (void *) 1 here */
  282     if(udata->master_thread)
  283         return(nerrors ? (void *) 1 : NULL);
  284     else
  285         pthread_exit(nerrors ? (void *) 1 : NULL);
  286 } /* end test_barriers_linear_array_read() */
  287 #endif /* OPA_HAVE_PTHREAD_H */
  288 
  289 
  290 /*-------------------------------------------------------------------------
  291  * Function: test_barriers_linear_array
  292  *
  293  * Purpose: Tests memory barriers using simultaneous reads and writes to
  294  *          a linear array.  Launches nthreads threads split into read
  295  *          and write threads.
  296  *
  297  * Return: Success: 0
  298  *         Failure: 1
  299  *
  300  * Programmer: Neil Fortner
  301  *             Wednesday, April 1, 2009
  302  *
  303  * Modifications:
  304  *
  305  *-------------------------------------------------------------------------
  306  */
  307 static int test_barriers_linear_array(void)
  308 {
  309 #if defined(OPA_HAVE_PTHREAD_H)
  310     pthread_t           *threads = NULL; /* Threads */
  311     pthread_attr_t      ptattr;         /* Thread attributes */
  312     linear_array_t      *thread_data = NULL; /* User data structs for each thread */
  313     static OPA_int_t    shared_array[LINEAR_ARRAY_LEN]; /* Array to operate on */
  314     void                *ret;           /* Thread return value */
  315     unsigned            nthreads = num_threads[curr_test];
  316     int                 nerrors = 0;    /* number of errors */
  317     int                 i;
  318 
  319     TESTING("memory barriers with linear array", nthreads);
  320 
  321     /* Allocate array of threads */
  322     if(NULL == (threads = (pthread_t *) malloc(nthreads * sizeof(pthread_t))))
  323         TEST_ERROR;
  324 
  325     /* Allocate array of thread data */
  326     if(NULL == (thread_data = (linear_array_t *) calloc(nthreads,
  327             sizeof(linear_array_t)))) TEST_ERROR;
  328 
  329     /* Set threads to be joinable */
  330     pthread_attr_init(&ptattr);
  331     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
  332 
  333     /* Initialize shared array */
  334     for(i=0; i<LINEAR_ARRAY_LEN; i++)
  335         OPA_store_int(&shared_array[i], 0);
  336 
  337     /* Initialize thread data structs */
  338     for(i=0; i<nthreads; i++)
  339         thread_data[i].shared_array = shared_array;
  340     thread_data[nthreads-1].master_thread = 1;
  341 
  342     /* Create the threads. */
  343     for(i=0; i<(nthreads - 1); i++) {
  344         if(pthread_create(&threads[i], &ptattr, test_barriers_linear_array_write,
  345                 &thread_data[i])) TEST_ERROR;
  346         if(++i < (nthreads - 1))
  347             if(pthread_create(&threads[i], &ptattr, test_barriers_linear_array_read,
  348                     &thread_data[i])) TEST_ERROR;
  349     } /* end for */
  350     if(nthreads % 2) {
  351         if(test_barriers_linear_array_write(&thread_data[(nthreads - 1)]))
  352             nerrors++;
  353     } else
  354         if(test_barriers_linear_array_read(&thread_data[(nthreads - 1)]))
  355             nerrors++;
  356 
  357     /* Free the attribute */
  358     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
  359 
  360     /* Join the threads */
  361     for (i=0; i<(nthreads - 1); i++) {
  362         if(pthread_join(threads[i], &ret)) TEST_ERROR;
  363         if(ret)
  364             nerrors++;
  365     } /* end for */
  366 
  367     /* Check for errors */
  368     if(nerrors)
  369         FAIL_OP_ERROR(printf("    Unexpected return from %d thread%s\n", nerrors,
  370                 nerrors == 1 ? "" : "s"));
  371 
  372     /* Free memory */
  373     free(threads);
  374 
  375     PASSED();
  376 
  377 #else /* OPA_HAVE_PTHREAD_H */
  378     TESTING("memory barriers with linear array", 0);
  379     SKIPPED();
  380     puts("    pthread.h not available");
  381 #endif /* OPA_HAVE_PTHREAD_H */
  382 
  383     return 0;
  384 
  385 #if defined(OPA_HAVE_PTHREAD_H)
  386 error:
  387     if(threads) free(threads);
  388     return 1;
  389 #endif /* OPA_HAVE_PTHREAD_H */
  390 } /* end test_barriers_linear_array() */
  391 
  392 
  393 #if defined(OPA_HAVE_PTHREAD_H)
  394 /*-------------------------------------------------------------------------
  395  * Function: test_barriers_variables_write
  396  *
  397  * Purpose: Helper (write thread) routine for test_barriers_variables.
  398  *          Writes successive increments to the shared variables with
  399  *          memory barriers between each increment.
  400  *
  401  * Return: NULL
  402  *
  403  * Programmer: Neil Fortner
  404  *             Wednesday, April 1, 2009
  405  *
  406  * Modifications:
  407  *
  408  *-------------------------------------------------------------------------
  409  */
  410 static void *test_barriers_variables_write(void *_udata)
  411 {
  412     variables_t         *udata = (variables_t *)_udata;
  413     OPA_int_t           *v_0, *v_1, *v_2, *v_3, *v_4, *v_5, *v_6, *v_7, *v_8, *v_9;
  414     int                 niter = VARIABLES_NITER / VARIABLES_NVAR
  415                                 / iter_reduction[curr_test];
  416     int                 i;
  417 
  418     /* Make local copies of the pointers in udata, to maximize the chance of the
  419      * compiler reordering instructions (if the barriers don't work) */
  420     v_0 = udata->v_0;
  421     v_1 = udata->v_1;
  422     v_2 = udata->v_2;
  423     v_3 = udata->v_3;
  424     v_4 = udata->v_4;
  425     v_5 = udata->v_5;
  426     v_6 = udata->v_6;
  427     v_7 = udata->v_7;
  428     v_8 = udata->v_8;
  429     v_9 = udata->v_9;
  430 
  431     /* Main loop */
  432     for(i=0; i<niter; i++) {
  433         /* Incrememnt the variables in forward order */
  434         OPA_incr_int(v_0);
  435         OPA_write_barrier();
  436         OPA_incr_int(v_1);
  437         OPA_write_barrier();
  438         OPA_incr_int(v_2);
  439         OPA_write_barrier();
  440         OPA_incr_int(v_3);
  441         OPA_write_barrier();
  442         OPA_incr_int(v_4);
  443         OPA_write_barrier();
  444         OPA_incr_int(v_5);
  445         OPA_write_barrier();
  446         OPA_incr_int(v_6);
  447         OPA_write_barrier();
  448         OPA_incr_int(v_7);
  449         OPA_write_barrier();
  450         OPA_incr_int(v_8);
  451         OPA_write_barrier();
  452         OPA_incr_int(v_9);
  453         OPA_write_barrier();
  454     } /* end for */
  455 
  456     /* Exit */
  457     if(udata->master_thread)
  458         return(NULL);
  459     else
  460         pthread_exit(NULL);
  461 } /* end test_barriers_variables_write() */
  462 
  463 
  464 /*-------------------------------------------------------------------------
  465  * Function: test_barriers_variables_read
  466  *
  467  * Purpose: Helper (read thread) routine for test_barriers_variables.
  468  *          Reads successive increments from the variables in reverse
  469  *          order with memory barriers between each read.
  470  *
  471  * Return: Success: NULL
  472  *         Failure: non-NULL
  473  *
  474  * Programmer: Neil Fortner
  475  *             Wednesday, April 1, 2009
  476  *
  477  * Modifications:
  478  *
  479  *-------------------------------------------------------------------------
  480  */
  481 static void *test_barriers_variables_read(void *_udata)
  482 {
  483     variables_t         *udata = (variables_t *)_udata;
  484     OPA_int_t           *v_0, *v_1, *v_2, *v_3, *v_4, *v_5, *v_6, *v_7, *v_8, *v_9;
  485     int                 read_buffer[VARIABLES_NVAR];
  486     int                 niter = VARIABLES_NITER / VARIABLES_NVAR
  487                                 / iter_reduction[curr_test];
  488     int                 nerrors = 0;    /* Number of errors */
  489     int                 i, j;
  490 
  491     /* Make local copies of the pointers in udata, to maximize the chance of the
  492      * compiler reordering instructions (if the barriers don't work) */
  493     v_0 = udata->v_0;
  494     v_1 = udata->v_1;
  495     v_2 = udata->v_2;
  496     v_3 = udata->v_3;
  497     v_4 = udata->v_4;
  498     v_5 = udata->v_5;
  499     v_6 = udata->v_6;
  500     v_7 = udata->v_7;
  501     v_8 = udata->v_8;
  502     v_9 = udata->v_9;
  503 
  504     /* Main loop */
  505     for(i=0; i<niter; i++) {
  506         /* Load the values from the array into the read buffer in reverse
  507          * order*/
  508         read_buffer[9] = OPA_load_int(v_9);
  509         OPA_read_barrier();
  510         read_buffer[8] = OPA_load_int(v_8);
  511         OPA_read_barrier();
  512         read_buffer[7] = OPA_load_int(v_7);
  513         OPA_read_barrier();
  514         read_buffer[6] = OPA_load_int(v_6);
  515         OPA_read_barrier();
  516         read_buffer[5] = OPA_load_int(v_5);
  517         OPA_read_barrier();
  518         read_buffer[4] = OPA_load_int(v_4);
  519         OPA_read_barrier();
  520         read_buffer[3] = OPA_load_int(v_3);
  521         OPA_read_barrier();
  522         read_buffer[2] = OPA_load_int(v_2);
  523         OPA_read_barrier();
  524         read_buffer[1] = OPA_load_int(v_1);
  525         OPA_read_barrier();
  526         read_buffer[0] = OPA_load_int(v_0);
  527         OPA_read_barrier();
  528 
  529         /* Verify that the values never increase when read back in forward
  530         * order */
  531          for(j=1; j<VARIABLES_NVAR; j++)
  532             if(read_buffer[j-1] < read_buffer[j]) {
  533                 printf("    Unexpected load: %d is less than %d\n",
  534                         read_buffer[j-1], read_buffer[j]);
  535                 nerrors++;
  536             } /* end if */
  537     } /* end for */
  538 
  539     /* Any non-NULL exit value indicates an error, we use (void *) 1 here */
  540     if(udata->master_thread)
  541         return(nerrors ? (void *) 1 : NULL);
  542     else
  543         pthread_exit(nerrors ? (void *) 1 : NULL);
  544 } /* end test_barriers_variables_read() */
  545 #endif /* OPA_HAVE_PTHREAD_H */
  546 
  547 
  548 /*-------------------------------------------------------------------------
  549  * Function: test_barriers_variables
  550  *
  551  * Purpose: Tests memory barriers using simultaneous reads and writes to
  552  *          a linear array.  Launches nthreads threads split into read
  553  *          and write threads.
  554  *
  555  * Return: Success: 0
  556  *         Failure: 1
  557  *
  558  * Programmer: Neil Fortner
  559  *             Wednesday, April 1, 2009
  560  *
  561  * Modifications:
  562  *
  563  *-------------------------------------------------------------------------
  564  */
  565 static int test_barriers_variables(void)
  566 {
  567 #if defined(OPA_HAVE_PTHREAD_H)
  568     pthread_t           *threads = NULL; /* Threads */
  569     pthread_attr_t      ptattr;         /* Thread attributes */
  570     variables_t         *thread_data = NULL; /* User data structs for each thread */
  571     OPA_int_t           v_0, v_1, v_2, v_3, v_4, v_5, v_6, v_7, v_8, v_9;
  572     void                *ret;           /* Thread return value */
  573     unsigned            nthreads = num_threads[curr_test];
  574     int                 nerrors = 0;    /* number of errors */
  575     int                 i;
  576 
  577     TESTING("memory barriers with local variables", nthreads);
  578 
  579     /* Allocate array of threads */
  580     if(NULL == (threads = (pthread_t *) malloc(nthreads * sizeof(pthread_t))))
  581         TEST_ERROR;
  582 
  583     /* Allocate array of thread data */
  584     if(NULL == (thread_data = (variables_t *) calloc(nthreads,
  585             sizeof(variables_t)))) TEST_ERROR;
  586 
  587     /* Set threads to be joinable */
  588     pthread_attr_init(&ptattr);
  589     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
  590 
  591     /* Initialize shared variables */
  592     OPA_store_int(&v_0, 0);
  593     OPA_store_int(&v_1, 0);
  594     OPA_store_int(&v_2, 0);
  595     OPA_store_int(&v_3, 0);
  596     OPA_store_int(&v_4, 0);
  597     OPA_store_int(&v_5, 0);
  598     OPA_store_int(&v_6, 0);
  599     OPA_store_int(&v_7, 0);
  600     OPA_store_int(&v_8, 0);
  601     OPA_store_int(&v_9, 0);
  602 
  603     /* Initialize thread data structs */
  604     for(i=0; i<nthreads; i++) {
  605         thread_data[i].v_0 = &v_0;
  606         thread_data[i].v_1 = &v_1;
  607         thread_data[i].v_2 = &v_2;
  608         thread_data[i].v_3 = &v_3;
  609         thread_data[i].v_4 = &v_4;
  610         thread_data[i].v_5 = &v_5;
  611         thread_data[i].v_6 = &v_6;
  612         thread_data[i].v_7 = &v_7;
  613         thread_data[i].v_8 = &v_8;
  614         thread_data[i].v_9 = &v_9;
  615     } /* end for */
  616     thread_data[nthreads-1].master_thread = 1;
  617 
  618     /* Create the threads. */
  619     for(i=0; i<(nthreads - 1); i++) {
  620         if(pthread_create(&threads[i], &ptattr, test_barriers_variables_write,
  621                 &thread_data[i])) TEST_ERROR;
  622         if(++i < (nthreads - 1))
  623             if(pthread_create(&threads[i], &ptattr, test_barriers_variables_read,
  624                     &thread_data[i])) TEST_ERROR;
  625     } /* end for */
  626     if(nthreads % 2) {
  627         if(test_barriers_variables_write(&thread_data[(nthreads - 1)]))
  628             nerrors++;
  629     } else
  630         if(test_barriers_variables_read(&thread_data[(nthreads - 1)]))
  631             nerrors++;
  632 
  633     /* Free the attribute */
  634     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
  635 
  636     /* Join the threads */
  637     for (i=0; i<(nthreads - 1); i++) {
  638         if(pthread_join(threads[i], &ret)) TEST_ERROR;
  639         if(ret)
  640             nerrors++;
  641     } /* end for */
  642 
  643     /* Check for errors */
  644     if(nerrors)
  645         FAIL_OP_ERROR(printf("    Unexpected return from %d thread%s\n", nerrors,
  646                 nerrors == 1 ? "" : "s"));
  647 
  648     /* Free memory */
  649     free(threads);
  650 
  651     PASSED();
  652 
  653 #else /* OPA_HAVE_PTHREAD_H */
  654     TESTING("memory barriers with local variables", 0);
  655     SKIPPED();
  656     puts("    pthread.h not available");
  657 #endif /* OPA_HAVE_PTHREAD_H */
  658 
  659     return 0;
  660 
  661 #if defined(OPA_HAVE_PTHREAD_H)
  662 error:
  663     if(threads) free(threads);
  664     return 1;
  665 #endif /* OPA_HAVE_PTHREAD_H */
  666 } /* end test_barriers_variables() */
  667 
  668 
  669 /*-------------------------------------------------------------------------
  670  * Function: test_barriers_scattered_array
  671  *
  672  * Purpose: Tests memory barriers using simultaneous reads and writes to
  673  *          locations scattered in an array.  Launches nthreads threads
  674  *          split into read and write threads.
  675  *
  676  * Return: Success: 0
  677  *         Failure: 1
  678  *
  679  * Programmer: Neil Fortner
  680  *             Wednesday, April 1, 2009
  681  *
  682  * Modifications:
  683  *
  684  *-------------------------------------------------------------------------
  685  */
  686 static int test_barriers_scattered_array(void)
  687 {
  688 #if defined(OPA_HAVE_PTHREAD_H)
  689     pthread_t           *threads = NULL; /* Threads */
  690     pthread_attr_t      ptattr;         /* Thread attributes */
  691     variables_t         *thread_data = NULL; /* User data structs for each thread */
  692     static OPA_int_t    shared_array[SCATTERED_ARRAY_SIZE];
  693     int                 shared_locs[VARIABLES_NVAR] = SCATTERED_ARRAY_LOCS;
  694     void                *ret;           /* Thread return value */
  695     unsigned            nthreads = num_threads[curr_test];
  696     int                 nerrors = 0;    /* number of errors */
  697     int                 i;
  698 
  699     TESTING("memory barriers with scattered array", nthreads);
  700 
  701     /* Allocate array of threads */
  702     if(NULL == (threads = (pthread_t *) malloc(nthreads * sizeof(pthread_t))))
  703         TEST_ERROR;
  704 
  705     /* Allocate array of thread data */
  706     if(NULL == (thread_data = (variables_t *) calloc(nthreads,
  707             sizeof(variables_t)))) TEST_ERROR;
  708 
  709     /* Set threads to be joinable */
  710     pthread_attr_init(&ptattr);
  711     pthread_attr_setdetachstate(&ptattr, PTHREAD_CREATE_JOINABLE);
  712 
  713     /* Initialize shared variables */
  714     for(i=0; i<VARIABLES_NVAR; i++)
  715         OPA_store_int(&shared_array[shared_locs[i]], 0);
  716 
  717     /* Initialize thread data structs */
  718     for(i=0; i<nthreads; i++) {
  719         thread_data[i].v_0 = &shared_array[shared_locs[0]];
  720         thread_data[i].v_1 = &shared_array[shared_locs[1]];
  721         thread_data[i].v_2 = &shared_array[shared_locs[2]];
  722         thread_data[i].v_3 = &shared_array[shared_locs[3]];
  723         thread_data[i].v_4 = &shared_array[shared_locs[4]];
  724         thread_data[i].v_5 = &shared_array[shared_locs[5]];
  725         thread_data[i].v_6 = &shared_array[shared_locs[6]];
  726         thread_data[i].v_7 = &shared_array[shared_locs[7]];
  727         thread_data[i].v_8 = &shared_array[shared_locs[8]];
  728         thread_data[i].v_9 = &shared_array[shared_locs[9]];
  729     } /* end for */
  730     thread_data[nthreads-1].master_thread = 1;
  731 
  732     /* Create the threads.  We will use the helper routines for
  733      * test_barriers_variables. */
  734     for(i=0; i<(nthreads - 1); i++) {
  735         if(pthread_create(&threads[i], &ptattr, test_barriers_variables_write,
  736                 &thread_data[i])) TEST_ERROR;
  737         if(++i < (nthreads - 1))
  738             if(pthread_create(&threads[i], &ptattr, test_barriers_variables_read,
  739                     &thread_data[i])) TEST_ERROR;
  740     } /* end for */
  741     if(nthreads % 2) {
  742         if(test_barriers_variables_write(&thread_data[(nthreads - 1)]))
  743             nerrors++;
  744     } else
  745         if(test_barriers_variables_read(&thread_data[(nthreads - 1)]))
  746             nerrors++;
  747 
  748     /* Free the attribute */
  749     if(pthread_attr_destroy(&ptattr)) TEST_ERROR;
  750 
  751     /* Join the threads */
  752     for (i=0; i<(nthreads - 1); i++) {
  753         if(pthread_join(threads[i], &ret)) TEST_ERROR;
  754         if(ret)
  755             nerrors++;
  756     } /* end for */
  757 
  758     /* Check for errors */
  759     if(nerrors)
  760         FAIL_OP_ERROR(printf("    Unexpected return from %d thread%s\n", nerrors,
  761                 nerrors == 1 ? "" : "s"));
  762 
  763     /* Free memory */
  764     free(threads);
  765 
  766     PASSED();
  767 
  768 #else /* OPA_HAVE_PTHREAD_H */
  769     TESTING("memory barriers with scattered array", 0);
  770     SKIPPED();
  771     puts("    pthread.h not available");
  772 #endif /* OPA_HAVE_PTHREAD_H */
  773 
  774     return 0;
  775 
  776 #if defined(OPA_HAVE_PTHREAD_H)
  777 error:
  778     if(threads) free(threads);
  779     return 1;
  780 #endif /* OPA_HAVE_PTHREAD_H */
  781 } /* end test_barriers_scattered_array() */
  782 
  783 
  784 /*-------------------------------------------------------------------------
  785  * Function:    main
  786  *
  787  * Purpose:     Tests the opa memory barriers
  788  *
  789  * Return:      Success:        exit(0)
  790  *
  791  *              Failure:        exit(1)
  792  *
  793  * Programmer:  Neil Fortner
  794  *              Wednesday, April 1, 2009
  795  *
  796  * Modifications:
  797  *
  798  *-------------------------------------------------------------------------
  799  */
  800 int main(int argc, char **argv)
  801 {
  802     unsigned nerrors = 0;
  803 #if defined(OPA_USE_LOCK_BASED_PRIMITIVES)
  804     OPA_emulation_ipl_t shm_lock;
  805     OPA_Interprocess_lock_init(&shm_lock, 1/*isLeader*/);
  806 #endif
  807 
  808     /* Simple tests */
  809     nerrors += test_barriers_sanity();
  810 
  811     /* Loop over test configurations */
  812     for(curr_test=0; curr_test<num_thread_tests; curr_test++) {
  813         /* Don't test with only 1 thread */
  814         if(num_threads[curr_test] == 1)
  815             continue;
  816 
  817         /* Threaded tests */
  818         nerrors += test_barriers_linear_array();
  819         nerrors += test_barriers_variables();
  820         nerrors += test_barriers_scattered_array();
  821     } /* end for */
  822 
  823     if(nerrors)
  824         goto error;
  825     printf("All barriers tests passed.\n");
  826 
  827     return 0;
  828 
  829 error:
  830     if(!nerrors)
  831         nerrors = 1;
  832     printf("***** %d BARRIERS TEST%s FAILED! *****\n",
  833             nerrors, 1 == nerrors ? "" : "S");
  834     return 1;
  835 } /* end main() */
  836