diff options
-rwxr-xr-x | .ci/after_success.sh | 6 | ||||
-rw-r--r-- | .travis.yml | 3 | ||||
-rw-r--r-- | src/nvim/event/process.c | 25 | ||||
-rw-r--r-- | test/functional/core/job_spec.lua (renamed from test/functional/job/job_spec.lua) | 49 | ||||
-rw-r--r-- | test/functional/ui/output_spec.lua | 39 |
5 files changed, 98 insertions, 24 deletions
diff --git a/.ci/after_success.sh b/.ci/after_success.sh index 580b988061..0215eb139b 100755 --- a/.ci/after_success.sh +++ b/.ci/after_success.sh @@ -3,8 +3,6 @@ set -e set -o pipefail -if [[ -n "${CI_TARGET}" ]]; then - exit +if [[ -n "${GCOV}" ]]; then + coveralls --gcov "$(which "${GCOV}")" --encoding iso-8859-1 || echo 'coveralls upload failed.' fi - -[ "$USE_GCOV" = on ] && { coveralls --gcov "$(which "${GCOV}")" --encoding iso-8859-1 || echo 'coveralls upload failed.' ; } diff --git a/.travis.yml b/.travis.yml index 8334b03cdf..9d529c2632 100644 --- a/.travis.yml +++ b/.travis.yml @@ -61,6 +61,7 @@ matrix: env: CI_TARGET=lint - os: linux compiler: gcc-5 + env: GCOV=gcov-5 CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON" - os: linux compiler: gcc-5 env: FUNCTIONALTEST=functionaltest-lua @@ -72,7 +73,7 @@ matrix: env: BUILD_32BIT=ON - os: linux compiler: clang - env: GCOV=llvm-cov CLANG_SANITIZER=ASAN_UBSAN CMAKE_FLAGS="$CMAKE_FLAGS -DUSE_GCOV=ON" + env: CLANG_SANITIZER=ASAN_UBSAN - os: linux compiler: clang env: CLANG_SANITIZER=TSAN diff --git a/src/nvim/event/process.c b/src/nvim/event/process.c index 1c4c9737c3..317e40e43a 100644 --- a/src/nvim/event/process.c +++ b/src/nvim/event/process.c @@ -116,23 +116,20 @@ void process_teardown(Loop *loop) FUNC_ATTR_NONNULL_ALL process_is_tearing_down = true; kl_iter(WatcherPtr, loop->children, current) { Process *proc = (*current)->data; - if (proc->detach) { + if (proc->detach || proc->type == kProcessTypePty) { // Close handles to process without killing it. CREATE_EVENT(loop->events, process_close_handles, 1, proc); } else { - if (proc->type == kProcessTypeUv) { - uv_kill(proc->pid, SIGTERM); - proc->term_sent = true; - process_stop(proc); - } else { // kProcessTypePty - process_close_streams(proc); - pty_process_close_master((PtyProcess *)proc); - } + uv_kill(proc->pid, SIGTERM); + proc->term_sent = true; + process_stop(proc); } } - // Wait until all children exit - LOOP_PROCESS_EVENTS_UNTIL(loop, loop->events, -1, kl_empty(loop->children)); + // Wait until all children exit and all close events are processed. + LOOP_PROCESS_EVENTS_UNTIL( + loop, loop->events, -1, + kl_empty(loop->children) && queue_empty(loop->events)); pty_process_teardown(loop); } @@ -315,8 +312,10 @@ static void decref(Process *proc) static void process_close(Process *proc) FUNC_ATTR_NONNULL_ARG(1) { - if (process_is_tearing_down && proc->detach && proc->closed) { - // If a detached process dies while tearing down it might get closed twice. + if (process_is_tearing_down && (proc->detach || proc->type == kProcessTypePty) + && proc->closed) { + // If a detached/pty process dies while tearing down it might get closed + // twice. return; } assert(!proc->closed); diff --git a/test/functional/job/job_spec.lua b/test/functional/core/job_spec.lua index b54d5166ac..61ecdd1835 100644 --- a/test/functional/job/job_spec.lua +++ b/test/functional/core/job_spec.lua @@ -1,4 +1,3 @@ - local helpers = require('test.functional.helpers')(after_each) local clear, eq, eval, execute, feed, insert, neq, next_msg, nvim, nvim_dir, ok, source, write_file, mkdir, rmdir = helpers.clear, @@ -120,7 +119,7 @@ describe('jobs', function() {0, {'a', '', 'c', '', '', '', 'b', '', ''}}}, next_msg()) end) - it('can preserve nuls', function() + it('can preserve NULs', function() nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)") nvim('command', 'call jobsend(j, ["\n123\n", "abc\\nxyz\n", ""])') eq({'notification', 'stdout', {0, {'\n123\n', 'abc\nxyz\n', ''}}}, @@ -144,7 +143,7 @@ describe('jobs', function() eq({'notification', 'exit', {0, 0}}, next_msg()) end) - it("won't allow jobsend with a job that closed stdin", function() + it("disallows jobsend on a job that closed stdin", function() nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)") nvim('command', 'call jobclose(j, "stdin")') eq(false, pcall(function() @@ -152,12 +151,12 @@ describe('jobs', function() end)) end) - it('will not allow jobsend/stop on a non-existent job', function() + it('disallows jobsend/stop on a non-existent job', function() eq(false, pcall(eval, "jobsend(-1, 'lol')")) eq(false, pcall(eval, "jobstop(-1)")) end) - it('will not allow jobstop twice on the same job', function() + it('disallows jobstop twice on the same job', function() nvim('command', "let j = jobstart(['cat', '-'], g:job_opts)") neq(0, eval('j')) eq(true, pcall(eval, "jobstop(j)")) @@ -244,7 +243,7 @@ describe('jobs', function() eq({'notification', 'exit', {45, 10}}, next_msg()) end) - it('cant redefine callbacks being used by a job', function() + it('cannot redefine callbacks being used by a job', function() local screen = Screen.new() screen:attach() local script = [[ @@ -467,3 +466,41 @@ describe('jobs', function() end) end) end) + +describe("pty process teardown", function() + local screen + before_each(function() + clear() + screen = Screen.new(30, 6) + screen:attach() + screen:expect([[ + ^ | + ~ | + ~ | + ~ | + ~ | + | + ]]) + end) + after_each(function() + screen:detach() + end) + + it("does not prevent/delay exit. #4798 #4900", function() + -- Use a nested nvim (in :term) to test without --headless. + execute(":terminal '"..helpers.nvim_prog + -- Use :term again in the _nested_ nvim to get a PTY process. + -- Use `sleep` to simulate a long-running child of the PTY. + .."' +terminal +'!(sleep 300 &)' +qa") + + -- Exiting should terminate all descendants (PTY, its children, ...). + screen:expect([[ + | + [Process exited 0] | + | + | + | + -- TERMINAL -- | + ]]) + end) +end) diff --git a/test/functional/ui/output_spec.lua b/test/functional/ui/output_spec.lua new file mode 100644 index 0000000000..c7c8986527 --- /dev/null +++ b/test/functional/ui/output_spec.lua @@ -0,0 +1,39 @@ +local session = require('test.functional.helpers')(after_each) +local child_session = require('test.functional.terminal.helpers') + +describe("shell command :!", function() + local screen + before_each(function() + session.clear() + screen = child_session.screen_setup(0, '["'..session.nvim_prog.. + '", "-u", "NONE", "-i", "NONE", "--cmd", "set noswapfile"]') + screen:expect([[ + {1: } | + ~ | + ~ | + ~ | + [No Name] | + | + -- TERMINAL -- | + ]]) + end) + + after_each(function() + screen:detach() + end) + + it("displays output even without LF/EOF. #4646 #4569 #3772", function() + -- NOTE: We use a child nvim (within a :term buffer) + -- to avoid triggering a UI flush. + child_session.feed_data(":!printf foo; sleep 200\n") + screen:expect([[ + ~ | + ~ | + [No Name] | + :!printf foo; sleep 200 | + | + foo | + -- TERMINAL -- | + ]]) + end) +end) |