All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/5] cobalt/events: add auto-clear feature
@ 2022-04-06 15:56 Philippe Gerum
  2022-04-06 15:56 ` [PATCH 2/5] cobalt/events: add single-waiter delivery mode Philippe Gerum
                   ` (4 more replies)
  0 siblings, 5 replies; 15+ messages in thread
From: Philippe Gerum @ 2022-04-06 15:56 UTC (permalink / raw)
  To: xenomai

From: Philippe Gerum <rpm@xenomai.org>

The current implementation does not atomically consume+clear the event
set to be received by the waiter(s), which makes it useless for
anything but a plain one-time latch due to the race window this opens
with a consume[A]->signal[B]->clear[A] sequence.

To address this issue, let's provide the auto-clear feature with
__cobalt_event_wait().

This change affects the ABI by adding the auto-clear mode as an opt-in
feature, enabled by passing COBALT_EVENT_AUTOCLEAR to
cobalt_event_init().

Signed-off-by: Philippe Gerum <rpm@xenomai.org>
---
 configure.ac                        |   1 +
 include/cobalt/uapi/event.h         |   7 +-
 kernel/cobalt/posix/event.c         |  17 +++-
 testsuite/smokey/Makefile.am        |   2 +
 testsuite/smokey/events/Makefile.am |   8 ++
 testsuite/smokey/events/events.c    | 123 ++++++++++++++++++++++++++++
 6 files changed, 152 insertions(+), 6 deletions(-)
 create mode 100644 testsuite/smokey/events/Makefile.am
 create mode 100644 testsuite/smokey/events/events.c

