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

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