(root)/
grep-3.11/
gnulib-tests/
select.c
       1  /* Emulation for select(2)
       2     Contributed by Paolo Bonzini.
       3  
       4     Copyright 2008-2023 Free Software Foundation, Inc.
       5  
       6     This file is part of gnulib.
       7  
       8     This file is free software: you can redistribute it and/or modify
       9     it under the terms of the GNU Lesser General Public License as
      10     published by the Free Software Foundation; either version 2.1 of the
      11     License, or (at your option) any later version.
      12  
      13     This file is distributed in the hope that it will be useful,
      14     but WITHOUT ANY WARRANTY; without even the implied warranty of
      15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16     GNU Lesser General Public License for more details.
      17  
      18     You should have received a copy of the GNU Lesser General Public License
      19     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      20  
      21  #include <config.h>
      22  
      23  /* Specification.  */
      24  #include <sys/select.h>
      25  
      26  #if defined _WIN32 && ! defined __CYGWIN__
      27  /* Native Windows.  */
      28  
      29  #include <alloca.h>
      30  #include <assert.h>
      31  #include <sys/types.h>
      32  #include <errno.h>
      33  #include <limits.h>
      34  
      35  #include <winsock2.h>
      36  #include <windows.h>
      37  #include <io.h>
      38  #include <stdio.h>
      39  #include <conio.h>
      40  #include <time.h>
      41  
      42  /* Get the overridden 'struct timeval'.  */
      43  #include <sys/time.h>
      44  
      45  #if GNULIB_MSVC_NOTHROW
      46  # include "msvc-nothrow.h"
      47  #else
      48  # include <io.h>
      49  #endif
      50  
      51  #undef select
      52  
      53  /* Don't assume that UNICODE is not defined.  */
      54  #undef GetModuleHandle
      55  #define GetModuleHandle GetModuleHandleA
      56  #undef PeekConsoleInput
      57  #define PeekConsoleInput PeekConsoleInputA
      58  #undef CreateEvent
      59  #define CreateEvent CreateEventA
      60  #undef PeekMessage
      61  #define PeekMessage PeekMessageA
      62  #undef DispatchMessage
      63  #define DispatchMessage DispatchMessageA
      64  
      65  /* Avoid warnings from gcc -Wcast-function-type.  */
      66  #define GetProcAddress \
      67    (void *) GetProcAddress
      68  
      69  struct bitset {
      70    unsigned char in[FD_SETSIZE / CHAR_BIT];
      71    unsigned char out[FD_SETSIZE / CHAR_BIT];
      72  };
      73  
      74  /* Declare data structures for ntdll functions.  */
      75  typedef struct _FILE_PIPE_LOCAL_INFORMATION {
      76    ULONG NamedPipeType;
      77    ULONG NamedPipeConfiguration;
      78    ULONG MaximumInstances;
      79    ULONG CurrentInstances;
      80    ULONG InboundQuota;
      81    ULONG ReadDataAvailable;
      82    ULONG OutboundQuota;
      83    ULONG WriteQuotaAvailable;
      84    ULONG NamedPipeState;
      85    ULONG NamedPipeEnd;
      86  } FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
      87  
      88  typedef struct _IO_STATUS_BLOCK
      89  {
      90    union {
      91      DWORD Status;
      92      PVOID Pointer;
      93    } u;
      94    ULONG_PTR Information;
      95  } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
      96  
      97  typedef enum _FILE_INFORMATION_CLASS {
      98    FilePipeLocalInformation = 24
      99  } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
     100  
     101  typedef DWORD (WINAPI *PNtQueryInformationFile)
     102           (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
     103  
     104  #ifndef PIPE_BUF
     105  #define PIPE_BUF        512
     106  #endif
     107  
     108  static BOOL IsConsoleHandle (HANDLE h)
     109  {
     110    DWORD mode;
     111    return GetConsoleMode (h, &mode) != 0;
     112  }
     113  
     114  static BOOL
     115  IsSocketHandle (HANDLE h)
     116  {
     117    WSANETWORKEVENTS ev;
     118  
     119    if (IsConsoleHandle (h))
     120      return FALSE;
     121  
     122    /* Under Wine, it seems that getsockopt returns 0 for pipes too.
     123       WSAEnumNetworkEvents instead distinguishes the two correctly.  */
     124    ev.lNetworkEvents = 0xDEADBEEF;
     125    WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
     126    return ev.lNetworkEvents != 0xDEADBEEF;
     127  }
     128  
     129  /* Compute output fd_sets for libc descriptor FD (whose Windows handle is
     130     H).  */
     131  
     132  static int
     133  windows_poll_handle (HANDLE h, int fd,
     134                       struct bitset *rbits,
     135                       struct bitset *wbits,
     136                       struct bitset *xbits)
     137  {
     138    BOOL read, write, except;
     139    int i, ret;
     140    INPUT_RECORD *irbuffer;
     141    DWORD avail, nbuffer;
     142    BOOL bRet;
     143    IO_STATUS_BLOCK iosb;
     144    FILE_PIPE_LOCAL_INFORMATION fpli;
     145    static PNtQueryInformationFile NtQueryInformationFile;
     146    static BOOL once_only;
     147  
     148    read = write = except = FALSE;
     149    switch (GetFileType (h))
     150      {
     151      case FILE_TYPE_DISK:
     152        read = TRUE;
     153        write = TRUE;
     154        break;
     155  
     156      case FILE_TYPE_PIPE:
     157        if (!once_only)
     158          {
     159            NtQueryInformationFile = (PNtQueryInformationFile)
     160              GetProcAddress (GetModuleHandle ("ntdll.dll"),
     161                              "NtQueryInformationFile");
     162            once_only = TRUE;
     163          }
     164  
     165        if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
     166          {
     167            if (avail)
     168              read = TRUE;
     169          }
     170        else if (GetLastError () == ERROR_BROKEN_PIPE)
     171          ;
     172  
     173        else
     174          {
     175            /* It was the write-end of the pipe.  Check if it is writable.
     176               If NtQueryInformationFile fails, optimistically assume the pipe is
     177               writable.  This could happen on Windows 9x, where
     178               NtQueryInformationFile is not available, or if we inherit a pipe
     179               that doesn't permit FILE_READ_ATTRIBUTES access on the write end
     180               (I think this should not happen since Windows XP SP2; WINE seems
     181               fine too).  Otherwise, ensure that enough space is available for
     182               atomic writes.  */
     183            memset (&iosb, 0, sizeof (iosb));
     184            memset (&fpli, 0, sizeof (fpli));
     185  
     186            if (!NtQueryInformationFile
     187                || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
     188                                           FilePipeLocalInformation)
     189                || fpli.WriteQuotaAvailable >= PIPE_BUF
     190                || (fpli.OutboundQuota < PIPE_BUF &&
     191                    fpli.WriteQuotaAvailable == fpli.OutboundQuota))
     192              write = TRUE;
     193          }
     194        break;
     195  
     196      case FILE_TYPE_CHAR:
     197        write = TRUE;
     198        if (!(rbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
     199          break;
     200  
     201        ret = WaitForSingleObject (h, 0);
     202        if (ret == WAIT_OBJECT_0)
     203          {
     204            if (!IsConsoleHandle (h))
     205              {
     206                read = TRUE;
     207                break;
     208              }
     209  
     210            nbuffer = avail = 0;
     211            bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
     212  
     213            /* Screen buffers handles are filtered earlier.  */
     214            assert (bRet);
     215            if (nbuffer == 0)
     216              {
     217                except = TRUE;
     218                break;
     219              }
     220  
     221            irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
     222            bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
     223            if (!bRet || avail == 0)
     224              {
     225                except = TRUE;
     226                break;
     227              }
     228  
     229            for (i = 0; i < avail; i++)
     230              if (irbuffer[i].EventType == KEY_EVENT)
     231                read = TRUE;
     232          }
     233        break;
     234  
     235      default:
     236        ret = WaitForSingleObject (h, 0);
     237        write = TRUE;
     238        if (ret == WAIT_OBJECT_0)
     239          read = TRUE;
     240  
     241        break;
     242      }
     243  
     244    ret = 0;
     245    if (read && (rbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
     246      {
     247        rbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
     248        ret++;
     249      }
     250  
     251    if (write && (wbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
     252      {
     253        wbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
     254        ret++;
     255      }
     256  
     257    if (except && (xbits->in[fd / CHAR_BIT] & (1 << (fd & (CHAR_BIT - 1)))))
     258      {
     259        xbits->out[fd / CHAR_BIT] |= (1 << (fd & (CHAR_BIT - 1)));
     260        ret++;
     261      }
     262  
     263    return ret;
     264  }
     265  
     266  int
     267  rpl_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
     268              struct timeval *timeout)
     269  #undef timeval
     270  {
     271    static struct timeval tv0;
     272    static HANDLE hEvent;
     273    HANDLE h, handle_array[FD_SETSIZE + 2];
     274    fd_set handle_rfds, handle_wfds, handle_xfds;
     275    struct bitset rbits, wbits, xbits;
     276    unsigned char anyfds_in[FD_SETSIZE / CHAR_BIT];
     277    DWORD ret, wait_timeout, nhandles, nsock, nbuffer;
     278    MSG msg;
     279    int i, fd, rc;
     280    clock_t tend;
     281  
     282    if (nfds < 0 || nfds > FD_SETSIZE)
     283      {
     284        errno = EINVAL;
     285        return -1;
     286      }
     287  
     288    if (!timeout)
     289      wait_timeout = INFINITE;
     290    else
     291      {
     292        wait_timeout = timeout->tv_sec * 1000 + timeout->tv_usec / 1000;
     293  
     294        /* select is also used as a portable usleep.  */
     295        if (!rfds && !wfds && !xfds)
     296          {
     297            Sleep (wait_timeout);
     298            return 0;
     299          }
     300      }
     301  
     302    if (!hEvent)
     303      hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
     304  
     305    handle_array[0] = hEvent;
     306    nhandles = 1;
     307    nsock = 0;
     308  
     309    /* Copy descriptors to bitsets.  At the same time, eliminate
     310       bits in the "wrong" direction for console input buffers
     311       and screen buffers, because screen buffers are waitable
     312       and they will block until a character is available.  */
     313    memset (&rbits, 0, sizeof (rbits));
     314    memset (&wbits, 0, sizeof (wbits));
     315    memset (&xbits, 0, sizeof (xbits));
     316    memset (anyfds_in, 0, sizeof (anyfds_in));
     317    if (rfds)
     318      for (i = 0; i < rfds->fd_count; i++)
     319        {
     320          fd = rfds->fd_array[i];
     321          h = (HANDLE) _get_osfhandle (fd);
     322          if (IsConsoleHandle (h)
     323              && !GetNumberOfConsoleInputEvents (h, &nbuffer))
     324            continue;
     325  
     326          rbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
     327          anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
     328        }
     329    else
     330      rfds = (fd_set *) alloca (sizeof (fd_set));
     331  
     332    if (wfds)
     333      for (i = 0; i < wfds->fd_count; i++)
     334        {
     335          fd = wfds->fd_array[i];
     336          h = (HANDLE) _get_osfhandle (fd);
     337          if (IsConsoleHandle (h)
     338              && GetNumberOfConsoleInputEvents (h, &nbuffer))
     339            continue;
     340  
     341          wbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
     342          anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
     343        }
     344    else
     345      wfds = (fd_set *) alloca (sizeof (fd_set));
     346  
     347    if (xfds)
     348      for (i = 0; i < xfds->fd_count; i++)
     349        {
     350          fd = xfds->fd_array[i];
     351          xbits.in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
     352          anyfds_in[fd / CHAR_BIT] |= 1 << (fd & (CHAR_BIT - 1));
     353        }
     354    else
     355      xfds = (fd_set *) alloca (sizeof (fd_set));
     356  
     357    /* Zero all the fd_sets, including the application's.  */
     358    FD_ZERO (rfds);
     359    FD_ZERO (wfds);
     360    FD_ZERO (xfds);
     361    FD_ZERO (&handle_rfds);
     362    FD_ZERO (&handle_wfds);
     363    FD_ZERO (&handle_xfds);
     364  
     365    /* Classify handles.  Create fd sets for sockets, poll the others. */
     366    for (i = 0; i < nfds; i++)
     367      {
     368        if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
     369          continue;
     370  
     371        h = (HANDLE) _get_osfhandle (i);
     372        if (!h)
     373          {
     374            errno = EBADF;
     375            return -1;
     376          }
     377  
     378        if (IsSocketHandle (h))
     379          {
     380            int requested = FD_CLOSE;
     381  
     382            /* See above; socket handles are mapped onto select, but we
     383               need to map descriptors to handles.  */
     384            if (rbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
     385              {
     386                requested |= FD_READ | FD_ACCEPT;
     387                FD_SET ((SOCKET) h, rfds);
     388                FD_SET ((SOCKET) h, &handle_rfds);
     389              }
     390            if (wbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
     391              {
     392                requested |= FD_WRITE | FD_CONNECT;
     393                FD_SET ((SOCKET) h, wfds);
     394                FD_SET ((SOCKET) h, &handle_wfds);
     395              }
     396            if (xbits.in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
     397              {
     398                requested |= FD_OOB;
     399                FD_SET ((SOCKET) h, xfds);
     400                FD_SET ((SOCKET) h, &handle_xfds);
     401              }
     402  
     403            WSAEventSelect ((SOCKET) h, hEvent, requested);
     404            nsock++;
     405          }
     406        else
     407          {
     408            handle_array[nhandles++] = h;
     409  
     410            /* Poll now.  If we get an event, do not wait below.  */
     411            if (wait_timeout != 0
     412                && windows_poll_handle (h, i, &rbits, &wbits, &xbits))
     413              wait_timeout = 0;
     414          }
     415      }
     416  
     417    /* Place a sentinel at the end of the array.  */
     418    handle_array[nhandles] = NULL;
     419  
     420    /* When will the waiting period expire?  */
     421    if (wait_timeout != INFINITE)
     422      tend = clock () + wait_timeout;
     423  
     424  restart:
     425    if (wait_timeout == 0 || nsock == 0)
     426      rc = 0;
     427    else
     428      {
     429        /* See if we need to wait in the loop below.  If any select is ready,
     430           do MsgWaitForMultipleObjects anyway to dispatch messages, but
     431           no need to call select again.  */
     432        rc = select (0, &handle_rfds, &handle_wfds, &handle_xfds, &tv0);
     433        if (rc == 0)
     434          {
     435            /* Restore the fd_sets for the other select we do below.  */
     436            memcpy (&handle_rfds, rfds, sizeof (fd_set));
     437            memcpy (&handle_wfds, wfds, sizeof (fd_set));
     438            memcpy (&handle_xfds, xfds, sizeof (fd_set));
     439          }
     440        else
     441          wait_timeout = 0;
     442      }
     443  
     444    /* How much is left to wait?  */
     445    if (wait_timeout != INFINITE)
     446      {
     447        clock_t tnow = clock ();
     448        if (tend >= tnow)
     449          wait_timeout = tend - tnow;
     450        else
     451          wait_timeout = 0;
     452      }
     453  
     454    for (;;)
     455      {
     456        ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
     457                                         wait_timeout, QS_ALLINPUT);
     458  
     459        if (ret == WAIT_OBJECT_0 + nhandles)
     460          {
     461            /* new input of some other kind */
     462            BOOL bRet;
     463            while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
     464              {
     465                TranslateMessage (&msg);
     466                DispatchMessage (&msg);
     467              }
     468          }
     469        else
     470          break;
     471      }
     472  
     473    /* If we haven't done it yet, check the status of the sockets.  */
     474    if (rc == 0 && nsock > 0)
     475      rc = select (0, &handle_rfds, &handle_wfds, &handle_xfds, &tv0);
     476  
     477    if (nhandles > 1)
     478      {
     479        /* Count results that are not counted in the return value of select.  */
     480        nhandles = 1;
     481        for (i = 0; i < nfds; i++)
     482          {
     483            if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
     484              continue;
     485  
     486            h = (HANDLE) _get_osfhandle (i);
     487            if (h == handle_array[nhandles])
     488              {
     489                /* Not a socket.  */
     490                nhandles++;
     491                windows_poll_handle (h, i, &rbits, &wbits, &xbits);
     492                if (rbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))
     493                    || wbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))
     494                    || xbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
     495                  rc++;
     496              }
     497          }
     498  
     499        if (rc == 0
     500            && (wait_timeout == INFINITE
     501                /* If NHANDLES > 1, but no bits are set, it means we've
     502                   been told incorrectly that some handle was signaled.
     503                   This happens with anonymous pipes, which always cause
     504                   MsgWaitForMultipleObjects to exit immediately, but no
     505                   data is found ready to be read by windows_poll_handle.
     506                   To avoid a total failure (whereby we return zero and
     507                   don't wait at all), let's poll in a more busy loop.  */
     508                || (wait_timeout != 0 && nhandles > 1)))
     509          {
     510            /* Sleep 1 millisecond to avoid busy wait and retry with the
     511               original fd_sets.  */
     512            memcpy (&handle_rfds, rfds, sizeof (fd_set));
     513            memcpy (&handle_wfds, wfds, sizeof (fd_set));
     514            memcpy (&handle_xfds, xfds, sizeof (fd_set));
     515            SleepEx (1, TRUE);
     516            goto restart;
     517          }
     518        if (timeout && wait_timeout == 0 && rc == 0)
     519          timeout->tv_sec = timeout->tv_usec = 0;
     520      }
     521  
     522    /* Now fill in the results.  */
     523    FD_ZERO (rfds);
     524    FD_ZERO (wfds);
     525    FD_ZERO (xfds);
     526    nhandles = 1;
     527    for (i = 0; i < nfds; i++)
     528      {
     529        if ((anyfds_in[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1)))) == 0)
     530          continue;
     531  
     532        h = (HANDLE) _get_osfhandle (i);
     533        if (h != handle_array[nhandles])
     534          {
     535            /* Perform handle->descriptor mapping.  */
     536            SOCKET s = (SOCKET) h;
     537            WSAEventSelect (s, NULL, 0);
     538            if (FD_ISSET (s, &handle_rfds))
     539              FD_SET (i, rfds);
     540            if (FD_ISSET (s, &handle_wfds))
     541              FD_SET (i, wfds);
     542            if (FD_ISSET (s, &handle_xfds))
     543              FD_SET (i, xfds);
     544          }
     545        else
     546          {
     547            /* Not a socket.  */
     548            nhandles++;
     549            if (rbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
     550              FD_SET (i, rfds);
     551            if (wbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
     552              FD_SET (i, wfds);
     553            if (xbits.out[i / CHAR_BIT] & (1 << (i & (CHAR_BIT - 1))))
     554              FD_SET (i, xfds);
     555          }
     556      }
     557  
     558    return rc;
     559  }
     560  
     561  #else /* ! Native Windows.  */
     562  
     563  #include <stddef.h> /* NULL */
     564  #include <errno.h>
     565  #include <unistd.h>
     566  
     567  #undef select
     568  
     569  int
     570  rpl_select (int nfds, fd_set *rfds, fd_set *wfds, fd_set *xfds,
     571              struct timeval *timeout)
     572  {
     573    int i;
     574  
     575    /* FreeBSD 8.2 has a bug: it does not always detect invalid fds.  */
     576    if (nfds < 0 || nfds > FD_SETSIZE)
     577      {
     578        errno = EINVAL;
     579        return -1;
     580      }
     581    for (i = 0; i < nfds; i++)
     582      {
     583        if (((rfds && FD_ISSET (i, rfds))
     584             || (wfds && FD_ISSET (i, wfds))
     585             || (xfds && FD_ISSET (i, xfds)))
     586            && dup2 (i, i) != i)
     587          return -1;
     588      }
     589  
     590    /* Interix 3.5 has a bug: it does not support nfds == 0.  */
     591    if (nfds == 0)
     592      {
     593        nfds = 1;
     594        rfds = NULL;
     595        wfds = NULL;
     596        xfds = NULL;
     597      }
     598    return select (nfds, rfds, wfds, xfds, timeout);
     599  }
     600  
     601  #endif