signal.c
来自「linux-2.4.29操作系统的源码」· C语言 代码 · 共 822 行 · 第 1/2 页
C
822 行
COPY(tregs[0]); COPY(tregs[1]); COPY(tregs[2]); COPY(tregs[3]); COPY(tregs[4]); COPY(tregs[5]); COPY(tregs[6]); COPY(tregs[7]); COPY(sr); COPY(pc);#undef COPY err |= __put_user(mask, &sc->oldmask); return err;}/* * Determine which stack to use.. */static inline void *get_sigframe(struct k_sigaction *ka, unsigned long sp, size_t frame_size){ if ((ka->sa.sa_flags & SA_ONSTACK) != 0 && ! on_sig_stack(sp)) sp = current->sas_ss_sp + current->sas_ss_size; return (void *)((sp - frame_size) & -8ul);}void sa_default_restorer(void); /* See comments below */void sa_default_rt_restorer(void); /* See comments below */static void setup_frame(int sig, struct k_sigaction *ka, sigset_t *set, struct pt_regs *regs){ struct sigframe *frame; int err = 0; int signal; frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; signal = current->exec_domain && current->exec_domain->signal_invmap && sig < 32 ? current->exec_domain->signal_invmap[sig] : sig; err |= setup_sigcontext(&frame->sc, regs, set->sig[0]); /* Give up earlier as i386, in case */ if (err) goto give_sigsegv; if (_NSIG_WORDS > 1) { err |= __copy_to_user(frame->extramask, &set->sig[1], sizeof(frame->extramask)); } /* Give up earlier as i386, in case */ if (err) goto give_sigsegv; /* Set up to return from userspace. If provided, use a stub already in userspace. */ if (ka->sa.sa_flags & SA_RESTORER) { DEREF_REG_PR = (unsigned long) ka->sa.sa_restorer | 0x1; /* * On SH5 all edited pointers are subject to NEFF */ DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; } else { /* * Different approach on SH5. * . Endianness independent asm code gets placed in entry.S . * This is limited to four ASM instructions corresponding * to two long longs in size. * . err checking is done on the else branch only * . flush_icache_range() is called upon __put_user() only * . all edited pointers are subject to NEFF * . being code, linker turns ShMedia bit on, always * dereference index -1. */ DEREF_REG_PR = (unsigned long) frame->retcode | 0x01; DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; if (__copy_to_user(frame->retcode, (unsigned long long)sa_default_restorer & (~1), 16) != 0) goto give_sigsegv; /* Cohere the trampoline with the I-cache. */ flush_cache_sigtramp(DEREF_REG_PR-1, DEREF_REG_PR-1+16); } /* * Set up registers for signal handler. * All edited pointers are subject to NEFF. */ regs->regs[REG_SP] = (unsigned long) frame; regs->regs[REG_SP] = (regs->regs[REG_SP] & NEFF_SIGN) ? (regs->regs[REG_SP] | NEFF_MASK) : regs->regs[REG_SP]; regs->regs[REG_ARG1] = signal; /* Arg for signal handler */ regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->sc; regs->pc = (unsigned long) ka->sa.sa_handler; regs->pc = (regs->pc & NEFF_SIGN) ? (regs->pc | NEFF_MASK) : regs->pc; set_fs(USER_DS);#if DEBUG_SIG /* Broken %016Lx */ printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n", signal, current->comm, current->pid, frame, regs->pc >> 32, regs->pc & 0xffffffff, DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);#endif return;give_sigsegv: if (sig == SIGSEGV) ka->sa.sa_handler = SIG_DFL; force_sig(SIGSEGV, current);}static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *set, struct pt_regs *regs){ struct rt_sigframe *frame; int err = 0; int signal; frame = get_sigframe(ka, regs->regs[REG_SP], sizeof(*frame)); if (!access_ok(VERIFY_WRITE, frame, sizeof(*frame))) goto give_sigsegv; signal = current->exec_domain && current->exec_domain->signal_invmap && sig < 32 ? current->exec_domain->signal_invmap[sig] : sig; err |= __put_user(&frame->info, &frame->pinfo); err |= __put_user(&frame->uc, &frame->puc); err |= copy_siginfo_to_user(&frame->info, info); /* Give up earlier as i386, in case */ if (err) goto give_sigsegv; /* Create the ucontext. */ err |= __put_user(0, &frame->uc.uc_flags); err |= __put_user(0, &frame->uc.uc_link); err |= __put_user((void *)current->sas_ss_sp, &frame->uc.uc_stack.ss_sp); err |= __put_user(sas_ss_flags(regs->regs[REG_SP]), &frame->uc.uc_stack.ss_flags); err |= __put_user(current->sas_ss_size, &frame->uc.uc_stack.ss_size); err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0]); err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); /* Give up earlier as i386, in case */ if (err) goto give_sigsegv; /* Set up to return from userspace. If provided, use a stub already in userspace. */ if (ka->sa.sa_flags & SA_RESTORER) { DEREF_REG_PR = (unsigned long) ka->sa.sa_restorer | 0x1; /* * On SH5 all edited pointers are subject to NEFF */ DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; } else { /* * Different approach on SH5. * . Endianness independent asm code gets placed in entry.S . * This is limited to four ASM instructions corresponding * to two long longs in size. * . err checking is done on the else branch only * . flush_icache_range() is called upon __put_user() only * . all edited pointers are subject to NEFF * . being code, linker turns ShMedia bit on, always * dereference index -1. */ DEREF_REG_PR = (unsigned long) frame->retcode | 0x01; DEREF_REG_PR = (DEREF_REG_PR & NEFF_SIGN) ? (DEREF_REG_PR | NEFF_MASK) : DEREF_REG_PR; if (__copy_to_user(frame->retcode, (unsigned long long)sa_default_rt_restorer & (~1), 16) != 0) goto give_sigsegv; flush_icache_range(DEREF_REG_PR-1, DEREF_REG_PR-1+15); } /* * Set up registers for signal handler. * All edited pointers are subject to NEFF. */ regs->regs[REG_SP] = (unsigned long) frame; regs->regs[REG_SP] = (regs->regs[REG_SP] & NEFF_SIGN) ? (regs->regs[REG_SP] | NEFF_MASK) : regs->regs[REG_SP]; regs->regs[REG_ARG1] = signal; /* Arg for signal handler */ regs->regs[REG_ARG2] = (unsigned long long)(unsigned long)(signed long)&frame->uc.uc_mcontext; regs->pc = (unsigned long) ka->sa.sa_handler; regs->pc = (regs->pc & NEFF_SIGN) ? (regs->pc | NEFF_MASK) : regs->pc; set_fs(USER_DS);#if DEBUG_SIG /* Broken %016Lx */ printk("SIG deliver (#%d,%s:%d): sp=%p pc=%08Lx%08Lx link=%08Lx%08Lx\n", signal, current->comm, current->pid, frame, regs->pc >> 32, regs->pc & 0xffffffff, DEREF_REG_PR >> 32, DEREF_REG_PR & 0xffffffff);#endif return;give_sigsegv: if (sig == SIGSEGV) ka->sa.sa_handler = SIG_DFL; force_sig(SIGSEGV, current);}/* * OK, we're invoking a handler */ static voidhandle_signal(unsigned long sig, struct k_sigaction *ka, siginfo_t *info, sigset_t *oldset, struct pt_regs * regs){ /* Are we from a system call? */ if (regs->syscall_nr >= 0) { /* If so, check system call restarting.. */ switch (regs->regs[REG_RET]) { case -ERESTARTNOHAND: regs->regs[REG_RET] = -EINTR; break; case -ERESTARTSYS: if (!(ka->sa.sa_flags & SA_RESTART)) { regs->regs[REG_RET] = -EINTR; break; } /* fallthrough */ case -ERESTARTNOINTR: /* Decode syscall # */ regs->regs[REG_RET] = regs->syscall_nr; regs->pc -= 4; } } /* Set up the stack frame */ if (ka->sa.sa_flags & SA_SIGINFO) setup_rt_frame(sig, ka, info, oldset, regs); else setup_frame(sig, ka, oldset, regs); if (ka->sa.sa_flags & SA_ONESHOT) ka->sa.sa_handler = SIG_DFL; if (!(ka->sa.sa_flags & SA_NODEFER)) { spin_lock_irq(¤t->sigmask_lock); sigorsets(¤t->blocked,¤t->blocked,&ka->sa.sa_mask); sigaddset(¤t->blocked,sig); recalc_sigpending(current); spin_unlock_irq(¤t->sigmask_lock); }}/* * Note that 'init' is a special process: it doesn't get signals it doesn't * want to handle. Thus you cannot kill init even with a SIGKILL even by * mistake. * * Note that we go through the signals twice: once to check the signals that * the kernel can handle, and then we build all the user-level signal handling * stack-frames in one go after that. */int do_signal(struct pt_regs *regs, sigset_t *oldset){ siginfo_t info; struct k_sigaction *ka; /* * 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 (!oldset) oldset = ¤t->blocked; for (;;) { unsigned long signr; spin_lock_irq(¤t->sigmask_lock); signr = dequeue_signal(¤t->blocked, &info); spin_unlock_irq(¤t->sigmask_lock); if (!signr) break; if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) { /* Let the debugger run. */ current->exit_code = signr; current->state = TASK_STOPPED; notify_parent(current, SIGCHLD); schedule(); /* We're back. Did the debugger cancel the sig? */ if (!(signr = current->exit_code)) continue; current->exit_code = 0; /* The debugger continued. Ignore SIGSTOP. */ if (signr == SIGSTOP) continue; /* Update the siginfo structure. Is this good? */ if (signr != info.si_signo) { info.si_signo = signr; info.si_errno = 0; info.si_code = SI_USER; info.si_pid = current->p_pptr->pid; info.si_uid = current->p_pptr->uid; } /* If the (new) signal is now blocked, requeue it. */ if (sigismember(¤t->blocked, signr)) { send_sig_info(signr, &info, current); continue; } } ka = ¤t->sig->action[signr-1]; if (ka->sa.sa_handler == SIG_IGN) { if (signr != SIGCHLD) continue; /* Check for SIGCHLD: it's special. */ while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0) /* nothing */; continue; } if (ka->sa.sa_handler == SIG_DFL) { int exit_code = signr; /* Init gets no signals it doesn't want. */ if (current->pid == 1) continue; switch (signr) { case SIGCONT: case SIGCHLD: case SIGWINCH: continue; case SIGTSTP: case SIGTTIN: case SIGTTOU: if (is_orphaned_pgrp(current->pgrp)) continue; /* FALLTHRU */ case SIGSTOP: current->state = TASK_STOPPED; current->exit_code = signr; if (!(current->p_pptr->sig->action[SIGCHLD-1].sa.sa_flags & SA_NOCLDSTOP)) notify_parent(current, SIGCHLD); schedule(); continue; case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: case SIGSYS: case SIGXCPU: case SIGXFSZ: if (do_coredump(signr, regs)) exit_code |= 0x80; /* FALLTHRU */ default: sig_exit(signr, exit_code, &info); /* NOTREACHED */ } } /* Whee! Actually deliver the signal. */ handle_signal(signr, ka, &info, oldset, regs); return 1; } /* Did we come from a system call? */ if (regs->syscall_nr >= 0) { /* Restart the system call - no handlers present */ if (regs->regs[REG_RET] == -ERESTARTNOHAND || regs->regs[REG_RET] == -ERESTARTSYS || regs->regs[REG_RET] == -ERESTARTNOINTR) { /* Decode Syscall # */ regs->regs[REG_RET] = regs->syscall_nr; regs->pc -= 4; } } return 0;}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?