summaryrefslogtreecommitdiffstats
path: root/src/evmgr.c
diff options
context:
space:
mode:
authorJosé Bollo <jose.bollo@iot.bzh>2019-02-13 20:14:52 +0100
committerJose Bollo <jose.bollo@iot.bzh>2019-03-27 10:48:40 +0100
commitd9de3cd38b17ad16fb6ad6f74e83f4700c5f2b49 (patch)
tree321ac1f2202913c947876f3f8f2c9b082616a79c /src/evmgr.c
parentc330ecf92fef81fdb0471715326b8bc6b4d52bc6 (diff)
evmgr: Isolate the event loop from jobs
The event loop is renamed evmgr for "event manager" with the intention (1) still use evloop in jobs (2) to provide an abstract event manager/handler/loop abstraction. Change-Id: Ib1955f661f98df80e1c7be99e9fe26a1e06d78f6 Signed-off-by: José Bollo <jose.bollo@iot.bzh>
Diffstat (limited to 'src/evmgr.c')
-rw-r--r--src/evmgr.c220
1 files changed, 220 insertions, 0 deletions
diff --git a/src/evmgr.c b/src/evmgr.c
new file mode 100644
index 00000000..2dc35e42
--- /dev/null
+++ b/src/evmgr.c
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2016-2019 "IoT.bzh"
+ * Author José Bollo <jose.bollo@iot.bzh>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#define _GNU_SOURCE
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <time.h>
+#include <sys/syscall.h>
+#include <pthread.h>
+#include <errno.h>
+#include <assert.h>
+#include <sys/eventfd.h>
+
+#include <systemd/sd-event.h>
+
+#include "evmgr.h"
+#include "verbose.h"
+#include "systemd.h"
+
+/** Description of handled event loops */
+struct evmgr
+{
+ unsigned state; /**< encoded state */
+ int efd; /**< event notification */
+ void *holder; /**< holder of the evmgr */
+ struct sd_event *sdev; /**< the systemd event loop */
+};
+
+#define EVLOOP_STATE_WAIT 1U
+#define EVLOOP_STATE_RUN 2U
+
+/**
+ * Run the event loop is set.
+ */
+void evmgr_run(struct evmgr *evmgr)
+{
+ int rc;
+ struct sd_event *se;
+
+ evmgr->state = EVLOOP_STATE_WAIT|EVLOOP_STATE_RUN;
+ se = evmgr->sdev;
+ rc = sd_event_prepare(se);
+ if (rc < 0) {
+ errno = -rc;
+ CRITICAL("sd_event_prepare returned an error (state: %d): %m", sd_event_get_state(se));
+ abort();
+ } else {
+ if (rc == 0) {
+ rc = sd_event_wait(se, (uint64_t)(int64_t)-1);
+ if (rc < 0) {
+ errno = -rc;
+ ERROR("sd_event_wait returned an error (state: %d): %m", sd_event_get_state(se));
+ }
+ }
+ evmgr->state = EVLOOP_STATE_RUN;
+ if (rc > 0) {
+ rc = sd_event_dispatch(se);
+ if (rc < 0) {
+ errno = -rc;
+ ERROR("sd_event_dispatch returned an error (state: %d): %m", sd_event_get_state(se));
+ }
+ }
+ }
+ evmgr->state = 0;
+}
+
+void evmgr_job_run(int signum, struct evmgr *evmgr)
+{
+ if (signum)
+ evmgr->state = 0;
+ else
+ evmgr_run(evmgr);
+}
+
+int evmgr_can_run(struct evmgr *evmgr)
+{
+ return !evmgr->state;
+}
+
+/**
+ * Internal callback for evmgr management.
+ * The effect of this function is hidden: it exits
+ * the waiting poll if any.
+ */
+static void evmgr_on_efd_event(struct evmgr *evmgr)
+{
+ uint64_t x;
+ read(evmgr->efd, &x, sizeof x);
+}
+
+/**
+ * wakeup the event loop if needed by sending
+ * an event.
+ */
+void evmgr_wakeup(struct evmgr *evmgr)
+{
+ uint64_t x;
+
+ if (evmgr->state & EVLOOP_STATE_WAIT) {
+ x = 1;
+ write(evmgr->efd, &x, sizeof x);
+ }
+}
+
+/**
+ */
+void *evmgr_holder(struct evmgr *evmgr)
+{
+ return evmgr->holder;
+}
+
+/**
+ */
+int evmgr_release_if(struct evmgr *evmgr, void *holder)
+{
+ if (evmgr->holder != holder)
+ return 0;
+ evmgr->holder = 0;
+ return 1;
+}
+
+/**
+ */
+int evmgr_try_hold(struct evmgr *evmgr, void *holder)
+{
+ if (!evmgr->holder)
+ evmgr->holder = holder;
+ return evmgr->holder == holder;
+}
+
+/******************************************************************************/
+/******************************************************************************/
+/****** SYSTEM D ******/
+/******************************************************************************/
+/******************************************************************************/
+
+/**
+ * Internal callback for evmgr management.
+ * The effect of this function is hidden: it exits
+ * the waiting poll if any. Then it wakes up a thread
+ * awaiting the evmgr using signal.
+ */
+static int on_evmgr_efd(sd_event_source *s, int fd, uint32_t revents, void *userdata)
+{
+ struct evmgr *evmgr = userdata;
+ evmgr_on_efd_event(evmgr);
+ return 1;
+}
+
+/**
+ * Gets a sd_event item for the current thread.
+ * @return a sd_event or NULL in case of error
+ */
+int evmgr_create(struct evmgr **result)
+{
+ int rc;
+ struct evmgr *evmgr;
+
+ /* creates the evmgr on need */
+ evmgr = malloc(sizeof *evmgr);
+ if (!evmgr) {
+ ERROR("out of memory");
+ rc = -ENOMEM;
+ goto error;
+ }
+
+ /* creates the eventfd for waking up polls */
+ evmgr->efd = eventfd(0, EFD_CLOEXEC|EFD_SEMAPHORE);
+ if (evmgr->efd < 0) {
+ ERROR("can't make eventfd for events");
+ rc = -errno;
+ goto error1;
+ }
+ /* create the systemd event loop */
+ evmgr->sdev = systemd_get_event_loop();
+ if (!evmgr->sdev) {
+ ERROR("can't make new event loop");
+ goto error2;
+ }
+ /* put the eventfd in the event loop */
+ rc = sd_event_add_io(evmgr->sdev, NULL, evmgr->efd, EPOLLIN, on_evmgr_efd, evmgr);
+ if (rc < 0) {
+ ERROR("can't register eventfd");
+ goto error2;
+ }
+
+ /* start the creation */
+ evmgr->state = 0;
+ evmgr->holder = 0;
+ *result = evmgr;
+ return 0;
+
+
+error2:
+ close(evmgr->efd);
+error1:
+ free(evmgr);
+error:
+ *result = 0;
+ return rc;
+}
+