1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 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 #include "../fpm_config.h"
20 #include "../fpm_events.h"
21 #include "../fpm.h"
22 #include "../zlog.h"
23
24 #if HAVE_POLL
25
26 #include <poll.h>
27 #include <errno.h>
28 #include <string.h>
29
30 static int fpm_event_poll_init(int max);
31 static int fpm_event_poll_clean();
32 static int fpm_event_poll_wait(struct fpm_event_queue_s *queue, unsigned long int timeout);
33 static int fpm_event_poll_add(struct fpm_event_s *ev);
34 static int fpm_event_poll_remove(struct fpm_event_s *ev);
35
36 static struct fpm_event_module_s poll_module = {
37 .name = "poll",
38 .support_edge_trigger = 0,
39 .init = fpm_event_poll_init,
40 .clean = fpm_event_poll_clean,
41 .wait = fpm_event_poll_wait,
42 .add = fpm_event_poll_add,
43 .remove = fpm_event_poll_remove,
44 };
45
46 static struct pollfd *pollfds = NULL;
47 static struct pollfd *active_pollfds = NULL;
48 static int npollfds = 0;
49 static int next_free_slot = 0;
50 #endif /* HAVE_POLL */
51
52 /*
53 * return the module configuration
54 */
fpm_event_poll_module()55 struct fpm_event_module_s *fpm_event_poll_module() /* {{{ */
56 {
57 #if HAVE_POLL
58 return &poll_module;
59 #else
60 return NULL;
61 #endif /* HAVE_POLL */
62 }
63 /* }}} */
64
65 #if HAVE_POLL
66
67 /*
68 * Init the module
69 */
fpm_event_poll_init(int max)70 static int fpm_event_poll_init(int max) /* {{{ */
71 {
72 int i;
73
74 if (max < 1) {
75 return 0;
76 }
77
78 /* alloc and clear pollfds */
79 pollfds = malloc(sizeof(struct pollfd) * max);
80 if (!pollfds) {
81 zlog(ZLOG_ERROR, "poll: unable to allocate %d events", max);
82 return -1;
83 }
84 memset(pollfds, 0, sizeof(struct pollfd) * max);
85
86 /* set all fd to -1 in order to ensure it's not set */
87 for (i = 0; i < max; i++) {
88 pollfds[i].fd = -1;
89 }
90
91 /* alloc and clear active_pollfds */
92 active_pollfds = malloc(sizeof(struct pollfd) * max);
93 if (!active_pollfds) {
94 free(pollfds);
95 zlog(ZLOG_ERROR, "poll: unable to allocate %d events", max);
96 return -1;
97 }
98 memset(active_pollfds, 0, sizeof(struct pollfd) * max);
99
100 /* save max */
101 npollfds = max;
102 return 0;
103 }
104 /* }}} */
105
106 /*
107 * Clean the module
108 */
fpm_event_poll_clean()109 static int fpm_event_poll_clean() /* {{{ */
110 {
111 /* free pollfds */
112 if (pollfds) {
113 free(pollfds);
114 pollfds = NULL;
115 }
116
117 /* free active_pollfds */
118 if (active_pollfds) {
119 free(active_pollfds);
120 active_pollfds = NULL;
121 }
122
123 npollfds = 0;
124 return 0;
125 }
126 /* }}} */
127
128 /*
129 * wait for events or timeout
130 */
fpm_event_poll_wait(struct fpm_event_queue_s * queue,unsigned long int timeout)131 static int fpm_event_poll_wait(struct fpm_event_queue_s *queue, unsigned long int timeout) /* {{{ */
132 {
133 int ret;
134 struct fpm_event_queue_s *q;
135
136 if (npollfds > 0) {
137 /* copy pollfds because poll() alters it */
138 memcpy(active_pollfds, pollfds, sizeof(struct pollfd) * npollfds);
139 }
140
141 /* wait for inconming event or timeout */
142 ret = poll(active_pollfds, npollfds, timeout);
143 if (ret == -1) {
144
145 /* trigger error unless signal interrupt */
146 if (errno != EINTR) {
147 zlog(ZLOG_WARNING, "poll() returns %d", errno);
148 return -1;
149 }
150 }
151
152 /* events have been triggered */
153 if (ret > 0) {
154
155 /* trigger POLLIN events */
156 q = queue;
157 while (q) {
158 /* ensure ev->index is valid */
159 if (q->ev && q->ev->index >= 0 && q->ev->index < npollfds && q->ev->fd == active_pollfds[q->ev->index].fd) {
160
161 /* has the event has been triggered ? */
162 if (active_pollfds[q->ev->index].revents & POLLIN) {
163
164 /* fire the event */
165 fpm_event_fire(q->ev);
166
167 /* sanity check */
168 if (fpm_globals.parent_pid != getpid()) {
169 return -2;
170 }
171 }
172 }
173 q = q->next; /* iterate */
174 }
175 }
176
177 return ret;
178 }
179 /* }}} */
180
181 /*
182 * Add a FD to the fd set
183 */
fpm_event_poll_add(struct fpm_event_s * ev)184 static int fpm_event_poll_add(struct fpm_event_s *ev) /* {{{ */
185 {
186 int i;
187
188 /* do we have a direct free slot */
189 if (pollfds[next_free_slot].fd == -1) {
190 /* register the event */
191 pollfds[next_free_slot].fd = ev->fd;
192 pollfds[next_free_slot].events = POLLIN;
193
194 /* remember the event place in the fd list and suppose next slot is free */
195 ev->index = next_free_slot++;
196 if (next_free_slot >= npollfds) {
197 next_free_slot = 0;
198 }
199 return 0;
200 }
201
202 /* let's search */
203 for (i = 0; i < npollfds; i++) {
204 if (pollfds[i].fd != -1) {
205 /* not free */
206 continue;
207 }
208
209 /* register the event */
210 pollfds[i].fd = ev->fd;
211 pollfds[i].events = POLLIN;
212
213 /* remember the event place in the fd list and suppose next slot is free */
214 ev->index = next_free_slot++;
215 if (next_free_slot >= npollfds) {
216 next_free_slot = 0;
217 }
218 return 0;
219 }
220
221 zlog(ZLOG_ERROR, "poll: not enought space to add event (fd=%d)", ev->fd);
222 return -1;
223 }
224 /* }}} */
225
226 /*
227 * Remove a FD from the fd set
228 */
fpm_event_poll_remove(struct fpm_event_s * ev)229 static int fpm_event_poll_remove(struct fpm_event_s *ev) /* {{{ */
230 {
231 int i;
232
233 /* do we have a direct access */
234 if (ev->index >= 0 && ev->index < npollfds && pollfds[ev->index].fd == ev->fd) {
235 /* remember this slot as free */
236 next_free_slot = ev->index;
237
238 /* clear event in pollfds */
239 pollfds[ev->index].fd = -1;
240 pollfds[ev->index].events = 0;
241
242 /* mark the event as not registered */
243 ev->index = -1;
244
245 return 0;
246 }
247
248 /* let's search */
249 for (i = 0; i < npollfds; i++) {
250
251 if (pollfds[i].fd != ev->fd) {
252 /* not found */
253 continue;
254 }
255
256 /* remember this slot as free */
257 next_free_slot = i;
258
259 /* clear event in pollfds */
260 pollfds[i].fd = -1;
261 pollfds[i].events = 0;
262
263 /* mark the event as not registered */
264 ev->index = -1;
265
266 return 0;
267 }
268
269 zlog(ZLOG_ERROR, "poll: unable to remove event: not found (fd=%d, index=%d)", ev->fd, ev->index);
270 return -1;
271 }
272 /* }}} */
273
274 #endif /* HAVE_POLL */
275