File:  [Early Linux] / linux / kernel / signal.c
Revision 1.1.1.8 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 18:15:15 2018 UTC (2 years, 7 months ago) by root
Branches: linus, MAIN
CVS tags: linux098, HEAD
linux 0.98

    1: /*
    2:  *  linux/kernel/signal.c
    3:  *
    4:  *  Copyright (C) 1991, 1992  Linus Torvalds
    5:  */
    6: 
    7: #include <linux/sched.h>
    8: #include <linux/kernel.h>
    9: #include <linux/signal.h>
   10: #include <linux/errno.h>
   11: #include <linux/wait.h>
   12: #include <linux/ptrace.h>
   13: 
   14: #include <asm/segment.h>
   15: 
   16: extern int core_dump(long signr,struct pt_regs * regs);
   17: 
   18: int sys_sgetmask()
   19: {
   20: 	return current->blocked;
   21: }
   22: 
   23: int sys_ssetmask(int newmask)
   24: {
   25: 	int old=current->blocked;
   26: 
   27: 	current->blocked = newmask & ~(1<<(SIGKILL-1)) & ~(1<<(SIGSTOP-1));
   28: 	return old;
   29: }
   30: 
   31: int sys_sigpending(sigset_t *set)
   32: {
   33:     /* fill in "set" with signals pending but blocked. */
   34:     verify_area(set,4);
   35:     put_fs_long(current->blocked & current->signal, (unsigned long *)set);
   36:     return 0;
   37: }
   38: 
   39: /* atomically swap in the new signal mask, and wait for a signal.
   40:  *
   41:  * we need to play some games with syscall restarting.  We get help
   42:  * from the syscall library interface.  Note that we need to coordinate
   43:  * the calling convention with the libc routine.
   44:  *
   45:  * "set" is just the sigmask as described in 1003.1-1988, 3.3.7.
   46:  * 	It is assumed that sigset_t can be passed as a 32 bit quantity.
   47:  *
   48:  * "restart" holds a restart indication.  If it's non-zero, then we 
   49:  * 	install the old mask, and return normally.  If it's zero, we store 
   50:  * 	the current mask in old_mask and block until a signal comes in.
   51:  */
   52: int sys_sigsuspend(int restart, unsigned long old_mask, unsigned long set)
   53: {
   54:     extern int sys_pause(void);
   55: 
   56:     if (restart) {
   57: 	/* we're restarting */
   58: 	current->blocked = old_mask;
   59: 	return -EINTR;
   60:     }
   61:     /* we're not restarting.  do the work */
   62:     *(&restart) = 1;
   63:     *(&old_mask) = current->blocked;
   64:     current->blocked = set;
   65:     (void) sys_pause();			/* return after a signal arrives */
   66:     return -ERESTARTNOINTR;		/* handle the signal, and come back */
   67: }
   68: 
   69: static inline void save_old(char * from,char * to)
   70: {
   71: 	int i;
   72: 
   73: 	verify_area(to, sizeof(struct sigaction));
   74: 	for (i=0 ; i< sizeof(struct sigaction) ; i++) {
   75: 		put_fs_byte(*from,to);
   76: 		from++;
   77: 		to++;
   78: 	}
   79: }
   80: 
   81: static inline void get_new(char * from,char * to)
   82: {
   83: 	int i;
   84: 
   85: 	for (i=0 ; i< sizeof(struct sigaction) ; i++)
   86: 		*(to++) = get_fs_byte(from++);
   87: }
   88: 
   89: int sys_signal(int signum, long handler, long restorer)
   90: {
   91: 	struct sigaction tmp;
   92: 
   93: 	if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
   94: 		return -EINVAL;
   95: 	tmp.sa_handler = (void (*)(int)) handler;
   96: 	tmp.sa_mask = 0;
   97: 	tmp.sa_flags = SA_ONESHOT | SA_NOMASK | SA_INTERRUPT;
   98: 	tmp.sa_restorer = (void (*)(void)) restorer;
   99: 	handler = (long) current->sigaction[signum-1].sa_handler;
  100: 	current->sigaction[signum-1] = tmp;
  101: 	return handler;
  102: }
  103: 
  104: int sys_sigaction(int signum, const struct sigaction * action,
  105: 	struct sigaction * oldaction)
  106: {
  107: 	struct sigaction tmp;
  108: 
  109: 	if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
  110: 		return -EINVAL;
  111: 	tmp = current->sigaction[signum-1];
  112: 	get_new((char *) action,
  113: 		(char *) (signum-1+current->sigaction));
  114: 	if (oldaction)
  115: 		save_old((char *) &tmp,(char *) oldaction);
  116: 	if (current->sigaction[signum-1].sa_flags & SA_NOMASK)
  117: 		current->sigaction[signum-1].sa_mask = 0;
  118: 	else
  119: 		current->sigaction[signum-1].sa_mask |= (1<<(signum-1));
  120: 	return 0;
  121: }
  122: 
  123: extern int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
  124: 
  125: /*
  126:  * Note that 'init' is a special process: it doesn't get signals it doesn't
  127:  * want to handle. Thus you cannot kill init even with a SIGKILL even by
  128:  * mistake.
  129:  */
  130: int do_signal(long signr,struct pt_regs * regs)
  131: {
  132: 	unsigned long sa_handler;
  133: 	long old_eip = regs->eip;
  134: 	struct sigaction * sa = current->sigaction + signr - 1;
  135: 	int longs;
  136: 	unsigned long * tmp_esp;
  137: 
  138: 	sa_handler = (unsigned long) sa->sa_handler;
  139: 	if ((regs->orig_eax >= 0) &&
  140: 	    ((regs->eax == -ERESTARTSYS) || (regs->eax == -ERESTARTNOINTR))) {
  141: 		if ((sa_handler > 1) && (regs->eax == -ERESTARTSYS) &&
  142: 		    (sa->sa_flags & SA_INTERRUPT))
  143: 			regs->eax = -EINTR;
  144: 		else {
  145: 			regs->eax = regs->orig_eax;
  146: 			regs->eip = old_eip -= 2;
  147: 		}
  148: 	}
  149: 	if (sa_handler==1) {
  150: /* check for SIGCHLD: it's special */
  151: 		if (signr == SIGCHLD)
  152: 			while (sys_waitpid(-1,NULL,WNOHANG) > 0)
  153: 				/* nothing */;
  154: 		return(1);   /* Ignore, see if there are more signals... */
  155: 	}
  156: 	if (!sa_handler) {
  157: 		if (current->pid == 1)
  158: 			return 1;
  159: 		switch (signr) {
  160: 		case SIGCONT:
  161: 		case SIGCHLD:
  162: 		case SIGWINCH:
  163: 			return(1);  /* Ignore, ... */
  164: 
  165: 		case SIGSTOP:
  166: 		case SIGTSTP:
  167: 		case SIGTTIN:
  168: 		case SIGTTOU:
  169: 			current->state = TASK_STOPPED;
  170: 			current->exit_code = signr;
  171: 			if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags & 
  172: 					SA_NOCLDSTOP))
  173: 				send_sig(SIGCHLD, current->p_pptr, 1);			
  174: 			return(1);  /* Reschedule another event */
  175: 
  176: 		case SIGQUIT:
  177: 		case SIGILL:
  178: 		case SIGTRAP:
  179: 		case SIGIOT:
  180: 		case SIGFPE:
  181: 		case SIGSEGV:
  182: 			if (core_dump(signr,regs))
  183: 				signr |= 0x80;
  184: 			/* fall through */
  185: 		default:
  186: 			current->signal |= 1<<((signr & 0x7f)-1);
  187: 			do_exit(signr);
  188: 		}
  189: 	}
  190: 	/*
  191: 	 * OK, we're invoking a handler 
  192: 	 */
  193: 	if (sa->sa_flags & SA_ONESHOT)
  194: 		sa->sa_handler = NULL;
  195: 	regs->eip = sa_handler;
  196: 	longs = (sa->sa_flags & SA_NOMASK)?(7*4):(8*4);
  197: 	regs->esp -= longs;
  198: 	tmp_esp = (unsigned long *) regs->esp;
  199: 	verify_area(tmp_esp,longs);
  200: 	put_fs_long((long) sa->sa_restorer,tmp_esp++);
  201: 	put_fs_long(signr,tmp_esp++);
  202: 	if (!(sa->sa_flags & SA_NOMASK))
  203: 		put_fs_long(current->blocked,tmp_esp++);
  204: 	put_fs_long(regs->eax,tmp_esp++);
  205: 	put_fs_long(regs->ecx,tmp_esp++);
  206: 	put_fs_long(regs->edx,tmp_esp++);
  207: 	put_fs_long(regs->eflags,tmp_esp++);
  208: 	put_fs_long(old_eip,tmp_esp++);
  209: 	current->blocked |= sa->sa_mask;
  210: /* force a supervisor-mode page-in of the signal handler to reduce races */
  211: 	__asm__("testb $0,%%fs:%0"::"m" (*(char *) sa_handler));
  212: 	return(0);		/* Continue, execute handler */
  213: }

unix.superglobalmegacorp.com