diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/nvim/getchar.c | 94 | ||||
| -rw-r--r-- | src/nvim/getchar.h | 24 | ||||
| -rw-r--r-- | src/nvim/globals.h | 6 | ||||
| -rw-r--r-- | src/nvim/main.c | 40 | ||||
| -rw-r--r-- | src/nvim/message.c | 10 | ||||
| -rw-r--r-- | src/nvim/os/fileio.c | 45 | ||||
| -rw-r--r-- | src/nvim/os/fileio.h | 3 | ||||
| -rw-r--r-- | src/nvim/os/fs.c | 50 | 
8 files changed, 174 insertions, 98 deletions
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index 03929a58b6..98164b2653 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -48,8 +48,14 @@  #include "nvim/event/loop.h"  #include "nvim/os/input.h"  #include "nvim/os/os.h" +#include "nvim/os/fileio.h"  #include "nvim/api/private/handle.h" + +/// Index in scriptin +static int curscript = 0; +FileDescriptor *scriptin[NSCRIPT] = { NULL }; +  /*   * These buffers are used for storing:   * - stuffed characters: A command that is translated into another command. @@ -1243,10 +1249,13 @@ openscript (      ++curscript;    /* use NameBuff for expanded name */    expand_env(name, NameBuff, MAXPATHL); -  if ((scriptin[curscript] = mch_fopen((char *)NameBuff, READBIN)) == NULL) { -    EMSG2(_(e_notopen), name); -    if (curscript) -      --curscript; +  int error; +  if ((scriptin[curscript] = file_open_new(&error, (char *)NameBuff, +                                           kFileReadOnly, 0)) == NULL) { +    emsgf(_(e_notopen_2), name, os_strerror(error)); +    if (curscript) { +      curscript--; +    }      return;    }    save_typebuf(); @@ -1296,7 +1305,7 @@ static void closescript(void)    free_typebuf();    typebuf = saved_typebuf[curscript]; -  fclose(scriptin[curscript]); +  file_free(scriptin[curscript], false);    scriptin[curscript] = NULL;    if (curscript > 0)      --curscript; @@ -2336,9 +2345,8 @@ inchar (      int tb_change_cnt  )  { -  int len = 0;                      /* init for GCC */ -  int retesc = FALSE;               /* return ESC with gotint */ -  int script_char; +  int len = 0;  // Init for GCC. +  int retesc = false;  // Return ESC with gotint.    if (wait_time == -1L || wait_time > 100L) {      // flush output before waiting @@ -2356,45 +2364,38 @@ inchar (    }    undo_off = FALSE;                 /* restart undo now */ -  /* -   * Get a character from a script file if there is one. -   * If interrupted: Stop reading script files, close them all. -   */ -  script_char = -1; -  while (scriptin[curscript] != NULL && script_char < 0 -         && !ignore_script -         ) { - - -    if (got_int || (script_char = getc(scriptin[curscript])) < 0) { -      /* Reached EOF. -       * Careful: closescript() frees typebuf.tb_buf[] and buf[] may -       * point inside typebuf.tb_buf[].  Don't use buf[] after this! */ +  // Get a character from a script file if there is one. +  // If interrupted: Stop reading script files, close them all. +  ptrdiff_t read_size = -1; +  while (scriptin[curscript] != NULL && read_size <= 0 && !ignore_script) { +    char script_char; +    if (got_int +        || (read_size = file_read(scriptin[curscript], &script_char, 1)) != 1) { +      // Reached EOF or some error occurred. +      // Careful: closescript() frees typebuf.tb_buf[] and buf[] may +      // point inside typebuf.tb_buf[].  Don't use buf[] after this!        closescript(); -      /* -       * When reading script file is interrupted, return an ESC to get -       * back to normal mode. -       * Otherwise return -1, because typebuf.tb_buf[] has changed. -       */ -      if (got_int) -        retesc = TRUE; -      else +      // When reading script file is interrupted, return an ESC to get +      // back to normal mode. +      // Otherwise return -1, because typebuf.tb_buf[] has changed. +      if (got_int) { +        retesc = true; +      } else {          return -1; +      }      } else {        buf[0] = (char_u)script_char;        len = 1;      }    } -  if (script_char < 0) {        /* did not get a character from script */ -    /* -     * If we got an interrupt, skip all previously typed characters and -     * return TRUE if quit reading script file. -     * Stop reading typeahead when a single CTRL-C was read, -     * fill_input_buf() returns this when not able to read from stdin. -     * Don't use buf[] here, closescript() may have freed typebuf.tb_buf[] -     * and buf may be pointing inside typebuf.tb_buf[]. -     */ +  if (read_size <= 0) {  // Did not get a character from script. +    // If we got an interrupt, skip all previously typed characters and +    // return TRUE if quit reading script file. +    // Stop reading typeahead when a single CTRL-C was read, +    // fill_input_buf() returns this when not able to read from stdin. +    // Don't use buf[] here, closescript() may have freed typebuf.tb_buf[] +    // and buf may be pointing inside typebuf.tb_buf[].      if (got_int) {  #define DUM_LEN MAXMAPLEN * 3 + 3        char_u dum[DUM_LEN + 1]; @@ -2407,21 +2408,18 @@ inchar (        return retesc;      } -    /* -     * Always flush the output characters when getting input characters -     * from the user. -     */ +    // Always flush the output characters when getting input characters +    // from the user.      ui_flush(); -    /* -     * Fill up to a third of the buffer, because each character may be -     * tripled below. -     */ +    // Fill up to a third of the buffer, because each character may be +    // tripled below.      len = os_inchar(buf, maxlen / 3, (int)wait_time, tb_change_cnt);    } -  if (typebuf_changed(tb_change_cnt)) +  if (typebuf_changed(tb_change_cnt)) {      return 0; +  }    return fix_input_buffer(buf, len);  } diff --git a/src/nvim/getchar.h b/src/nvim/getchar.h index e634273e0d..38a2e75663 100644 --- a/src/nvim/getchar.h +++ b/src/nvim/getchar.h @@ -1,24 +1,30 @@  #ifndef NVIM_GETCHAR_H  #define NVIM_GETCHAR_H +#include "nvim/os/fileio.h"  #include "nvim/types.h"  #include "nvim/buffer_defs.h"  #include "nvim/ex_cmds_defs.h" -/// Values for "noremap" argument of ins_typebuf().  Also used for -/// map->m_noremap and menu->noremap[]. -/// @addtogroup REMAP_VALUES -/// @{ -#define REMAP_YES       0       ///< allow remapping -#define REMAP_NONE      -1      ///< no remapping -#define REMAP_SCRIPT    -2      ///< remap script-local mappings only -#define REMAP_SKIP      -3      ///< no remapping for first char -/// @} +/// Values for "noremap" argument of ins_typebuf() +/// +/// Also used for map->m_noremap and menu->noremap[]. +enum { +  REMAP_YES = 0,  ///< Allow remapping. +  REMAP_NONE = -1,  ///< No remapping. +  REMAP_SCRIPT = -2,  ///< Remap script-local mappings only. +  REMAP_SKIP = -3,  ///< No remapping for first char. +} RemapValues;  #define KEYLEN_PART_KEY -1      /* keylen value for incomplete key-code */  #define KEYLEN_PART_MAP -2      /* keylen value for incomplete mapping */  #define KEYLEN_REMOVED  9999    /* keylen value for removed sequence */ +/// Maximum number of streams to read script from +enum { NSCRIPT = 15 }; + +/// Streams to read script from +extern FileDescriptor *scriptin[NSCRIPT];  #ifdef INCLUDE_GENERATED_DECLARATIONS  # include "getchar.h.generated.h" diff --git a/src/nvim/globals.h b/src/nvim/globals.h index 89d93310a6..56790bc89b 100644 --- a/src/nvim/globals.h +++ b/src/nvim/globals.h @@ -834,10 +834,7 @@ EXTERN int do_redraw INIT(= FALSE);         /* extra redraw once */  EXTERN int need_highlight_changed INIT(= true);  EXTERN char *used_shada_file INIT(= NULL);  // name of the ShaDa file to use -#define NSCRIPT 15 -EXTERN FILE     *scriptin[NSCRIPT];         /* streams to read script from */ -EXTERN int curscript INIT(= 0);             /* index in scriptin[] */ -EXTERN FILE     *scriptout INIT(= NULL);    /* stream to write script to */ +EXTERN FILE *scriptout INIT(= NULL);  ///< Stream to write script to.  // volatile because it is used in a signal handler.  EXTERN volatile int got_int INIT(= false);  // set to true when interrupt @@ -1085,6 +1082,7 @@ EXTERN char_u e_norange[] INIT(= N_("E481: No range allowed"));  EXTERN char_u e_noroom[] INIT(= N_("E36: Not enough room"));  EXTERN char_u e_notmp[] INIT(= N_("E483: Can't get temp file name"));  EXTERN char_u e_notopen[] INIT(= N_("E484: Can't open file %s")); +EXTERN char_u e_notopen_2[] INIT(= N_("E484: Can't open file %s: %s"));  EXTERN char_u e_notread[] INIT(= N_("E485: Can't read file %s"));  EXTERN char_u e_nowrtmsg[] INIT(= N_(          "E37: No write since last change (add ! to override)")); diff --git a/src/nvim/main.c b/src/nvim/main.c index b7a4caaab1..a4ed868af1 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -787,7 +787,8 @@ static void command_line_scan(mparm_T *parmp)              mch_exit(0);            } else if (STRICMP(argv[0] + argv_idx, "api-info") == 0) {              FileDescriptor fp; -            const int fof_ret = file_open_fd(&fp, STDOUT_FILENO, true); +            const int fof_ret = file_open_fd(&fp, STDOUT_FILENO, +                                             kFileWriteOnly);              msgpack_packer *p = msgpack_packer_new(&fp, msgpack_file_write);              if (fof_ret != 0) { @@ -1085,17 +1086,36 @@ static void command_line_scan(mparm_T *parmp)            case 's':               /* "-s {scriptin}" read from script file */              if (scriptin[0] != NULL) {  scripterror: -              mch_errmsg(_("Attempt to open script file again: \"")); -              mch_errmsg(argv[-1]); -              mch_errmsg(" "); -              mch_errmsg(argv[0]); -              mch_errmsg("\"\n"); +              vim_snprintf((char *)IObuff, IOSIZE, +                           _("Attempt to open script file again: \"%s %s\"\n"), +                           argv[-1], argv[0]); +              mch_errmsg((const char *)IObuff);                mch_exit(2);              } -            if ((scriptin[0] = mch_fopen(argv[0], READBIN)) == NULL) { -              mch_errmsg(_("Cannot open for reading: \"")); -              mch_errmsg(argv[0]); -              mch_errmsg("\"\n"); +            int error; +            if (STRCMP(argv[0], "-") == 0) { +              const int stdin_dup_fd = os_dup(STDIN_FILENO); +#ifdef WIN32 +              // On Windows, replace the original stdin with the +              // console input handle. +              close(STDIN_FILENO); +              const HANDLE conin_handle = +                CreateFile("CONIN$", GENERIC_READ | GENERIC_WRITE, +                           FILE_SHARE_READ, (LPSECURITY_ATTRIBUTES)NULL, +                           OPEN_EXISTING, 0, (HANDLE)NULL); +              const int conin_fd = _open_osfhandle(conin_handle, _O_RDONLY); +              assert(conin_fd == STDIN_FILENO); +#endif +              FileDescriptor *const stdin_dup = file_open_fd_new( +                  &error, stdin_dup_fd, kFileReadOnly|kFileNonBlocking); +              assert(stdin_dup != NULL); +              scriptin[0] = stdin_dup; +            } else if ((scriptin[0] = file_open_new( +                &error, argv[0], kFileReadOnly|kFileNonBlocking, 0)) == NULL) { +              vim_snprintf((char *)IObuff, IOSIZE, +                           _("Cannot open for reading: \"%s\": %s\n"), +                           argv[0], os_strerror(error)); +              mch_errmsg((const char *)IObuff);                mch_exit(2);              }              save_typebuf(); diff --git a/src/nvim/message.c b/src/nvim/message.c index 04528629c7..3a3c9cb167 100644 --- a/src/nvim/message.c +++ b/src/nvim/message.c @@ -2351,10 +2351,9 @@ static int do_more_prompt(int typed_char)   * yet.  When stderr can't be used, collect error messages until the GUI has   * started and they can be displayed in a message box.   */ -void mch_errmsg(char *str) +void mch_errmsg(const char *const str) +  FUNC_ATTR_NONNULL_ALL  { -  int len; -  #ifdef UNIX    /* On Unix use stderr if it's a tty.     * When not going to start the GUI also use stderr. @@ -2368,14 +2367,13 @@ void mch_errmsg(char *str)    /* avoid a delay for a message that isn't there */    emsg_on_display = FALSE; -  len = (int)STRLEN(str) + 1; +  const size_t len = strlen(str) + 1;    if (error_ga.ga_data == NULL) {      ga_set_growsize(&error_ga, 80);      error_ga.ga_itemsize = 1;    }    ga_grow(&error_ga, len); -  memmove((char_u *)error_ga.ga_data + error_ga.ga_len, -      (char_u *)str, len); +  memmove(error_ga.ga_data + error_ga.ga_len, str, len);  #ifdef UNIX    /* remove CR characters, they are displayed */    { diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c index a95adc86b6..ccf35fd57c 100644 --- a/src/nvim/os/fileio.c +++ b/src/nvim/os/fileio.c @@ -83,7 +83,7 @@ int file_open(FileDescriptor *const ret_fp, const char *const fname,    if (fd < 0) {      return fd;    } -  return file_open_fd(ret_fp, fd, (wr == kTrue)); +  return file_open_fd(ret_fp, fd, flags);  }  /// Wrap file descriptor with FileDescriptor structure @@ -94,14 +94,23 @@ int file_open(FileDescriptor *const ret_fp, const char *const fname,  /// @param[out]  ret_fp  Address where information needed for reading from or  ///                      writing to a file is saved  /// @param[in]  fd  File descriptor to wrap. -/// @param[in]  wr  True if fd is opened for writing only, false if it is read -///                 only. +/// @param[in]  flags  Flags, @see FileOpenFlags. Currently reading from and +///                    writing to the file at once is not supported, so either +///                    FILE_WRITE_ONLY or FILE_READ_ONLY is required.  ///  /// @return Error code (@see os_strerror()) or 0. Currently always returns 0. -int file_open_fd(FileDescriptor *const ret_fp, const int fd, const bool wr) +int file_open_fd(FileDescriptor *const ret_fp, const int fd, +                 const int flags)    FUNC_ATTR_NONNULL_ALL FUNC_ATTR_WARN_UNUSED_RESULT  { -  ret_fp->wr = wr; +  ret_fp->wr = !!(flags & (kFileCreate +                           |kFileCreateOnly +                           |kFileTruncate +                           |kFileAppend +                           |kFileWriteOnly)); +  ret_fp->non_blocking = !!(flags & kFileNonBlocking); +  // Non-blocking writes not supported currently. +  assert(!ret_fp->wr || !ret_fp->non_blocking);    ret_fp->fd = fd;    ret_fp->eof = false;    ret_fp->rv = rbuffer_new(kRWBufferSize); @@ -138,15 +147,17 @@ FileDescriptor *file_open_new(int *const error, const char *const fname,  ///  /// @param[out]  error  Error code, or 0 on success. @see os_strerror()  /// @param[in]  fd  File descriptor to wrap. -/// @param[in]  wr  True if fd is opened for writing only, false if it is read -///                 only. +/// @param[in]  flags  Flags, @see FileOpenFlags. +/// @param[in]  mode  Permissions for the newly created file (ignored if flags +///                   does not have FILE_CREATE\*).  ///  /// @return [allocated] Opened file or NULL in case of error. -FileDescriptor *file_open_fd_new(int *const error, const int fd, const bool wr) +FileDescriptor *file_open_fd_new(int *const error, const int fd, +                                 const int flags)    FUNC_ATTR_NONNULL_ALL FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT  {    FileDescriptor *const fp = xmalloc(sizeof(*fp)); -  if ((*error = file_open_fd(fp, fd, wr)) != 0) { +  if ((*error = file_open_fd(fp, fd, flags)) != 0) {      xfree(fp);      return NULL;    } @@ -244,7 +255,8 @@ static void file_rb_write_full_cb(RBuffer *const rv, FileDescriptor *const fp)      return;    }    const size_t read_bytes = rbuffer_read(rv, writebuf, kRWBufferSize); -  const ptrdiff_t wres = os_write(fp->fd, writebuf, read_bytes); +  const ptrdiff_t wres = os_write(fp->fd, writebuf, read_bytes, +                                  fp->non_blocking);    if (wres != (ptrdiff_t)read_bytes) {      if (wres >= 0) {        fp->_error = UV_EIO; @@ -270,6 +282,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,    char *buf = ret_buf;    size_t read_remaining = size;    RBuffer *const rv = fp->rv; +  bool called_read = false;    while (read_remaining) {      const size_t rv_size = rbuffer_size(rv);      if (rv_size > 0) { @@ -277,7 +290,9 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,        buf += rsize;        read_remaining -= rsize;      } -    if (fp->eof) { +    if (fp->eof +        // Allow only at most one os_read[v] call. +        || (called_read && fp->non_blocking)) {        break;      }      if (read_remaining) { @@ -294,7 +309,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,        };        assert(write_count == kRWBufferSize);        const ptrdiff_t r_ret = os_readv(fp->fd, &fp->eof, iov, -                                       ARRAY_SIZE(iov)); +                                       ARRAY_SIZE(iov), fp->non_blocking);        if (r_ret > 0) {          if (r_ret > (ptrdiff_t)read_remaining) {            rbuffer_produced(rv, (size_t)(r_ret - (ptrdiff_t)read_remaining)); @@ -310,7 +325,8 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,        if (read_remaining >= kRWBufferSize) {          // …otherwise leave RBuffer empty and populate only target buffer,          // because filtering information through rbuffer will be more syscalls. -        const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, buf, read_remaining); +        const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof, buf, read_remaining, +                                        fp->non_blocking);          if (r_ret >= 0) {            read_remaining -= (size_t)r_ret;            return (ptrdiff_t)(size - read_remaining); @@ -321,7 +337,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,          size_t write_count;          const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof,                                          rbuffer_write_ptr(rv, &write_count), -                                        kRWBufferSize); +                                        kRWBufferSize, fp->non_blocking);          assert(write_count == kRWBufferSize);          if (r_ret > 0) {            rbuffer_produced(rv, (size_t)r_ret); @@ -330,6 +346,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,          }        }  #endif +      called_read = true;      }    }    return (ptrdiff_t)(size - read_remaining); diff --git a/src/nvim/os/fileio.h b/src/nvim/os/fileio.h index 0b55cc695f..7c53cd4f07 100644 --- a/src/nvim/os/fileio.h +++ b/src/nvim/os/fileio.h @@ -14,6 +14,7 @@ typedef struct {    RBuffer *rv;  ///< Read or write buffer.    bool wr;  ///< True if file is in write mode.    bool eof;  ///< True if end of file was encountered. +  bool non_blocking;  ///< True if EAGAIN should not restart syscalls.  } FileDescriptor;  /// file_open() flags @@ -32,6 +33,8 @@ typedef enum {                         ///< kFileCreateOnly.    kFileAppend = 64,  ///< Append to the file. Implies kFileWriteOnly. Cannot                       ///< be used with kFileCreateOnly. +  kFileNonBlocking = 128,  ///< Do not restart read() or write() syscall if +                           ///< EAGAIN was encountered.  } FileOpenFlags;  static inline bool file_eof(const FileDescriptor *const fp) diff --git a/src/nvim/os/fs.c b/src/nvim/os/fs.c index b7c2714296..0414794d01 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -436,6 +436,29 @@ int os_close(const int fd)    return r;  } +/// Duplicate file descriptor +/// +/// @param[in]  fd  File descriptor to duplicate. +/// +/// @return New file descriptor or libuv error code (< 0). +int os_dup(const int fd) +  FUNC_ATTR_WARN_UNUSED_RESULT +{ +  int ret; +os_dup_dup: +  ret = dup(fd); +  if (ret < 0) { +    const int error = os_translate_sys_error(errno); +    errno = 0; +    if (error == UV_EINTR) { +      goto os_dup_dup; +    } else { +      return error; +    } +  } +  return ret; +} +  /// Read from a file  ///  /// Handles EINTR and ENOMEM, but not other errors. @@ -445,10 +468,11 @@ int os_close(const int fd)  ///                       to false. Initial value is ignored.  /// @param[out]  ret_buf  Buffer to write to. May be NULL if size is zero.  /// @param[in]  size  Amount of bytes to read. +/// @param[in]  non_blocking  Do not restart syscall if EAGAIN was encountered.  ///  /// @return Number of bytes read or libuv error code (< 0). -ptrdiff_t os_read(const int fd, bool *ret_eof, char *const ret_buf, -                  const size_t size) +ptrdiff_t os_read(const int fd, bool *const ret_eof, char *const ret_buf, +                  const size_t size, const bool non_blocking)    FUNC_ATTR_WARN_UNUSED_RESULT  {    *ret_eof = false; @@ -468,7 +492,9 @@ ptrdiff_t os_read(const int fd, bool *ret_eof, char *const ret_buf,      if (cur_read_bytes < 0) {        const int error = os_translate_sys_error(errno);        errno = 0; -      if (error == UV_EINTR || error == UV_EAGAIN) { +      if (non_blocking && error == UV_EAGAIN) { +        break; +      } else if (error == UV_EINTR || error == UV_EAGAIN) {          continue;        } else if (error == UV_ENOMEM && !did_try_to_free) {          try_to_free_memory(); @@ -498,7 +524,11 @@ ptrdiff_t os_read(const int fd, bool *ret_eof, char *const ret_buf,  ///                   may change, it is incorrect to use data it points to after  ///                   os_readv().  /// @param[in]  iov_size  Number of buffers in iov. -ptrdiff_t os_readv(int fd, bool *ret_eof, struct iovec *iov, size_t iov_size) +/// @param[in]  non_blocking  Do not restart syscall if EAGAIN was encountered. +/// +/// @return Number of bytes read or libuv error code (< 0). +ptrdiff_t os_readv(const int fd, bool *const ret_eof, struct iovec *iov, +                   size_t iov_size, const bool non_blocking)    FUNC_ATTR_NONNULL_ALL  {    *ret_eof = false; @@ -531,7 +561,9 @@ ptrdiff_t os_readv(int fd, bool *ret_eof, struct iovec *iov, size_t iov_size)      } else if (cur_read_bytes < 0) {        const int error = os_translate_sys_error(errno);        errno = 0; -      if (error == UV_EINTR || error == UV_EAGAIN) { +      if (non_blocking && error == UV_EAGAIN) { +        break; +      } else if (error == UV_EINTR || error == UV_EAGAIN) {          continue;        } else if (error == UV_ENOMEM && !did_try_to_free) {          try_to_free_memory(); @@ -551,9 +583,11 @@ ptrdiff_t os_readv(int fd, bool *ret_eof, struct iovec *iov, size_t iov_size)  /// @param[in]  fd  File descriptor to write to.  /// @param[in]  buf  Data to write. May be NULL if size is zero.  /// @param[in]  size  Amount of bytes to write. +/// @param[in]  non_blocking  Do not restart syscall if EAGAIN was encountered.  ///  /// @return Number of bytes written or libuv error code (< 0). -ptrdiff_t os_write(const int fd, const char *const buf, const size_t size) +ptrdiff_t os_write(const int fd, const char *const buf, const size_t size, +                   const bool non_blocking)    FUNC_ATTR_WARN_UNUSED_RESULT  {    if (buf == NULL) { @@ -571,7 +605,9 @@ ptrdiff_t os_write(const int fd, const char *const buf, const size_t size)      if (cur_written_bytes < 0) {        const int error = os_translate_sys_error(errno);        errno = 0; -      if (error == UV_EINTR || error == UV_EAGAIN) { +      if (non_blocking && error == UV_EAGAIN) { +        break; +      } else if (error == UV_EINTR || error == UV_EAGAIN) {          continue;        } else {          return error;  | 
