From 4056c09e13c1aeead6dd4085fc7e263a17a0b195 Mon Sep 17 00:00:00 2001 From: Ryan Dwyer Date: Sat, 13 Oct 2018 16:04:37 +1000 Subject: Move swaybar's event loop to common directory and refactor * The loop functions are now prefixed with `loop_`. * It is now easy to add timers to the loop. * Timers are implemented using pollfd and timerfd, rather than manually checking them when any other event happens to arrive. --- common/loop.c | 105 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 105 insertions(+) create mode 100644 common/loop.c (limited to 'common/loop.c') diff --git a/common/loop.c b/common/loop.c new file mode 100644 index 00000000..bfbfd5a6 --- /dev/null +++ b/common/loop.c @@ -0,0 +1,105 @@ +#include +#include +#include +#include +#include +#include +#include +#include "list.h" +#include "log.h" +#include "loop.h" + +struct loop_event { + void (*callback)(int fd, short mask, void *data); + void *data; +}; + +struct loop { + struct pollfd *fds; + int fd_length; + int fd_capacity; + + list_t *events; // struct loop_event +}; + +struct loop *loop_create(void) { + struct loop *loop = calloc(1, sizeof(struct loop)); + if (!loop) { + wlr_log(WLR_ERROR, "Unable to allocate memory for loop"); + return NULL; + } + loop->fd_capacity = 10; + loop->fds = malloc(sizeof(struct pollfd) * loop->fd_capacity); + loop->events = create_list(); + return loop; +} + +void loop_destroy(struct loop *loop) { + list_foreach(loop->events, free); + list_free(loop->events); + free(loop); +} + +void loop_poll(struct loop *loop) { + poll(loop->fds, loop->fd_length, -1); + + for (int i = 0; i < loop->fd_length; ++i) { + struct pollfd pfd = loop->fds[i]; + struct loop_event *event = loop->events->items[i]; + + // Always send these events + unsigned events = pfd.events | POLLHUP | POLLERR; + + if (pfd.revents & events) { + event->callback(pfd.fd, pfd.revents, event->data); + } + } +} + +struct loop_event *loop_add_fd(struct loop *loop, int fd, short mask, + void (*callback)(int fd, short mask, void *data), void *data) { + struct pollfd pfd = {fd, mask, 0}; + + if (loop->fd_length == loop->fd_capacity) { + loop->fd_capacity += 10; + loop->fds = realloc(loop->fds, sizeof(struct pollfd) * loop->fd_capacity); + } + + loop->fds[loop->fd_length++] = pfd; + + struct loop_event *event = calloc(1, sizeof(struct loop_event)); + event->callback = callback; + event->data = data; + + list_add(loop->events, event); + + return event; +} + +struct loop_event *loop_add_timer(struct loop *loop, int ms, + void (*callback)(int fd, short mask, void *data), void *data) { + int fd = timerfd_create(CLOCK_MONOTONIC, 0); + struct itimerspec its; + its.it_interval.tv_sec = 0; + its.it_interval.tv_nsec = 0; + its.it_value.tv_sec = ms / 1000000000; + its.it_value.tv_nsec = (ms * 1000000) % 1000000000; + timerfd_settime(fd, 0, &its, NULL); + + return loop_add_fd(loop, fd, POLLIN, callback, data); +} + +bool loop_remove_event(struct loop *loop, struct loop_event *event) { + for (int i = 0; i < loop->events->length; ++i) { + if (loop->events->items[i] == event) { + list_del(loop->events, i); + + loop->fd_length--; + memmove(&loop->fds[i], &loop->fds[i + 1], sizeof(void*) * (loop->fd_length - i)); + + free(event); + return true; + } + } + return false; +} -- cgit v1.2.3-54-g00ecf