mirror of
https://github.com/neovim/neovim.git
synced 2026-04-28 18:24:13 +00:00
revert: "refactor(process): don't read from PTY master using uv_pipe_t" (#37401)
This reverts commit75c8f75501. (cherry picked from commit9c15a382de)
This commit is contained in:
committed by
github-actions[bot]
parent
2eb14c54bc
commit
ad0adbb1b2
@@ -78,15 +78,12 @@ typedef void (*stream_close_cb)(Stream *stream, void *data);
|
|||||||
|
|
||||||
struct stream {
|
struct stream {
|
||||||
bool closed;
|
bool closed;
|
||||||
bool use_poll;
|
|
||||||
union {
|
union {
|
||||||
uv_pipe_t pipe;
|
uv_pipe_t pipe;
|
||||||
uv_tcp_t tcp;
|
uv_tcp_t tcp;
|
||||||
uv_idle_t idle;
|
uv_idle_t idle;
|
||||||
#ifdef MSWIN
|
#ifdef MSWIN
|
||||||
uv_tty_t tty;
|
uv_tty_t tty;
|
||||||
#else
|
|
||||||
uv_poll_t poll;
|
|
||||||
#endif
|
#endif
|
||||||
} uv;
|
} uv;
|
||||||
uv_stream_t *uvstream; ///< NULL when the stream is a file
|
uv_stream_t *uvstream; ///< NULL when the stream is a file
|
||||||
|
|||||||
@@ -45,16 +45,6 @@ int proc_spawn(Proc *proc, bool in, bool out, bool err)
|
|||||||
// forwarding stderr contradicts with processing it internally
|
// forwarding stderr contradicts with processing it internally
|
||||||
assert(!(err && proc->fwd_err));
|
assert(!(err && proc->fwd_err));
|
||||||
|
|
||||||
#ifdef MSWIN
|
|
||||||
const bool out_use_poll = false;
|
|
||||||
#else
|
|
||||||
// Using uv_pipe_t to read from PTY master may drop data if the PTY process exits
|
|
||||||
// immediately after output, as libuv treats a partial read after POLLHUP as EOF,
|
|
||||||
// which isn't true for PTY master on Linux. Therefore use uv_poll_t instead. #3030
|
|
||||||
// Ref: https://github.com/libuv/libuv/issues/4992
|
|
||||||
const bool out_use_poll = proc->type == kProcTypePty;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (in) {
|
if (in) {
|
||||||
uv_pipe_init(&proc->loop->uv, &proc->in.uv.pipe, 0);
|
uv_pipe_init(&proc->loop->uv, &proc->in.uv.pipe, 0);
|
||||||
} else {
|
} else {
|
||||||
@@ -62,9 +52,7 @@ int proc_spawn(Proc *proc, bool in, bool out, bool err)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (out) {
|
if (out) {
|
||||||
if (!out_use_poll) {
|
uv_pipe_init(&proc->loop->uv, &proc->out.s.uv.pipe, 0);
|
||||||
uv_pipe_init(&proc->loop->uv, &proc->out.s.uv.pipe, 0);
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
proc->out.s.closed = true;
|
proc->out.s.closed = true;
|
||||||
}
|
}
|
||||||
@@ -94,7 +82,7 @@ int proc_spawn(Proc *proc, bool in, bool out, bool err)
|
|||||||
if (in) {
|
if (in) {
|
||||||
uv_close((uv_handle_t *)&proc->in.uv.pipe, NULL);
|
uv_close((uv_handle_t *)&proc->in.uv.pipe, NULL);
|
||||||
}
|
}
|
||||||
if (out && !out_use_poll) {
|
if (out) {
|
||||||
uv_close((uv_handle_t *)&proc->out.s.uv.pipe, NULL);
|
uv_close((uv_handle_t *)&proc->out.s.uv.pipe, NULL);
|
||||||
}
|
}
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -112,29 +100,21 @@ int proc_spawn(Proc *proc, bool in, bool out, bool err)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (in) {
|
if (in) {
|
||||||
stream_init(NULL, &proc->in, -1, false, (uv_stream_t *)&proc->in.uv.pipe);
|
stream_init(NULL, &proc->in, -1, (uv_stream_t *)&proc->in.uv.pipe);
|
||||||
proc->in.internal_data = proc;
|
proc->in.internal_data = proc;
|
||||||
proc->in.internal_close_cb = on_proc_stream_close;
|
proc->in.internal_close_cb = on_proc_stream_close;
|
||||||
proc->refcount++;
|
proc->refcount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (out) {
|
if (out) {
|
||||||
if (out_use_poll) {
|
stream_init(NULL, &proc->out.s, -1, (uv_stream_t *)&proc->out.s.uv.pipe);
|
||||||
#ifdef MSWIN
|
|
||||||
abort();
|
|
||||||
#else
|
|
||||||
stream_init(proc->loop, &proc->out.s, ((PtyProc *)proc)->tty_fd, true, NULL);
|
|
||||||
#endif
|
|
||||||
} else {
|
|
||||||
stream_init(NULL, &proc->out.s, -1, false, (uv_stream_t *)&proc->out.s.uv.pipe);
|
|
||||||
}
|
|
||||||
proc->out.s.internal_data = proc;
|
proc->out.s.internal_data = proc;
|
||||||
proc->out.s.internal_close_cb = on_proc_stream_close;
|
proc->out.s.internal_close_cb = on_proc_stream_close;
|
||||||
proc->refcount++;
|
proc->refcount++;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
stream_init(NULL, &proc->err.s, -1, false, (uv_stream_t *)&proc->err.s.uv.pipe);
|
stream_init(NULL, &proc->err.s, -1, (uv_stream_t *)&proc->err.s.uv.pipe);
|
||||||
proc->err.s.internal_data = proc;
|
proc->err.s.internal_data = proc;
|
||||||
proc->err.s.internal_close_cb = on_proc_stream_close;
|
proc->err.s.internal_close_cb = on_proc_stream_close;
|
||||||
proc->refcount++;
|
proc->refcount++;
|
||||||
|
|||||||
@@ -13,25 +13,19 @@
|
|||||||
#include "nvim/os/os_defs.h"
|
#include "nvim/os/os_defs.h"
|
||||||
#include "nvim/types_defs.h"
|
#include "nvim/types_defs.h"
|
||||||
|
|
||||||
#ifndef MSWIN
|
|
||||||
# include <errno.h>
|
|
||||||
|
|
||||||
# include "nvim/fileio.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "event/rstream.c.generated.h"
|
#include "event/rstream.c.generated.h"
|
||||||
|
|
||||||
void rstream_init_fd(Loop *loop, RStream *stream, int fd)
|
void rstream_init_fd(Loop *loop, RStream *stream, int fd)
|
||||||
FUNC_ATTR_NONNULL_ARG(1, 2)
|
FUNC_ATTR_NONNULL_ARG(1, 2)
|
||||||
{
|
{
|
||||||
stream_init(loop, &stream->s, fd, false, NULL);
|
stream_init(loop, &stream->s, fd, NULL);
|
||||||
rstream_init(stream);
|
rstream_init(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rstream_init_stream(RStream *stream, uv_stream_t *uvstream)
|
void rstream_init_stream(RStream *stream, uv_stream_t *uvstream)
|
||||||
FUNC_ATTR_NONNULL_ARG(1, 2)
|
FUNC_ATTR_NONNULL_ARG(1, 2)
|
||||||
{
|
{
|
||||||
stream_init(NULL, &stream->s, -1, false, uvstream);
|
stream_init(NULL, &stream->s, -1, uvstream);
|
||||||
rstream_init(stream);
|
rstream_init(stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -51,10 +45,6 @@ void rstream_start_inner(RStream *stream)
|
|||||||
{
|
{
|
||||||
if (stream->s.uvstream) {
|
if (stream->s.uvstream) {
|
||||||
uv_read_start(stream->s.uvstream, alloc_cb, read_cb);
|
uv_read_start(stream->s.uvstream, alloc_cb, read_cb);
|
||||||
#ifndef MSWIN
|
|
||||||
} else if (stream->s.use_poll) {
|
|
||||||
uv_poll_start(&stream->s.uv.poll, UV_READABLE, poll_cb);
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
uv_idle_start(&stream->s.uv.idle, fread_idle_cb);
|
uv_idle_start(&stream->s.uv.idle, fread_idle_cb);
|
||||||
}
|
}
|
||||||
@@ -82,10 +72,6 @@ void rstream_stop_inner(RStream *stream)
|
|||||||
{
|
{
|
||||||
if (stream->s.uvstream) {
|
if (stream->s.uvstream) {
|
||||||
uv_read_stop(stream->s.uvstream);
|
uv_read_stop(stream->s.uvstream);
|
||||||
#ifndef MSWIN
|
|
||||||
} else if (stream->s.use_poll) {
|
|
||||||
uv_poll_stop(&stream->s.uv.poll);
|
|
||||||
#endif
|
|
||||||
} else {
|
} else {
|
||||||
uv_idle_stop(&stream->s.uv.idle);
|
uv_idle_stop(&stream->s.uv.idle);
|
||||||
}
|
}
|
||||||
@@ -185,46 +171,6 @@ static void fread_idle_cb(uv_idle_t *handle)
|
|||||||
invoke_read_cb(stream, false);
|
invoke_read_cb(stream, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef MSWIN
|
|
||||||
static void poll_cb(uv_poll_t *handle, int status, int events)
|
|
||||||
{
|
|
||||||
RStream *stream = handle->data;
|
|
||||||
|
|
||||||
if (status < 0) {
|
|
||||||
ELOG("poll error on Stream (%p) with descriptor %d: %s (%s)", (void *)stream,
|
|
||||||
stream->s.fd, uv_err_name(status), os_strerror(status));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!(events & UV_READABLE)) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t cnt = read_eintr(stream->s.fd, stream->write_pos, rstream_space(stream));
|
|
||||||
|
|
||||||
if (cnt < 0) {
|
|
||||||
if (errno == EAGAIN || errno == EWOULDBLOCK) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
DLOG("closing Stream (%p) with descriptor %d: %s", (void *)stream,
|
|
||||||
stream->s.fd, strerror(errno));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cnt <= 0) {
|
|
||||||
// Read error or EOF, either way stop the stream and invoke the callback
|
|
||||||
// with eof == true
|
|
||||||
uv_poll_stop(handle);
|
|
||||||
invoke_read_cb(stream, true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// at this point we're sure that cnt is positive, no error occurred
|
|
||||||
size_t nread = (size_t)cnt;
|
|
||||||
stream->num_bytes += nread;
|
|
||||||
stream->write_pos += cnt;
|
|
||||||
invoke_read_cb(stream, false);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static void read_event(void **argv)
|
static void read_event(void **argv)
|
||||||
{
|
{
|
||||||
RStream *stream = argv[0];
|
RStream *stream = argv[0];
|
||||||
|
|||||||
@@ -239,7 +239,7 @@ int socket_watcher_accept(SocketWatcher *watcher, RStream *stream)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
stream_init(NULL, &stream->s, -1, false, client);
|
stream_init(NULL, &stream->s, -1, client);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,7 +332,7 @@ tcp_retry:
|
|||||||
status = 1;
|
status = 1;
|
||||||
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, timeout, status != 1);
|
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, timeout, status != 1);
|
||||||
if (status == 0) {
|
if (status == 0) {
|
||||||
stream_init(NULL, &stream->s, -1, false, uv_stream);
|
stream_init(NULL, &stream->s, -1, uv_stream);
|
||||||
assert(uv_stream->data != &closed); // Should have been set by stream_init().
|
assert(uv_stream->data != &closed); // Should have been set by stream_init().
|
||||||
success = true;
|
success = true;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -40,14 +40,11 @@ int stream_set_blocking(int fd, bool blocking)
|
|||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
void stream_init(Loop *loop, Stream *stream, int fd, bool poll, uv_stream_t *uvstream)
|
void stream_init(Loop *loop, Stream *stream, int fd, uv_stream_t *uvstream)
|
||||||
FUNC_ATTR_NONNULL_ARG(2)
|
FUNC_ATTR_NONNULL_ARG(2)
|
||||||
{
|
{
|
||||||
// The underlying stream is either a file or an existing uv stream.
|
// The underlying stream is either a file or an existing uv stream.
|
||||||
assert(uvstream == NULL ? fd >= 0 && loop != NULL : fd < 0 && loop == NULL && !poll);
|
assert(uvstream == NULL ? fd >= 0 && loop != NULL : fd < 0 && loop == NULL);
|
||||||
#ifdef MSWIN
|
|
||||||
assert(!poll);
|
|
||||||
#endif
|
|
||||||
stream->uvstream = uvstream;
|
stream->uvstream = uvstream;
|
||||||
|
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
@@ -55,7 +52,6 @@ void stream_init(Loop *loop, Stream *stream, int fd, bool poll, uv_stream_t *uvs
|
|||||||
stream->fd = fd;
|
stream->fd = fd;
|
||||||
|
|
||||||
if (type == UV_FILE) {
|
if (type == UV_FILE) {
|
||||||
assert(!poll);
|
|
||||||
// Non-blocking file reads are simulated with an idle handle that reads in
|
// Non-blocking file reads are simulated with an idle handle that reads in
|
||||||
// chunks of the ring buffer size, giving time for other events to be
|
// chunks of the ring buffer size, giving time for other events to be
|
||||||
// processed between reads.
|
// processed between reads.
|
||||||
@@ -71,11 +67,6 @@ void stream_init(Loop *loop, Stream *stream, int fd, bool poll, uv_stream_t *uvs
|
|||||||
SetConsoleMode(stream->uv.tty.handle, dwMode);
|
SetConsoleMode(stream->uv.tty.handle, dwMode);
|
||||||
}
|
}
|
||||||
stream->uvstream = (uv_stream_t *)&stream->uv.tty;
|
stream->uvstream = (uv_stream_t *)&stream->uv.tty;
|
||||||
#else
|
|
||||||
} else if (poll) {
|
|
||||||
uv_poll_init(&loop->uv, &stream->uv.poll, fd);
|
|
||||||
stream->uv.poll.data = stream;
|
|
||||||
stream->use_poll = true;
|
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
assert(type == UV_NAMED_PIPE || type == UV_TTY);
|
assert(type == UV_NAMED_PIPE || type == UV_TTY);
|
||||||
@@ -134,8 +125,7 @@ void stream_close_handle(Stream *stream)
|
|||||||
}
|
}
|
||||||
handle = (uv_handle_t *)stream->uvstream;
|
handle = (uv_handle_t *)stream->uvstream;
|
||||||
} else {
|
} else {
|
||||||
// All members of the stream->uv union share the same address.
|
handle = (uv_handle_t *)&stream->uv.idle;
|
||||||
handle = (uv_handle_t *)&stream->uv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
assert(handle != NULL);
|
assert(handle != NULL);
|
||||||
|
|||||||
@@ -23,14 +23,14 @@ typedef struct {
|
|||||||
void wstream_init_fd(Loop *loop, Stream *stream, int fd, size_t maxmem)
|
void wstream_init_fd(Loop *loop, Stream *stream, int fd, size_t maxmem)
|
||||||
FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2)
|
FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2)
|
||||||
{
|
{
|
||||||
stream_init(loop, stream, fd, false, NULL);
|
stream_init(loop, stream, fd, NULL);
|
||||||
wstream_init(stream, maxmem);
|
wstream_init(stream, maxmem);
|
||||||
}
|
}
|
||||||
|
|
||||||
void wstream_init_stream(Stream *stream, uv_stream_t *uvstream, size_t maxmem)
|
void wstream_init_stream(Stream *stream, uv_stream_t *uvstream, size_t maxmem)
|
||||||
FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2)
|
FUNC_ATTR_NONNULL_ARG(1) FUNC_ATTR_NONNULL_ARG(2)
|
||||||
{
|
{
|
||||||
stream_init(NULL, stream, -1, false, uvstream);
|
stream_init(NULL, stream, -1, uvstream);
|
||||||
wstream_init(stream, maxmem);
|
wstream_init(stream, maxmem);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,7 +68,6 @@ int wstream_write(Stream *stream, WBuffer *buffer)
|
|||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
assert(stream->maxmem);
|
assert(stream->maxmem);
|
||||||
assert(!stream->use_poll);
|
|
||||||
// This should not be called after a stream was freed
|
// This should not be called after a stream was freed
|
||||||
assert(!stream->closed);
|
assert(!stream->closed);
|
||||||
|
|
||||||
|
|||||||
@@ -217,7 +217,10 @@ int pty_proc_spawn(PtyProc *ptyproc)
|
|||||||
&& (status = set_duplicating_descriptor(master, &proc->in.uv.pipe))) {
|
&& (status = set_duplicating_descriptor(master, &proc->in.uv.pipe))) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
// The stream_init() call in proc_spawn() will initialize proc->out.s.uv.poll.
|
if (!proc->out.s.closed
|
||||||
|
&& (status = set_duplicating_descriptor(master, &proc->out.s.uv.pipe))) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
ptyproc->tty_fd = master;
|
ptyproc->tty_fd = master;
|
||||||
proc->pid = pid;
|
proc->pid = pid;
|
||||||
|
|||||||
Reference in New Issue
Block a user