diff options
Diffstat (limited to 'common/loop.c')
-rw-r--r-- | common/loop.c | 143 |
1 files changed, 100 insertions, 43 deletions
diff --git a/common/loop.c b/common/loop.c index da3c2142..c358e212 100644 --- a/common/loop.c +++ b/common/loop.c | |||
@@ -1,18 +1,24 @@ | |||
1 | #include <limits.h> | ||
1 | #include <string.h> | 2 | #include <string.h> |
2 | #include <stdbool.h> | 3 | #include <stdbool.h> |
3 | #include <stdlib.h> | 4 | #include <stdlib.h> |
4 | #include <stdio.h> | 5 | #include <stdio.h> |
5 | #include <poll.h> | 6 | #include <poll.h> |
6 | #include <sys/timerfd.h> | 7 | #include <time.h> |
7 | #include <unistd.h> | 8 | #include <unistd.h> |
8 | #include "list.h" | 9 | #include "list.h" |
9 | #include "log.h" | 10 | #include "log.h" |
10 | #include "loop.h" | 11 | #include "loop.h" |
11 | 12 | ||
12 | struct loop_event { | 13 | struct loop_fd_event { |
13 | void (*callback)(int fd, short mask, void *data); | 14 | void (*callback)(int fd, short mask, void *data); |
14 | void *data; | 15 | void *data; |
15 | bool is_timer; | 16 | }; |
17 | |||
18 | struct loop_timer { | ||
19 | void (*callback)(void *data); | ||
20 | void *data; | ||
21 | struct timespec expiry; | ||
16 | }; | 22 | }; |
17 | 23 | ||
18 | struct loop { | 24 | struct loop { |
@@ -20,7 +26,8 @@ struct loop { | |||
20 | int fd_length; | 26 | int fd_length; |
21 | int fd_capacity; | 27 | int fd_capacity; |
22 | 28 | ||
23 | list_t *events; // struct loop_event | 29 | list_t *fd_events; // struct loop_fd_event |
30 | list_t *timers; // struct loop_timer | ||
24 | }; | 31 | }; |
25 | 32 | ||
26 | struct loop *loop_create(void) { | 33 | struct loop *loop_create(void) { |
@@ -31,86 +38,136 @@ struct loop *loop_create(void) { | |||
31 | } | 38 | } |
32 | loop->fd_capacity = 10; | 39 | loop->fd_capacity = 10; |
33 | loop->fds = malloc(sizeof(struct pollfd) * loop->fd_capacity); | 40 | loop->fds = malloc(sizeof(struct pollfd) * loop->fd_capacity); |
34 | loop->events = create_list(); | 41 | loop->fd_events = create_list(); |
42 | loop->timers = create_list(); | ||
35 | return loop; | 43 | return loop; |
36 | } | 44 | } |
37 | 45 | ||
38 | void loop_destroy(struct loop *loop) { | 46 | void loop_destroy(struct loop *loop) { |
39 | list_foreach(loop->events, free); | 47 | list_foreach(loop->fd_events, free); |
40 | list_free(loop->events); | 48 | list_foreach(loop->timers, free); |
49 | list_free(loop->fd_events); | ||
50 | list_free(loop->timers); | ||
41 | free(loop); | 51 | free(loop); |
42 | } | 52 | } |
43 | 53 | ||
44 | void loop_poll(struct loop *loop) { | 54 | void loop_poll(struct loop *loop) { |
45 | poll(loop->fds, loop->fd_length, -1); | 55 | // Calculate next timer in ms |
56 | int ms = INT_MAX; | ||
57 | if (loop->timers->length) { | ||
58 | struct timespec now; | ||
59 | clock_gettime(CLOCK_MONOTONIC, &now); | ||
60 | for (int i = 0; i < loop->timers->length; ++i) { | ||
61 | struct loop_timer *timer = loop->timers->items[i]; | ||
62 | int timer_ms = (timer->expiry.tv_sec - now.tv_sec) * 1000; | ||
63 | timer_ms += (timer->expiry.tv_nsec - now.tv_nsec) / 1000000; | ||
64 | if (timer_ms < ms) { | ||
65 | ms = timer_ms; | ||
66 | } | ||
67 | } | ||
68 | } | ||
46 | 69 | ||
70 | poll(loop->fds, loop->fd_length, ms); | ||
71 | |||
72 | // Dispatch fds | ||
47 | for (int i = 0; i < loop->fd_length; ++i) { | 73 | for (int i = 0; i < loop->fd_length; ++i) { |
48 | struct pollfd pfd = loop->fds[i]; | 74 | struct pollfd pfd = loop->fds[i]; |
49 | struct loop_event *event = loop->events->items[i]; | 75 | struct loop_fd_event *event = loop->fd_events->items[i]; |
50 | 76 | ||
51 | // Always send these events | 77 | // Always send these events |
52 | unsigned events = pfd.events | POLLHUP | POLLERR; | 78 | unsigned events = pfd.events | POLLHUP | POLLERR; |
53 | 79 | ||
54 | if (pfd.revents & events) { | 80 | if (pfd.revents & events) { |
55 | event->callback(pfd.fd, pfd.revents, event->data); | 81 | event->callback(pfd.fd, pfd.revents, event->data); |
82 | } | ||
83 | } | ||
56 | 84 | ||
57 | if (event->is_timer) { | 85 | // Dispatch timers |
58 | loop_remove_event(loop, event); | 86 | if (loop->timers->length) { |
87 | struct timespec now; | ||
88 | clock_gettime(CLOCK_MONOTONIC, &now); | ||
89 | for (int i = 0; i < loop->timers->length; ++i) { | ||
90 | struct loop_timer *timer = loop->timers->items[i]; | ||
91 | bool expired = timer->expiry.tv_sec < now.tv_sec || | ||
92 | (timer->expiry.tv_sec == now.tv_sec && | ||
93 | timer->expiry.tv_nsec < now.tv_nsec); | ||
94 | if (expired) { | ||
95 | timer->callback(timer->data); | ||
96 | loop_remove_timer(loop, timer); | ||
59 | --i; | 97 | --i; |
60 | } | 98 | } |
61 | } | 99 | } |
62 | } | 100 | } |
63 | } | 101 | } |
64 | 102 | ||
65 | struct loop_event *loop_add_fd(struct loop *loop, int fd, short mask, | 103 | void loop_add_fd(struct loop *loop, int fd, short mask, |
66 | void (*callback)(int fd, short mask, void *data), void *data) { | 104 | void (*callback)(int fd, short mask, void *data), void *data) { |
105 | struct loop_fd_event *event = calloc(1, sizeof(struct loop_fd_event)); | ||
106 | if (!event) { | ||
107 | wlr_log(WLR_ERROR, "Unable to allocate memory for event"); | ||
108 | return; | ||
109 | } | ||
110 | event->callback = callback; | ||
111 | event->data = data; | ||
112 | list_add(loop->fd_events, event); | ||
113 | |||
67 | struct pollfd pfd = {fd, mask, 0}; | 114 | struct pollfd pfd = {fd, mask, 0}; |
68 | 115 | ||
69 | if (loop->fd_length == loop->fd_capacity) { | 116 | if (loop->fd_length == loop->fd_capacity) { |
70 | loop->fd_capacity += 10; | 117 | loop->fd_capacity += 10; |
71 | loop->fds = realloc(loop->fds, sizeof(struct pollfd) * loop->fd_capacity); | 118 | loop->fds = realloc(loop->fds, |
119 | sizeof(struct pollfd) * loop->fd_capacity); | ||
72 | } | 120 | } |
73 | 121 | ||
74 | loop->fds[loop->fd_length++] = pfd; | 122 | loop->fds[loop->fd_length++] = pfd; |
123 | } | ||
75 | 124 | ||
76 | struct loop_event *event = calloc(1, sizeof(struct loop_event)); | 125 | struct loop_timer *loop_add_timer(struct loop *loop, int ms, |
77 | event->callback = callback; | 126 | void (*callback)(void *data), void *data) { |
78 | event->data = data; | 127 | struct loop_timer *timer = calloc(1, sizeof(struct loop_timer)); |
128 | if (!timer) { | ||
129 | wlr_log(WLR_ERROR, "Unable to allocate memory for timer"); | ||
130 | return NULL; | ||
131 | } | ||
132 | timer->callback = callback; | ||
133 | timer->data = data; | ||
79 | 134 | ||
80 | list_add(loop->events, event); | 135 | clock_gettime(CLOCK_MONOTONIC, &timer->expiry); |
136 | timer->expiry.tv_sec += ms / 1000; | ||
81 | 137 | ||
82 | return event; | 138 | long int nsec = (ms % 1000) * 1000000; |
83 | } | 139 | if (timer->expiry.tv_nsec + nsec >= 1000000000) { |
140 | timer->expiry.tv_sec++; | ||
141 | nsec -= 1000000000; | ||
142 | } | ||
143 | timer->expiry.tv_nsec += nsec; | ||
84 | 144 | ||
85 | struct loop_event *loop_add_timer(struct loop *loop, int ms, | 145 | list_add(loop->timers, timer); |
86 | void (*callback)(int fd, short mask, void *data), void *data) { | ||
87 | int fd = timerfd_create(CLOCK_MONOTONIC, 0); | ||
88 | struct itimerspec its; | ||
89 | its.it_interval.tv_sec = 0; | ||
90 | its.it_interval.tv_nsec = 0; | ||
91 | its.it_value.tv_sec = ms / 1000; | ||
92 | its.it_value.tv_nsec = (ms % 1000) * 1000000; | ||
93 | timerfd_settime(fd, 0, &its, NULL); | ||
94 | |||
95 | struct loop_event *event = loop_add_fd(loop, fd, POLLIN, callback, data); | ||
96 | event->is_timer = true; | ||
97 | |||
98 | return event; | ||
99 | } | ||
100 | 146 | ||
101 | bool loop_remove_event(struct loop *loop, struct loop_event *event) { | 147 | return timer; |
102 | for (int i = 0; i < loop->events->length; ++i) { | 148 | } |
103 | if (loop->events->items[i] == event) { | ||
104 | list_del(loop->events, i); | ||
105 | 149 | ||
106 | if (event->is_timer) { | 150 | bool loop_remove_fd(struct loop *loop, int fd) { |
107 | close(loop->fds[i].fd); | 151 | for (int i = 0; i < loop->fd_length; ++i) { |
108 | } | 152 | if (loop->fds[i].fd == fd) { |
153 | free(loop->fd_events->items[i]); | ||
154 | list_del(loop->fd_events, i); | ||
109 | 155 | ||
110 | loop->fd_length--; | 156 | loop->fd_length--; |
111 | memmove(&loop->fds[i], &loop->fds[i + 1], sizeof(void*) * (loop->fd_length - i)); | 157 | memmove(&loop->fds[i], &loop->fds[i + 1], |
158 | sizeof(void*) * (loop->fd_length - i)); | ||
159 | |||
160 | return true; | ||
161 | } | ||
162 | } | ||
163 | return false; | ||
164 | } | ||
112 | 165 | ||
113 | free(event); | 166 | bool loop_remove_timer(struct loop *loop, struct loop_timer *timer) { |
167 | for (int i = 0; i < loop->timers->length; ++i) { | ||
168 | if (loop->timers->items[i] == timer) { | ||
169 | list_del(loop->timers, i); | ||
170 | free(timer); | ||
114 | return true; | 171 | return true; |
115 | } | 172 | } |
116 | } | 173 | } |