/* * Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P. * Original Author: Hans Boehm * * This file may be redistributed and/or modified under the * terms of the GNU General Public License as published by the Free Software * Foundation; either version 2, or (at your option) any later version. * * It is distributed in the hope that it will be useful, but WITHOUT ANY * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU General Public License in the * file doc/COPYING for more details. */ #if defined(HAVE_CONFIG_H) # include "config.h" #endif #include "run_parallel.inc" #include "test_atomic_include.h" #ifdef AO_USE_PTHREAD_DEFS # define NITERS 100000 #else # define NITERS 10000000 #endif void * add1sub1_thr(void * id); int add1sub1_test(void); void * acqrel_thr(void *id); int acqrel_test(void); void * test_and_set_thr(void * id); int test_and_set_test(void); #if defined(AO_HAVE_fetch_and_add1) && defined(AO_HAVE_fetch_and_sub1) AO_t counter = 0; void * add1sub1_thr(void * id) { int me = (int)(AO_PTRDIFF_T)id; int i; for (i = 0; i < NITERS; ++i) if (me & 1) AO_fetch_and_sub1(&counter); else AO_fetch_and_add1(&counter); return 0; } int add1sub1_test(void) { return counter == 0; } #endif /* defined(AO_HAVE_fetch_and_add1) && defined(AO_HAVE_fetch_and_sub1) */ #if defined(AO_HAVE_store_release_write) && defined(AO_HAVE_load_acquire_read) /* Invariant: counter1 >= counter2 */ AO_t counter1 = 0; AO_t counter2 = 0; void * acqrel_thr(void *id) { int me = (int)(AO_PTRDIFF_T)id; int i; for (i = 0; i < NITERS; ++i) if (me & 1) { AO_t my_counter1; if (me != 1) fprintf(stderr, "acqrel test: too many threads\n"); my_counter1 = AO_load(&counter1); AO_store(&counter1, my_counter1 + 1); AO_store_release_write(&counter2, my_counter1 + 1); } else { AO_t my_counter1a, my_counter2a; AO_t my_counter1b, my_counter2b; my_counter2a = AO_load_acquire_read(&counter2); my_counter1a = AO_load(&counter1); /* Redo this, to make sure that the second load of counter1 */ /* is not viewed as a common subexpression. */ my_counter2b = AO_load_acquire_read(&counter2); my_counter1b = AO_load(&counter1); if (my_counter1a < my_counter2a) { fprintf(stderr, "Saw release store out of order: %lu < %lu\n", (unsigned long)my_counter1a, (unsigned long)my_counter2a); abort(); } if (my_counter1b < my_counter2b) { fprintf(stderr, "Saw release store out of order (bad CSE?): %lu < %lu\n", (unsigned long)my_counter1b, (unsigned long)my_counter2b); abort(); } } return 0; } int acqrel_test(void) { return counter1 == NITERS && counter2 == NITERS; } #endif /* AO_HAVE_store_release_write && AO_HAVE_load_acquire_read */ #if defined(AO_HAVE_test_and_set_acquire) AO_TS_T lock = AO_TS_INITIALIZER; unsigned long locked_counter; volatile unsigned long junk = 13; void * test_and_set_thr(void * id) { unsigned long i; for (i = 0; i < NITERS/10; ++i) { while (AO_test_and_set_acquire(&lock) != AO_TS_CLEAR); ++locked_counter; if (locked_counter != 1) { fprintf(stderr, "Test and set failure 1, counter = %ld\n", locked_counter); abort(); } locked_counter *= 2; locked_counter -= 1; locked_counter *= 5; locked_counter -= 4; if (locked_counter != 1) { fprintf(stderr, "Test and set failure 2, counter = %ld\n", locked_counter); abort(); } --locked_counter; AO_CLEAR(&lock); /* Spend a bit of time outside the lock. */ junk *= 17; junk *= 17; } return 0; } int test_and_set_test(void) { return locked_counter == 0; } #endif /* defined(AO_HAVE_test_and_set_acquire) */ int main(void) { test_atomic(); test_atomic_acquire(); test_atomic_release(); test_atomic_read(); test_atomic_write(); test_atomic_full(); test_atomic_release_write(); test_atomic_acquire_read(); # if defined(AO_HAVE_fetch_and_add1) && defined(AO_HAVE_fetch_and_sub1) run_parallel(4, add1sub1_thr, add1sub1_test, "add1/sub1"); # endif # if defined(AO_HAVE_store_release_write) && defined(AO_HAVE_load_acquire_read) run_parallel(3, acqrel_thr, acqrel_test, "store_release_write/load_acquire_read"); # endif # if defined(AO_HAVE_test_and_set_acquire) run_parallel(5, test_and_set_thr, test_and_set_test, "test_and_set"); # endif return 0; }