summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2014-09-23 00:31:04 +0200
committerRichard Braun <rbraun@sceen.net>2014-09-23 00:31:04 +0200
commit9817163fb65ef95431eb826985febdc916f10773 (patch)
treed0940c7e40236caf8690060bffb83b4c0a7284d0 /test
parente53d1a6c5faac903cc2dd684bf552b90df094c64 (diff)
test/test_sref_dirty_zeroes: new test module
Actually, it's not that hard to produce dirty zeroes. Here is a test module that does just that, and exposes a bug in the algorithm.
Diffstat (limited to 'test')
-rw-r--r--test/test_sref_dirty_zeroes.c122
-rw-r--r--test/test_sref_noref.c5
2 files changed, 124 insertions, 3 deletions
diff --git a/test/test_sref_dirty_zeroes.c b/test/test_sref_dirty_zeroes.c
new file mode 100644
index 00000000..2e16ffc6
--- /dev/null
+++ b/test/test_sref_dirty_zeroes.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2014 Richard Braun.
+ *
+ * This program 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.
+ *
+ * This program 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/>.
+ *
+ *
+ * The purpose of this test module is to produce dirty zeroes and make
+ * sure they're correctly processed. It is a stress test that never ends,
+ * except on failure. Two threads are created. The first increments a
+ * scalable reference counter, then signals the second that it can decrement
+ * it. Since these threads are likely to run on different processors, a
+ * good amount of dirty zeroes should be produced, as reported by regularly
+ * printing the relevant event counters. Since the true number of references
+ * can never drop to 0, the no-reference function should never be called,
+ * and panics if it is.
+ */
+
+#include <kern/assert.h>
+#include <kern/condition.h>
+#include <kern/evcnt.h>
+#include <kern/kmem.h>
+#include <kern/macros.h>
+#include <kern/mutex.h>
+#include <kern/sprintf.h>
+#include <kern/sref.h>
+#include <kern/stddef.h>
+#include <kern/thread.h>
+#include <test/test.h>
+#include <vm/vm_kmem.h>
+
+static struct condition test_condition;
+static struct mutex test_lock;
+static struct sref_counter test_counter;
+static unsigned long test_transient_ref;
+
+static void
+test_inc(void *arg)
+{
+ volatile unsigned long i;
+ (void)arg;
+
+ for (;;) {
+ for (i = 0; i < 1000000; i++) {
+ sref_counter_inc(&test_counter);
+
+ mutex_lock(&test_lock);
+ test_transient_ref++;
+ condition_signal(&test_condition);
+
+ while (test_transient_ref != 0)
+ condition_wait(&test_condition, &test_lock);
+
+ mutex_unlock(&test_lock);
+ }
+
+ printk("counter global value: %lu\n", test_counter.value);
+ evcnt_info("sref_epoch");
+ evcnt_info("sref_dirty_zero");
+ evcnt_info("sref_true_zero");
+ }
+}
+
+static void
+test_dec(void *arg)
+{
+ (void)arg;
+
+ for (;;) {
+ mutex_lock(&test_lock);
+
+ while (test_transient_ref == 0)
+ condition_wait(&test_condition, &test_lock);
+
+ test_transient_ref--;
+ condition_signal(&test_condition);
+ mutex_unlock(&test_lock);
+
+ sref_counter_dec(&test_counter);
+ }
+}
+
+static void
+test_noref(struct sref_counter *counter)
+{
+ (void)counter;
+ panic("0 references, page released\n");
+}
+
+void
+test_setup(void)
+{
+ struct thread_attr attr;
+ struct thread *thread;
+ int error;
+
+ condition_init(&test_condition);
+ mutex_init(&test_lock);
+
+ sref_counter_init(&test_counter, test_noref);
+ test_transient_ref = 0;
+
+ thread_attr_init(&attr, "x15_test_inc");
+ thread_attr_set_detached(&attr);
+ error = thread_create(&thread, &attr, test_inc, NULL);
+ assert(!error);
+
+ thread_attr_init(&attr, "x15_test_dec");
+ thread_attr_set_detached(&attr);
+ error = thread_create(&thread, &attr, test_dec, NULL);
+ assert(!error);
+}
diff --git a/test/test_sref_noref.c b/test/test_sref_noref.c
index e58917c7..911eb61e 100644
--- a/test/test_sref_noref.c
+++ b/test/test_sref_noref.c
@@ -28,9 +28,8 @@
* Finally, it releases the initial reference, at which point, the
* no-reference function should be called.
*
- * Notes:
- * The number of loops must be large enough to allow many epochs to occur.
- * Also, it's very hard to artificially produce dirty zeroes.
+ * Notes: the number of loops must be large enough to allow many epochs
+ * to occur.
*/
#include <kern/assert.h>