diff options
| author | Jeff Garzik <jeff@garzik.org> | 2006-03-29 19:58:22 -0500 |
|---|---|---|
| committer | Jeff Garzik <jeff@garzik.org> | 2006-03-29 19:58:22 -0500 |
| commit | 79072f38909e3d9883317238887460c39ddcc4cb (patch) | |
| tree | 28369f5a844535ff836565eefd62695b0e890fa3 /kernel/exit.c | |
| parent | 200d5a7684cc49ef4be40e832daf3f217e70dfbb (diff) | |
| parent | 55d8ca4f8094246da6e71889a4e04bfafaa78b10 (diff) | |
Merge branch 'upstream'
Diffstat (limited to 'kernel/exit.c')
| -rw-r--r-- | kernel/exit.c | 141 |
1 files changed, 92 insertions, 49 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index d1e8d500a7e1..bc0ec674d3f4 100644 --- a/kernel/exit.c +++ b/kernel/exit.c | |||
| @@ -29,8 +29,11 @@ | |||
| 29 | #include <linux/cpuset.h> | 29 | #include <linux/cpuset.h> |
| 30 | #include <linux/syscalls.h> | 30 | #include <linux/syscalls.h> |
| 31 | #include <linux/signal.h> | 31 | #include <linux/signal.h> |
| 32 | #include <linux/posix-timers.h> | ||
| 32 | #include <linux/cn_proc.h> | 33 | #include <linux/cn_proc.h> |
| 33 | #include <linux/mutex.h> | 34 | #include <linux/mutex.h> |
| 35 | #include <linux/futex.h> | ||
| 36 | #include <linux/compat.h> | ||
| 34 | 37 | ||
| 35 | #include <asm/uaccess.h> | 38 | #include <asm/uaccess.h> |
| 36 | #include <asm/unistd.h> | 39 | #include <asm/unistd.h> |
| @@ -48,15 +51,80 @@ static void __unhash_process(struct task_struct *p) | |||
| 48 | { | 51 | { |
| 49 | nr_threads--; | 52 | nr_threads--; |
| 50 | detach_pid(p, PIDTYPE_PID); | 53 | detach_pid(p, PIDTYPE_PID); |
| 51 | detach_pid(p, PIDTYPE_TGID); | ||
| 52 | if (thread_group_leader(p)) { | 54 | if (thread_group_leader(p)) { |
| 53 | detach_pid(p, PIDTYPE_PGID); | 55 | detach_pid(p, PIDTYPE_PGID); |
| 54 | detach_pid(p, PIDTYPE_SID); | 56 | detach_pid(p, PIDTYPE_SID); |
| 55 | if (p->pid) | 57 | |
| 56 | __get_cpu_var(process_counts)--; | 58 | list_del_init(&p->tasks); |
| 59 | __get_cpu_var(process_counts)--; | ||
| 57 | } | 60 | } |
| 61 | list_del_rcu(&p->thread_group); | ||
| 62 | remove_parent(p); | ||
| 63 | } | ||
| 58 | 64 | ||
| 59 | REMOVE_LINKS(p); | 65 | /* |
| 66 | * This function expects the tasklist_lock write-locked. | ||
| 67 | */ | ||
| 68 | static void __exit_signal(struct task_struct *tsk) | ||
| 69 | { | ||
| 70 | struct signal_struct *sig = tsk->signal; | ||
| 71 | struct sighand_struct *sighand; | ||
| 72 | |||
| 73 | BUG_ON(!sig); | ||
| 74 | BUG_ON(!atomic_read(&sig->count)); | ||
| 75 | |||
| 76 | rcu_read_lock(); | ||
| 77 | sighand = rcu_dereference(tsk->sighand); | ||
| 78 | spin_lock(&sighand->siglock); | ||
| 79 | |||
| 80 | posix_cpu_timers_exit(tsk); | ||
| 81 | if (atomic_dec_and_test(&sig->count)) | ||
| 82 | posix_cpu_timers_exit_group(tsk); | ||
| 83 | else { | ||
| 84 | /* | ||
| 85 | * If there is any task waiting for the group exit | ||
| 86 | * then notify it: | ||
| 87 | */ | ||
| 88 | if (sig->group_exit_task && atomic_read(&sig->count) == sig->notify_count) { | ||
| 89 | wake_up_process(sig->group_exit_task); | ||
| 90 | sig->group_exit_task = NULL; | ||
| 91 | } | ||
| 92 | if (tsk == sig->curr_target) | ||
| 93 | sig->curr_target = next_thread(tsk); | ||
| 94 | /* | ||
| 95 | * Accumulate here the counters for all threads but the | ||
| 96 | * group leader as they die, so they can be added into | ||
| 97 | * the process-wide totals when those are taken. | ||
| 98 | * The group leader stays around as a zombie as long | ||
| 99 | * as there are other threads. When it gets reaped, | ||
| 100 | * the exit.c code will add its counts into these totals. | ||
| 101 | * We won't ever get here for the group leader, since it | ||
| 102 | * will have been the last reference on the signal_struct. | ||
| 103 | */ | ||
| 104 | sig->utime = cputime_add(sig->utime, tsk->utime); | ||
| 105 | sig->stime = cputime_add(sig->stime, tsk->stime); | ||
| 106 | sig->min_flt += tsk->min_flt; | ||
| 107 | sig->maj_flt += tsk->maj_flt; | ||
| 108 | sig->nvcsw += tsk->nvcsw; | ||
| 109 | sig->nivcsw += tsk->nivcsw; | ||
| 110 | sig->sched_time += tsk->sched_time; | ||
| 111 | sig = NULL; /* Marker for below. */ | ||
| 112 | } | ||
| 113 | |||
| 114 | __unhash_process(tsk); | ||
| 115 | |||
| 116 | tsk->signal = NULL; | ||
| 117 | tsk->sighand = NULL; | ||
| 118 | spin_unlock(&sighand->siglock); | ||
| 119 | rcu_read_unlock(); | ||
| 120 | |||
| 121 | __cleanup_sighand(sighand); | ||
| 122 | clear_tsk_thread_flag(tsk,TIF_SIGPENDING); | ||
| 123 | flush_sigqueue(&tsk->pending); | ||
| 124 | if (sig) { | ||
| 125 | flush_sigqueue(&sig->shared_pending); | ||
| 126 | __cleanup_signal(sig); | ||
| 127 | } | ||
| 60 | } | 128 | } |
| 61 | 129 | ||
| 62 | void release_task(struct task_struct * p) | 130 | void release_task(struct task_struct * p) |
| @@ -65,21 +133,14 @@ void release_task(struct task_struct * p) | |||
| 65 | task_t *leader; | 133 | task_t *leader; |
| 66 | struct dentry *proc_dentry; | 134 | struct dentry *proc_dentry; |
| 67 | 135 | ||
| 68 | repeat: | 136 | repeat: |
| 69 | atomic_dec(&p->user->processes); | 137 | atomic_dec(&p->user->processes); |
| 70 | spin_lock(&p->proc_lock); | 138 | spin_lock(&p->proc_lock); |
| 71 | proc_dentry = proc_pid_unhash(p); | 139 | proc_dentry = proc_pid_unhash(p); |
| 72 | write_lock_irq(&tasklist_lock); | 140 | write_lock_irq(&tasklist_lock); |
| 73 | if (unlikely(p->ptrace)) | 141 | ptrace_unlink(p); |
| 74 | __ptrace_unlink(p); | ||
| 75 | BUG_ON(!list_empty(&p->ptrace_list) || !list_empty(&p->ptrace_children)); | 142 | BUG_ON(!list_empty(&p->ptrace_list) || !list_empty(&p->ptrace_children)); |
| 76 | __exit_signal(p); | 143 | __exit_signal(p); |
| 77 | /* | ||
| 78 | * Note that the fastpath in sys_times depends on __exit_signal having | ||
| 79 | * updated the counters before a task is removed from the tasklist of | ||
| 80 | * the process by __unhash_process. | ||
| 81 | */ | ||
| 82 | __unhash_process(p); | ||
| 83 | 144 | ||
| 84 | /* | 145 | /* |
| 85 | * If we are the last non-leader member of the thread | 146 | * If we are the last non-leader member of the thread |
| @@ -114,21 +175,6 @@ repeat: | |||
| 114 | goto repeat; | 175 | goto repeat; |
| 115 | } | 176 | } |
| 116 | 177 | ||
| 117 | /* we are using it only for SMP init */ | ||
| 118 | |||
| 119 | void unhash_process(struct task_struct *p) | ||
| 120 | { | ||
| 121 | struct dentry *proc_dentry; | ||
| 122 | |||
| 123 | spin_lock(&p->proc_lock); | ||
| 124 | proc_dentry = proc_pid_unhash(p); | ||
| 125 | write_lock_irq(&tasklist_lock); | ||
| 126 | __unhash_process(p); | ||
| 127 | write_unlock_irq(&tasklist_lock); | ||
| 128 | spin_unlock(&p->proc_lock); | ||
| 129 | proc_pid_flush(proc_dentry); | ||
| 130 | } | ||
| 131 | |||
| 132 | /* | 178 | /* |
| 133 | * This checks not only the pgrp, but falls back on the pid if no | 179 | * This checks not only the pgrp, but falls back on the pid if no |
| 134 | * satisfactory pgrp is found. I dunno - gdb doesn't work correctly | 180 | * satisfactory pgrp is found. I dunno - gdb doesn't work correctly |
| @@ -236,10 +282,10 @@ static void reparent_to_init(void) | |||
| 236 | 282 | ||
| 237 | ptrace_unlink(current); | 283 | ptrace_unlink(current); |
| 238 | /* Reparent to init */ | 284 | /* Reparent to init */ |
| 239 | REMOVE_LINKS(current); | 285 | remove_parent(current); |
| 240 | current->parent = child_reaper; | 286 | current->parent = child_reaper; |
| 241 | current->real_parent = child_reaper; | 287 | current->real_parent = child_reaper; |
| 242 | SET_LINKS(current); | 288 | add_parent(current); |
| 243 | 289 | ||
| 244 | /* Set the exit signal to SIGCHLD so we signal init on exit */ | 290 | /* Set the exit signal to SIGCHLD so we signal init on exit */ |
| 245 | current->exit_signal = SIGCHLD; | 291 | current->exit_signal = SIGCHLD; |
| @@ -345,9 +391,9 @@ void daemonize(const char *name, ...) | |||
| 345 | exit_mm(current); | 391 | exit_mm(current); |
| 346 | 392 | ||
| 347 | set_special_pids(1, 1); | 393 | set_special_pids(1, 1); |
| 348 | down(&tty_sem); | 394 | mutex_lock(&tty_mutex); |
| 349 | current->signal->tty = NULL; | 395 | current->signal->tty = NULL; |
| 350 | up(&tty_sem); | 396 | mutex_unlock(&tty_mutex); |
| 351 | 397 | ||
| 352 | /* Block and flush all signals */ | 398 | /* Block and flush all signals */ |
| 353 | sigfillset(&blocked); | 399 | sigfillset(&blocked); |
| @@ -536,13 +582,13 @@ static void exit_mm(struct task_struct * tsk) | |||
| 536 | mmput(mm); | 582 | mmput(mm); |
| 537 | } | 583 | } |
| 538 | 584 | ||
| 539 | static inline void choose_new_parent(task_t *p, task_t *reaper, task_t *child_reaper) | 585 | static inline void choose_new_parent(task_t *p, task_t *reaper) |
| 540 | { | 586 | { |
| 541 | /* | 587 | /* |
| 542 | * Make sure we're not reparenting to ourselves and that | 588 | * Make sure we're not reparenting to ourselves and that |
| 543 | * the parent is not a zombie. | 589 | * the parent is not a zombie. |
| 544 | */ | 590 | */ |
| 545 | BUG_ON(p == reaper || reaper->exit_state >= EXIT_ZOMBIE); | 591 | BUG_ON(p == reaper || reaper->exit_state); |
| 546 | p->real_parent = reaper; | 592 | p->real_parent = reaper; |
| 547 | } | 593 | } |
| 548 | 594 | ||
| @@ -567,9 +613,9 @@ static void reparent_thread(task_t *p, task_t *father, int traced) | |||
| 567 | * anyway, so let go of it. | 613 | * anyway, so let go of it. |
| 568 | */ | 614 | */ |
| 569 | p->ptrace = 0; | 615 | p->ptrace = 0; |
| 570 | list_del_init(&p->sibling); | 616 | remove_parent(p); |
| 571 | p->parent = p->real_parent; | 617 | p->parent = p->real_parent; |
| 572 | list_add_tail(&p->sibling, &p->parent->children); | 618 | add_parent(p); |
| 573 | 619 | ||
| 574 | /* If we'd notified the old parent about this child's death, | 620 | /* If we'd notified the old parent about this child's death, |
| 575 | * also notify the new parent. | 621 | * also notify the new parent. |
| @@ -643,7 +689,7 @@ static void forget_original_parent(struct task_struct * father, | |||
| 643 | 689 | ||
| 644 | if (father == p->real_parent) { | 690 | if (father == p->real_parent) { |
| 645 | /* reparent with a reaper, real father it's us */ | 691 | /* reparent with a reaper, real father it's us */ |
| 646 | choose_new_parent(p, reaper, child_reaper); | 692 | choose_new_parent(p, reaper); |
| 647 | reparent_thread(p, father, 0); | 693 | reparent_thread(p, father, 0); |
| 648 | } else { | 694 | } else { |
| 649 | /* reparent ptraced task to its real parent */ | 695 | /* reparent ptraced task to its real parent */ |
| @@ -664,7 +710,7 @@ static void forget_original_parent(struct task_struct * father, | |||
| 664 | } | 710 | } |
| 665 | list_for_each_safe(_p, _n, &father->ptrace_children) { | 711 | list_for_each_safe(_p, _n, &father->ptrace_children) { |
| 666 | p = list_entry(_p,struct task_struct,ptrace_list); | 712 | p = list_entry(_p,struct task_struct,ptrace_list); |
| 667 | choose_new_parent(p, reaper, child_reaper); | 713 | choose_new_parent(p, reaper); |
| 668 | reparent_thread(p, father, 1); | 714 | reparent_thread(p, father, 1); |
| 669 | } | 715 | } |
| 670 | } | 716 | } |
| @@ -805,7 +851,7 @@ fastcall NORET_TYPE void do_exit(long code) | |||
| 805 | panic("Aiee, killing interrupt handler!"); | 851 | panic("Aiee, killing interrupt handler!"); |
| 806 | if (unlikely(!tsk->pid)) | 852 | if (unlikely(!tsk->pid)) |
| 807 | panic("Attempted to kill the idle task!"); | 853 | panic("Attempted to kill the idle task!"); |
| 808 | if (unlikely(tsk->pid == 1)) | 854 | if (unlikely(tsk == child_reaper)) |
| 809 | panic("Attempted to kill init!"); | 855 | panic("Attempted to kill init!"); |
| 810 | 856 | ||
| 811 | if (unlikely(current->ptrace & PT_TRACE_EXIT)) { | 857 | if (unlikely(current->ptrace & PT_TRACE_EXIT)) { |
| @@ -852,6 +898,12 @@ fastcall NORET_TYPE void do_exit(long code) | |||
| 852 | exit_itimers(tsk->signal); | 898 | exit_itimers(tsk->signal); |
| 853 | acct_process(code); | 899 | acct_process(code); |
| 854 | } | 900 | } |
| 901 | if (unlikely(tsk->robust_list)) | ||
| 902 | exit_robust_list(tsk); | ||
| 903 | #ifdef CONFIG_COMPAT | ||
| 904 | if (unlikely(tsk->compat_robust_list)) | ||
| 905 | compat_exit_robust_list(tsk); | ||
| 906 | #endif | ||
| 855 | exit_mm(tsk); | 907 | exit_mm(tsk); |
| 856 | 908 | ||
| 857 | exit_sem(tsk); | 909 | exit_sem(tsk); |
| @@ -912,13 +964,6 @@ asmlinkage long sys_exit(int error_code) | |||
| 912 | do_exit((error_code&0xff)<<8); | 964 | do_exit((error_code&0xff)<<8); |
| 913 | } | 965 | } |
| 914 | 966 | ||
| 915 | task_t fastcall *next_thread(const task_t *p) | ||
| 916 | { | ||
| 917 | return pid_task(p->pids[PIDTYPE_TGID].pid_list.next, PIDTYPE_TGID); | ||
| 918 | } | ||
| 919 | |||
| 920 | EXPORT_SYMBOL(next_thread); | ||
| 921 | |||
| 922 | /* | 967 | /* |
| 923 | * Take down every thread in the group. This is called by fatal signals | 968 | * Take down every thread in the group. This is called by fatal signals |
| 924 | * as well as by sys_exit_group (below). | 969 | * as well as by sys_exit_group (below). |
| @@ -933,7 +978,6 @@ do_group_exit(int exit_code) | |||
| 933 | else if (!thread_group_empty(current)) { | 978 | else if (!thread_group_empty(current)) { |
| 934 | struct signal_struct *const sig = current->signal; | 979 | struct signal_struct *const sig = current->signal; |
| 935 | struct sighand_struct *const sighand = current->sighand; | 980 | struct sighand_struct *const sighand = current->sighand; |
| 936 | read_lock(&tasklist_lock); | ||
| 937 | spin_lock_irq(&sighand->siglock); | 981 | spin_lock_irq(&sighand->siglock); |
| 938 | if (sig->flags & SIGNAL_GROUP_EXIT) | 982 | if (sig->flags & SIGNAL_GROUP_EXIT) |
| 939 | /* Another thread got here before we took the lock. */ | 983 | /* Another thread got here before we took the lock. */ |
| @@ -943,7 +987,6 @@ do_group_exit(int exit_code) | |||
| 943 | zap_other_threads(current); | 987 | zap_other_threads(current); |
| 944 | } | 988 | } |
| 945 | spin_unlock_irq(&sighand->siglock); | 989 | spin_unlock_irq(&sighand->siglock); |
| 946 | read_unlock(&tasklist_lock); | ||
| 947 | } | 990 | } |
| 948 | 991 | ||
| 949 | do_exit(exit_code); | 992 | do_exit(exit_code); |
| @@ -1273,7 +1316,7 @@ bail_ref: | |||
| 1273 | 1316 | ||
| 1274 | /* move to end of parent's list to avoid starvation */ | 1317 | /* move to end of parent's list to avoid starvation */ |
| 1275 | remove_parent(p); | 1318 | remove_parent(p); |
| 1276 | add_parent(p, p->parent); | 1319 | add_parent(p); |
| 1277 | 1320 | ||
| 1278 | write_unlock_irq(&tasklist_lock); | 1321 | write_unlock_irq(&tasklist_lock); |
| 1279 | 1322 | ||
