Make __WCLONE option for wait4(2) and flags for clone(2) work properly.

This commit is contained in:
Naoki Hamada
2014-09-29 16:28:55 +09:00
committed by Tomoki Shirasawa
parent 66db108dd3
commit 2997274470
3 changed files with 31 additions and 7 deletions

View File

@@ -112,6 +112,7 @@
#define WEXITED 0x00000004 #define WEXITED 0x00000004
#define WCONTINUED 0x00000008 #define WCONTINUED 0x00000008
#define WNOWAIT 0x01000000 /* Don't reap, just poll status. */ #define WNOWAIT 0x01000000 /* Don't reap, just poll status. */
#define __WCLONE 0x80000000
/* If WIFEXITED(STATUS), the low-order 8 bits of the status. */ /* If WIFEXITED(STATUS), the low-order 8 bits of the status. */
#define __WEXITSTATUS(status) (((status) & 0xff00) >> 8) #define __WEXITSTATUS(status) (((status) & 0xff00) >> 8)
@@ -224,6 +225,9 @@ struct fork_tree_node {
/* Store event related to signal. For example, /* Store event related to signal. For example,
it represents that the proceess has been resumed by SIGCONT. */ it represents that the proceess has been resumed by SIGCONT. */
int signal_flags; int signal_flags;
/* Store signal sent to parent when the process terminates. */
int termsig;
}; };
void hold_fork_tree_node(struct fork_tree_node *ftn); void hold_fork_tree_node(struct fork_tree_node *ftn);

View File

