[RFC PATCH 4/4] WIP: hazptr: Add hazptr test sample

Boqun Feng posted 4 patches 2 months, 1 week ago
[RFC PATCH 4/4] WIP: hazptr: Add hazptr test sample
Posted by Boqun Feng 2 months, 1 week ago
Sample code for hazptr. This should go away or get more polished when
hazptr support is added into rcutorture.

Signed-off-by: Boqun Feng <boqun.feng@gmail.com>
---
 samples/Kconfig              |  6 +++
 samples/Makefile             |  1 +
 samples/hazptr/hazptr_test.c | 87 ++++++++++++++++++++++++++++++++++++
 3 files changed, 94 insertions(+)
 create mode 100644 samples/hazptr/hazptr_test.c

diff --git a/samples/Kconfig b/samples/Kconfig
index b288d9991d27..9b42cde35dca 100644
--- a/samples/Kconfig
+++ b/samples/Kconfig
@@ -293,6 +293,12 @@ config SAMPLE_CGROUP
 
 source "samples/rust/Kconfig"
 
+config SAMPLE_HAZPTR
+	bool "Build hazptr sample code"
+	help
+	  Build samples that shows hazard pointer usage. Currently only
+	  builtin usage is supported.
+
 endif # SAMPLES
 
 config HAVE_SAMPLE_FTRACE_DIRECT
diff --git a/samples/Makefile b/samples/Makefile
index b85fa64390c5..0be21edc8a30 100644
--- a/samples/Makefile
+++ b/samples/Makefile
@@ -39,3 +39,4 @@ obj-$(CONFIG_SAMPLE_KMEMLEAK)		+= kmemleak/
 obj-$(CONFIG_SAMPLE_CORESIGHT_SYSCFG)	+= coresight/
 obj-$(CONFIG_SAMPLE_FPROBE)		+= fprobe/
 obj-$(CONFIG_SAMPLES_RUST)		+= rust/
+obj-$(CONFIG_SAMPLE_HAZPTR)		+= hazptr/
diff --git a/samples/hazptr/hazptr_test.c b/samples/hazptr/hazptr_test.c
new file mode 100644
index 000000000000..3cf0cdc8a83a
--- /dev/null
+++ b/samples/hazptr/hazptr_test.c
@@ -0,0 +1,87 @@
+#include <linux/module.h>
+#include <linux/kthread.h>
+#include <linux/hazptr.h>
+
+struct foo {
+	int i;
+	struct callback_head head;
+};
+
+static void simple_func(struct callback_head *head)
+{
+	struct foo *ptr = container_of(head, struct foo, head);
+
+	printk("callback called %px, i is %d\n", ptr, ptr->i);
+	kfree(ptr);
+}
+
+static void simple(void)
+{
+	struct hazptr_context ctx;
+	struct foo *dummy, *tmp, *other;
+	hazptr_t *hptr;
+	hazptr_t *hptr2;
+
+	dummy = kzalloc(sizeof(*dummy), GFP_KERNEL);
+	dummy->i = 42;
+
+	other = kzalloc(sizeof(*dummy), GFP_KERNEL);
+	other->i = 43;
+
+	if (!dummy || !other) {
+		printk("allocation failed, skip test\n");
+		return;
+	}
+
+	init_hazptr_context(&ctx);
+	hptr = hazptr_alloc(&ctx);
+	BUG_ON(!hptr);
+
+	// Get a second hptr.
+	hptr2 = hazptr_alloc(&ctx);
+	BUG_ON(!hptr2);
+
+	// No one is modifying 'dummy', protection must succeed.
+	BUG_ON(!hazptr_tryprotect(hptr, dummy, head));
+
+	// Simulate changing a global pointer.
+	tmp = dummy;
+	WRITE_ONCE(dummy, other);
+
+	// Callback will run after no active readers.
+	printk("callback added, %px\n", tmp);
+
+	call_hazptr(&tmp->head, simple_func);
+
+	// No one is modifying 'dummy', protection must succeed.
+	tmp = hazptr_protect(hptr2, dummy, head);
+
+	printk("reader2 got %px, i is %d\n", tmp, tmp->i);
+
+	// The above callback should run after this.
+	hazptr_clear(hptr);
+	printk("first reader is out\n");
+
+	for (int i = 0; i < 10; i++)
+		schedule(); // yield a few times.
+
+	// Simulate freeing a global pointer.
+	tmp = dummy;
+	WRITE_ONCE(dummy, NULL);
+	printk("callback added, %px\n", tmp);
+	call_hazptr(&tmp->head, simple_func);
+
+	cleanup_hazptr_context(&ctx);
+	printk("no reader here\n");
+
+	for (int i = 0; i < 10; i++)
+		schedule(); // yield a few times.
+}
+
+static int hazptr_test(void)
+{
+	simple();
+	printk("test ends\n");
+	return 0;
+}
+module_init(hazptr_test);
-- 
2.45.2