Skip to content
This repository has been archived by the owner on Jun 30, 2023. It is now read-only.

[WIP/RFC] session: store exitcode/exitsignal from child #44

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open
11 changes: 8 additions & 3 deletions nvim/child_process_stream.lua
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ function ChildProcessStream.spawn(argv, env)
stdio = {self._child_stdin, self._child_stdout, 2},
args = args,
env = env,
}, function()
}, function(code, signal)
self.exitcode = code
self.exitsignal = signal
self:close()
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be good to have this as a module function, so it could be changed / and/or pass in a callback additionally somehow.
Then Neovim could use busted.fail here directly maybe.

end)

Expand Down Expand Up @@ -59,8 +61,11 @@ function ChildProcessStream:close(signal)
if type(signal) == 'string' then
self._proc:kill('sig'..signal)
end
self._proc:close()
uv.run('nowait')

while not self.exitcode do
uv.run('once')
end
assert(self.exitcode)
native.pid_wait(self._pid)
end

Expand Down
13 changes: 12 additions & 1 deletion nvim/session.lua
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ function Session:close(signal)
if not self._timer:is_closing() then self._timer:close() end
if not self._prepare:is_closing() then self._prepare:close() end
self._msgpack_rpc_stream:close(signal)

if not self.child_exit then
uv.run('nowait') -- run the loop to get exitcode from child process.
self.child_exit = self._msgpack_rpc_stream._stream.exitcode
self.child_signal = self._msgpack_rpc_stream._stream.exitsignal
end
end

function Session:_yielding_request(method, args)
Expand Down Expand Up @@ -175,7 +181,12 @@ function Session:_run(request_cb, notification_cb, timeout)
self._prepare:stop()
end)
end
self._msgpack_rpc_stream:read_start(request_cb, notification_cb, uv.stop)
self._msgpack_rpc_stream:read_start(request_cb, notification_cb, function()
uv.run() -- run the loop to get exitcode from child process.
blueyed marked this conversation as resolved.
Show resolved Hide resolved
self.child_exit = self._msgpack_rpc_stream._stream.exitcode
self.child_signal = self._msgpack_rpc_stream._stream.exitsignal
uv.stop()
end)
uv.run()
self._prepare:stop()
self._timer:stop()
Expand Down
14 changes: 14 additions & 0 deletions test/session_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ local function test_session(description, session_factory, session_destroy)
session_destroy()
else
session:close()
assert.are.equal(0, session.child_exit)
assert.are.equal(0, session.child_signal)
end
closed = true
end)
Expand All @@ -179,6 +181,8 @@ test_session(string.format("Session using SocketStream [%s]", socket_file), func
return socket_session
end, function ()
child_session:close()
assert.are.equal(0, child_session.child_exit)
assert.are.equal(0, child_session.child_signal)
socket_session:close()
-- clean up leftovers if something goes wrong
local fd = io.open(socket_file)
Expand Down Expand Up @@ -218,6 +222,8 @@ test_session("Session using TcpStream", function ()
return tcp_session
end, function ()
child_session:close()
assert.are.equal(0, child_session.child_exit)
assert.are.equal(0, child_session.child_signal)
tcp_session:close()
end)

Expand Down Expand Up @@ -257,3 +263,11 @@ describe('stdio', function()
assert.are.same({'notification', 'd', {6, 7}}, session:next_message())
end)
end)

it('closing session does not hang with active loop', function()
local cmd = {nvim_prog, '-u', 'NONE', '--embed', '--headless'}
local session1 = Session.new(ChildProcessStream.spawn(cmd))
local session2 = Session.new(ChildProcessStream.spawn(cmd))
session1:close()
session2:close()
end)