mirror of
				https://github.com/neovim/neovim.git
				synced 2025-10-26 12:27:24 +00:00 
			
		
		
		
	channels: reflect exit due to signals in exit status code (#10573)
Uses `128 + term_signal` in case of exit due to a signal. Fixes https://github.com/neovim/neovim/issues/10571.
This commit is contained in:
		| @@ -67,7 +67,7 @@ For |on_stdout| and |on_stderr| see |channel-callback|. | |||||||
| 							*on_exit* | 							*on_exit* | ||||||
| Arguments passed to on_exit callback: | Arguments passed to on_exit callback: | ||||||
|   0: |job-id| |   0: |job-id| | ||||||
|   1: Exit-code of the process. |   1: Exit-code of the process, or 128+SIGNUM if by signal (e.g. 143 on SIGTERM). | ||||||
|   2: Event type: "exit" |   2: Event type: "exit" | ||||||
|  |  | ||||||
|  |  | ||||||
|   | |||||||
| @@ -12354,7 +12354,6 @@ static void f_jobstop(typval_T *argvars, typval_T *rettv, FunPtr fptr) | |||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |  | ||||||
|   Channel *data = find_job(argvars[0].vval.v_number, true); |   Channel *data = find_job(argvars[0].vval.v_number, true); | ||||||
|   if (!data) { |   if (!data) { | ||||||
|     return; |     return; | ||||||
|   | |||||||
| @@ -101,6 +101,10 @@ static void close_cb(uv_handle_t *handle) | |||||||
| static void exit_cb(uv_process_t *handle, int64_t status, int term_signal) | static void exit_cb(uv_process_t *handle, int64_t status, int term_signal) | ||||||
| { | { | ||||||
|   Process *proc = handle->data; |   Process *proc = handle->data; | ||||||
|   proc->status = (int)status; | #if defined(WIN32) | ||||||
|  |   // Use stored/expected signal. | ||||||
|  |   term_signal = proc->exit_signal; | ||||||
|  | #endif | ||||||
|  |   proc->status = term_signal ? 128 + term_signal : (int)status; | ||||||
|   proc->internal_exit_cb(proc); |   proc->internal_exit_cb(proc); | ||||||
| } | } | ||||||
|   | |||||||
| @@ -159,7 +159,7 @@ void process_close_streams(Process *proc) FUNC_ATTR_NONNULL_ALL | |||||||
| ///                 0 for no wait. -1 to wait until the process quits. | ///                 0 for no wait. -1 to wait until the process quits. | ||||||
| /// @return Exit code of the process. proc->status will have the same value. | /// @return Exit code of the process. proc->status will have the same value. | ||||||
| ///         -1 if the timeout expired while the process is still running. | ///         -1 if the timeout expired while the process is still running. | ||||||
| ///         -2 if the user interruped the wait. | ///         -2 if the user interrupted the wait. | ||||||
| int process_wait(Process *proc, int ms, MultiQueue *events) | int process_wait(Process *proc, int ms, MultiQueue *events) | ||||||
|   FUNC_ATTR_NONNULL_ARG(1) |   FUNC_ATTR_NONNULL_ARG(1) | ||||||
| { | { | ||||||
| @@ -220,6 +220,7 @@ void process_stop(Process *proc) FUNC_ATTR_NONNULL_ALL | |||||||
|     return; |     return; | ||||||
|   } |   } | ||||||
|   proc->stopped_time = os_hrtime(); |   proc->stopped_time = os_hrtime(); | ||||||
|  |   proc->exit_signal = SIGTERM; | ||||||
|  |  | ||||||
|   switch (proc->type) { |   switch (proc->type) { | ||||||
|     case kProcessTypeUv: |     case kProcessTypeUv: | ||||||
| @@ -253,8 +254,10 @@ static void children_kill_cb(uv_timer_t *handle) | |||||||
|     } |     } | ||||||
|     uint64_t term_sent = UINT64_MAX == proc->stopped_time; |     uint64_t term_sent = UINT64_MAX == proc->stopped_time; | ||||||
|     if (kProcessTypePty != proc->type || term_sent) { |     if (kProcessTypePty != proc->type || term_sent) { | ||||||
|  |       proc->exit_signal = SIGKILL; | ||||||
|       os_proc_tree_kill(proc->pid, SIGKILL); |       os_proc_tree_kill(proc->pid, SIGKILL); | ||||||
|     } else { |     } else { | ||||||
|  |       proc->exit_signal = SIGTERM; | ||||||
|       os_proc_tree_kill(proc->pid, SIGTERM); |       os_proc_tree_kill(proc->pid, SIGTERM); | ||||||
|       proc->stopped_time = UINT64_MAX;  // Flag: SIGTERM was sent. |       proc->stopped_time = UINT64_MAX;  // Flag: SIGTERM was sent. | ||||||
|       // Restart timer. |       // Restart timer. | ||||||
| @@ -403,4 +406,3 @@ static void on_process_stream_close(Stream *stream, void *data) | |||||||
|   Process *proc = data; |   Process *proc = data; | ||||||
|   decref(proc); |   decref(proc); | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -19,6 +19,7 @@ struct process { | |||||||
|   Loop *loop; |   Loop *loop; | ||||||
|   void *data; |   void *data; | ||||||
|   int pid, status, refcount; |   int pid, status, refcount; | ||||||
|  |   uint8_t exit_signal;  // Signal used when killing (on Windows). | ||||||
|   uint64_t stopped_time;  // process_stop() timestamp |   uint64_t stopped_time;  // process_stop() timestamp | ||||||
|   const char *cwd; |   const char *cwd; | ||||||
|   char **argv; |   char **argv; | ||||||
|   | |||||||
| @@ -288,7 +288,7 @@ static void chld_handler(uv_signal_t *handle, int signum) | |||||||
|     if (WIFEXITED(stat)) { |     if (WIFEXITED(stat)) { | ||||||
|       proc->status = WEXITSTATUS(stat); |       proc->status = WEXITSTATUS(stat); | ||||||
|     } else if (WIFSIGNALED(stat)) { |     } else if (WIFSIGNALED(stat)) { | ||||||
|       proc->status = WTERMSIG(stat); |       proc->status = 128 + WTERMSIG(stat); | ||||||
|     } |     } | ||||||
|     proc->internal_exit_cb(proc); |     proc->internal_exit_cb(proc); | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -252,7 +252,7 @@ static void pty_process_finish2(PtyProcess *ptyproc) | |||||||
|  |  | ||||||
|   DWORD exit_code = 0; |   DWORD exit_code = 0; | ||||||
|   GetExitCodeProcess(ptyproc->process_handle, &exit_code); |   GetExitCodeProcess(ptyproc->process_handle, &exit_code); | ||||||
|   proc->status = (int)exit_code; |   proc->status = proc->exit_signal ? 128 + proc->exit_signal : (int)exit_code; | ||||||
|  |  | ||||||
|   CloseHandle(ptyproc->process_handle); |   CloseHandle(ptyproc->process_handle); | ||||||
|   ptyproc->process_handle = NULL; |   ptyproc->process_handle = NULL; | ||||||
|   | |||||||
| @@ -183,7 +183,7 @@ describe('jobs', function() | |||||||
|     ) |     ) | ||||||
|     nvim('command', "call jobstop(j)") |     nvim('command', "call jobstop(j)") | ||||||
|     eq({'notification', 'stdout', {0, {''}}}, next_msg()) |     eq({'notification', 'stdout', {0, {''}}}, next_msg()) | ||||||
|     eq({'notification', 'exit', {0, iswin() and 15 or 0}}, next_msg()) |     eq({'notification', 'exit', {0, 143}}, next_msg()) | ||||||
|   end) |   end) | ||||||
|  |  | ||||||
|   it('preserves NULs', function() |   it('preserves NULs', function() | ||||||
| @@ -217,7 +217,7 @@ describe('jobs', function() | |||||||
|     eq({'notification', 'stdout', {0, {'abc', 'xyz'}}}, next_msg()) |     eq({'notification', 'stdout', {0, {'abc', 'xyz'}}}, next_msg()) | ||||||
|     nvim('command', "call jobstop(j)") |     nvim('command', "call jobstop(j)") | ||||||
|     eq({'notification', 'stdout', {0, {''}}}, next_msg()) |     eq({'notification', 'stdout', {0, {''}}}, next_msg()) | ||||||
|     eq({'notification', 'exit', {0, iswin() and 15 or 0}}, next_msg()) |     eq({'notification', 'exit', {0, 143}}, next_msg()) | ||||||
|   end) |   end) | ||||||
|  |  | ||||||
|   it('preserves newlines', function() |   it('preserves newlines', function() | ||||||
| @@ -234,7 +234,7 @@ describe('jobs', function() | |||||||
|       next_msg()) |       next_msg()) | ||||||
|     nvim('command', "call jobstop(j)") |     nvim('command', "call jobstop(j)") | ||||||
|     eq({'notification', 'stdout', {0, {''}}}, next_msg()) |     eq({'notification', 'stdout', {0, {''}}}, next_msg()) | ||||||
|     eq({'notification', 'exit', {0, iswin() and 15 or 0}}, next_msg()) |     eq({'notification', 'exit', {0, 143}}, next_msg()) | ||||||
|   end) |   end) | ||||||
|  |  | ||||||
|   it('avoids sending final newline', function() |   it('avoids sending final newline', function() | ||||||
| @@ -244,7 +244,7 @@ describe('jobs', function() | |||||||
|       next_msg()) |       next_msg()) | ||||||
|     nvim('command', "call jobstop(j)") |     nvim('command', "call jobstop(j)") | ||||||
|     eq({'notification', 'stdout', {0, {''}}}, next_msg()) |     eq({'notification', 'stdout', {0, {''}}}, next_msg()) | ||||||
|     eq({'notification', 'exit', {0, iswin() and 15 or 0}}, next_msg()) |     eq({'notification', 'exit', {0, 143}}, next_msg()) | ||||||
|   end) |   end) | ||||||
|  |  | ||||||
|   it('closes the job streams with jobclose', function() |   it('closes the job streams with jobclose', function() | ||||||
| @@ -284,18 +284,7 @@ describe('jobs', function() | |||||||
|     neq(NIL, meths.get_proc(pid)) |     neq(NIL, meths.get_proc(pid)) | ||||||
|     nvim('command', 'call jobstop(j)') |     nvim('command', 'call jobstop(j)') | ||||||
|     eq({'notification', 'stdout', {0, {''}}}, next_msg()) |     eq({'notification', 'stdout', {0, {''}}}, next_msg()) | ||||||
|     if iswin() then |     eq({'notification', 'exit', {0, 143}}, next_msg()) | ||||||
|       expect_msg_seq( |  | ||||||
|         -- win64 |  | ||||||
|         { {'notification', 'exit', {0, 1}} |  | ||||||
|         }, |  | ||||||
|         -- win32 |  | ||||||
|         { {'notification', 'exit', {0, 15}} |  | ||||||
|         } |  | ||||||
|       ) |  | ||||||
|     else |  | ||||||
|       eq({'notification', 'exit', {0, 0}}, next_msg()) |  | ||||||
|     end |  | ||||||
|     eq(NIL, meths.get_proc(pid)) |     eq(NIL, meths.get_proc(pid)) | ||||||
|   end) |   end) | ||||||
|  |  | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user
	 Daniel Hahler
					Daniel Hahler