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

📄 signal.c

📁 linux1.1源代码
💻 C
字号:
/* *  linux/kernel/signal.c * *  Copyright (C) 1991, 1992  Linus Torvalds */#include <linux/sched.h>#include <linux/kernel.h>#include <linux/signal.h>#include <linux/errno.h>#include <linux/wait.h>#include <linux/ptrace.h>#include <linux/unistd.h>#include <asm/segment.h>#define _S(nr) (1<<((nr)-1))#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP)))extern int core_dump(long signr,struct pt_regs * regs);asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs);struct sigcontext_struct {	unsigned short gs, __gsh;	unsigned short fs, __fsh;	unsigned short es, __esh;	unsigned short ds, __dsh;	unsigned long edi;	unsigned long esi;	unsigned long ebp;	unsigned long esp;	unsigned long ebx;	unsigned long edx;	unsigned long ecx;	unsigned long eax;	unsigned long trapno;	unsigned long err;	unsigned long eip;	unsigned short cs, __csh;	unsigned long eflags;	unsigned long esp_at_signal;	unsigned short ss, __ssh;	unsigned long i387;	unsigned long oldmask;	unsigned long cr2;};asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset){	sigset_t new_set, old_set = current->blocked;	int error;	if (set) {		error = verify_area(VERIFY_READ, set, sizeof(sigset_t));		if (error)			return error;		new_set = get_fs_long((unsigned long *) set) & _BLOCKABLE;		switch (how) {		case SIG_BLOCK:			current->blocked |= new_set;			break;		case SIG_UNBLOCK:			current->blocked &= ~new_set;			break;		case SIG_SETMASK:			current->blocked = new_set;			break;		default:			return -EINVAL;		}	}	if (oset) {		error = verify_area(VERIFY_WRITE, oset, sizeof(sigset_t));		if (error)			return error;		put_fs_long(old_set, (unsigned long *) oset);	}	return 0;}asmlinkage int sys_sgetmask(void){	return current->blocked;}asmlinkage int sys_ssetmask(int newmask){	int old=current->blocked;	current->blocked = newmask & _BLOCKABLE;	return old;}asmlinkage int sys_sigpending(sigset_t *set){	int error;	/* fill in "set" with signals pending but blocked. */	error = verify_area(VERIFY_WRITE, set, 4);	if (!error)		put_fs_long(current->blocked & current->signal, (unsigned long *)set);	return error;}/* * atomically swap in the new signal mask, and wait for a signal. */asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set){	unsigned long mask;	struct pt_regs * regs = (struct pt_regs *) &restart;	mask = current->blocked;	current->blocked = set & _BLOCKABLE;	regs->eax = -EINTR;	while (1) {		current->state = TASK_INTERRUPTIBLE;		schedule();		if (do_signal(mask,regs))			return -EINTR;	}}/* * POSIX 3.3.1.3: *  "Setting a signal action to SIG_IGN for a signal that is pending *   shall cause the pending signal to be discarded, whether or not *   it is blocked" (but SIGCHLD is unspecified: linux leaves it alone). * *  "Setting a signal action to SIG_DFL for a signal that is pending *   and whose default action is to ignore the signal (for example, *   SIGCHLD), shall cause the pending signal to be discarded, whether *   or not it is blocked" * * Note the silly behaviour of SIGCHLD: SIG_IGN means that the signal * isn't actually ignored, but does automatic child reaping, while * SIG_DFL is explicitly said by POSIX to force the signal to be ignored.. */static void check_pending(int signum){	struct sigaction *p;	p = signum - 1 + current->sigaction;	if (p->sa_handler == SIG_IGN) {		if (signum == SIGCHLD)			return;		current->signal &= ~_S(signum);		return;	}	if (p->sa_handler == SIG_DFL) {		if (signum != SIGCONT && signum != SIGCHLD && signum != SIGWINCH)			return;		current->signal &= ~_S(signum);		return;	}	}asmlinkage int sys_signal(int signum, unsigned long handler){	struct sigaction tmp;	if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)		return -EINVAL;	if (handler >= TASK_SIZE)		return -EFAULT;	tmp.sa_handler = (void (*)(int)) handler;	tmp.sa_mask = 0;	tmp.sa_flags = SA_ONESHOT | SA_NOMASK;	tmp.sa_restorer = NULL;	handler = (long) current->sigaction[signum-1].sa_handler;	current->sigaction[signum-1] = tmp;	check_pending(signum);	return handler;}asmlinkage int sys_sigaction(int signum, const struct sigaction * action,	struct sigaction * oldaction){	struct sigaction new_sa, *p;	if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)		return -EINVAL;	p = signum - 1 + current->sigaction;	if (action) {		int err = verify_area(VERIFY_READ, action, sizeof(*action));		if (err)			return err;		memcpy_fromfs(&new_sa, action, sizeof(struct sigaction));		if (new_sa.sa_flags & SA_NOMASK)			new_sa.sa_mask = 0;		else {			new_sa.sa_mask |= _S(signum);			new_sa.sa_mask &= _BLOCKABLE;		}		if (TASK_SIZE <= (unsigned long) new_sa.sa_handler)			return -EFAULT;	}	if (oldaction) {		int err = verify_area(VERIFY_WRITE, oldaction, sizeof(*oldaction));		if (err)			return err;		memcpy_tofs(oldaction, p, sizeof(struct sigaction));	}	if (action) {		*p = new_sa;		check_pending(signum);	}	return 0;}asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);/* * This sets regs->esp even though we don't actually use sigstacks yet.. */asmlinkage int sys_sigreturn(unsigned long __unused){#define COPY(x) regs->x = context.x#define COPY_SEG(x) \if ((context.x & 0xfffc) && (context.x & 3) != 3) goto badframe; COPY(x);#define COPY_SEG_STRICT(x) \if (!(context.x & 0xfffc) || (context.x & 3) != 3) goto badframe; COPY(x);	struct sigcontext_struct context;	struct pt_regs * regs;	regs = (struct pt_regs *) &__unused;	if (verify_area(VERIFY_READ, (void *) regs->esp, sizeof(context)))		goto badframe;	memcpy_fromfs(&context,(void *) regs->esp, sizeof(context));	current->blocked = context.oldmask & _BLOCKABLE;	COPY_SEG(ds);	COPY_SEG(es);	COPY_SEG(fs);	COPY_SEG(gs);	COPY_SEG_STRICT(ss);	COPY_SEG_STRICT(cs);	COPY(eip);	COPY(ecx); COPY(edx);	COPY(ebx);	COPY(esp); COPY(ebp);	COPY(edi); COPY(esi);	regs->eflags &= ~0xCD5;	regs->eflags |= context.eflags & 0xCD5;	regs->orig_eax = -1;		/* disable syscall checks */	return context.eax;badframe:	do_exit(SIGSEGV);}/* * Set up a signal frame... Make the stack look the way iBCS2 expects * it to look. */static void setup_frame(struct sigaction * sa, unsigned long ** fp, unsigned long eip,	struct pt_regs * regs, int signr, unsigned long oldmask){	unsigned long * frame;#define __CODE ((unsigned long)(frame+24))#define CODE(x) ((unsigned long *) ((x)+__CODE))	frame = *fp;	if (regs->ss != USER_DS)		frame = (unsigned long *) sa->sa_restorer;	frame -= 32;	if (verify_area(VERIFY_WRITE,frame,32*4))		do_exit(SIGSEGV);/* set up the "normal" stack seen by the signal handler (iBCS2) */	put_fs_long(__CODE,frame);	put_fs_long(signr, frame+1);	put_fs_long(regs->gs, frame+2);	put_fs_long(regs->fs, frame+3);	put_fs_long(regs->es, frame+4);	put_fs_long(regs->ds, frame+5);	put_fs_long(regs->edi, frame+6);	put_fs_long(regs->esi, frame+7);	put_fs_long(regs->ebp, frame+8);	put_fs_long((long)*fp, frame+9);	put_fs_long(regs->ebx, frame+10);	put_fs_long(regs->edx, frame+11);	put_fs_long(regs->ecx, frame+12);	put_fs_long(regs->eax, frame+13);	put_fs_long(current->tss.trap_no, frame+14);	put_fs_long(current->tss.error_code, frame+15);	put_fs_long(eip, frame+16);	put_fs_long(regs->cs, frame+17);	put_fs_long(regs->eflags, frame+18);	put_fs_long(regs->esp, frame+19);	put_fs_long(regs->ss, frame+20);	put_fs_long(0,frame+21);		/* 387 state pointer - not implemented*//* non-iBCS2 extensions.. */	put_fs_long(oldmask, frame+22);	put_fs_long(current->tss.cr2, frame+23);/* set up the return code... */	put_fs_long(0x0000b858, CODE(0));	/* popl %eax ; movl $,%eax */	put_fs_long(0x80cd0000, CODE(4));	/* int $0x80 */	put_fs_long(__NR_sigreturn, CODE(2));	*fp = frame;#undef __CODE#undef CODE}/* * 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. */asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs){	unsigned long mask = ~current->blocked;	unsigned long handler_signal = 0;	unsigned long *frame = NULL;	unsigned long eip = 0;	unsigned long signr;	struct sigaction * sa;	while ((signr = current->signal & mask)) {		__asm__("bsf %2,%1\n\t"			"btrl %1,%0"			:"=m" (current->signal),"=r" (signr)			:"1" (signr));		sa = current->sigaction + signr;		signr++;		if ((current->flags & PF_PTRACED) && signr != SIGKILL) {			current->exit_code = signr;			current->state = TASK_STOPPED;			notify_parent(current);			schedule();			if (!(signr = current->exit_code))				continue;			current->exit_code = 0;			if (signr == SIGSTOP)				continue;			if (_S(signr) & current->blocked) {				current->signal |= _S(signr);				continue;			}			sa = current->sigaction + signr - 1;		}		if (sa->sa_handler == SIG_IGN) {			if (signr != SIGCHLD)				continue;			/* check for SIGCHLD: it's special */			while (sys_waitpid(-1,NULL,WNOHANG) > 0)				/* nothing */;			continue;		}		if (sa->sa_handler == SIG_DFL) {			if (current->pid == 1)				continue;			switch (signr) {			case SIGCONT: case SIGCHLD: case SIGWINCH:				continue;			case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU:				if (current->flags & PF_PTRACED)					continue;				current->state = TASK_STOPPED;				current->exit_code = signr;				if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags & 						SA_NOCLDSTOP))					notify_parent(current);				schedule();				continue;			case SIGQUIT: case SIGILL: case SIGTRAP:			case SIGIOT: case SIGFPE: case SIGSEGV:				if (core_dump(signr,regs))					signr |= 0x80;				/* fall through */			default:				current->signal |= _S(signr & 0x7f);				do_exit(signr);			}		}		/*		 * OK, we're invoking a handler		 */		if (regs->orig_eax >= 0) {			if (regs->eax == -ERESTARTNOHAND ||			   (regs->eax == -ERESTARTSYS && !(sa->sa_flags & SA_RESTART)))				regs->eax = -EINTR;		}		handler_signal |= 1 << (signr-1);		mask &= ~sa->sa_mask;	}	if (regs->orig_eax >= 0 &&	    (regs->eax == -ERESTARTNOHAND ||	     regs->eax == -ERESTARTSYS ||	     regs->eax == -ERESTARTNOINTR)) {		regs->eax = regs->orig_eax;		regs->eip -= 2;	}	if (!handler_signal)		/* no handler will be called - return 0 */		return 0;	eip = regs->eip;	frame = (unsigned long *) regs->esp;	signr = 1;	sa = current->sigaction;	for (mask = 1 ; mask ; sa++,signr++,mask += mask) {		if (mask > handler_signal)			break;		if (!(mask & handler_signal))			continue;		setup_frame(sa,&frame,eip,regs,signr,oldmask);		eip = (unsigned long) sa->sa_handler;		if (sa->sa_flags & SA_ONESHOT)			sa->sa_handler = NULL;/* force a supervisor-mode page-in of the signal handler to reduce races */		__asm__("testb $0,%%fs:%0": :"m" (*(char *) eip));		regs->cs = USER_CS; regs->ss = USER_DS;		regs->ds = USER_DS; regs->es = USER_DS;		regs->gs = USER_DS; regs->fs = USER_DS;		current->blocked |= sa->sa_mask;		oldmask |= sa->sa_mask;	}	regs->esp = (unsigned long) frame;	regs->eip = eip;		/* "return" to the first handler */	current->tss.trap_no = current->tss.error_code = 0;	return 1;}

⌨️ 快捷键说明

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