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 /* $Id$ */
20
21 #include "../fpm_config.h"
22 #include "../fpm_events.h"
23 #include "../fpm.h"
24 #include "../zlog.h"
25
26 #if HAVE_EPOLL
27
28 #include <sys/epoll.h>
29 #include <errno.h>
30
31 static int fpm_event_epoll_init(int max);
32 static int fpm_event_epoll_clean();
33 static int fpm_event_epoll_wait(struct fpm_event_queue_s *queue, unsigned long int timeout);
34 static int fpm_event_epoll_add(struct fpm_event_s *ev);
35 static int fpm_event_epoll_remove(struct fpm_event_s *ev);
36
37 static struct fpm_event_module_s epoll_module = {
38 .name = "epoll",
39 .support_edge_trigger = 1,
40 .init = fpm_event_epoll_init,
41 .clean = fpm_event_epoll_clean,
42 .wait = fpm_event_epoll_wait,
43 .add = fpm_event_epoll_add,
44 .remove = fpm_event_epoll_remove,
45 };
46
47 static struct epoll_event *epollfds = NULL;
48 static int nepollfds = 0;
49 static int epollfd = -1;
50
51 #endif /* HAVE_EPOLL */
52
fpm_event_epoll_module()53 struct fpm_event_module_s *fpm_event_epoll_module() /* {{{ */
54 {
55 #if HAVE_EPOLL
56 return &epoll_module;
57 #else
58 return NULL;
59 #endif /* HAVE_EPOLL */
60 }
61 /* }}} */
62
63 #if HAVE_EPOLL
64
65 /*
66 * Init the module
67 */
fpm_event_epoll_init(int max)68 static int fpm_event_epoll_init(int max) /* {{{ */
69 {
70 if (max < 1) {
71 return 0;
72 }
73
74 /* init epoll */
75 epollfd = epoll_create(max + 1);
76 if (epollfd < 0) {
77 zlog(ZLOG_ERROR, "epoll: unable to initialize");
78 return -1;
79 }
80
81 /* allocate fds */
82 epollfds = malloc(sizeof(struct epoll_event) * max);
83 if (!epollfds) {
84 zlog(ZLOG_ERROR, "epoll: unable to allocate %d events", max);
85 return -1;
86 }
87 memset(epollfds, 0, sizeof(struct epoll_event) * max);
88
89 /* save max */
90 nepollfds = max;
91
92 return 0;
93 }
94 /* }}} */
95
96 /*
97 * Clean the module
98 */
fpm_event_epoll_clean()99 static int fpm_event_epoll_clean() /* {{{ */
100 {
101 /* free epollfds */
102 if (epollfds) {
103 free(epollfds);
104 epollfds = NULL;
105 }
106 if (epollfd != -1) {
107 close(epollfd);
108 epollfd = -1;
109 }
110
111 nepollfds = 0;
112
113 return 0;
114 }
115 /* }}} */
116
117 /*
118 * wait for events or timeout
119 */
fpm_event_epoll_wait(struct fpm_event_queue_s * queue,unsigned long int timeout)120 static int fpm_event_epoll_wait(struct fpm_event_queue_s *queue, unsigned long int timeout) /* {{{ */
121 {
122 int ret, i;
123
124 /* ensure we have a clean epoolfds before calling epoll_wait() */
125 memset(epollfds, 0, sizeof(struct epoll_event) * nepollfds);
126
127 /* wait for inconming event or timeout */
128 ret = epoll_wait(epollfd, epollfds, nepollfds, timeout);
129 if (ret == -1) {
130
131 /* trigger error unless signal interrupt */
132 if (errno != EINTR) {
133 zlog(ZLOG_WARNING, "epoll_wait() returns %d", errno);
134 return -1;
135 }
136 }
137
138 /* events have been triggered, let's fire them */
139 for (i = 0; i < ret; i++) {
140
141 /* do we have a valid ev ptr ? */
142 if (!epollfds[i].data.ptr) {
143 continue;
144 }
145
146 /* fire the event */
147 fpm_event_fire((struct fpm_event_s *)epollfds[i].data.ptr);
148
149 /* sanity check */
150 if (fpm_globals.parent_pid != getpid()) {
151 return -2;
152 }
153 }
154
155 return ret;
156 }
157 /* }}} */
158
159 /*
160 * Add a FD to the fd set
161 */
fpm_event_epoll_add(struct fpm_event_s * ev)162 static int fpm_event_epoll_add(struct fpm_event_s *ev) /* {{{ */
163 {
164 struct epoll_event e;
165
166 /* fill epoll struct */
167 #if SIZEOF_SIZE_T == 4
168 /* Completely initialize event data to prevent valgrind reports */
169 e.data.u64 = 0;
170 #endif
171 e.events = EPOLLIN;
172 e.data.fd = ev->fd;
173 e.data.ptr = (void *)ev;
174
175 if (ev->flags & FPM_EV_EDGE) {
176 e.events = e.events | EPOLLET;
177 }
178
179 /* add the event to epoll internal queue */
180 if (epoll_ctl(epollfd, EPOLL_CTL_ADD, ev->fd, &e) == -1) {
181 zlog(ZLOG_ERROR, "epoll: unable to add fd %d", ev->fd);
182 return -1;
183 }
184
185 /* mark the event as registered */
186 ev->index = ev->fd;
187 return 0;
188 }
189 /* }}} */
190
191 /*
192 * Remove a FD from the fd set
193 */
fpm_event_epoll_remove(struct fpm_event_s * ev)194 static int fpm_event_epoll_remove(struct fpm_event_s *ev) /* {{{ */
195 {
196 struct epoll_event e;
197
198 /* fill epoll struct the same way we did in fpm_event_epoll_add() */
199 e.events = EPOLLIN;
200 e.data.fd = ev->fd;
201 e.data.ptr = (void *)ev;
202
203 if (ev->flags & FPM_EV_EDGE) {
204 e.events = e.events | EPOLLET;
205 }
206
207 /* remove the event from epoll internal queue */
208 if (epoll_ctl(epollfd, EPOLL_CTL_DEL, ev->fd, &e) == -1) {
209 zlog(ZLOG_ERROR, "epoll: unable to remove fd %d", ev->fd);
210 return -1;
211 }
212
213 /* mark the event as not registered */
214 ev->index = -1;
215 return 0;
216 }
217 /* }}} */
218
219 #endif /* HAVE_EPOLL */
220