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 /arch/mips/kernel/signal.c | |
parent | 7206675c40394c78a90e74812bbdbf8cf3cca1be (diff) |
Import of Linux/MIPS 2.1.36
Diffstat (limited to 'arch/mips/kernel/signal.c')
-rw-r--r-- | arch/mips/kernel/signal.c | 125 |
1 files changed, 43 insertions, 82 deletions
diff --git a/arch/mips/kernel/signal.c b/arch/mips/kernel/signal.c index fdbc86558..848f0742b 100644 --- a/arch/mips/kernel/signal.c +++ b/arch/mips/kernel/signal.c @@ -7,6 +7,8 @@ #include <linux/config.h> #include <linux/sched.h> #include <linux/mm.h> +#include <linux/smp.h> +#include <linux/smp_lock.h> #include <linux/kernel.h> #include <linux/signal.h> #include <linux/errno.h> @@ -23,77 +25,37 @@ #define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) -asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options); +asmlinkage int sys_wait4(pid_t pid, unsigned long *stat_addr, + int options, unsigned long *ru); asmlinkage int do_signal(unsigned long oldmask, struct pt_regs *regs); extern asmlinkage void (*save_fp_context)(struct sigcontext *sc); extern asmlinkage void (*restore_fp_context)(struct sigcontext *sc); -asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset) -{ - k_sigset_t new_set, old_set = current->blocked; - int error; - - if (set) { - error = verify_area(VERIFY_READ, set, sizeof(sigset_t)); - if (error) - return error; - new_set = *to_k_sigset_t(set) & _BLOCKABLE; - switch (how) { - case SIG_BLOCK: - current->blocked |= new_set; - break; - case SIG_UNBLOCK: - current->blocked &= ~new_set; - break; - case SIG_SETMASK: - current->blocked = new_set; - break; - /* - * SGI goodie: Just set the low 32 bits of 'blocked' even - * for 128 bit sigset_t. - */ - case SIG_SETMASK32: - current->blocked = new_set; - break; - default: - return -EINVAL; - } - } - if (oset) { - error = verify_area(VERIFY_WRITE, oset, sizeof(sigset_t)); - if (error) - return error; - put_user(old_set, &oset->__sigbits[0]); - put_user(0, &oset->__sigbits[1]); - put_user(0, &oset->__sigbits[2]); - put_user(0, &oset->__sigbits[3]); - } - return 0; -} - /* * Atomically swap in the new signal mask, and wait for a signal. + * Unlike on Intel we pass a sigset_t *, not sigset_t. */ asmlinkage int sys_sigsuspend(struct pt_regs *regs) { - unsigned int mask; - sigset_t *uset; - k_sigset_t kset; + unsigned long mask; + sigset_t *uset, set; - mask = current->blocked; uset = (sigset_t *)(long) regs->regs[4]; - if (verify_area(VERIFY_READ, uset, sizeof(sigset_t))) + if (get_user(set, uset)) return -EFAULT; - kset = *to_k_sigset_t(uset); - current->blocked = kset & _BLOCKABLE; + + spin_lock_irq(¤t->sigmask_lock); + mask = current->blocked; + current->blocked = set & _BLOCKABLE; + spin_unlock_irq(¤t->sigmask_lock); + regs->regs[2] = -EINTR; while (1) { current->state = TASK_INTERRUPTIBLE; schedule(); - if (do_signal(mask,regs)) + if (do_signal(mask, regs)) return -EINTR; } - return -EINTR; } @@ -102,17 +64,12 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) struct sigcontext *context; int i; - /* - * We don't support fixing ADEL/ADES exceptions for signal stack frames. - * No big loss - who doesn't care about the alignment of this stack - * really deserves to loose. - */ context = (struct sigcontext *)(long) regs->regs[29]; if (!access_ok(VERIFY_READ, context, sizeof(struct sigcontext)) || (regs->regs[29] & (SZREG - 1))) goto badframe; - current->blocked = context->sc_sigset.__sigbits[0] & _BLOCKABLE; + current->blocked = context->sc_sigset & _BLOCKABLE; regs->cp0_epc = context->sc_pc; /* @@ -140,7 +97,7 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) /* * Don't let your children do this ... */ - asm __volatile__( + __asm__ __volatile__( "move\t$29,%0\n\t" "j\tret_from_sys_call" :/* no outputs */ @@ -148,7 +105,9 @@ asmlinkage int sys_sigreturn(struct pt_regs *regs) /* Unreached */ badframe: + lock_kernel(); do_exit(SIGSEGV); + unlock_kernel(); } /* @@ -201,7 +160,7 @@ static void setup_frame(struct sigaction * sa, struct pt_regs *regs, /* We realign the stack to an adequate boundary for the architecture. */ if (verify_area(VERIFY_WRITE, frame, sizeof (struct sc))) - do_exit(SIGSEGV); + goto segv_and_exit; frame = (struct sc *)((unsigned long)frame & ALMASK); sc = &frame->scc; @@ -235,10 +194,10 @@ static void setup_frame(struct sigaction * sa, struct pt_regs *regs, __put_user(regs->lo, &sc->sc_mdlo); __put_user(regs->cp0_cause, &sc->sc_cause); __put_user((regs->cp0_status & ST0_CU1) != 0, &sc->sc_ownedfp); - __put_user(oldmask, &sc->sc_sigset.__sigbits[0]); - __put_user(0, &sc->sc_sigset.__sigbits[1]); - __put_user(0, &sc->sc_sigset.__sigbits[2]); - __put_user(0, &sc->sc_sigset.__sigbits[3]); + __put_user(oldmask, &sc->sc_sigset); + __put_user(0, &sc->__pad0[0]); + __put_user(0, &sc->__pad0[1]); + __put_user(0, &sc->__pad0[2]); regs->regs[4] = signr; /* Arguments for handler */ regs->regs[5] = 0; /* For now. */ @@ -247,6 +206,11 @@ static void setup_frame(struct sigaction * sa, struct pt_regs *regs, regs->regs[31] = (unsigned long) frame->code; /* Return address */ regs->cp0_epc = (unsigned long) sa->sa_handler; /* "return" to the first handler */ regs->regs[25] = regs->cp0_epc; /* PIC shit... */ + +segv_and_exit: + lock_kernel(); + do_exit(SIGSEGV); + unlock_kernel(); } static inline void handle_signal(unsigned long signr, struct sigaction *sa, @@ -256,9 +220,11 @@ static inline void handle_signal(unsigned long signr, struct sigaction *sa, if (sa->sa_flags & SA_ONESHOT) sa->sa_handler = NULL; - if (!(sa->sa_flags & SA_NOMASK)) - current->blocked |= - ((*to_k_sigset_t(&sa->sa_mask) | _S(signr)) & _BLOCKABLE); + if (!(sa->sa_flags & SA_NOMASK)) { + spin_lock_irq(¤t->sigmask_lock); + current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE; + spin_unlock_irq(¤t->sigmask_lock); + } } static inline void syscall_restart(unsigned long r0, unsigned long or2, @@ -319,7 +285,9 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) if (signr == SIGSTOP) continue; if (_S(signr) & current->blocked) { + spin_lock_irq(¤t->sigmask_lock); current->signal |= _S(signr); + spin_unlock_irq(¤t->sigmask_lock); continue; } sa = current->sig->action + signr - 1; @@ -328,7 +296,7 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) if (signr != SIGCHLD) continue; /* check for SIGCHLD: it's special */ - while (sys_waitpid(-1,NULL,WNOHANG) > 0) + while (sys_wait4(-1,NULL,WNOHANG, NULL) > 0) /* nothing */; continue; } @@ -350,7 +318,6 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) schedule(); continue; - case SIGQUIT: case SIGILL: case SIGTRAP: case SIGIOT: case SIGFPE: case SIGSEGV: case SIGBUS: if (current->binfmt && current->binfmt->core_dump) { if (current->binfmt->core_dump(signr, regs)) @@ -358,25 +325,23 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) } /* fall through */ default: + spin_lock_irq(¤t->sigmask_lock); current->signal |= _S(signr & 0x7f); + spin_unlock_irq(¤t->sigmask_lock); + current->flags |= PF_SIGNALED; + + lock_kernel(); /* 8-( */ do_exit(signr); + unlock_kernel(); } } /* * OK, we're invoking a handler */ -#if 0 - printk("[%s:%d] send sig1: r0[%08lx] r7[%08lx] reg[2]=%08lx\n", - current->comm, current->pid, r0, r7, regs->regs[2]); -#endif if(r0) syscall_restart(r0, regs->orig_reg2, r7, regs, sa); -#if 0 - printk("send sig2: r0[%08lx] r7[%08lx] reg[2]=%08lx\n", - r0, r7, regs->regs[2]); -#endif handle_signal(signr, sa, oldmask, regs); return 1; } @@ -385,10 +350,6 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) * dies here!!! The li instruction, a single machine instruction, * must directly be followed by the syscall instruction. */ -#if 0 - printk("[%s:%d] send sig3: r0[%08lx] r7[%08lx] reg[2]=%08lx\n", - current->comm, current->pid, r0, r7, regs->regs[2]); -#endif if (r0 && (regs->regs[2] == ERESTARTNOHAND || regs->regs[2] == ERESTARTSYS || |