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

📄 signal.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 2 页
字号:
	   already in userspace.  */	err |= __put_user(in_syscall ? INSN_LDI_R25_1 : INSN_LDI_R25_0,			&frame->tramp[0]);	err |= __put_user(INSN_LDI_R20, &frame->tramp[1]);	err |= __put_user(INSN_BLE_SR2_R0, &frame->tramp[2]);	err |= __put_user(INSN_NOP, &frame->tramp[3]);#if DEBUG_SIG	/* Assert that we're flushing in the correct space... */	{		int sid;		asm ("mfsp %%sr3,%0" : "=r" (sid));		printk("flushing 64 bytes at space %#x offset %p\n",		       sid, frame->tramp);	}#endif#if CACHE_FLUSHING_IS_NOT_BROKEN	flush_icache_range((unsigned long) &frame->tramp[0],			   (unsigned long) &frame->tramp[4]);#else	/* It should *always* be cache line-aligned, but the compiler           sometimes screws up. */	asm volatile("fdc 0(%%sr3,%0)\n\t"		     "fdc %1(%%sr3,%0)\n\t"		     "sync\n\t"		     "fic 0(%%sr3,%0)\n\t"		     "fic %1(%%sr3,%0)\n\t"		     "sync\n\t"		     : : "r" (frame->tramp), "r" (L1_CACHE_BYTES));#endif	rp = (unsigned long) frame->tramp;	if (err)		goto give_sigsegv;#ifdef __LP64__/* Much more has to happen with signals than this -- but it'll at least *//* provide a pointer to some places which definitely need a look. */#define HACK unsigned int#else#define HACK unsigned long#endif	haddr = (HACK) ka->sa.sa_handler;	/* ARGH!  Fucking brain damage.  You don't want to know. */	if (haddr & 2) {		HACK *plabel;		HACK ltp;		plabel = (HACK *) (haddr & ~3);		err |= __get_user(haddr, plabel);		err |= __get_user(ltp, plabel + 1);		if (err)			goto give_sigsegv;		regs->gr[19] = ltp;	}	/* The syscall return path will create IAOQ values from r31.	 */	if (in_syscall)		regs->gr[31] = (HACK) haddr;	else {		regs->iaoq[0] = (HACK) haddr | 3;		regs->iaoq[1] = regs->iaoq[0] + 4;	}	regs->gr[2]  = rp;                /* userland return pointer */	regs->gr[26] = sig;               /* signal number */	regs->gr[25] = (HACK) &frame->info; /* siginfo pointer */	regs->gr[24] = (HACK) &frame->uc;   /* ucontext pointer */#if DEBUG_SIG	printk("making sigreturn frame: %#lx + %#lx = %#lx\n",	       regs->gr[30], PARISC_RT_SIGFRAME_SIZE,	       regs->gr[30] + PARISC_RT_SIGFRAME_SIZE);#endif	/* Raise the user stack pointer to make a proper call frame. */	regs->gr[30] = ((HACK) frame + PARISC_RT_SIGFRAME_SIZE);#if DEBUG_SIG	printk("SIG deliver (%s:%d): frame=0x%p sp=%#lx iaoq=%#lx/%#lx rp=%#lx\n",	       current->comm, current->pid, frame, regs->gr[30],	       regs->iaoq[0], regs->iaoq[1], rp);#endif	return 1;give_sigsegv:#if DEBUG_SIG	printk("fuckup in setup_rt_frame, sending SIGSEGV\n");#endif	if (sig == SIGSEGV)		ka->sa.sa_handler = SIG_DFL;	si.si_signo = SIGSEGV;	si.si_errno = 0;	si.si_code = SI_KERNEL;	si.si_pid = current->pid;	si.si_uid = current->uid;	si.si_addr = frame;	force_sig_info(SIGSEGV, &si, current);	return 0;}/* * OK, we're invoking a handler. */	static longhandle_signal(unsigned long sig, struct k_sigaction *ka,	      siginfo_t *info, sigset_t *oldset,	      struct pt_regs *regs, int in_syscall){#if DEBUG_SIG	printk("handle_signal(sig=%ld, ka=%p, info=%p, oldset=%p, regs=%p)\n",	       sig, ka, info, oldset, regs);#endif	/* Set up the stack frame */	if (!setup_rt_frame(sig, ka, info, oldset, regs, in_syscall))		return 0;	if (ka->sa.sa_flags & SA_ONESHOT)		ka->sa.sa_handler = SIG_DFL;	if (!(ka->sa.sa_flags & SA_NODEFER)) {		spin_lock_irq(&current->sigmask_lock);		sigorsets(&current->blocked,&current->blocked,&ka->sa.sa_mask);		sigaddset(&current->blocked,sig);		recalc_sigpending(current);		spin_unlock_irq(&current->sigmask_lock);	}	return 1;}/* * 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. * * We need to be able to restore the syscall arguments (r21-r26) to * restart syscalls.  Thus, the syscall path should save them in the * pt_regs structure (it's okay to do so since they are caller-save * registers).  As noted below, the syscall number gets restored for * us due to the magic of delayed branching. */asmlinkage intdo_signal(sigset_t *oldset, struct pt_regs *regs, int in_syscall){	siginfo_t info;	struct k_sigaction *ka;#if DEBUG_SIG	printk("do_signal(oldset=0x%p, regs=0x%p, sr7 %#lx, pending %d, in_syscall=%d\n",	       oldset, regs, regs->sr[7], current->sigpending, in_syscall);#endif	/* Everyone else checks to see if they are in kernel mode at	   this point and exits if that's the case.  I'm not sure why	   we would be called in that case, but for some reason we	   are. */	if (!oldset)		oldset = &current->blocked;#if DEBUG_SIG	printk("do_signal: oldset %08lx:%08lx\n", oldset->sig[0], oldset->sig[1]);#endif	for (;;) {		unsigned long signr;		spin_lock_irq(&current->sigmask_lock);		signr = dequeue_signal(&current->blocked, &info);		spin_unlock_irq(&current->sigmask_lock);#if DEBUG_SIG		printk("do_signal: signr=%ld, pid=%d\n", signr, current->pid);#endif		if (!signr)			break;		if ((current->ptrace & PT_PTRACED) && signr != SIGKILL) {			/* Let the debugger run.  */			current->exit_code = signr;			set_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(&current->blocked, signr)) {				send_sig_info(signr, &info, current);				continue;			}		}		ka = &current->sig->action[signr-1];#if DEBUG_SIG		printk("sa_handler is %lx\n", ka->sa.sa_handler);#endif		if ((unsigned long) ka->sa.sa_handler == (unsigned long) SIG_IGN) {			if (signr != SIGCHLD)				continue;			while (sys_wait4(-1, NULL, WNOHANG, NULL) > 0)				/* nothing */;			continue;		}		if ((unsigned long) ka->sa.sa_handler == (unsigned long) 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:				set_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 (signr == SIGQUIT) /* Userspace debugging */					show_regs(regs);				if (do_coredump(signr, regs))					exit_code |= 0x80;				/* FALLTHRU */			default:				lock_kernel();				sigaddset(&current->pending.signal, signr);				recalc_sigpending(current);				current->flags |= PF_SIGNALED;				do_exit(exit_code);				/* NOTREACHED */			}		}		/* Restart a system call if necessary. */		if (in_syscall) {			/* Check the return code */			switch (regs->gr[28]) {			case -ERESTARTNOHAND:#if DEBUG_SIG				printk("ERESTARTNOHAND: returning -EINTR\n");#endif				regs->gr[28] = -EINTR;				break;			case -ERESTARTSYS:				if (!(ka->sa.sa_flags & SA_RESTART)) {#if DEBUG_SIG					printk("ERESTARTSYS: putting -EINTR\n");#endif					regs->gr[28] = -EINTR;					break;				}			/* fallthrough */			case -ERESTARTNOINTR:				/* A syscall is just a branch, so all                                   we have to do is fiddle the return                                   pointer. */				regs->gr[31] -= 8; /* delayed branching */				/* Preserve original r28. */				regs->gr[28] = regs->orig_r28;				break;			}		}		/* Whee!  Actually deliver the signal.  If the		   delivery failed, we need to continue to iterate in		   this loop so we can deliver the SIGSEGV... */		if (handle_signal(signr, ka, &info, oldset, regs, in_syscall)) {#if DEBUG_SIG			printk("Exiting do_signal (success), regs->gr[28] = %ld\n", regs->gr[28]);#endif			return 1;		}	}	/* Did we come from a system call? */	if (in_syscall) {		/* Restart the system call - no handlers present */		if (regs->gr[28] == -ERESTARTNOHAND ||		    regs->gr[28] == -ERESTARTSYS ||		    regs->gr[28] == -ERESTARTNOINTR) {			/* Hooray for delayed branching.  We don't                           have to restore %r20 (the system call                           number) because it gets loaded in the delay                           slot of the branch external instruction. */			regs->gr[31] -= 8;			/* Preserve original r28. */			regs->gr[28] = regs->orig_r28;		}	}#if DEBUG_SIG	printk("Exiting do_signal (not delivered), regs->gr[28] = %ld\n", regs->gr[28]);#endif	return 0;}

⌨️ 快捷键说明

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