"Fossies" - the Fresh Open Source Software Archive

Member "apr-1.7.0/poll/unix/port.c" (3 Jan 2018, 17484 Bytes) of package /linux/www/apr-1.7.0.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "port.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.6.5_vs_1.7.0.

    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"
   24 #include "apr_arch_poll_private.h"
   25 #include "apr_arch_inherit.h"
   26 
   27 #if defined(HAVE_PORT_CREATE)
   28 
   29 static apr_int16_t get_event(apr_int16_t event)
   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 
   44 static apr_int16_t get_revent(apr_int16_t event)
   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 
   65 struct apr_pollset_private_t
   66 {
   67     int port_fd;
   68     port_event_t *port_set;
   69     apr_pollfd_t *result_set;
   70 #if APR_HAS_THREADS
   71     /* A thread mutex to protect operations on the rings */
   72     apr_thread_mutex_t *ring_lock;
   73 #endif
   74     /* A ring containing all of the pollfd_t that are active */
   75     APR_RING_HEAD(pfd_query_ring_t, pfd_elem_t) query_ring;
   76     /* A ring containing the pollfd_t that will be added on the
   77      * next call to apr_pollset_poll().
   78      */
   79     APR_RING_HEAD(pfd_add_ring_t, pfd_elem_t) add_ring;
   80     /* A ring of pollfd_t that have been used, and then _remove'd */
   81     APR_RING_HEAD(pfd_free_ring_t, pfd_elem_t) free_ring;
   82     /* A ring of pollfd_t where rings that have been _remove'd but
   83        might still be inside a _poll */
   84     APR_RING_HEAD(pfd_dead_ring_t, pfd_elem_t) dead_ring;
   85     /* number of threads in poll */
   86     volatile apr_uint32_t waiting;
   87 };
   88 
   89 static apr_status_t call_port_getn(int port, port_event_t list[], 
   90                                    unsigned int max, unsigned int *nget,
   91                                    apr_interval_time_t timeout)
   92 {
   93     struct timespec tv, *tvptr;
   94     int ret;
   95     apr_status_t rv = APR_SUCCESS;
   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 
  110     ret = port_getn(port, list, max, nget, tvptr);
  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 
  150 static apr_status_t impl_pollset_cleanup(apr_pollset_t *pollset)
  151 {
  152     close(pollset->p->port_fd);
  153     return APR_SUCCESS;
  154 }
  155 
  156 static apr_status_t impl_pollset_create(apr_pollset_t *pollset,
  157                                              apr_uint32_t size,
  158                                              apr_pool_t *p,
  159                                              apr_uint32_t flags)
  160 {
  161     apr_status_t rv = APR_SUCCESS;
  162     pollset->p = apr_palloc(p, sizeof(apr_pollset_private_t));
  163 #if APR_HAS_THREADS
  164     if (flags & APR_POLLSET_THREADSAFE &&
  165         ((rv = apr_thread_mutex_create(&pollset->p->ring_lock,
  166                                        APR_THREAD_MUTEX_DEFAULT,
  167                                        p)) != APR_SUCCESS)) {
  168         pollset->p = NULL;
  169         return rv;
  170     }
  171 #else
  172     if (flags & APR_POLLSET_THREADSAFE) {
  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 
  207     pollset->p->result_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
  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 
  217 static apr_status_t impl_pollset_add(apr_pollset_t *pollset,
  218                                      const apr_pollfd_t *descriptor)
  219 {
  220     apr_os_sock_t fd;
  221     pfd_elem_t *elem;
  222     int res;
  223     apr_status_t rv = APR_SUCCESS;
  224 
  225     pollset_lock_rings();
  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 {
  232         elem = (pfd_elem_t *) apr_palloc(pollset->pool, sizeof(pfd_elem_t));
  233         APR_RING_ELEM_INIT(elem, link);
  234         elem->on_query_ring = 0;
  235     }
  236     elem->pfd = *descriptor;
  237 
  238     if (descriptor->desc_type == APR_POLL_SOCKET) {
  239         fd = descriptor->desc.s->socketdes;
  240     }
  241     else {
  242         fd = descriptor->desc.f->filedes;
  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)) {
  249         res = port_associate(pollset->p->port_fd, PORT_SOURCE_FD, fd, 
  250                              get_event(descriptor->reqevents), (void *)elem);
  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 
  265     pollset_unlock_rings();
  266 
  267     return rv;
  268 }
  269 
  270 static apr_status_t impl_pollset_remove(apr_pollset_t *pollset,
  271                                         const apr_pollfd_t *descriptor)
  272 {
  273     apr_os_sock_t fd;
  274     pfd_elem_t *ep;
  275     apr_status_t rv = APR_SUCCESS;
  276     int res;
  277     int err = 0;
  278     int found;
  279 
  280     pollset_lock_rings();
  281 
  282     if (descriptor->desc_type == APR_POLL_SOCKET) {
  283         fd = descriptor->desc.s->socketdes;
  284     }
  285     else {
  286         fd = descriptor->desc.f->filedes;
  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) {
  315         res = port_dissociate(pollset->p->port_fd, PORT_SOURCE_FD, fd);
  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 
  346     pollset_unlock_rings();
  347 
  348     return rv;
  349 }
  350 
  351 static apr_status_t impl_pollset_poll(apr_pollset_t *pollset,
  352                                       apr_interval_time_t timeout,
  353                                       apr_int32_t *num,
  354                                       const apr_pollfd_t **descriptors)
  355 {
  356     apr_os_sock_t fd;
  357     int ret;
  358     unsigned int nget, i;
  359     apr_int32_t j;
  360     pfd_elem_t *ep;
  361     apr_status_t rv = APR_SUCCESS;
  362 
  363     *num = 0;
  364     nget = 1;
  365 
  366     pollset_lock_rings();
  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 
  381         ret = port_associate(pollset->p->port_fd, PORT_SOURCE_FD, 
  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 
  393     pollset_unlock_rings();
  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, 
  401                         pollset->nalloc, &nget, timeout);
  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 
  407     pollset_lock_rings();
  408 
  409     for (i = 0, j = 0; i < nget; i++) {
  410         ep = (pfd_elem_t *)pollset->p->port_set[i].portev_user;
  411         if ((pollset->flags & APR_POLLSET_WAKEABLE) &&
  412             ep->pfd.desc_type == APR_POLL_FILE &&
  413             ep->pfd.desc.f == pollset->wakeup_pipe[0]) {
  414             apr_poll_drain_wakeup_pipe(pollset->wakeup_pipe);
  415             rv = APR_EINTR;
  416         }
  417         else {
  418             pollset->p->result_set[j] = ep->pfd;
  419             pollset->p->result_set[j].rtnevents =
  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) {
  438             *descriptors = pollset->p->result_set;
  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 
  445     pollset_unlock_rings();
  446 
  447     return rv;
  448 }
  449 
  450 static const apr_pollset_provider_t impl = {
  451     impl_pollset_create,
  452     impl_pollset_add,
  453     impl_pollset_remove,
  454     impl_pollset_poll,
  455     impl_pollset_cleanup,
  456     "port"
  457 };
  458 
  459 const apr_pollset_provider_t *apr_pollset_provider_port = &impl;
  460 
  461 static apr_status_t impl_pollcb_cleanup(apr_pollcb_t *pollcb)
  462 {
  463     close(pollcb->fd);
  464     return APR_SUCCESS;
  465 }
  466 
  467 static apr_status_t impl_pollcb_create(apr_pollcb_t *pollcb,
  468                                        apr_uint32_t size,
  469                                        apr_pool_t *p,
  470                                        apr_uint32_t flags)
  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 
  503 static apr_status_t impl_pollcb_add(apr_pollcb_t *pollcb,
  504                                     apr_pollfd_t *descriptor)
  505 {
  506     int ret, fd;
  507 
  508     if (descriptor->desc_type == APR_POLL_SOCKET) {
  509         fd = descriptor->desc.s->socketdes;
  510     }
  511     else {
  512         fd = descriptor->desc.f->filedes;
  513     }
  514 
  515     ret = port_associate(pollcb->fd, PORT_SOURCE_FD, fd,
  516                          get_event(descriptor->reqevents), descriptor);
  517 
  518     if (ret == -1) {
  519         return apr_get_netos_error();
  520     }
  521 
  522     return APR_SUCCESS;
  523 }
  524 
  525 static apr_status_t impl_pollcb_remove(apr_pollcb_t *pollcb,
  526                                        apr_pollfd_t *descriptor)
  527 {
  528     int fd, ret;
  529 
  530     if (descriptor->desc_type == APR_POLL_SOCKET) {
  531         fd = descriptor->desc.s->socketdes;
  532     }
  533     else {
  534         fd = descriptor->desc.f->filedes;
  535     }
  536 
  537     ret = port_dissociate(pollcb->fd, PORT_SOURCE_FD, fd);
  538 
  539     if (ret < 0) {
  540         return APR_NOTFOUND;
  541     }
  542 
  543     return APR_SUCCESS;
  544 }
  545 
  546 static apr_status_t impl_pollcb_poll(apr_pollcb_t *pollcb,
  547                                      apr_interval_time_t timeout,
  548                                      apr_pollcb_cb_t func,
  549                                      void *baton)
  550 {
  551     apr_status_t rv;
  552     unsigned int nget = 1;
  553 
  554     rv = call_port_getn(pollcb->fd, pollcb->pollset.port, pollcb->nalloc,
  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 
  563             if ((pollcb->flags & APR_POLLSET_WAKEABLE) &&
  564                 pollfd->desc_type == APR_POLL_FILE &&
  565                 pollfd->desc.f == pollcb->wakeup_pipe[0]) {
  566                 apr_poll_drain_wakeup_pipe(pollcb->wakeup_pipe);
  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             }
  576             rv = apr_pollcb_add(pollcb, pollfd);
  577         }
  578     }
  579 
  580     return rv;
  581 }
  582 
  583 static const apr_pollcb_provider_t impl_cb = {
  584     impl_pollcb_create,
  585     impl_pollcb_add,
  586     impl_pollcb_remove,
  587     impl_pollcb_poll,
  588     impl_pollcb_cleanup,
  589     "port"
  590 };
  591 
  592 const apr_pollcb_provider_t *apr_pollcb_provider_port = &impl_cb;
  593 
  594 #endif /* HAVE_PORT_CREATE */