[LTP] [PATCH 2/6] api/evloop: Add helpers for creating an event loop
Richard Palethorpe
rpalethorpe@suse.com
Tue Sep 27 18:14:04 CEST 2022
Puts some of the boiler plate for creating an "event loop", into an
API. Useful for asynchronous or evented I/O.
This uses epoll and signalfd which are very widely supported on
Linux. I also think epoll is a better interface than ppoll and
pselect.
The tst_epoll_event_data struct (added in the previous commit) can be
used to add callbacks on particular FD events.
There is also a special callback for the signlfd and on_cont which is
called at the end of each loop. Returning 0 from these will cause the
loop to exit.
Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
---
include/tst_evloop.h | 32 ++++++++++++++
lib/tst_evloop.c | 102 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 134 insertions(+)
create mode 100644 include/tst_evloop.h
create mode 100644 lib/tst_evloop.c
diff --git a/include/tst_evloop.h b/include/tst_evloop.h
new file mode 100644
index 000000000..bdab2d6f7
--- /dev/null
+++ b/include/tst_evloop.h
@@ -0,0 +1,32 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 SUSE LLC <rpalethorpe@suse.com>
+ */
+
+#include "inttypes.h"
+#include "sys/signalfd.h"
+
+#include "tst_epoll.h"
+
+#ifndef TST_EVLOOP_H
+#define TST_EVLOOP_H
+
+struct tst_evloop {
+ int epollfd;
+ int signalfd;
+ struct tst_epoll_event_data signalfd_evdata;
+ int timeout;
+
+ void *priv;
+ int (*on_cont)(struct tst_evloop *self);
+ int (*on_signal)(struct tst_evloop *self, struct signalfd_siginfo *si);
+};
+
+void tst_evloop_setup(struct tst_evloop *self);
+void tst_evloop_run(struct tst_evloop *self);
+void tst_evloop_add(struct tst_evloop *self,
+ struct tst_epoll_event_data *evdata,
+ int fd, uint32_t events);
+void tst_evloop_cleanup(struct tst_evloop *self);
+
+#endif
diff --git a/lib/tst_evloop.c b/lib/tst_evloop.c
new file mode 100644
index 000000000..66d74ce58
--- /dev/null
+++ b/lib/tst_evloop.c
@@ -0,0 +1,102 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2022 SUSE LLC <rpalethorpe@suse.com>
+ */
+#define _GNU_SOURCE
+#define TST_NO_DEFAULT_MAIN
+
+#include "tst_test.h"
+#include "tst_evloop.h"
+
+static void handle_epoll_event(struct epoll_event *event)
+{
+ struct tst_epoll_event_data *data = event->data.ptr;
+
+ data->on_epoll(data->self, event->events);
+}
+
+static int evloop_on_signal(struct tst_evloop *self, uint32_t events)
+{
+ int i, n;
+ struct signalfd_siginfo si[16];
+
+ if (events ^ EPOLLIN) {
+ tst_brk(TBROK, "Unexpected event on signalfd");
+ return 1;
+ }
+
+ n = SAFE_READ(0, self->signalfd, si, sizeof(si));
+
+ if (!n)
+ tst_brk(TBROK, "Got EPOLLIN on signalfd, but no signal read from fd");
+
+ for (i = 0; i < n/(int)sizeof(si[0]); i++) {
+ if (!self->on_signal(self, si + i))
+ return 0;
+ }
+
+ return 1;
+}
+
+void tst_evloop_add(struct tst_evloop *self,
+ struct tst_epoll_event_data *evdata,
+ int fd, uint32_t events)
+{
+ struct epoll_event ev = {
+ .events = events,
+ .data.ptr = evdata,
+ };
+
+ SAFE_EPOLL_CTL(self->epollfd, EPOLL_CTL_ADD, fd, &ev);
+}
+
+void tst_evloop_setup(struct tst_evloop *self)
+{
+
+ sigset_t mask;
+
+ self->epollfd = SAFE_EPOLL_CREATE1(EPOLL_CLOEXEC);
+
+ sigfillset(&mask);
+ SAFE_SIGPROCMASK(SIG_BLOCK, &mask, NULL);
+ self->signalfd = signalfd(-1, &mask, SFD_CLOEXEC);
+
+ self->signalfd_evdata.self = self;
+ self->signalfd_evdata.on_epoll = (tst_on_epoll_fn)evloop_on_signal;
+
+ tst_evloop_add(self, &self->signalfd_evdata, self->signalfd, EPOLLIN);
+}
+
+void tst_evloop_run(struct tst_evloop *self)
+{
+ static int saturated_warn;
+ const int maxevents = 128;
+ struct epoll_event events[maxevents];
+
+ for (;;) {
+ const int ev_num = SAFE_EPOLL_WAIT(self->epollfd, events,
+ maxevents, self->timeout);
+
+ for (int i = 0; i < ev_num; i++)
+ handle_epoll_event(events + i);
+
+ if (ev_num == maxevents) {
+ if (!saturated_warn)
+ tst_res(TINFO, "Event loop saturated");
+
+ saturated_warn = 1;
+ continue;
+ }
+
+ if (!self->on_cont(self))
+ break;
+ }
+}
+
+void tst_evloop_cleanup(struct tst_evloop *self)
+{
+ if (self->epollfd > 0)
+ SAFE_CLOSE(self->epollfd);
+ if (self->signalfd > 0)
+ SAFE_CLOSE(self->signalfd);
+}
--
2.36.1
More information about the ltp
mailing list