summaryrefslogtreecommitdiffstats
path: root/regressions/ck_sequence/validate/ck_sequence.c
diff options
context:
space:
mode:
Diffstat (limited to 'regressions/ck_sequence/validate/ck_sequence.c')
-rw-r--r--regressions/ck_sequence/validate/ck_sequence.c171
1 files changed, 171 insertions, 0 deletions
diff --git a/regressions/ck_sequence/validate/ck_sequence.c b/regressions/ck_sequence/validate/ck_sequence.c
new file mode 100644
index 0000000..e0bc700
--- /dev/null
+++ b/regressions/ck_sequence/validate/ck_sequence.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright 2011-2015 Samy Al Bahra.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <ck_cc.h>
+#include <ck_sequence.h>
+#include <errno.h>
+#include <pthread.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "../../common.h"
+
+#ifndef STEPS
+#define STEPS 1000000
+#endif
+
+struct example {
+ unsigned int a;
+ unsigned int b;
+ unsigned int c;
+};
+
+static struct example global CK_CC_CACHELINE;
+static ck_sequence_t seqlock CK_CC_CACHELINE = CK_SEQUENCE_INITIALIZER;
+static unsigned int barrier;
+static struct affinity affinerator;
+
+static void
+validate(struct example *copy)
+{
+
+ if (copy->b != copy->a + 1000) {
+ ck_error("ERROR: Failed regression: copy->b (%u != %u + %u / %u)\n",
+ copy->b, copy->a, 1000, copy->a + 1000);
+ }
+
+ if (copy->c != copy->a + copy->b) {
+ ck_error("ERROR: Failed regression: copy->c (%u != %u + %u / %u)\n",
+ copy->c, copy->a, copy->b, copy->a + copy->b);
+ }
+
+ return;
+}
+
+static void *
+consumer(void *unused CK_CC_UNUSED)
+{
+ struct example copy;
+ uint32_t version;
+ unsigned int retries = 0;
+ unsigned int i;
+
+ unused = NULL;
+ if (aff_iterate(&affinerator)) {
+ perror("ERROR: Could not affine thread");
+ exit(EXIT_FAILURE);
+ }
+
+ while (ck_pr_load_uint(&barrier) == 0);
+ for (i = 0; i < STEPS; i++) {
+ /*
+ * Attempt a read of the data structure. If the structure
+ * has been modified between ck_sequence_read_begin and
+ * ck_sequence_read_retry then attempt another read since
+ * the data may be in an inconsistent state.
+ */
+ do {
+ version = ck_sequence_read_begin(&seqlock);
+ copy.a = ck_pr_load_uint(&global.a);
+ copy.b = ck_pr_load_uint(&global.b);
+ copy.c = ck_pr_load_uint(&global.c);
+ retries++;
+ } while (ck_sequence_read_retry(&seqlock, version) == true);
+ validate(&copy);
+
+ CK_SEQUENCE_READ(&seqlock, &version) {
+ copy.a = ck_pr_load_uint(&global.a);
+ copy.b = ck_pr_load_uint(&global.b);
+ copy.c = ck_pr_load_uint(&global.c);
+ retries++;
+ }
+ validate(&copy);
+ }
+
+ fprintf(stderr, "%u retries.\n", retries - STEPS);
+ ck_pr_dec_uint(&barrier);
+ return (NULL);
+}
+
+int
+main(int argc, char *argv[])
+{
+ pthread_t *threads;
+ unsigned int counter = 0;
+ bool first = true;
+ int n_threads, i;
+
+ if (argc != 3) {
+ ck_error("Usage: ck_sequence <number of threads> <affinity delta>\n");
+ }
+
+ n_threads = atoi(argv[1]);
+ if (n_threads <= 0) {
+ ck_error("ERROR: Number of threads must be greater than 0\n");
+ }
+
+ threads = malloc(sizeof(pthread_t) * n_threads);
+ if (threads == NULL) {
+ ck_error("ERROR: Could not allocate memory for threads\n");
+ }
+
+ affinerator.delta = atoi(argv[2]);
+ affinerator.request = 0;
+
+ for (i = 0; i < n_threads; i++) {
+ if (pthread_create(&threads[i], NULL, consumer, NULL)) {
+ ck_error("ERROR: Failed to create thread %d\n", i);
+ }
+ }
+
+ for (;;) {
+ /*
+ * Update the shared data in a non-blocking fashion.
+ * If the data is modified by multiple writers then
+ * ck_sequence_write_begin must be called after acquiring
+ * the associated lock and ck_sequence_write_end must be
+ * called before relinquishing the lock.
+ */
+ ck_sequence_write_begin(&seqlock);
+ global.a = counter++;
+ global.b = global.a + 1000;
+ global.c = global.b + global.a;
+ ck_sequence_write_end(&seqlock);
+
+ if (first == true) {
+ ck_pr_store_uint(&barrier, n_threads);
+ first = false;
+ }
+
+ counter++;
+ if (ck_pr_load_uint(&barrier) == 0)
+ break;
+ }
+
+ printf("%u updates made.\n", counter);
+ return (0);
+}
+