signal.c
来自「优龙2410linux2.6.8内核源代码」· C语言 代码 · 共 621 行 · 第 1/2 页
C
621 行
err |= __put_user(regs->cp0_badvaddr, &sc->sc_badvaddr); err |= __put_user(current->used_math, &sc->sc_used_math); if (!current->used_math) goto out; /* * Save FPU state to signal context. Signal handler will "inherit" * current FPU state. */ if (!is_fpu_owner()) { own_fpu(); restore_fp(current); } err |= save_fp_context(sc);out: return err;}/* * Determine which stack to use.. */static inline void *get_sigframe(struct k_sigaction *ka, struct pt_regs *regs, size_t frame_size){ unsigned long sp; /* Default to using normal stack */ sp = regs->regs[29]; /* * FPU emulator may have it's own trampoline active just * above the user stack, 16-bytes before the next lowest * 16 byte boundary. Try to avoid trashing it. */ sp -= 32; /* This is the X/Open sanctioned signal stack switching. */ if ((ka->sa.sa_flags & SA_ONSTACK) && (sas_ss_flags (sp) == 0)) sp = current->sas_ss_sp + current->sas_ss_size; return (void *)((sp - frame_size) & ALMASK);}#ifdef CONFIG_TRAD_SIGNALSstatic void inline setup_frame(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *set){ struct sigframe *frame; int err = 0; frame = get_sigframe(ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) goto give_sigsegv; /* * Set up the return code ... * * li v0, __NR_sigreturn * syscall */ err |= __put_user(0x24020000 + __NR_sigreturn, frame->sf_code + 0); err |= __put_user(0x0000000c , frame->sf_code + 1); flush_cache_sigtramp((unsigned long) frame->sf_code); err |= setup_sigcontext(regs, &frame->sf_sc); err |= __copy_to_user(&frame->sf_mask, set, sizeof(*set)); if (err) goto give_sigsegv; /* * Arguments to signal handler: * * a0 = signal number * a1 = 0 (should be cause) * a2 = pointer to struct sigcontext * * $25 and c0_epc point to the signal handler, $29 points to the * struct sigframe. */ regs->regs[ 4] = signr; regs->regs[ 5] = 0; regs->regs[ 6] = (unsigned long) &frame->sf_sc; regs->regs[29] = (unsigned long) frame; regs->regs[31] = (unsigned long) frame->sf_code; regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;#if DEBUG_SIG printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n", current->comm, current->pid, frame, regs->cp0_epc, frame->regs[31]);#endif return;give_sigsegv: if (signr == SIGSEGV) ka->sa.sa_handler = SIG_DFL; force_sig(SIGSEGV, current);}#endifstatic void inline setup_rt_frame(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info){ struct rt_sigframe *frame; int err = 0; frame = get_sigframe(ka, regs, sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof (*frame))) goto give_sigsegv; /* * Set up the return code ... * * li v0, __NR_rt_sigreturn * syscall */ err |= __put_user(0x24020000 + __NR_rt_sigreturn, frame->rs_code + 0); err |= __put_user(0x0000000c , frame->rs_code + 1); flush_cache_sigtramp((unsigned long) frame->rs_code); /* Create siginfo. */ err |= copy_siginfo_to_user(&frame->rs_info, info); /* Create the ucontext. */ err |= __put_user(0, &frame->rs_uc.uc_flags); err |= __put_user(0, &frame->rs_uc.uc_link); err |= __put_user((void *)current->sas_ss_sp, &frame->rs_uc.uc_stack.ss_sp); err |= __put_user(sas_ss_flags(regs->regs[29]), &frame->rs_uc.uc_stack.ss_flags); err |= __put_user(current->sas_ss_size, &frame->rs_uc.uc_stack.ss_size); err |= setup_sigcontext(regs, &frame->rs_uc.uc_mcontext); err |= __copy_to_user(&frame->rs_uc.uc_sigmask, set, sizeof(*set)); if (err) goto give_sigsegv; /* * Arguments to signal handler: * * a0 = signal number * a1 = 0 (should be cause) * a2 = pointer to ucontext * * $25 and c0_epc point to the signal handler, $29 points to * the struct rt_sigframe. */ regs->regs[ 4] = signr; regs->regs[ 5] = (unsigned long) &frame->rs_info; regs->regs[ 6] = (unsigned long) &frame->rs_uc; regs->regs[29] = (unsigned long) frame; regs->regs[31] = (unsigned long) frame->rs_code; regs->cp0_epc = regs->regs[25] = (unsigned long) ka->sa.sa_handler;#if DEBUG_SIG printk("SIG deliver (%s:%d): sp=0x%p pc=0x%lx ra=0x%p\n", current->comm, current->pid, frame, regs->cp0_epc, regs->regs[31]);#endif return;give_sigsegv: if (signr == SIGSEGV) ka->sa.sa_handler = SIG_DFL; force_sig(SIGSEGV, current);}extern void setup_rt_frame_n32(struct k_sigaction * ka, struct pt_regs *regs, int signr, sigset_t *set, siginfo_t *info);static inline void handle_signal(unsigned long sig, siginfo_t *info, sigset_t *oldset, struct pt_regs *regs){ struct k_sigaction *ka = ¤t->sighand->action[sig-1]; switch(regs->regs[0]) { case ERESTART_RESTARTBLOCK: case ERESTARTNOHAND: regs->regs[2] = EINTR; break; case ERESTARTSYS: if(!(ka->sa.sa_flags & SA_RESTART)) { regs->regs[2] = EINTR; break; } /* fallthrough */ case ERESTARTNOINTR: /* Userland will reload $v0. */ regs->regs[7] = regs->regs[26]; regs->cp0_epc -= 8; } regs->regs[0] = 0; /* Don't deal with this again. */#ifdef CONFIG_TRAD_SIGNALS if (ka->sa.sa_flags & SA_SIGINFO) {#else if (1) {#endif#ifdef CONFIG_MIPS32_N32 if ((current->thread.mflags & MF_ABI_MASK) == MF_N32) setup_rt_frame_n32 (ka, regs, sig, oldset, info); else#endif setup_rt_frame(ka, regs, sig, oldset, info); }#ifdef CONFIG_TRAD_SIGNALS else setup_frame(ka, regs, sig, oldset);#endif if (ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL; if (!(ka->sa.sa_flags & SA_NODEFER)) { spin_lock_irq(¤t->sighand->siglock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); sigaddset(¤t->blocked,sig); recalc_sigpending(); spin_unlock_irq(¤t->sighand->siglock); }}extern int do_signal32(sigset_t *oldset, struct pt_regs *regs);extern int do_irix_signal(sigset_t *oldset, struct pt_regs *regs);asmlinkage int do_signal(sigset_t *oldset, struct pt_regs *regs){ siginfo_t info; int signr;#ifdef CONFIG_BINFMT_ELF32 if ((current->thread.mflags & MF_ABI_MASK) == MF_O32) { return do_signal32(oldset, regs); }#endif /* * We want the common case to go fast, which is why we may in certain * cases get here from kernel mode. Just return without doing anything * if so. */ if (!user_mode(regs)) return 1; if (current->flags & PF_FREEZE) { refrigerator(0); goto no_signal; } if (!oldset) oldset = ¤t->blocked; signr = get_signal_to_deliver(&info, regs, NULL); if (signr > 0) { handle_signal(signr, &info, oldset, regs); return 1; }no_signal: /* * Who's code doesn't conform to the restartable syscall convention * dies here!!! The li instruction, a single machine instruction, * must directly be followed by the syscall instruction. */ if (regs->regs[0]) { if (regs->regs[2] == ERESTARTNOHAND || regs->regs[2] == ERESTARTSYS || regs->regs[2] == ERESTARTNOINTR) { regs->regs[7] = regs->regs[26]; regs->cp0_epc -= 8; } if (regs->regs[2] == ERESTART_RESTARTBLOCK) { regs->regs[2] = __NR_restart_syscall; regs->regs[7] = regs->regs[26]; regs->cp0_epc -= 4; } } return 0;}extern int do_irix_signal(sigset_t *oldset, struct pt_regs *regs);/* * notification of userspace execution resumption * - triggered by current->work.notify_resume */asmlinkage void do_notify_resume(struct pt_regs *regs, sigset_t *oldset, __u32 thread_info_flags){ /* deal with pending signal delivery */ if (thread_info_flags & _TIF_SIGPENDING) {#ifdef CONFIG_BINFMT_ELF32 if (likely((current->thread.mflags & MF_ABI_MASK) == MF_O32)) { do_signal32(oldset, regs); return; }#endif#ifdef CONFIG_BINFMT_IRIX if (unlikely(current->personality != PER_LINUX)) { do_irix_signal(oldset, regs); return; }#endif do_signal(oldset, regs); }}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?