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