bug-gnulib
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: non-blocking I/O


From: Bastien ROUCARIES
Subject: Re: non-blocking I/O
Date: Tue, 29 Mar 2011 18:34:58 +0200

On Tue, Mar 29, 2011 at 5:16 PM, Bruno Haible <address@hidden> wrote:
> Paolo Bonzini wrote:
>> Without guessing what your bias is, I also :) prefer to implement
>> {g,s}et_nonblock_flag functions.  It would use either
>> SetNamedPipeHandleState or ioctlsocket (using the socket detection trick
>> in sockets.c to detect sockets, and then GetFileType to detect pipes if
>> it fails).
>
> Here's proposed code to that effect.  Note that the getter function cannot
> be implemented: How to determine whether a Woe32 socket is non-blocking?

according to crappy doc:
The WSAEventSelect function automatically sets a socket to nonblocking
mode. If WSAEventSelect has been issued on a socket, then any attempt
to use ioctlsocket to set the socket back to blocking mode will fail
with WSAEINVAL.

To set the socket back to blocking mode, an application must first
disable WSAEventSelect by calling WSAEventSelect with the
lNetworkEvents parameter equal to zero.

Using this trick will allow to ask the socket (but not thread safe :S)

Bastien

>
>
> ================================ nonblocking.h 
> ================================
> /* Non-blocking I/O for pipe or socket descriptors.
>   Copyright (C) 2011 Free Software Foundation, Inc.
>
>   This program is free software: you can redistribute it and/or modify
>   it under the terms of the GNU General Public License as published by
>   the Free Software Foundation; either version 3 of the License, or
>   (at your option) any later version.
>
>   This program is distributed in the hope that it will be useful,
>   but WITHOUT ANY WARRANTY; without even the implied warranty of
>   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>   GNU General Public License for more details.
>
>   You should have received a copy of the GNU General Public License
>   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
>
> #ifndef _NONBLOCKING_H
> #define _NONBLOCKING_H
>
> #include <stdbool.h>
>
> /* Non-blocking I/O is an I/O mode by which read(), write() calls avoid
>   blocking the current thread.  When non-blocking is enabled:
>   - A read() call returns -1 with errno set to EAGAIN when no data or EOF
>     information is immediately available.
>   - A write() call returns -1 with errno set to EAGAIN when it cannot
>     transport the requested amount of data (but at most one pipe buffer)
>     without blocking.
>
>   There are two modern alternatives to non-blocking I/O:
>     - use select() or poll() followed by read() or write() if the descriptor
>       is ready,
>     - call read() or write() in separate threads.  */
>
>
> #ifdef __cplusplus
> extern "C" {
> #endif
>
>
> #if 0 /* cannot be portably implemented */
> /* Return true if I/O to the descriptor DESC is currently non-blocking,
>   or false if it is blocking.  */
> extern bool get_nonblocking_flag (int desc);
> #endif
>
> /* Specify the non-blocking flag for the descriptor DESC.
>   Return 0 upon success, or -1 with errno set upon failure.
>   The default depends on the presence of the O_NONBLOCK flag for files
>   or pipes opened with open() or on the presence of the SOCK_NONBLOCK
>   flag for pipes.  */
> extern int set_nonblocking_flag (int desc, bool value);
>
>
> #ifdef __cplusplus
> }
> #endif
>
> #endif /* _NONBLOCKING_H */
> ================================ nonblocking.c 
> ================================
> /* Non-blocking I/O for pipe or socket descriptors.
>   Copyright (C) 2011 Free Software Foundation, Inc.
>
>   This program is free software: you can redistribute it and/or modify
>   it under the terms of the GNU General Public License as published by
>   the Free Software Foundation; either version 3 of the License, or
>   (at your option) any later version.
>
>   This program is distributed in the hope that it will be useful,
>   but WITHOUT ANY WARRANTY; without even the implied warranty of
>   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
>   GNU General Public License for more details.
>
>   You should have received a copy of the GNU General Public License
>   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
>
> #include <config.h>
>
> /* Specification.  */
> #include "nonblocking.h"
>
> #include <errno.h>
>
> #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
> /* Native Woe32 API.  */
>
> # if 0
> bool
> get_nonblocking_flag (int desc)
> {
>  HANDLE h = (HANDLE) _get_osfhandle (desc);
>  if (GetFileType (h) == FILE_TYPE_PIPE)
>    {
>      /* h is a pipe or socket.  */
>      DWORD state;
>      if (GetNamedPipeHandleState (h, &state, NULL, NULL, NULL, NULL, 0))
>        /* h is a pipe.  */
>        return (state & PIPE_NOWAIT) != 0;
>      else
>        /* h is a socket.  */
>        ?? How can this be implemented ??
>    }
>  else
>    return false;
> }
> # endif
>
> int
> set_nonblocking_flag (int desc, bool value)
> {
>  HANDLE h = (HANDLE) _get_osfhandle (desc);
>  if (GetFileType (h) == FILE_TYPE_PIPE)
>    {
>      /* h is a pipe or socket.  */
>      DWORD state;
>      if (GetNamedPipeHandleState (h, &state, NULL, NULL, NULL, NULL, 0))
>        {
>          /* h is a pipe.  */
>          if ((state & PIPE_NOWAIT) != 0)
>            {
>              if (value)
>                return 0;
>              state &= ~PIPE_NOWAIT;
>            }
>          else
>            {
>              if (!value)
>                return 0;
>              state |= PIPE_NOWAIT;
>            }
>          if (SetNamedPipeHandleState (h, &state, NULL, NULL))
>            return 0;
>          errno = EINVAL;
>          return -1;
>        }
>      else
>        {
>          /* h is a socket.  */
>          int v = value;
>          return ioctl ((SOCKET) h, FIONBIO, &v);
>        }
>    }
>  else
>    {
>      /* Win32 does not support non-blocking on regular files.  */
>      errno = ENOTSUP;
>      return -1;
>    }
> }
>
> #else
> /* Unix API.  */
>
> # include <fcntl.h>
>
> /* We don't need the gnulib replacement of fcntl() here.  */
> # undef fcntl
>
> # if 0
> bool
> get_nonblocking_flag (int desc)
> {
>  int fcntl_flags;
>
>  fcntl_flags = fcntl (desc, F_GETFL, 0);
>  if (fcntl_flags < 0)
>    return false;
>  return (fcntl_flags & O_NONBLOCK) != 0;
> }
> # endif
>
> int
> set_nonblocking_flag (int desc, bool value)
> {
>  int fcntl_flags;
>
>  fcntl_flags = fcntl (desc, F_GETFL, 0);
>  if (fcntl_flags < 0)
>    return -1;
>  if ((O_NONBLOCK & ~fcntl_flags) == 0)
>    return 0;
>  return fcntl (desc, F_SETFL, fcntl_flags | O_NONBLOCK);
> }
>
> #endif
> ===============================================================================
> --- lib/ioctl.c.orig    Tue Mar 29 17:15:16 2011
> +++ lib/ioctl.c Tue Mar 29 16:08:53 2011
> @@ -63,6 +63,10 @@
>   buf = va_arg (args, void *);
>   va_end (args);
>
> +  /* We don't support FIONBIO on pipes here.  If you want to make pipe fds
> +     non-blocking, use the gnulib 'nonblocking' module, until gnulib 
> implements
> +     fcntl F_GETFL / F_SETFL with O_NONBLOCK.  */
> +
>   sock = FD_TO_SOCKET (fd);
>   r = ioctlsocket (sock, req, buf);
>   if (r < 0)
>
> --
> In memoriam Rachel Levy <http://en.wikipedia.org/wiki/Rachel_Levy>
>
>



reply via email to

[Prev in Thread] Current Thread [Next in Thread]