diff --git a/configure.ac b/configure.ac
index 5611b5b8db..15d3e46e9a 100644
--- a/configure.ac
+++ b/configure.ac
@@ -1002,6 +1002,7 @@ AC_CONFIG_FILES([ \
 	testsuite/smokey/gdb/Makefile \
 	testsuite/smokey/y2038/Makefile \
 	testsuite/smokey/can/Makefile
+	testsuite/smokey/events/Makefile \
 	testsuite/clocktest/Makefile \
 	testsuite/xeno-test/Makefile \
 	utils/Makefile \
diff --git a/include/cobalt/uapi/event.h b/include/cobalt/uapi/event.h
index 8710e8e25f..14ddbcf567 100644
--- a/include/cobalt/uapi/event.h
+++ b/include/cobalt/uapi/event.h
@@ -30,9 +30,10 @@ struct cobalt_event_state {
 struct cobalt_event;
 
 /* Creation flags. */
-#define COBALT_EVENT_FIFO    0x0
-#define COBALT_EVENT_PRIO    0x1
-#define COBALT_EVENT_SHARED  0x2
+#define COBALT_EVENT_FIFO       0x0
+#define COBALT_EVENT_PRIO       0x1
+#define COBALT_EVENT_SHARED     0x2
+#define COBALT_EVENT_AUTOCLEAR  0x4
 
 /* Wait mode. */
 #define COBALT_EVENT_ALL  0x0
diff --git a/kernel/cobalt/posix/event.c b/kernel/cobalt/posix/event.c
index 052c686050..0a1236ad73 100644
--- a/kernel/cobalt/posix/event.c
+++ b/kernel/cobalt/posix/event.c
@@ -146,7 +146,7 @@ int __cobalt_event_wait(struct cobalt_event_shadow __user *u_event,
 	if (bits == 0) {
 		/*
 		 * Special case: we don't wait for any event, we only
-		 * return the current flag group value.
+		 * return the pending ones without consuming them.
 		 */
 		rbits = state->value;
 		goto out;
@@ -155,8 +155,11 @@ int __cobalt_event_wait(struct cobalt_event_shadow __user *u_event,
 	state->flags |= COBALT_EVENT_PENDED;
 	rbits = state->value & bits;
 	testval = mode & COBALT_EVENT_ANY ? rbits : bits;
-	if (rbits && rbits == testval)
+	if (rbits && rbits == testval) {
+		if (event->flags & COBALT_EVENT_AUTOCLEAR)
+			state->value &= ~rbits;
 		goto done;
+	}
 
 	if (timeout == XN_NONBLOCK) {
 		ret = -EWOULDBLOCK;
@@ -239,7 +242,7 @@ COBALT_SYSCALL(event_wait64, primary,
 COBALT_SYSCALL(event_sync, current,
 	       (struct cobalt_event_shadow __user *u_event))
 {
-	unsigned int bits, waitval, testval;
+	unsigned int bits, waitval, testval, consumed = 0;
 	struct xnthread_wait_context *wc;
 	struct cobalt_event_state *state;
 	struct event_wait_context *ewc;
@@ -275,10 +278,18 @@ COBALT_SYSCALL(event_sync, current,
 		if (waitval && waitval == testval) {
 			state->nwaiters--;
 			ewc->value = waitval;
+			consumed |= waitval;
 			xnsynch_wakeup_this_sleeper(&event->synch, p);
 		}
 	}
 
+	/*
+	 * If some flags were consumed and auto-clear is enabled,
+	 * clear the former.
+	 */
+	if (consumed && (event->flags & COBALT_EVENT_AUTOCLEAR))
+		state->value &= ~consumed;
+
 	xnsched_run();
 out:
 	xnlock_put_irqrestore(&nklock, s);
diff --git a/testsuite/smokey/Makefile.am b/testsuite/smokey/Makefile.am
index 4a9773f586..3f0521282b 100644
--- a/testsuite/smokey/Makefile.am
+++ b/testsuite/smokey/Makefile.am
@@ -14,6 +14,7 @@ COBALT_SUBDIRS = 	\
 	bufp		\
 	can		\
 	cpu-affinity	\
+	events		\
 	fpu-stress	\
 	gdb		\
 	iddp		\
@@ -53,6 +54,7 @@ DIST_SUBDIRS = 		\
 	can		\
 	cpu-affinity	\
 	dlopen		\
+	events		\
 	fpu-stress	\
 	gdb		\
 	iddp		\
diff --git a/testsuite/smokey/events/Makefile.am b/testsuite/smokey/events/Makefile.am
new file mode 100644
index 0000000000..37b9f92d7f
--- /dev/null
+++ b/testsuite/smokey/events/Makefile.am
@@ -0,0 +1,8 @@
+
+noinst_LIBRARIES = libevents.a
+
+libevents_a_SOURCES = events.c
+
+libevents_a_CPPFLAGS = 		\
+	@XENO_USER_CFLAGS@	\
+	-I$(top_srcdir)/include
diff --git a/testsuite/smokey/events/events.c b/testsuite/smokey/events/events.c
new file mode 100644
index 0000000000..79711795ac
--- /dev/null
+++ b/testsuite/smokey/events/events.c
@@ -0,0 +1,123 @@
+#include <stdlib.h>
+#include <unistd.h>
+#include <smokey/smokey.h>
+#include <cobalt/time.h>
+#include <cobalt/semaphore.h>
+#include <cobalt/pthread.h>
+#include <cobalt/sys/cobalt.h>
+#include <boilerplate/time.h>
+
+smokey_test_plugin(events,
+		   SMOKEY_NOARGS,
+		   "Check event event"
+);
+
+#define LOW_PRIO	1
+#define HIGH_PRIO	2
+
+struct test_context {
+	cobalt_event_t event;
+	sem_t start;
+	sem_t sem;
+};
+
+static void *event_receiver(void *arg)
+{
+	struct test_context *p = arg;
+	struct timespec now, timeout;
+	unsigned int bits;
+	int ret;
+
+	sem_wait(&p->start);
+	clock_gettime(CLOCK_MONOTONIC, &now);
+	timespec_adds(&timeout, &now, 400000000); /* 400ms */
+
+	/* Sender is quiet: expect timeout. */
+	if (!__F(ret, cobalt_event_wait(&p->event, -1U, &bits,
+				COBALT_EVENT_ANY, &timeout)) ||
+		!__Tassert(ret == -ETIMEDOUT))
+		goto fail;
+
+	sem_post(&p->sem);
+
+	/* Sender should have sent 0x12121212. */
+	clock_gettime(CLOCK_MONOTONIC, &now);
+	timespec_adds(&timeout, &now, 400000000); /* 400ms */
+	if (!__T(ret, cobalt_event_wait(&p->event, -1U, &bits,
+				COBALT_EVENT_ANY, &timeout)))
+		goto fail;
+
+	if (!__Tassert(bits == 0x12121212))
+		goto fail;
+
+	sem_post(&p->sem);
+
+	/* Sender should send 0x41414141 in a moment. */
+	if (!__T(ret, cobalt_event_wait(&p->event, 0x41414141, &bits,
+				COBALT_EVENT_ALL, NULL)))
+		goto fail;
+
+	if (!__Tassert(bits == 0x41414141))
+		goto fail;
+
+	sem_post(&p->sem);
+
+	return NULL;
+fail:
+	exit(-ret);
+}
+
+static int run_events(struct smokey_test *t, int argc, char *const argv[])
+{
+	struct sched_param param;
+	struct test_context c;
+	pthread_attr_t attr;
+	void *status = NULL;
+	pthread_t receiver;
+	int ret;
+
+	param.sched_priority = HIGH_PRIO;
+	if (!__Tassert(pthread_setschedparam(pthread_self(),
+			SCHED_FIFO, &param) == 0))
+		return -EPERM;
+
+	sem_init(&c.sem, 0, 0);
+	sem_init(&c.start, 0, 0);
+
+	if (!__T(ret, cobalt_event_init(&c.event, 0,
+		COBALT_EVENT_FIFO|COBALT_EVENT_AUTOCLEAR)))
+		return ret;
+
+	param.sched_priority = LOW_PRIO;
+	pthread_attr_init(&attr);
+	pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
+	pthread_attr_setinheritsched(&attr, PTHREAD_EXPLICIT_SCHED);
+	pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
+	pthread_attr_setschedparam(&attr, &param);
+
+	if (!__T(ret, pthread_create(&receiver, &attr, event_receiver, &c)))
+		return ret;
+
+	sem_post(&c.start);
+	sem_wait(&c.sem);
+
+	if (!__T(ret, cobalt_event_post(&c.event, 0x12121212)))
+		return ret;
+
+	sem_wait(&c.sem);
+	usleep(1000);
+
+	if (!__T(ret, cobalt_event_post(&c.event, 0x41414141)))
+		return ret;
+
+	sem_wait(&c.sem);
+
+	pthread_join(receiver, &status);
+	if (!__Tassert(status == NULL))
+		return -EPROTO;
+
+	if (!__T(ret, cobalt_event_destroy(&c.event)))
+		return ret;
+
+	return 0;
+}
-- 
2.34.1



^ permalink raw reply related	[flat|nested] 15+ messages in thread

end of thread, other threads:[~2022-04-13 11:21 UTC | newest]

Thread overview: 15+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2022-04-06 15:56 [PATCH 1/5] cobalt/events: add auto-clear feature Philippe Gerum
2022-04-06 15:56 ` [PATCH 2/5] cobalt/events: add single-waiter delivery mode Philippe Gerum
2022-04-07  9:49   ` Jan Kiszka
2022-04-07 11:26     ` Philippe Gerum
2022-04-06 15:56 ` [PATCH 3/5] copperplate, testsuite: convert to cobalt_event_broadcast() Philippe Gerum
2022-04-06 15:56 ` [PATCH 4/5] lib/cobalt: deprecate cobalt_event_post() Philippe Gerum
2022-04-06 15:56 ` [PATCH 5/5] drivers: ipc: enable non-blocking write from regular threads Philippe Gerum
2022-04-07  9:51   ` Jan Kiszka
2022-04-07 11:37     ` Philippe Gerum
2022-04-13 11:21   ` Jan Kiszka
2022-04-07  9:47 ` [PATCH 1/5] cobalt/events: add auto-clear feature Jan Kiszka
2022-04-07 11:16   ` Philippe Gerum
2022-04-07 16:39     ` Jan Kiszka
2022-04-07 17:09       ` Philippe Gerum
2022-04-13 11:20         ` Jan Kiszka

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.