xref: /PHP-7.4/sapi/fpm/fpm/events/poll.c (revision 0cf7de1c)
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