1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2013 The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Jerome Loyet <jerome@loyet.net> |
16 +----------------------------------------------------------------------+
17 */
18
19 /* $Id$ */
20
21 #include "../fpm_config.h"
22 #include "../fpm_events.h"
23 #include "../fpm.h"
24 #include "../zlog.h"
25
26 #if HAVE_DEVPOLL
27
28 #include <sys/types.h>
29 #include <sys/stat.h>
30 #include <fcntl.h>
31 #include <poll.h>
32 #include <sys/devpoll.h>
33 #include <errno.h>
34
35 static int fpm_event_devpoll_init(int max);
36 static int fpm_event_devpoll_clean();
37 static int fpm_event_devpoll_wait(struct fpm_event_queue_s *queue, unsigned long int timeout);
38 static int fpm_event_devpoll_add(struct fpm_event_s *ev);
39 static int fpm_event_devpoll_remove(struct fpm_event_s *ev);
40
41 static struct fpm_event_module_s devpoll_module = {
42 .name = "/dev/poll",
43 .support_edge_trigger = 0,
44 .init = fpm_event_devpoll_init,
45 .clean = fpm_event_devpoll_clean,
46 .wait = fpm_event_devpoll_wait,
47 .add = fpm_event_devpoll_add,
48 .remove = fpm_event_devpoll_remove,
49 };
50
51 int dpfd = -1;
52 static struct pollfd *pollfds = NULL;
53 static struct pollfd *active_pollfds = NULL;
54 static int npollfds = 0;
55
56 #endif /* HAVE_DEVPOLL */
57
fpm_event_devpoll_module()58 struct fpm_event_module_s *fpm_event_devpoll_module() /* {{{ */
59 {
60 #if HAVE_DEVPOLL
61 return &devpoll_module;
62 #else
63 return NULL;
64 #endif /* HAVE_DEVPOLL */
65 }
66 /* }}} */
67
68 #if HAVE_DEVPOLL
69
70 /*
71 * Init module
72 */
fpm_event_devpoll_init(int max)73 static int fpm_event_devpoll_init(int max) /* {{{ */
74 {
75 int i;
76
77 /* open /dev/poll for future usages */
78 dpfd = open("/dev/poll", O_RDWR);
79 if (dpfd < 0) {
80 zlog(ZLOG_ERROR, "Unable to open /dev/poll");
81 return -1;
82 }
83
84 if (max < 1) {
85 return 0;
86 }
87
88 /* alloc and clear pollfds */
89 pollfds = malloc(sizeof(struct pollfd) * max);
90 if (!pollfds) {
91 zlog(ZLOG_ERROR, "poll: unable to allocate %d events", max);
92 return -1;
93 }
94 memset(pollfds, 0, sizeof(struct pollfd) * max);
95
96 /* set all fd to -1 in order to ensure it's not set */
97 for (i = 0; i < max; i++) {
98 pollfds[i].fd = -1;
99 }
100
101 /* alloc and clear active_pollfds */
102 active_pollfds = malloc(sizeof(struct pollfd) * max);
103 if (!active_pollfds) {
104 free(pollfds);
105 zlog(ZLOG_ERROR, "poll: unable to allocate %d events", max);
106 return -1;
107 }
108 memset(active_pollfds, 0, sizeof(struct pollfd) * max);
109
110 /* save max */
111 npollfds = max;
112
113 return 0;
114 }
115 /* }}} */
116
117 /*
118 * Clean the module
119 */
fpm_event_devpoll_clean()120 static int fpm_event_devpoll_clean() /* {{{ */
121 {
122 /* close /dev/poll if open */
123 if (dpfd > -1) {
124 close(dpfd);
125 dpfd = -1;
126 }
127
128 /* free pollfds */
129 if (pollfds) {
130 free(pollfds);
131 pollfds = NULL;
132 }
133
134 /* free active_pollfds */
135 if (active_pollfds) {
136 free(active_pollfds);
137 active_pollfds = NULL;
138 }
139
140 npollfds = 0;
141 return 0;
142 }
143 /* }}} */
144
145 /*
146 * wait for events or timeout
147 */
fpm_event_devpoll_wait(struct fpm_event_queue_s * queue,unsigned long int timeout)148 static int fpm_event_devpoll_wait(struct fpm_event_queue_s *queue, unsigned long int timeout) /* {{{ */
149 {
150 int ret, i;
151 struct fpm_event_queue_s *q;
152 struct dvpoll dopoll;
153
154 /* setup /dev/poll */
155 dopoll.dp_fds = active_pollfds;
156 dopoll.dp_nfds = npollfds;
157 dopoll.dp_timeout = (int)timeout;
158
159 /* wait for inconming event or timeout */
160 ret = ioctl(dpfd, DP_POLL, &dopoll);
161
162 if (ret < 0) {
163
164 /* trigger error unless signal interrupt */
165 if (errno != EINTR) {
166 zlog(ZLOG_WARNING, "/dev/poll: ioctl() returns %d", errno);
167 return -1;
168 }
169 }
170
171 /* iterate throught triggered events */
172 for (i = 0; i < ret; i++) {
173
174 /* find the corresponding event */
175 q = queue;
176 while (q) {
177
178 /* found */
179 if (q->ev && q->ev->fd == active_pollfds[i].fd) {
180
181 /* fire the event */
182 fpm_event_fire(q->ev);
183
184 /* sanity check */
185 if (fpm_globals.parent_pid != getpid()) {
186 return -2;
187 }
188 break; /* next triggered event */
189 }
190 q = q->next; /* iterate */
191 }
192 }
193
194 return ret;
195 }
196 /* }}} */
197
198 /*
199 * Add a FD from the fd set
200 */
fpm_event_devpoll_add(struct fpm_event_s * ev)201 static int fpm_event_devpoll_add(struct fpm_event_s *ev) /* {{{ */
202 {
203 struct pollfd pollfd;
204
205 /* fill pollfd with event informations */
206 pollfd.fd = ev->fd;
207 pollfd.events = POLLIN;
208 pollfd.revents = 0;
209
210 /* add the event to the internal queue */
211 if (write(dpfd, &pollfd, sizeof(struct pollfd)) != sizeof(struct pollfd)) {
212 zlog(ZLOG_ERROR, "/dev/poll: Unable to add the event in the internal queue");
213 return -1;
214 }
215
216 /* mark the event as registered */
217 ev->index = ev->fd;
218
219 return 0;
220 }
221 /* }}} */
222
223 /*
224 * Remove a FD from the fd set
225 */
fpm_event_devpoll_remove(struct fpm_event_s * ev)226 static int fpm_event_devpoll_remove(struct fpm_event_s *ev) /* {{{ */
227 {
228 struct pollfd pollfd;
229
230 /* fill pollfd with the same informations as fpm_event_devpoll_add */
231 pollfd.fd = ev->fd;
232 pollfd.events = POLLIN | POLLREMOVE;
233 pollfd.revents = 0;
234
235 /* add the event to the internal queue */
236 if (write(dpfd, &pollfd, sizeof(struct pollfd)) != sizeof(struct pollfd)) {
237 zlog(ZLOG_ERROR, "/dev/poll: Unable to remove the event in the internal queue");
238 return -1;
239 }
240
241 /* mark the event as registered */
242 ev->index = -1;
243
244 return 0;
245 }
246 /* }}} */
247
248 #endif /* HAVE_DEVPOLL */
249