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