From 836e0457064eb3b0b21bd2d4954cbc428a6b6277 Mon Sep 17 00:00:00 2001 From: Bruno Haible Date: Wed, 13 Apr 2011 12:15:43 +0200 Subject: [PATCH] Support non-blocking pipe I/O in write() on native Windows. * lib/unistd.in.h (write): Enable replacement also if GNULIB_UNISTD_H_NONBLOCKING is 1. * lib/write.c: Enable replacement also if GNULIB_NONBLOCKING. (rpl_write): When failing to write on a non-blocking pipe, change errno from ENOSPC to EAGAIN. * lib/stdio.in.h (fprintf, fputc, fputs, fwrite, printf, putc, putchar, puts, vfprintf, vprintf): Enable replacement also if GNULIB_STDIO_H_NONBLOCKING is 1. * lib/stdio-write.c: Enable replacements also if GNULIB_NONBLOCKING. (CLEAR_ERRNO, HANDLE_ENOSPC): New macros. (CLEAR_LastError, HANDLE_ERROR_NO_DATA): New macros, extracted from CALL_WITH_SIGPIPE_EMULATION. (CALL_WITH_SIGPIPE_EMULATION): Use them. * m4/nonblocking.m4: New file. * m4/write.m4 (gl_FUNC_WRITE): Enable REPLACE_WRITE also if required for non-blocking I/O support. * m4/unistd_h.m4 (gl_UNISTD_H_DEFAULTS): Initialize GNULIB_UNISTD_H_NONBLOCKING. * m4/stdio_h.m4 (gl_STDIO_H): Enable REPLACE_STDIO_WRITE_FUNCS also if required for non-blocking I/O support. (gl_STDIO_H_DEFAULTS): Initialize GNULIB_STDIO_H_NONBLOCKING. * modules/nonblocking (Files): Add m4/nonblocking.m4, lib/stdio-write.c, m4/asm-underscore.m4. (Depends-on): Add stdio, unistd. (configure.ac): Invoke gl_NONBLOCKING_IO. Define GNULIB_NONBLOCKING. Set GNULIB_STDIO_H_NONBLOCKING, GNULIB_UNISTD_H_NONBLOCKING. * modules/unistd (Makefile.am): Substitute GNULIB_UNISTD_H_NONBLOCKING. * modules/stdio (Makefile.am): Substitute GNULIB_STDIO_H_NONBLOCKING. * doc/posix-functions/fprintf.texi: Mention 'nonblocking' module and problem with non-blocking pipes. * doc/posix-functions/fputc.texi: Likewise. * doc/posix-functions/fputs.texi: Likewise. * doc/posix-functions/fwrite.texi: Likewise. * doc/posix-functions/printf.texi: Likewise. * doc/posix-functions/putc.texi: Likewise. * doc/posix-functions/putchar.texi: Likewise. * doc/posix-functions/puts.texi: Likewise. * doc/posix-functions/vfprintf.texi: Likewise. * doc/posix-functions/vprintf.texi: Likewise. * doc/posix-functions/write.texi: Likewise. --- ChangeLog | 44 ++++++++++++++++++++ doc/posix-functions/fprintf.texi | 11 ++++- doc/posix-functions/fputc.texi | 13 +++++- doc/posix-functions/fputs.texi | 13 +++++- doc/posix-functions/fwrite.texi | 13 +++++- doc/posix-functions/printf.texi | 11 ++++- doc/posix-functions/putc.texi | 13 +++++- doc/posix-functions/putchar.texi | 13 +++++- doc/posix-functions/puts.texi | 13 +++++- doc/posix-functions/vfprintf.texi | 11 ++++- doc/posix-functions/vprintf.texi | 11 ++++- doc/posix-functions/write.texi | 13 +++++- lib/stdio-write.c | 76 +++++++++++++++++++++++++++------- lib/stdio.in.h | 20 ++++----- lib/unistd.in.h | 2 +- lib/write.c | 40 +++++++++++++----- m4/nonblocking.m4 | 23 +++++++++++ m4/stdio_h.m4 | 13 +++++- m4/unistd_h.m4 | 85 ++++++++++++++++++++------------------- m4/write.m4 | 12 +++++- modules/nonblocking | 17 +++++++- modules/stdio | 1 + modules/unistd | 1 + 23 files changed, 370 insertions(+), 99 deletions(-) create mode 100644 m4/nonblocking.m4 diff --git a/ChangeLog b/ChangeLog index 365dd2f65..d01c6652c 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,47 @@ +2011-04-13 Bruno Haible + + Support non-blocking pipe I/O in write() on native Windows. + * lib/unistd.in.h (write): Enable replacement also if + GNULIB_UNISTD_H_NONBLOCKING is 1. + * lib/write.c: Enable replacement also if GNULIB_NONBLOCKING. + (rpl_write): When failing to write on a non-blocking pipe, change + errno from ENOSPC to EAGAIN. + * lib/stdio.in.h (fprintf, fputc, fputs, fwrite, printf, putc, + putchar, puts, vfprintf, vprintf): Enable replacement also if + GNULIB_STDIO_H_NONBLOCKING is 1. + * lib/stdio-write.c: Enable replacements also if GNULIB_NONBLOCKING. + (CLEAR_ERRNO, HANDLE_ENOSPC): New macros. + (CLEAR_LastError, HANDLE_ERROR_NO_DATA): New macros, extracted from + CALL_WITH_SIGPIPE_EMULATION. + (CALL_WITH_SIGPIPE_EMULATION): Use them. + * m4/nonblocking.m4: New file. + * m4/write.m4 (gl_FUNC_WRITE): Enable REPLACE_WRITE also if required + for non-blocking I/O support. + * m4/unistd_h.m4 (gl_UNISTD_H_DEFAULTS): Initialize + GNULIB_UNISTD_H_NONBLOCKING. + * m4/stdio_h.m4 (gl_STDIO_H): Enable REPLACE_STDIO_WRITE_FUNCS also if + required for non-blocking I/O support. + (gl_STDIO_H_DEFAULTS): Initialize GNULIB_STDIO_H_NONBLOCKING. + * modules/nonblocking (Files): Add m4/nonblocking.m4, + lib/stdio-write.c, m4/asm-underscore.m4. + (Depends-on): Add stdio, unistd. + (configure.ac): Invoke gl_NONBLOCKING_IO. Define GNULIB_NONBLOCKING. + Set GNULIB_STDIO_H_NONBLOCKING, GNULIB_UNISTD_H_NONBLOCKING. + * modules/unistd (Makefile.am): Substitute GNULIB_UNISTD_H_NONBLOCKING. + * modules/stdio (Makefile.am): Substitute GNULIB_STDIO_H_NONBLOCKING. + * doc/posix-functions/fprintf.texi: Mention 'nonblocking' module and + problem with non-blocking pipes. + * doc/posix-functions/fputc.texi: Likewise. + * doc/posix-functions/fputs.texi: Likewise. + * doc/posix-functions/fwrite.texi: Likewise. + * doc/posix-functions/printf.texi: Likewise. + * doc/posix-functions/putc.texi: Likewise. + * doc/posix-functions/putchar.texi: Likewise. + * doc/posix-functions/puts.texi: Likewise. + * doc/posix-functions/vfprintf.texi: Likewise. + * doc/posix-functions/vprintf.texi: Likewise. + * doc/posix-functions/write.texi: Likewise. + 2011-04-10 Jim Meyering maint.mk: prohibit doubled words diff --git a/doc/posix-functions/fprintf.texi b/doc/posix-functions/fprintf.texi index e922e85e0..04c4c72ca 100644 --- a/doc/posix-functions/fprintf.texi +++ b/doc/posix-functions/fprintf.texi @@ -4,7 +4,7 @@ POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/fprintf.html} -Gnulib module: fprintf-posix or stdio, sigpipe +Gnulib module: fprintf-posix or stdio, nonblocking, sigpipe Portability problems fixed by Gnulib module @code{fprintf-posix}: @itemize @@ -64,6 +64,15 @@ This function can crash in out-of-memory conditions on some platforms: MacOS X 10.3, FreeBSD 6.0, NetBSD 5.0. @end itemize +Portability problems fixed by Gnulib module @code{stdio} or @code{fprintf-posix}, together with module @code{nonblocking}: +@itemize +@item +When writing to a non-blocking pipe whose buffer is full, this function fails +with @code{errno} being set to @code{ENOSPC} instead of @code{EAGAIN} on some +platforms: +mingw. +@end itemize + Portability problems fixed by Gnulib module @code{stdio} or @code{fprintf-posix}, together with module @code{sigpipe}: @itemize @item diff --git a/doc/posix-functions/fputc.texi b/doc/posix-functions/fputc.texi index 2f09a8a98..9d6c9fd29 100644 --- a/doc/posix-functions/fputc.texi +++ b/doc/posix-functions/fputc.texi @@ -4,9 +4,18 @@ POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/fputc.html} -Gnulib module: stdio, sigpipe +Gnulib module: stdio, nonblocking, sigpipe -Portability problems fixed by Gnulib: +Portability problems fixed by Gnulib module @code{stdio}, together with module @code{nonblocking}: +@itemize +@item +When writing to a non-blocking pipe whose buffer is full, this function fails +with @code{errno} being set to @code{ENOSPC} instead of @code{EAGAIN} on some +platforms: +mingw. +@end itemize + +Portability problems fixed by Gnulib module @code{stdio}, together with module @code{sigpipe}: @itemize @item When writing to a pipe with no readers, this function fails, instead of diff --git a/doc/posix-functions/fputs.texi b/doc/posix-functions/fputs.texi index d2c46ef8b..7fc4bf531 100644 --- a/doc/posix-functions/fputs.texi +++ b/doc/posix-functions/fputs.texi @@ -4,9 +4,18 @@ POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/fputs.html} -Gnulib module: stdio, sigpipe +Gnulib module: stdio, nonblocking, sigpipe -Portability problems fixed by Gnulib: +Portability problems fixed by Gnulib module @code{stdio}, together with module @code{nonblocking}: +@itemize +@item +When writing to a non-blocking pipe whose buffer is full, this function fails +with @code{errno} being set to @code{ENOSPC} instead of @code{EAGAIN} on some +platforms: +mingw. +@end itemize + +Portability problems fixed by Gnulib module @code{stdio}, together with module @code{sigpipe}: @itemize @item When writing to a pipe with no readers, this function fails, instead of diff --git a/doc/posix-functions/fwrite.texi b/doc/posix-functions/fwrite.texi index d9defec9c..20f7fb810 100644 --- a/doc/posix-functions/fwrite.texi +++ b/doc/posix-functions/fwrite.texi @@ -4,9 +4,18 @@ POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/fwrite.html} -Gnulib module: stdio, sigpipe +Gnulib module: stdio, nonblocking, sigpipe -Portability problems fixed by Gnulib: +Portability problems fixed by Gnulib module @code{stdio}, together with module @code{nonblocking}: +@itemize +@item +When writing to a non-blocking pipe whose buffer is full, this function fails +with @code{errno} being set to @code{ENOSPC} instead of @code{EAGAIN} on some +platforms: +mingw. +@end itemize + +Portability problems fixed by Gnulib module @code{stdio}, together with module @code{sigpipe}: @itemize @item When writing to a pipe with no readers, this function fails, instead of diff --git a/doc/posix-functions/printf.texi b/doc/posix-functions/printf.texi index eaee96a75..df7813f6a 100644 --- a/doc/posix-functions/printf.texi +++ b/doc/posix-functions/printf.texi @@ -4,7 +4,7 @@ POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/printf.html} -Gnulib module: printf-posix or stdio, sigpipe +Gnulib module: printf-posix or stdio, nonblocking, sigpipe Portability problems fixed by Gnulib module @code{printf-posix}: @itemize @@ -64,6 +64,15 @@ This function can crash in out-of-memory conditions on some platforms: MacOS X 10.3, FreeBSD 6.0, NetBSD 5.0. @end itemize +Portability problems fixed by Gnulib module @code{stdio} or @code{printf-posix}, together with module @code{nonblocking}: +@itemize +@item +When writing to a non-blocking pipe whose buffer is full, this function fails +with @code{errno} being set to @code{ENOSPC} instead of @code{EAGAIN} on some +platforms: +mingw. +@end itemize + Portability problems fixed by Gnulib module @code{stdio} or @code{printf-posix}, together with module @code{sigpipe}: @itemize @item diff --git a/doc/posix-functions/putc.texi b/doc/posix-functions/putc.texi index b7011a01b..d156461ac 100644 --- a/doc/posix-functions/putc.texi +++ b/doc/posix-functions/putc.texi @@ -4,9 +4,18 @@ POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/putc.html} -Gnulib module: stdio, sigpipe +Gnulib module: stdio, nonblocking, sigpipe -Portability problems fixed by Gnulib: +Portability problems fixed by Gnulib module @code{stdio}, together with module @code{nonblocking}: +@itemize +@item +When writing to a non-blocking pipe whose buffer is full, this function fails +with @code{errno} being set to @code{ENOSPC} instead of @code{EAGAIN} on some +platforms: +mingw. +@end itemize + +Portability problems fixed by Gnulib module @code{stdio}, together with module @code{sigpipe}: @itemize @item When writing to a pipe with no readers, this function fails, instead of diff --git a/doc/posix-functions/putchar.texi b/doc/posix-functions/putchar.texi index d89ab7189..aeb6b4307 100644 --- a/doc/posix-functions/putchar.texi +++ b/doc/posix-functions/putchar.texi @@ -4,9 +4,18 @@ POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/putchar.html} -Gnulib module: stdio, sigpipe +Gnulib module: stdio, nonblocking, sigpipe -Portability problems fixed by Gnulib: +Portability problems fixed by Gnulib module @code{stdio}, together with module @code{nonblocking}: +@itemize +@item +When writing to a non-blocking pipe whose buffer is full, this function fails +with @code{errno} being set to @code{ENOSPC} instead of @code{EAGAIN} on some +platforms: +mingw. +@end itemize + +Portability problems fixed by Gnulib module @code{stdio}, together with module @code{sigpipe}: @itemize @item When writing to a pipe with no readers, this function fails, instead of diff --git a/doc/posix-functions/puts.texi b/doc/posix-functions/puts.texi index 69ee72e3d..ef350ac1b 100644 --- a/doc/posix-functions/puts.texi +++ b/doc/posix-functions/puts.texi @@ -4,9 +4,18 @@ POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/puts.html} -Gnulib module: stdio, sigpipe +Gnulib module: stdio, nonblocking, sigpipe -Portability problems fixed by Gnulib: +Portability problems fixed by Gnulib module @code{stdio}, together with module @code{nonblocking}: +@itemize +@item +When writing to a non-blocking pipe whose buffer is full, this function fails +with @code{errno} being set to @code{ENOSPC} instead of @code{EAGAIN} on some +platforms: +mingw. +@end itemize + +Portability problems fixed by Gnulib module @code{stdio}, together with module @code{sigpipe}: @itemize @item When writing to a pipe with no readers, this function fails, instead of diff --git a/doc/posix-functions/vfprintf.texi b/doc/posix-functions/vfprintf.texi index 7e502347d..b40a33416 100644 --- a/doc/posix-functions/vfprintf.texi +++ b/doc/posix-functions/vfprintf.texi @@ -4,7 +4,7 @@ POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/vfprintf.html} -Gnulib module: vfprintf-posix or stdio, sigpipe +Gnulib module: vfprintf-posix or stdio, nonblocking, sigpipe Portability problems fixed by Gnulib module @code{vfprintf-posix}: @itemize @@ -64,6 +64,15 @@ This function can crash in out-of-memory conditions on some platforms: MacOS X 10.3, FreeBSD 6.0, NetBSD 5.0. @end itemize +Portability problems fixed by Gnulib module @code{stdio} or @code{vfprintf-posix}, together with module @code{nonblocking}: +@itemize +@item +When writing to a non-blocking pipe whose buffer is full, this function fails +with @code{errno} being set to @code{ENOSPC} instead of @code{EAGAIN} on some +platforms: +mingw. +@end itemize + Portability problems fixed by Gnulib module @code{stdio} or @code{vfprintf-posix}, together with module @code{sigpipe}: @itemize @item diff --git a/doc/posix-functions/vprintf.texi b/doc/posix-functions/vprintf.texi index 526070e22..342d182c6 100644 --- a/doc/posix-functions/vprintf.texi +++ b/doc/posix-functions/vprintf.texi @@ -4,7 +4,7 @@ POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/vprintf.html} -Gnulib module: vprintf-posix or stdio, sigpipe +Gnulib module: vprintf-posix or stdio, nonblocking, sigpipe Portability problems fixed by Gnulib module @code{vprintf-posix}: @itemize @@ -64,6 +64,15 @@ This function can crash in out-of-memory conditions on some platforms: MacOS X 10.3, FreeBSD 6.0, NetBSD 5.0. @end itemize +Portability problems fixed by Gnulib module @code{stdio} or @code{vprintf-posix}, together with module @code{nonblocking}: +@itemize +@item +When writing to a non-blocking pipe whose buffer is full, this function fails +with @code{errno} being set to @code{ENOSPC} instead of @code{EAGAIN} on some +platforms: +mingw. +@end itemize + Portability problems fixed by Gnulib module @code{stdio} or @code{vprintf-posix}, together with module @code{sigpipe}: @itemize @item diff --git a/doc/posix-functions/write.texi b/doc/posix-functions/write.texi index 826151c9e..7587fbb9d 100644 --- a/doc/posix-functions/write.texi +++ b/doc/posix-functions/write.texi @@ -4,9 +4,18 @@ POSIX specification:@* @url{http://www.opengroup.org/onlinepubs/9699919799/functions/write.html} -Gnulib module: write, sigpipe +Gnulib module: write, nonblocking, sigpipe -Portability problems fixed by Gnulib: +Portability problems fixed by Gnulib module @code{stdio}, together with module @code{nonblocking}: +@itemize +@item +When writing to a non-blocking pipe whose buffer is full, this function fails +with @code{errno} being set to @code{ENOSPC} instead of @code{EAGAIN} on some +platforms: +mingw. +@end itemize + +Portability problems fixed by Gnulib module @code{stdio}, together with module @code{sigpipe}: @itemize @item When writing to a pipe with no readers, this function fails with error diff --git a/lib/stdio-write.c b/lib/stdio-write.c index 10fcfba9e..a586c3512 100644 --- a/lib/stdio-write.c +++ b/lib/stdio-write.c @@ -20,8 +20,9 @@ /* Specification. */ #include -/* Replace these functions only if module 'sigpipe' is requested. */ -#if GNULIB_SIGPIPE +/* Replace these functions only if module 'nonblocking' or module 'sigpipe' is + requested. */ +#if GNULIB_NONBLOCKING || GNULIB_SIGPIPE /* On native Windows platforms, SIGPIPE does not exist. When write() is called on a pipe with no readers, WriteFile() fails with error @@ -38,26 +39,73 @@ # define WIN32_LEAN_AND_MEAN /* avoid including junk */ # include +# if GNULIB_NONBLOCKING +# define CLEAR_ERRNO \ + errno = 0; +# define HANDLE_ENOSPC \ + if (errno == ENOSPC && ferror (stream)) \ + { \ + int fd = fileno (stream); \ + if (fd >= 0) \ + { \ + HANDLE h = (HANDLE) _get_osfhandle (fd); \ + if (GetFileType (h) == FILE_TYPE_PIPE) \ + { \ + /* h is a pipe or socket. */ \ + DWORD state; \ + if (GetNamedPipeHandleState (h, &state, NULL, NULL, \ + NULL, NULL, 0) \ + && (state & PIPE_NOWAIT) != 0) \ + /* h is a pipe in non-blocking mode. \ + Change errno from ENOSPC to EAGAIN. */ \ + errno = EAGAIN; \ + } \ + } \ + } \ + else +# else +# define CLEAR_ERRNO +# define HANDLE_ENOSPC +# endif + +# if GNULIB_SIGPIPE +# define CLEAR_LastError \ + SetLastError (0); +# define HANDLE_ERROR_NO_DATA \ + if (GetLastError () == ERROR_NO_DATA && ferror (stream)) \ + { \ + int fd = fileno (stream); \ + if (fd >= 0 \ + && GetFileType ((HANDLE) _get_osfhandle (fd)) \ + == FILE_TYPE_PIPE) \ + { \ + /* Try to raise signal SIGPIPE. */ \ + raise (SIGPIPE); \ + /* If it is currently blocked or ignored, change errno from \ + EINVAL to EPIPE. */ \ + errno = EPIPE; \ + } \ + } \ + else +# else +# define CLEAR_LastError +# define HANDLE_ERROR_NO_DATA +# endif + # define CALL_WITH_SIGPIPE_EMULATION(RETTYPE, EXPRESSION, FAILED) \ if (ferror (stream)) \ return (EXPRESSION); \ else \ { \ RETTYPE ret; \ - SetLastError (0); \ + CLEAR_ERRNO \ + CLEAR_LastError \ ret = (EXPRESSION); \ - if (FAILED && GetLastError () == ERROR_NO_DATA && ferror (stream)) \ + if (FAILED) \ { \ - int fd = fileno (stream); \ - if (fd >= 0 \ - && GetFileType ((HANDLE) _get_osfhandle (fd)) == FILE_TYPE_PIPE)\ - { \ - /* Try to raise signal SIGPIPE. */ \ - raise (SIGPIPE); \ - /* If it is currently blocked or ignored, change errno from \ - EINVAL to EPIPE. */ \ - errno = EPIPE; \ - } \ + HANDLE_ENOSPC \ + HANDLE_ERROR_NO_DATA \ + ; \ } \ return ret; \ } diff --git a/lib/stdio.in.h b/lib/stdio.in.h index f12d3be8e..c209d6f90 100644 --- a/lib/stdio.in.h +++ b/lib/stdio.in.h @@ -203,7 +203,7 @@ _GL_WARN_ON_USE (fopen, "fopen on Win32 platforms is not POSIX compatible - " #if @GNULIB_FPRINTF_POSIX@ || @GNULIB_FPRINTF@ # if (@GNULIB_FPRINTF_POSIX@ && @REPLACE_FPRINTF@) \ - || (@GNULIB_FPRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && @GNULIB_STDIO_H_SIGPIPE@) + || (@GNULIB_FPRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@)) # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # define fprintf rpl_fprintf # endif @@ -262,7 +262,7 @@ _GL_WARN_ON_USE (fpurge, "fpurge is not always present - " #endif #if @GNULIB_FPUTC@ -# if @REPLACE_STDIO_WRITE_FUNCS@ && @GNULIB_STDIO_H_SIGPIPE@ +# if @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@) # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # undef fputc # define fputc rpl_fputc @@ -276,7 +276,7 @@ _GL_CXXALIASWARN (fputc); #endif #if @GNULIB_FPUTS@ -# if @REPLACE_STDIO_WRITE_FUNCS@ && @GNULIB_STDIO_H_SIGPIPE@ +# if @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@) # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # undef fputs # define fputs rpl_fputs @@ -506,7 +506,7 @@ _GL_WARN_ON_USE (ftell, "ftell cannot handle files larger than 4 GB " #if @GNULIB_FWRITE@ -# if @REPLACE_STDIO_WRITE_FUNCS@ && @GNULIB_STDIO_H_SIGPIPE@ +# if @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@) # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # undef fwrite # define fwrite rpl_fwrite @@ -711,7 +711,7 @@ _GL_WARN_ON_USE (popen, "popen is buggy on some platforms - " #if @GNULIB_PRINTF_POSIX@ || @GNULIB_PRINTF@ # if (@GNULIB_PRINTF_POSIX@ && @REPLACE_PRINTF@) \ - || (@GNULIB_PRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && @GNULIB_STDIO_H_SIGPIPE@) + || (@GNULIB_PRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@)) # if defined __GNUC__ # if !(defined __cplusplus && defined GNULIB_NAMESPACE) /* Don't break __attribute__((format(printf,M,N))). */ @@ -760,7 +760,7 @@ _GL_WARN_ON_USE (printf, "printf is not always POSIX compliant - " #endif #if @GNULIB_PUTC@ -# if @REPLACE_STDIO_WRITE_FUNCS@ && @GNULIB_STDIO_H_SIGPIPE@ +# if @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@) # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # undef putc # define putc rpl_fputc @@ -774,7 +774,7 @@ _GL_CXXALIASWARN (putc); #endif #if @GNULIB_PUTCHAR@ -# if @REPLACE_STDIO_WRITE_FUNCS@ && @GNULIB_STDIO_H_SIGPIPE@ +# if @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@) # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # undef putchar # define putchar rpl_putchar @@ -788,7 +788,7 @@ _GL_CXXALIASWARN (putchar); #endif #if @GNULIB_PUTS@ -# if @REPLACE_STDIO_WRITE_FUNCS@ && @GNULIB_STDIO_H_SIGPIPE@ +# if @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@) # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # undef puts # define puts rpl_puts @@ -1031,7 +1031,7 @@ _GL_WARN_ON_USE (vdprintf, "vdprintf is unportable - " #if @GNULIB_VFPRINTF_POSIX@ || @GNULIB_VFPRINTF@ # if (@GNULIB_VFPRINTF_POSIX@ && @REPLACE_VFPRINTF@) \ - || (@GNULIB_VFPRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && @GNULIB_STDIO_H_SIGPIPE@) + || (@GNULIB_VFPRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@)) # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # define vfprintf rpl_vfprintf # endif @@ -1067,7 +1067,7 @@ _GL_WARN_ON_USE (vfprintf, "vfprintf is not always POSIX compliant - " #if @GNULIB_VPRINTF_POSIX@ || @GNULIB_VPRINTF@ # if (@GNULIB_VPRINTF_POSIX@ && @REPLACE_VPRINTF@) \ - || (@GNULIB_VPRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && @GNULIB_STDIO_H_SIGPIPE@) + || (@GNULIB_VPRINTF@ && @REPLACE_STDIO_WRITE_FUNCS@ && (@GNULIB_STDIO_H_NONBLOCKING@ || @GNULIB_STDIO_H_SIGPIPE@)) # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # define vprintf rpl_vprintf # endif diff --git a/lib/unistd.in.h b/lib/unistd.in.h index 156e864f3..10245c42e 100644 --- a/lib/unistd.in.h +++ b/lib/unistd.in.h @@ -1359,7 +1359,7 @@ _GL_WARN_ON_USE (usleep, "usleep is unportable - " /* Write up to COUNT bytes starting at BUF to file descriptor FD. See the POSIX:2001 specification . */ -# if @REPLACE_WRITE@ && @GNULIB_UNISTD_H_SIGPIPE@ +# if @REPLACE_WRITE@ && (@GNULIB_UNISTD_H_NONBLOCKING@ || @GNULIB_UNISTD_H_SIGPIPE@) # if !(defined __cplusplus && defined GNULIB_NAMESPACE) # undef write # define write rpl_write diff --git a/lib/write.c b/lib/write.c index 4cf296255..4b40cd31d 100644 --- a/lib/write.c +++ b/lib/write.c @@ -20,8 +20,9 @@ /* Specification. */ #include -/* Replace this function only if module 'sigpipe' is requested. */ -#if GNULIB_SIGPIPE +/* Replace this function only if module 'nonblocking' or module 'sigpipe' is + requested. */ +#if GNULIB_NONBLOCKING || GNULIB_SIGPIPE /* On native Windows platforms, SIGPIPE does not exist. When write() is called on a pipe with no readers, WriteFile() fails with error @@ -45,14 +46,35 @@ rpl_write (int fd, const void *buf, size_t count) if (ret < 0) { - if (GetLastError () == ERROR_NO_DATA - && GetFileType ((HANDLE) _get_osfhandle (fd)) == FILE_TYPE_PIPE) +# if GNULIB_NONBLOCKING + if (errno == ENOSPC) { - /* Try to raise signal SIGPIPE. */ - raise (SIGPIPE); - /* If it is currently blocked or ignored, change errno from EINVAL - to EPIPE. */ - errno = EPIPE; + HANDLE h = (HANDLE) _get_osfhandle (fd); + if (GetFileType (h) == FILE_TYPE_PIPE) + { + /* h is a pipe or socket. */ + DWORD state; + if (GetNamedPipeHandleState (h, &state, NULL, NULL, NULL, NULL, 0) + && (state & PIPE_NOWAIT) != 0) + /* h is a pipe in non-blocking mode. + Change errno from ENOSPC to EAGAIN. */ + errno = EAGAIN; + } + } + else +# endif + { +# if GNULIB_SIGPIPE + if (GetLastError () == ERROR_NO_DATA + && GetFileType ((HANDLE) _get_osfhandle (fd)) == FILE_TYPE_PIPE) + { + /* Try to raise signal SIGPIPE. */ + raise (SIGPIPE); + /* If it is currently blocked or ignored, change errno from + EINVAL to EPIPE. */ + errno = EPIPE; + } +# endif } } return ret; diff --git a/m4/nonblocking.m4 b/m4/nonblocking.m4 new file mode 100644 index 000000000..8224626be --- /dev/null +++ b/m4/nonblocking.m4 @@ -0,0 +1,23 @@ +# nonblocking.m4 serial 1 +dnl Copyright (C) 2011 Free Software Foundation, Inc. +dnl This file is free software; the Free Software Foundation +dnl gives unlimited permission to copy and/or distribute it, +dnl with or without modifications, as long as this notice is preserved. + +dnl Tests whether non-blocking I/O is natively supported by read(), write(). +dnl Sets gl_cv_have_nonblocking. +AC_DEFUN([gl_NONBLOCKING_IO], +[ + dnl Use AC_REQUIRE here, so that the default behavior below is expanded + dnl once only, before all statements that occur in other macros. + AC_REQUIRE([gl_NONBLOCKING_IO_BODY]) +]) + +AC_DEFUN([gl_NONBLOCKING_IO_BODY], +[ + AC_REQUIRE([AC_CANONICAL_HOST]) + case "$host_os" in + mingw*) gl_cv_have_nonblocking=no ;; + *) gl_cv_have_nonblocking=yes ;; + esac +]) diff --git a/m4/stdio_h.m4 b/m4/stdio_h.m4 index 7f3ae5629..a513689ab 100644 --- a/m4/stdio_h.m4 +++ b/m4/stdio_h.m4 @@ -1,4 +1,4 @@ -# stdio_h.m4 serial 33 +# stdio_h.m4 serial 34 dnl Copyright (C) 2007-2011 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -28,9 +28,17 @@ AC_DEFUN([gl_STDIO_H], gl_SIGNAL_SIGPIPE if test $gl_cv_header_signal_h_SIGPIPE != yes; then REPLACE_STDIO_WRITE_FUNCS=1 - AC_LIBOBJ([stdio-write]) fi ]) + m4_ifdef([gl_NONBLOCKING_IO], [ + gl_NONBLOCKING_IO + if test $gl_cv_have_nonblocking != yes; then + REPLACE_STDIO_WRITE_FUNCS=1 + fi + ]) + if test $REPLACE_STDIO_WRITE_FUNCS = 1; then + AC_LIBOBJ([stdio-write]) + fi dnl Check for declarations of anything we want to poison if the dnl corresponding gnulib module is not in use, and which is not @@ -82,6 +90,7 @@ AC_DEFUN([gl_STDIO_H_DEFAULTS], GNULIB_RENAMEAT=0; AC_SUBST([GNULIB_RENAMEAT]) GNULIB_SNPRINTF=0; AC_SUBST([GNULIB_SNPRINTF]) GNULIB_SPRINTF_POSIX=0; AC_SUBST([GNULIB_SPRINTF_POSIX]) + GNULIB_STDIO_H_NONBLOCKING=0; AC_SUBST([GNULIB_STDIO_H_NONBLOCKING]) GNULIB_STDIO_H_SIGPIPE=0; AC_SUBST([GNULIB_STDIO_H_SIGPIPE]) GNULIB_TMPFILE=0; AC_SUBST([GNULIB_TMPFILE]) GNULIB_VASPRINTF=0; AC_SUBST([GNULIB_VASPRINTF]) diff --git a/m4/unistd_h.m4 b/m4/unistd_h.m4 index c81a1138e..90feccbb4 100644 --- a/m4/unistd_h.m4 +++ b/m4/unistd_h.m4 @@ -1,4 +1,4 @@ -# unistd_h.m4 serial 53 +# unistd_h.m4 serial 54 dnl Copyright (C) 2006-2011 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -52,47 +52,48 @@ AC_DEFUN([gl_UNISTD_MODULE_INDICATOR], AC_DEFUN([gl_UNISTD_H_DEFAULTS], [ - GNULIB_CHOWN=0; AC_SUBST([GNULIB_CHOWN]) - GNULIB_CLOSE=0; AC_SUBST([GNULIB_CLOSE]) - GNULIB_DUP2=0; AC_SUBST([GNULIB_DUP2]) - GNULIB_DUP3=0; AC_SUBST([GNULIB_DUP3]) - GNULIB_ENVIRON=0; AC_SUBST([GNULIB_ENVIRON]) - GNULIB_EUIDACCESS=0; AC_SUBST([GNULIB_EUIDACCESS]) - GNULIB_FACCESSAT=0; AC_SUBST([GNULIB_FACCESSAT]) - GNULIB_FCHDIR=0; AC_SUBST([GNULIB_FCHDIR]) - GNULIB_FCHOWNAT=0; AC_SUBST([GNULIB_FCHOWNAT]) - GNULIB_FSYNC=0; AC_SUBST([GNULIB_FSYNC]) - GNULIB_FTRUNCATE=0; AC_SUBST([GNULIB_FTRUNCATE]) - GNULIB_GETCWD=0; AC_SUBST([GNULIB_GETCWD]) - GNULIB_GETDOMAINNAME=0; AC_SUBST([GNULIB_GETDOMAINNAME]) - GNULIB_GETDTABLESIZE=0; AC_SUBST([GNULIB_GETDTABLESIZE]) - GNULIB_GETGROUPS=0; AC_SUBST([GNULIB_GETGROUPS]) - GNULIB_GETHOSTNAME=0; AC_SUBST([GNULIB_GETHOSTNAME]) - GNULIB_GETLOGIN=0; AC_SUBST([GNULIB_GETLOGIN]) - GNULIB_GETLOGIN_R=0; AC_SUBST([GNULIB_GETLOGIN_R]) - GNULIB_GETPAGESIZE=0; AC_SUBST([GNULIB_GETPAGESIZE]) - GNULIB_GETUSERSHELL=0; AC_SUBST([GNULIB_GETUSERSHELL]) - GNULIB_LCHOWN=0; AC_SUBST([GNULIB_LCHOWN]) - GNULIB_LINK=0; AC_SUBST([GNULIB_LINK]) - GNULIB_LINKAT=0; AC_SUBST([GNULIB_LINKAT]) - GNULIB_LSEEK=0; AC_SUBST([GNULIB_LSEEK]) - GNULIB_PIPE=0; AC_SUBST([GNULIB_PIPE]) - GNULIB_PIPE2=0; AC_SUBST([GNULIB_PIPE2]) - GNULIB_PREAD=0; AC_SUBST([GNULIB_PREAD]) - GNULIB_PWRITE=0; AC_SUBST([GNULIB_PWRITE]) - GNULIB_READLINK=0; AC_SUBST([GNULIB_READLINK]) - GNULIB_READLINKAT=0; AC_SUBST([GNULIB_READLINKAT]) - GNULIB_RMDIR=0; AC_SUBST([GNULIB_RMDIR]) - GNULIB_SLEEP=0; AC_SUBST([GNULIB_SLEEP]) - GNULIB_SYMLINK=0; AC_SUBST([GNULIB_SYMLINK]) - GNULIB_SYMLINKAT=0; AC_SUBST([GNULIB_SYMLINKAT]) - GNULIB_TTYNAME_R=0; AC_SUBST([GNULIB_TTYNAME_R]) - GNULIB_UNISTD_H_GETOPT=0; AC_SUBST([GNULIB_UNISTD_H_GETOPT]) - GNULIB_UNISTD_H_SIGPIPE=0; AC_SUBST([GNULIB_UNISTD_H_SIGPIPE]) - GNULIB_UNLINK=0; AC_SUBST([GNULIB_UNLINK]) - GNULIB_UNLINKAT=0; AC_SUBST([GNULIB_UNLINKAT]) - GNULIB_USLEEP=0; AC_SUBST([GNULIB_USLEEP]) - GNULIB_WRITE=0; AC_SUBST([GNULIB_WRITE]) + GNULIB_CHOWN=0; AC_SUBST([GNULIB_CHOWN]) + GNULIB_CLOSE=0; AC_SUBST([GNULIB_CLOSE]) + GNULIB_DUP2=0; AC_SUBST([GNULIB_DUP2]) + GNULIB_DUP3=0; AC_SUBST([GNULIB_DUP3]) + GNULIB_ENVIRON=0; AC_SUBST([GNULIB_ENVIRON]) + GNULIB_EUIDACCESS=0; AC_SUBST([GNULIB_EUIDACCESS]) + GNULIB_FACCESSAT=0; AC_SUBST([GNULIB_FACCESSAT]) + GNULIB_FCHDIR=0; AC_SUBST([GNULIB_FCHDIR]) + GNULIB_FCHOWNAT=0; AC_SUBST([GNULIB_FCHOWNAT]) + GNULIB_FSYNC=0; AC_SUBST([GNULIB_FSYNC]) + GNULIB_FTRUNCATE=0; AC_SUBST([GNULIB_FTRUNCATE]) + GNULIB_GETCWD=0; AC_SUBST([GNULIB_GETCWD]) + GNULIB_GETDOMAINNAME=0; AC_SUBST([GNULIB_GETDOMAINNAME]) + GNULIB_GETDTABLESIZE=0; AC_SUBST([GNULIB_GETDTABLESIZE]) + GNULIB_GETGROUPS=0; AC_SUBST([GNULIB_GETGROUPS]) + GNULIB_GETHOSTNAME=0; AC_SUBST([GNULIB_GETHOSTNAME]) + GNULIB_GETLOGIN=0; AC_SUBST([GNULIB_GETLOGIN]) + GNULIB_GETLOGIN_R=0; AC_SUBST([GNULIB_GETLOGIN_R]) + GNULIB_GETPAGESIZE=0; AC_SUBST([GNULIB_GETPAGESIZE]) + GNULIB_GETUSERSHELL=0; AC_SUBST([GNULIB_GETUSERSHELL]) + GNULIB_LCHOWN=0; AC_SUBST([GNULIB_LCHOWN]) + GNULIB_LINK=0; AC_SUBST([GNULIB_LINK]) + GNULIB_LINKAT=0; AC_SUBST([GNULIB_LINKAT]) + GNULIB_LSEEK=0; AC_SUBST([GNULIB_LSEEK]) + GNULIB_PIPE=0; AC_SUBST([GNULIB_PIPE]) + GNULIB_PIPE2=0; AC_SUBST([GNULIB_PIPE2]) + GNULIB_PREAD=0; AC_SUBST([GNULIB_PREAD]) + GNULIB_PWRITE=0; AC_SUBST([GNULIB_PWRITE]) + GNULIB_READLINK=0; AC_SUBST([GNULIB_READLINK]) + GNULIB_READLINKAT=0; AC_SUBST([GNULIB_READLINKAT]) + GNULIB_RMDIR=0; AC_SUBST([GNULIB_RMDIR]) + GNULIB_SLEEP=0; AC_SUBST([GNULIB_SLEEP]) + GNULIB_SYMLINK=0; AC_SUBST([GNULIB_SYMLINK]) + GNULIB_SYMLINKAT=0; AC_SUBST([GNULIB_SYMLINKAT]) + GNULIB_TTYNAME_R=0; AC_SUBST([GNULIB_TTYNAME_R]) + GNULIB_UNISTD_H_GETOPT=0; AC_SUBST([GNULIB_UNISTD_H_GETOPT]) + GNULIB_UNISTD_H_NONBLOCKING=0; AC_SUBST([GNULIB_UNISTD_H_NONBLOCKING]) + GNULIB_UNISTD_H_SIGPIPE=0; AC_SUBST([GNULIB_UNISTD_H_SIGPIPE]) + GNULIB_UNLINK=0; AC_SUBST([GNULIB_UNLINK]) + GNULIB_UNLINKAT=0; AC_SUBST([GNULIB_UNLINKAT]) + GNULIB_USLEEP=0; AC_SUBST([GNULIB_USLEEP]) + GNULIB_WRITE=0; AC_SUBST([GNULIB_WRITE]) dnl Assume proper GNU behavior unless another module says otherwise. HAVE_CHOWN=1; AC_SUBST([HAVE_CHOWN]) HAVE_DUP2=1; AC_SUBST([HAVE_DUP2]) diff --git a/m4/write.m4 b/m4/write.m4 index 8695c8962..63ab5e4c0 100644 --- a/m4/write.m4 +++ b/m4/write.m4 @@ -1,4 +1,4 @@ -# write.m4 serial 1 +# write.m4 serial 2 dnl Copyright (C) 2008-2011 Free Software Foundation, Inc. dnl This file is free software; the Free Software Foundation dnl gives unlimited permission to copy and/or distribute it, @@ -14,7 +14,15 @@ AC_DEFUN([gl_FUNC_WRITE], gl_SIGNAL_SIGPIPE if test $gl_cv_header_signal_h_SIGPIPE != yes; then REPLACE_WRITE=1 - AC_LIBOBJ([write]) fi ]) + m4_ifdef([gl_NONBLOCKING_IO], [ + gl_NONBLOCKING_IO + if test $gl_cv_have_nonblocking != yes; then + REPLACE_WRITE=1 + fi + ]) + if test $REPLACE_WRITE = 1; then + AC_LIBOBJ([write]) + fi ]) diff --git a/modules/nonblocking b/modules/nonblocking index 604cc47c7..86816f314 100644 --- a/modules/nonblocking +++ b/modules/nonblocking @@ -2,18 +2,33 @@ Description: Read, set or clear the non-blocking file descriptor flag. Files: -lib/nonblocking.c lib/nonblocking.h +lib/nonblocking.c +m4/nonblocking.m4 +lib/stdio-write.c +m4/asm-underscore.m4 Depends-on: fcntl-h ioctl open stdbool +stdio sys_socket +unistd configure.ac: +gl_NONBLOCKING_IO gl_FCNTL_MODULE_INDICATOR([nonblocking]) +dnl Define the C macro GNULIB_NONBLOCKING to 1. +gl_MODULE_INDICATOR([nonblocking]) +dnl Define the substituted variable GNULIB_STDIO_H_NONBLOCKING to 1. +AC_REQUIRE([gl_STDIO_H_DEFAULTS]) +AC_REQUIRE([gl_ASM_SYMBOL_PREFIX]) +GNULIB_STDIO_H_NONBLOCKING=1 +dnl Define the substituted variable GNULIB_UNISTD_H_NONBLOCKING to 1. +AC_REQUIRE([gl_UNISTD_H_DEFAULTS]) +GNULIB_UNISTD_H_NONBLOCKING=1 Makefile.am: lib_SOURCES += nonblocking.c diff --git a/modules/stdio b/modules/stdio index db0790ff0..049ad7bf3 100644 --- a/modules/stdio +++ b/modules/stdio @@ -58,6 +58,7 @@ stdio.h: stdio.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H) -e 's|@''GNULIB_RENAMEAT''@|$(GNULIB_RENAMEAT)|g' \ -e 's|@''GNULIB_SNPRINTF''@|$(GNULIB_SNPRINTF)|g' \ -e 's|@''GNULIB_SPRINTF_POSIX''@|$(GNULIB_SPRINTF_POSIX)|g' \ + -e 's|@''GNULIB_STDIO_H_NONBLOCKING''@|$(GNULIB_STDIO_H_NONBLOCKING)|g' \ -e 's|@''GNULIB_STDIO_H_SIGPIPE''@|$(GNULIB_STDIO_H_SIGPIPE)|g' \ -e 's|@''GNULIB_TMPFILE''@|$(GNULIB_TMPFILE)|g' \ -e 's|@''GNULIB_VASPRINTF''@|$(GNULIB_VASPRINTF)|g' \ diff --git a/modules/unistd b/modules/unistd index f6774ce96..fde9f7d03 100644 --- a/modules/unistd +++ b/modules/unistd @@ -64,6 +64,7 @@ unistd.h: unistd.in.h $(top_builddir)/config.status $(CXXDEFS_H) $(ARG_NONNULL_H -e 's|@''GNULIB_SYMLINKAT''@|$(GNULIB_SYMLINKAT)|g' \ -e 's|@''GNULIB_TTYNAME_R''@|$(GNULIB_TTYNAME_R)|g' \ -e 's|@''GNULIB_UNISTD_H_GETOPT''@|$(GNULIB_UNISTD_H_GETOPT)|g' \ + -e 's|@''GNULIB_UNISTD_H_NONBLOCKING''@|$(GNULIB_UNISTD_H_NONBLOCKING)|g' \ -e 's|@''GNULIB_UNISTD_H_SIGPIPE''@|$(GNULIB_UNISTD_H_SIGPIPE)|g' \ -e 's|@''GNULIB_UNLINK''@|$(GNULIB_UNLINK)|g' \ -e 's|@''GNULIB_UNLINKAT''@|$(GNULIB_UNLINKAT)|g' \ -- 2.11.0