summaryrefslogtreecommitdiffstats
path: root/libdimension/tests/concurrency/future.c
diff options
context:
space:
mode:
Diffstat (limited to 'libdimension/tests/concurrency/future.c')
-rw-r--r--libdimension/tests/concurrency/future.c98
1 files changed, 98 insertions, 0 deletions
diff --git a/libdimension/tests/concurrency/future.c b/libdimension/tests/concurrency/future.c
new file mode 100644
index 0000000..b226e4f
--- /dev/null
+++ b/libdimension/tests/concurrency/future.c
@@ -0,0 +1,98 @@
+/*************************************************************************
+ * Copyright (C) 2014 Tavian Barnes <tavianator@tavianator.com> *
+ * *
+ * This file is part of The Dimension Test Suite. *
+ * *
+ * The Dimension Test Suite is free software; you can redistribute it *
+ * and/or modify it under the terms of the GNU General Public License as *
+ * published by the Free Software Foundation; either version 3 of the *
+ * License, or (at your option) any later version. *
+ * *
+ * The Dimension Test Suite 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 for more details. *
+ * *
+ * You should have received a copy of the GNU General Public License *
+ * along with this program. If not, see <http://www.gnu.org/licenses/>. *
+ *************************************************************************/
+
+/**
+ * @file
+ * Tests for dmnsn_future.
+ */
+
+#include "../../platform/platform.c"
+#include "../../concurrency/future.c"
+#include "../../concurrency/threads.c"
+#include "tests.h"
+#include <stdatomic.h>
+
+static dmnsn_future *future;
+static atomic_int counter = ATOMIC_VAR_INIT(0);
+static const int NTHREADS = 8;
+static const int CHUNK = 100;
+
+static int
+dmnsn_future_test_ccthread(void *ptr, unsigned int thread, unsigned int nthreads)
+{
+ for (int i = 0; i < CHUNK; ++i) {
+ for (int j = 0; j < CHUNK; ++j) {
+ atomic_fetch_add(&counter, 1);
+ }
+ dmnsn_future_increment(future);
+ }
+ return 0;
+}
+
+static int
+dmnsn_future_test_thread(void *ptr)
+{
+ dmnsn_future_set_total(future, NTHREADS*CHUNK);
+ return dmnsn_execute_concurrently(future, dmnsn_future_test_ccthread, ptr, NTHREADS);
+}
+
+DMNSN_TEST_SETUP(future)
+{
+ future = dmnsn_new_future();
+ dmnsn_new_thread(future, dmnsn_future_test_thread, NULL);
+}
+
+DMNSN_TEST_TEARDOWN(future)
+{
+ int res = dmnsn_future_join(future);
+ ck_assert_int_eq(res, 0);
+}
+
+void *
+dmnsn_future_pause_and_check(void *ptr)
+{
+ for (int i = 0; i < CHUNK; ++i) {
+ dmnsn_future_pause(future);
+
+ int value = atomic_load(&counter);
+ ck_assert_int_eq(value%CHUNK, 0);
+
+ for (int j = 0; j < CHUNK; ++j) {
+ int new_value = atomic_load(&counter);
+ ck_assert_int_eq(new_value, value);
+ }
+
+ dmnsn_future_resume(future);
+ }
+
+ return NULL;
+}
+
+DMNSN_TEST(future, pause_safely)
+{
+ // Check dmnsn_future_pause() behaviour from two concurrent threads
+ pthread_t thread;
+ if (pthread_create(&thread, NULL, dmnsn_future_pause_and_check, NULL) != 0) {
+ dmnsn_error("Couldn't start thread.");
+ }
+
+ dmnsn_future_pause_and_check(NULL);
+
+ dmnsn_join_thread(thread, NULL);
+}