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 #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 throught 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 informations */
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 informations 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