summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Braun <rbraun@sceen.net>2018-04-01 07:01:35 +0200
committerRichard Braun <rbraun@sceen.net>2018-04-01 07:01:35 +0200
commitab90d4e1fcd12552105843beef888d342b58fd7b (patch)
tree4243ce2df63d489b5b0a40536a0dde4059fa3958
parenta098d10f233dcc43bfeba70fb54ab57b5a7d500a (diff)
parentcb86e4abaa7f3419ea0e096e5ca80ede5505a696 (diff)
Merge branch 'bulletin'
-rw-r--r--kern/Makefile1
-rw-r--r--kern/bulletin.c83
-rw-r--r--kern/bulletin.h75
-rw-r--r--kern/bulletin_i.h35
-rw-r--r--test/Kconfig3
-rw-r--r--test/Makefile1
-rw-r--r--test/test_bulletin.c83
7 files changed, 281 insertions, 0 deletions
diff --git a/kern/Makefile b/kern/Makefile
index 0d848cc..ab7d6b5 100644
--- a/kern/Makefile
+++ b/kern/Makefile
@@ -1,6 +1,7 @@
x15_SOURCES-y += \
kern/arg.c \
kern/bitmap.c \
+ kern/bulletin.c \
kern/cbuf.c \
kern/clock.c \
kern/condition.c \
diff --git a/kern/bulletin.c b/kern/bulletin.c
new file mode 100644
index 0000000..bbb1bfc
--- /dev/null
+++ b/kern/bulletin.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017-2018 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/>.
+ */
+
+#include <assert.h>
+#include <stdint.h>
+
+#include <kern/bulletin.h>
+#include <kern/list.h>
+#include <kern/rcu.h>
+#include <kern/spinlock.h>
+#include <kern/thread.h>
+
+static void
+bulletin_sub_init(struct bulletin_sub *sub,
+ bulletin_notif_fn_t notif_fn, void *arg)
+{
+ sub->notif_fn = notif_fn;
+ sub->arg = arg;
+}
+
+static void
+bulletin_sub_notify(const struct bulletin_sub *sub, uintptr_t value)
+{
+ sub->notif_fn(value, sub->arg);
+}
+
+void
+bulletin_init(struct bulletin *bulletin)
+{
+ spinlock_init(&bulletin->lock);
+ list_init(&bulletin->subs);
+}
+
+void
+bulletin_subscribe(struct bulletin *bulletin, struct bulletin_sub *sub,
+ bulletin_notif_fn_t notif_fn, void *arg)
+{
+ bulletin_sub_init(sub, notif_fn, arg);
+
+ spinlock_lock(&bulletin->lock);
+ list_rcu_insert_tail(&bulletin->subs, &sub->node);
+ spinlock_unlock(&bulletin->lock);
+}
+
+void
+bulletin_unsubscribe(struct bulletin *bulletin, struct bulletin_sub *sub)
+{
+ spinlock_lock(&bulletin->lock);
+ list_rcu_remove(&sub->node);
+ spinlock_unlock(&bulletin->lock);
+
+ rcu_wait();
+}
+
+void
+bulletin_publish(struct bulletin *bulletin, uintptr_t value)
+{
+ struct bulletin_sub *sub;
+
+ assert(!thread_interrupted());
+
+ rcu_read_enter();
+
+ list_rcu_for_each_entry(&bulletin->subs, sub, node) {
+ bulletin_sub_notify(sub, value);
+ }
+
+ rcu_read_leave();
+}
diff --git a/kern/bulletin.h b/kern/bulletin.h
new file mode 100644
index 0000000..8ce9d9e
--- /dev/null
+++ b/kern/bulletin.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2017-2018 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/>.
+ *
+ *
+ * Minimalist publish-subscribe mechanism.
+ */
+
+#ifndef KERN_BULLETIN_H
+#define KERN_BULLETIN_H
+
+#include <stdint.h>
+
+#include <kern/macros.h>
+#include <kern/work.h>
+
+/*
+ * Type for bulletin notification functions.
+ *
+ * The value is passed from the publisher unmodified, and can safely be
+ * cast into a pointer. Notification functions run in the context of the
+ * publisher.
+ */
+typedef void (*bulletin_notif_fn_t)(uintptr_t value, void *arg);
+
+#include <kern/bulletin_i.h>
+
+struct bulletin;
+
+/*
+ * Bulletin subscriber.
+ */
+struct bulletin_sub;
+
+void bulletin_init(struct bulletin *bulletin);
+
+/*
+ * Subscribe to a bulletin.
+ *
+ * Once subscribed, the notification function is called with its argument
+ * each time the bulletin is published.
+ */
+void bulletin_subscribe(struct bulletin *bulletin, struct bulletin_sub *sub,
+ bulletin_notif_fn_t notif_fn, void *arg);
+
+/*
+ * Unsubscribe from a bulletin.
+ *
+ * On return, the subscriber notification function may not be called any more.
+ *
+ * This function synchronizes with RCU.
+ */
+void bulletin_unsubscribe(struct bulletin *bulletin, struct bulletin_sub *sub);
+
+/*
+ * Publish a bulletin.
+ *
+ * All subscribers are notified by calling their notification function, with
+ * the given value passed unmodified.
+ */
+void bulletin_publish(struct bulletin *bulletin, uintptr_t value);
+
+#endif /* KERN_BULLETIN_H */
diff --git a/kern/bulletin_i.h b/kern/bulletin_i.h
new file mode 100644
index 0000000..ea0940a
--- /dev/null
+++ b/kern/bulletin_i.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (c) 2017-2018 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/>.
+ */
+
+#ifndef KERN_BULLETIN_I_H
+#define KERN_BULLETIN_I_H
+
+#include <kern/list.h>
+#include <kern/spinlock.h>
+
+struct bulletin_sub {
+ struct list node;
+ bulletin_notif_fn_t notif_fn;
+ void *arg;
+};
+
+struct bulletin {
+ struct spinlock lock;
+ struct list subs;
+};
+
+#endif /* KERN_BULLETIN_I_H */
diff --git a/test/Kconfig b/test/Kconfig
index 5c3072d..80679ef 100644
--- a/test/Kconfig
+++ b/test/Kconfig
@@ -9,6 +9,9 @@ if TEST_MODULE
choice
prompt "Select test module"
+config TEST_MODULE_BULLETIN
+ bool "bulletin"
+
config TEST_MODULE_MUTEX
bool "mutex"
select MUTEX_DEBUG
diff --git a/test/Makefile b/test/Makefile
index 96541af..c98d6fb 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -1,3 +1,4 @@
+x15_SOURCES-$(CONFIG_TEST_MODULE_BULLETIN) += test/test_bulletin.c
x15_SOURCES-$(CONFIG_TEST_MODULE_MUTEX) += test/test_mutex.c
x15_SOURCES-$(CONFIG_TEST_MODULE_MUTEX_PI) += test/test_mutex_pi.c
x15_SOURCES-$(CONFIG_TEST_MODULE_PMAP_UPDATE_MP) += test/test_pmap_update_mp.c
diff --git a/test/test_bulletin.c b/test/test_bulletin.c
new file mode 100644
index 0000000..4a2fdb5
--- /dev/null
+++ b/test/test_bulletin.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2018 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/>.
+ *
+ *
+ * This test makes a bulletin subscriber subscribe to a bulletin, and uses
+ * a timer to periodically publish, unsubscribe, and resubscribe to the
+ * bulletin. A counter is used to test passing values to the notification
+ * callback function.
+ */
+
+#include <assert.h>
+#include <stdbool.h>
+#include <stddef.h>
+#include <stdio.h>
+
+#include <kern/bulletin.h>
+#include <kern/clock.h>
+#include <kern/error.h>
+#include <kern/log.h>
+#include <kern/timer.h>
+#include <test/test.h>
+
+#define TEST_INTERVAL 1
+#define TEST_NR_LOOPS 4
+
+static struct bulletin test_bulletin;
+static struct bulletin_sub test_bulletin_sub;
+static struct timer test_timer;
+static unsigned int test_counter;
+
+static void
+test_notify(uintptr_t value, void *arg)
+{
+ log_info("test: notify: value:%lu arg:%p", value, arg);
+}
+
+static void
+test_tick(struct timer *timer)
+{
+ uint64_t ticks;
+
+ test_counter++;
+ bulletin_publish(&test_bulletin, test_counter);
+ bulletin_unsubscribe(&test_bulletin, &test_bulletin_sub);
+
+ if (test_counter == TEST_NR_LOOPS) {
+ log_info("test: done");
+ return;
+ }
+
+ bulletin_subscribe(&test_bulletin, &test_bulletin_sub,
+ test_notify, (void *)0x123);
+
+ ticks = timer_get_time(timer) + clock_ticks_from_ms(TEST_INTERVAL * 1000);
+ timer_schedule(&test_timer, ticks);
+}
+
+void __init
+test_setup(void)
+{
+ uint64_t ticks;
+
+ bulletin_init(&test_bulletin);
+ bulletin_subscribe(&test_bulletin, &test_bulletin_sub,
+ test_notify, (void *)0x123);
+
+ timer_init(&test_timer, test_tick, TIMER_DETACHED);
+ ticks = clock_get_time() + clock_ticks_from_ms(TEST_INTERVAL * 1000);
+ timer_schedule(&test_timer, ticks);
+}