Commit 817fdd72 authored by Ingo Molnar's avatar Ingo Molnar Committed by Linus Torvalds

[PATCH] pidhash cleanups, tgid-2.5.38-F3

This does the following things:

 - removes the ->thread_group list and uses a new PIDTYPE_TGID pid class
   to handle thread groups. This cleans up lots of code in signal.c and
   elsewhere.

 - fixes sys_execve() if a non-leader thread calls it. (2.5.38 crashed in
   this case.)

 - renames list_for_each_noprefetch to __list_for_each.

 - cleans up delayed-leader parent notification.

 - introduces link_pid() to optimize PIDTYPE_TGID installation in the
   thread-group case.

I've tested the patch with a number of threaded and non-threaded
workloads, and it works just fine. Compiles & boots on UP and SMP x86.

The session/pgrp bugs reported to lkml are probably still open, they are
the next on my todo - now that we have a clean pidhash architecture they
should be easier to fix.
parent 76417366
...@@ -537,7 +537,7 @@ static inline int de_thread(struct signal_struct *oldsig) ...@@ -537,7 +537,7 @@ static inline int de_thread(struct signal_struct *oldsig)
if (!newsig) if (!newsig)
return -ENOMEM; return -ENOMEM;
if (list_empty(&current->thread_group)) if (thread_group_empty(current))
goto out; goto out;
/* /*
* Kill all other threads in the thread group: * Kill all other threads in the thread group:
...@@ -607,21 +607,17 @@ static inline int de_thread(struct signal_struct *oldsig) ...@@ -607,21 +607,17 @@ static inline int de_thread(struct signal_struct *oldsig)
ptrace = leader->ptrace; ptrace = leader->ptrace;
parent = leader->parent; parent = leader->parent;
ptrace_unlink(leader);
ptrace_unlink(current); ptrace_unlink(current);
ptrace_unlink(leader);
remove_parent(current); remove_parent(current);
remove_parent(leader); remove_parent(leader);
/*
* Split up the last two remaining members of the
* thread group:
*/
list_del_init(&leader->thread_group);
leader->pid = leader->tgid = current->pid; switch_exec_pids(leader, current);
current->pid = current->tgid;
current->parent = current->real_parent = leader->real_parent; current->parent = current->real_parent = leader->real_parent;
leader->parent = leader->real_parent = child_reaper; leader->parent = leader->real_parent = child_reaper;
current->exit_signal = SIGCHLD; current->group_leader = current;
leader->group_leader = leader;
add_parent(current, current->parent); add_parent(current, current->parent);
add_parent(leader, leader->parent); add_parent(leader, leader->parent);
...@@ -631,15 +627,17 @@ static inline int de_thread(struct signal_struct *oldsig) ...@@ -631,15 +627,17 @@ static inline int de_thread(struct signal_struct *oldsig)
} }
list_add_tail(&current->tasks, &init_task.tasks); list_add_tail(&current->tasks, &init_task.tasks);
current->exit_signal = SIGCHLD;
state = leader->state; state = leader->state;
write_unlock_irq(&tasklist_lock); write_unlock_irq(&tasklist_lock);
put_proc_dentry(proc_dentry1);
put_proc_dentry(proc_dentry2);
if (state != TASK_ZOMBIE) if (state != TASK_ZOMBIE)
BUG(); BUG();
release_task(leader); release_task(leader);
put_proc_dentry(proc_dentry1);
put_proc_dentry(proc_dentry2);
} }
out: out:
...@@ -661,7 +659,7 @@ static inline int de_thread(struct signal_struct *oldsig) ...@@ -661,7 +659,7 @@ static inline int de_thread(struct signal_struct *oldsig)
if (atomic_dec_and_test(&oldsig->count)) if (atomic_dec_and_test(&oldsig->count))
kmem_cache_free(sigact_cachep, oldsig); kmem_cache_free(sigact_cachep, oldsig);
if (!list_empty(&current->thread_group)) if (!thread_group_empty(current))
BUG(); BUG();
if (current->tgid != current->pid) if (current->tgid != current->pid)
BUG(); BUG();
......
...@@ -76,7 +76,6 @@ ...@@ -76,7 +76,6 @@
.children = LIST_HEAD_INIT(tsk.children), \ .children = LIST_HEAD_INIT(tsk.children), \
.sibling = LIST_HEAD_INIT(tsk.sibling), \ .sibling = LIST_HEAD_INIT(tsk.sibling), \
.group_leader = &tsk, \ .group_leader = &tsk, \
.thread_group = LIST_HEAD_INIT(tsk.thread_group), \
.wait_chldexit = __WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\ .wait_chldexit = __WAIT_QUEUE_HEAD_INITIALIZER(tsk.wait_chldexit),\
.real_timer = { \ .real_timer = { \
.function = it_real_fn \ .function = it_real_fn \
......
...@@ -196,7 +196,17 @@ static inline void list_splice_init(struct list_head *list, ...@@ -196,7 +196,17 @@ static inline void list_splice_init(struct list_head *list,
for (pos = (head)->next, prefetch(pos->next); pos != (head); \ for (pos = (head)->next, prefetch(pos->next); pos != (head); \
pos = pos->next, prefetch(pos->next)) pos = pos->next, prefetch(pos->next))
#define list_for_each_noprefetch(pos, head) \ /**
* __list_for_each - iterate over a list
* @pos: the &struct list_head to use as a loop counter.
* @head: the head for your list.
*
* This variant differs from list_for_each() in that it's the
* simplest possible list iteration code, no prefetching is done.
* Use this for code that knows the list to be very short (empty
* or 1 entry) most of the time.
*/
#define __list_for_each(pos, head) \
for (pos = (head)->next; pos != (head); pos = pos->next) for (pos = (head)->next; pos != (head); pos = pos->next)
/** /**
......
...@@ -4,6 +4,7 @@ ...@@ -4,6 +4,7 @@
enum pid_type enum pid_type
{ {
PIDTYPE_PID, PIDTYPE_PID,
PIDTYPE_TGID,
PIDTYPE_PGID, PIDTYPE_PGID,
PIDTYPE_SID, PIDTYPE_SID,
PIDTYPE_MAX PIDTYPE_MAX
...@@ -29,13 +30,12 @@ struct pid_link ...@@ -29,13 +30,12 @@ struct pid_link
list_entry(elem, struct task_struct, pids[type].pid_chain) list_entry(elem, struct task_struct, pids[type].pid_chain)
/* /*
* attach_pid() must be called with the tasklist_lock write-held. * attach_pid() and link_pid() must be called with the tasklist_lock
* * write-held.
* It might unlock the tasklist_lock for allocation, so this
* function must be called after installing all other links of
* a new task.
*/ */
extern int FASTCALL(attach_pid(struct task_struct *, enum pid_type, int)); extern int FASTCALL(attach_pid(struct task_struct *task, enum pid_type type, int nr));
extern void FASTCALL(link_pid(struct task_struct *task, struct pid_link *link, struct pid *pid));
/* /*
* detach_pid() must be called with the tasklist_lock write-held. * detach_pid() must be called with the tasklist_lock write-held.
...@@ -50,6 +50,7 @@ extern struct pid *FASTCALL(find_pid(enum pid_type, int)); ...@@ -50,6 +50,7 @@ extern struct pid *FASTCALL(find_pid(enum pid_type, int));
extern int alloc_pidmap(void); extern int alloc_pidmap(void);
extern void FASTCALL(free_pidmap(int)); extern void FASTCALL(free_pidmap(int));
extern void switch_exec_pids(struct task_struct *leader, struct task_struct *thread);
#define for_each_task_pid(who, type, task, elem, pid) \ #define for_each_task_pid(who, type, task, elem, pid) \
if ((pid = find_pid(type, who))) \ if ((pid = find_pid(type, who))) \
......
...@@ -328,7 +328,6 @@ struct task_struct { ...@@ -328,7 +328,6 @@ struct task_struct {
struct list_head children; /* list of my children */ struct list_head children; /* list of my children */
struct list_head sibling; /* linkage in my parent's children list */ struct list_head sibling; /* linkage in my parent's children list */
struct task_struct *group_leader; struct task_struct *group_leader;
struct list_head thread_group;
/* PID/PID hash table linkage. */ /* PID/PID hash table linkage. */
struct pid_link pids[PIDTYPE_MAX]; struct pid_link pids[PIDTYPE_MAX];
...@@ -797,34 +796,19 @@ static inline struct task_struct *younger_sibling(struct task_struct *p) ...@@ -797,34 +796,19 @@ static inline struct task_struct *younger_sibling(struct task_struct *p)
#define while_each_thread(g, t) \ #define while_each_thread(g, t) \
while ((t = next_thread(t)) != g) while ((t = next_thread(t)) != g)
static inline task_t *next_thread(task_t *p) extern task_t * FASTCALL(next_thread(task_t *p));
{
if (!p->sig) #define thread_group_leader(p) (p->pid == p->tgid)
BUG();
#if CONFIG_SMP
if (!spin_is_locked(&p->sig->siglock) &&
!rwlock_is_locked(&tasklist_lock))
BUG();
#endif
return list_entry((p)->thread_group.next, task_t, thread_group);
}
static inline task_t *prev_thread(task_t *p) static inline int thread_group_empty(task_t *p)
{ {
if (!p->sig) struct pid *pid = p->pids[PIDTYPE_TGID].pidptr;
BUG();
#if CONFIG_SMP
if (!spin_is_locked(&p->sig->siglock) &&
!rwlock_is_locked(&tasklist_lock))
BUG();
#endif
return list_entry((p)->thread_group.prev, task_t, thread_group);
}
#define thread_group_leader(p) (p->pid == p->tgid) return pid->task_list.next->next == &pid->task_list;
}
#define delay_group_leader(p) \ #define delay_group_leader(p) \
(p->tgid == p->pid && !list_empty(&p->thread_group)) (thread_group_leader(p) && !thread_group_empty(p))
extern void unhash_process(struct task_struct *p); extern void unhash_process(struct task_struct *p);
......
...@@ -34,13 +34,13 @@ static struct dentry * __unhash_process(struct task_struct *p) ...@@ -34,13 +34,13 @@ static struct dentry * __unhash_process(struct task_struct *p)
struct dentry *proc_dentry; struct dentry *proc_dentry;
nr_threads--; nr_threads--;
detach_pid(p, PIDTYPE_PID); detach_pid(p, PIDTYPE_PID);
detach_pid(p, PIDTYPE_TGID);
if (thread_group_leader(p)) { if (thread_group_leader(p)) {
detach_pid(p, PIDTYPE_PGID); detach_pid(p, PIDTYPE_PGID);
detach_pid(p, PIDTYPE_SID); detach_pid(p, PIDTYPE_SID);
} }
REMOVE_LINKS(p); REMOVE_LINKS(p);
p->pid = 0;
proc_dentry = p->proc_dentry; proc_dentry = p->proc_dentry;
if (unlikely(proc_dentry != NULL)) { if (unlikely(proc_dentry != NULL)) {
spin_lock(&dcache_lock); spin_lock(&dcache_lock);
...@@ -74,6 +74,15 @@ void release_task(struct task_struct * p) ...@@ -74,6 +74,15 @@ void release_task(struct task_struct * p)
write_lock_irq(&tasklist_lock); write_lock_irq(&tasklist_lock);
__exit_sighand(p); __exit_sighand(p);
proc_dentry = __unhash_process(p); proc_dentry = __unhash_process(p);
/*
* If we are the last non-leader member of the thread
* group, and the leader is zombie, then notify the
* group leader's parent process.
*/
if (p->group_leader != p && thread_group_empty(p))
do_notify_parent(p->group_leader, p->group_leader->exit_signal);
p->parent->cutime += p->utime + p->cutime; p->parent->cutime += p->utime + p->cutime;
p->parent->cstime += p->stime + p->cstime; p->parent->cstime += p->stime + p->cstime;
p->parent->cmin_flt += p->min_flt + p->cmin_flt; p->parent->cmin_flt += p->min_flt + p->cmin_flt;
...@@ -670,6 +679,25 @@ asmlinkage long sys_exit(int error_code) ...@@ -670,6 +679,25 @@ asmlinkage long sys_exit(int error_code)
do_exit((error_code&0xff)<<8); do_exit((error_code&0xff)<<8);
} }
task_t *next_thread(task_t *p)
{
struct pid_link *link = p->pids + PIDTYPE_TGID;
struct list_head *tmp, *head = &link->pidptr->task_list;
#if CONFIG_SMP
if (!p->sig)
BUG();
if (!spin_is_locked(&p->sig->siglock) &&
!rwlock_is_locked(&tasklist_lock))
BUG();
#endif
tmp = link->pid_chain.next;
if (tmp == head)
tmp = head->next;
return pid_task(tmp, PIDTYPE_TGID);
}
/* /*
* this kills every thread in the thread group. Note that any externally * this kills every thread in the thread group. Note that any externally
* wait4()-ing process will get the correct exit code - even if this * wait4()-ing process will get the correct exit code - even if this
...@@ -679,7 +707,7 @@ asmlinkage long sys_exit_group(int error_code) ...@@ -679,7 +707,7 @@ asmlinkage long sys_exit_group(int error_code)
{ {
unsigned int exit_code = (error_code & 0xff) << 8; unsigned int exit_code = (error_code & 0xff) << 8;
if (!list_empty(&current->thread_group)) { if (!thread_group_empty(current)) {
struct signal_struct *sig = current->sig; struct signal_struct *sig = current->sig;
spin_lock_irq(&sig->siglock); spin_lock_irq(&sig->siglock);
......
...@@ -802,7 +802,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, ...@@ -802,7 +802,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
*/ */
p->tgid = p->pid; p->tgid = p->pid;
p->group_leader = p; p->group_leader = p;
INIT_LIST_HEAD(&p->thread_group);
INIT_LIST_HEAD(&p->ptrace_children); INIT_LIST_HEAD(&p->ptrace_children);
INIT_LIST_HEAD(&p->ptrace_list); INIT_LIST_HEAD(&p->ptrace_list);
...@@ -830,7 +829,6 @@ static struct task_struct *copy_process(unsigned long clone_flags, ...@@ -830,7 +829,6 @@ static struct task_struct *copy_process(unsigned long clone_flags,
} }
p->tgid = current->tgid; p->tgid = current->tgid;
p->group_leader = current->group_leader; p->group_leader = current->group_leader;
list_add(&p->thread_group, &current->thread_group);
spin_unlock(&current->sig->siglock); spin_unlock(&current->sig->siglock);
} }
...@@ -840,9 +838,11 @@ static struct task_struct *copy_process(unsigned long clone_flags, ...@@ -840,9 +838,11 @@ static struct task_struct *copy_process(unsigned long clone_flags,
attach_pid(p, PIDTYPE_PID, p->pid); attach_pid(p, PIDTYPE_PID, p->pid);
if (thread_group_leader(p)) { if (thread_group_leader(p)) {
attach_pid(p, PIDTYPE_TGID, p->tgid);
attach_pid(p, PIDTYPE_PGID, p->pgrp); attach_pid(p, PIDTYPE_PGID, p->pgrp);
attach_pid(p, PIDTYPE_SID, p->session); attach_pid(p, PIDTYPE_SID, p->session);
} } else
link_pid(p, p->pids + PIDTYPE_TGID, &p->group_leader->pids[PIDTYPE_TGID].pid);
nr_threads++; nr_threads++;
write_unlock_irq(&tasklist_lock); write_unlock_irq(&tasklist_lock);
......
...@@ -142,7 +142,7 @@ inline struct pid *find_pid(enum pid_type type, int nr) ...@@ -142,7 +142,7 @@ inline struct pid *find_pid(enum pid_type type, int nr)
struct list_head *elem, *bucket = &pid_hash[type][pid_hashfn(nr)]; struct list_head *elem, *bucket = &pid_hash[type][pid_hashfn(nr)];
struct pid *pid; struct pid *pid;
list_for_each_noprefetch(elem, bucket) { __list_for_each(elem, bucket) {
pid = list_entry(elem, struct pid, hash_chain); pid = list_entry(elem, struct pid, hash_chain);
if (pid->nr == nr) if (pid->nr == nr)
return pid; return pid;
...@@ -150,6 +150,13 @@ inline struct pid *find_pid(enum pid_type type, int nr) ...@@ -150,6 +150,13 @@ inline struct pid *find_pid(enum pid_type type, int nr)
return NULL; return NULL;
} }
void link_pid(task_t *task, struct pid_link *link, struct pid *pid)
{
atomic_inc(&pid->count);
list_add_tail(&link->pid_chain, &pid->task_list);
link->pidptr = pid;
}
int attach_pid(task_t *task, enum pid_type type, int nr) int attach_pid(task_t *task, enum pid_type type, int nr)
{ {
struct pid *pid = find_pid(type, nr); struct pid *pid = find_pid(type, nr);
...@@ -165,13 +172,13 @@ int attach_pid(task_t *task, enum pid_type type, int nr) ...@@ -165,13 +172,13 @@ int attach_pid(task_t *task, enum pid_type type, int nr)
get_task_struct(task); get_task_struct(task);
list_add(&pid->hash_chain, &pid_hash[type][pid_hashfn(nr)]); list_add(&pid->hash_chain, &pid_hash[type][pid_hashfn(nr)]);
} }
list_add(&task->pids[type].pid_chain, &pid->task_list); list_add_tail(&task->pids[type].pid_chain, &pid->task_list);
task->pids[type].pidptr = pid; task->pids[type].pidptr = pid;
return 0; return 0;
} }
void detach_pid(task_t *task, enum pid_type type) static inline int __detach_pid(task_t *task, enum pid_type type)
{ {
struct pid_link *link = task->pids + type; struct pid_link *link = task->pids + type;
struct pid *pid = link->pidptr; struct pid *pid = link->pidptr;
...@@ -179,19 +186,34 @@ void detach_pid(task_t *task, enum pid_type type) ...@@ -179,19 +186,34 @@ void detach_pid(task_t *task, enum pid_type type)
list_del(&link->pid_chain); list_del(&link->pid_chain);
if (!atomic_dec_and_test(&pid->count)) if (!atomic_dec_and_test(&pid->count))
return; return 0;
nr = pid->nr; nr = pid->nr;
list_del(&pid->hash_chain); list_del(&pid->hash_chain);
put_task_struct(pid->task); put_task_struct(pid->task);
return nr;
}
static void _detach_pid(task_t *task, enum pid_type type)
{
__detach_pid(task, type);
}
void detach_pid(task_t *task, enum pid_type type)
{
int nr = __detach_pid(task, type);
if (!nr)
return;
for (type = 0; type < PIDTYPE_MAX; ++type) for (type = 0; type < PIDTYPE_MAX; ++type)
if (find_pid(type, nr)) if (find_pid(type, nr))
return; return;
free_pidmap(nr); free_pidmap(nr);
} }
extern task_t *find_task_by_pid(int nr) task_t *find_task_by_pid(int nr)
{ {
struct pid *pid = find_pid(PIDTYPE_PID, nr); struct pid *pid = find_pid(PIDTYPE_PID, nr);
...@@ -200,6 +222,35 @@ extern task_t *find_task_by_pid(int nr) ...@@ -200,6 +222,35 @@ extern task_t *find_task_by_pid(int nr)
return pid_task(pid->task_list.next, PIDTYPE_PID); return pid_task(pid->task_list.next, PIDTYPE_PID);
} }
/*
* This function switches the PIDs if a non-leader thread calls
* sys_execve() - this must be done without releasing the PID.
* (which a detach_pid() would eventually do.)
*/
void switch_exec_pids(task_t *leader, task_t *thread)
{
_detach_pid(leader, PIDTYPE_PID);
_detach_pid(leader, PIDTYPE_TGID);
_detach_pid(leader, PIDTYPE_PGID);
_detach_pid(leader, PIDTYPE_SID);
_detach_pid(thread, PIDTYPE_PID);
_detach_pid(thread, PIDTYPE_TGID);
leader->pid = leader->tgid = thread->pid;
thread->pid = thread->tgid;
attach_pid(thread, PIDTYPE_PID, thread->pid);
attach_pid(thread, PIDTYPE_TGID, thread->tgid);
attach_pid(thread, PIDTYPE_PGID, thread->pgrp);
attach_pid(thread, PIDTYPE_SID, thread->session);
attach_pid(leader, PIDTYPE_PID, leader->pid);
attach_pid(leader, PIDTYPE_TGID, leader->tgid);
attach_pid(leader, PIDTYPE_PGID, leader->pgrp);
attach_pid(leader, PIDTYPE_SID, leader->session);
}
void __init pidhash_init(void) void __init pidhash_init(void)
{ {
int i, j; int i, j;
......
...@@ -254,7 +254,6 @@ static inline void __remove_thread_group(struct task_struct *tsk, struct signal_ ...@@ -254,7 +254,6 @@ static inline void __remove_thread_group(struct task_struct *tsk, struct signal_
{ {
if (tsk == sig->curr_target) if (tsk == sig->curr_target)
sig->curr_target = next_thread(tsk); sig->curr_target = next_thread(tsk);
list_del_init(&tsk->thread_group);
} }
void remove_thread_group(struct task_struct *tsk, struct signal_struct *sig) void remove_thread_group(struct task_struct *tsk, struct signal_struct *sig)
...@@ -281,15 +280,13 @@ void __exit_sighand(struct task_struct *tsk) ...@@ -281,15 +280,13 @@ void __exit_sighand(struct task_struct *tsk)
BUG(); BUG();
spin_lock(&sig->siglock); spin_lock(&sig->siglock);
spin_lock(&tsk->sigmask_lock); spin_lock(&tsk->sigmask_lock);
tsk->sig = NULL;
if (atomic_dec_and_test(&sig->count)) { if (atomic_dec_and_test(&sig->count)) {
__remove_thread_group(tsk, sig); __remove_thread_group(tsk, sig);
tsk->sig = NULL;
spin_unlock(&sig->siglock); spin_unlock(&sig->siglock);
flush_sigqueue(&sig->shared_pending); flush_sigqueue(&sig->shared_pending);
kmem_cache_free(sigact_cachep, sig); kmem_cache_free(sigact_cachep, sig);
} else { } else {
struct task_struct *leader = tsk->group_leader;
/* /*
* If there is any task waiting for the group exit * If there is any task waiting for the group exit
* then notify it: * then notify it:
...@@ -298,24 +295,9 @@ void __exit_sighand(struct task_struct *tsk) ...@@ -298,24 +295,9 @@ void __exit_sighand(struct task_struct *tsk)
wake_up_process(sig->group_exit_task); wake_up_process(sig->group_exit_task);
sig->group_exit_task = NULL; sig->group_exit_task = NULL;
} }
/* __remove_thread_group(tsk, sig);
* If we are the last non-leader member of the thread tsk->sig = NULL;
* group, and the leader is zombie, then notify the spin_unlock(&sig->siglock);
* group leader's parent process.
*
* (subtle: here we also rely on the fact that if we are the
* thread group leader then we are not zombied yet.)
*/
if (atomic_read(&sig->count) == 1 &&
leader->state == TASK_ZOMBIE) {
__remove_thread_group(tsk, sig);
spin_unlock(&sig->siglock);
do_notify_parent(leader, leader->exit_signal);
} else {
__remove_thread_group(tsk, sig);
spin_unlock(&sig->siglock);
}
} }
clear_tsk_thread_flag(tsk,TIF_SIGPENDING); clear_tsk_thread_flag(tsk,TIF_SIGPENDING);
flush_sigqueue(&tsk->pending); flush_sigqueue(&tsk->pending);
...@@ -853,7 +835,7 @@ int load_balance_thread_group(struct task_struct *p, int sig, ...@@ -853,7 +835,7 @@ int load_balance_thread_group(struct task_struct *p, int sig,
p->sig->curr_target = p; p->sig->curr_target = p;
else for (;;) { else for (;;) {
if (list_empty(&p->thread_group)) if (thread_group_empty(p))
BUG(); BUG();
if (!tmp || tmp->tgid != p->tgid) if (!tmp || tmp->tgid != p->tgid)
BUG(); BUG();
...@@ -882,17 +864,13 @@ int load_balance_thread_group(struct task_struct *p, int sig, ...@@ -882,17 +864,13 @@ int load_balance_thread_group(struct task_struct *p, int sig,
int __broadcast_thread_group(struct task_struct *p, int sig) int __broadcast_thread_group(struct task_struct *p, int sig)
{ {
struct task_struct *tmp; struct task_struct *tmp;
struct list_head *entry; struct list_head *l;
struct pid *pid;
int err = 0; int err = 0;
/* send a signal to the head of the list */ for_each_task_pid(p->tgid, PIDTYPE_TGID, tmp, l, pid)
err = __force_sig_info(sig, p);
/* send a signal to all members of the list */
list_for_each(entry, &p->thread_group) {
tmp = list_entry(entry, task_t, thread_group);
err = __force_sig_info(sig, tmp); err = __force_sig_info(sig, tmp);
}
return err; return err;
} }
...@@ -909,7 +887,7 @@ send_sig_info(int sig, struct siginfo *info, struct task_struct *p) ...@@ -909,7 +887,7 @@ send_sig_info(int sig, struct siginfo *info, struct task_struct *p)
spin_lock_irqsave(&p->sig->siglock, flags); spin_lock_irqsave(&p->sig->siglock, flags);
/* not a thread group - normal signal behavior */ /* not a thread group - normal signal behavior */
if (list_empty(&p->thread_group) || !sig) if (thread_group_empty(p) || !sig)
goto out_send; goto out_send;
if (sig_user_defined(p, sig)) { if (sig_user_defined(p, sig)) {
......
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