support waitid
send SIGCHLD to parent when SIGSTOP or SIGCONT received refs #425 refs #283
This commit is contained in:
@@ -95,6 +95,7 @@ SYSCALL_HANDLED(234, tgkill)
|
||||
SYSCALL_HANDLED(237, mbind)
|
||||
SYSCALL_HANDLED(238, set_mempolicy)
|
||||
SYSCALL_HANDLED(239, get_mempolicy)
|
||||
SYSCALL_HANDLED(247, waitid)
|
||||
SYSCALL_HANDLED(256, migrate_pages)
|
||||
SYSCALL_HANDLED(273, set_robust_list)
|
||||
SYSCALL_HANDLED(279, move_pages)
|
||||
|
||||
@@ -525,6 +525,8 @@ do_signal(unsigned long rc, void *regs0, struct process *proc, struct sig_pendin
|
||||
}
|
||||
else {
|
||||
int coredumped = 0;
|
||||
siginfo_t info;
|
||||
|
||||
kfree(pending);
|
||||
ihk_mc_spinlock_unlock(&proc->sighandler->lock, irqstate);
|
||||
switch (sig) {
|
||||
@@ -532,6 +534,12 @@ do_signal(unsigned long rc, void *regs0, struct process *proc, struct sig_pendin
|
||||
case SIGTSTP:
|
||||
case SIGTTIN:
|
||||
case SIGTTOU:
|
||||
memset(&info, '\0', sizeof info);
|
||||
info.si_signo = SIGCHLD;
|
||||
info.si_code = CLD_STOPPED;
|
||||
info._sifields._sigchld.si_pid = proc->ftn->pid;
|
||||
info._sifields._sigchld.si_status = (sig << 8) | 0x7f;
|
||||
do_kill(proc->ftn->parent->pid, -1, SIGCHLD, &info, 0);
|
||||
if(ptraceflag){
|
||||
ptrace_report_signal(proc, orgsig);
|
||||
}
|
||||
@@ -580,6 +588,13 @@ do_signal(unsigned long rc, void *regs0, struct process *proc, struct sig_pendin
|
||||
dkprintf("SIGTRAP(): woken up\n");
|
||||
break;
|
||||
case SIGCONT:
|
||||
memset(&info, '\0', sizeof info);
|
||||
info.si_signo = SIGCHLD;
|
||||
info.si_code = CLD_CONTINUED;
|
||||
info._sifields._sigchld.si_pid = proc->ftn->pid;
|
||||
info._sifields._sigchld.si_status = 0x0000ffff;
|
||||
do_kill(proc->ftn->parent->pid, -1, SIGCHLD, &info, 0);
|
||||
ftn->signal_flags = SIGNAL_STOP_CONTINUED;
|
||||
dkprintf("do_signal,SIGCONT,do nothing\n");
|
||||
break;
|
||||
case SIGQUIT:
|
||||
@@ -606,58 +621,82 @@ do_signal(unsigned long rc, void *regs0, struct process *proc, struct sig_pendin
|
||||
}
|
||||
}
|
||||
|
||||
static struct sig_pending *
|
||||
getsigpending(struct process *proc, int delflag){
|
||||
struct list_head *head;
|
||||
ihk_spinlock_t *lock;
|
||||
struct sig_pending *next;
|
||||
struct sig_pending *pending;
|
||||
__sigset_t w;
|
||||
int irqstate;
|
||||
|
||||
w = proc->sigmask.__val[0];
|
||||
|
||||
lock = &proc->sigshared->lock;
|
||||
head = &proc->sigshared->sigpending;
|
||||
for(;;){
|
||||
irqstate = ihk_mc_spinlock_lock(lock);
|
||||
list_for_each_entry_safe(pending, next, head, list){
|
||||
if(!(pending->sigmask.__val[0] & w)){
|
||||
if(delflag)
|
||||
list_del(&pending->list);
|
||||
ihk_mc_spinlock_unlock(lock, irqstate);
|
||||
return pending;
|
||||
}
|
||||
}
|
||||
ihk_mc_spinlock_unlock(lock, irqstate);
|
||||
|
||||
if(lock == &proc->sigpendinglock)
|
||||
return NULL;
|
||||
lock = &proc->sigpendinglock;
|
||||
head = &proc->sigpending;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
struct sig_pending *
|
||||
hassigpending(struct process *proc)
|
||||
{
|
||||
return getsigpending(proc, 0);
|
||||
}
|
||||
|
||||
void
|
||||
check_signal(unsigned long rc, void *regs0)
|
||||
{
|
||||
struct x86_regs *regs = regs0;
|
||||
struct process *proc;
|
||||
struct sig_pending *pending;
|
||||
struct sig_pending *next;
|
||||
struct list_head *head;
|
||||
ihk_spinlock_t *lock;
|
||||
int irqstate;
|
||||
__sigset_t w;
|
||||
|
||||
if(clv == NULL)
|
||||
return;
|
||||
proc = cpu_local_var(current);
|
||||
if(proc == NULL || proc->ftn->pid == 0)
|
||||
if(proc == NULL || proc->ftn->pid == 0){
|
||||
struct process *p;
|
||||
|
||||
irqstate = ihk_mc_spinlock_lock(&(cpu_local_var(runq_lock)));
|
||||
list_for_each_entry(p, &(cpu_local_var(runq)), sched_list){
|
||||
if(p->ftn->pid <= 0)
|
||||
continue;
|
||||
if(p->ftn->status == PS_INTERRUPTIBLE &&
|
||||
hassigpending(p)){
|
||||
p->ftn->status = PS_RUNNING;
|
||||
ihk_mc_spinlock_unlock(&(cpu_local_var(runq_lock)), irqstate);
|
||||
// schedule();
|
||||
return;
|
||||
}
|
||||
}
|
||||
ihk_mc_spinlock_unlock(&(cpu_local_var(runq_lock)), irqstate);
|
||||
return;
|
||||
}
|
||||
|
||||
if(regs != NULL && (regs->rsp & 0x8000000000000000)) {
|
||||
return;
|
||||
}
|
||||
|
||||
for(;;){
|
||||
w = proc->sigmask.__val[0];
|
||||
lock = &proc->sigshared->lock;
|
||||
head = &proc->sigshared->sigpending;
|
||||
pending = NULL;
|
||||
irqstate = ihk_mc_spinlock_lock(lock);
|
||||
list_for_each_entry_safe(pending, next, head, list){
|
||||
if(!(pending->sigmask.__val[0] & w)){
|
||||
list_del(&pending->list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(&pending->list == head)
|
||||
pending = NULL;
|
||||
ihk_mc_spinlock_unlock(lock, irqstate);
|
||||
|
||||
if(!pending){
|
||||
lock = &proc->sigpendinglock;
|
||||
head = &proc->sigpending;
|
||||
irqstate = ihk_mc_spinlock_lock(lock);
|
||||
list_for_each_entry_safe(pending, next, head, list){
|
||||
if(!(pending->sigmask.__val[0] & w)){
|
||||
list_del(&pending->list);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(&pending->list == head)
|
||||
pending = NULL;
|
||||
ihk_mc_spinlock_unlock(lock, irqstate);
|
||||
}
|
||||
pending = getsigpending(proc, 1);
|
||||
if(!pending) {
|
||||
dkprintf("check_signal,queue is empty\n");
|
||||
return;
|
||||
|
||||
@@ -122,6 +122,11 @@
|
||||
#define WNOWAIT 0x01000000 /* Don't reap, just poll status. */
|
||||
#define __WCLONE 0x80000000
|
||||
|
||||
/* idtype */
|
||||
#define P_ALL 0
|
||||
#define P_PID 1
|
||||
#define P_PGID 2
|
||||
|
||||
/* If WIFEXITED(STATUS), the low-order 8 bits of the status. */
|
||||
#define __WEXITSTATUS(status) (((status) & 0xff00) >> 8)
|
||||
|
||||
|
||||
110
kernel/syscall.c
110
kernel/syscall.c
@@ -97,6 +97,7 @@ static char *syscall_name[] MCKERNEL_UNUSED = {
|
||||
void check_signal(unsigned long rc, void *regs);
|
||||
void do_signal(long rc, void *regs, struct process *proc, struct sig_pending *pending);
|
||||
extern unsigned long do_kill(int pid, int tid, int sig, struct siginfo *info, int ptracecont);
|
||||
extern struct sigpending *hassigpending(struct process *proc);
|
||||
int copy_from_user(struct process *, void *, const void *, size_t);
|
||||
int copy_to_user(struct process *, void *, const void *, size_t);
|
||||
void do_setpgid(int, int);
|
||||
@@ -383,26 +384,20 @@ static int wait_continued(struct process *proc, struct fork_tree_node *child, in
|
||||
/*
|
||||
* From glibc: INLINE_SYSCALL (wait4, 4, pid, stat_loc, options, NULL);
|
||||
*/
|
||||
SYSCALL_DECLARE(wait4)
|
||||
static int
|
||||
do_wait(int pid, int *status, int options, void *rusage, ihk_mc_user_context_t *ctx)
|
||||
{
|
||||
struct process *proc = cpu_local_var(current);
|
||||
struct fork_tree_node *child_iter, *next;
|
||||
int pid = (int)ihk_mc_syscall_arg0(ctx);
|
||||
int pgid = proc->ftn->pgid;
|
||||
int *status = (int *)ihk_mc_syscall_arg1(ctx);
|
||||
int options = (int)ihk_mc_syscall_arg2(ctx);
|
||||
int ret;
|
||||
struct waitq_entry waitpid_wqe;
|
||||
int empty = 1;
|
||||
int orgpid = pid;
|
||||
|
||||
dkprintf("wait4,proc->pid=%d,pid=%d\n", proc->ftn->pid, pid);
|
||||
if (options & ~(WNOHANG | WUNTRACED | WCONTINUED | __WCLONE)) {
|
||||
dkprintf("wait4: unexpected options(%x).\n", options);
|
||||
ret = -EINVAL;
|
||||
goto exit;
|
||||
}
|
||||
rescan:
|
||||
pid = (int)ihk_mc_syscall_arg0(ctx);
|
||||
pid = orgpid;
|
||||
|
||||
ihk_mc_spinlock_lock_noirq(&proc->ftn->lock);
|
||||
list_for_each_entry_safe(child_iter, next, &proc->ftn->children, siblings_list) {
|
||||
@@ -420,11 +415,14 @@ SYSCALL_DECLARE(wait4)
|
||||
|
||||
empty = 0;
|
||||
|
||||
if(child_iter->status == PS_ZOMBIE) {
|
||||
if((options & WEXITED) &&
|
||||
child_iter->status == PS_ZOMBIE) {
|
||||
ret = wait_zombie(proc, child_iter, status, ctx);
|
||||
if(ret) {
|
||||
list_del(&child_iter->siblings_list);
|
||||
release_fork_tree_node(child_iter);
|
||||
if(!(options & WNOWAIT)){
|
||||
list_del(&child_iter->siblings_list);
|
||||
release_fork_tree_node(child_iter);
|
||||
}
|
||||
goto out_found;
|
||||
}
|
||||
}
|
||||
@@ -434,6 +432,9 @@ SYSCALL_DECLARE(wait4)
|
||||
/* Not ptraced and in stopped state and WUNTRACED is specified */
|
||||
ret = wait_stopped(proc, child_iter, status, options);
|
||||
if(ret) {
|
||||
if(!(options & WNOWAIT)){
|
||||
child_iter->signal_flags &= ~SIGNAL_STOP_STOPPED;
|
||||
}
|
||||
goto out_found;
|
||||
}
|
||||
}
|
||||
@@ -442,6 +443,9 @@ SYSCALL_DECLARE(wait4)
|
||||
(options & WCONTINUED)) {
|
||||
ret = wait_continued(proc, child_iter, status, options);
|
||||
if(ret) {
|
||||
if(!(options & WNOWAIT)){
|
||||
child_iter->signal_flags &= ~SIGNAL_STOP_CONTINUED;
|
||||
}
|
||||
goto out_found;
|
||||
}
|
||||
}
|
||||
@@ -464,11 +468,14 @@ SYSCALL_DECLARE(wait4)
|
||||
|
||||
empty = 0;
|
||||
|
||||
if(child_iter->status == PS_ZOMBIE) {
|
||||
if((options & WEXITED) &&
|
||||
child_iter->status == PS_ZOMBIE) {
|
||||
ret = wait_zombie(proc, child_iter, status, ctx);
|
||||
if(ret) {
|
||||
list_del(&child_iter->ptrace_siblings_list);
|
||||
release_fork_tree_node(child_iter);
|
||||
if(!(options & WNOWAIT)){
|
||||
list_del(&child_iter->ptrace_siblings_list);
|
||||
release_fork_tree_node(child_iter);
|
||||
}
|
||||
goto out_found;
|
||||
}
|
||||
}
|
||||
@@ -477,6 +484,9 @@ SYSCALL_DECLARE(wait4)
|
||||
/* ptraced and in stopped or trace-stopped state */
|
||||
ret = wait_stopped(proc, child_iter, status, options);
|
||||
if(ret) {
|
||||
if(!(options & WNOWAIT)){
|
||||
child_iter->signal_flags &= ~SIGNAL_STOP_STOPPED;
|
||||
}
|
||||
goto out_found;
|
||||
}
|
||||
} else {
|
||||
@@ -487,6 +497,9 @@ SYSCALL_DECLARE(wait4)
|
||||
(options & WCONTINUED)) {
|
||||
ret = wait_continued(proc, child_iter, status, options);
|
||||
if(ret) {
|
||||
if(!(options & WNOWAIT)){
|
||||
child_iter->signal_flags &= ~SIGNAL_STOP_CONTINUED;
|
||||
}
|
||||
goto out_found;
|
||||
}
|
||||
}
|
||||
@@ -513,6 +526,11 @@ SYSCALL_DECLARE(wait4)
|
||||
waitq_prepare_to_wait(&proc->ftn->waitpid_q, &waitpid_wqe, PS_INTERRUPTIBLE);
|
||||
|
||||
ihk_mc_spinlock_unlock_noirq(&proc->ftn->lock);
|
||||
if(hassigpending(proc)){
|
||||
waitq_finish_wait(&proc->ftn->waitpid_q, &waitpid_wqe);
|
||||
return -EINTR;
|
||||
}
|
||||
|
||||
|
||||
schedule();
|
||||
dkprintf("wait4(): woken up\n");
|
||||
@@ -532,6 +550,66 @@ SYSCALL_DECLARE(wait4)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
SYSCALL_DECLARE(wait4)
|
||||
{
|
||||
int pid = (int)ihk_mc_syscall_arg0(ctx);
|
||||
int *status = (int *)ihk_mc_syscall_arg1(ctx);
|
||||
int options = (int)ihk_mc_syscall_arg2(ctx);
|
||||
void *rusage = (void *)ihk_mc_syscall_arg3(ctx);
|
||||
|
||||
if(options & ~(WNOHANG | WUNTRACED | WCONTINUED | __WCLONE)){
|
||||
dkprintf("wait4: unexpected options(%x).\n", options);
|
||||
return -EINVAL;
|
||||
}
|
||||
return do_wait(pid, status, WEXITED | options, rusage, ctx);
|
||||
}
|
||||
|
||||
SYSCALL_DECLARE(waitid)
|
||||
{
|
||||
int idtype = (int)ihk_mc_syscall_arg0(ctx);
|
||||
int id = (int)ihk_mc_syscall_arg1(ctx);
|
||||
siginfo_t *info = (siginfo_t *)ihk_mc_syscall_arg2(ctx);
|
||||
int options = (int)ihk_mc_syscall_arg3(ctx);
|
||||
int pid;
|
||||
int status;
|
||||
int rc;
|
||||
|
||||
if(idtype == P_PID)
|
||||
pid = id;
|
||||
else if(idtype == P_PGID)
|
||||
pid = -id;
|
||||
else if(idtype == P_ALL)
|
||||
pid = -1;
|
||||
else
|
||||
return -EINVAL;
|
||||
if(options & ~(WEXITED | WSTOPPED | WCONTINUED | WNOHANG | WNOWAIT | __WCLONE)){
|
||||
dkprintf("waitid: unexpected options(%x).\n", options);
|
||||
return -EINVAL;
|
||||
}
|
||||
if(!(options & (WEXITED | WSTOPPED | WCONTINUED))){
|
||||
dkprintf("waitid: no waiting status(%x).\n", options);
|
||||
return -EINVAL;
|
||||
}
|
||||
rc = do_wait(pid, &status, options, NULL, ctx);
|
||||
if(rc < 0)
|
||||
return rc;
|
||||
if(rc && info){
|
||||
memset(info, '\0', sizeof(siginfo_t));
|
||||
info->si_signo = SIGCHLD;
|
||||
info->_sifields._sigchld.si_pid = rc;
|
||||
info->_sifields._sigchld.si_status = status;
|
||||
if((status & 0x000000ff) == 0x0000007f)
|
||||
info->si_code = CLD_STOPPED;
|
||||
else if((status & 0x0000ffff) == 0x0000ffff)
|
||||
info->si_code = CLD_CONTINUED;
|
||||
else if(status & 0x000000ff)
|
||||
info->si_code = CLD_KILLED;
|
||||
else
|
||||
info->si_code = CLD_EXITED;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ptrace_terminate_tracer(struct process *proc, struct fork_tree_node *tracer);
|
||||
|
||||
void
|
||||
|
||||
Reference in New Issue
Block a user