Add test_atomic_ops to perform minimal testing of used atomic primitives
authorIvan Maidanski <ivmai@mail.ru>
Wed, 14 Jun 2017 09:16:00 +0000 (12:16 +0300)
committerIvan Maidanski <ivmai@mail.ru>
Wed, 14 Jun 2017 09:26:12 +0000 (12:26 +0300)
The main purpose of test_atomic_ops is to be able to check whether
it is safe to use compiler atomic intrinsics (enabled by defining
GC_BUILTIN_ATOMIC macro).

* tests/test_atomic_ops.c: New file.
* tests/tests.am [THREADS] (TESTS, check_PROGRAMS): Add
test_atomic_ops.
* tests/tests.am [THREADS] (test_atomic_ops_SOURCES,
test_atomic_ops_LDADD): New variable.
* tests/tests.am (check-without-test-driver): Run test_atomic_ops (if
available).

tests/test_atomic_ops.c [new file with mode: 0644]
tests/tests.am

diff --git a/tests/test_atomic_ops.c b/tests/test_atomic_ops.c
new file mode 100644 (file)
index 0000000..f767533
--- /dev/null
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017 Ivan Maidanski
+ *
+ * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED
+ * OR IMPLIED.  ANY USE IS AT YOUR OWN RISK.
+ *
+ * Permission is hereby granted to use or copy this program
+ * for any purpose,  provided the above notices are retained on all copies.
+ * Permission to modify the code and to distribute modified code is granted,
+ * provided the above notices are retained, and a notice that the code was
+ * modified is included with the above copyright notice.
+ */
+
+/* Minimal testing of atomic operations used by the BDWGC.  Primary use */
+/* is to determine whether compiler atomic intrinsics can be relied on. */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <stdio.h>
+
+#if defined(GC_BUILTIN_ATOMIC) || defined(PARALLEL_MARK) \
+    || (defined(GC_THREADS) && !defined(_WIN32) && !defined(_MSC_VER) \
+        && !defined(__CYGWIN__) && !defined(__MINGW32__))
+
+# include <stdlib.h>
+
+# ifdef PARALLEL_MARK
+#   define AO_REQUIRE_CAS
+# endif
+
+# include "private/gc_atomic_ops.h"
+
+# define TA_assert(e) \
+    if (!(e)) { \
+        fprintf(stderr, "Assertion failure, line %d: " #e "\n", __LINE__); \
+        exit(-1); \
+    }
+
+  int main(void) {
+    AO_t x = 13;
+#   ifdef AO_HAVE_test_and_set_acquire
+        AO_TS_t z = AO_TS_INITIALIZER;
+
+        TA_assert(AO_test_and_set_acquire(&z) == AO_TS_CLEAR);
+        TA_assert(AO_test_and_set_acquire(&z) == AO_TS_SET);
+        AO_CLEAR(&z);
+#   endif
+    AO_compiler_barrier();
+    AO_nop_full();
+#   ifdef AO_HAVE_load_acquire
+      TA_assert(AO_load_acquire(&x) == 13);
+#   endif
+#   if defined(AO_HAVE_fetch_and_add) && defined(AO_HAVE_fetch_and_add1)
+      TA_assert(AO_fetch_and_add(&x, 42) == 13);
+      TA_assert(AO_fetch_and_add(&x, (AO_t)(-43)) == 55);
+      TA_assert(AO_fetch_and_add1(&x) == 12);
+#   endif
+#   if defined(AO_REQUIRE_CAS) && defined(AO_HAVE_compare_and_swap) \
+       && defined(AO_HAVE_compare_and_swap_release)
+      TA_assert(!AO_compare_and_swap(&x, 14, 42));
+      TA_assert(x == 13);
+      TA_assert(AO_compare_and_swap_release(&x, 13, 42));
+      TA_assert(x == 42);
+#   else
+      if (*(volatile AO_t *)&x == 13)
+        *(volatile AO_t *)&x = 42;
+#   endif
+#   ifdef AO_HAVE_or
+      AO_or(&x, 66);
+      TA_assert(x == 106);
+#   endif
+#   ifdef AO_HAVE_store_release
+      AO_store_release(&x, 113);
+      TA_assert(x == 113);
+#   endif
+    return 0;
+  }
+
+#else
+
+  int main(void)
+  {
+    printf("test_atomic_ops skipped\n");
+    return 0;
+  }
+
+#endif
index 90fbfe0..b851f35 100644 (file)
@@ -70,6 +70,12 @@ endif
 
 if THREADS
 
+TESTS += test_atomic_ops$(EXEEXT)
+check_PROGRAMS += test_atomic_ops
+test_atomic_ops_SOURCES = tests/test_atomic_ops.c
+# Really should need only $(ATOMIC_OPS_LIBS)
+test_atomic_ops_LDADD = $(test_ldadd) $(THREADDLLIBS)
+
 TESTS += threadleaktest$(EXEEXT)
 check_PROGRAMS += threadleaktest
 threadleaktest_SOURCES = tests/thread_leak_test.c
@@ -134,6 +140,7 @@ check-without-test-driver: $(TESTS)
        test ! -f disclaim_test$(EXEEXT) || ./disclaim_test$(EXEEXT)
        test ! -f initsecondarythread_test$(EXEEXT) \
          || ./initsecondarythread_test$(EXEEXT)
+       test ! -f test_atomic_ops$(EXEEXT) || ./test_atomic_ops$(EXEEXT)
        test ! -f threadkey_test$(EXEEXT) || ./threadkey_test$(EXEEXT)
        test ! -f threadleaktest$(EXEEXT) || ./threadleaktest$(EXEEXT)
        test ! -f subthreadcreate_test$(EXEEXT) || ./subthreadcreate_test$(EXEEXT)