aboutsummaryrefslogtreecommitdiffstats
path: root/src/fdev.c
diff options
context:
space:
mode:
authorJosé Bollo <jose.bollo@iot.bzh>2018-02-22 13:22:48 +0100
committerJosé Bollo <jose.bollo@iot.bzh>2018-02-22 13:22:48 +0100
commitca820c65c2b03a24e8936218171c6c1d138fd1f7 (patch)
treef7e31ea8e63d3321af64226e360a78c504a09bb3 /src/fdev.c
parentf15ea770dd9b13a20331853a026091316984f9ca (diff)
fdev: Introduce fdev for file event handling
This is an effort to keep cutting dependency to systemd. Change-Id: I9a0c032a1095e297c7f3ac5b67827fda3658b8d9 Signed-off-by: José Bollo <jose.bollo@iot.bzh>
Diffstat (limited to 'src/fdev.c')
-rw-r--r--src/fdev.c158
1 files changed, 158 insertions, 0 deletions
diff --git a/src/fdev.c b/src/fdev.c
new file mode 100644
index 00000000..5c31d31b
--- /dev/null
+++ b/src/fdev.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2018 "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.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#define FDEV_PROVIDER
+#include "fdev.h"
+
+struct fdev
+{
+ int fd;
+ uint32_t events;
+ int repeat;
+ unsigned refcount;
+ struct fdev_itf *itf;
+ void *closure_itf;
+ void (*callback)(void*,uint32_t,struct fdev*);
+ void *closure_callback;
+};
+
+struct fdev *fdev_create(int fd)
+{
+ struct fdev *fdev;
+
+ fdev = calloc(1, sizeof *fdev);
+ if (!fdev)
+ errno = ENOMEM;
+ else {
+ fdev->fd = fd;
+ fdev->refcount = 3; /* set autoclose by default */
+ fdev->repeat = -1;
+ }
+ return fdev;
+}
+
+void fdev_set_itf(struct fdev *fdev, struct fdev_itf *itf, void *closure_itf)
+{
+ fdev->itf = itf;
+ fdev->closure_itf = closure_itf;
+}
+
+void fdev_dispatch(struct fdev *fdev, uint32_t events)
+{
+ if (fdev->repeat > 0 && !--fdev->repeat && fdev->itf)
+ fdev->itf->disable(fdev->closure_itf, fdev);
+ if (fdev->callback)
+ fdev->callback(fdev->closure_callback, events, fdev);
+}
+
+struct fdev *fdev_addref(struct fdev *fdev)
+{
+ if (fdev)
+ __atomic_add_fetch(&fdev->refcount, 2, __ATOMIC_RELAXED);
+ return fdev;
+}
+
+void fdev_unref(struct fdev *fdev)
+{
+ if (fdev && __atomic_sub_fetch(&fdev->refcount, 2, __ATOMIC_RELAXED) <= 1) {
+ if (fdev->itf) {
+ fdev->itf->disable(fdev->closure_itf, fdev);
+ fdev->itf->unref(fdev->closure_itf);
+ }
+ if (fdev->refcount)
+ close(fdev->fd);
+ free(fdev);
+ }
+}
+
+int fdev_fd(const struct fdev *fdev)
+{
+ return fdev->fd;
+}
+
+uint32_t fdev_events(const struct fdev *fdev)
+{
+ return fdev->events;
+}
+
+int fdev_repeat(const struct fdev *fdev)
+{
+ return fdev->repeat;
+}
+
+int fdev_autoclose(const struct fdev *fdev)
+{
+ return 1 & fdev->refcount;
+}
+
+static inline int is_active(struct fdev *fdev)
+{
+ return fdev->repeat && fdev->callback;
+}
+
+static inline void update_activity(struct fdev *fdev, int old_active)
+{
+ if (is_active(fdev)) {
+ if (!old_active)
+ fdev->itf->enable(fdev->closure_itf, fdev);
+ } else {
+ if (old_active)
+ fdev->itf->disable(fdev->closure_itf, fdev);
+ }
+}
+
+void fdev_set_callback(struct fdev *fdev, void (*callback)(void*,uint32_t,struct fdev*), void *closure)
+{
+ int oa;
+
+ oa = is_active(fdev);
+ fdev->callback = callback;
+ fdev->closure_callback = closure;
+ update_activity(fdev, oa);
+}
+
+void fdev_set_events(struct fdev *fdev, uint32_t events)
+{
+ if (events != fdev->events) {
+ fdev->events = events;
+ if (is_active(fdev))
+ fdev->itf->enable(fdev->closure_itf, fdev);
+ }
+}
+
+void fdev_set_repeat(struct fdev *fdev, int count)
+{
+ int oa;
+
+ oa = is_active(fdev);
+ fdev->repeat = count;
+ update_activity(fdev, oa);
+}
+
+void fdev_set_autoclose(struct fdev *fdev, int autoclose)
+{
+ if (autoclose)
+ fdev->refcount |= 1;
+ else
+ fdev->refcount &= -2;
+}
+