📄 signal.c
字号:
/*===========================================================================* * cause_sigalrm * *===========================================================================*/PRIVATE void cause_sigalrm(tp)struct timer *tp;{ int proc_nr; register struct mproc *rmp; proc_nr = tmr_arg(tp)->ta_int; /* get process from timer */ rmp = &mproc[proc_nr]; if ((rmp->mp_flags & (IN_USE | ZOMBIE)) != IN_USE) return; if ((rmp->mp_flags & ALARM_ON) == 0) return; rmp->mp_flags &= ~ALARM_ON; check_sig(rmp->mp_pid, SIGALRM);}/*===========================================================================* * do_pause * *===========================================================================*/PUBLIC int do_pause(){/* Perform the pause() system call. */ mp->mp_flags |= PAUSED; return(SUSPEND);}/*===========================================================================* * sig_proc * *===========================================================================*/PUBLIC void sig_proc(rmp, signo)register struct mproc *rmp; /* pointer to the process to be signaled */int signo; /* signal to send to process (1 to _NSIG) */{/* Send a signal to a process. Check to see if the signal is to be caught, * ignored, tranformed into a message (for system processes) or blocked. * - If the signal is to be transformed into a message, request the KERNEL to * send the target process a system notification with the pending signal as an * argument. * - If the signal is to be caught, request the KERNEL to push a sigcontext * structure and a sigframe structure onto the catcher's stack. Also, KERNEL * will reset the program counter and stack pointer, so that when the process * next runs, it will be executing the signal handler. When the signal handler * returns, sigreturn(2) will be called. Then KERNEL will restore the signal * context from the sigcontext structure. * If there is insufficient stack space, kill the process. */ vir_bytes new_sp; int s; int slot; int sigflags; struct sigmsg sm; slot = (int) (rmp - mproc); if ((rmp->mp_flags & (IN_USE | ZOMBIE)) != IN_USE) { printf("PM: signal %d sent to %s process %d\n", signo, (rmp->mp_flags & ZOMBIE) ? "zombie" : "dead", slot); panic(__FILE__,"", NO_NUM); } if ((rmp->mp_flags & TRACED) && signo != SIGKILL) { /* A traced process has special handling. */ unpause(slot); stop_proc(rmp, signo); /* a signal causes it to stop */ return; } /* Some signals are ignored by default. */ if (sigismember(&rmp->mp_ignore, signo)) { return; } if (sigismember(&rmp->mp_sigmask, signo)) { /* Signal should be blocked. */ sigaddset(&rmp->mp_sigpending, signo); return; }#if ENABLE_SWAP if (rmp->mp_flags & ONSWAP) { /* Process is swapped out, leave signal pending. */ sigaddset(&rmp->mp_sigpending, signo); swap_inqueue(rmp); return; }#endif sigflags = rmp->mp_sigact[signo].sa_flags; if (sigismember(&rmp->mp_catch, signo)) { if (rmp->mp_flags & SIGSUSPENDED) sm.sm_mask = rmp->mp_sigmask2; else sm.sm_mask = rmp->mp_sigmask; sm.sm_signo = signo; sm.sm_sighandler = (vir_bytes) rmp->mp_sigact[signo].sa_handler; sm.sm_sigreturn = rmp->mp_sigreturn; if ((s=get_stack_ptr(slot, &new_sp)) != OK) panic(__FILE__,"couldn't get new stack pointer",s); sm.sm_stkptr = new_sp; /* Make room for the sigcontext and sigframe struct. */ new_sp -= sizeof(struct sigcontext) + 3 * sizeof(char *) + 2 * sizeof(int); if (adjust(rmp, rmp->mp_seg[D].mem_len, new_sp) != OK) goto doterminate; rmp->mp_sigmask |= rmp->mp_sigact[signo].sa_mask; if (sigflags & SA_NODEFER) sigdelset(&rmp->mp_sigmask, signo); else sigaddset(&rmp->mp_sigmask, signo); if (sigflags & SA_RESETHAND) { sigdelset(&rmp->mp_catch, signo); rmp->mp_sigact[signo].sa_handler = SIG_DFL; } if (OK == (s=sys_sigsend(slot, &sm))) { sigdelset(&rmp->mp_sigpending, signo); /* If process is hanging on PAUSE, WAIT, SIGSUSPEND, tty, * pipe, etc., release it. */ unpause(slot); return; } panic(__FILE__, "warning, sys_sigsend failed", s); } else if (sigismember(&rmp->mp_sig2mess, signo)) { if (OK != (s=sys_kill(slot,signo))) panic(__FILE__, "warning, sys_kill failed", s); return; }doterminate: /* Signal should not or cannot be caught. Take default action. */ if (sigismember(&ign_sset, signo)) return; rmp->mp_sigstatus = (char) signo; if (sigismember(&core_sset, signo)) {#if ENABLE_SWAP if (rmp->mp_flags & ONSWAP) { /* Process is swapped out, leave signal pending. */ sigaddset(&rmp->mp_sigpending, signo); swap_inqueue(rmp); return; }#endif /* Switch to the user's FS environment and dump core. */ tell_fs(CHDIR, slot, FALSE, 0); dump_core(rmp); } pm_exit(rmp, 0); /* terminate process */}/*===========================================================================* * check_sig * *===========================================================================*/PUBLIC int check_sig(proc_id, signo)pid_t proc_id; /* pid of proc to sig, or 0 or -1, or -pgrp */int signo; /* signal to send to process (0 to _NSIG) */{/* Check to see if it is possible to send a signal. The signal may have to be * sent to a group of processes. This routine is invoked by the KILL system * call, and also when the kernel catches a DEL or other signal. */ register struct mproc *rmp; int count; /* count # of signals sent */ int error_code; if (signo < 0 || signo > _NSIG) return(EINVAL); /* Return EINVAL for attempts to send SIGKILL to INIT alone. */ if (proc_id == INIT_PID && signo == SIGKILL) return(EINVAL); /* Search the proc table for processes to signal. (See forkexit.c about * pid magic.) */ count = 0; error_code = ESRCH; for (rmp = &mproc[0]; rmp < &mproc[NR_PROCS]; rmp++) { if (!(rmp->mp_flags & IN_USE)) continue; if ((rmp->mp_flags & ZOMBIE) && signo != 0) continue; /* Check for selection. */ if (proc_id > 0 && proc_id != rmp->mp_pid) continue; if (proc_id == 0 && mp->mp_procgrp != rmp->mp_procgrp) continue; if (proc_id == -1 && rmp->mp_pid <= INIT_PID) continue; if (proc_id < -1 && rmp->mp_procgrp != -proc_id) continue; /* Check for permission. */ if (mp->mp_effuid != SUPER_USER && mp->mp_realuid != rmp->mp_realuid && mp->mp_effuid != rmp->mp_realuid && mp->mp_realuid != rmp->mp_effuid && mp->mp_effuid != rmp->mp_effuid) { error_code = EPERM; continue; } count++; if (signo == 0) continue; /* 'sig_proc' will handle the disposition of the signal. The * signal may be caught, blocked, ignored, or cause process * termination, possibly with core dump. */ sig_proc(rmp, signo); if (proc_id > 0) break; /* only one process being signaled */ } /* If the calling process has killed itself, don't reply. */ if ((mp->mp_flags & (IN_USE | ZOMBIE)) != IN_USE) return(SUSPEND); return(count > 0 ? OK : error_code);}/*===========================================================================* * check_pending * *===========================================================================*/PUBLIC void check_pending(rmp)register struct mproc *rmp;{ /* Check to see if any pending signals have been unblocked. The * first such signal found is delivered. * * If multiple pending unmasked signals are found, they will be * delivered sequentially. * * There are several places in this file where the signal mask is * changed. At each such place, check_pending() should be called to * check for newly unblocked signals. */ int i; for (i = 1; i <= _NSIG; i++) { if (sigismember(&rmp->mp_sigpending, i) && !sigismember(&rmp->mp_sigmask, i)) { sigdelset(&rmp->mp_sigpending, i); sig_proc(rmp, i); break; } }}/*===========================================================================* * unpause * *===========================================================================*/PRIVATE void unpause(pro)int pro; /* which process number */{/* A signal is to be sent to a process. If that process is hanging on a * system call, the system call must be terminated with EINTR. Possible * calls are PAUSE, WAIT, READ and WRITE, the latter two for pipes and ttys. * First check if the process is hanging on an PM call. If not, tell FS, * so it can check for READs and WRITEs from pipes, ttys and the like. */ register struct mproc *rmp; rmp = &mproc[pro]; /* Check to see if process is hanging on a PAUSE, WAIT or SIGSUSPEND call. */ if (rmp->mp_flags & (PAUSED | WAITING | SIGSUSPENDED)) { rmp->mp_flags &= ~(PAUSED | WAITING | SIGSUSPENDED); setreply(pro, EINTR); return; } /* Process is not hanging on an PM call. Ask FS to take a look. */ tell_fs(UNPAUSE, pro, 0, 0);}/*===========================================================================* * dump_core * *===========================================================================*/PRIVATE void dump_core(rmp)register struct mproc *rmp; /* whose core is to be dumped */{/* Make a core dump on the file "core", if possible. */ int s, fd, seg, slot; vir_bytes current_sp; long trace_data, trace_off; slot = (int) (rmp - mproc); /* Can core file be written? We are operating in the user's FS environment, * so no special permission checks are needed. */ if (rmp->mp_realuid != rmp->mp_effuid) return; if ( (fd = open(core_name, O_WRONLY | O_CREAT | O_TRUNC | O_NONBLOCK, CORE_MODE)) < 0) return; rmp->mp_sigstatus |= DUMPED; /* Make sure the stack segment is up to date. * We don't want adjust() to fail unless current_sp is preposterous, * but it might fail due to safety checking. Also, we don't really want * the adjust() for sending a signal to fail due to safety checking. * Maybe make SAFETY_BYTES a parameter. */ if ((s=get_stack_ptr(slot, ¤t_sp)) != OK) panic(__FILE__,"couldn't get new stack pointer",s); adjust(rmp, rmp->mp_seg[D].mem_len, current_sp); /* Write the memory map of all segments to begin the core file. */ if (write(fd, (char *) rmp->mp_seg, (unsigned) sizeof rmp->mp_seg) != (unsigned) sizeof rmp->mp_seg) { close(fd); return; } /* Write out the whole kernel process table entry to get the regs. */ trace_off = 0; while (sys_trace(T_GETUSER, slot, trace_off, &trace_data) == OK) { if (write(fd, (char *) &trace_data, (unsigned) sizeof (long)) != (unsigned) sizeof (long)) { close(fd); return; } trace_off += sizeof (long); } /* Loop through segments and write the segments themselves out. */ for (seg = 0; seg < NR_LOCAL_SEGS; seg++) { rw_seg(1, fd, slot, seg, (phys_bytes) rmp->mp_seg[seg].mem_len << CLICK_SHIFT); } close(fd);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -