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