Annotation of linux/kernel/signal.c, revision 1.1.1.8

1.1       root        1: /*
                      2:  *  linux/kernel/signal.c
                      3:  *
1.1.1.7   root        4:  *  Copyright (C) 1991, 1992  Linus Torvalds
1.1       root        5:  */
                      6: 
                      7: #include <linux/sched.h>
                      8: #include <linux/kernel.h>
1.1.1.7   root        9: #include <linux/signal.h>
                     10: #include <linux/errno.h>
                     11: #include <linux/wait.h>
                     12: #include <linux/ptrace.h>
1.1       root       13: 
1.1.1.7   root       14: #include <asm/segment.h>
1.1.1.5   root       15: 
1.1.1.6   root       16: extern int core_dump(long signr,struct pt_regs * regs);
                     17: 
1.1       root       18: int sys_sgetmask()
                     19: {
                     20:        return current->blocked;
                     21: }
                     22: 
                     23: int sys_ssetmask(int newmask)
                     24: {
                     25:        int old=current->blocked;
                     26: 
1.1.1.3   root       27:        current->blocked = newmask & ~(1<<(SIGKILL-1)) & ~(1<<(SIGSTOP-1));
1.1       root       28:        return old;
                     29: }
                     30: 
1.1.1.3   root       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: 
1.1       root       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: 
1.1.1.3   root       93:        if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
                     94:                return -EINVAL;
1.1       root       95:        tmp.sa_handler = (void (*)(int)) handler;
                     96:        tmp.sa_mask = 0;
1.1.1.6   root       97:        tmp.sa_flags = SA_ONESHOT | SA_NOMASK | SA_INTERRUPT;
1.1       root       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: 
1.1.1.3   root      109:        if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP)
                    110:                return -EINVAL;
1.1       root      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: 
1.1.1.4   root      123: extern int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options);
                    124: 
1.1.1.7   root      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:  */
1.1.1.6   root      130: int do_signal(long signr,struct pt_regs * regs)
1.1       root      131: {
1.1.1.2   root      132:        unsigned long sa_handler;
1.1.1.6   root      133:        long old_eip = regs->eip;
1.1       root      134:        struct sigaction * sa = current->sigaction + signr - 1;
                    135:        int longs;
                    136:        unsigned long * tmp_esp;
                    137: 
1.1.1.6   root      138:        sa_handler = (unsigned long) sa->sa_handler;
1.1.1.8 ! root      139:        if ((regs->orig_eax >= 0) &&
1.1.1.6   root      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;
1.1.1.3   root      144:                else {
1.1.1.6   root      145:                        regs->eax = regs->orig_eax;
                    146:                        regs->eip = old_eip -= 2;
1.1.1.3   root      147:                }
                    148:        }
1.1.1.4   root      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 */;
1.1.1.3   root      154:                return(1);   /* Ignore, see if there are more signals... */
1.1.1.4   root      155:        }
1.1       root      156:        if (!sa_handler) {
1.1.1.7   root      157:                if (current->pid == 1)
                    158:                        return 1;
1.1.1.3   root      159:                switch (signr) {
                    160:                case SIGCONT:
                    161:                case SIGCHLD:
1.1.1.4   root      162:                case SIGWINCH:
1.1.1.3   root      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))
1.1.1.6   root      173:                                send_sig(SIGCHLD, current->p_pptr, 1);                  
1.1.1.3   root      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:
1.1.1.6   root      182:                        if (core_dump(signr,regs))
1.1.1.8 ! root      183:                                signr |= 0x80;
1.1.1.3   root      184:                        /* fall through */
                    185:                default:
1.1.1.8 ! root      186:                        current->signal |= 1<<((signr & 0x7f)-1);
1.1.1.3   root      187:                        do_exit(signr);
                    188:                }
1.1       root      189:        }
1.1.1.3   root      190:        /*
                    191:         * OK, we're invoking a handler 
                    192:         */
1.1       root      193:        if (sa->sa_flags & SA_ONESHOT)
                    194:                sa->sa_handler = NULL;
1.1.1.6   root      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);
1.1       root      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++);
1.1.1.6   root      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++);
1.1       root      208:        put_fs_long(old_eip,tmp_esp++);
                    209:        current->blocked |= sa->sa_mask;
1.1.1.4   root      210: /* force a supervisor-mode page-in of the signal handler to reduce races */
                    211:        __asm__("testb $0,%%fs:%0"::"m" (*(char *) sa_handler));
1.1.1.3   root      212:        return(0);              /* Continue, execute handler */
1.1       root      213: }

unix.superglobalmegacorp.com