Commit 3154d91d authored by David Howells's avatar David Howells Committed by Kai Germaschewski

[PATCH] wait4() WIFSTOPPED starvation fix #1/2

This patch (#1) just converts the task_struct to use struct list_head rather
than direct pointers for maintaining the children list.
parent 5d043fec
......@@ -630,8 +630,8 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
info.si_signo = signr;
info.si_errno = 0;
info.si_code = SI_USER;
info.si_pid = current->p_pptr->pid;
info.si_uid = current->p_pptr->uid;
info.si_pid = current->parent->pid;
info.si_uid = current->parent->uid;
}
/* If the (new) signal is now blocked, requeue it. */
......@@ -670,7 +670,7 @@ int do_signal(struct pt_regs *regs, sigset_t *oldset)
case SIGSTOP: {
struct signal_struct *sig;
current->exit_code = signr;
sig = current->p_pptr->sig;
sig = current->parent->sig;
preempt_disable();
current->state = TASK_STOPPED;
if (sig && !(sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP))
......
......@@ -1094,7 +1094,7 @@ static int elf_core_dump(long signr, struct pt_regs * regs, struct file * file)
prstatus.pr_sigpend = current->pending.signal.sig[0];
prstatus.pr_sighold = current->blocked.sig[0];
psinfo.pr_pid = prstatus.pr_pid = current->pid;
psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid;
psinfo.pr_ppid = prstatus.pr_ppid = current->parent->pid;
psinfo.pr_pgrp = prstatus.pr_pgrp = current->pgrp;
psinfo.pr_sid = prstatus.pr_sid = current->session;
prstatus.pr_utime.tv_sec = CT_TO_SECS(current->times.tms_utime);
......
......@@ -159,7 +159,7 @@ static inline char * task_state(struct task_struct *p, char *buffer)
"Uid:\t%d\t%d\t%d\t%d\n"
"Gid:\t%d\t%d\t%d\t%d\n",
get_task_state(p), p->tgid,
p->pid, p->pid ? p->p_opptr->pid : 0, 0,
p->pid, p->pid ? p->real_parent->pid : 0, 0,
p->uid, p->euid, p->suid, p->fsuid,
p->gid, p->egid, p->sgid, p->fsgid);
read_unlock(&tasklist_lock);
......@@ -340,7 +340,7 @@ int proc_pid_stat(struct task_struct *task, char * buffer)
nice = task_nice(task);
read_lock(&tasklist_lock);
ppid = task->pid ? task->p_opptr->pid : 0;
ppid = task->pid ? task->real_parent->pid : 0;
read_unlock(&tasklist_lock);
res = sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
%lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
......
......@@ -336,7 +336,7 @@ static struct file_operations proc_info_file_operations = {
};
#define MAY_PTRACE(p) \
(p==current||(p->p_pptr==current&&(p->ptrace & PT_PTRACED)&&p->state==TASK_STOPPED))
(p==current||(p->parent==current&&(p->ptrace & PT_PTRACED)&&p->state==TASK_STOPPED))
static int mem_open(struct inode* inode, struct file* file)
......
......@@ -55,8 +55,10 @@
time_slice: HZ, \
next_task: &tsk, \
prev_task: &tsk, \
p_opptr: &tsk, \
p_pptr: &tsk, \
real_parent: &tsk, \
parent: &tsk, \
children: LIST_HEAD_INIT(tsk.children), \
sibling: LIST_HEAD_INIT(tsk.sibling), \
thread_group: LIST_HEAD_INIT(tsk.thread_group), \
wait_chldexit: __WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\
real_timer: { \
......
......@@ -274,9 +274,12 @@ struct task_struct {
/*
* pointers to (original) parent process, youngest child, younger sibling,
* older sibling, respectively. (p->father can be replaced with
* p->p_pptr->pid)
* p->parent->pid)
*/
struct task_struct *p_opptr, *p_pptr, *p_cptr, *p_ysptr, *p_osptr;
struct task_struct *real_parent; /* real parent process (when being debugged) */
struct task_struct *parent; /* parent process */
struct list_head children; /* list of my children */
struct list_head sibling; /* linkage in my parent's children list */
struct list_head thread_group;
/* PID hash table linkage. */
......@@ -715,28 +718,44 @@ do { \
__ret; \
})
#define REMOVE_LINKS(p) do { \
(p)->next_task->prev_task = (p)->prev_task; \
(p)->prev_task->next_task = (p)->next_task; \
if ((p)->p_osptr) \
(p)->p_osptr->p_ysptr = (p)->p_ysptr; \
if ((p)->p_ysptr) \
(p)->p_ysptr->p_osptr = (p)->p_osptr; \
else \
(p)->p_pptr->p_cptr = (p)->p_osptr; \
#define REMOVE_LINKS(p) do { \
(p)->next_task->prev_task = (p)->prev_task; \
(p)->prev_task->next_task = (p)->next_task; \
list_del_init(&(p)->sibling); \
} while (0)
#define SET_LINKS(p) do { \
(p)->next_task = &init_task; \
(p)->prev_task = init_task.prev_task; \
init_task.prev_task->next_task = (p); \
init_task.prev_task = (p); \
(p)->p_ysptr = NULL; \
if (((p)->p_osptr = (p)->p_pptr->p_cptr) != NULL) \
(p)->p_osptr->p_ysptr = p; \
(p)->p_pptr->p_cptr = p; \
#define SET_LINKS(p) do { \
(p)->next_task = &init_task; \
(p)->prev_task = init_task.prev_task; \
init_task.prev_task->next_task = (p); \
init_task.prev_task = (p); \
list_add_tail(&(p)->sibling,&(p)->parent->children); \
} while (0)
static inline struct task_struct *eldest_child(struct task_struct *p)
{
if (list_empty(&p->children)) return NULL;
return list_entry(p->children.next,struct task_struct,sibling);
}
static inline struct task_struct *youngest_child(struct task_struct *p)
{
if (list_empty(&p->children)) return NULL;
return list_entry(p->children.prev,struct task_struct,sibling);
}
static inline struct task_struct *older_sibling(struct task_struct *p)
{
if (p->sibling.prev==&p->parent->children) return NULL;
return list_entry(p->sibling.prev,struct task_struct,sibling);
}
static inline struct task_struct *younger_sibling(struct task_struct *p)
{
if (p->sibling.next==&p->parent->children) return NULL;
return list_entry(p->sibling.next,struct task_struct,sibling);
}
#define for_each_task(p) \
for (p = &init_task ; (p = p->next_task) != &init_task ; )
......
......@@ -91,10 +91,10 @@ static int will_become_orphaned_pgrp(int pgrp, struct task_struct * ignored_task
for_each_task(p) {
if ((p == ignored_task) || (p->pgrp != pgrp) ||
(p->state == TASK_ZOMBIE) ||
(p->p_pptr->pid == 1))
(p->parent->pid == 1))
continue;
if ((p->p_pptr->pgrp != pgrp) &&
(p->p_pptr->session == p->session)) {
if ((p->parent->pgrp != pgrp) &&
(p->parent->session == p->session)) {
read_unlock(&tasklist_lock);
return 0;
}
......@@ -144,8 +144,8 @@ void reparent_to_init(void)
/* Reparent to init */
REMOVE_LINKS(current);
current->p_pptr = child_reaper;
current->p_opptr = child_reaper;
current->parent = child_reaper;
current->real_parent = child_reaper;
SET_LINKS(current);
/* Set the exit signal to SIGCHLD so we signal init on exit */
......@@ -217,16 +217,16 @@ static inline void forget_original_parent(struct task_struct * father)
reaper = child_reaper;
for_each_task(p) {
if (p->p_opptr == father) {
if (p->real_parent == father) {
/* We dont want people slaying init */
p->exit_signal = SIGCHLD;
p->self_exec_id++;
/* Make sure we're not reparenting to ourselves */
if (p == reaper)
p->p_opptr = child_reaper;
p->real_parent = child_reaper;
else
p->p_opptr = reaper;
p->real_parent = reaper;
if (p->pdeath_signal) send_sig(p->pdeath_signal, p, 0);
}
......@@ -400,7 +400,7 @@ static void exit_notify(void)
* is about to become orphaned.
*/
t = current->p_pptr;
t = current->parent;
if ((t->pgrp != current->pgrp) &&
(t->session == current->session) &&
......@@ -445,17 +445,12 @@ static void exit_notify(void)
write_lock_irq(&tasklist_lock);
current->state = TASK_ZOMBIE;
do_notify_parent(current, current->exit_signal);
while (current->p_cptr != NULL) {
p = current->p_cptr;
current->p_cptr = p->p_osptr;
p->p_ysptr = NULL;
while ((p = eldest_child(current))) {
list_del_init(&p->sibling);
p->ptrace = 0;
p->p_pptr = p->p_opptr;
p->p_osptr = p->p_pptr->p_cptr;
if (p->p_osptr)
p->p_osptr->p_ysptr = p;
p->p_pptr->p_cptr = p;
p->parent = p->real_parent;
list_add_tail(&p->sibling,&p->parent->children);
if (p->state == TASK_ZOMBIE)
do_notify_parent(p, p->exit_signal);
/*
......@@ -568,7 +563,9 @@ asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struc
tsk = current;
do {
struct task_struct *p;
for (p = tsk->p_cptr ; p ; p = p->p_osptr) {
struct list_head *_p;
list_for_each(_p,&tsk->children) {
p = list_entry(_p,struct task_struct,sibling);
if (pid>0) {
if (p->pid != pid)
continue;
......@@ -613,10 +610,10 @@ asmlinkage long sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struc
if (retval)
goto end_wait4;
retval = p->pid;
if (p->p_opptr != p->p_pptr) {
if (p->real_parent != p->parent) {
write_lock_irq(&tasklist_lock);
REMOVE_LINKS(p);
p->p_pptr = p->p_opptr;
p->parent = p->real_parent;
SET_LINKS(p);
do_notify_parent(p, SIGCHLD);
write_unlock_irq(&tasklist_lock);
......
......@@ -666,7 +666,8 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start,
INIT_LIST_HEAD(&p->run_list);
p->p_cptr = NULL;
INIT_LIST_HEAD(&p->children);
INIT_LIST_HEAD(&p->sibling);
init_waitqueue_head(&p->wait_chldexit);
p->vfork_done = NULL;
if (clone_flags & CLONE_VFORK) {
......@@ -766,12 +767,12 @@ int do_fork(unsigned long clone_flags, unsigned long stack_start,
write_lock_irq(&tasklist_lock);
/* CLONE_PARENT re-uses the old parent */
p->p_opptr = current->p_opptr;
p->p_pptr = current->p_pptr;
p->real_parent = current->real_parent;
p->parent = current->parent;
if (!(clone_flags & CLONE_PARENT)) {
p->p_opptr = current;
p->real_parent = current;
if (!(p->ptrace & PT_PTRACED))
p->p_pptr = current;
p->parent = current;
}
if (clone_flags & CLONE_THREAD) {
......
......@@ -24,7 +24,7 @@ int ptrace_check_attach(struct task_struct *child, int kill)
if (!(child->ptrace & PT_PTRACED))
return -ESRCH;
if (child->p_pptr != current)
if (child->parent != current)
return -ESRCH;
if (!kill) {
......@@ -70,9 +70,9 @@ int ptrace_attach(struct task_struct *task)
task_unlock(task);
write_lock_irq(&tasklist_lock);
if (task->p_pptr != current) {
if (task->parent != current) {
REMOVE_LINKS(task);
task->p_pptr = current;
task->parent = current;
SET_LINKS(task);
}
write_unlock_irq(&tasklist_lock);
......@@ -98,7 +98,7 @@ int ptrace_detach(struct task_struct *child, unsigned int data)
child->exit_code = data;
write_lock_irq(&tasklist_lock);
REMOVE_LINKS(child);
child->p_pptr = child->p_opptr;
child->parent = child->real_parent;
SET_LINKS(child);
write_unlock_irq(&tasklist_lock);
......
......@@ -1320,6 +1320,7 @@ asmlinkage long sys_sched_rr_get_interval(pid_t pid, struct timespec *interval)
static void show_task(task_t * p)
{
unsigned long free = 0;
task_t *relative;
int state;
static const char * stat_nam[] = { "R", "S", "D", "Z", "T", "W" };
......@@ -1346,17 +1347,17 @@ static void show_task(task_t * p)
n++;
free = (unsigned long) n - (unsigned long)(p+1);
}
printk("%5lu %5d %6d ", free, p->pid, p->p_pptr->pid);
if (p->p_cptr)
printk("%5d ", p->p_cptr->pid);
printk("%5lu %5d %6d ", free, p->pid, p->parent->pid);
if ((relative = eldest_child(p)))
printk("%5d ", relative->pid);
else
printk(" ");
if (p->p_ysptr)
printk("%7d", p->p_ysptr->pid);
if ((relative = younger_sibling(p)))
printk("%7d", relative->pid);
else
printk(" ");
if (p->p_osptr)
printk(" %5d", p->p_osptr->pid);
if ((relative = older_sibling(p)))
printk(" %5d", relative->pid);
else
printk(" ");
if (!p->mm)
......
......@@ -804,8 +804,8 @@ void do_notify_parent(struct task_struct *tsk, int sig)
info.si_code = why;
info.si_status = status;
send_sig_info(sig, &info, tsk->p_pptr);
wake_up_parent(tsk->p_pptr);
send_sig_info(sig, &info, tsk->parent);
wake_up_parent(tsk->parent);
}
......
......@@ -839,7 +839,7 @@ asmlinkage long sys_setpgid(pid_t pid, pid_t pgid)
if (!p)
goto out;
if (p->p_pptr == current || p->p_opptr == current) {
if (p->parent == current || p->real_parent == current) {
err = -EPERM;
if (p->session != current->session)
goto out;
......
......@@ -742,14 +742,14 @@ asmlinkage long sys_getppid(void)
struct task_struct * me = current;
struct task_struct * parent;
parent = me->p_opptr;
parent = me->real_parent;
for (;;) {
pid = parent->pid;
#if CONFIG_SMP
{
struct task_struct *old = parent;
mb();
parent = me->p_opptr;
parent = me->real_parent;
if (old != parent)
continue;
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment