From 77b0ec86df577f3f66ec716824ec4b650787f24d Mon Sep 17 00:00:00 2001 From: manojampalam Date: Fri, 25 Mar 2016 21:22:13 -0700 Subject: [PATCH] SIGCHLD and waitpid implementation with sshd on board --- contrib/win32/win32compat/fileio.c | 10 +-- contrib/win32/win32compat/inc/defs.h | 5 +- contrib/win32/win32compat/inc/sys/wait.h | 21 +++-- contrib/win32/win32compat/inc/w32posix.h | 2 +- contrib/win32/win32compat/misc.c | 5 -- contrib/win32/win32compat/signal.c | 110 ++++++++++++++++++++--- contrib/win32/win32compat/socketio.c | 11 +-- contrib/win32/win32compat/w32fd.h | 2 +- session.c | 25 +++--- session.h | 4 - sshd.c | 12 +-- 11 files changed, 135 insertions(+), 72 deletions(-) diff --git a/contrib/win32/win32compat/fileio.c b/contrib/win32/win32compat/fileio.c index d6756c9..63c8106 100644 --- a/contrib/win32/win32compat/fileio.c +++ b/contrib/win32/win32compat/fileio.c @@ -373,8 +373,7 @@ fileio_read(struct w32_io* pio, void *dst, unsigned int max) { } /* pick up APC if IO has completed */ - if (-1 == wait_for_any_event(NULL, 0, 0)) - return -1; + SleepEx(0, TRUE); if (w32_io_is_blocking(pio)) { while (fileio_is_io_available(pio, TRUE) == FALSE) { @@ -519,12 +518,7 @@ fileio_write(struct w32_io* pio, const void *buf, unsigned int max) { } } /* execute APC to give a chance for write to complete */ - else if (wait_for_any_event(NULL, 0, 0) == -1) { - /* if interrupted but write has completed, we are good*/ - if ((errno != EINTR) || (pio->write_details.pending)) - return -1; - errno = 0; - } + SleepEx(0, TRUE); /* if write has completed, pick up any error reported*/ if (!pio->write_details.pending && pio->write_details.error) { diff --git a/contrib/win32/win32compat/inc/defs.h b/contrib/win32/win32compat/inc/defs.h index 38c1316..c81113f 100644 --- a/contrib/win32/win32compat/inc/defs.h +++ b/contrib/win32/win32compat/inc/defs.h @@ -70,4 +70,7 @@ typedef int sigset_t; typedef unsigned short _mode_t; typedef _mode_t mode_t; -typedef unsigned long pid_t; +typedef int pid_t; + +/* wait pid options */ +#define WNOHANG 1 \ No newline at end of file diff --git a/contrib/win32/win32compat/inc/sys/wait.h b/contrib/win32/win32compat/inc/sys/wait.h index b7eeb25..25ad69f 100644 --- a/contrib/win32/win32compat/inc/sys/wait.h +++ b/contrib/win32/win32compat/inc/sys/wait.h @@ -1,14 +1,17 @@ #pragma once #include "..\w32posix.h" -#define _W_INT(w) (*(int*)&(w)) /* convert union wait to int */ -#define WIFEXITED(w) (!((_W_INT(w)) & 0377)) -#define WIFSTOPPED(w) ((_W_INT(w)) & 0100) -#define WIFSIGNALED(w) (!WIFEXITED(w) && !WIFSTOPPED(w)) -#define WEXITSTATUS(w) (int)(WIFEXITED(w) ? ((_W_INT(w) >> 8) & 0377) : -1) -#define WTERMSIG(w) (int)(WIFSIGNALED(w) ? (_W_INT(w) & 0177) : -1) +//#define _W_INT(w) (*(int*)&(w)) /* convert union wait to int */ +//#define WIFEXITED(w) (!((_W_INT(w)) & 0377)) +//#define WIFSTOPPED(w) ((_W_INT(w)) & 0100) +//#define WIFSIGNALED(w) (!WIFEXITED(w) && !WIFSTOPPED(w)) +//#define WEXITSTATUS(w) (int)(WIFEXITED(w) ? ((_W_INT(w) >> 8) & 0377) : -1) +//#define WTERMSIG(w) (int)(WIFSIGNALED(w) ? (_W_INT(w) & 0177) : -1) -/* wait pid options */ -#define WNOHANG 1 +#define WIFEXITED(w) TRUE +#define WIFSTOPPED(w) TRUE +#define WIFSIGNALED(w) FALSE +#define WEXITSTATUS(w) w +#define WTERMSIG(w) -1 -pid_t waitpid(pid_t pid, int *status, int options); \ No newline at end of file +int waitpid(int pid, int *status, int options); \ No newline at end of file diff --git a/contrib/win32/win32compat/inc/w32posix.h b/contrib/win32/win32compat/inc/w32posix.h index 834cfd6..0cce0e6 100644 --- a/contrib/win32/win32compat/inc/w32posix.h +++ b/contrib/win32/win32compat/inc/w32posix.h @@ -107,7 +107,7 @@ int w32_temp_DelChildToWatch(HANDLE processtowatch); int w32_temp_AddChildToWatch(HANDLE processtowatch); HANDLE w32_fd_to_handle(int fd); int w32_allocate_fd_for_handle(HANDLE h, BOOL is_sock); -int sw_add_child(HANDLE child); +int sw_add_child(HANDLE child, DWORD pid); /* temporary definitions to aid in transition */ #define WSHELPDelChildToWatch(a) w32_temp_DelChildToWatch((a)) diff --git a/contrib/win32/win32compat/misc.c b/contrib/win32/win32compat/misc.c index 666b4aa..038bf80 100644 --- a/contrib/win32/win32compat/misc.c +++ b/contrib/win32/win32compat/misc.c @@ -8,11 +8,6 @@ int usleep(unsigned int useconds) return 1; } -pid_t waitpid(pid_t pid, int *status, int options) { - /* TODO - implement this*/ - return 0; -} - void explicit_bzero(void *b, size_t len) { SecureZeroMemory(b, len); diff --git a/contrib/win32/win32compat/signal.c b/contrib/win32/win32compat/signal.c index 827adff..056145d 100644 --- a/contrib/win32/win32compat/signal.c +++ b/contrib/win32/win32compat/signal.c @@ -70,17 +70,19 @@ sw_init_signal_handler_table() { #define MAX_CHILDREN 50 struct _children { HANDLE handles[MAX_CHILDREN]; - //DWORD process_id[MAX_CHILDREN]; + DWORD process_id[MAX_CHILDREN]; DWORD num_children; } children; int -sw_add_child(HANDLE child) { +sw_add_child(HANDLE child, DWORD pid) { if (children.num_children == MAX_CHILDREN) { errno = ENOTSUP; return -1; } - children.handles[children.num_children++] = child; + children.handles[children.num_children] = child; + children.process_id[children.num_children] = pid; + children.num_children++; return 0; } @@ -100,7 +102,6 @@ sw_remove_child_at_index(DWORD index) { return 0; } - int sw_remove_child(HANDLE child) { HANDLE* handles = children.handles; @@ -117,6 +118,90 @@ sw_remove_child(HANDLE child) { return -1; } +int waitpid(int pid, int *status, int options) { + DWORD index, ret, ret_id, exit_code, timeout = 0; + HANDLE process = NULL; + + if (options & (~WNOHANG)) { + errno = ENOTSUP; + DebugBreak(); + return -1; + } + + if ((pid < -1) || (pid == 0)) { + errno = ENOTSUP; + DebugBreak(); + return -1; + } + + if (children.num_children == 0) { + errno = ECHILD; + return -1; + } + + if (pid > 0) { + if (options != 0) { + errno = ENOTSUP; + DebugBreak(); + return -1; + } + /* find entry in table */ + for (index = 0; index < children.num_children; index++) + if (children.process_id[index] == pid) + break; + + if (index == children.num_children) { + errno = ECHILD; + return -1; + } + + process = children.handles[index]; + ret = WaitForSingleObject(process, INFINITE); + if (ret != WAIT_OBJECT_0) + DebugBreak();//fatal + + ret_id = children.process_id[index]; + GetExitCodeProcess(process, &exit_code); + CloseHandle(process); + sw_remove_child_at_index(index); + if (status) + *status = exit_code; + return ret_id; + } + + /* pid = -1*/ + timeout = INFINITE; + if (options & WNOHANG) + timeout = 0; + ret = WaitForMultipleObjects(children.num_children, children.handles, FALSE, timeout); + if ((ret >= WAIT_OBJECT_0) && (ret < (WAIT_OBJECT_0 + children.num_children))) { + index = ret - WAIT_OBJECT_0; + process = children.handles[index]; + ret_id = children.process_id[index]; + GetExitCodeProcess(process, &exit_code); + CloseHandle(process); + sw_remove_child_at_index(index); + if (status) + *status = exit_code; + return ret_id; + } + else if (ret == WAIT_TIMEOUT) { + /* assert that WNOHANG was specified*/ + return 0; + } + + DebugBreak();//fatal + return -1; +} + +static void +sw_cleanup_child_zombies() { + int pid = 1; + while (pid > 0) { + pid = waitpid(-1, NULL, WNOHANG); + } +} + struct { HANDLE timer; ULONGLONG ticks_at_start; /* 0 if timer is not live */ @@ -223,7 +308,7 @@ sw_raise(int sig) { /* execute any default handlers */ switch (sig) { case W32_SIGCHLD: - /*TODO - execute sigchild default handler */ + sw_cleanup_child_zombies(); break; case W32_SIGINT: /* TODO - execute sigint default handler */ @@ -274,9 +359,6 @@ sw_process_pending_signals() { sw_raise(exp[i]); sig_int = TRUE; } - else {/* disposition is W32_SIG_IGN */ - /* TODO for SIG_CHLD - do clean up of Zombies */ - } sigdelset(&pending_tmp, exp[i]); } @@ -313,7 +395,9 @@ int wait_for_any_event(HANDLE* events, int num_events, DWORD milli_seconds) { HANDLE all_events[MAXIMUM_WAIT_OBJECTS]; - DWORD num_all_events = num_events + children.num_children; + DWORD num_all_events; + + num_all_events = num_events + children.num_children; if (num_all_events > MAXIMUM_WAIT_OBJECTS) { errno = ENOTSUP; @@ -335,11 +419,9 @@ wait_for_any_event(HANDLE* events, int num_events, DWORD milli_seconds) //woken up by event signalled /* is this due to a child process going down*/ if (children.num_children && ((ret - WAIT_OBJECT_0) < children.num_children)) { - /* TODO - enable this once all direct closes are removed in core code*/ - //sigaddset(&pending_signals, W32_SIGCHLD); - //sw_remove_child(ret - WAIT_OBJECT_0); - errno = EINTR; - return -1; + sigaddset(&pending_signals, W32_SIGCHLD); + //errno = EINTR; + //return -1; } } else if (ret == WAIT_IO_COMPLETION) { diff --git a/contrib/win32/win32compat/socketio.c b/contrib/win32/win32compat/socketio.c index 27b4c03..4353138 100644 --- a/contrib/win32/win32compat/socketio.c +++ b/contrib/win32/win32compat/socketio.c @@ -421,8 +421,7 @@ socketio_recv(struct w32_io* pio, void *buf, size_t len, int flags) { if (completed) { /* Let APC be scheduled */ debug2("recv - Letting APC to execute, io:%p", pio); - if (wait_for_any_event(NULL, 0, 0) == -1) - return -1; + SleepEx(0, TRUE); if (pio->read_details.pending) { /* this shouldn't be happening */ errno = EOTHER; @@ -588,13 +587,7 @@ socketio_send(struct w32_io* pio, const void *buf, size_t len, int flags) { debug2("send - WSASend() returned 0, APC scheduled io:%p", pio); pio->write_details.pending = TRUE; pio->write_details.remaining = wsabuf.len; - if (wait_for_any_event(NULL, 0, 0) == -1) { - //interrupted but send went through - if (errno == EINTR) - errno = 0; - else - return -1; - } + SleepEx(0, TRUE); if ((pio->write_details.pending) || (pio->write_details.remaining != 0)) { errno = EOTHER; debug("send - ERROR: Unexpected IO state, io:%p", pio); diff --git a/contrib/win32/win32compat/w32fd.h b/contrib/win32/win32compat/w32fd.h index a90afd7..4925969 100644 --- a/contrib/win32/win32compat/w32fd.h +++ b/contrib/win32/win32compat/w32fd.h @@ -123,7 +123,7 @@ int termio_close(struct w32_io* pio); /* signal related APIs*/ int sw_initialize(); -int sw_add_child(HANDLE child); +int sw_add_child(HANDLE child, DWORD pid); int sw_remove_child(HANDLE child); unsigned int sw_alarm(unsigned int seconds); sighandler_t sw_signal(int signum, sighandler_t handler); diff --git a/session.c b/session.c index 03520a3..6cff37c 100644 --- a/session.c +++ b/session.c @@ -843,9 +843,8 @@ do_exec_no_pty(Session *s, const char *command) * Log the process handle (fake it as the pid) for termination lookups */ - s -> pid = pi.hProcess; - s -> processId = pi.dwProcessId; - sw_add_child(pi.hProcess); + s -> pid = pi.dwProcessId; + sw_add_child(pi.hProcess, pi.dwProcessId); // Add the child process created to select mux so that during our select data call we know if the process has exited /* TODO - fix thi s*/ @@ -2877,10 +2876,12 @@ session_pty_cleanup2(Session *s) debug("Sending exit signal to child process [pid = %u]...", s -> pid); - if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, s -> processId)) - { - debug("ERROR. Cannot send signal to process."); - } + //if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, s -> processId)) + //{ + // debug("ERROR. Cannot send signal to process."); + //} + + kill(s->pid, SIGTERM); /* * Try wait 100 ms until child finished. @@ -2991,11 +2992,11 @@ session_close_single_x11(int id, void *arg) { debug("Sending exit signal to child process [pid = %u]...", s -> pid); - if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, s -> processId)) - { - debug("ERROR. Cannot send signal to process."); - } - + //if (!GenerateConsoleCtrlEvent(CTRL_BREAK_EVENT, s -> processId)) + //{ + // debug("ERROR. Cannot send signal to process."); + //} + kill(s->pid, SIGTERM); /* * Try wait 100 ms until child finished. */ diff --git a/session.h b/session.h index f63cdd6..6a2f35e 100644 --- a/session.h +++ b/session.h @@ -35,10 +35,6 @@ struct Session { struct passwd *pw; Authctxt *authctxt; pid_t pid; - - #ifdef WIN32_FIXME - DWORD processId; - #endif /* tty */ char *term; diff --git a/sshd.c b/sshd.c index d37c29a..6574088 100644 --- a/sshd.c +++ b/sshd.c @@ -1605,20 +1605,16 @@ server_accept_loop(int *sock_in, int *sock_out, int *newsock, int *config_s) &si, &pi) == FALSE) { debug("CreateProcess failure: %d", GetLastError()); exit(1); - } - - /* - * Close child thread and process handles so it can go away - */ - - CloseHandle(pi.hThread); - CloseHandle(pi.hProcess); + } close(*newsock); close(startup_pipes[i]); startup_pipes[i] = -1; startups--; + sw_add_child(pi.hProcess, pi.dwProcessId); + CloseHandle(pi.hThread); + CloseHandle(pi.hProcess); pid = pi.dwProcessId; }