diff options
author | Damien Miller <djm@mindrot.org> | 2000-01-17 20:55:18 +1100 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2000-01-17 20:55:18 +1100 |
commit | b284b546c092f5f9f8c509c8b49f7d57233a5f3f (patch) | |
tree | a0de7aa63a4aa8716b4eee4fee1fa134c2e6c41c /serverloop.c | |
parent | d426ed6e51b1802e2d47a5ed291232a659dc251a (diff) |
- Fix hang on logout if processes are still using the pty. Needs
further testing.
Diffstat (limited to 'serverloop.c')
-rw-r--r-- | serverloop.c | 17 |
1 files changed, 15 insertions, 2 deletions
diff --git a/serverloop.c b/serverloop.c index a5ecfe97d..2afca7637 100644 --- a/serverloop.c +++ b/serverloop.c | |||
@@ -36,10 +36,15 @@ static int max_fd; /* Max file descriptor number for select(). */ | |||
36 | /* | 36 | /* |
37 | * This SIGCHLD kludge is used to detect when the child exits. The server | 37 | * This SIGCHLD kludge is used to detect when the child exits. The server |
38 | * will exit after that, as soon as forwarded connections have terminated. | 38 | * will exit after that, as soon as forwarded connections have terminated. |
39 | * | ||
40 | * After SIGCHLD child_has_selected is set to 1 after the first pass | ||
41 | * through the wait_until_can_do_something() select(). This ensures | ||
42 | * that the child's output gets a chance to drain before it is yanked. | ||
39 | */ | 43 | */ |
40 | 44 | ||
41 | static int child_pid; /* Pid of the child. */ | 45 | static int child_pid; /* Pid of the child. */ |
42 | static volatile int child_terminated; /* The child has terminated. */ | 46 | static volatile int child_terminated; /* The child has terminated. */ |
47 | static volatile int child_has_selected; /* Child has had chance to drain. */ | ||
43 | static volatile int child_wait_status; /* Status from wait(). */ | 48 | static volatile int child_wait_status; /* Status from wait(). */ |
44 | 49 | ||
45 | void | 50 | void |
@@ -56,6 +61,7 @@ sigchld_handler(int sig) | |||
56 | if (WIFEXITED(child_wait_status) || | 61 | if (WIFEXITED(child_wait_status) || |
57 | WIFSIGNALED(child_wait_status)) | 62 | WIFSIGNALED(child_wait_status)) |
58 | child_terminated = 1; | 63 | child_terminated = 1; |
64 | child_has_selected = 0; | ||
59 | } | 65 | } |
60 | signal(SIGCHLD, sigchld_handler); | 66 | signal(SIGCHLD, sigchld_handler); |
61 | errno = save_errno; | 67 | errno = save_errno; |
@@ -300,6 +306,9 @@ retry_select: | |||
300 | else | 306 | else |
301 | goto retry_select; | 307 | goto retry_select; |
302 | } | 308 | } |
309 | |||
310 | if (child_terminated) | ||
311 | child_has_selected = 1; | ||
303 | } | 312 | } |
304 | 313 | ||
305 | /* | 314 | /* |
@@ -438,6 +447,7 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg) | |||
438 | /* Initialize the SIGCHLD kludge. */ | 447 | /* Initialize the SIGCHLD kludge. */ |
439 | child_pid = pid; | 448 | child_pid = pid; |
440 | child_terminated = 0; | 449 | child_terminated = 0; |
450 | child_has_selected = 0; | ||
441 | signal(SIGCHLD, sigchld_handler); | 451 | signal(SIGCHLD, sigchld_handler); |
442 | 452 | ||
443 | /* Initialize our global variables. */ | 453 | /* Initialize our global variables. */ |
@@ -533,8 +543,11 @@ server_loop(int pid, int fdin_arg, int fdout_arg, int fderr_arg) | |||
533 | * descriptors, and we have no more data to send to the | 543 | * descriptors, and we have no more data to send to the |
534 | * client, and there is no pending buffered data. | 544 | * client, and there is no pending buffered data. |
535 | */ | 545 | */ |
536 | if (fdout_eof && fderr_eof && !packet_have_data_to_write() && | 546 | if (((fdout_eof && fderr_eof) || |
537 | buffer_len(&stdout_buffer) == 0 && buffer_len(&stderr_buffer) == 0) { | 547 | (child_terminated && child_has_selected)) && |
548 | !packet_have_data_to_write() && | ||
549 | (buffer_len(&stdout_buffer) == 0) && | ||
550 | (buffer_len(&stderr_buffer) == 0)) { | ||
538 | if (!channel_still_open()) | 551 | if (!channel_still_open()) |
539 | goto quit; | 552 | goto quit; |
540 | if (!waiting_termination) { | 553 | if (!waiting_termination) { |