summaryrefslogtreecommitdiffstats
path: root/lib/isc/tests/atomic_test.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/isc/tests/atomic_test.c')
-rw-r--r--lib/isc/tests/atomic_test.c354
1 files changed, 354 insertions, 0 deletions
diff --git a/lib/isc/tests/atomic_test.c b/lib/isc/tests/atomic_test.c
new file mode 100644
index 0000000..8013010
--- /dev/null
+++ b/lib/isc/tests/atomic_test.c
@@ -0,0 +1,354 @@
+/*
+ * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+ *
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * See the COPYRIGHT file distributed with this work for additional
+ * information regarding copyright ownership.
+ */
+
+#include <config.h>
+
+#include <inttypes.h>
+#include <stdlib.h>
+
+#include <atf-c.h>
+
+#include <isc/atomic.h>
+#include <isc/print.h>
+#include <isc/result.h>
+
+#include "isctest.h"
+
+#define TASKS 32
+#define ITERATIONS 1000
+#define COUNTS_PER_ITERATION 1000
+#define INCREMENT_64 (int64_t)0x0000000010000000
+#define EXPECTED_COUNT_32 (TASKS * ITERATIONS * COUNTS_PER_ITERATION)
+#define EXPECTED_COUNT_64 (TASKS * ITERATIONS * COUNTS_PER_ITERATION * INCREMENT_64)
+
+typedef struct {
+ uint32_t iteration;
+} counter_t;
+
+counter_t counters[TASKS];
+
+#if defined(ISC_PLATFORM_HAVEXADD)
+static int32_t counter_32;
+
+static void
+do_xadd(isc_task_t *task, isc_event_t *ev) {
+ counter_t *state = (counter_t *)ev->ev_arg;
+ int i;
+
+ for (i = 0 ; i < COUNTS_PER_ITERATION ; i++) {
+ isc_atomic_xadd(&counter_32, 1);
+ }
+
+ state->iteration++;
+ if (state->iteration < ITERATIONS) {
+ isc_task_send(task, &ev);
+ } else {
+ isc_event_free(&ev);
+ }
+}
+
+ATF_TC(atomic_xadd);
+ATF_TC_HEAD(atomic_xadd, tc) {
+ atf_tc_set_md_var(tc, "descr", "atomic XADD");
+}
+ATF_TC_BODY(atomic_xadd, tc) {
+ isc_result_t result;
+ isc_task_t *tasks[TASKS];
+ isc_event_t *event = NULL;
+ int i;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ memset(counters, 0, sizeof(counters));
+ counter_32 = 0;
+
+ /*
+ * Create our tasks, and allocate an event to get the counters going.
+ */
+ for (i = 0 ; i < TASKS ; i++) {
+ tasks[i] = NULL;
+ ATF_REQUIRE_EQ(isc_task_create(taskmgr, 0, &tasks[i]),
+ ISC_R_SUCCESS);
+ event = isc_event_allocate(mctx, NULL, 1000, do_xadd,
+ &counters[i],
+ sizeof(struct isc_event));
+ ATF_REQUIRE(event != NULL);
+ isc_task_sendanddetach(&tasks[i], &event);
+ }
+
+ isc_test_end();
+
+ printf("32-bit counter %d, expected %d\n",
+ counter_32, EXPECTED_COUNT_32);
+
+ ATF_CHECK_EQ(counter_32, EXPECTED_COUNT_32);
+ counter_32 = 0;
+}
+#endif
+
+#if defined(ISC_PLATFORM_HAVEXADDQ)
+static int64_t counter_64;
+
+static void
+do_xaddq(isc_task_t *task, isc_event_t *ev) {
+ counter_t *state = (counter_t *)ev->ev_arg;
+ int i;
+
+ for (i = 0 ; i < COUNTS_PER_ITERATION ; i++) {
+ isc_atomic_xaddq(&counter_64, INCREMENT_64);
+ }
+
+ state->iteration++;
+ if (state->iteration < ITERATIONS) {
+ isc_task_send(task, &ev);
+ } else {
+ isc_event_free(&ev);
+ }
+}
+
+ATF_TC(atomic_xaddq);
+ATF_TC_HEAD(atomic_xaddq, tc) {
+ atf_tc_set_md_var(tc, "descr", "atomic XADDQ");
+}
+ATF_TC_BODY(atomic_xaddq, tc) {
+ isc_result_t result;
+ isc_task_t *tasks[TASKS];
+ isc_event_t *event = NULL;
+ int i;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ memset(counters, 0, sizeof(counters));
+ counter_64 = 0;
+
+ /*
+ * Create our tasks, and allocate an event to get the counters going.
+ */
+ for (i = 0 ; i < TASKS ; i++) {
+ tasks[i] = NULL;
+ ATF_REQUIRE_EQ(isc_task_create(taskmgr, 0, &tasks[i]),
+ ISC_R_SUCCESS);
+ event = isc_event_allocate(mctx, NULL, 1000, do_xaddq,
+ &counters[i],
+ sizeof(struct isc_event));
+ ATF_REQUIRE(event != NULL);
+ isc_task_sendanddetach(&tasks[i], &event);
+ }
+
+ isc_test_end();
+
+ printf("64-bit counter %" PRId64 ", "
+ "expected %" PRId64 "\n",
+ counter_64, EXPECTED_COUNT_64);
+
+ ATF_CHECK_EQ(counter_64, EXPECTED_COUNT_64);
+ counter_32 = 0;
+}
+#endif
+
+#if defined(ISC_PLATFORM_HAVEATOMICSTORE)
+static int32_t store_32;
+
+static void
+do_store(isc_task_t *task, isc_event_t *ev) {
+ counter_t *state = (counter_t *)ev->ev_arg;
+ int i;
+ uint32_t r;
+ uint32_t val;
+
+ r = random() % 256;
+ val = (r << 24) | (r << 16) | (r << 8) | r;
+
+ for (i = 0 ; i < COUNTS_PER_ITERATION ; i++) {
+ isc_atomic_store(&store_32, val);
+ }
+
+ state->iteration++;
+ if (state->iteration < ITERATIONS) {
+ isc_task_send(task, &ev);
+ } else {
+ isc_event_free(&ev);
+ }
+}
+
+ATF_TC(atomic_store);
+ATF_TC_HEAD(atomic_store, tc) {
+ atf_tc_set_md_var(tc, "descr", "atomic STORE");
+}
+ATF_TC_BODY(atomic_store, tc) {
+ isc_result_t result;
+ isc_task_t *tasks[TASKS];
+ isc_event_t *event = NULL;
+ uint32_t val;
+ uint32_t r;
+ int i;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ memset(counters, 0, sizeof(counters));
+ store_32 = 0;
+
+ /*
+ * Create our tasks, and allocate an event to get the counters
+ * going.
+ */
+ for (i = 0 ; i < TASKS ; i++) {
+ tasks[i] = NULL;
+ ATF_REQUIRE_EQ(isc_task_create(taskmgr, 0, &tasks[i]),
+ ISC_R_SUCCESS);
+ event = isc_event_allocate(mctx, NULL, 1000, do_store,
+ &counters[i],
+ sizeof(struct isc_event));
+ ATF_REQUIRE(event != NULL);
+ isc_task_sendanddetach(&tasks[i], &event);
+ }
+
+ isc_test_end();
+
+ r = store_32 & 0xff;
+ val = (r << 24) | (r << 16) | (r << 8) | r;
+
+ printf("32-bit store 0x%x, expected 0x%x\n",
+ (uint32_t) store_32, val);
+
+ ATF_CHECK_EQ((uint32_t) store_32, val);
+ store_32 = 0;
+}
+#endif
+
+#if defined(ISC_PLATFORM_HAVEATOMICSTOREQ)
+static int64_t store_64;
+
+static void
+do_storeq(isc_task_t *task, isc_event_t *ev) {
+ counter_t *state = (counter_t *)ev->ev_arg;
+ int i;
+ uint8_t r;
+ uint64_t val;
+
+ r = random() % 256;
+ val = (((uint64_t) r << 24) |
+ ((uint64_t) r << 16) |
+ ((uint64_t) r << 8) |
+ (uint64_t) r);
+ val |= ((uint64_t) val << 32);
+
+ for (i = 0 ; i < COUNTS_PER_ITERATION ; i++) {
+ isc_atomic_storeq(&store_64, val);
+ }
+
+ state->iteration++;
+ if (state->iteration < ITERATIONS) {
+ isc_task_send(task, &ev);
+ } else {
+ isc_event_free(&ev);
+ }
+}
+
+ATF_TC(atomic_storeq);
+ATF_TC_HEAD(atomic_storeq, tc) {
+ atf_tc_set_md_var(tc, "descr", "atomic STOREQ");
+}
+ATF_TC_BODY(atomic_storeq, tc) {
+ isc_result_t result;
+ isc_task_t *tasks[TASKS];
+ isc_event_t *event = NULL;
+ uint64_t val;
+ uint32_t r;
+ int i;
+
+ UNUSED(tc);
+
+ result = isc_test_begin(NULL, true, 0);
+ ATF_REQUIRE_EQ(result, ISC_R_SUCCESS);
+
+ memset(counters, 0, sizeof(counters));
+ store_64 = 0;
+
+ /*
+ * Create our tasks, and allocate an event to get the counters
+ * going.
+ */
+ for (i = 0 ; i < TASKS ; i++) {
+ tasks[i] = NULL;
+ ATF_REQUIRE_EQ(isc_task_create(taskmgr, 0, &tasks[i]),
+ ISC_R_SUCCESS);
+ event = isc_event_allocate(mctx, NULL, 1000, do_storeq,
+ &counters[i],
+ sizeof(struct isc_event));
+ ATF_REQUIRE(event != NULL);
+ isc_task_sendanddetach(&tasks[i], &event);
+ }
+
+ isc_test_end();
+
+ r = store_64 & 0xff;
+ val = (((uint64_t) r << 24) |
+ ((uint64_t) r << 16) |
+ ((uint64_t) r << 8) |
+ (uint64_t) r);
+ val |= ((uint64_t) val << 32);
+
+ printf("64-bit store 0x%" PRIx64 ", "
+ "expected 0x%" PRIx64 "\n",
+ (uint64_t) store_64, val);
+
+ ATF_CHECK_EQ((uint64_t) store_64, val);
+ store_64 = 0;
+}
+#endif
+
+#if !defined(ISC_PLATFORM_HAVEXADD) && \
+ !defined(ISC_PLATFORM_HAVEXADDQ) && \
+ !defined(ISC_PLATFORM_HAVEATOMICSTOREQ)
+ATF_TC(untested);
+ATF_TC_HEAD(untested, tc) {
+ atf_tc_set_md_var(tc, "descr", "skipping aes test");
+}
+ATF_TC_BODY(untested, tc) {
+ UNUSED(tc);
+ atf_tc_skip("AES not available");
+}
+#endif /* !HAVEXADD, !HAVEXADDQ, !HAVEATOMICSTOREQ */
+
+/*
+ * Main
+ */
+ATF_TP_ADD_TCS(tp) {
+#if defined(ISC_PLATFORM_HAVEXADD)
+ ATF_TP_ADD_TC(tp, atomic_xadd);
+#endif
+#if defined(ISC_PLATFORM_HAVEXADDQ)
+ ATF_TP_ADD_TC(tp, atomic_xaddq);
+#endif
+#ifdef ISC_PLATFORM_HAVEATOMICSTORE
+ ATF_TP_ADD_TC(tp, atomic_store);
+#endif
+#if defined(ISC_PLATFORM_HAVEATOMICSTOREQ)
+ ATF_TP_ADD_TC(tp, atomic_storeq);
+#endif
+#if !defined(ISC_PLATFORM_HAVEXADD) && \
+ !defined(ISC_PLATFORM_HAVEXADDQ) && \
+ !defined(ISC_PLATFORM_HAVEATOMICSTOREQ)
+ ATF_TP_ADD_TC(tp, untested);
+#endif
+
+ return (atf_no_error());
+}