diff options
author | ZyX <kp-pav@yandex.ru> | 2017-03-19 17:29:48 +0300 |
---|---|---|
committer | ZyX <kp-pav@yandex.ru> | 2017-03-19 17:29:48 +0300 |
commit | e78e75d85d91e9f14964465ea136b3899b774d6e (patch) | |
tree | 619520179b6a24aa62586e8a862a6df8f371fedc | |
parent | bd798a3267a496c644b339c45189b09e2a952014 (diff) | |
download | rneovim-e78e75d85d91e9f14964465ea136b3899b774d6e.tar.gz rneovim-e78e75d85d91e9f14964465ea136b3899b774d6e.tar.bz2 rneovim-e78e75d85d91e9f14964465ea136b3899b774d6e.zip |
fileio,main: Do not restart syscall at EAGAIN when reading for -s
-rw-r--r-- | src/nvim/getchar.c | 4 | ||||
-rw-r--r-- | src/nvim/main.c | 4 | ||||
-rw-r--r-- | src/nvim/os/fileio.c | 38 | ||||
-rw-r--r-- | src/nvim/os/fileio.h | 3 | ||||
-rw-r--r-- | src/nvim/os/fs.c | 27 | ||||
-rw-r--r-- | test/unit/os/fs_spec.lua | 6 |
6 files changed, 55 insertions, 27 deletions
diff --git a/src/nvim/getchar.c b/src/nvim/getchar.c index b6e235146e..4ea8eb0513 100644 --- a/src/nvim/getchar.c +++ b/src/nvim/getchar.c @@ -2375,7 +2375,7 @@ inchar ( // 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) { + 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) { @@ -2397,7 +2397,7 @@ inchar ( } } - if (read_size < 0) { // Did not get a character from script. + 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, diff --git a/src/nvim/main.c b/src/nvim/main.c index da3ec4381e..8114164158 100644 --- a/src/nvim/main.c +++ b/src/nvim/main.c @@ -1060,11 +1060,11 @@ scripterror: if (STRCMP(argv[0], "-") == 0) { const int stdin_dup_fd = os_dup(OS_STDIN_FILENO); FileDescriptor *const stdin_dup = file_open_fd_new( - &error, stdin_dup_fd, false, 0); + &error, stdin_dup_fd, kFileReadOnly|kFileNonBlocking, 0); assert(stdin_dup != NULL); scriptin[0] = stdin_dup; } else if ((scriptin[0] = file_open_new( - &error, argv[0], kFileReadOnly, 0)) == NULL) { + &error, argv[0], kFileReadOnly|kFileNonBlocking, 0)) == NULL) { mch_errmsg(_("Cannot open for reading: \"")); mch_errmsg(argv[0]); mch_errmsg("\": "); diff --git a/src/nvim/os/fileio.c b/src/nvim/os/fileio.c index 3742fd53de..70ed49c3aa 100644 --- a/src/nvim/os/fileio.c +++ b/src/nvim/os/fileio.c @@ -74,7 +74,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), mode); + return file_open_fd(ret_fp, fd, flags, mode); } /// Wrap file descriptor with FileDescriptor structure @@ -85,17 +85,24 @@ 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. /// @param[in] mode Permissions for the newly created file (ignored if flags /// does not have FILE_CREATE\*). /// /// @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, const int mode) + const int flags, const int mode) 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); @@ -134,18 +141,17 @@ FileDescriptor *file_open_new(int *const error, const char *const fname, /// @param[out] error Error code, @see os_strerror(). Is set to zero on /// success. /// @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, const int mode) + const int flags, const int mode) 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, mode)) != 0) { + if ((*error = file_open_fd(fp, fd, flags, mode)) != 0) { xfree(fp); return NULL; } @@ -224,7 +230,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; @@ -274,7 +281,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)); @@ -290,7 +297,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); @@ -301,7 +309,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); @@ -311,6 +319,10 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf, } #endif } + if (fp->non_blocking) { + // Allow only at most one os_read[v] call. + break; + } } 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 9ce50d4afd..383a2ac682 100644 --- a/src/nvim/os/fs.c +++ b/src/nvim/os/fs.c @@ -462,10 +462,11 @@ os_dup_dup: /// 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; @@ -485,7 +486,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(); @@ -515,7 +518,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; @@ -548,7 +555,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(); @@ -568,9 +577,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) { @@ -588,7 +599,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; diff --git a/test/unit/os/fs_spec.lua b/test/unit/os/fs_spec.lua index b03040260f..5f8be93aad 100644 --- a/test/unit/os/fs_spec.lua +++ b/test/unit/os/fs_spec.lua @@ -382,7 +382,7 @@ describe('fs function', function() buf = ffi.new('char[?]', size + 1, ('\0'):rep(size)) end local eof = ffi.new('bool[?]', 1, {true}) - local ret2 = fs.os_read(fd, eof, buf, size) + local ret2 = fs.os_read(fd, eof, buf, size, false) local ret1 = eof[0] local ret3 = '' if buf ~= nil then @@ -400,7 +400,7 @@ describe('fs function', function() end local iov = ffi.new('struct iovec[?]', #sizes, bufs) local eof = ffi.new('bool[?]', 1, {true}) - local ret2 = fs.os_readv(fd, eof, iov, #sizes) + local ret2 = fs.os_readv(fd, eof, iov, #sizes, false) local ret1 = eof[0] local ret3 = {} for i = 1,#sizes do @@ -410,7 +410,7 @@ describe('fs function', function() return ret1, ret2, ret3 end local function os_write(fd, data) - return fs.os_write(fd, data, data and #data or 0) + return fs.os_write(fd, data, data and #data or 0, false) end describe('os_path_exists', function() |