xref: /PHP-5.5/sapi/fpm/fpm/events/epoll.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_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 	e.events = EPOLLIN;
168 	e.data.fd = ev->fd;
169 	e.data.ptr = (void *)ev;
170 
171 	if (ev->flags & FPM_EV_EDGE) {
172 		e.events = e.events | EPOLLET;
173 	}
174 
175 	/* add the event to epoll internal queue */
176 	if (epoll_ctl(epollfd, EPOLL_CTL_ADD, ev->fd, &e) == -1) {
177 		zlog(ZLOG_ERROR, "epoll: unable to add fd %d", ev->fd);
178 		return -1;
179 	}
180 
181 	/* mark the event as registered */
182 	ev->index = ev->fd;
183 	return 0;
184 }
185 /* }}} */
186 
187 /*
188  * Remove a FD from the fd set
189  */
fpm_event_epoll_remove(struct fpm_event_s * ev)190 static int fpm_event_epoll_remove(struct fpm_event_s *ev) /* {{{ */
191 {
192 	struct epoll_event e;
193 
194 	/* fill epoll struct the same way we did in fpm_event_epoll_add() */
195 	e.events = EPOLLIN;
196 	e.data.fd = ev->fd;
197 	e.data.ptr = (void *)ev;
198 
199 	if (ev->flags & FPM_EV_EDGE) {
200 		e.events = e.events | EPOLLET;
201 	}
202 
203 	/* remove the event from epoll internal queue */
204 	if (epoll_ctl(epollfd, EPOLL_CTL_DEL, ev->fd, &e) == -1) {
205 		zlog(ZLOG_ERROR, "epoll: unable to remove fd %d", ev->fd);
206 		return -1;
207 	}
208 
209 	/* mark the event as not registered */
210 	ev->index = -1;
211 	return 0;
212 }
213 /* }}} */
214 
215 #endif /* HAVE_EPOLL */
216