mirror of
https://github.com/neovim/neovim.git
synced 2026-04-19 05:50:39 +00:00
fix(channel): possible hang after connecting with TCP times out (#37813)
Problem: Possible hang after connecting with TCP times out. Solution: Wait for the close callback to arrive.
This commit is contained in:
committed by
github-actions[bot]
parent
3a94763124
commit
7281cf883e
@@ -79,6 +79,13 @@ int socket_watcher_init(Loop *loop, SocketWatcher *watcher, const char *endpoint
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Callback for closing a handle initialized by socket_connect().
|
||||||
|
static void connect_close_cb(uv_handle_t *handle)
|
||||||
|
{
|
||||||
|
bool *closed = handle->data;
|
||||||
|
*closed = true;
|
||||||
|
}
|
||||||
|
|
||||||
int socket_watcher_start(SocketWatcher *watcher, int backlog, socket_cb cb)
|
int socket_watcher_start(SocketWatcher *watcher, int backlog, socket_cb cb)
|
||||||
FUNC_ATTR_NONNULL_ALL
|
FUNC_ATTR_NONNULL_ALL
|
||||||
{
|
{
|
||||||
@@ -194,7 +201,7 @@ static void connect_cb(uv_connect_t *req, int status)
|
|||||||
*ret_status = status;
|
*ret_status = status;
|
||||||
uv_handle_t *handle = (uv_handle_t *)req->handle;
|
uv_handle_t *handle = (uv_handle_t *)req->handle;
|
||||||
if (status != 0 && !uv_is_closing(handle)) {
|
if (status != 0 && !uv_is_closing(handle)) {
|
||||||
uv_close(handle, NULL);
|
uv_close(handle, connect_close_cb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -202,6 +209,7 @@ bool socket_connect(Loop *loop, RStream *stream, bool is_tcp, const char *addres
|
|||||||
const char **error)
|
const char **error)
|
||||||
{
|
{
|
||||||
bool success = false;
|
bool success = false;
|
||||||
|
bool closed;
|
||||||
int status;
|
int status;
|
||||||
uv_connect_t req;
|
uv_connect_t req;
|
||||||
req.data = &status;
|
req.data = &status;
|
||||||
@@ -243,21 +251,21 @@ tcp_retry:
|
|||||||
uv_pipe_connect(&req, pipe, address, connect_cb);
|
uv_pipe_connect(&req, pipe, address, connect_cb);
|
||||||
uv_stream = (uv_stream_t *)pipe;
|
uv_stream = (uv_stream_t *)pipe;
|
||||||
}
|
}
|
||||||
|
uv_stream->data = &closed;
|
||||||
|
closed = false;
|
||||||
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, uv_stream);
|
stream_init(NULL, &stream->s, -1, uv_stream);
|
||||||
|
assert(uv_stream->data != &closed); // Should have been set by stream_init().
|
||||||
success = true;
|
success = true;
|
||||||
} else {
|
} else {
|
||||||
if (!uv_is_closing((uv_handle_t *)uv_stream)) {
|
if (!uv_is_closing((uv_handle_t *)uv_stream)) {
|
||||||
uv_close((uv_handle_t *)uv_stream, NULL);
|
uv_close((uv_handle_t *)uv_stream, connect_close_cb);
|
||||||
if (status == 1) {
|
|
||||||
// The uv_close() above will make libuv call connect_cb() with UV_ECANCELED.
|
|
||||||
// Make sure connect_cb() has been called here, as if it's called after this
|
|
||||||
// function ends it will cause a stack-use-after-scope.
|
|
||||||
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, -1, status != 1);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
// Wait for the close callback to arrive before retrying or returning, otherwise
|
||||||
|
// it may lead to a hang or stack-use-after-return.
|
||||||
|
LOOP_PROCESS_EVENTS_UNTIL(&main_loop, NULL, -1, closed);
|
||||||
|
|
||||||
if (is_tcp && addrinfo->ai_next) {
|
if (is_tcp && addrinfo->ai_next) {
|
||||||
addrinfo = addrinfo->ai_next;
|
addrinfo = addrinfo->ai_next;
|
||||||
|
|||||||
@@ -475,7 +475,6 @@ describe('channels', function()
|
|||||||
end)
|
end)
|
||||||
|
|
||||||
it('in "tcp" mode', function()
|
it('in "tcp" mode', function()
|
||||||
skip(not is_os('linux'), 'FIXME: hangs on non-Linux')
|
|
||||||
eq(
|
eq(
|
||||||
'Vim:connection failed: connection refused',
|
'Vim:connection failed: connection refused',
|
||||||
pcall_err(fn.sockconnect, 'tcp', '127.0.0.1:0')
|
pcall_err(fn.sockconnect, 'tcp', '127.0.0.1:0')
|
||||||
|
|||||||
Reference in New Issue
Block a user