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