1
/* Copyright 2000-2005 The Apache Software Foundation or its licensors, as
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
* you may not use this file except in compliance with the License.
6
* You may obtain a copy of the License at
8
* http://www.apache.org/licenses/LICENSE-2.0
10
* Unless required by applicable law or agreed to in writing, software
11
* distributed under the License is distributed on an "AS IS" BASIS,
12
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
* See the License for the specific language governing permissions and
14
* limitations under the License.
17
#include "apr_arch_poll_private.h"
19
#ifdef POLLSET_USES_PORT
21
static apr_int16_t get_event(apr_int16_t event)
25
if (event & APR_POLLIN)
27
if (event & APR_POLLPRI)
29
if (event & APR_POLLOUT)
31
if (event & APR_POLLERR)
33
if (event & APR_POLLHUP)
35
if (event & APR_POLLNVAL)
41
static apr_int16_t get_revent(apr_int16_t event)
68
port_event_t *port_set;
69
apr_pollfd_t *result_set;
72
/* A thread mutex to protect operations on the rings */
73
apr_thread_mutex_t *ring_lock;
75
/* A ring containing all of the pollfd_t that are active */
76
APR_RING_HEAD(pfd_query_ring_t, pfd_elem_t) query_ring;
77
APR_RING_HEAD(pfd_add_ring_t, pfd_elem_t) add_ring;
78
/* A ring of pollfd_t that have been used, and then _remove'd */
79
APR_RING_HEAD(pfd_free_ring_t, pfd_elem_t) free_ring;
80
/* A ring of pollfd_t where rings that have been _remove'd but
81
might still be inside a _poll */
82
APR_RING_HEAD(pfd_dead_ring_t, pfd_elem_t) dead_ring;
85
static apr_status_t backend_cleanup(void *p_)
87
apr_pollset_t *pollset = (apr_pollset_t *) p_;
88
close(pollset->port_fd);
92
APR_DECLARE(apr_status_t) apr_pollset_create(apr_pollset_t **pollset,
97
apr_status_t rv = APR_SUCCESS;
98
*pollset = apr_palloc(p, sizeof(**pollset));
100
if (flags & APR_POLLSET_THREADSAFE &&
101
((rv = apr_thread_mutex_create(&(*pollset)->ring_lock,
102
APR_THREAD_MUTEX_DEFAULT,
103
p) != APR_SUCCESS))) {
108
if (flags & APR_POLLSET_THREADSAFE) {
113
(*pollset)->nelts = 0;
114
(*pollset)->nalloc = size;
115
(*pollset)->flags = flags;
116
(*pollset)->pool = p;
118
(*pollset)->port_set = apr_palloc(p, size * sizeof(port_event_t));
120
(*pollset)->port_fd = port_create();
122
if ((*pollset)->port_fd < 0) {
126
apr_pool_cleanup_register(p, (void *) (*pollset), backend_cleanup,
127
apr_pool_cleanup_null);
129
(*pollset)->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
131
APR_RING_INIT(&(*pollset)->query_ring, pfd_elem_t, link);
132
APR_RING_INIT(&(*pollset)->add_ring, pfd_elem_t, link);
133
APR_RING_INIT(&(*pollset)->free_ring, pfd_elem_t, link);
134
APR_RING_INIT(&(*pollset)->dead_ring, pfd_elem_t, link);
139
APR_DECLARE(apr_status_t) apr_pollset_destroy(apr_pollset_t *pollset)
141
return apr_pool_cleanup_run(pollset->pool, pollset, backend_cleanup);
144
APR_DECLARE(apr_status_t) apr_pollset_add(apr_pollset_t *pollset,
145
const apr_pollfd_t *descriptor)
150
apr_status_t rv = APR_SUCCESS;
152
pollset_lock_rings();
154
if (!APR_RING_EMPTY(&(pollset->free_ring), pfd_elem_t, link)) {
155
elem = APR_RING_FIRST(&(pollset->free_ring));
156
APR_RING_REMOVE(elem, link);
159
elem = (pfd_elem_t *) apr_palloc(pollset->pool, sizeof(pfd_elem_t));
160
APR_RING_ELEM_INIT(elem, link);
162
elem->pfd = *descriptor;
164
if (descriptor->desc_type == APR_POLL_SOCKET) {
165
fd = descriptor->desc.s->socketdes;
168
fd = descriptor->desc.f->filedes;
171
res = port_associate(pollset->port_fd, PORT_SOURCE_FD, fd,
172
get_event(descriptor->reqevents), (void *)elem);
176
APR_RING_INSERT_TAIL(&(pollset->free_ring), elem, pfd_elem_t, link);
180
APR_RING_INSERT_TAIL(&(pollset->query_ring), elem, pfd_elem_t, link);
183
pollset_unlock_rings();
188
APR_DECLARE(apr_status_t) apr_pollset_remove(apr_pollset_t *pollset,
189
const apr_pollfd_t *descriptor)
193
apr_status_t rv = APR_SUCCESS;
196
pollset_lock_rings();
198
if (descriptor->desc_type == APR_POLL_SOCKET) {
199
fd = descriptor->desc.s->socketdes;
202
fd = descriptor->desc.f->filedes;
205
res = port_dissociate(pollset->port_fd, PORT_SOURCE_FD, fd);
211
if (!APR_RING_EMPTY(&(pollset->query_ring), pfd_elem_t, link)) {
212
for (ep = APR_RING_FIRST(&(pollset->query_ring));
213
ep != APR_RING_SENTINEL(&(pollset->query_ring),
215
ep = APR_RING_NEXT(ep, link)) {
217
if (descriptor->desc.s == ep->pfd.desc.s) {
218
APR_RING_REMOVE(ep, link);
219
APR_RING_INSERT_TAIL(&(pollset->dead_ring),
220
ep, pfd_elem_t, link);
226
if (!APR_RING_EMPTY(&(pollset->add_ring), pfd_elem_t, link)) {
227
for (ep = APR_RING_FIRST(&(pollset->add_ring));
228
ep != APR_RING_SENTINEL(&(pollset->add_ring),
230
ep = APR_RING_NEXT(ep, link)) {
232
if (descriptor->desc.s == ep->pfd.desc.s) {
233
APR_RING_REMOVE(ep, link);
234
APR_RING_INSERT_TAIL(&(pollset->dead_ring),
235
ep, pfd_elem_t, link);
241
pollset_unlock_rings();
246
APR_DECLARE(apr_status_t) apr_pollset_poll(apr_pollset_t *pollset,
247
apr_interval_time_t timeout,
249
const apr_pollfd_t **descriptors)
255
struct timespec tv, *tvptr;
256
apr_status_t rv = APR_SUCCESS;
262
tv.tv_sec = (long) apr_time_sec(timeout);
263
tv.tv_nsec = (long) apr_time_msec(timeout);
269
pollset_lock_rings();
271
while (!APR_RING_EMPTY(&(pollset->add_ring), pfd_elem_t, link)) {
272
ep = APR_RING_FIRST(&(pollset->add_ring));
273
APR_RING_REMOVE(ep, link);
275
if (ep->pfd.desc_type == APR_POLL_SOCKET) {
276
fd = ep->pfd.desc.s->socketdes;
279
fd = ep->pfd.desc.f->filedes;
282
port_associate(pollset->port_fd, PORT_SOURCE_FD,
283
fd, get_event(ep->pfd.reqevents), ep);
285
APR_RING_INSERT_TAIL(&(pollset->query_ring), ep, pfd_elem_t, link);
289
pollset_unlock_rings();
291
ret = port_getn(pollset->port_fd, pollset->port_set, pollset->nalloc,
298
if (errno == ETIME || errno == EINTR) {
305
else if (nget == 0) {
310
pollset_lock_rings();
312
for (i = 0; i < nget; i++) {
313
pollset->result_set[i] =
314
(((pfd_elem_t*)(pollset->port_set[i].portev_user))->pfd);
315
pollset->result_set[i].rtnevents =
316
get_revent(pollset->port_set[i].portev_events);
318
APR_RING_REMOVE((pfd_elem_t*)pollset->port_set[i].portev_user, link);
320
APR_RING_INSERT_TAIL(&(pollset->add_ring),
321
(pfd_elem_t*)pollset->port_set[i].portev_user,
325
pollset_unlock_rings();
328
*descriptors = pollset->result_set;
333
pollset_lock_rings();
335
/* Shift all PFDs in the Dead Ring to be Free Ring */
336
APR_RING_CONCAT(&(pollset->free_ring), &(pollset->dead_ring), pfd_elem_t, link);
338
pollset_unlock_rings();
343
#endif /* POLLSET_USES_PORT */