xref: /PHP-7.4/sapi/fpm/fpm/events/port.c (revision ef3e0ee0)
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_PORT
25 
26 #include <port.h>
27 #include <poll.h>
28 #include <errno.h>
29 
30 static int fpm_event_port_init(int max);
31 static int fpm_event_port_clean();
32 static int fpm_event_port_wait(struct fpm_event_queue_s *queue, unsigned long int timeout);
33 static int fpm_event_port_add(struct fpm_event_s *ev);
34 static int fpm_event_port_remove(struct fpm_event_s *ev);
35 
36 static struct fpm_event_module_s port_module = {
37 	.name = "port",
38 	.support_edge_trigger = 0,
39 	.init = fpm_event_port_init,
40 	.clean = fpm_event_port_clean,
41 	.wait = fpm_event_port_wait,
42 	.add = fpm_event_port_add,
43 	.remove = fpm_event_port_remove,
44 };
45 
46 port_event_t *events = NULL;
47 int nevents = 0;
48 static int pfd = -1;
49 
50 #endif /* HAVE_PORT */
51 
fpm_event_port_module()52 struct fpm_event_module_s *fpm_event_port_module() /* {{{ */
53 {
54 #if HAVE_PORT
55 	return &port_module;
56 #else
57 	return NULL;
58 #endif /* HAVE_PORT */
59 }
60 /* }}} */
61 
62 #if HAVE_PORT
63 
64 /*
65  * Init the module
66  */
fpm_event_port_init(int max)67 static int fpm_event_port_init(int max) /* {{{ */
68 {
69 	/* open port */
70 	pfd = port_create();
71 	if (pfd < 0) {
72 		zlog(ZLOG_ERROR, "port: unable to initialize port_create()");
73 		return -1;
74 	}
75 
76 	if (max < 1) {
77 		return 0;
78 	}
79 
80 	/* alloc and clear active_pollfds */
81 	events = malloc(sizeof(port_event_t) * max);
82 	if (!events) {
83 		zlog(ZLOG_ERROR, "port: Unable to allocate %d events", max);
84 		return -1;
85 	}
86 
87 	nevents = max;
88 	return 0;
89 }
90 /* }}} */
91 
92 /*
93  * Clean the module
94  */
fpm_event_port_clean()95 static int fpm_event_port_clean() /* {{{ */
96 {
97 	if (pfd > -1) {
98 		close(pfd);
99 		pfd = -1;
100 	}
101 
102 	if (events) {
103 		free(events);
104 		events = NULL;
105 	}
106 
107 	nevents = 0;
108 	return 0;
109 }
110 /* }}} */
111 
112 /*
113  * wait for events or timeout
114  */
fpm_event_port_wait(struct fpm_event_queue_s * queue,unsigned long int timeout)115 static int fpm_event_port_wait(struct fpm_event_queue_s *queue, unsigned long int timeout) /* {{{ */
116 {
117 	int ret;
118 	unsigned int i, nget;
119 	timespec_t t;
120 
121 	/* convert timeout into timespec_t */
122 	t.tv_sec = (int)(timeout / 1000);
123 	t.tv_nsec = (timeout % 1000) * 1000 * 1000;
124 
125 	/* wait for inconming event or timeout. We want at least one event or timeout */
126 	nget = 1;
127 	events[0].portev_user = (void *)-1; /* so we can double check that an event was returned */
128 
129 	ret = port_getn(pfd, events, nevents, &nget, &t);
130 	if (ret < 0) {
131 
132 		/* trigger error unless signal interrupt or timeout */
133 		if (errno != EINTR && errno != ETIME) {
134 			zlog(ZLOG_WARNING, "poll() returns %d", errno);
135 			return -1;
136 		} else if (nget > 0 && events[0].portev_user == (void *)-1) {
137 			/* This confusing API can return an event at the same time
138 			 * that it reports EINTR or ETIME.  If that occurs, just
139 			 * report the event.  With EINTR, nget can be > 0 without
140 			 * any event, so check that portev_user was filled in.
141 			 *
142 			 * See discussion thread
143 			 *   http://marc.info/?l=opensolaris-networking-discuss&m=125071205204540
144 			 */
145 			nget = 0;
146 		}
147 	}
148 
149 	for (i = 0; i < nget; i++) {
150 
151 		/* do we have a ptr to the event ? */
152 		if (!events[i].portev_user) {
153 			continue;
154 		}
155 
156 		/* fire the event */
157 		fpm_event_fire((struct fpm_event_s *)events[i].portev_user);
158 
159 		/* sanity check */
160 		if (fpm_globals.parent_pid != getpid()) {
161 			return -2;
162 		}
163 	}
164 	return nget;
165 }
166 /* }}} */
167 
168 /*
169  * Add a FD to the fd set
170  */
fpm_event_port_add(struct fpm_event_s * ev)171 static int fpm_event_port_add(struct fpm_event_s *ev) /* {{{ */
172 {
173 	/* add the event to port */
174 	if (port_associate(pfd, PORT_SOURCE_FD, ev->fd, POLLIN, (void *)ev) < 0) {
175 		zlog(ZLOG_ERROR, "port: unable to add the event");
176 		return -1;
177 	}
178 	return 0;
179 }
180 /* }}} */
181 
182 /*
183  * Remove a FD from the fd set
184  */
fpm_event_port_remove(struct fpm_event_s * ev)185 static int fpm_event_port_remove(struct fpm_event_s *ev) /* {{{ */
186 {
187 	/* remove the event from port */
188 	if (port_dissociate(pfd, PORT_SOURCE_FD, ev->fd) < 0) {
189 		zlog(ZLOG_ERROR, "port: unable to add the event");
190 		return -1;
191 	}
192 	return 0;
193 }
194 /* }}} */
195 
196 #endif /* HAVE_PORT */
197