blob: f4311616c5283d934ced7cfefcd4394a5621b39d [file] [log] [blame]
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -04001#include <stddef.h>
2#include <stdio.h>
3#include <errno.h>
4#include <stdlib.h>
5#include <string.h>
6#include <sys/socket.h>
7#include <sys/un.h>
8#include <sys/epoll.h>
9#include <unistd.h>
10#include "wayland.h"
11
12struct wl_event_loop {
13 int epoll_fd;
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -040014 wl_event_loop_idle_func_t idle_func;
15 void *idle_data;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040016};
17
18struct wl_event_source {
19 int fd;
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -040020 wl_event_loop_fd_func_t func;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040021 void *data;
22};
23
24struct wl_event_source *
25wl_event_loop_add_fd(struct wl_event_loop *loop,
26 int fd, uint32_t mask,
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -040027 wl_event_loop_fd_func_t func,
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040028 void *data)
29{
30 struct wl_event_source *source;
31 struct epoll_event ep;
32
33 source = malloc(sizeof *source);
34 source->fd = fd;
35 source->func = func;
36 source->data = data;
37
38 ep.events = 0;
39 if (mask & WL_EVENT_READABLE)
40 ep.events |= EPOLLIN;
41 if (mask & WL_EVENT_WRITEABLE)
42 ep.events |= EPOLLOUT;
43 ep.data.ptr = source;
44
45 if (epoll_ctl(loop->epoll_fd, EPOLL_CTL_ADD, fd, &ep) < 0) {
46 free(source);
47 return NULL;
48 }
49
50 return source;
51}
52
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -040053struct wl_event_source idle_source;
54
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040055int
56wl_event_loop_remove_source(struct wl_event_loop *loop,
57 struct wl_event_source *source)
58{
59 int fd;
60
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -040061 if (source == &idle_source) {
62 loop->idle_func = NULL;
63 return 0;
64 } else {
65 fd = source->fd;
66 free(source);
67 return epoll_ctl(loop->epoll_fd,
68 EPOLL_CTL_DEL, fd, NULL);
69 };
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040070}
71
Kristian Høgsberga67a71a2008-10-07 10:10:36 -040072int
73wl_event_loop_update_source(struct wl_event_loop *loop,
74 struct wl_event_source *source,
75 uint32_t mask)
76{
77 struct epoll_event ep;
78
79 ep.events = 0;
80 if (mask & WL_EVENT_READABLE)
81 ep.events |= EPOLLIN;
82 if (mask & WL_EVENT_WRITEABLE)
83 ep.events |= EPOLLOUT;
84 ep.data.ptr = source;
85
86 return epoll_ctl(loop->epoll_fd,
87 EPOLL_CTL_MOD, source->fd, &ep);
88}
89
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -040090struct wl_event_loop *
91wl_event_loop_create(void)
92{
93 struct wl_event_loop *loop;
94
95 loop = malloc(sizeof *loop);
96 if (loop == NULL)
97 return NULL;
98
99 loop->epoll_fd = epoll_create(16);
100 if (loop->epoll_fd < 0) {
101 free(loop);
102 return NULL;
103 }
104
105 return loop;
106}
107
108void
109wl_event_loop_destroy(struct wl_event_loop *loop)
110{
111 close(loop->epoll_fd);
112 free(loop);
113}
114
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400115struct wl_event_source *
116wl_event_loop_add_idle(struct wl_event_loop *loop,
117 wl_event_loop_idle_func_t func,
118 void *data)
119{
120 loop->idle_func = func;
121 loop->idle_data = data;
122
123 return &idle_source;
124}
125
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400126#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
127
128int
129wl_event_loop_wait(struct wl_event_loop *loop)
130{
131 struct epoll_event ep[32];
132 struct wl_event_source *source;
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400133 int i, count, timeout;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400134 uint32_t mask;
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400135
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400136 if (loop->idle_func)
137 timeout = 0;
138 else
139 timeout = -1;
140
141 count = epoll_wait(loop->epoll_fd, ep, ARRAY_LENGTH(ep), timeout);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400142 if (count < 0)
143 return -1;
144
145 for (i = 0; i < count; i++) {
146 source = ep[i].data.ptr;
Kristian Høgsberga67a71a2008-10-07 10:10:36 -0400147 mask = 0;
148 if (ep[i].events & EPOLLIN)
149 mask |= WL_EVENT_READABLE;
150 if (ep[i].events & EPOLLOUT)
151 mask |= WL_EVENT_WRITEABLE;
152
153 source->func(source->fd, mask, source->data);
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400154 }
155
Kristian Høgsberg5ebb3172008-10-11 19:21:35 -0400156 if (count == 0 && loop->idle_func != NULL) {
157 loop->idle_func(loop->idle_data);
158 loop->idle_func = NULL;
159 }
160
Kristian Høgsberg97f1ebe2008-09-30 09:46:10 -0400161 return 0;
162}