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