blob: 345660f6789055b7cada202ee6465d8d08d40cba [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>
Ray Strodefe573472008-12-19 00:22:18 -050026#include <signal.h>
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040027#include <stdlib.h>
28#include <string.h>
29#include <sys/socket.h>
30#include <sys/un.h>
31#include <sys/epoll.h>
Ray Strodefe573472008-12-19 00:22:18 -050032#include <sys/signalfd.h>
Kristian Høgsberg4a298902008-11-28 18:35:25 -050033#include <sys/timerfd.h>
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040034#include <unistd.h>
Kristian Høgsberg4a298902008-11-28 18:35:25 -050035#include <assert.h>
Kristian Høgsberga661f262010-08-10 14:12:05 -040036#include "wayland-server.h"
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040037
38struct wl_event_loop {
39 int epoll_fd;
Kristian Høgsberg4a298902008-11-28 18:35:25 -050040 struct wl_list idle_list;
41};
42
43struct wl_event_source_interface {
44 void (*dispatch)(struct wl_event_source *source,
45 struct epoll_event *ep);
46 int (*remove)(struct wl_event_source *source);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040047};
48
49struct wl_event_source {
Kristian Høgsberg4a298902008-11-28 18:35:25 -050050 struct wl_event_source_interface *interface;
51 struct wl_event_loop *loop;
52};
53
54struct wl_event_source_fd {
55 struct wl_event_source base;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040056 int fd;
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -040057 wl_event_loop_fd_func_t func;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040058 void *data;
59};
60
Kristian Høgsberg4a298902008-11-28 18:35:25 -050061static void
62wl_event_source_fd_dispatch(struct wl_event_source *source,
63 struct epoll_event *ep)
64{
65 struct wl_event_source_fd *fd_source = (struct wl_event_source_fd *) source;
66 uint32_t mask;
67
68 mask = 0;
69 if (ep->events & EPOLLIN)
70 mask |= WL_EVENT_READABLE;
71 if (ep->events & EPOLLOUT)
72 mask |= WL_EVENT_WRITEABLE;
73
74 fd_source->func(fd_source->fd, mask, fd_source->data);
75}
76
77static int
78wl_event_source_fd_remove(struct wl_event_source *source)
79{
80 struct wl_event_source_fd *fd_source =
81 (struct wl_event_source_fd *) source;
82 struct wl_event_loop *loop = source->loop;
83 int fd;
84
85 fd = fd_source->fd;
86 free(source);
87
88 return epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
89}
90
91struct wl_event_source_interface fd_source_interface = {
92 wl_event_source_fd_dispatch,
93 wl_event_source_fd_remove
94};
95
Kristian Høgsbergb7a01922008-11-08 15:39:41 -050096WL_EXPORT struct wl_event_source *
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040097wl_event_loop_add_fd(struct wl_event_loop *loop,
98 int fd, uint32_t mask,
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -040099 wl_event_loop_fd_func_t func,
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400100 void *data)
101{
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500102 struct wl_event_source_fd *source;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400103 struct epoll_event ep;
104
105 source = malloc(sizeof *source);
Kristian Høgsbergf9bc7952008-11-02 10:12:29 -0500106 if (source == NULL)
107 return NULL;
108
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500109 source->base.interface = &fd_source_interface;
110 source->base.loop = loop;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400111 source->fd = fd;
112 source->func = func;
113 source->data = data;
114
Kristian Høgsbergfbd0fb02010-07-29 15:01:01 -0400115 memset(&ep, 0, sizeof ep);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400116 if (mask & WL_EVENT_READABLE)
117 ep.events |= EPOLLIN;
118 if (mask & WL_EVENT_WRITEABLE)
119 ep.events |= EPOLLOUT;
120 ep.data.ptr = source;
121
122 if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, fd, &ep) < 0) {
123 free(source);
124 return NULL;
125 }
126
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500127 return &source->base;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400128}
129
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500130WL_EXPORT int
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500131wl_event_source_fd_update(struct wl_event_source *source, uint32_t mask)
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400132{
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500133 struct wl_event_source_fd *fd_source =
134 (struct wl_event_source_fd *) source;
135 struct wl_event_loop *loop = source->loop;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400136 struct epoll_event ep;
137
Kristian Høgsbergfbd0fb02010-07-29 15:01:01 -0400138 memset(&ep, 0, sizeof ep);
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400139 if (mask & WL_EVENT_READABLE)
140 ep.events |= EPOLLIN;
141 if (mask & WL_EVENT_WRITEABLE)
142 ep.events |= EPOLLOUT;
143 ep.data.ptr = source;
144
145 return epoll_ctl(loop->epoll_fd,
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500146 EPOLL_CTL_MOD, fd_source->fd, &ep);
147}
148
149struct wl_event_source_timer {
150 struct wl_event_source base;
151 int fd;
152 wl_event_loop_timer_func_t func;
153 void *data;
154};
155
156static void
157wl_event_source_timer_dispatch(struct wl_event_source *source,
158 struct epoll_event *ep)
159{
160 struct wl_event_source_timer *timer_source =
161 (struct wl_event_source_timer *) source;
162 uint64_t expires;
163
164 read(timer_source->fd, &expires, sizeof expires);
165
166 timer_source->func(timer_source->data);
167}
168
169static int
170wl_event_source_timer_remove(struct wl_event_source *source)
171{
172 struct wl_event_source_timer *timer_source =
173 (struct wl_event_source_timer *) source;
174 struct wl_event_loop *loop = source->loop;
175 int fd;
176
177 fd = timer_source->fd;
178 free(source);
179
180 return epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
181}
182
183struct wl_event_source_interface timer_source_interface = {
184 wl_event_source_timer_dispatch,
185 wl_event_source_timer_remove
186};
187
188WL_EXPORT struct wl_event_source *
189wl_event_loop_add_timer(struct wl_event_loop *loop,
190 wl_event_loop_timer_func_t func,
191 void *data)
192{
193 struct wl_event_source_timer *source;
194 struct epoll_event ep;
195
196 source = malloc(sizeof *source);
197 if (source == NULL)
198 return NULL;
199
200 source->base.interface = &timer_source_interface;
201 source->base.loop = loop;
202
203 source->fd = timerfd_create(CLOCK_MONOTONIC, 0);
204 if (source->fd < 0) {
205 fprintf(stderr, "could not create timerfd\n: %m");
206 free(source);
207 return NULL;
208 }
209
210 source->func = func;
211 source->data = data;
212
Kristian Høgsbergfbd0fb02010-07-29 15:01:01 -0400213 memset(&ep, 0, sizeof ep);
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500214 ep.events = EPOLLIN;
215 ep.data.ptr = source;
216
217 if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, source->fd, &ep) < 0) {
218 free(source);
219 return NULL;
220 }
221
222 return &source->base;
223}
224
225WL_EXPORT int
226wl_event_source_timer_update(struct wl_event_source *source, int ms_delay)
227{
228 struct wl_event_source_timer *timer_source =
229 (struct wl_event_source_timer *) source;
230 struct itimerspec its;
231
232 its.it_interval.tv_sec = 0;
233 its.it_interval.tv_nsec = 0;
234 its.it_value.tv_sec = 0;
235 its.it_value.tv_nsec = ms_delay * 1000 * 1000;
236 if (timerfd_settime(timer_source->fd, 0, &its, NULL) < 0) {
237 fprintf(stderr, "could not set timerfd\n: %m");
238 return -1;
239 }
240
241 return 0;
242}
243
Ray Strodefe573472008-12-19 00:22:18 -0500244struct wl_event_source_signal {
245 struct wl_event_source base;
246 int fd;
247 int signal_number;
248 wl_event_loop_signal_func_t func;
249 void *data;
250};
251
252static void
253wl_event_source_signal_dispatch(struct wl_event_source *source,
254 struct epoll_event *ep)
255{
256 struct wl_event_source_signal *signal_source =
257 (struct wl_event_source_signal *) source;
258 struct signalfd_siginfo signal_info;
259
260 read(signal_source->fd, &signal_info, sizeof signal_info);
261
262 signal_source->func(signal_source->signal_number, signal_source->data);
263}
264
265static int
266wl_event_source_signal_remove(struct wl_event_source *source)
267{
268 struct wl_event_source_signal *signal_source =
269 (struct wl_event_source_signal *) source;
270 struct wl_event_loop *loop = source->loop;
271 int fd;
272
273 fd = signal_source->fd;
274 free(source);
275
276 return epoll_ctl(loop->epoll_fd, EPOLL_CTL_DEL, fd, NULL);
277}
278
279struct wl_event_source_interface signal_source_interface = {
280 wl_event_source_signal_dispatch,
281 wl_event_source_signal_remove
282};
283
284WL_EXPORT struct wl_event_source *
285wl_event_loop_add_signal(struct wl_event_loop *loop,
286 int signal_number,
287 wl_event_loop_signal_func_t func,
288 void *data)
289{
290 struct wl_event_source_signal *source;
291 struct epoll_event ep;
292 sigset_t mask;
293
294 source = malloc(sizeof *source);
295 if (source == NULL)
296 return NULL;
297
298 source->base.interface = &signal_source_interface;
299 source->base.loop = loop;
300
301 sigemptyset(&mask);
302 sigaddset(&mask, signal_number);
303 source->fd = signalfd(-1, &mask, 0);
304 if (source->fd < 0) {
305 fprintf(stderr, "could not create fd to watch signal\n: %m");
306 free(source);
307 return NULL;
308 }
309 sigprocmask(SIG_BLOCK, &mask, NULL);
310
311 source->func = func;
312 source->data = data;
313
Kristian Høgsbergfbd0fb02010-07-29 15:01:01 -0400314 memset(&ep, 0, sizeof ep);
Ray Strodefe573472008-12-19 00:22:18 -0500315 ep.events = EPOLLIN;
316 ep.data.ptr = source;
317
318 if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, source->fd, &ep) < 0) {
319 free(source);
320 return NULL;
321 }
322
323 return &source->base;
324}
325
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500326struct wl_event_source_idle {
327 struct wl_event_source base;
328 struct wl_list link;
329 wl_event_loop_idle_func_t func;
330 void *data;
331};
332
333static void
334wl_event_source_idle_dispatch(struct wl_event_source *source,
335 struct epoll_event *ep)
336{
337 assert(0);
338}
339
340static int
341wl_event_source_idle_remove(struct wl_event_source *source)
342{
343 struct wl_event_source_idle *idle_source =
344 (struct wl_event_source_idle *) source;
345
346 wl_list_remove(&idle_source->link);
Kristian Høgsbergce5325d2010-06-14 11:54:00 -0400347 free(source);
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500348
349 return 0;
350}
351
352struct wl_event_source_interface idle_source_interface = {
353 wl_event_source_idle_dispatch,
354 wl_event_source_idle_remove
355};
356
357WL_EXPORT struct wl_event_source *
358wl_event_loop_add_idle(struct wl_event_loop *loop,
359 wl_event_loop_idle_func_t func,
360 void *data)
361{
362 struct wl_event_source_idle *source;
363
364 source = malloc(sizeof *source);
365 if (source == NULL)
366 return NULL;
367
368 source->base.interface = &idle_source_interface;
369 source->base.loop = loop;
370
371 source->func = func;
372 source->data = data;
373 wl_list_insert(loop->idle_list.prev, &source->link);
374
375 return &source->base;
376}
377
378WL_EXPORT int
379wl_event_source_remove(struct wl_event_source *source)
380{
381 source->interface->remove(source);
382
383 return 0;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400384}
385
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500386WL_EXPORT struct wl_event_loop *
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400387wl_event_loop_create(void)
388{
389 struct wl_event_loop *loop;
390
391 loop = malloc(sizeof *loop);
392 if (loop == NULL)
393 return NULL;
394
395 loop->epoll_fd = epoll_create(16);
396 if (loop->epoll_fd < 0) {
397 free(loop);
398 return NULL;
399 }
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500400 wl_list_init(&loop->idle_list);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400401
402 return loop;
403}
404
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500405WL_EXPORT void
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400406wl_event_loop_destroy(struct wl_event_loop *loop)
407{
408 close(loop->epoll_fd);
409 free(loop);
410}
411
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500412static void
413dispatch_idles(struct wl_event_loop *loop)
414{
415 struct wl_event_source_idle *source, *next;
416
417 source = container_of(loop->idle_list.next,
418 struct wl_event_source_idle, link);
419
420 while (&source->link != &loop->idle_list) {
421 source->func(source->data);
422 next = container_of(source->link.next,
423 struct wl_event_source_idle, link);
424 free(source);
425 source = next;
426 }
427
428 wl_list_init(&loop->idle_list);
429}
430
Kristian Høgsbergb7a01922008-11-08 15:39:41 -0500431WL_EXPORT int
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400432wl_event_loop_wait(struct wl_event_loop *loop)
433{
434 struct epoll_event ep[32];
435 struct wl_event_source *source;
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400436 int i, count, timeout;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400437
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500438 if (wl_list_empty(&loop->idle_list))
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400439 timeout = -1;
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500440 else
441 timeout = 0;
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400442
443 count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400444 if (count < 0)
445 return -1;
446
447 for (i = 0; i < count; i++) {
448 source = ep[i].data.ptr;
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500449 source->interface->dispatch(source, &ep[i]);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400450 }
451
Kristian Høgsberg4a298902008-11-28 18:35:25 -0500452 if (count == 0)
453 dispatch_idles(loop);
454
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400455
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400456 return 0;
457}