|
Packit |
fe9d6e |
/*
|
|
Packit |
fe9d6e |
* Copyright (c) 2003-2005 Hewlett-Packard Development Company, L.P.
|
|
Packit |
fe9d6e |
*
|
|
Packit |
fe9d6e |
* This file may be redistributed and/or modified under the
|
|
Packit |
fe9d6e |
* terms of the GNU General Public License as published by the Free Software
|
|
Packit |
fe9d6e |
* Foundation; either version 2, or (at your option) any later version.
|
|
Packit |
fe9d6e |
*
|
|
Packit |
fe9d6e |
* It is distributed in the hope that it will be useful, but WITHOUT ANY
|
|
Packit |
fe9d6e |
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
|
|
Packit |
fe9d6e |
* FOR A PARTICULAR PURPOSE. See the GNU General Public License in the
|
|
Packit |
fe9d6e |
* file COPYING for more details.
|
|
Packit |
fe9d6e |
*/
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#if defined(HAVE_CONFIG_H)
|
|
Packit |
fe9d6e |
# include "config.h"
|
|
Packit |
fe9d6e |
#endif
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#if defined(AO_NO_PTHREADS) && defined(AO_USE_PTHREAD_DEFS)
|
|
Packit |
fe9d6e |
# include <stdio.h>
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
int main(void)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
printf("test skipped\n");
|
|
Packit |
fe9d6e |
return 0;
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#else
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#include "run_parallel.h"
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#include "test_atomic_include.h"
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#if defined(AO_USE_PTHREAD_DEFS) || defined(AO_PREFER_GENERALIZED)
|
|
Packit |
fe9d6e |
# define NITERS 100000
|
|
Packit |
fe9d6e |
#else
|
|
Packit |
fe9d6e |
# define NITERS 10000000
|
|
Packit |
fe9d6e |
#endif
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
void * add1sub1_thr(void * id);
|
|
Packit |
fe9d6e |
int add1sub1_test(void);
|
|
Packit |
fe9d6e |
void * acqrel_thr(void *id);
|
|
Packit |
fe9d6e |
int acqrel_test(void);
|
|
Packit |
fe9d6e |
void * test_and_set_thr(void * id);
|
|
Packit |
fe9d6e |
int test_and_set_test(void);
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#if defined(AO_HAVE_fetch_and_add1) && defined(AO_HAVE_fetch_and_sub1)
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
AO_t counter = 0;
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
void * add1sub1_thr(void * id)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
int me = (int)(AO_PTRDIFF_T)id;
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
int i;
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
for (i = 0; i < NITERS; ++i)
|
|
Packit |
fe9d6e |
if ((me & 1) != 0) {
|
|
Packit |
fe9d6e |
(void)AO_fetch_and_sub1(&counter);
|
|
Packit |
fe9d6e |
} else {
|
|
Packit |
fe9d6e |
(void)AO_fetch_and_add1(&counter);
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
return 0;
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
int add1sub1_test(void)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
return counter == 0;
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#endif /* defined(AO_HAVE_fetch_and_add1) && defined(AO_HAVE_fetch_and_sub1) */
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#if defined(AO_HAVE_store_release_write) && defined(AO_HAVE_load_acquire_read)
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
/* Invariant: counter1 >= counter2 */
|
|
Packit |
fe9d6e |
AO_t counter1 = 0;
|
|
Packit |
fe9d6e |
AO_t counter2 = 0;
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
void * acqrel_thr(void *id)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
int me = (int)(AO_PTRDIFF_T)id;
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
int i;
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
for (i = 0; i < NITERS; ++i)
|
|
Packit |
fe9d6e |
if (me & 1)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
AO_t my_counter1;
|
|
Packit |
fe9d6e |
if (me != 1)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
fprintf(stderr, "acqrel test: too many threads\n");
|
|
Packit |
fe9d6e |
abort();
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
my_counter1 = AO_load(&counter1);
|
|
Packit |
fe9d6e |
AO_store(&counter1, my_counter1 + 1);
|
|
Packit |
fe9d6e |
AO_store_release_write(&counter2, my_counter1 + 1);
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
else
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
AO_t my_counter1a, my_counter2a;
|
|
Packit |
fe9d6e |
AO_t my_counter1b, my_counter2b;
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
my_counter2a = AO_load_acquire_read(&counter2);
|
|
Packit |
fe9d6e |
my_counter1a = AO_load(&counter1);
|
|
Packit |
fe9d6e |
/* Redo this, to make sure that the second load of counter1 */
|
|
Packit |
fe9d6e |
/* is not viewed as a common subexpression. */
|
|
Packit |
fe9d6e |
my_counter2b = AO_load_acquire_read(&counter2);
|
|
Packit |
fe9d6e |
my_counter1b = AO_load(&counter1);
|
|
Packit |
fe9d6e |
if (my_counter1a < my_counter2a)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
fprintf(stderr, "Saw release store out of order: %lu < %lu\n",
|
|
Packit |
fe9d6e |
(unsigned long)my_counter1a, (unsigned long)my_counter2a);
|
|
Packit |
fe9d6e |
abort();
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
if (my_counter1b < my_counter2b)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
fprintf(stderr,
|
|
Packit |
fe9d6e |
"Saw release store out of order (bad CSE?): %lu < %lu\n",
|
|
Packit |
fe9d6e |
(unsigned long)my_counter1b, (unsigned long)my_counter2b);
|
|
Packit |
fe9d6e |
abort();
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
return 0;
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
int acqrel_test(void)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
return counter1 == NITERS && counter2 == NITERS;
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#endif /* AO_HAVE_store_release_write && AO_HAVE_load_acquire_read */
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#if defined(AO_HAVE_test_and_set_acquire)
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
AO_TS_t lock = AO_TS_INITIALIZER;
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
unsigned long locked_counter;
|
|
Packit |
fe9d6e |
volatile unsigned long junk = 13;
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
AO_ATTR_NO_SANITIZE_THREAD
|
|
Packit |
fe9d6e |
void do_junk(void)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
junk *= 17;
|
|
Packit |
fe9d6e |
junk *= 19;
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
void * test_and_set_thr(void * id)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
unsigned long i;
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
for (i = 0; i < NITERS/10; ++i)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
while (AO_test_and_set_acquire(&lock) != AO_TS_CLEAR);
|
|
Packit |
fe9d6e |
++locked_counter;
|
|
Packit |
fe9d6e |
if (locked_counter != 1)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
fprintf(stderr, "Test and set failure 1, counter = %ld, id = %d\n",
|
|
Packit |
fe9d6e |
(long)locked_counter, (int)(AO_PTRDIFF_T)id);
|
|
Packit |
fe9d6e |
abort();
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
locked_counter *= 2;
|
|
Packit |
fe9d6e |
locked_counter -= 1;
|
|
Packit |
fe9d6e |
locked_counter *= 5;
|
|
Packit |
fe9d6e |
locked_counter -= 4;
|
|
Packit |
fe9d6e |
if (locked_counter != 1)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
fprintf(stderr, "Test and set failure 2, counter = %ld, id = %d\n",
|
|
Packit |
fe9d6e |
(long)locked_counter, (int)(AO_PTRDIFF_T)id);
|
|
Packit |
fe9d6e |
abort();
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
--locked_counter;
|
|
Packit |
fe9d6e |
AO_CLEAR(&lock);
|
|
Packit |
fe9d6e |
/* Spend a bit of time outside the lock. */
|
|
Packit |
fe9d6e |
do_junk();
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
return 0;
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
int test_and_set_test(void)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
return locked_counter == 0;
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#endif /* defined(AO_HAVE_test_and_set_acquire) */
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#if (!defined(_MSC_VER) && !defined(__MINGW32__) && !defined(__BORLANDC__) \
|
|
Packit |
fe9d6e |
|| defined(AO_USE_NO_SIGNALS) || defined(AO_USE_WIN32_PTHREADS)) \
|
|
Packit |
fe9d6e |
&& defined(AO_TEST_EMULATION)
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
void AO_store_full_emulation(volatile AO_t *addr, AO_t val);
|
|
Packit |
fe9d6e |
AO_t AO_fetch_compare_and_swap_emulation(volatile AO_t *addr, AO_t old_val,
|
|
Packit |
fe9d6e |
AO_t new_val);
|
|
Packit |
fe9d6e |
# ifdef AO_HAVE_double_t
|
|
Packit |
fe9d6e |
int AO_compare_double_and_swap_double_emulation(volatile AO_double_t *,
|
|
Packit |
fe9d6e |
AO_t old_val1, AO_t old_val2,
|
|
Packit |
fe9d6e |
AO_t new_val1, AO_t new_val2);
|
|
Packit |
fe9d6e |
# endif
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
void test_atomic_emulation(void)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
AO_t x;
|
|
Packit |
fe9d6e |
# ifdef AO_HAVE_double_t
|
|
Packit |
fe9d6e |
AO_double_t w; /* double-word alignment not needed */
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
w.AO_val1 = 0;
|
|
Packit |
fe9d6e |
w.AO_val2 = 0;
|
|
Packit |
fe9d6e |
TA_assert(!AO_compare_double_and_swap_double_emulation(&w, 4116, 2121,
|
|
Packit |
fe9d6e |
8537, 6410));
|
|
Packit |
fe9d6e |
TA_assert(w.AO_val1 == 0 && w.AO_val2 == 0);
|
|
Packit |
fe9d6e |
TA_assert(AO_compare_double_and_swap_double_emulation(&w, 0, 0,
|
|
Packit |
fe9d6e |
8537, 6410));
|
|
Packit |
fe9d6e |
TA_assert(w.AO_val1 == 8537 && w.AO_val2 == 6410);
|
|
Packit |
fe9d6e |
# endif
|
|
Packit |
fe9d6e |
AO_store_full_emulation(&x, 1314);
|
|
Packit |
fe9d6e |
TA_assert(x == 1314);
|
|
Packit |
fe9d6e |
TA_assert(AO_fetch_compare_and_swap_emulation(&x, 14, 13117) == 1314);
|
|
Packit |
fe9d6e |
TA_assert(x == 1314);
|
|
Packit |
fe9d6e |
TA_assert(AO_fetch_compare_and_swap_emulation(&x, 1314, 14117) == 1314);
|
|
Packit |
fe9d6e |
TA_assert(x == 14117);
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#else
|
|
Packit |
fe9d6e |
# define test_atomic_emulation() (void)0
|
|
Packit |
fe9d6e |
#endif /* _MSC_VER && !AO_USE_NO_SIGNALS || !AO_TEST_EMULATION */
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
int main(void)
|
|
Packit |
fe9d6e |
{
|
|
Packit |
fe9d6e |
test_atomic();
|
|
Packit |
fe9d6e |
test_atomic_acquire();
|
|
Packit |
fe9d6e |
test_atomic_release();
|
|
Packit |
fe9d6e |
test_atomic_read();
|
|
Packit |
fe9d6e |
test_atomic_write();
|
|
Packit |
fe9d6e |
test_atomic_full();
|
|
Packit |
fe9d6e |
test_atomic_release_write();
|
|
Packit |
fe9d6e |
test_atomic_acquire_read();
|
|
Packit |
fe9d6e |
test_atomic_dd_acquire_read();
|
|
Packit |
fe9d6e |
# if defined(AO_HAVE_fetch_and_add1) && defined(AO_HAVE_fetch_and_sub1)
|
|
Packit |
fe9d6e |
run_parallel(4, add1sub1_thr, add1sub1_test, "add1/sub1");
|
|
Packit |
fe9d6e |
# endif
|
|
Packit |
fe9d6e |
# if defined(AO_HAVE_store_release_write) && defined(AO_HAVE_load_acquire_read)
|
|
Packit |
fe9d6e |
run_parallel(3, acqrel_thr, acqrel_test,
|
|
Packit |
fe9d6e |
"store_release_write/load_acquire_read");
|
|
Packit |
fe9d6e |
# endif
|
|
Packit |
fe9d6e |
# if defined(AO_HAVE_test_and_set_acquire)
|
|
Packit |
fe9d6e |
run_parallel(5, test_and_set_thr, test_and_set_test,
|
|
Packit |
fe9d6e |
"test_and_set");
|
|
Packit |
fe9d6e |
# endif
|
|
Packit |
fe9d6e |
test_atomic_emulation();
|
|
Packit |
fe9d6e |
return 0;
|
|
Packit |
fe9d6e |
}
|
|
Packit |
fe9d6e |
|
|
Packit |
fe9d6e |
#endif /* !AO_NO_PTHREADS || !AO_USE_PTHREAD_DEFS */
|