diff options
author | José Bollo <jose.bollo@iot.bzh> | 2018-02-22 13:22:48 +0100 |
---|---|---|
committer | José Bollo <jose.bollo@iot.bzh> | 2018-02-22 13:22:48 +0100 |
commit | ca820c65c2b03a24e8936218171c6c1d138fd1f7 (patch) | |
tree | f7e31ea8e63d3321af64226e360a78c504a09bb3 /src/fdev.c | |
parent | f15ea770dd9b13a20331853a026091316984f9ca (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.c | 158 |
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; +} + |