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