blob: e83573c8cfeb5cc6cf8590e0449df25db8351ca9 [file] [log] [blame]
Kristian Høgsbergffd710e2008-12-02 15:15:01 -05001/*
2 * Copyright © 2008 Kristian Høgsberg
3 *
4 * Permission to use, copy, modify, distribute, and sell this software and its
5 * documentation for any purpose is hereby granted without fee, provided that
6 * the above copyright notice appear in all copies and that both that copyright
7 * notice and this permission notice appear in supporting documentation, and
8 * that the name of the copyright holders not be used in advertising or
9 * publicity pertaining to distribution of the software without specific,
10 * written prior permission. The copyright holders make no representations
11 * about the suitability of this software for any purpose. It is provided "as
12 * is" without express or implied warranty.
13 *
14 * THE COPYRIGHT HOLDERS DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
15 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
16 * EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT OR
17 * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE,
18 * DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
19 * TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
20 * OF THIS SOFTWARE.
21 */
22
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040023#include <stddef.h>
24#include <stdio.h>
25#include <errno.h>
26#include <stdlib.h>
27#include <string.h>
28#include <sys/socket.h>
29#include <sys/un.h>
30#include <sys/epoll.h>
Kristian Høgsberg4a298902008-11-28 18:35:25 -050031#include <sys/timerfd.h>
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040032#include <unistd.h>
Kristian Høgsberg4a298902008-11-28 18:35:25 -050033#include <assert.h>
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040034#include "wayland.h"
35
36struct wl_event_loop {
37 int epoll_fd;
Kristian Høgsberg4a298902008-11-28 18:35:25 -050038 struct wl_list idle_list;
39};
40
41struct wl_event_source_interface {
42 void (*dispatch)(struct wl_event_source *source,
43 struct epoll_event *ep);
44 int (*remove)(struct wl_event_source *source);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040045};
46
47struct wl_event_source {
Kristian Høgsberg4a298902008-11-28 18:35:25 -050048 struct wl_event_source_interface *interface;
49 struct wl_event_loop *loop;
50};
51
52struct wl_event_source_fd {
53 struct wl_event_source base;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040054 int fd;
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -040055 wl_event_loop_fd_func_t func;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040056 void *data;
57};
58
Kristian Høgsberg4a298902008-11-28 18:35:25 -050059static void
60wl_event_source_fd_dispatch(struct wl_event_source *source,
61 struct epoll_event *ep)
62{
63 struct wl_event_source_fd *fd_source = (struct wl_event_source_fd *) source;
64 uint32_t mask;
65
66 mask = 0;
67 if (ep->events & EPOLLIN)
68 mask |= WL_EVENT_READABLE;
69 if (ep->events & EPOLLOUT)
70 mask |= WL_EVENT_WRITEABLE;
71
72 fd_source->func(fd_source->fd, mask, fd_source->data);
73}
74
75static int
76wl_event_source_fd_remove(struct wl_event_source *source)
77{
78 struct wl_event_source_fd *fd_source =
79 (struct wl_event_source_fd *) source;
80 struct wl_event_loop *loop = source->loop;
81 int fd;
82
83 fd = fd_source->fd;
84 free(source);
85
86 return epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
87}
88
89struct wl_event_source_interface fd_source_interface = {
90 wl_event_source_fd_dispatch,
91 wl_event_source_fd_remove
92};
93
Kristian Høgsbergb7a01922008-11-08 15:39:41 -050094WL_EXPORT struct wl_event_source *
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040095wl_event_loop_add_fd(struct wl_event_loop *loop,
96 int fd, uint32_t mask,
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -040097 wl_event_loop_fd_func_t func,
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040098 void *data)
99{
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500100 struct wl_event_source_fd *source;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400101 struct epoll_event ep;
102
103 source = malloc(sizeof *source);
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500104 if (source == NULL)
105 return NULL;
106
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500107 source->base.interface = &fd_source_interface;
108 source->base.loop = loop;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400109 source->fd = fd;
110 source->func = func;
111 source->data = data;
112
113 ep.events = 0;
114 if (mask & WL_EVENT_READABLE)
115 ep.events |= EPOLLIN;
116 if (mask & WL_EVENT_WRITEABLE)
117 ep.events |= EPOLLOUT;
118 ep.data.ptr = source;
119
120 if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, fd, &ep) < 0) {
121 free(source);
122 return NULL;
123 }
124
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500125 return &source->base;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400126}
127
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500128WL_EXPORT int
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500129wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask)
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400130{
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500131 struct wl_event_source_fd *fd_source =
132 (struct wl_event_source_fd *) source;
133 struct wl_event_loop *loop = source->loop;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400134 struct epoll_event ep;
135
136 ep.events = 0;
137 if (mask & WL_EVENT_READABLE)
138 ep.events |= EPOLLIN;
139 if (mask & WL_EVENT_WRITEABLE)
140 ep.events |= EPOLLOUT;
141 ep.data.ptr = source;
142
143 return epoll_ctl(loop->epoll_fd,
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500144 EPOLL_CTL_MOD, fd_source->fd, &ep);
145}
146
147struct wl_event_source_timer {
148 struct wl_event_source base;
149 int fd;
150 wl_event_loop_timer_func_t func;
151 void *data;
152};
153
154static void
155wl_event_source_timer_dispatch(struct wl_event_source *source,
156 struct epoll_event *ep)
157{
158 struct wl_event_source_timer *timer_source =
159 (struct wl_event_source_timer *) source;
160 uint64_t expires;
161
162 read(timer_source->fd, &expires, sizeof expires);
163
164 timer_source->func(timer_source->data);
165}
166
167static int
168wl_event_source_timer_remove(struct wl_event_source *source)
169{
170 struct wl_event_source_timer *timer_source =
171 (struct wl_event_source_timer *) source;
172 struct wl_event_loop *loop = source->loop;
173 int fd;
174
175 fd = timer_source->fd;
176 free(source);
177
178 return epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
179}
180
181struct wl_event_source_interface timer_source_interface = {
182 wl_event_source_timer_dispatch,
183 wl_event_source_timer_remove
184};
185
186WL_EXPORT struct wl_event_source *
187wl_event_loop_add_timer(struct wl_event_loop *loop,
188 wl_event_loop_timer_func_t func,
189 void *data)
190{
191 struct wl_event_source_timer *source;
192 struct epoll_event ep;
193
194 source = malloc(sizeof *source);
195 if (source == NULL)
196 return NULL;
197
198 source->base.interface = &timer_source_interface;
199 source->base.loop = loop;
200
201 source->fd = timerfd_create(CLOCK_MONOTONIC, 0);
202 if (source->fd < 0) {
203 fprintf(stderr, "could not create timerfd\n: %m");
204 free(source);
205 return NULL;
206 }
207
208 source->func = func;
209 source->data = data;
210
211 ep.events = EPOLLIN;
212 ep.data.ptr = source;
213
214 if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, source->fd, &ep) < 0) {
215 free(source);
216 return NULL;
217 }
218
219 return &source->base;
220}
221
222WL_EXPORT int
223wl_event_source_timer_update(struct wl_event_source *source, int ms_delay)
224{
225 struct wl_event_source_timer *timer_source =
226 (struct wl_event_source_timer *) source;
227 struct itimerspec its;
228
229 its.it_interval.tv_sec = 0;
230 its.it_interval.tv_nsec = 0;
231 its.it_value.tv_sec = 0;
232 its.it_value.tv_nsec = ms_delay * 1000 * 1000;
233 if (timerfd_settime(timer_source->fd, 0, &its, NULL) < 0) {
234 fprintf(stderr, "could not set timerfd\n: %m");
235 return -1;
236 }
237
238 return 0;
239}
240
241struct wl_event_source_idle {
242 struct wl_event_source base;
243 struct wl_list link;
244 wl_event_loop_idle_func_t func;
245 void *data;
246};
247
248static void
249wl_event_source_idle_dispatch(struct wl_event_source *source,
250 struct epoll_event *ep)
251{
252 assert(0);
253}
254
255static int
256wl_event_source_idle_remove(struct wl_event_source *source)
257{
258 struct wl_event_source_idle *idle_source =
259 (struct wl_event_source_idle *) source;
260
261 wl_list_remove(&idle_source->link);
262
263 return 0;
264}
265
266struct wl_event_source_interface idle_source_interface = {
267 wl_event_source_idle_dispatch,
268 wl_event_source_idle_remove
269};
270
271WL_EXPORT struct wl_event_source *
272wl_event_loop_add_idle(struct wl_event_loop *loop,
273 wl_event_loop_idle_func_t func,
274 void *data)
275{
276 struct wl_event_source_idle *source;
277
278 source = malloc(sizeof *source);
279 if (source == NULL)
280 return NULL;
281
282 source->base.interface = &idle_source_interface;
283 source->base.loop = loop;
284
285 source->func = func;
286 source->data = data;
287 wl_list_insert(loop->idle_list.prev, &source->link);
288
289 return &source->base;
290}
291
292WL_EXPORT int
293wl_event_source_remove(struct wl_event_source *source)
294{
295 source->interface->remove(source);
296
297 return 0;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400298}
299
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500300WL_EXPORT struct wl_event_loop *
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400301wl_event_loop_create(void)
302{
303 struct wl_event_loop *loop;
304
305 loop = malloc(sizeof *loop);
306 if (loop == NULL)
307 return NULL;
308
309 loop->epoll_fd = epoll_create(16);
310 if (loop->epoll_fd < 0) {
311 free(loop);
312 return NULL;
313 }
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500314 wl_list_init(&loop->idle_list);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400315
316 return loop;
317}
318
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500319WL_EXPORT void
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400320wl_event_loop_destroy(struct wl_event_loop *loop)
321{
322 close(loop->epoll_fd);
323 free(loop);
324}
325
326#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
327
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500328static void
329dispatch_idles(struct wl_event_loop *loop)
330{
331 struct wl_event_source_idle *source, *next;
332
333 source = container_of(loop->idle_list.next,
334 struct wl_event_source_idle, link);
335
336 while (&source->link != &loop->idle_list) {
337 source->func(source->data);
338 next = container_of(source->link.next,
339 struct wl_event_source_idle, link);
340 free(source);
341 source = next;
342 }
343
344 wl_list_init(&loop->idle_list);
345}
346
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500347WL_EXPORT int
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400348wl_event_loop_wait(struct wl_event_loop *loop)
349{
350 struct epoll_event ep[32];
351 struct wl_event_source *source;
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400352 int i, count, timeout;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400353
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500354 if (wl_list_empty(&loop->idle_list))
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400355 timeout = -1;
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500356 else
357 timeout = 0;
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400358
359 count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400360 if (count < 0)
361 return -1;
362
363 for (i = 0; i < count; i++) {
364 source = ep[i].data.ptr;
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500365 source->interface->dispatch(source, &ep[i]);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400366 }
367
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500368 if (count == 0)
369 dispatch_idles(loop);
370
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400371
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400372 return 0;
373}