Welcome to The Fiwix Project
A UNIX-like kernel for the i386 architecture
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(¤t->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 }