Skip to content

Commit

Permalink
stdio: sometimes quit main loop after io is done
Browse files Browse the repository at this point in the history
in the event of a non-terminal, api v1 exec session, we need to run the main_loop a second time to make sure we get all output from the i/o pipes connected to the container.

However, occasionally, the container process will finish before this main loop is called. We catch it when we check the child processes immediately preceeding the g_main_loop_run, but that gives no way to exit the main loop (as we've already removed container_exit_cb as a source.

The solution here is to exit the main loop if we get to stdio_cb, the first i/o pipe has been closed (either stderr or stdout, doesn't matter the order), and we know the container_status. this allows us to read all the i/o, but still properly exit conmon

Signed-off-by: Peter Hunt <[email protected]>
  • Loading branch information
haircommander committed Mar 17, 2020
1 parent f31e5f2 commit 10823ae
Showing 1 changed file with 22 additions and 3 deletions.
25 changes: 22 additions & 3 deletions src/conmon.c
Original file line number Diff line number Diff line change
Expand Up @@ -489,12 +489,28 @@ static gboolean stdio_cb(int fd, GIOCondition condition, gpointer user_data)
return G_SOURCE_REMOVE;
}

/* End of input */
if (read_eof || (has_hup && !has_input)) {
/* End of input */
if (pipe == STDOUT_PIPE)
/* There exists a case that the process has already exited
* and we know about it (because we checked our child processes)
* but we needed to run the main_loop to catch all the rest of the output
* (specifically, when we are exec, but not terminal)
* In this case, after both the stderr and stdout pipes have closed
* we should quit the loop. Otherwise, conmon will hang forever
* waiting for container_exit_cb that will never be called.
*/
if (pipe == STDOUT_PIPE) {
masterfd_stdout = -1;
if (pipe == STDERR_PIPE)
if (container_status >= 0 && masterfd_stderr < 0) {
g_main_loop_quit(main_loop);
}
}
if (pipe == STDERR_PIPE) {
masterfd_stderr = -1;
if (container_status >= 0 && masterfd_stdout < 0) {
g_main_loop_quit(main_loop);
}
}

close(fd);
return G_SOURCE_REMOVE;
Expand Down Expand Up @@ -1772,6 +1788,9 @@ int main(int argc, char *argv[])
specifically, the check child processes call above could set the container
status if it is a quickly exiting command. We only want to run the loop if
this hasn't happened yet.
Note: there exists a chance that we have the container_status, are exec, and api>=1,
but are not terminal. In this case, we still want to run to process all of the output,
but will need to exit once all the i/o is read. This will be handled in stdio_cb above.
*/
if (opt_api_version < 1 || !opt_exec || !opt_terminal || container_status < 0)
g_main_loop_run(main_loop);
Expand Down

0 comments on commit 10823ae

Please sign in to comment.