Apache HTTPD
port.c
Go to the documentation of this file.
1/* Licensed to the Apache Software Foundation (ASF) under one or more
2 * contributor license agreements. See the NOTICE file distributed with
3 * this work for additional information regarding copyright ownership.
4 * The ASF licenses this file to You under the Apache License, Version 2.0
5 * (the "License"); you may not use this file except in compliance with
6 * the License. You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17#include "apr.h"
18#include "apr_poll.h"
19#include "apr_time.h"
20#include "apr_portable.h"
21#include "apr_atomic.h"
22#include "apr_arch_file_io.h"
23#include "apr_arch_networkio.h"
25#include "apr_arch_inherit.h"
26
27#if defined(HAVE_PORT_CREATE)
28
30{
31 apr_int16_t rv = 0;
32
33 if (event & APR_POLLIN)
34 rv |= POLLIN;
35 if (event & APR_POLLPRI)
36 rv |= POLLPRI;
37 if (event & APR_POLLOUT)
38 rv |= POLLOUT;
39 /* POLLERR, POLLHUP, and POLLNVAL aren't valid as requested events */
40
41 return rv;
42}
43
45{
46 apr_int16_t rv = 0;
47
48 if (event & POLLIN)
49 rv |= APR_POLLIN;
50 if (event & POLLPRI)
51 rv |= APR_POLLPRI;
52 if (event & POLLOUT)
53 rv |= APR_POLLOUT;
54 if (event & POLLERR)
55 rv |= APR_POLLERR;
56 if (event & POLLHUP)
57 rv |= APR_POLLHUP;
58 if (event & POLLNVAL)
59 rv |= APR_POLLNVAL;
60
61 return rv;
62}
63
64
66{
67 int port_fd;
70#if APR_HAS_THREADS
71 /* A thread mutex to protect operations on the rings */
73#endif
74 /* A ring containing all of the pollfd_t that are active */
76 /* A ring containing the pollfd_t that will be added on the
77 * next call to apr_pollset_poll().
78 */
80 /* A ring of pollfd_t that have been used, and then _remove'd */
82 /* A ring of pollfd_t where rings that have been _remove'd but
83 might still be inside a _poll */
85 /* number of threads in poll */
86 volatile apr_uint32_t waiting;
87};
88
90 unsigned int max, unsigned int *nget,
92{
93 struct timespec tv, *tvptr;
94 int ret;
96
97 if (timeout < 0) {
98 tvptr = NULL;
99 }
100 else {
101 tv.tv_sec = (long) apr_time_sec(timeout);
102 tv.tv_nsec = (long) apr_time_usec(timeout) * 1000;
103 tvptr = &tv;
104 }
105
106 list[0].portev_user = (void *)-1; /* so we can double check that an
107 * event was returned
108 */
109
111 /* Note: 32-bit port_getn() on Solaris 10 x86 returns large negative
112 * values instead of 0 when returning immediately.
113 */
114
115 if (ret == -1) {
116 rv = apr_get_netos_error();
117
118 switch(rv) {
119 case EINTR:
120 case ETIME:
121 if (*nget > 0 && list[0].portev_user != (void *)-1) {
122 /* This confusing API can return an event at the same time
123 * that it reports EINTR or ETIME. If that occurs, just
124 * report the event. With EINTR, nget can be > 0 without
125 * any event, so check that portev_user was filled in.
126 *
127 * (Maybe it will be simplified; see thread
128 * http://mail.opensolaris.org
129 * /pipermail/networking-discuss/2009-August/011979.html
130 * This code will still work afterwards.)
131 */
132 rv = APR_SUCCESS;
133 break;
134 }
135 if (rv == ETIME) {
136 rv = APR_TIMEUP;
137 }
138 /* fall-through */
139 default:
140 *nget = 0;
141 }
142 }
143 else if (*nget == 0) {
144 rv = APR_TIMEUP;
145 }
146
147 return rv;
148}
149
151{
152 close(pollset->p->port_fd);
153 return APR_SUCCESS;
154}
155
158 apr_pool_t *p,
160{
163#if APR_HAS_THREADS
165 ((rv = apr_thread_mutex_create(&pollset->p->ring_lock,
167 p)) != APR_SUCCESS)) {
168 pollset->p = NULL;
169 return rv;
170 }
171#else
173 pollset->p = NULL;
174 return APR_ENOTIMPL;
175 }
176#endif
177 pollset->p->waiting = 0;
178
179 pollset->p->port_set = apr_palloc(p, size * sizeof(port_event_t));
180
181 pollset->p->port_fd = port_create();
182
183 if (pollset->p->port_fd < 0) {
184 pollset->p = NULL;
185 return apr_get_netos_error();
186 }
187
188 {
189 int flags;
190
191 if ((flags = fcntl(pollset->p->port_fd, F_GETFD)) == -1) {
192 rv = errno;
193 close(pollset->p->port_fd);
194 pollset->p = NULL;
195 return rv;
196 }
197
198 flags |= FD_CLOEXEC;
199 if (fcntl(pollset->p->port_fd, F_SETFD, flags) == -1) {
200 rv = errno;
201 close(pollset->p->port_fd);
202 pollset->p = NULL;
203 return rv;
204 }
205 }
206
208
209 APR_RING_INIT(&pollset->p->query_ring, pfd_elem_t, link);
210 APR_RING_INIT(&pollset->p->add_ring, pfd_elem_t, link);
211 APR_RING_INIT(&pollset->p->free_ring, pfd_elem_t, link);
212 APR_RING_INIT(&pollset->p->dead_ring, pfd_elem_t, link);
213
214 return rv;
215}
216
219{
222 int res;
224
226
227 if (!APR_RING_EMPTY(&(pollset->p->free_ring), pfd_elem_t, link)) {
228 elem = APR_RING_FIRST(&(pollset->p->free_ring));
229 APR_RING_REMOVE(elem, link);
230 }
231 else {
234 elem->on_query_ring = 0;
235 }
236 elem->pfd = *descriptor;
237
240 }
241 else {
243 }
244
245 /* If another thread is polling, notify the kernel immediately; otherwise,
246 * wait until the next call to apr_pollset_poll().
247 */
248 if (apr_atomic_read32(&pollset->p->waiting)) {
251
252 if (res < 0) {
253 rv = apr_get_netos_error();
254 APR_RING_INSERT_TAIL(&(pollset->p->free_ring), elem, pfd_elem_t, link);
255 }
256 else {
257 elem->on_query_ring = 1;
258 APR_RING_INSERT_TAIL(&(pollset->p->query_ring), elem, pfd_elem_t, link);
259 }
260 }
261 else {
262 APR_RING_INSERT_TAIL(&(pollset->p->add_ring), elem, pfd_elem_t, link);
263 }
264
266
267 return rv;
268}
269
272{
274 pfd_elem_t *ep;
276 int res;
277 int err = 0;
278 int found;
279
281
284 }
285 else {
287 }
288
289 /* Search the add ring first. This ring is often shorter,
290 * and it often contains the descriptor being removed.
291 * (For the common scenario where apr_pollset_poll()
292 * returns activity for the descriptor and the descriptor
293 * is then removed from the pollset, it will have just
294 * been moved to the add ring by apr_pollset_poll().)
295 *
296 * If it is on the add ring, it isn't associated with the
297 * event port yet/anymore.
298 */
299 found = 0;
300 for (ep = APR_RING_FIRST(&(pollset->p->add_ring));
301 ep != APR_RING_SENTINEL(&(pollset->p->add_ring),
302 pfd_elem_t, link);
303 ep = APR_RING_NEXT(ep, link)) {
304
305 if (descriptor->desc.s == ep->pfd.desc.s) {
306 found = 1;
307 APR_RING_REMOVE(ep, link);
308 APR_RING_INSERT_TAIL(&(pollset->p->free_ring),
309 ep, pfd_elem_t, link);
310 break;
311 }
312 }
313
314 if (!found) {
316
317 if (res < 0) {
318 /* The expected case for this failure is that another
319 * thread's call to port_getn() returned this fd and
320 * disassociated the fd from the event port, and
321 * impl_pollset_poll() is blocked on the ring lock,
322 * which this thread holds.
323 */
324 err = errno;
325 rv = APR_NOTFOUND;
326 }
327
328 for (ep = APR_RING_FIRST(&(pollset->p->query_ring));
329 ep != APR_RING_SENTINEL(&(pollset->p->query_ring),
330 pfd_elem_t, link);
331 ep = APR_RING_NEXT(ep, link)) {
332
333 if (descriptor->desc.s == ep->pfd.desc.s) {
334 APR_RING_REMOVE(ep, link);
335 ep->on_query_ring = 0;
336 APR_RING_INSERT_TAIL(&(pollset->p->dead_ring),
337 ep, pfd_elem_t, link);
338 if (ENOENT == err) {
339 rv = APR_SUCCESS;
340 }
341 break;
342 }
343 }
344 }
345
347
348 return rv;
349}
350
355{
357 int ret;
358 unsigned int nget, i;
359 apr_int32_t j;
360 pfd_elem_t *ep;
362
363 *num = 0;
364 nget = 1;
365
367
368 apr_atomic_inc32(&pollset->p->waiting);
369
370 while (!APR_RING_EMPTY(&(pollset->p->add_ring), pfd_elem_t, link)) {
371 ep = APR_RING_FIRST(&(pollset->p->add_ring));
372 APR_RING_REMOVE(ep, link);
373
374 if (ep->pfd.desc_type == APR_POLL_SOCKET) {
375 fd = ep->pfd.desc.s->socketdes;
376 }
377 else {
378 fd = ep->pfd.desc.f->filedes;
379 }
380
382 fd, get_event(ep->pfd.reqevents), ep);
383 if (ret < 0) {
384 rv = apr_get_netos_error();
385 APR_RING_INSERT_TAIL(&(pollset->p->free_ring), ep, pfd_elem_t, link);
386 break;
387 }
388
389 ep->on_query_ring = 1;
390 APR_RING_INSERT_TAIL(&(pollset->p->query_ring), ep, pfd_elem_t, link);
391 }
392
394
395 if (rv != APR_SUCCESS) {
396 apr_atomic_dec32(&pollset->p->waiting);
397 return rv;
398 }
399
400 rv = call_port_getn(pollset->p->port_fd, pollset->p->port_set,
402
403 /* decrease the waiting ASAP to reduce the window for calling
404 port_associate within apr_pollset_add() */
405 apr_atomic_dec32(&pollset->p->waiting);
406
408
409 for (i = 0, j = 0; i < nget; i++) {
410 ep = (pfd_elem_t *)pollset->p->port_set[i].portev_user;
412 ep->pfd.desc_type == APR_POLL_FILE &&
413 ep->pfd.desc.f == pollset->wakeup_pipe[0]) {
415 rv = APR_EINTR;
416 }
417 else {
418 pollset->p->result_set[j] = ep->pfd;
420 get_revent(pollset->p->port_set[i].portev_events);
421 j++;
422 }
423 /* If the ring element is still on the query ring, move it
424 * to the add ring for re-association with the event port
425 * later. (It may have already been moved to the dead ring
426 * by a call to pollset_remove on another thread.)
427 */
428 if (ep->on_query_ring) {
429 APR_RING_REMOVE(ep, link);
430 ep->on_query_ring = 0;
431 APR_RING_INSERT_TAIL(&(pollset->p->add_ring), ep,
432 pfd_elem_t, link);
433 }
434 }
435 if ((*num = j)) { /* any event besides wakeup pipe? */
436 rv = APR_SUCCESS;
437 if (descriptors) {
439 }
440 }
441
442 /* Shift all PFDs in the Dead Ring to the Free Ring */
443 APR_RING_CONCAT(&(pollset->p->free_ring), &(pollset->p->dead_ring), pfd_elem_t, link);
444
446
447 return rv;
448}
449
450static const apr_pollset_provider_t impl = {
456 "port"
457};
458
460
462{
463 close(pollcb->fd);
464 return APR_SUCCESS;
465}
466
469 apr_pool_t *p,
471{
472 pollcb->fd = port_create();
473
474 if (pollcb->fd < 0) {
475 return apr_get_netos_error();
476 }
477
478 {
479 int flags;
480 apr_status_t rv;
481
482 if ((flags = fcntl(pollcb->fd, F_GETFD)) == -1) {
483 rv = errno;
484 close(pollcb->fd);
485 pollcb->fd = -1;
486 return rv;
487 }
488
489 flags |= FD_CLOEXEC;
490 if (fcntl(pollcb->fd, F_SETFD, flags) == -1) {
491 rv = errno;
492 close(pollcb->fd);
493 pollcb->fd = -1;
494 return rv;
495 }
496 }
497
498 pollcb->pollset.port = apr_palloc(p, size * sizeof(port_event_t));
499
500 return APR_SUCCESS;
501}
502
505{
506 int ret, fd;
507
510 }
511 else {
513 }
514
517
518 if (ret == -1) {
519 return apr_get_netos_error();
520 }
521
522 return APR_SUCCESS;
523}
524
527{
528 int fd, ret;
529
532 }
533 else {
535 }
536
538
539 if (ret < 0) {
540 return APR_NOTFOUND;
541 }
542
543 return APR_SUCCESS;
544}
545
549 void *baton)
550{
551 apr_status_t rv;
552 unsigned int nget = 1;
553
555 &nget, timeout);
556
557 if (nget) {
558 unsigned int i;
559
560 for (i = 0; i < nget; i++) {
561 apr_pollfd_t *pollfd = (apr_pollfd_t *)(pollcb->pollset.port[i].portev_user);
562
564 pollfd->desc_type == APR_POLL_FILE &&
565 pollfd->desc.f == pollcb->wakeup_pipe[0]) {
567 return APR_EINTR;
568 }
569
570 pollfd->rtnevents = get_revent(pollcb->pollset.port[i].portev_events);
571
572 rv = func(baton, pollfd);
573 if (rv) {
574 return rv;
575 }
577 }
578 }
579
580 return rv;
581}
582
583static const apr_pollcb_provider_t impl_cb = {
589 "port"
590};
591
593
594#endif /* HAVE_PORT_CREATE */
void apr_poll_drain_wakeup_pipe(apr_file_t **wakeup_pipe)
Definition wakeup.c:138
APR Atomic Operations.
APR Poll interface.
APR Portability Routines.
APR Time Library.
apr_uint32_t apr_atomic_inc32(volatile apr_uint32_t *mem)
Definition atomic.c:51
int apr_atomic_dec32(volatile apr_uint32_t *mem)
Definition atomic.c:56
apr_uint32_t apr_atomic_read32(volatile apr_uint32_t *mem)
Definition atomic.c:68
return found
Definition core.c:2840
const char apr_port_t port
Definition http_vhost.h:125
ap_vhost_iterate_conn_cb void * baton
Definition http_vhost.h:87
#define APR_ENOTIMPL
Definition apr_errno.h:476
#define APR_TIMEUP
Definition apr_errno.h:450
#define APR_NOTFOUND
Definition apr_errno.h:463
#define APR_EINTR
Definition apr_errno.h:737
apr_file_t * fd
apr_pool_t apr_dbd_t apr_dbd_results_t ** res
Definition apr_dbd.h:287
const char apr_ssize_t int flags
Definition apr_encode.h:168
apr_size_t size
const apr_array_header_t * list
Definition apr_cstr.h:105
#define apr_get_netos_error()
Definition apr_errno.h:1222
#define APR_SUCCESS
Definition apr_errno.h:225
int apr_status_t
Definition apr_errno.h:44
apr_status_t(* apr_pollcb_cb_t)(void *baton, apr_pollfd_t *descriptor)
Definition apr_poll.h:401
apr_interval_time_t apr_int32_t const apr_pollfd_t ** descriptors
Definition apr_poll.h:274
apr_interval_time_t apr_int32_t * num
Definition apr_poll.h:273
const apr_pollfd_t * descriptor
Definition apr_poll.h:230
apr_interval_time_t apr_pollcb_cb_t func
Definition apr_poll.h:422
@ APR_POLL_SOCKET
Definition apr_poll.h:93
@ APR_POLL_FILE
Definition apr_poll.h:94
int apr_os_sock_t
#define APR_RING_INSERT_TAIL(hp, nep, elem, link)
Definition apr_ring.h:328
#define APR_RING_INIT(hp, elem, link)
Definition apr_ring.h:192
#define APR_RING_HEAD(head, elem)
Definition apr_ring.h:91
#define APR_RING_CONCAT(h1, h2, elem, link)
Definition apr_ring.h:338
#define APR_RING_SENTINEL(hp, elem, link)
Definition apr_ring.h:159
#define APR_RING_EMPTY(hp, elem, link)
Definition apr_ring.h:204
#define APR_RING_REMOVE(ep, link)
Definition apr_ring.h:381
#define APR_RING_FIRST(hp)
Definition apr_ring.h:166
#define APR_RING_NEXT(ep, link)
Definition apr_ring.h:177
#define APR_RING_ELEM_INIT(ep, link)
Definition apr_ring.h:212
apr_int32_t apr_int32_t apr_int32_t err
apr_int64_t apr_interval_time_t
Definition apr_time.h:55
apr_size_t apr_size_t max
Definition apr_time.h:220
#define apr_time_sec(time)
Definition apr_time.h:63
#define apr_time_usec(time)
Definition apr_time.h:66
#define APR_POLLSET_WAKEABLE
Definition apr_poll.h:68
#define APR_POLLSET_THREADSAFE
Definition apr_poll.h:62
#define APR_POLLNVAL
Definition apr_poll.h:54
#define APR_POLLPRI
Definition apr_poll.h:50
#define APR_POLLERR
Definition apr_poll.h:52
#define APR_POLLOUT
Definition apr_poll.h:51
#define APR_POLLIN
Definition apr_poll.h:49
#define APR_POLLHUP
Definition apr_poll.h:53
static md_http_impl_t impl
Definition md_curl.c:639
apr_pool_t * p
Definition md_event.c:32
return NULL
Definition mod_so.c:359
int i
Definition mod_so.c:347
static apr_status_t impl_pollset_poll(apr_pollset_t *pollset, apr_interval_time_t timeout, apr_int32_t *num, const apr_pollfd_t **descriptors)
Definition select.c:339
static apr_status_t impl_pollset_add(apr_pollset_t *pollset, const apr_pollfd_t *descriptor)
Definition select.c:226
static apr_status_t impl_pollset_create(apr_pollset_t *pollset, apr_uint32_t size, apr_pool_t *p, apr_uint32_t flags)
Definition select.c:197
static apr_status_t impl_pollset_remove(apr_pollset_t *pollset, const apr_pollfd_t *descriptor)
Definition select.c:294
apr_file_t * wakeup_pipe[2]
apr_pollcb_pset pollset
apr_int16_t reqevents
Definition apr_poll.h:111
apr_datatype_e desc_type
Definition apr_poll.h:110
apr_descriptor desc
Definition apr_poll.h:113
apr_int16_t rtnevents
Definition apr_poll.h:112
apr_pollfd_t * result_set
Definition select.c:190
apr_file_t * wakeup_pipe[2]
apr_pollset_private_t * p
static apr_pollcb_t * pollcb
Definition testpoll.c:42
static apr_pollset_t * pollset
Definition testpoll.c:41
apr_socket_t * s
Definition apr_poll.h:101
apr_file_t * f
Definition apr_poll.h:100
#define POLLHUP
#define POLLIN
#define POLLOUT
#define POLLERR
#define POLLPRI
#define POLLNVAL
IN ULONG IN INT timeout