PING On Wed, Sep 12, 2018 at 10:17 PM Janne Blomqvist <blomqvist.ja...@gmail.com> wrote:
> When producing error and warning messages, libgfortran writes a > message by using many system calls. By using vectored writes (the > POSIX writev function) when available and feasible to use without > major surgery, we reduce the chance that output gets intermingled with > other output to stderr. > > In practice, this is done by introducing a new function estr_writev in > addition to the existing estr_write. In order to use this, the old > st_vprintf is removed, replaced by direct calls of vsnprintf, allowing > more message batching. > > Regtested on x86_64-pc-linux-gnu, Ok for trunk? > > libgfortran/ChangeLog: > > 2018-09-12 Janne Blomqvist <j...@gcc.gnu.org> > > * config.h.in: Regenerated. > * configure: Regenerated. > * configure.ac: Check for writev and sys/uio.h. > * libgfortran.h: Include sys/uio.h. > (st_vprintf): Remove prototype. > (struct iovec): Define if not available. > (estr_writev): New prototype. > * runtime/backtrace.c (error_callback): Use estr_writev. > * runtime/error.c (ST_VPRINTF_SIZE): Remove. > (estr_writev): New function. > (st_vprintf): Remove. > (gf_vsnprintf): New function. > (ST_ERRBUF_SIZE): New macro. > (st_printf): Use vsnprintf. > (os_error): Use estr_writev. > (runtime_error): Use vsnprintf and estr_writev. > (runtime_error_at): Likewise. > (runtime_warning_at): Likewise. > (internal_error): Use estr_writev. > (generate_error_common): Likewise. > (generate_warning): Likewise. > (notify_std): Likewise. > * runtime/pause.c (pause_string): Likewise. > * runtime/stop.c (report_exception): Likewise. > (stop_string): Likewise. > (error_stop_string): Likewise. > --- > libgfortran/config.h.in | 6 + > libgfortran/configure | 10 +- > libgfortran/configure.ac | 4 +- > libgfortran/libgfortran.h | 15 ++- > libgfortran/runtime/backtrace.c | 27 +++-- > libgfortran/runtime/error.c | 188 +++++++++++++++++++++++--------- > libgfortran/runtime/pause.c | 14 ++- > libgfortran/runtime/stop.c | 71 +++++++++--- > 8 files changed, 250 insertions(+), 85 deletions(-) > > diff --git a/libgfortran/config.h.in b/libgfortran/config.h.in > index 65fd27c6b11..c7f47146030 100644 > --- a/libgfortran/config.h.in > +++ b/libgfortran/config.h.in > @@ -762,6 +762,9 @@ > /* Define to 1 if you have the <sys/types.h> header file. */ > #undef HAVE_SYS_TYPES_H > > +/* Define to 1 if you have the <sys/uio.h> header file. */ > +#undef HAVE_SYS_UIO_H > + > /* Define to 1 if you have the <sys/wait.h> header file. */ > #undef HAVE_SYS_WAIT_H > > @@ -828,6 +831,9 @@ > /* Define if target has a reliable stat. */ > #undef HAVE_WORKING_STAT > > +/* Define to 1 if you have the `writev' function. */ > +#undef HAVE_WRITEV > + > /* Define to 1 if you have the <xlocale.h> header file. */ > #undef HAVE_XLOCALE_H > > diff --git a/libgfortran/configure b/libgfortran/configure > index a583b676a3e..1c93683acd2 100755 > --- a/libgfortran/configure > +++ b/libgfortran/configure > @@ -2553,6 +2553,7 @@ as_fn_append ac_header_list " sys/times.h" > as_fn_append ac_header_list " sys/resource.h" > as_fn_append ac_header_list " sys/types.h" > as_fn_append ac_header_list " sys/stat.h" > +as_fn_append ac_header_list " sys/uio.h" > as_fn_append ac_header_list " sys/wait.h" > as_fn_append ac_header_list " floatingpoint.h" > as_fn_append ac_header_list " ieeefp.h" > @@ -2584,6 +2585,7 @@ as_fn_append ac_func_list " access" > as_fn_append ac_func_list " fork" > as_fn_append ac_func_list " setmode" > as_fn_append ac_func_list " fcntl" > +as_fn_append ac_func_list " writev" > as_fn_append ac_func_list " gettimeofday" > as_fn_append ac_func_list " stat" > as_fn_append ac_func_list " fstat" > @@ -12514,7 +12516,7 @@ else > lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 > lt_status=$lt_dlunknown > cat > conftest.$ac_ext <<_LT_EOF > -#line 12517 "configure" > +#line 12519 "configure" > #include "confdefs.h" > > #if HAVE_DLFCN_H > @@ -12620,7 +12622,7 @@ else > lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2 > lt_status=$lt_dlunknown > cat > conftest.$ac_ext <<_LT_EOF > -#line 12623 "configure" > +#line 12625 "configure" > #include "confdefs.h" > > #if HAVE_DLFCN_H > @@ -16168,6 +16170,8 @@ done > > > > + > + > > > > @@ -16763,6 +16767,8 @@ done > > > > + > + > > > > diff --git a/libgfortran/configure.ac b/libgfortran/configure.ac > index 05952aa0d40..64f7b9a39d5 100644 > --- a/libgfortran/configure.ac > +++ b/libgfortran/configure.ac > @@ -276,7 +276,7 @@ AC_CHECK_TYPES([ptrdiff_t]) > > # check header files (we assume C89 is available, so don't check for that) > AC_CHECK_HEADERS_ONCE(unistd.h sys/random.h sys/time.h sys/times.h \ > -sys/resource.h sys/types.h sys/stat.h sys/wait.h \ > +sys/resource.h sys/types.h sys/stat.h sys/uio.h sys/wait.h \ > floatingpoint.h ieeefp.h fenv.h fptrap.h \ > fpxcp.h pwd.h complex.h xlocale.h) > > @@ -315,7 +315,7 @@ else > AC_CHECK_FUNCS_ONCE(getrusage times mkstemp strtof strtold snprintf \ > ftruncate chsize chdir getentropy getlogin gethostname kill link > symlink \ > sleep ttyname \ > - alarm access fork setmode fcntl \ > + alarm access fork setmode fcntl writev \ > gettimeofday stat fstat lstat getpwuid vsnprintf dup \ > getcwd localtime_r gmtime_r getpwuid_r ttyname_r clock_gettime \ > getgid getpid getuid geteuid umask getegid \ > diff --git a/libgfortran/libgfortran.h b/libgfortran/libgfortran.h > index b5a742aac88..1179812310b 100644 > --- a/libgfortran/libgfortran.h > +++ b/libgfortran/libgfortran.h > @@ -88,6 +88,10 @@ extern long double __strtold (const char *, char **); > #include <sys/types.h> > #endif > > +#ifdef HAVE_SYS_UIO_H > +#include <sys/uio.h> > +#endif > + > #ifdef __MINGW32__ > typedef off64_t gfc_offset; > #else > @@ -701,8 +705,15 @@ internal_proto(exit_error); > extern ssize_t estr_write (const char *); > internal_proto(estr_write); > > -extern int st_vprintf (const char *, va_list); > -internal_proto(st_vprintf); > +#if !defined(HAVE_WRITEV) && !defined(HAVE_SYS_UIO_H) > +struct iovec { > + void *iov_base; /* Starting address */ > + size_t iov_len; /* Number of bytes to transfer */ > +}; > +#endif > + > +extern ssize_t estr_writev (const struct iovec *iov, int iovcnt); > +internal_proto(estr_writev); > > extern int st_printf (const char *, ...) > __attribute__((format (gfc_printf, 1, 2))); > diff --git a/libgfortran/runtime/backtrace.c > b/libgfortran/runtime/backtrace.c > index b8246889fde..e0c277044b6 100644 > --- a/libgfortran/runtime/backtrace.c > +++ b/libgfortran/runtime/backtrace.c > @@ -68,6 +68,7 @@ static void > error_callback (void *data, const char *msg, int errnum) > { > struct mystate *state = (struct mystate *) data; > + struct iovec iov[5]; > #define ERRHDR "\nCould not print backtrace: " > > if (errnum < 0) > @@ -77,21 +78,31 @@ error_callback (void *data, const char *msg, int > errnum) > } > else if (errnum == 0) > { > - estr_write (ERRHDR); > - estr_write (msg); > - estr_write ("\n"); > + iov[0].iov_base = (char*) ERRHDR; > + iov[0].iov_len = strlen (ERRHDR); > + iov[1].iov_base = (char*) msg; > + iov[1].iov_len = strlen (msg); > + iov[2].iov_base = (char*) "\n"; > + iov[2].iov_len = 1; > + estr_writev (iov, 3); > } > else > { > char errbuf[256]; > if (state->in_signal_handler) > { > - estr_write (ERRHDR); > - estr_write (msg); > - estr_write (", errno: "); > + iov[0].iov_base = (char*) ERRHDR; > + iov[0].iov_len = strlen (ERRHDR); > + iov[1].iov_base = (char*) msg; > + iov[1].iov_len = strlen (msg); > + iov[2].iov_base = (char*) ", errno: "; > + iov[2].iov_len = strlen (iov[2].iov_base); > const char *p = gfc_itoa (errnum, errbuf, sizeof (errbuf)); > - estr_write (p); > - estr_write ("\n"); > + iov[3].iov_base = (char*) p; > + iov[3].iov_len = strlen (p); > + iov[4].iov_base = (char*) "\n"; > + iov[4].iov_len = 1; > + estr_writev (iov, 5); > } > else > st_printf (ERRHDR "%s: %s\n", msg, > diff --git a/libgfortran/runtime/error.c b/libgfortran/runtime/error.c > index 1e8b6223aca..b07a4c0b12a 100644 > --- a/libgfortran/runtime/error.c > +++ b/libgfortran/runtime/error.c > @@ -114,52 +114,71 @@ estr_write (const char *str) > } > > > -/* st_vprintf()-- vsnprintf-like function for error output. We use a > - stack allocated buffer for formatting; since this function might be > - called from within a signal handler, printing directly to stderr > - with vfprintf is not safe since the stderr locking might lead to a > - deadlock. */ > +/* Write a vector of strings to standard error. This function is > + async-signal-safe. */ > > -#define ST_VPRINTF_SIZE 512 > +ssize_t > +estr_writev (const struct iovec *iov, int iovcnt) > +{ > +#ifdef HAVE_WRITEV > + return writev (STDERR_FILENO, iov, iovcnt); > +#else > + ssize_t w = 0; > + for (int i = 0; i < iovcnt; i++) > + { > + ssize_t r = write (STDERR_FILENO, iov[i].iov_base, iov[i].iov_len); > + if (r == -1) > + return r; > + w += r; > + } > + return w; > +#endif > +} > > -int > -st_vprintf (const char *format, va_list ap) > + > +#ifndef HAVE_VSNPRINTF > +static int > +gf_vsnprintf (char *str, size_t size, const char *format, va_list ap) > { > int written; > - char buffer[ST_VPRINTF_SIZE]; > > -#ifdef HAVE_VSNPRINTF > - written = vsnprintf(buffer, ST_VPRINTF_SIZE, format, ap); > -#else > written = vsprintf(buffer, format, ap); > > - if (written >= ST_VPRINTF_SIZE - 1) > + if (written >= size - 1) > { > /* The error message was longer than our buffer. Ouch. Because > we may have messed up things badly, report the error and > quit. */ > -#define ERROR_MESSAGE "Internal error: buffer overrun in st_vprintf()\n" > - write (STDERR_FILENO, buffer, ST_VPRINTF_SIZE - 1); > - write (STDERR_FILENO, ERROR_MESSAGE, strlen(ERROR_MESSAGE)); > +#define ERROR_MESSAGE "Internal error: buffer overrun in gf_vsnprintf()\n" > + write (STDERR_FILENO, buffer, size - 1); > + write (STDERR_FILENO, ERROR_MESSAGE, strlen (ERROR_MESSAGE)); > sys_abort (); > #undef ERROR_MESSAGE > > } > -#endif > - > - written = write (STDERR_FILENO, buffer, written); > return written; > } > > +#define vsnprintf gf_vsnprintf > +#endif > + > + > +/* printf() like function for for printing to stderr. Uses a stack > + allocated buffer and doesn't lock stderr, so it should be safe to > + use from within a signal handler. */ > + > +#define ST_ERRBUF_SIZE 512 > > int > st_printf (const char * format, ...) > { > + char buffer[ST_ERRBUF_SIZE]; > int written; > va_list ap; > va_start (ap, format); > - written = st_vprintf (format, ap); > + written = vsnprintf (buffer, ST_ERRBUF_SIZE, format, ap); > va_end (ap); > + written = write (STDERR_FILENO, buffer, written); > return written; > } > > @@ -340,12 +359,19 @@ void > os_error (const char *message) > { > char errmsg[STRERR_MAXSZ]; > + struct iovec iov[5]; > recursion_check (); > - estr_write ("Operating system error: "); > - estr_write (gf_strerror (errno, errmsg, STRERR_MAXSZ)); > - estr_write ("\n"); > - estr_write (message); > - estr_write ("\n"); > + iov[0].iov_base = (char*) "Operating system error: "; > + iov[0].iov_len = strlen (iov[0].iov_base); > + iov[1].iov_base = gf_strerror (errno, errmsg, STRERR_MAXSZ); > + iov[1].iov_len = strlen (iov[1].iov_base); > + iov[2].iov_base = (char*) "\n"; > + iov[2].iov_len = 1; > + iov[3].iov_base = (char*) message; > + iov[3].iov_len = strlen (message); > + iov[4].iov_base = (char*) "\n"; > + iov[4].iov_len = 1; > + estr_writev (iov, 5); > exit_error (1); > } > iexport(os_error); > @@ -357,14 +383,25 @@ iexport(os_error); > void > runtime_error (const char *message, ...) > { > + char buffer[ST_ERRBUF_SIZE]; > + struct iovec iov[3]; > va_list ap; > + int written; > > recursion_check (); > - estr_write ("Fortran runtime error: "); > + iov[0].iov_base = (char*) "Fortran runtime error: "; > + iov[0].iov_len = strlen (iov[0].iov_base); > va_start (ap, message); > - st_vprintf (message, ap); > + written = vsnprintf (buffer, ST_ERRBUF_SIZE, message, ap); > va_end (ap); > - estr_write ("\n"); > + if (written >= 0) > + { > + iov[1].iov_base = buffer; > + iov[1].iov_len = written; > + iov[2].iov_base = (char*) "\n"; > + iov[2].iov_len = 1; > + estr_writev (iov, 3); > + } > exit_error (2); > } > iexport(runtime_error); > @@ -375,15 +412,27 @@ iexport(runtime_error); > void > runtime_error_at (const char *where, const char *message, ...) > { > + char buffer[ST_ERRBUF_SIZE]; > va_list ap; > + struct iovec iov[4]; > + int written; > > recursion_check (); > - estr_write (where); > - estr_write ("\nFortran runtime error: "); > + iov[0].iov_base = (char*) where; > + iov[0].iov_len = strlen (where); > + iov[1].iov_base = (char*) "\nFortran runtime error: "; > + iov[1].iov_len = strlen (iov[1].iov_base); > va_start (ap, message); > - st_vprintf (message, ap); > + written = vsnprintf (buffer, ST_ERRBUF_SIZE, message, ap); > va_end (ap); > - estr_write ("\n"); > + if (written >= 0) > + { > + iov[2].iov_base = buffer; > + iov[2].iov_len = written; > + iov[3].iov_base = (char*) "\n"; > + iov[3].iov_len = 1; > + estr_writev (iov, 4); > + } > exit_error (2); > } > iexport(runtime_error_at); > @@ -392,14 +441,26 @@ iexport(runtime_error_at); > void > runtime_warning_at (const char *where, const char *message, ...) > { > + char buffer[ST_ERRBUF_SIZE]; > va_list ap; > + struct iovec iov[4]; > + int written; > > - estr_write (where); > - estr_write ("\nFortran runtime warning: "); > + iov[0].iov_base = (char*) where; > + iov[0].iov_len = strlen (where); > + iov[1].iov_base = (char*) "\nFortran runtime warning: "; > + iov[1].iov_len = strlen (iov[1].iov_base); > va_start (ap, message); > - st_vprintf (message, ap); > + written = vsnprintf (buffer, ST_ERRBUF_SIZE, message, ap); > va_end (ap); > - estr_write ("\n"); > + if (written >= 0) > + { > + iov[2].iov_base = buffer; > + iov[2].iov_len = written; > + iov[3].iov_base = (char*) "\n"; > + iov[3].iov_len = 1; > + estr_writev (iov, 4); > + } > } > iexport(runtime_warning_at); > > @@ -410,11 +471,17 @@ iexport(runtime_warning_at); > void > internal_error (st_parameter_common *cmp, const char *message) > { > + struct iovec iov[3]; > + > recursion_check (); > show_locus (cmp); > - estr_write ("Internal Error: "); > - estr_write (message); > - estr_write ("\n"); > + iov[0].iov_base = (char*) "Internal Error: "; > + iov[0].iov_len = strlen (iov[0].iov_base); > + iov[1].iov_base = (char*) message; > + iov[1].iov_len = strlen (message); > + iov[2].iov_base = (char*) "\n"; > + iov[2].iov_len = 1; > + estr_writev (iov, 3); > > /* This function call is here to get the main.o object file included > when linking statically. This works because error.o is supposed to > @@ -609,9 +676,14 @@ generate_error_common (st_parameter_common *cmp, int > family, const char *message > > recursion_check (); > show_locus (cmp); > - estr_write ("Fortran runtime error: "); > - estr_write (message); > - estr_write ("\n"); > + struct iovec iov[3]; > + iov[0].iov_base = (char*) "Fortran runtime error: "; > + iov[0].iov_len = strlen (iov[0].iov_base); > + iov[1].iov_base = (char*) message; > + iov[1].iov_len = strlen (message); > + iov[2].iov_base = (char*) "\n"; > + iov[2].iov_len = 1; > + estr_writev (iov, 3); > return false; > } > > @@ -645,9 +717,14 @@ generate_warning (st_parameter_common *cmp, const > char *message) > message = " "; > > show_locus (cmp); > - estr_write ("Fortran runtime warning: "); > - estr_write (message); > - estr_write ("\n"); > + struct iovec iov[3]; > + iov[0].iov_base = (char*) "Fortran runtime warning: "; > + iov[0].iov_len = strlen (iov[0].iov_base); > + iov[1].iov_base = (char*) message; > + iov[1].iov_len = strlen (message); > + iov[2].iov_base = (char*) "\n"; > + iov[2].iov_len = 1; > + estr_writev (iov, 3); > } > > > @@ -678,6 +755,7 @@ bool > notify_std (st_parameter_common *cmp, int std, const char * message) > { > int warning; > + struct iovec iov[3]; > > if (!compile_options.pedantic) > return true; > @@ -690,17 +768,25 @@ notify_std (st_parameter_common *cmp, int std, const > char * message) > { > recursion_check (); > show_locus (cmp); > - estr_write ("Fortran runtime error: "); > - estr_write (message); > - estr_write ("\n"); > + iov[0].iov_base = (char*) "Fortran runtime error: "; > + iov[0].iov_len = strlen (iov[0].iov_base); > + iov[1].iov_base = (char*) message; > + iov[1].iov_len = strlen (message); > + iov[2].iov_base = (char*) "\n"; > + iov[2].iov_len = 1; > + estr_writev (iov, 3); > exit_error (2); > } > else > { > show_locus (cmp); > - estr_write ("Fortran runtime warning: "); > - estr_write (message); > - estr_write ("\n"); > + iov[0].iov_base = (char*) "Fortran runtime warning: "; > + iov[0].iov_len = strlen (iov[0].iov_base); > + iov[1].iov_base = (char*) message; > + iov[1].iov_len = strlen (message); > + iov[2].iov_base = (char*) "\n"; > + iov[2].iov_len = 1; > + estr_writev (iov, 3); > } > return false; > } > diff --git a/libgfortran/runtime/pause.c b/libgfortran/runtime/pause.c > index 37672d4a02c..12997c7a685 100644 > --- a/libgfortran/runtime/pause.c > +++ b/libgfortran/runtime/pause.c > @@ -64,11 +64,15 @@ export_proto(pause_string); > void > pause_string (char *string, size_t len) > { > - estr_write ("PAUSE "); > - ssize_t w = write (STDERR_FILENO, string, len); > - (void) sizeof (w); /* Avoid compiler warning about not using write > - return val. */ > - estr_write ("\n"); > + struct iovec iov[3]; > + > + iov[0].iov_base = (char*) "PAUSE "; > + iov[0].iov_len = strlen (iov[0].iov_base); > + iov[1].iov_base = string; > + iov[1].iov_len = len; > + iov[2].iov_base = (char*) "\n"; > + iov[2].iov_len = 1; > + estr_writev (iov, 3); > > do_pause (); > } > diff --git a/libgfortran/runtime/stop.c b/libgfortran/runtime/stop.c > index 1e6dd8c28d0..4833e7b414a 100644 > --- a/libgfortran/runtime/stop.c > +++ b/libgfortran/runtime/stop.c > @@ -29,6 +29,7 @@ see the files COPYING3 and COPYING.RUNTIME > respectively. If not, see > #include <unistd.h> > #endif > > +#include <string.h> > > /* Fortran 2008 demands: If any exception (14) is signaling on that > image, the > processor shall issue a warning indicating which exceptions are > signaling; > @@ -40,7 +41,8 @@ see the files COPYING3 and COPYING.RUNTIME > respectively. If not, see > static void > report_exception (void) > { > - int set_excepts; > + struct iovec iov[8]; > + int set_excepts, iovcnt = 1; > > if (!compile_options.fpe_summary) > return; > @@ -49,33 +51,62 @@ report_exception (void) > if ((set_excepts & compile_options.fpe_summary) == 0) > return; > > - estr_write ("Note: The following floating-point exceptions are > signalling:"); > + iov[0].iov_base = (char*) "Note: The following floating-point > exceptions are signalling:"; > + iov[0].iov_len = strlen (iov[0].iov_base); > > if ((compile_options.fpe_summary & GFC_FPE_INVALID) > && (set_excepts & GFC_FPE_INVALID)) > - estr_write (" IEEE_INVALID_FLAG"); > + { > + iov[iovcnt].iov_base = (char*) " IEEE_INVALID_FLAG"; > + iov[iovcnt].iov_len = strlen (iov[iovcnt].iov_base); > + iovcnt++; > + } > > if ((compile_options.fpe_summary & GFC_FPE_ZERO) > && (set_excepts & GFC_FPE_ZERO)) > - estr_write (" IEEE_DIVIDE_BY_ZERO"); > + { > + iov[iovcnt].iov_base = (char*) " IEEE_DIVIDE_BY_ZERO"; > + iov[iovcnt].iov_len = strlen (iov[iovcnt].iov_base); > + iovcnt++; > + } > > if ((compile_options.fpe_summary & GFC_FPE_OVERFLOW) > && (set_excepts & GFC_FPE_OVERFLOW)) > - estr_write (" IEEE_OVERFLOW_FLAG"); > + { > + iov[iovcnt].iov_base = (char*) " IEEE_OVERFLOW_FLAG"; > + iov[iovcnt].iov_len = strlen (iov[iovcnt].iov_base); > + iovcnt++; > + } > > if ((compile_options.fpe_summary & GFC_FPE_UNDERFLOW) > && (set_excepts & GFC_FPE_UNDERFLOW)) > - estr_write (" IEEE_UNDERFLOW_FLAG"); > + { > + iov[iovcnt].iov_base = (char*) " IEEE_UNDERFLOW_FLAG"; > + iov[iovcnt].iov_len = strlen (iov[iovcnt].iov_base); > + iovcnt++; > + } > > if ((compile_options.fpe_summary & GFC_FPE_DENORMAL) > && (set_excepts & GFC_FPE_DENORMAL)) > - estr_write (" IEEE_DENORMAL"); > + { > + iov[iovcnt].iov_base = (char*) " IEEE_DENORMAL"; > + iov[iovcnt].iov_len = strlen (iov[iovcnt].iov_base); > + iovcnt++; > + } > > if ((compile_options.fpe_summary & GFC_FPE_INEXACT) > && (set_excepts & GFC_FPE_INEXACT)) > - estr_write (" IEEE_INEXACT_FLAG"); > + { > + iov[iovcnt].iov_base = (char*) " IEEE_INEXACT_FLAG"; > + iov[iovcnt].iov_len = strlen (iov[iovcnt].iov_base); > + iovcnt++; > + } > + > + iov[iovcnt].iov_base = (char*) "\n"; > + iov[iovcnt].iov_len = 1; > + iovcnt++; > > - estr_write ("\n"); > + estr_writev (iov, iovcnt); > } > > > @@ -106,9 +137,14 @@ stop_string (const char *string, size_t len, bool > quiet) > report_exception (); > if (string) > { > - estr_write ("STOP "); > - (void) write (STDERR_FILENO, string, len); > - estr_write ("\n"); > + struct iovec iov[3]; > + iov[0].iov_base = (char*) "STOP "; > + iov[0].iov_len = strlen (iov[0].iov_base); > + iov[1].iov_base = (char*) string; > + iov[1].iov_len = len; > + iov[2].iov_base = (char*) "\n"; > + iov[2].iov_len = 1; > + estr_writev (iov, 3); > } > } > exit (0); > @@ -128,10 +164,15 @@ error_stop_string (const char *string, size_t len, > bool quiet) > { > if (!quiet) > { > + struct iovec iov[3]; > report_exception (); > - estr_write ("ERROR STOP "); > - (void) write (STDERR_FILENO, string, len); > - estr_write ("\n"); > + iov[0].iov_base = (char*) "ERROR STOP "; > + iov[0].iov_len = strlen (iov[0].iov_base); > + iov[1].iov_base = (char*) string; > + iov[1].iov_len = len; > + iov[2].iov_base = (char*) "\n"; > + iov[2].iov_len = 1; > + estr_writev (iov, 3); > } > exit_error (1); > } > -- > 2.17.1 > > -- Janne Blomqvist