⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 signal.c

📁 优龙2410linux2.6.8内核源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
restore_sigmask(sigset_t *set){	sigdelsetmask(set, ~_BLOCKABLE);	spin_lock_irq(&current->sighand->siglock);	current->blocked = *set;	recalc_sigpending();	spin_unlock_irq(&current->sighand->siglock);}/* * Set up a signal frame for a "real-time" signal handler * (one which gets siginfo). */static voidhandle_rt_signal(unsigned long sig, struct k_sigaction *ka,		 siginfo_t *info, sigset_t *oldset, struct pt_regs * regs,		 unsigned long newsp){	struct rt_sigframe __user *rt_sf;	struct mcontext __user *frame;	unsigned long origsp = newsp;	/* Set up Signal Frame */	/* Put a Real Time Context onto stack */	newsp -= sizeof(*rt_sf);	rt_sf = (struct rt_sigframe __user *) newsp;	/* create a stack frame for the caller of the handler */	newsp -= __SIGNAL_FRAMESIZE + 16;	if (verify_area(VERIFY_WRITE, (void __user *) newsp, origsp - newsp))		goto badframe;	/* Put the siginfo & fill in most of the ucontext */	if (copy_siginfo_to_user(&rt_sf->info, info)	    || __put_user(0, &rt_sf->uc.uc_flags)	    || __put_user(0, &rt_sf->uc.uc_link)	    || __put_user(current->sas_ss_sp, &rt_sf->uc.uc_stack.ss_sp)	    || __put_user(sas_ss_flags(regs->gpr[1]),			  &rt_sf->uc.uc_stack.ss_flags)	    || __put_user(current->sas_ss_size, &rt_sf->uc.uc_stack.ss_size)	    || __put_user(&rt_sf->uc.uc_mcontext, &rt_sf->uc.uc_regs)	    || __copy_to_user(&rt_sf->uc.uc_sigmask, oldset, sizeof(*oldset)))		goto badframe;	/* Save user registers on the stack */	frame = &rt_sf->uc.uc_mcontext;	if (save_user_regs(regs, frame, __NR_rt_sigreturn))		goto badframe;	if (put_user(regs->gpr[1], (unsigned long __user *)newsp))		goto badframe;	regs->gpr[1] = newsp;	regs->gpr[3] = sig;	regs->gpr[4] = (unsigned long) &rt_sf->info;	regs->gpr[5] = (unsigned long) &rt_sf->uc;	regs->gpr[6] = (unsigned long) rt_sf;	regs->nip = (unsigned long) ka->sa.sa_handler;	regs->link = (unsigned long) frame->tramp;	regs->trap = 0;	return;badframe:#ifdef DEBUG_SIG	printk("badframe in handle_rt_signal, regs=%p frame=%p newsp=%lx\n",	       regs, frame, newsp);#endif	if (sig == SIGSEGV)		ka->sa.sa_handler = SIG_DFL;	force_sig(SIGSEGV, current);}static int do_setcontext(struct ucontext __user *ucp, struct pt_regs *regs, int sig){	sigset_t set;	struct mcontext __user *mcp;	if (__copy_from_user(&set, &ucp->uc_sigmask, sizeof(set))	    || __get_user(mcp, &ucp->uc_regs))		return -EFAULT;	restore_sigmask(&set);	if (restore_user_regs(regs, mcp, sig))		return -EFAULT;	return 0;}int sys_swapcontext(struct ucontext __user *old_ctx,		    struct ucontext __user *new_ctx,		    int ctx_size, int r6, int r7, int r8, struct pt_regs *regs){	unsigned char tmp;	/* Context size is for future use. Right now, we only make sure	 * we are passed something we understand	 */	if (ctx_size < sizeof(struct ucontext))		return -EINVAL;	if (old_ctx != NULL) {		if (verify_area(VERIFY_WRITE, old_ctx, sizeof(*old_ctx))		    || save_user_regs(regs, &old_ctx->uc_mcontext, 0)		    || __copy_to_user(&old_ctx->uc_sigmask,				      &current->blocked, sizeof(sigset_t))		    || __put_user(&old_ctx->uc_mcontext, &old_ctx->uc_regs))			return -EFAULT;	}	if (new_ctx == NULL)		return 0;	if (verify_area(VERIFY_READ, new_ctx, sizeof(*new_ctx))	    || __get_user(tmp, (u8 __user *) new_ctx)	    || __get_user(tmp, (u8 __user *) (new_ctx + 1) - 1))		return -EFAULT;	/*	 * If we get a fault copying the context into the kernel's	 * image of the user's registers, we can't just return -EFAULT	 * because the user's registers will be corrupted.  For instance	 * the NIP value may have been updated but not some of the	 * other registers.  Given that we have done the verify_area	 * and successfully read the first and last bytes of the region	 * above, this should only happen in an out-of-memory situation	 * or if another thread unmaps the region containing the context.	 * We kill the task with a SIGSEGV in this situation.	 */	if (do_setcontext(new_ctx, regs, 0))		do_exit(SIGSEGV);	sigreturn_exit(regs);	/* doesn't actually return back to here */	return 0;}int sys_rt_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,		     struct pt_regs *regs){	struct rt_sigframe __user *rt_sf;	/* Always make any pending restarted system calls return -EINTR */	current_thread_info()->restart_block.fn = do_no_restart_syscall;	rt_sf = (struct rt_sigframe __user *)		(regs->gpr[1] + __SIGNAL_FRAMESIZE + 16);	if (verify_area(VERIFY_READ, rt_sf, sizeof(struct rt_sigframe)))		goto bad;	if (do_setcontext(&rt_sf->uc, regs, 1))		goto bad;	/*	 * It's not clear whether or why it is desirable to save the	 * sigaltstack setting on signal delivery and restore it on	 * signal return.  But other architectures do this and we have	 * always done it up until now so it is probably better not to	 * change it.  -- paulus	 */	do_sigaltstack(&rt_sf->uc.uc_stack, NULL, regs->gpr[1]);	sigreturn_exit(regs);		/* doesn't return here */	return 0; bad:	force_sig(SIGSEGV, current);	return 0;}/* * 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,	      unsigned long newsp){	struct sigcontext __user *sc;	struct sigregs __user *frame;	unsigned long origsp = newsp;	/* Set up Signal Frame */	newsp -= sizeof(struct sigregs);	frame = (struct sigregs __user *) newsp;	/* Put a sigcontext on the stack */	newsp -= sizeof(*sc);	sc = (struct sigcontext __user *) newsp;	/* create a stack frame for the caller of the handler */	newsp -= __SIGNAL_FRAMESIZE;	if (verify_area(VERIFY_WRITE, (void __user *) newsp, origsp - newsp))		goto badframe;#if _NSIG != 64#error "Please adjust handle_signal()"#endif	if (__put_user((unsigned long) ka->sa.sa_handler, &sc->handler)	    || __put_user(oldset->sig[0], &sc->oldmask)	    || __put_user(oldset->sig[1], &sc->_unused[3])	    || __put_user((struct pt_regs *)frame, &sc->regs)	    || __put_user(sig, &sc->signal))		goto badframe;	if (save_user_regs(regs, &frame->mctx, __NR_sigreturn))		goto badframe;	if (put_user(regs->gpr[1], (unsigned long __user *)newsp))		goto badframe;	regs->gpr[1] = newsp;	regs->gpr[3] = sig;	regs->gpr[4] = (unsigned long) sc;	regs->nip = (unsigned long) ka->sa.sa_handler;	regs->link = (unsigned long) frame->mctx.tramp;	regs->trap = 0;	return;badframe:#ifdef DEBUG_SIG	printk("badframe in handle_signal, regs=%p frame=%p newsp=%lx\n",	       regs, frame, newsp);#endif	if (sig == SIGSEGV)		ka->sa.sa_handler = SIG_DFL;	force_sig(SIGSEGV, current);}/* * Do a signal return; undo the signal stack. */int sys_sigreturn(int r3, int r4, int r5, int r6, int r7, int r8,		  struct pt_regs *regs){	struct sigcontext __user *sc;	struct sigcontext sigctx;	struct mcontext __user *sr;	sigset_t set;	/* Always make any pending restarted system calls return -EINTR */	current_thread_info()->restart_block.fn = do_no_restart_syscall;	sc = (struct sigcontext __user *)(regs->gpr[1] + __SIGNAL_FRAMESIZE);	if (copy_from_user(&sigctx, sc, sizeof(sigctx)))		goto badframe;	set.sig[0] = sigctx.oldmask;	set.sig[1] = sigctx._unused[3];	restore_sigmask(&set);	sr = (struct mcontext __user *) sigctx.regs;	if (verify_area(VERIFY_READ, sr, sizeof(*sr))	    || restore_user_regs(regs, sr, 1))		goto badframe;	sigreturn_exit(regs);		/* doesn't return */	return 0;badframe:	force_sig(SIGSEGV, current);	return 0;}/* * 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. */int do_signal(sigset_t *oldset, struct pt_regs *regs){	siginfo_t info;	struct k_sigaction *ka;	unsigned long frame, newsp;	int signr, ret;	if (!oldset)		oldset = &current->blocked;	newsp = frame = 0;	signr = get_signal_to_deliver(&info, regs, NULL);	ka = (signr == 0)? NULL: &current->sighand->action[signr-1];	if (TRAP(regs) == 0x0C00		/* System Call! */	    && regs->ccr & 0x10000000		/* error signalled */	    && ((ret = regs->gpr[3]) == ERESTARTSYS		|| ret == ERESTARTNOHAND || ret == ERESTARTNOINTR		|| ret == ERESTART_RESTARTBLOCK)) {		if (signr > 0		    && (ret == ERESTARTNOHAND || ret == ERESTART_RESTARTBLOCK			|| (ret == ERESTARTSYS			    && !(ka->sa.sa_flags & SA_RESTART)))) {			/* make the system call return an EINTR error */			regs->result = -EINTR;			regs->gpr[3] = EINTR;			/* note that the cr0.SO bit is already set */		} else {			regs->nip -= 4;	/* Back up & retry system call */			regs->result = 0;			regs->trap = 0;			if (ret == ERESTART_RESTARTBLOCK)				regs->gpr[0] = __NR_restart_syscall;			else				regs->gpr[3] = regs->orig_gpr3;		}	}	if (signr == 0)		return 0;		/* no signals delivered */	if ((ka->sa.sa_flags & SA_ONSTACK) && current->sas_ss_size	    && !on_sig_stack(regs->gpr[1]))		newsp = current->sas_ss_sp + current->sas_ss_size;	else		newsp = regs->gpr[1];	newsp &= ~0xfUL;	/* Whee!  Actually deliver the signal.  */	if (ka->sa.sa_flags & SA_SIGINFO)		handle_rt_signal(signr, ka, &info, oldset, regs, newsp);	else		handle_signal(signr, ka, &info, oldset, regs, newsp);	if (ka->sa.sa_flags & SA_ONESHOT)		ka->sa.sa_handler = SIG_DFL;	if (!(ka->sa.sa_flags & SA_NODEFER)) {		spin_lock_irq(&current->sighand->siglock);		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);		sigaddset(&current->blocked, signr);		recalc_sigpending();		spin_unlock_irq(&current->sighand->siglock);	}	return 1;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -