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

📄 kern_sig.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 2 页
字号:
 * Send a signal to a  process group.  If checktty is 1, * limit to members which have a controlling terminal. */voidpgsignal(pgrp, signum, checkctty)	struct pgrp *pgrp;	int signum, checkctty;{	register struct proc *p;	if (pgrp)		for (p = pgrp->pg_mem; p != NULL; p = p->p_pgrpnxt)			if (checkctty == 0 || p->p_flag & P_CONTROLT)				psignal(p, signum);}/* * Send a signal caused by a trap to the current process. * If it will be caught immediately, deliver it with correct code. * Otherwise, post it normally. */voidtrapsignal(p, signum, code)	struct proc *p;	register int signum;	u_int code;{	register struct sigacts *ps = p->p_sigacts;	int mask;	mask = sigmask(signum);	if ((p->p_flag & P_TRACED) == 0 && (p->p_sigcatch & mask) != 0 &&	    (p->p_sigmask & mask) == 0) {		p->p_stats->p_ru.ru_nsignals++;#ifdef KTRACE		if (KTRPOINT(p, KTR_PSIG))			ktrpsig(p->p_tracep, signum, ps->ps_sigact[signum], 				p->p_sigmask, code);#endif		sendsig(ps->ps_sigact[signum], signum, p->p_sigmask, code);		p->p_sigmask |= ps->ps_catchmask[signum] | mask;	} else {		ps->ps_code = code;	/* XXX for core dump/debugger */		psignal(p, signum);	}}/* * Send the signal to the process.  If the signal has an action, the action * is usually performed by the target process rather than the caller; we add * the signal to the set of pending signals for the process. * * Exceptions: *   o When a stop signal is sent to a sleeping process that takes the *     default action, the process is stopped without awakening it. *   o SIGCONT restarts stopped processes (or puts them back to sleep) *     regardless of the signal action (eg, blocked or ignored). * * Other ignored signals are discarded immediately. */voidpsignal(p, signum)	register struct proc *p;	register int signum;{	register int s, prop;	register sig_t action;	int mask;	if ((u_int)signum >= NSIG || signum == 0)		panic("psignal signal number");	mask = sigmask(signum);	prop = sigprop[signum];	/*	 * If proc is traced, always give parent a chance.	 */	if (p->p_flag & P_TRACED)		action = SIG_DFL;	else {		/*		 * If the signal is being ignored,		 * then we forget about it immediately.		 * (Note: we don't set SIGCONT in p_sigignore,		 * and if it is set to SIG_IGN,		 * action will be SIG_DFL here.)		 */		if (p->p_sigignore & mask)			return;		if (p->p_sigmask & mask)			action = SIG_HOLD;		else if (p->p_sigcatch & mask)			action = SIG_CATCH;		else			action = SIG_DFL;	}	if (p->p_nice > NZERO && action == SIG_DFL && (prop & SA_KILL) &&	    (p->p_flag & P_TRACED) == 0)		p->p_nice = NZERO;	if (prop & SA_CONT)		p->p_siglist &= ~stopsigmask;	if (prop & SA_STOP) {		/*		 * If sending a tty stop signal to a member of an orphaned		 * process group, discard the signal here if the action		 * is default; don't stop the process below if sleeping,		 * and don't clear any pending SIGCONT.		 */		if (prop & SA_TTYSTOP && p->p_pgrp->pg_jobc == 0 &&		    action == SIG_DFL)		        return;		p->p_siglist &= ~contsigmask;	}	p->p_siglist |= mask;	/*	 * Defer further processing for signals which are held,	 * except that stopped processes must be continued by SIGCONT.	 */	if (action == SIG_HOLD && ((prop & SA_CONT) == 0 || p->p_stat != SSTOP))		return;	s = splhigh();	switch (p->p_stat) {	case SSLEEP:		/*		 * If process is sleeping uninterruptibly		 * we can't interrupt the sleep... the signal will		 * be noticed when the process returns through		 * trap() or syscall().		 */		if ((p->p_flag & P_SINTR) == 0)			goto out;		/*		 * Process is sleeping and traced... make it runnable		 * so it can discover the signal in issignal() and stop		 * for the parent.		 */		if (p->p_flag & P_TRACED)			goto run;		/*		 * If SIGCONT is default (or ignored) and process is		 * asleep, we are finished; the process should not		 * be awakened.		 */		if ((prop & SA_CONT) && action == SIG_DFL) {			p->p_siglist &= ~mask;			goto out;		}		/*		 * When a sleeping process receives a stop		 * signal, process immediately if possible.		 * All other (caught or default) signals		 * cause the process to run.		 */		if (prop & SA_STOP) {			if (action != SIG_DFL)				goto runfast;			/*			 * If a child holding parent blocked,			 * stopping could cause deadlock.			 */			if (p->p_flag & P_PPWAIT)				goto out;			p->p_siglist &= ~mask;			p->p_xstat = signum;			if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0)				psignal(p->p_pptr, SIGCHLD);			stop(p);			goto out;		} else			goto runfast;		/*NOTREACHED*/	case SSTOP:		/*		 * If traced process is already stopped,		 * then no further action is necessary.		 */		if (p->p_flag & P_TRACED)			goto out;		/*		 * Kill signal always sets processes running.		 */		if (signum == SIGKILL)			goto runfast;		if (prop & SA_CONT) {			/*			 * If SIGCONT is default (or ignored), we continue the			 * process but don't leave the signal in p_siglist, as			 * it has no further action.  If SIGCONT is held, we			 * continue the process and leave the signal in			 * p_siglist.  If the process catches SIGCONT, let it			 * handle the signal itself.  If it isn't waiting on			 * an event, then it goes back to run state.			 * Otherwise, process goes back to sleep state.			 */			if (action == SIG_DFL)				p->p_siglist &= ~mask;			if (action == SIG_CATCH)				goto runfast;			if (p->p_wchan == 0)				goto run;			p->p_stat = SSLEEP;			goto out;		}		if (prop & SA_STOP) {			/*			 * Already stopped, don't need to stop again.			 * (If we did the shell could get confused.)			 */			p->p_siglist &= ~mask;		/* take it away */			goto out;		}		/*		 * If process is sleeping interruptibly, then simulate a		 * wakeup so that when it is continued, it will be made		 * runnable and can look at the signal.  But don't make		 * the process runnable, leave it stopped.		 */		if (p->p_wchan && p->p_flag & P_SINTR)			unsleep(p);		goto out;	default:		/*		 * SRUN, SIDL, SZOMB do nothing with the signal,		 * other than kicking ourselves if we are running.		 * It will either never be noticed, or noticed very soon.		 */		if (p == curproc)			signotify(p);		goto out;	}	/*NOTREACHED*/runfast:	/*	 * Raise priority to at least PUSER.	 */	if (p->p_priority > PUSER)		p->p_priority = PUSER;run:	setrunnable(p);out:	splx(s);}/* * If the current process has received a signal (should be caught or cause * termination, should interrupt current syscall), return the signal number. * Stop signals with default action are processed immediately, then cleared; * they aren't returned.  This is checked after each entry to the system for * a syscall or trap (though this can usually be done without calling issignal * by checking the pending signal masks in the CURSIG macro.) The normal call * sequence is * *	while (signum = CURSIG(curproc)) *		postsig(signum); */issignal(p)	register struct proc *p;{	register int signum, mask, prop;	for (;;) {		mask = p->p_siglist & ~p->p_sigmask;		if (p->p_flag & P_PPWAIT)			mask &= ~stopsigmask;		if (mask == 0)	 	/* no signal to send */			return (0);		signum = ffs((long)mask);		mask = sigmask(signum);		prop = sigprop[signum];		/*		 * We should see pending but ignored signals		 * only if P_TRACED was on when they were posted.		 */		if (mask & p->p_sigignore && (p->p_flag & P_TRACED) == 0) {			p->p_siglist &= ~mask;			continue;		}		if (p->p_flag & P_TRACED && (p->p_flag & P_PPWAIT) == 0) {			/*			 * If traced, always stop, and stay			 * stopped until released by the parent.			 */			p->p_xstat = signum;			psignal(p->p_pptr, SIGCHLD);			do {				stop(p);				mi_switch();			} while (!trace_req(p) && p->p_flag & P_TRACED);			/*			 * If the traced bit got turned off, go back up			 * to the top to rescan signals.  This ensures			 * that p_sig* and ps_sigact are consistent.			 */			if ((p->p_flag & P_TRACED) == 0)				continue;			/*			 * If parent wants us to take the signal,			 * then it will leave it in p->p_xstat;			 * otherwise we just look for signals again.			 */			p->p_siglist &= ~mask;	/* clear the old signal */			signum = p->p_xstat;			if (signum == 0)				continue;			/*			 * Put the new signal into p_siglist.  If the			 * signal is being masked, look for other signals.			 */			mask = sigmask(signum);			p->p_siglist |= mask;			if (p->p_sigmask & mask)				continue;		}		/*		 * Decide whether the signal should be returned.		 * Return the signal's number, or fall through		 * to clear it from the pending mask.		 */		switch ((int)p->p_sigacts->ps_sigact[signum]) {		case SIG_DFL:			/*			 * Don't take default actions on system processes.			 */			if (p->p_pid <= 1) {#ifdef DIAGNOSTIC				/*				 * Are you sure you want to ignore SIGSEGV				 * in init? XXX				 */				printf("Process (pid %d) got signal %d\n",					p->p_pid, signum);#endif				break;		/* == ignore */			}			/*			 * If there is a pending stop signal to process			 * with default action, stop here,			 * then clear the signal.  However,			 * if process is member of an orphaned			 * process group, ignore tty stop signals.			 */			if (prop & SA_STOP) {				if (p->p_flag & P_TRACED ||		    		    (p->p_pgrp->pg_jobc == 0 &&				    prop & SA_TTYSTOP))					break;	/* == ignore */				p->p_xstat = signum;				stop(p);				if ((p->p_pptr->p_flag & P_NOCLDSTOP) == 0)					psignal(p->p_pptr, SIGCHLD);				mi_switch();				break;			} else if (prop & SA_IGNORE) {				/*				 * Except for SIGCONT, shouldn't get here.				 * Default action is to ignore; drop it.				 */				break;		/* == ignore */			} else				return (signum);			/*NOTREACHED*/		case SIG_IGN:			/*			 * Masking above should prevent us ever trying			 * to take action on an ignored signal other			 * than SIGCONT, unless process is traced.			 */			if ((prop & SA_CONT) == 0 &&			    (p->p_flag & P_TRACED) == 0)				printf("issignal\n");			break;		/* == ignore */		default:			/*			 * This signal has an action, let			 * postsig() process it.			 */			return (signum);		}		p->p_siglist &= ~mask;		/* take the signal! */	}	/* NOTREACHED */}/* * Put the argument process into the stopped state and notify the parent * via wakeup.  Signals are handled elsewhere.  The process must not be * on the run queue. */stop(p)	register struct proc *p;{	p->p_stat = SSTOP;	p->p_flag &= ~P_WAITED;	wakeup((caddr_t)p->p_pptr);}/* * Take the action for the specified signal * from the current set of pending signals. */voidpostsig(signum)	register int signum;{	register struct proc *p = curproc;	register struct sigacts *ps = p->p_sigacts;	register sig_t action;	int code, mask, returnmask;#ifdef DIAGNOSTIC	if (signum == 0)		panic("postsig");#endif	mask = sigmask(signum);	p->p_siglist &= ~mask;	action = ps->ps_sigact[signum];#ifdef KTRACE	if (KTRPOINT(p, KTR_PSIG))		ktrpsig(p->p_tracep,		    signum, action, ps->ps_flags & SAS_OLDMASK ?		    ps->ps_oldmask : p->p_sigmask, 0);#endif	if (action == SIG_DFL) {		/*		 * Default action, where the default is to kill		 * the process.  (Other cases were ignored above.)		 */		sigexit(p, signum);		/* NOTREACHED */	} else {		/*		 * If we get here, the signal must be caught.		 */#ifdef DIAGNOSTIC		if (action == SIG_IGN || (p->p_sigmask & mask))			panic("postsig action");#endif		/*		 * Set the new mask value and also defer further		 * occurences of this signal.		 *		 * Special case: user has done a sigpause.  Here the		 * current mask is not of interest, but rather the		 * mask from before the sigpause is what we want		 * restored after the signal processing is completed.		 */		(void) splhigh();		if (ps->ps_flags & SAS_OLDMASK) {			returnmask = ps->ps_oldmask;			ps->ps_flags &= ~SAS_OLDMASK;		} else			returnmask = p->p_sigmask;		p->p_sigmask |= ps->ps_catchmask[signum] | mask;		(void) spl0();		p->p_stats->p_ru.ru_nsignals++;		if (ps->ps_sig != signum) {			code = 0;		} else {			code = ps->ps_code;			ps->ps_code = 0;		}		sendsig(action, signum, returnmask, code);	}}/* * Kill the current process for stated reason. */killproc(p, why)	struct proc *p;	char *why;{	log(LOG_ERR, "pid %d was killed: %s\n", p->p_pid, why);	uprintf("sorry, pid %d was killed: %s\n", p->p_pid, why);	psignal(p, SIGKILL);}/* * Force the current process to exit with the specified signal, dumping core * if appropriate.  We bypass the normal tests for masked and caught signals, * allowing unrecoverable failures to terminate the process without changing * signal state.  Mark the accounting record with the signal termination. * If dumping core, save the signal number for the debugger.  Calls exit and * does not return. */sigexit(p, signum)	register struct proc *p;	int signum;{	p->p_acflag |= AXSIG;	if (sigprop[signum] & SA_CORE) {		p->p_sigacts->ps_sig = signum;		if (coredump(p) == 0)			signum |= WCOREFLAG;	}	exit1(p, W_EXITCODE(0, signum));	/* NOTREACHED */}/* * Dump core, into a file named "progname.core", unless the process was * setuid/setgid. */coredump(p)	register struct proc *p;{	register struct vnode *vp;	register struct pcred *pcred = p->p_cred;	register struct ucred *cred = pcred->pc_ucred;	register struct vmspace *vm = p->p_vmspace;	struct nameidata nd;	struct vattr vattr;	int error, error1;	char name[MAXCOMLEN+6];		/* progname.core */	if (pcred->p_svuid != pcred->p_ruid || pcred->p_svgid != pcred->p_rgid)		return (EFAULT);	if (ctob(UPAGES + vm->vm_dsize + vm->vm_ssize) >=	    p->p_rlimit[RLIMIT_CORE].rlim_cur)		return (EFAULT);	sprintf(name, "%s.core", p->p_comm);	NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, name, p);	if (error = vn_open(&nd,	    O_CREAT | FWRITE, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))		return (error);	vp = nd.ni_vp;	/* Don't dump to non-regular files or files with links. */	if (vp->v_type != VREG ||	    VOP_GETATTR(vp, &vattr, cred, p) || vattr.va_nlink != 1) {		error = EFAULT;		goto out;	}	VATTR_NULL(&vattr);	vattr.va_size = 0;	LEASE_CHECK(vp, p, cred, LEASE_WRITE);	VOP_SETATTR(vp, &vattr, cred, p);	p->p_acflag |= ACORE;	bcopy(p, &p->p_addr->u_kproc.kp_proc, sizeof(struct proc));	fill_eproc(p, &p->p_addr->u_kproc.kp_eproc);	error = cpu_coredump(p, vp, cred);	if (error == 0)		error = vn_rdwr(UIO_WRITE, vp, vm->vm_daddr,		    (int)ctob(vm->vm_dsize), (off_t)ctob(UPAGES), UIO_USERSPACE,		    IO_NODELOCKED|IO_UNIT, cred, (int *) NULL, p);	if (error == 0)		error = vn_rdwr(UIO_WRITE, vp,		    (caddr_t) trunc_page(USRSTACK - ctob(vm->vm_ssize)),		    round_page(ctob(vm->vm_ssize)),		    (off_t)ctob(UPAGES) + ctob(vm->vm_dsize), UIO_USERSPACE,		    IO_NODELOCKED|IO_UNIT, cred, (int *) NULL, p);out:	VOP_UNLOCK(vp);	error1 = vn_close(vp, FWRITE, cred, p);	if (error == 0)		error = error1;	return (error);}/* * Nonexistent system call-- signal process (may want to handle it). * Flag error in case process won't see signal immediately (blocked or ignored). */struct nosys_args {	int	dummy;};/* ARGSUSED */nosys(p, args, retval)	struct proc *p;	struct nosys_args *args;	int *retval;{	psignal(p, SIGSYS);	return (EINVAL);}

⌨️ 快捷键说明

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