SIGCHLD and waitpid implementation with sshd on board

This commit is contained in:
manojampalam 2016-03-25 21:22:13 -07:00
parent ed535436d0
commit 77b0ec86df
11 changed files with 135 additions and 72 deletions

View File

@ -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) {

View File

@ -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

View File

@ -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);
int waitpid(int pid, int *status, int options);

View File

@ -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))

View File

@ -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);

View File

@ -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) {

View File

@ -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);

View File

@ -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);

View File

@ -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.
*/

View File

@ -35,10 +35,6 @@ struct Session {
struct passwd *pw;
Authctxt *authctxt;
pid_t pid;
#ifdef WIN32_FIXME
DWORD processId;
#endif
/* tty */
char *term;

12
sshd.c
View File

@ -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;
}