"Fossies" - the Fresh Open Source Software Archive

Member "libev-4.33/ev_select.c" (31 Oct 2019, 8853 Bytes) of package /linux/misc/libev-4.33.tar.gz:


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 "ev_select.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 4.27_vs_4.31.

    1 /*
    2  * libev select fd activity backend
    3  *
    4  * Copyright (c) 2007,2008,2009,2010,2011 Marc Alexander Lehmann <libev@schmorp.de>
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without modifica-
    8  * tion, are permitted provided that the following conditions are met:
    9  *
   10  *   1.  Redistributions of source code must retain the above copyright notice,
   11  *       this list of conditions and the following disclaimer.
   12  *
   13  *   2.  Redistributions in binary form must reproduce the above copyright
   14  *       notice, this list of conditions and the following disclaimer in the
   15  *       documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
   18  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MER-
   19  * CHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO
   20  * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPE-
   21  * CIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
   22  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
   23  * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
   24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTH-
   25  * ERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   26  * OF THE POSSIBILITY OF SUCH DAMAGE.
   27  *
   28  * Alternatively, the contents of this file may be used under the terms of
   29  * the GNU General Public License ("GPL") version 2 or any later version,
   30  * in which case the provisions of the GPL are applicable instead of
   31  * the above. If you wish to allow the use of your version of this file
   32  * only under the terms of the GPL and not to allow others to use your
   33  * version of this file under the BSD license, indicate your decision
   34  * by deleting the provisions above and replace them with the notice
   35  * and other provisions required by the GPL. If you do not delete the
   36  * provisions above, a recipient may use your version of this file under
   37  * either the BSD or the GPL.
   38  */
   39 
   40 #ifndef _WIN32
   41 /* for unix systems */
   42 # include <inttypes.h>
   43 # ifndef __hpux
   44 /* for REAL unix systems */
   45 #  include <sys/select.h>
   46 # endif
   47 #endif
   48 
   49 #ifndef EV_SELECT_USE_FD_SET
   50 # ifdef NFDBITS
   51 #  define EV_SELECT_USE_FD_SET 0
   52 # else
   53 #  define EV_SELECT_USE_FD_SET 1
   54 # endif
   55 #endif
   56 
   57 #if EV_SELECT_IS_WINSOCKET
   58 # undef EV_SELECT_USE_FD_SET
   59 # define EV_SELECT_USE_FD_SET 1
   60 # undef NFDBITS
   61 # define NFDBITS 0
   62 #endif
   63 
   64 #if !EV_SELECT_USE_FD_SET
   65 # define NFDBYTES (NFDBITS / 8)
   66 #endif
   67 
   68 #include <string.h>
   69 
   70 static void
   71 select_modify (EV_P_ int fd, int oev, int nev)
   72 {
   73   if (oev == nev)
   74     return;
   75 
   76   {
   77 #if EV_SELECT_USE_FD_SET
   78 
   79     #if EV_SELECT_IS_WINSOCKET
   80     SOCKET handle = anfds [fd].handle;
   81     #else
   82     int handle = fd;
   83     #endif
   84 
   85     assert (("libev: fd >= FD_SETSIZE passed to fd_set-based select backend", fd < FD_SETSIZE));
   86 
   87     /* FD_SET is broken on windows (it adds the fd to a set twice or more,
   88      * which eventually leads to overflows). Need to call it only on changes.
   89      */
   90     #if EV_SELECT_IS_WINSOCKET
   91     if ((oev ^ nev) & EV_READ)
   92     #endif
   93       if (nev & EV_READ)
   94         FD_SET (handle, (fd_set *)vec_ri);
   95       else
   96         FD_CLR (handle, (fd_set *)vec_ri);
   97 
   98     #if EV_SELECT_IS_WINSOCKET
   99     if ((oev ^ nev) & EV_WRITE)
  100     #endif
  101       if (nev & EV_WRITE)
  102         FD_SET (handle, (fd_set *)vec_wi);
  103       else
  104         FD_CLR (handle, (fd_set *)vec_wi);
  105 
  106 #else
  107 
  108     int     word = fd / NFDBITS;
  109     fd_mask mask = 1UL << (fd % NFDBITS);
  110 
  111     if (ecb_expect_false (vec_max <= word))
  112       {
  113         int new_max = word + 1;
  114 
  115         vec_ri = ev_realloc (vec_ri, new_max * NFDBYTES);
  116         vec_ro = ev_realloc (vec_ro, new_max * NFDBYTES); /* could free/malloc */
  117         vec_wi = ev_realloc (vec_wi, new_max * NFDBYTES);
  118         vec_wo = ev_realloc (vec_wo, new_max * NFDBYTES); /* could free/malloc */
  119         #ifdef _WIN32
  120         vec_eo = ev_realloc (vec_eo, new_max * NFDBYTES); /* could free/malloc */
  121         #endif
  122 
  123         for (; vec_max < new_max; ++vec_max)
  124           ((fd_mask *)vec_ri) [vec_max] =
  125           ((fd_mask *)vec_wi) [vec_max] = 0;
  126       }
  127 
  128     ((fd_mask *)vec_ri) [word] |= mask;
  129     if (!(nev & EV_READ))
  130       ((fd_mask *)vec_ri) [word] &= ~mask;
  131 
  132     ((fd_mask *)vec_wi) [word] |= mask;
  133     if (!(nev & EV_WRITE))
  134       ((fd_mask *)vec_wi) [word] &= ~mask;
  135 #endif
  136   }
  137 }
  138 
  139 static void
  140 select_poll (EV_P_ ev_tstamp timeout)
  141 {
  142   struct timeval tv;
  143   int res;
  144   int fd_setsize;
  145 
  146   EV_RELEASE_CB;
  147   EV_TV_SET (tv, timeout);
  148 
  149 #if EV_SELECT_USE_FD_SET
  150   fd_setsize = sizeof (fd_set);
  151 #else
  152   fd_setsize = vec_max * NFDBYTES;
  153 #endif
  154 
  155   memcpy (vec_ro, vec_ri, fd_setsize);
  156   memcpy (vec_wo, vec_wi, fd_setsize);
  157 
  158 #ifdef _WIN32
  159   /* pass in the write set as except set.
  160    * the idea behind this is to work around a windows bug that causes
  161    * errors to be reported as an exception and not by setting
  162    * the writable bit. this is so uncontrollably lame.
  163    */
  164   memcpy (vec_eo, vec_wi, fd_setsize);
  165   res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, (fd_set *)vec_eo, &tv);
  166 #elif EV_SELECT_USE_FD_SET
  167   fd_setsize = anfdmax < FD_SETSIZE ? anfdmax : FD_SETSIZE;
  168   res = select (fd_setsize, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv);
  169 #else
  170   res = select (vec_max * NFDBITS, (fd_set *)vec_ro, (fd_set *)vec_wo, 0, &tv);
  171 #endif
  172   EV_ACQUIRE_CB;
  173 
  174   if (ecb_expect_false (res < 0))
  175     {
  176       #if EV_SELECT_IS_WINSOCKET
  177       errno = WSAGetLastError ();
  178       #endif
  179       #ifdef WSABASEERR
  180       /* on windows, select returns incompatible error codes, fix this */
  181       if (errno >= WSABASEERR && errno < WSABASEERR + 1000)
  182         if (errno == WSAENOTSOCK)
  183           errno = EBADF;
  184         else
  185           errno -= WSABASEERR;
  186       #endif
  187 
  188       #ifdef _WIN32
  189       /* select on windows erroneously returns EINVAL when no fd sets have been
  190        * provided (this is documented). what microsoft doesn't tell you that this bug
  191        * exists even when the fd sets _are_ provided, so we have to check for this bug
  192        * here and emulate by sleeping manually.
  193        * we also get EINVAL when the timeout is invalid, but we ignore this case here
  194        * and assume that EINVAL always means: you have to wait manually.
  195        */
  196       if (errno == EINVAL)
  197         {
  198           if (timeout)
  199             {
  200               unsigned long ms = EV_TS_TO_MSEC (timeout);
  201               Sleep (ms ? ms : 1);
  202             }
  203 
  204           return;
  205         }
  206       #endif
  207 
  208       if (errno == EBADF)
  209         fd_ebadf (EV_A);
  210       else if (errno == ENOMEM && !syserr_cb)
  211         fd_enomem (EV_A);
  212       else if (errno != EINTR)
  213         ev_syserr ("(libev) select");
  214 
  215       return;
  216     }
  217 
  218 #if EV_SELECT_USE_FD_SET
  219 
  220   {
  221     int fd;
  222 
  223     for (fd = 0; fd < anfdmax; ++fd)
  224       if (anfds [fd].events)
  225         {
  226           int events = 0;
  227           #if EV_SELECT_IS_WINSOCKET
  228           SOCKET handle = anfds [fd].handle;
  229           #else
  230           int handle = fd;
  231           #endif
  232 
  233           if (FD_ISSET (handle, (fd_set *)vec_ro)) events |= EV_READ;
  234           if (FD_ISSET (handle, (fd_set *)vec_wo)) events |= EV_WRITE;
  235           #ifdef _WIN32
  236           if (FD_ISSET (handle, (fd_set *)vec_eo)) events |= EV_WRITE;
  237           #endif
  238 
  239           if (ecb_expect_true (events))
  240             fd_event (EV_A_ fd, events);
  241         }
  242   }
  243 
  244 #else
  245 
  246   {
  247     int word, bit;
  248     for (word = vec_max; word--; )
  249       {
  250         fd_mask word_r = ((fd_mask *)vec_ro) [word];
  251         fd_mask word_w = ((fd_mask *)vec_wo) [word];
  252         #ifdef _WIN32
  253         word_w |= ((fd_mask *)vec_eo) [word];
  254         #endif
  255 
  256         if (word_r || word_w)
  257           for (bit = NFDBITS; bit--; )
  258             {
  259               fd_mask mask = 1UL << bit;
  260               int events = 0;
  261 
  262               events |= word_r & mask ? EV_READ  : 0;
  263               events |= word_w & mask ? EV_WRITE : 0;
  264 
  265               if (ecb_expect_true (events))
  266                 fd_event (EV_A_ word * NFDBITS + bit, events);
  267             }
  268       }
  269   }
  270 
  271 #endif
  272 }
  273 
  274 inline_size
  275 int
  276 select_init (EV_P_ int flags)
  277 {
  278   backend_mintime = EV_TS_CONST (1e-6);
  279   backend_modify  = select_modify;
  280   backend_poll    = select_poll;
  281 
  282 #if EV_SELECT_USE_FD_SET
  283   vec_ri  = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_ri);
  284   vec_ro  = ev_malloc (sizeof (fd_set));
  285   vec_wi  = ev_malloc (sizeof (fd_set)); FD_ZERO ((fd_set *)vec_wi);
  286   vec_wo  = ev_malloc (sizeof (fd_set));
  287   #ifdef _WIN32
  288   vec_eo  = ev_malloc (sizeof (fd_set));
  289   #endif
  290 #else
  291   vec_max = 0;
  292   vec_ri  = 0;
  293   vec_ro  = 0;
  294   vec_wi  = 0;
  295   vec_wo  = 0;
  296   #ifdef _WIN32
  297   vec_eo  = 0;
  298   #endif
  299 #endif
  300 
  301   return EVBACKEND_SELECT;
  302 }
  303 
  304 inline_size
  305 void
  306 select_destroy (EV_P)
  307 {
  308   ev_free (vec_ri);
  309   ev_free (vec_ro);
  310   ev_free (vec_wi);
  311   ev_free (vec_wo);
  312   #ifdef _WIN32
  313   ev_free (vec_eo);
  314   #endif
  315 }
  316