diff options
Diffstat (limited to 'kernel/exit.c')
| -rw-r--r-- | kernel/exit.c | 40 |
1 files changed, 15 insertions, 25 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index 019a2843bf95..ceffc67b564a 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
| @@ -58,11 +58,11 @@ | |||
| 58 | 58 | ||
| 59 | static void exit_mm(struct task_struct * tsk); | 59 | static void exit_mm(struct task_struct * tsk); |
| 60 | 60 | ||
| 61 | static void __unhash_process(struct task_struct *p) | 61 | static void __unhash_process(struct task_struct *p, bool group_dead) |
| 62 | { | 62 | { |
| 63 | nr_threads--; | 63 | nr_threads--; |
| 64 | detach_pid(p, PIDTYPE_PID); | 64 | detach_pid(p, PIDTYPE_PID); |
| 65 | if (thread_group_leader(p)) { | 65 | if (group_dead) { |
| 66 | detach_pid(p, PIDTYPE_PGID); | 66 | detach_pid(p, PIDTYPE_PGID); |
| 67 | detach_pid(p, PIDTYPE_SID); | 67 | detach_pid(p, PIDTYPE_SID); |
| 68 | 68 | ||
| @@ -79,10 +79,9 @@ static void __unhash_process(struct task_struct *p) | |||
| 79 | static void __exit_signal(struct task_struct *tsk) | 79 | static void __exit_signal(struct task_struct *tsk) |
| 80 | { | 80 | { |
| 81 | struct signal_struct *sig = tsk->signal; | 81 | struct signal_struct *sig = tsk->signal; |
| 82 | bool group_dead = thread_group_leader(tsk); | ||
| 82 | struct sighand_struct *sighand; | 83 | struct sighand_struct *sighand; |
| 83 | 84 | struct tty_struct *uninitialized_var(tty); | |
| 84 | BUG_ON(!sig); | ||
| 85 | BUG_ON(!atomic_read(&sig->count)); | ||
| 86 | 85 | ||
| 87 | sighand = rcu_dereference_check(tsk->sighand, | 86 | sighand = rcu_dereference_check(tsk->sighand, |
| 88 | rcu_read_lock_held() || | 87 | rcu_read_lock_held() || |
| @@ -90,14 +89,16 @@ static void __exit_signal(struct task_struct *tsk) | |||
| 90 | spin_lock(&sighand->siglock); | 89 | spin_lock(&sighand->siglock); |
| 91 | 90 | ||
| 92 | posix_cpu_timers_exit(tsk); | 91 | posix_cpu_timers_exit(tsk); |
| 93 | if (atomic_dec_and_test(&sig->count)) | 92 | if (group_dead) { |
| 94 | posix_cpu_timers_exit_group(tsk); | 93 | posix_cpu_timers_exit_group(tsk); |
| 95 | else { | 94 | tty = sig->tty; |
| 95 | sig->tty = NULL; | ||
| 96 | } else { | ||
| 96 | /* | 97 | /* |
| 97 | * If there is any task waiting for the group exit | 98 | * If there is any task waiting for the group exit |
| 98 | * then notify it: | 99 | * then notify it: |
| 99 | */ | 100 | */ |
| 100 | if (sig->group_exit_task && atomic_read(&sig->count) == sig->notify_count) | 101 | if (sig->notify_count > 0 && !--sig->notify_count) |
| 101 | wake_up_process(sig->group_exit_task); | 102 | wake_up_process(sig->group_exit_task); |
| 102 | 103 | ||
| 103 | if (tsk == sig->curr_target) | 104 | if (tsk == sig->curr_target) |
| @@ -123,32 +124,24 @@ static void __exit_signal(struct task_struct *tsk) | |||
| 123 | sig->oublock += task_io_get_oublock(tsk); | 124 | sig->oublock += task_io_get_oublock(tsk); |
| 124 | task_io_accounting_add(&sig->ioac, &tsk->ioac); | 125 | task_io_accounting_add(&sig->ioac, &tsk->ioac); |
| 125 | sig->sum_sched_runtime += tsk->se.sum_exec_runtime; | 126 | sig->sum_sched_runtime += tsk->se.sum_exec_runtime; |
| 126 | sig = NULL; /* Marker for below. */ | ||
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | __unhash_process(tsk); | 129 | sig->nr_threads--; |
| 130 | __unhash_process(tsk, group_dead); | ||
| 130 | 131 | ||
| 131 | /* | 132 | /* |
| 132 | * Do this under ->siglock, we can race with another thread | 133 | * Do this under ->siglock, we can race with another thread |
| 133 | * doing sigqueue_free() if we have SIGQUEUE_PREALLOC signals. | 134 | * doing sigqueue_free() if we have SIGQUEUE_PREALLOC signals. |
| 134 | */ | 135 | */ |
| 135 | flush_sigqueue(&tsk->pending); | 136 | flush_sigqueue(&tsk->pending); |
| 136 | |||
| 137 | tsk->signal = NULL; | ||
| 138 | tsk->sighand = NULL; | 137 | tsk->sighand = NULL; |
| 139 | spin_unlock(&sighand->siglock); | 138 | spin_unlock(&sighand->siglock); |
| 140 | 139 | ||
| 141 | __cleanup_sighand(sighand); | 140 | __cleanup_sighand(sighand); |
| 142 | clear_tsk_thread_flag(tsk,TIF_SIGPENDING); | 141 | clear_tsk_thread_flag(tsk,TIF_SIGPENDING); |
| 143 | if (sig) { | 142 | if (group_dead) { |
| 144 | flush_sigqueue(&sig->shared_pending); | 143 | flush_sigqueue(&sig->shared_pending); |
| 145 | taskstats_tgid_free(sig); | 144 | tty_kref_put(tty); |
| 146 | /* | ||
| 147 | * Make sure ->signal can't go away under rq->lock, | ||
| 148 | * see account_group_exec_runtime(). | ||
| 149 | */ | ||
| 150 | task_rq_unlock_wait(tsk); | ||
| 151 | __cleanup_signal(sig); | ||
| 152 | } | 145 | } |
| 153 | } | 146 | } |
| 154 | 147 | ||
| @@ -856,12 +849,9 @@ static void exit_notify(struct task_struct *tsk, int group_dead) | |||
| 856 | 849 | ||
| 857 | tsk->exit_state = signal == DEATH_REAP ? EXIT_DEAD : EXIT_ZOMBIE; | 850 | tsk->exit_state = signal == DEATH_REAP ? EXIT_DEAD : EXIT_ZOMBIE; |
| 858 | 851 | ||
| 859 | /* mt-exec, de_thread() is waiting for us */ | 852 | /* mt-exec, de_thread() is waiting for group leader */ |
| 860 | if (thread_group_leader(tsk) && | 853 | if (unlikely(tsk->signal->notify_count < 0)) |
| 861 | tsk->signal->group_exit_task && | ||
| 862 | tsk->signal->notify_count < 0) | ||
| 863 | wake_up_process(tsk->signal->group_exit_task); | 854 | wake_up_process(tsk->signal->group_exit_task); |
| 864 | |||
| 865 | write_unlock_irq(&tasklist_lock); | 855 | write_unlock_irq(&tasklist_lock); |
| 866 | 856 | ||
| 867 | tracehook_report_death(tsk, signal, cookie, group_dead); | 857 | tracehook_report_death(tsk, signal, cookie, group_dead); |
