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 WCONTINUED 0x00000008
#define WNOWAIT 0x01000000 /* Don't reap, just poll status. */
#define __WCLONE 0x80000000
/* If WIFEXITED(STATUS), the low-order 8 bits of the status. */
#define __WEXITSTATUS(status) (((status) & 0xff00) >> 8)
@@ -224,6 +225,9 @@ struct fork_tree_node {
/* Store event related to signal. For example,
it represents that the proceess has been resumed by SIGCONT. */
int signal_flags;
/* Store signal sent to parent when the process terminates. */
int termsig;
};
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)
{
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,
IHK_MC_AP_NOWAIT)) == NULL) {
@@ -228,6 +233,8 @@ struct process *clone_process(struct process *org, unsigned long pc,
goto err_free_sigshared;
}
proc->ftn->termsig = termsig;
init_fork_tree_node(proc->ftn, (clone_flags & CLONE_VM) ? NULL : org->ftn,
proc);

View File

@@ -389,7 +389,8 @@ SYSCALL_DECLARE(wait4)
int empty = 1;
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;
goto exit;
}
@@ -399,6 +400,10 @@ SYSCALL_DECLARE(wait4)
ihk_mc_spinlock_lock_noirq(&proc->ftn->lock);
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);
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) {
if (!(!!(options & __WCLONE) ^ (child_iter->termsig == SIGCHLD))) {
continue;
}
ihk_mc_spinlock_lock_noirq(&child_iter->lock);
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;
ihk_mc_spinlock_unlock_noirq(&ftn->lock);
/* Send SIGCHLD to parent */
/* Send signal to parent */
if (ftn->parent) {
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_pid = parent_owner ? ftn->parent->owner->pid : 0;
ihk_mc_spinlock_unlock_noirq(&ftn->parent->lock);
if (parent_owner) {
if (parent_owner && (ftn->termsig != 0)) {
struct siginfo info;
memset(&info, '\0', sizeof info);
info.si_signo = SIGCHLD;
info.si_code = sig? ((sig & 0x80)? CLD_DUMPED: CLD_KILLED): CLD_EXITED;
info._sifields._sigchld.si_pid = proc->pid;
info._sifields._sigchld.si_status = ((rc & 0x00ff) << 8) | (sig & 0xff);
dkprintf("terminate,kill SIGCHLD,target pid=%d\n",
parent_owner_pid);
dkprintf("terminate,kill %d,target pid=%d\n",
ftn->termsig, parent_owner_pid);
error = do_kill(ftn->parent->owner->pid, -1, SIGCHLD, &info);
/*
sigchld_parent(ftn->parent->owner, 0);
*/
dkprintf("terminate,klll SIGCHLD,error=%d\n",
error);
dkprintf("terminate,klll %d,error=%d\n",
ftn->termsig, error);
}
release_fork_tree_node(ftn->parent);
@@ -2363,13 +2373,16 @@ SYSCALL_DECLARE(ptrace)
switch(request) {
case PTRACE_TRACEME:
dkprintf("ptrace: PTRACE_TRACEME\n");
error = ptrace_traceme();
break;
case PTRACE_KILL:
case PTRACE_CONT:
dkprintf("ptrace: PTRACE_KILL/CONT\n");
error = ptrace_wakeup_sig(pid, request, data);
break;
default:
dkprintf("ptrace: unimplemented ptrace called.\n");
error = 0;
break;
}