aboutsummaryrefslogtreecommitdiffstats
path: root/common/loop.c
diff options
context:
space:
mode:
authorLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-10-13 16:04:37 +1000
committerLibravatar Ryan Dwyer <ryandwyer1@gmail.com>2018-10-15 00:26:27 +1000
commit4056c09e13c1aeead6dd4085fc7e263a17a0b195 (patch)
treea3413f2a5717968e370d68521b689580d5adc5a0 /common/loop.c
parentDocument `border csd` (diff)
downloadsway-4056c09e13c1aeead6dd4085fc7e263a17a0b195.tar.gz
sway-4056c09e13c1aeead6dd4085fc7e263a17a0b195.tar.zst
sway-4056c09e13c1aeead6dd4085fc7e263a17a0b195.zip
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.
Diffstat (limited to 'common/loop.c')
-rw-r--r--common/loop.c105
1 files changed, 105 insertions, 0 deletions
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 @@
1#include <string.h>
2#include <stdbool.h>
3#include <stdlib.h>
4#include <stdio.h>
5#include <poll.h>
6#include <sys/timerfd.h>
7#include <unistd.h>
8#include "list.h"
9#include "log.h"
10#include "loop.h"
11
12struct loop_event {
13 void (*callback)(int fd, short mask, void *data);
14 void *data;
15};
16
17struct loop {
18 struct pollfd *fds;
19 int fd_length;
20 int fd_capacity;
21
22 list_t *events; // struct loop_event
23};
24
25struct loop *loop_create(void) {
26 struct loop *loop = calloc(1, sizeof(struct loop));
27 if (!loop) {
28 wlr_log(WLR_ERROR, "Unable to allocate memory for loop");
29 return NULL;
30 }
31 loop->fd_capacity = 10;
32 loop->fds = malloc(sizeof(struct pollfd) * loop->fd_capacity);
33 loop->events = create_list();
34 return loop;
35}
36
37void loop_destroy(struct loop *loop) {
38 list_foreach(loop->events, free);
39 list_free(loop->events);
40 free(loop);
41}
42
43void loop_poll(struct loop *loop) {
44 poll(loop->fds, loop->fd_length, -1);
45
46 for (int i = 0; i < loop->fd_length; ++i) {
47 struct pollfd pfd = loop->fds[i];
48 struct loop_event *event = loop->events->items[i];
49
50 // Always send these events
51 unsigned events = pfd.events | POLLHUP | POLLERR;
52
53 if (pfd.revents & events) {
54 event->callback(pfd.fd, pfd.revents, event->data);
55 }
56 }
57}
58
59struct loop_event *loop_add_fd(struct loop *loop, int fd, short mask,
60 void (*callback)(int fd, short mask, void *data), void *data) {
61 struct pollfd pfd = {fd, mask, 0};
62
63 if (loop->fd_length == loop->fd_capacity) {
64 loop->fd_capacity += 10;
65 loop->fds = realloc(loop->fds, sizeof(struct pollfd) * loop->fd_capacity);
66 }
67
68 loop->fds[loop->fd_length++] = pfd;
69
70 struct loop_event *event = calloc(1, sizeof(struct loop_event));
71 event->callback = callback;
72 event->data = data;
73
74 list_add(loop->events, event);
75
76 return event;
77}
78
79struct loop_event *loop_add_timer(struct loop *loop, int ms,
80 void (*callback)(int fd, short mask, void *data), void *data) {
81 int fd = timerfd_create(CLOCK_MONOTONIC, 0);
82 struct itimerspec its;
83 its.it_interval.tv_sec = 0;
84 its.it_interval.tv_nsec = 0;
85 its.it_value.tv_sec = ms / 1000000000;
86 its.it_value.tv_nsec = (ms * 1000000) % 1000000000;
87 timerfd_settime(fd, 0, &its, NULL);
88
89 return loop_add_fd(loop, fd, POLLIN, callback, data);
90}
91
92bool loop_remove_event(struct loop *loop, struct loop_event *event) {
93 for (int i = 0; i < loop->events->length; ++i) {
94 if (loop->events->items[i] == event) {
95 list_del(loop->events, i);
96
97 loop->fd_length--;
98 memmove(&loop->fds[i], &loop->fds[i + 1], sizeof(void*) * (loop->fd_length - i));
99
100 free(event);
101 return true;
102 }
103 }
104 return false;
105}