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(237, mbind)
|
||||||
SYSCALL_HANDLED(238, set_mempolicy)
|
SYSCALL_HANDLED(238, set_mempolicy)
|
||||||
SYSCALL_HANDLED(239, get_mempolicy)
|
SYSCALL_HANDLED(239, get_mempolicy)
|
||||||
|
SYSCALL_HANDLED(247, waitid)
|
||||||
SYSCALL_HANDLED(256, migrate_pages)
|
SYSCALL_HANDLED(256, migrate_pages)
|
||||||
SYSCALL_HANDLED(273, set_robust_list)
|
SYSCALL_HANDLED(273, set_robust_list)
|
||||||
SYSCALL_HANDLED(279, move_pages)
|
SYSCALL_HANDLED(279, move_pages)
|
||||||
|
|||||||
@ -525,6 +525,8 @@ do_signal(unsigned long rc, void *regs0, struct process *proc, struct sig_pendin
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
int coredumped = 0;
|
int coredumped = 0;
|
||||||
|
siginfo_t info;
|
||||||
|
|
||||||
kfree(pending);
|
kfree(pending);
|
||||||
ihk_mc_spinlock_unlock(&proc->sighandler->lock, irqstate);
|
ihk_mc_spinlock_unlock(&proc->sighandler->lock, irqstate);
|
||||||
switch (sig) {
|
switch (sig) {
|
||||||
@ -532,6 +534,12 @@ do_signal(unsigned long rc, void *regs0, struct process *proc, struct sig_pendin
|
|||||||
case SIGTSTP:
|
case SIGTSTP:
|
||||||
case SIGTTIN:
|
case SIGTTIN:
|
||||||
case SIGTTOU:
|
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){
|
if(ptraceflag){
|
||||||
ptrace_report_signal(proc, orgsig);
|
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");
|
dkprintf("SIGTRAP(): woken up\n");
|
||||||
break;
|
break;
|
||||||
case SIGCONT:
|
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");
|
dkprintf("do_signal,SIGCONT,do nothing\n");
|
||||||
break;
|
break;
|
||||||
case SIGQUIT:
|
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
|
void
|
||||||
check_signal(unsigned long rc, void *regs0)
|
check_signal(unsigned long rc, void *regs0)
|
||||||
{
|
{
|
||||||
struct x86_regs *regs = regs0;
|
struct x86_regs *regs = regs0;
|
||||||
struct process *proc;
|
struct process *proc;
|
||||||
struct sig_pending *pending;
|
struct sig_pending *pending;
|
||||||
struct sig_pending *next;
|
|
||||||
struct list_head *head;
|
|
||||||
ihk_spinlock_t *lock;
|
|
||||||
int irqstate;
|
int irqstate;
|
||||||
__sigset_t w;
|
|
||||||
|
|
||||||
if(clv == NULL)
|
if(clv == NULL)
|
||||||
return;
|
return;
|
||||||
proc = cpu_local_var(current);
|
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;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if(regs != NULL && (regs->rsp & 0x8000000000000000)) {
|
if(regs != NULL && (regs->rsp & 0x8000000000000000)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
for(;;){
|
for(;;){
|
||||||
w = proc->sigmask.__val[0];
|
pending = getsigpending(proc, 1);
|
||||||
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);
|
|
||||||
}
|
|
||||||
if(!pending) {
|
if(!pending) {
|
||||||
dkprintf("check_signal,queue is empty\n");
|
dkprintf("check_signal,queue is empty\n");
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -122,6 +122,11 @@
|
|||||||
#define WNOWAIT 0x01000000 /* Don't reap, just poll status. */
|
#define WNOWAIT 0x01000000 /* Don't reap, just poll status. */
|
||||||
#define __WCLONE 0x80000000
|
#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. */
|
/* If WIFEXITED(STATUS), the low-order 8 bits of the status. */
|
||||||
#define __WEXITSTATUS(status) (((status) & 0xff00) >> 8)
|
#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 check_signal(unsigned long rc, void *regs);
|
||||||
void do_signal(long rc, void *regs, struct process *proc, struct sig_pending *pending);
|
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 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_from_user(struct process *, void *, const void *, size_t);
|
||||||
int copy_to_user(struct process *, void *, const void *, size_t);
|
int copy_to_user(struct process *, void *, const void *, size_t);
|
||||||
void do_setpgid(int, int);
|
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);
|
* 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 process *proc = cpu_local_var(current);
|
||||||
struct fork_tree_node *child_iter, *next;
|
struct fork_tree_node *child_iter, *next;
|
||||||
int pid = (int)ihk_mc_syscall_arg0(ctx);
|
|
||||||
int pgid = proc->ftn->pgid;
|
int pgid = proc->ftn->pgid;
|
||||||
int *status = (int *)ihk_mc_syscall_arg1(ctx);
|
|
||||||
int options = (int)ihk_mc_syscall_arg2(ctx);
|
|
||||||
int ret;
|
int ret;
|
||||||
struct waitq_entry waitpid_wqe;
|
struct waitq_entry waitpid_wqe;
|
||||||
int empty = 1;
|
int empty = 1;
|
||||||
|
int orgpid = pid;
|
||||||
|
|
||||||
dkprintf("wait4,proc->pid=%d,pid=%d\n", proc->ftn->pid, 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:
|
rescan:
|
||||||
pid = (int)ihk_mc_syscall_arg0(ctx);
|
pid = orgpid;
|
||||||
|
|
||||||
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) {
|
||||||
@ -420,11 +415,14 @@ SYSCALL_DECLARE(wait4)
|
|||||||
|
|
||||||
empty = 0;
|
empty = 0;
|
||||||
|
|
||||||
if(child_iter->status == PS_ZOMBIE) {
|
if((options & WEXITED) &&
|
||||||
|
child_iter->status == PS_ZOMBIE) {
|
||||||
ret = wait_zombie(proc, child_iter, status, ctx);
|
ret = wait_zombie(proc, child_iter, status, ctx);
|
||||||
if(ret) {
|
if(ret) {
|
||||||
list_del(&child_iter->siblings_list);
|
if(!(options & WNOWAIT)){
|
||||||
release_fork_tree_node(child_iter);
|
list_del(&child_iter->siblings_list);
|
||||||
|
release_fork_tree_node(child_iter);
|
||||||
|
}
|
||||||
goto out_found;
|
goto out_found;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -434,6 +432,9 @@ SYSCALL_DECLARE(wait4)
|
|||||||
/* Not ptraced and in stopped state and WUNTRACED is specified */
|
/* Not ptraced and in stopped state and WUNTRACED is specified */
|
||||||
ret = wait_stopped(proc, child_iter, status, options);
|
ret = wait_stopped(proc, child_iter, status, options);
|
||||||
if(ret) {
|
if(ret) {
|
||||||
|
if(!(options & WNOWAIT)){
|
||||||
|
child_iter->signal_flags &= ~SIGNAL_STOP_STOPPED;
|
||||||
|
}
|
||||||
goto out_found;
|
goto out_found;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -442,6 +443,9 @@ SYSCALL_DECLARE(wait4)
|
|||||||
(options & WCONTINUED)) {
|
(options & WCONTINUED)) {
|
||||||
ret = wait_continued(proc, child_iter, status, options);
|
ret = wait_continued(proc, child_iter, status, options);
|
||||||
if(ret) {
|
if(ret) {
|
||||||
|
if(!(options & WNOWAIT)){
|
||||||
|
child_iter->signal_flags &= ~SIGNAL_STOP_CONTINUED;
|
||||||
|
}
|
||||||
goto out_found;
|
goto out_found;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -464,11 +468,14 @@ SYSCALL_DECLARE(wait4)
|
|||||||
|
|
||||||
empty = 0;
|
empty = 0;
|
||||||
|
|
||||||
if(child_iter->status == PS_ZOMBIE) {
|
if((options & WEXITED) &&
|
||||||
|
child_iter->status == PS_ZOMBIE) {
|
||||||
ret = wait_zombie(proc, child_iter, status, ctx);
|
ret = wait_zombie(proc, child_iter, status, ctx);
|
||||||
if(ret) {
|
if(ret) {
|
||||||
list_del(&child_iter->ptrace_siblings_list);
|
if(!(options & WNOWAIT)){
|
||||||
release_fork_tree_node(child_iter);
|
list_del(&child_iter->ptrace_siblings_list);
|
||||||
|
release_fork_tree_node(child_iter);
|
||||||
|
}
|
||||||
goto out_found;
|
goto out_found;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -477,6 +484,9 @@ SYSCALL_DECLARE(wait4)
|
|||||||
/* ptraced and in stopped or trace-stopped state */
|
/* ptraced and in stopped or trace-stopped state */
|
||||||
ret = wait_stopped(proc, child_iter, status, options);
|
ret = wait_stopped(proc, child_iter, status, options);
|
||||||
if(ret) {
|
if(ret) {
|
||||||
|
if(!(options & WNOWAIT)){
|
||||||
|
child_iter->signal_flags &= ~SIGNAL_STOP_STOPPED;
|
||||||
|
}
|
||||||
goto out_found;
|
goto out_found;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -487,6 +497,9 @@ SYSCALL_DECLARE(wait4)
|
|||||||
(options & WCONTINUED)) {
|
(options & WCONTINUED)) {
|
||||||
ret = wait_continued(proc, child_iter, status, options);
|
ret = wait_continued(proc, child_iter, status, options);
|
||||||
if(ret) {
|
if(ret) {
|
||||||
|
if(!(options & WNOWAIT)){
|
||||||
|
child_iter->signal_flags &= ~SIGNAL_STOP_CONTINUED;
|
||||||
|
}
|
||||||
goto out_found;
|
goto out_found;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -513,6 +526,11 @@ SYSCALL_DECLARE(wait4)
|
|||||||
waitq_prepare_to_wait(&proc->ftn->waitpid_q, &waitpid_wqe, PS_INTERRUPTIBLE);
|
waitq_prepare_to_wait(&proc->ftn->waitpid_q, &waitpid_wqe, PS_INTERRUPTIBLE);
|
||||||
|
|
||||||
ihk_mc_spinlock_unlock_noirq(&proc->ftn->lock);
|
ihk_mc_spinlock_unlock_noirq(&proc->ftn->lock);
|
||||||
|
if(hassigpending(proc)){
|
||||||
|
waitq_finish_wait(&proc->ftn->waitpid_q, &waitpid_wqe);
|
||||||
|
return -EINTR;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
schedule();
|
schedule();
|
||||||
dkprintf("wait4(): woken up\n");
|
dkprintf("wait4(): woken up\n");
|
||||||
@ -532,6 +550,66 @@ SYSCALL_DECLARE(wait4)
|
|||||||
goto exit;
|
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);
|
static int ptrace_terminate_tracer(struct process *proc, struct fork_tree_node *tracer);
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|||||||
Reference in New Issue
Block a user