root/kernel/signal.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. sys_sgetmask
  2. sys_ssetmask
  3. sys_sigpending
  4. sys_sigsuspend
  5. save_old
  6. get_new
  7. sys_signal
  8. sys_sigaction
  9. core_dump
  10. do_signal

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

/* [previous][next][first][last][top][bottom][index][help] */