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  */
test_barriers_sanity(void)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  */
test_barriers_linear_array_write(void * _udata)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  */
test_barriers_linear_array_read(void * _udata)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  */
test_barriers_linear_array(void)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  */
test_barriers_variables_write(void * _udata)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  */
test_barriers_variables_read(void * _udata)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  */
test_barriers_variables(void)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  */
test_barriers_scattered_array(void)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  */
main(int argc,char ** argv)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 
837