Fork me on GitHub

root/kernel/signal.c

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

DEFINITIONS

This source file includes following definitions.
  1. send_sig
  2. issig
  3. psig

   1 /*
   2  * fiwix/kernel/signal.c
   3  *
   4  * Copyright 2018, Jordi Sanfeliu. All rights reserved.
   5  * Distributed under the terms of the Fiwix License.
   6  */
   7 
   8 #include <fiwix/asm.h>
   9 #include <fiwix/kernel.h>
  10 #include <fiwix/errno.h>
  11 #include <fiwix/process.h>
  12 #include <fiwix/signal.h>
  13 #include <fiwix/sigcontext.h>
  14 #include <fiwix/sleep.h>
  15 #include <fiwix/sched.h>
  16 #include <fiwix/syscalls.h>
  17 #include <fiwix/mm.h>
  18 #include <fiwix/stdio.h>
  19 #include <fiwix/string.h>
  20 
  21 int send_sig(struct proc *p, __sigset_t signum)
  22 {
  23         struct proc *z;
  24 
  25         if(signum > NSIG || !p) {
  26                 return -EINVAL;
  27         }
  28 
  29         if(!IS_SUPERUSER && current->euid != p->euid && current->sid != p->sid) {
  30                 return -EPERM;
  31         }
  32 
  33         /* kernel processes can't receive signals */
  34         if(p->flags & PF_KPROC) {
  35                 return 0;
  36         }
  37 
  38         switch(signum) {
  39                 case 0:
  40                         return 0;
  41                 case SIGKILL:
  42                 case SIGCONT:
  43                         if(p->state == PROC_STOPPED) {
  44                                 p->state = PROC_RUNNING;
  45                         }
  46                         /* discard all pending stop signals */
  47                         p->sigpending &= SIG_MASK(SIGSTOP);
  48                         p->sigpending &= SIG_MASK(SIGTSTP);
  49                         p->sigpending &= SIG_MASK(SIGTTIN);
  50                         p->sigpending &= SIG_MASK(SIGTTOU);
  51                         break;
  52                 case SIGSTOP:
  53                 case SIGTSTP:
  54                 case SIGTTIN:
  55                 case SIGTTOU:
  56                         /* discard all pending SIGCONT signals */
  57                         p->sigpending &= SIG_MASK(SIGCONT);
  58                         break;
  59                 default:
  60                         break;
  61         }
  62 
  63         /*
  64          * Force some signals, that a process cannot ignore, by changing its
  65          * signal disposition to SIG_DFL.
  66          */
  67         switch(signum) {
  68                 case SIGFPE:
  69                 case SIGSEGV:
  70                         if(p->sigaction[signum - 1].sa_handler == SIG_IGN) {
  71                                 p->sigaction[signum - 1].sa_handler = SIG_DFL;
  72                         }
  73                         break;
  74         }
  75 
  76         if(p->sigaction[signum - 1].sa_handler == SIG_IGN && signum != SIGCHLD) {
  77                 return 0;
  78         }
  79 
  80         /* SIGCHLD is ignored by default */
  81         if(p->sigaction[signum - 1].sa_handler == SIG_DFL) {
  82                 /*
  83                  * INIT process is special, it only gets signals that have the
  84                  * signal handler installed. This avoids to bring down the
  85                  * system accidentally.
  86                  */
  87                 if(p->pid == INIT) {
  88                         return 0;
  89                 }
  90                 if(signum == SIGCHLD) {
  91                         return 0;
  92                 }
  93         }
  94 
  95         /* if SIGCHLD is ignored reap its children (prevent zombies) */
  96         if(p->sigaction[signum - 1].sa_handler == SIG_IGN) {
  97                 if(signum == SIGCHLD) {
  98                         while((z = get_next_zombie(p))) {
  99                                 remove_zombie(z);
 100                         }
 101                         return 0;
 102                 }
 103         }
 104 
 105         p->sigpending |= 1 << (signum - 1);
 106         p->usage.ru_nsignals++;
 107 
 108         /* wake up the process only if that signal is not blocked */
 109         if(!(p->sigblocked & (1 << (signum - 1)))) {
 110                 wakeup_proc(p);
 111         }
 112 
 113         return 0;
 114 }
 115 
 116 int issig(void)
 117 {
 118         __sigset_t signum;
 119         unsigned int mask;
 120         struct proc *p;
 121 
 122         if(!(current->sigpending & ~current->sigblocked)) {
 123                 return 0;
 124         }
 125 
 126         for(signum = 1, mask = 1; signum < NSIG; signum++, mask <<= 1) {
 127                 if(current->sigpending & mask) {
 128                         if(signum == SIGCHLD) {
 129                                 if(current->sigaction[signum - 1].sa_handler == SIG_IGN) {
 130                                         /* this process ignores SIGCHLD */
 131                                         while((p = get_next_zombie(current))) {
 132                                                 remove_zombie(p);
 133                                         }
 134                                 } else {
 135                                         if(current->sigaction[signum - 1].sa_handler != SIG_DFL) {
 136                                                 return signum;
 137                                         }
 138                                 }
 139                         } else {
 140                                 if(current->sigaction[signum - 1].sa_handler != SIG_IGN) {
 141                                         return signum;
 142                                 }
 143                         }
 144                         current->sigpending &= ~mask;
 145                 }
 146         }
 147         return 0;
 148 }
 149 
 150 void psig(unsigned int stack)
 151 {
 152         int len;
 153         __sigset_t signum;
 154         unsigned int mask;
 155         struct sigcontext *sc;
 156 
 157         sc = (struct sigcontext *)stack;
 158         for(signum = 1, mask = 1; signum < NSIG; signum++, mask <<= 1) {
 159                 if(current->sigpending & mask) {
 160                         current->sigpending &= ~mask;
 161 
 162                         if((unsigned int)current->sigaction[signum - 1].sa_handler) {
 163                                 current->sigexecuting = mask;
 164                                 if(!(current->sigaction[signum - 1].sa_flags & SA_NODEFER)) {
 165                                         current->sigblocked |= mask;
 166                                 }
 167 
 168                                 /* save the current sigcontext */
 169                                 memcpy_b(&current->sc[signum - 1], sc, sizeof(struct sigcontext));
 170                                 /* setup the jump to the user signal handler */
 171                                 len = ((int)end_sighandler_trampoline - (int)sighandler_trampoline);
 172                                 sc->oldesp -= len;
 173                                 sc->oldesp -= 4;
 174                                 sc->oldesp &= ~3;       /* round up */
 175                                 memcpy_b((void *)sc->oldesp, sighandler_trampoline, len);
 176                                 sc->ecx = (unsigned int)current->sigaction[signum - 1].sa_handler;
 177                                 sc->eax= signum;
 178                                 sc->eip = sc->oldesp;
 179 
 180                                 if(current->sigaction[signum - 1].sa_flags & SA_RESETHAND) {
 181                                         current->sigaction[signum - 1].sa_handler = SIG_DFL;
 182                                 }
 183                                 return;
 184                         }
 185                         if(current->sigaction[signum - 1].sa_handler == SIG_DFL) {
 186                                 switch(signum) {
 187                                         case SIGCONT:
 188                                                 current->state = PROC_RUNNING;
 189                                                 need_resched = 1;
 190                                                 break;
 191                                         case SIGSTOP:
 192                                         case SIGTSTP:
 193                                         case SIGTTIN:
 194                                         case SIGTTOU:
 195                                                 current->exit_code = signum;
 196                                                 current->state = PROC_STOPPED;
 197                                                 if(!(current->sigaction[signum - 1].sa_flags & SA_NOCLDSTOP)) {
 198                                                         send_sig(get_proc_by_pid(current->ppid), SIGCHLD);
 199                                                         /* needed for job control */
 200                                                         wakeup(&sys_wait4);
 201                                                 }
 202                                                 need_resched = 1;
 203                                                 break;
 204                                         case SIGCHLD:
 205                                                 break;
 206                                         default:
 207                                                 do_exit(signum);
 208                                 }
 209                         }
 210                 }
 211         }
 212 
 213         /* coming from a system call that needs to be restarted */
 214         if(sc->err > 0) {
 215                 if(sc->eax == -ERESTART) {
 216                         sc->eax = sc->err;      /* syscall was saved in 'err' */
 217                         sc->eip -= 2;           /* point again to 'int 0x80' */
 218                 }
 219         }
 220 }

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