@@ -202,6 +202,11 @@ struct process *clone_process(struct process *org, unsigned long pc,
unsigned long sp, int clone_flags) unsigned long sp, int clone_flags)
{ {
struct process *proc; struct process *proc;
int termsig = clone_flags & 0xff;
if (termsig < 0 || _NSIG < termsig) {
return -EINVAL;
}
if ((proc = ihk_mc_alloc_pages(KERNEL_STACK_NR_PAGES, if ((proc = ihk_mc_alloc_pages(KERNEL_STACK_NR_PAGES,
IHK_MC_AP_NOWAIT)) == NULL) { IHK_MC_AP_NOWAIT)) == NULL) {
@@ -228,6 +233,8 @@ struct process *clone_process(struct process *org, unsigned long pc,
goto err_free_sigshared; goto err_free_sigshared;
} }
proc->ftn->termsig = termsig;
init_fork_tree_node(proc->ftn, (clone_flags & CLONE_VM) ? NULL : org->ftn, init_fork_tree_node(proc->ftn, (clone_flags & CLONE_VM) ? NULL : org->ftn,
proc); proc);

View File

@@ -389,7 +389,8 @@ SYSCALL_DECLARE(wait4)
int empty = 1; int empty = 1;
dkprintf("wait4,proc->pid=%d,pid=%d\n", proc->pid, pid); dkprintf("wait4,proc->pid=%d,pid=%d\n", proc->pid, pid);
if (options & ~(WNOHANG | WUNTRACED | WCONTINUED)) { if (options & ~(WNOHANG | WUNTRACED | WCONTINUED | __WCLONE)) {
dkprintf("wait4: unexpected options(%x).\n", options);
ret = -EINVAL; ret = -EINVAL;
goto exit; goto exit;
} }
@@ -399,6 +400,10 @@ SYSCALL_DECLARE(wait4)
ihk_mc_spinlock_lock_noirq(&proc->ftn->lock); ihk_mc_spinlock_lock_noirq(&proc->ftn->lock);
list_for_each_entry_safe(child_iter, next, &proc->ftn->children, siblings_list) { list_for_each_entry_safe(child_iter, next, &proc->ftn->children, siblings_list) {
if (!(!!(options & __WCLONE) ^ (child_iter->termsig == SIGCHLD))) {
continue;
}
ihk_mc_spinlock_lock_noirq(&child_iter->lock); ihk_mc_spinlock_lock_noirq(&child_iter->lock);
if ((pid < 0 && -pid == child_iter->pgid) || if ((pid < 0 && -pid == child_iter->pgid) ||
@@ -439,6 +444,10 @@ SYSCALL_DECLARE(wait4)
} }
list_for_each_entry_safe(child_iter, next, &proc->ftn->ptrace_children, ptrace_siblings_list) { list_for_each_entry_safe(child_iter, next, &proc->ftn->ptrace_children, ptrace_siblings_list) {
if (!(!!(options & __WCLONE) ^ (child_iter->termsig == SIGCHLD))) {
continue;
}
ihk_mc_spinlock_lock_noirq(&child_iter->lock); ihk_mc_spinlock_lock_noirq(&child_iter->lock);
if ((pid < 0 && -pid == child_iter->pgid) || if ((pid < 0 && -pid == child_iter->pgid) ||
@@ -554,7 +563,7 @@ terminate(int rc, int sig, ihk_mc_user_context_t *ctx)
ftn->owner = NULL; ftn->owner = NULL;
ihk_mc_spinlock_unlock_noirq(&ftn->lock); ihk_mc_spinlock_unlock_noirq(&ftn->lock);
/* Send SIGCHLD to parent */ /* Send signal to parent */
if (ftn->parent) { if (ftn->parent) {
int parent_owner_pid; int parent_owner_pid;
@@ -576,21 +585,22 @@ terminate(int rc, int sig, ihk_mc_user_context_t *ctx)
parent_owner = ftn->parent->owner; parent_owner = ftn->parent->owner;
parent_owner_pid = parent_owner ? ftn->parent->owner->pid : 0; parent_owner_pid = parent_owner ? ftn->parent->owner->pid : 0;
ihk_mc_spinlock_unlock_noirq(&ftn->parent->lock); ihk_mc_spinlock_unlock_noirq(&ftn->parent->lock);
if (parent_owner) { if (parent_owner && (ftn->termsig != 0)) {
struct siginfo info; struct siginfo info;
memset(&info, '\0', sizeof info); memset(&info, '\0', sizeof info);
info.si_signo = SIGCHLD; info.si_signo = SIGCHLD;
info.si_code = sig? ((sig & 0x80)? CLD_DUMPED: CLD_KILLED): CLD_EXITED; info.si_code = sig? ((sig & 0x80)? CLD_DUMPED: CLD_KILLED): CLD_EXITED;
info._sifields._sigchld.si_pid = proc->pid; info._sifields._sigchld.si_pid = proc->pid;
info._sifields._sigchld.si_status = ((rc & 0x00ff) << 8) | (sig & 0xff); info._sifields._sigchld.si_status = ((rc & 0x00ff) << 8) | (sig & 0xff);
dkprintf("terminate,kill SIGCHLD,target pid=%d\n", dkprintf("terminate,kill %d,target pid=%d\n",
parent_owner_pid); ftn->termsig, parent_owner_pid);
error = do_kill(ftn->parent->owner->pid, -1, SIGCHLD, &info); error = do_kill(ftn->parent->owner->pid, -1, SIGCHLD, &info);
/* /*
sigchld_parent(ftn->parent->owner, 0); sigchld_parent(ftn->parent->owner, 0);
*/ */
dkprintf("terminate,klll SIGCHLD,error=%d\n", dkprintf("terminate,klll %d,error=%d\n",
error); ftn->termsig, error);
} }
release_fork_tree_node(ftn->parent); release_fork_tree_node(ftn->parent);
@@ -2363,13 +2373,16 @@ SYSCALL_DECLARE(ptrace)
switch(request) { switch(request) {
case PTRACE_TRACEME: case PTRACE_TRACEME:
dkprintf("ptrace: PTRACE_TRACEME\n");
error = ptrace_traceme(); error = ptrace_traceme();
break; break;
case PTRACE_KILL: case PTRACE_KILL:
case PTRACE_CONT: case PTRACE_CONT:
dkprintf("ptrace: PTRACE_KILL/CONT\n");
error = ptrace_wakeup_sig(pid, request, data); error = ptrace_wakeup_sig(pid, request, data);
break; break;
default: default:
dkprintf("ptrace: unimplemented ptrace called.\n");
error = 0; error = 0;
break; break;
} }