diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-04-29 21:13:14 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1997-04-29 21:13:14 +0000 |
commit | 19c9bba94152148523ba0f7ef7cffe3d45656b11 (patch) | |
tree | 40b1cb534496a7f1ca0f5c314a523c69f1fee464 /kernel/exit.c | |
parent | 7206675c40394c78a90e74812bbdbf8cf3cca1be (diff) |
Import of Linux/MIPS 2.1.36
Diffstat (limited to 'kernel/exit.c')
-rw-r--r-- | kernel/exit.c | 276 |
1 files changed, 176 insertions, 100 deletions
diff --git a/kernel/exit.c b/kernel/exit.c index d4c54209d..0d03916e8 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -6,6 +6,7 @@ #undef DEBUG_PROC_TREE +#include <linux/config.h> #include <linux/wait.h> #include <linux/errno.h> #include <linux/signal.h> @@ -16,9 +17,14 @@ #include <linux/tty.h> #include <linux/malloc.h> #include <linux/interrupt.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> +#include <linux/module.h> +#include <asm/system.h> #include <asm/uaccess.h> #include <asm/pgtable.h> +#include <asm/mmu_context.h> extern void sem_exit (void); extern void acct_process (long exitcode); @@ -36,18 +42,23 @@ static inline void generate(unsigned long sig, struct task_struct * p) * be handled immediately (ie non-blocked and untraced) * and that is ignored (either explicitly or by default) */ + spin_lock_irq(&p->sig->siglock); if (!(mask & p->blocked) && !(p->flags & PF_PTRACED)) { /* don't bother with ignored signals (but SIGCHLD is special) */ if (sa->sa_handler == SIG_IGN && sig != SIGCHLD) - return; + goto out; /* some signals are ignored by default.. (but SIGCONT already did its deed) */ if ((sa->sa_handler == SIG_DFL) && (sig == SIGCONT || sig == SIGCHLD || sig == SIGWINCH || sig == SIGURG)) - return; + goto out; } + spin_lock(&p->sigmask_lock); p->signal |= mask; + spin_unlock(&p->sigmask_lock); if (p->state == TASK_INTERRUPTIBLE && (p->signal & ~p->blocked)) wake_up_process(p); +out: + spin_unlock_irq(&p->sig->siglock); } /* @@ -60,15 +71,22 @@ void force_sig(unsigned long sig, struct task_struct * p) if (p->sig) { unsigned long mask = 1UL << sig; struct sigaction *sa = p->sig->action + sig; + + spin_lock_irq(&p->sig->siglock); + + spin_lock(&p->sigmask_lock); p->signal |= mask; p->blocked &= ~mask; + spin_unlock(&p->sigmask_lock); + if (sa->sa_handler == SIG_IGN) sa->sa_handler = SIG_DFL; if (p->state == TASK_INTERRUPTIBLE) wake_up_process(p); + + spin_unlock_irq(&p->sig->siglock); } } - int send_sig(unsigned long sig,struct task_struct * p,int priv) { @@ -79,24 +97,23 @@ int send_sig(unsigned long sig,struct task_struct * p,int priv) (current->uid ^ p->suid) && (current->uid ^ p->uid) && !suser()) return -EPERM; - if (!sig) - return 0; - /* - * Forget it if the process is already zombie'd. - */ - if (!p->sig) - return 0; - if ((sig == SIGKILL) || (sig == SIGCONT)) { - if (p->state == TASK_STOPPED) - wake_up_process(p); - p->exit_code = 0; - p->signal &= ~( (1<<(SIGSTOP-1)) | (1<<(SIGTSTP-1)) | - (1<<(SIGTTIN-1)) | (1<<(SIGTTOU-1)) ); + + if (sig && p->sig) { + spin_lock_irq(&p->sigmask_lock); + if ((sig == SIGKILL) || (sig == SIGCONT)) { + if (p->state == TASK_STOPPED) + wake_up_process(p); + p->exit_code = 0; + p->signal &= ~( (1<<(SIGSTOP-1)) | (1<<(SIGTSTP-1)) | + (1<<(SIGTTIN-1)) | (1<<(SIGTTOU-1)) ); + } + if (sig == SIGSTOP || sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) + p->signal &= ~(1<<(SIGCONT-1)); + spin_unlock_irq(&p->sigmask_lock); + + /* Actually generate the signal */ + generate(sig,p); } - if (sig == SIGSTOP || sig == SIGTSTP || sig == SIGTTIN || sig == SIGTTOU) - p->signal &= ~(1<<(SIGCONT-1)); - /* Actually generate the signal */ - generate(sig,p); return 0; } @@ -120,6 +137,12 @@ void release(struct task_struct * p) } for (i=1 ; i<NR_TASKS ; i++) if (task[i] == p) { +#ifdef __SMP__ + /* FIXME! Cheesy, but kills the window... -DaveM */ + while(p->processor != NO_PROC_ID) + barrier(); + spin_unlock_wait(&scheduler_lock); +#endif nr_tasks--; task[i] = NULL; REMOVE_LINKS(p); @@ -130,7 +153,7 @@ void release(struct task_struct * p) current->cmin_flt += p->min_flt + p->cmin_flt; current->cmaj_flt += p->maj_flt + p->cmaj_flt; current->cnswap += p->nswap + p->cnswap; - kfree(p); + free_task_struct(p); return; } panic("trying to release non-existent task"); @@ -152,14 +175,14 @@ int bad_task_ptr(struct task_struct *p) return 0; return 1; } - + /* * This routine scans the pid tree and makes sure the rep invariant still * holds. Used for debugging only, since it's very slow.... * * It looks a lot scarier than it really is.... we're doing nothing more - * than verifying the doubly-linked list found in p_ysptr and p_osptr, - * and checking it corresponds with the process tree defined by p_cptr and + * than verifying the doubly-linked list found in p_ysptr and p_osptr, + * and checking it corresponds with the process tree defined by p_cptr and * p_pptr; */ void audit_ptree(void) @@ -240,14 +263,18 @@ int session_of_pgrp(int pgrp) int fallback; fallback = -1; + read_lock(&tasklist_lock); for_each_task(p) { if (p->session <= 0) continue; - if (p->pgrp == pgrp) - return p->session; + if (p->pgrp == pgrp) { + fallback = p->session; + break; + } if (p->pid == pgrp) fallback = p->session; } + read_unlock(&tasklist_lock); return fallback; } @@ -257,21 +284,29 @@ int session_of_pgrp(int pgrp) */ int kill_pg(int pgrp, int sig, int priv) { - struct task_struct *p; - int err,retval = -ESRCH; - int found = 0; + int retval; - if (sig<0 || sig>32 || pgrp<=0) - return -EINVAL; - for_each_task(p) { - if (p->pgrp == pgrp) { - if ((err = send_sig(sig,p,priv)) != 0) - retval = err; - else - found++; + retval = -EINVAL; + if (sig >= 0 && sig <= 32 && pgrp > 0) { + struct task_struct *p; + int found = 0; + + retval = -ESRCH; + read_lock(&tasklist_lock); + for_each_task(p) { + if (p->pgrp == pgrp) { + int err = send_sig(sig,p,priv); + if (err != 0) + retval = err; + else + found++; + } } + read_unlock(&tasklist_lock); + if (found) + retval = 0; } - return(found ? 0 : retval); + return retval; } /* @@ -281,34 +316,51 @@ int kill_pg(int pgrp, int sig, int priv) */ int kill_sl(int sess, int sig, int priv) { - struct task_struct *p; - int err,retval = -ESRCH; - int found = 0; + int retval; - if (sig<0 || sig>32 || sess<=0) - return -EINVAL; - for_each_task(p) { - if (p->session == sess && p->leader) { - if ((err = send_sig(sig,p,priv)) != 0) - retval = err; - else - found++; + retval = -EINVAL; + if (sig >= 0 && sig <= 32 && sess > 0) { + struct task_struct *p; + int found = 0; + + retval = -ESRCH; + read_lock(&tasklist_lock); + for_each_task(p) { + if (p->leader && p->session == sess) { + int err = send_sig(sig,p,priv); + + if (err) + retval = err; + else + found++; + } } + read_unlock(&tasklist_lock); + if (found) + retval = 0; } - return(found ? 0 : retval); + return retval; } int kill_proc(int pid, int sig, int priv) { - struct task_struct *p; + int retval; - if (sig<0 || sig>32) - return -EINVAL; - for_each_task(p) { - if (p && p->pid == pid) - return send_sig(sig,p,priv); + retval = -EINVAL; + if (sig >= 0 && sig <= 32) { + struct task_struct *p; + + retval = -ESRCH; + read_lock(&tasklist_lock); + for_each_task(p) { + if (p->pid != pid) + continue; + retval = send_sig(sig,p,priv); + break; + } + read_unlock(&tasklist_lock); } - return(-ESRCH); + return retval; } /* @@ -317,49 +369,58 @@ int kill_proc(int pid, int sig, int priv) */ asmlinkage int sys_kill(int pid,int sig) { - int err, retval = 0, count = 0; - if (!pid) - return(kill_pg(current->pgrp,sig,0)); + return kill_pg(current->pgrp,sig,0); + if (pid == -1) { + int retval = 0, count = 0; struct task_struct * p; + + read_lock(&tasklist_lock); for_each_task(p) { if (p->pid > 1 && p != current) { + int err; ++count; if ((err = send_sig(sig,p,0)) != -EPERM) retval = err; } } - return(count ? retval : -ESRCH); + read_unlock(&tasklist_lock); + return count ? retval : -ESRCH; } - if (pid < 0) - return(kill_pg(-pid,sig,0)); + if (pid < 0) + return kill_pg(-pid,sig,0); + /* Normal kill */ - return(kill_proc(pid,sig,0)); + return kill_proc(pid,sig,0); } /* * Determine if a process group is "orphaned", according to the POSIX * definition in 2.2.2.52. Orphaned process groups are not to be affected - * by terminal-generated stop signals. Newly orphaned process groups are + * by terminal-generated stop signals. Newly orphaned process groups are * to receive a SIGHUP and a SIGCONT. - * + * * "I ask you, have you ever known what it is to be an orphan?" */ static int will_become_orphaned_pgrp(int pgrp, struct task_struct * ignored_task) { struct task_struct *p; + read_lock(&tasklist_lock); for_each_task(p) { - if ((p == ignored_task) || (p->pgrp != pgrp) || + if ((p == ignored_task) || (p->pgrp != pgrp) || (p->state == TASK_ZOMBIE) || (p->p_pptr->pid == 1)) continue; if ((p->p_pptr->pgrp != pgrp) && - (p->p_pptr->session == p->session)) - return 0; + (p->p_pptr->session == p->session)) { + read_unlock(&tasklist_lock); + return 0; + } } - return(1); /* (sighing) "Often!" */ + read_unlock(&tasklist_lock); + return 1; /* (sighing) "Often!" */ } int is_orphaned_pgrp(int pgrp) @@ -369,21 +430,27 @@ int is_orphaned_pgrp(int pgrp) static inline int has_stopped_jobs(int pgrp) { + int retval = 0; struct task_struct * p; + read_lock(&tasklist_lock); for_each_task(p) { if (p->pgrp != pgrp) continue; - if (p->state == TASK_STOPPED) - return(1); + if (p->state != TASK_STOPPED) + continue; + retval = 1; + break; } - return(0); + read_unlock(&tasklist_lock); + return retval; } static inline void forget_original_parent(struct task_struct * father) { struct task_struct * p; + read_lock(&tasklist_lock); for_each_task(p) { if (p->p_opptr == father) if (task[smp_num_cpus]) /* init */ @@ -391,6 +458,7 @@ static inline void forget_original_parent(struct task_struct * father) else p->p_opptr = task[0]; } + read_unlock(&tasklist_lock); } static inline void close_files(struct files_struct * files) @@ -456,9 +524,8 @@ static inline void __exit_sighand(struct task_struct *tsk) if (sig) { tsk->sig = NULL; - if (!--sig->count) { + if (atomic_dec_and_test(&sig->count)) kfree(sig); - } } } @@ -475,9 +542,7 @@ static inline void __exit_mm(struct task_struct * tsk) if (mm != &init_mm) { flush_cache_mm(mm); flush_tlb_mm(mm); -#ifdef __mips__ - mm->context = 0; -#endif + destroy_context(mm); tsk->mm = &init_mm; tsk->swappable = 0; SET_PAGE_DIR(tsk, swapper_pg_dir); @@ -496,7 +561,7 @@ void exit_mm(struct task_struct *tsk) __exit_mm(tsk); } -/* +/* * Send signals to all our closest relatives so that they know * to properly mourn us.. */ @@ -505,7 +570,7 @@ static void exit_notify(void) struct task_struct * p; forget_original_parent(current); - /* + /* * Check to see if any process groups have become orphaned * as a result of our exiting, and if they have any stopped * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2) @@ -523,10 +588,10 @@ static void exit_notify(void) } /* Let father know we died */ notify_parent(current); - + /* * This loop does two things: - * + * * A. Make init inherit all the child processes * B. Check to see if any process groups have become orphaned * as a result of our exiting, and if they have any stopped @@ -547,7 +612,7 @@ static void exit_notify(void) notify_parent(p); /* * process group orphan check - * Case ii: Our child is in a different pgrp + * Case ii: Our child is in a different pgrp * than we are, and it was the only connection * outside, so the child pgrp is now orphaned. */ @@ -565,9 +630,9 @@ static void exit_notify(void) NORET_TYPE void do_exit(long code) { - if (intr_count) { + if (in_interrupt()) { + local_irq_count[smp_processor_id()] = 0; /* Not really correct */ printk("Aiee, killing interrupt handler\n"); - intr_count = 0; } fake_volatile: acct_process(code); @@ -576,6 +641,9 @@ fake_volatile: sem_exit(); kerneld_exit(); __exit_mm(current); +#if CONFIG_AP1000 + exit_msc(current); +#endif __exit_files(current); __exit_fs(current); __exit_sighand(current); @@ -586,10 +654,10 @@ fake_volatile: #ifdef DEBUG_PROC_TREE audit_ptree(); #endif - if (current->exec_domain && current->exec_domain->use_count) - (*current->exec_domain->use_count)--; - if (current->binfmt && current->binfmt->use_count) - (*current->binfmt->use_count)--; + if (current->exec_domain && current->exec_domain->module) + __MOD_DEC_USE_COUNT(current->exec_domain->module); + if (current->binfmt && current->binfmt->module) + __MOD_DEC_USE_COUNT(current->binfmt->module); schedule(); /* * In order to get rid of the "volatile function does return" message @@ -609,7 +677,9 @@ fake_volatile: asmlinkage int sys_exit(int error_code) { + lock_kernel(); do_exit((error_code&0xff)<<8); + unlock_kernel(); } asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct rusage * ru) @@ -619,21 +689,21 @@ asmlinkage int sys_wait4(pid_t pid,unsigned int * stat_addr, int options, struct struct task_struct *p; if (stat_addr) { - flag = verify_area(VERIFY_WRITE, stat_addr, sizeof(*stat_addr)); - if (flag) - return flag; + if(verify_area(VERIFY_WRITE, stat_addr, sizeof(*stat_addr))) + return -EFAULT; } if (ru) { - flag = verify_area(VERIFY_WRITE, ru, sizeof(*ru)); - if (flag) - return flag; + if(verify_area(VERIFY_WRITE, ru, sizeof(*ru))) + return -EFAULT; } + if (options & ~(WNOHANG|WUNTRACED|__WCLONE)) - return -EINVAL; + return -EINVAL; add_wait_queue(¤t->wait_chldexit,&wait); repeat: - flag=0; + flag = 0; + read_lock(&tasklist_lock); for (p = current->p_cptr ; p ; p = p->p_osptr) { if (pid>0) { if (p->pid != pid) @@ -655,23 +725,28 @@ repeat: continue; if (!(options & WUNTRACED) && !(p->flags & PF_PTRACED)) continue; + read_unlock(&tasklist_lock); if (ru != NULL) getrusage(p, RUSAGE_BOTH, ru); if (stat_addr) - put_user((p->exit_code << 8) | 0x7f, - stat_addr); + __put_user((p->exit_code << 8) | 0x7f, + stat_addr); p->exit_code = 0; retval = p->pid; goto end_wait4; case TASK_ZOMBIE: current->cutime += p->utime + p->cutime; current->cstime += p->stime + p->cstime; + read_unlock(&tasklist_lock); if (ru != NULL) getrusage(p, RUSAGE_BOTH, ru); if (stat_addr) - put_user(p->exit_code, stat_addr); + __put_user(p->exit_code, stat_addr); retval = p->pid; if (p->p_opptr != p->p_pptr) { + /* Note this grabs tasklist_lock + * as a writer... (twice!) + */ REMOVE_LINKS(p); p->p_pptr = p->p_opptr; SET_LINKS(p); @@ -686,6 +761,7 @@ repeat: continue; } } + read_unlock(&tasklist_lock); if (flag) { retval = 0; if (options & WNOHANG) |