mirror of
https://github.com/neovim/neovim.git
synced 2025-09-07 11:58:17 +00:00
fileio,main: Do not restart syscall at EAGAIN when reading for -s
This commit is contained in:
@@ -2375,7 +2375,7 @@ inchar (
|
|||||||
// Get a character from a script file if there is one.
|
// Get a character from a script file if there is one.
|
||||||
// If interrupted: Stop reading script files, close them all.
|
// If interrupted: Stop reading script files, close them all.
|
||||||
ptrdiff_t read_size = -1;
|
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;
|
char script_char;
|
||||||
if (got_int
|
if (got_int
|
||||||
|| (read_size = file_read(scriptin[curscript], &script_char, 1)) != 1) {
|
|| (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
|
// If we got an interrupt, skip all previously typed characters and
|
||||||
// return TRUE if quit reading script file.
|
// return TRUE if quit reading script file.
|
||||||
// Stop reading typeahead when a single CTRL-C was read,
|
// Stop reading typeahead when a single CTRL-C was read,
|
||||||
|
@@ -1060,11 +1060,11 @@ scripterror:
|
|||||||
if (STRCMP(argv[0], "-") == 0) {
|
if (STRCMP(argv[0], "-") == 0) {
|
||||||
const int stdin_dup_fd = os_dup(OS_STDIN_FILENO);
|
const int stdin_dup_fd = os_dup(OS_STDIN_FILENO);
|
||||||
FileDescriptor *const stdin_dup = file_open_fd_new(
|
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);
|
assert(stdin_dup != NULL);
|
||||||
scriptin[0] = stdin_dup;
|
scriptin[0] = stdin_dup;
|
||||||
} else if ((scriptin[0] = file_open_new(
|
} 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(_("Cannot open for reading: \""));
|
||||||
mch_errmsg(argv[0]);
|
mch_errmsg(argv[0]);
|
||||||
mch_errmsg("\": ");
|
mch_errmsg("\": ");
|
||||||
|
@@ -74,7 +74,7 @@ int file_open(FileDescriptor *const ret_fp, const char *const fname,
|
|||||||
if (fd < 0) {
|
if (fd < 0) {
|
||||||
return fd;
|
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
|
/// 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
|
/// @param[out] ret_fp Address where information needed for reading from or
|
||||||
/// writing to a file is saved
|
/// writing to a file is saved
|
||||||
/// @param[in] fd File descriptor to wrap.
|
/// @param[in] fd File descriptor to wrap.
|
||||||
/// @param[in] wr True if fd is opened for writing only, false if it is read
|
/// @param[in] flags Flags, @see FileOpenFlags. Currently reading from and
|
||||||
/// only.
|
/// 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
|
/// @param[in] mode Permissions for the newly created file (ignored if flags
|
||||||
/// does not have FILE_CREATE\*).
|
/// does not have FILE_CREATE\*).
|
||||||
///
|
///
|
||||||
/// @return Error code (@see os_strerror()) or 0. Currently always returns 0.
|
/// @return Error code (@see os_strerror()) or 0. Currently always returns 0.
|
||||||
int file_open_fd(FileDescriptor *const ret_fp, const int fd,
|
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
|
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->fd = fd;
|
||||||
ret_fp->eof = false;
|
ret_fp->eof = false;
|
||||||
ret_fp->rv = rbuffer_new(kRWBufferSize);
|
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
|
/// @param[out] error Error code, @see os_strerror(). Is set to zero on
|
||||||
/// success.
|
/// success.
|
||||||
/// @param[in] fd File descriptor to wrap.
|
/// @param[in] fd File descriptor to wrap.
|
||||||
/// @param[in] wr True if fd is opened for writing only, false if it is read
|
/// @param[in] flags Flags, @see FileOpenFlags.
|
||||||
/// only.
|
|
||||||
/// @param[in] mode Permissions for the newly created file (ignored if flags
|
/// @param[in] mode Permissions for the newly created file (ignored if flags
|
||||||
/// does not have FILE_CREATE\*).
|
/// does not have FILE_CREATE\*).
|
||||||
///
|
///
|
||||||
/// @return [allocated] Opened file or NULL in case of error.
|
/// @return [allocated] Opened file or NULL in case of error.
|
||||||
FileDescriptor *file_open_fd_new(int *const error, const int fd,
|
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
|
FUNC_ATTR_NONNULL_ALL FUNC_ATTR_MALLOC FUNC_ATTR_WARN_UNUSED_RESULT
|
||||||
{
|
{
|
||||||
FileDescriptor *const fp = xmalloc(sizeof(*fp));
|
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);
|
xfree(fp);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -224,7 +230,8 @@ static void file_rb_write_full_cb(RBuffer *const rv, FileDescriptor *const fp)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const size_t read_bytes = rbuffer_read(rv, writebuf, kRWBufferSize);
|
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 != (ptrdiff_t)read_bytes) {
|
||||||
if (wres >= 0) {
|
if (wres >= 0) {
|
||||||
fp->_error = UV_EIO;
|
fp->_error = UV_EIO;
|
||||||
@@ -274,7 +281,7 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,
|
|||||||
};
|
};
|
||||||
assert(write_count == kRWBufferSize);
|
assert(write_count == kRWBufferSize);
|
||||||
const ptrdiff_t r_ret = os_readv(fp->fd, &fp->eof, iov,
|
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 > 0) {
|
||||||
if (r_ret > (ptrdiff_t)read_remaining) {
|
if (r_ret > (ptrdiff_t)read_remaining) {
|
||||||
rbuffer_produced(rv, (size_t)(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) {
|
if (read_remaining >= kRWBufferSize) {
|
||||||
// …otherwise leave RBuffer empty and populate only target buffer,
|
// …otherwise leave RBuffer empty and populate only target buffer,
|
||||||
// because filtering information through rbuffer will be more syscalls.
|
// 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) {
|
if (r_ret >= 0) {
|
||||||
read_remaining -= (size_t)r_ret;
|
read_remaining -= (size_t)r_ret;
|
||||||
return (ptrdiff_t)(size - read_remaining);
|
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;
|
size_t write_count;
|
||||||
const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof,
|
const ptrdiff_t r_ret = os_read(fp->fd, &fp->eof,
|
||||||
rbuffer_write_ptr(rv, &write_count),
|
rbuffer_write_ptr(rv, &write_count),
|
||||||
kRWBufferSize);
|
kRWBufferSize, fp->non_blocking);
|
||||||
assert(write_count == kRWBufferSize);
|
assert(write_count == kRWBufferSize);
|
||||||
if (r_ret > 0) {
|
if (r_ret > 0) {
|
||||||
rbuffer_produced(rv, (size_t)r_ret);
|
rbuffer_produced(rv, (size_t)r_ret);
|
||||||
@@ -311,6 +319,10 @@ ptrdiff_t file_read(FileDescriptor *const fp, char *const ret_buf,
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
if (fp->non_blocking) {
|
||||||
|
// Allow only at most one os_read[v] call.
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return (ptrdiff_t)(size - read_remaining);
|
return (ptrdiff_t)(size - read_remaining);
|
||||||
}
|
}
|
||||||
|
@@ -14,6 +14,7 @@ typedef struct {
|
|||||||
RBuffer *rv; ///< Read or write buffer.
|
RBuffer *rv; ///< Read or write buffer.
|
||||||
bool wr; ///< True if file is in write mode.
|
bool wr; ///< True if file is in write mode.
|
||||||
bool eof; ///< True if end of file was encountered.
|
bool eof; ///< True if end of file was encountered.
|
||||||
|
bool non_blocking; ///< True if EAGAIN should not restart syscalls.
|
||||||
} FileDescriptor;
|
} FileDescriptor;
|
||||||
|
|
||||||
/// file_open() flags
|
/// file_open() flags
|
||||||
@@ -32,6 +33,8 @@ typedef enum {
|
|||||||
///< kFileCreateOnly.
|
///< kFileCreateOnly.
|
||||||
kFileAppend = 64, ///< Append to the file. Implies kFileWriteOnly. Cannot
|
kFileAppend = 64, ///< Append to the file. Implies kFileWriteOnly. Cannot
|
||||||
///< be used with kFileCreateOnly.
|
///< be used with kFileCreateOnly.
|
||||||
|
kFileNonBlocking = 128, ///< Do not restart read() or write() syscall if
|
||||||
|
///< EAGAIN was encountered.
|
||||||
} FileOpenFlags;
|
} FileOpenFlags;
|
||||||
|
|
||||||
static inline bool file_eof(const FileDescriptor *const fp)
|
static inline bool file_eof(const FileDescriptor *const fp)
|
||||||
|
@@ -462,10 +462,11 @@ os_dup_dup:
|
|||||||
/// to false. Initial value is ignored.
|
/// to false. Initial value is ignored.
|
||||||
/// @param[out] ret_buf Buffer to write to. May be NULL if size is zero.
|
/// @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] 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).
|
/// @return Number of bytes read or libuv error code (< 0).
|
||||||
ptrdiff_t os_read(const int fd, bool *ret_eof, char *const ret_buf,
|
ptrdiff_t os_read(const int fd, bool *const ret_eof, char *const ret_buf,
|
||||||
const size_t size)
|
const size_t size, const bool non_blocking)
|
||||||
FUNC_ATTR_WARN_UNUSED_RESULT
|
FUNC_ATTR_WARN_UNUSED_RESULT
|
||||||
{
|
{
|
||||||
*ret_eof = false;
|
*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) {
|
if (cur_read_bytes < 0) {
|
||||||
const int error = os_translate_sys_error(errno);
|
const int error = os_translate_sys_error(errno);
|
||||||
errno = 0;
|
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;
|
continue;
|
||||||
} else if (error == UV_ENOMEM && !did_try_to_free) {
|
} else if (error == UV_ENOMEM && !did_try_to_free) {
|
||||||
try_to_free_memory();
|
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
|
/// may change, it is incorrect to use data it points to after
|
||||||
/// os_readv().
|
/// os_readv().
|
||||||
/// @param[in] iov_size Number of buffers in iov.
|
/// @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
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
*ret_eof = false;
|
*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) {
|
} else if (cur_read_bytes < 0) {
|
||||||
const int error = os_translate_sys_error(errno);
|
const int error = os_translate_sys_error(errno);
|
||||||
errno = 0;
|
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;
|
continue;
|
||||||
} else if (error == UV_ENOMEM && !did_try_to_free) {
|
} else if (error == UV_ENOMEM && !did_try_to_free) {
|
||||||
try_to_free_memory();
|
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] fd File descriptor to write to.
|
||||||
/// @param[in] buf Data to write. May be NULL if size is zero.
|
/// @param[in] buf Data to write. May be NULL if size is zero.
|
||||||
/// @param[in] size Amount of bytes to write.
|
/// @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).
|
/// @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
|
FUNC_ATTR_WARN_UNUSED_RESULT
|
||||||
{
|
{
|
||||||
if (buf == NULL) {
|
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) {
|
if (cur_written_bytes < 0) {
|
||||||
const int error = os_translate_sys_error(errno);
|
const int error = os_translate_sys_error(errno);
|
||||||
errno = 0;
|
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;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
return error;
|
return error;
|
||||||
|
@@ -382,7 +382,7 @@ describe('fs function', function()
|
|||||||
buf = ffi.new('char[?]', size + 1, ('\0'):rep(size))
|
buf = ffi.new('char[?]', size + 1, ('\0'):rep(size))
|
||||||
end
|
end
|
||||||
local eof = ffi.new('bool[?]', 1, {true})
|
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 ret1 = eof[0]
|
||||||
local ret3 = ''
|
local ret3 = ''
|
||||||
if buf ~= nil then
|
if buf ~= nil then
|
||||||
@@ -400,7 +400,7 @@ describe('fs function', function()
|
|||||||
end
|
end
|
||||||
local iov = ffi.new('struct iovec[?]', #sizes, bufs)
|
local iov = ffi.new('struct iovec[?]', #sizes, bufs)
|
||||||
local eof = ffi.new('bool[?]', 1, {true})
|
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 ret1 = eof[0]
|
||||||
local ret3 = {}
|
local ret3 = {}
|
||||||
for i = 1,#sizes do
|
for i = 1,#sizes do
|
||||||
@@ -410,7 +410,7 @@ describe('fs function', function()
|
|||||||
return ret1, ret2, ret3
|
return ret1, ret2, ret3
|
||||||
end
|
end
|
||||||
local function os_write(fd, data)
|
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
|
end
|
||||||
|
|
||||||
describe('os_path_exists', function()
|
describe('os_path_exists', function()
|
||||||
|
Reference in New Issue
Block a user