📄 proc.c
字号:
/*- * Copyright (c) 1980, 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char sccsid[] = "@(#)proc.c 8.1 (Berkeley) 5/31/93";#endif /* not lint */#include <sys/types.h>#include <sys/wait.h>#include <errno.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#if __STDC__# include <stdarg.h>#else# include <varargs.h>#endif#include "csh.h"#include "dir.h"#include "proc.h"#include "extern.h"#define BIGINDEX 9 /* largest desirable job index */static struct rusage zru;static void pflushall __P((void));static void pflush __P((struct process *));static void pclrcurr __P((struct process *));static void padd __P((struct command *));static int pprint __P((struct process *, int));static void ptprint __P((struct process *));static void pads __P((Char *));static void pkill __P((Char **v, int));static struct process *pgetcurr __P((struct process *));static void okpcntl __P((void));/* * pchild - called at interrupt level by the SIGCHLD signal * indicating that at least one child has terminated or stopped * thus at least one wait system call will definitely return a * childs status. Top level routines (like pwait) must be sure * to mask interrupts when playing with the proclist data structures! *//* ARGUSED */voidpchild(notused) int notused;{ register struct process *pp; register struct process *fp; register int pid; extern int insource; union wait w; int jobflags; struct rusage ru;loop: errno = 0; /* reset, just in case */ pid = wait3(&w.w_status, (setintr && (intty || insource) ? WNOHANG | WUNTRACED : WNOHANG), &ru); if (pid <= 0) { if (errno == EINTR) { errno = 0; goto loop; } pnoprocesses = pid == -1; return; } for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) if (pid == pp->p_pid) goto found; goto loop;found: if (pid == atoi(short2str(value(STRchild)))) unsetv(STRchild); pp->p_flags &= ~(PRUNNING | PSTOPPED | PREPORTED); if (WIFSTOPPED(w)) { pp->p_flags |= PSTOPPED; pp->p_reason = w.w_stopsig; } else { if (pp->p_flags & (PTIME | PPTIME) || adrof(STRtime)) (void) gettimeofday(&pp->p_etime, NULL); pp->p_rusage = ru; if (WIFSIGNALED(w)) { if (w.w_termsig == SIGINT) pp->p_flags |= PINTERRUPTED; else pp->p_flags |= PSIGNALED; if (w.w_coredump) pp->p_flags |= PDUMPED; pp->p_reason = w.w_termsig; } else { pp->p_reason = w.w_retcode; if (pp->p_reason != 0) pp->p_flags |= PAEXITED; else pp->p_flags |= PNEXITED; } } jobflags = 0; fp = pp; do { if ((fp->p_flags & (PPTIME | PRUNNING | PSTOPPED)) == 0 && !child && adrof(STRtime) && fp->p_rusage.ru_utime.tv_sec + fp->p_rusage.ru_stime.tv_sec >= atoi(short2str(value(STRtime)))) fp->p_flags |= PTIME; jobflags |= fp->p_flags; } while ((fp = fp->p_friends) != pp); pp->p_flags &= ~PFOREGND; if (pp == pp->p_friends && (pp->p_flags & PPTIME)) { pp->p_flags &= ~PPTIME; pp->p_flags |= PTIME; } if ((jobflags & (PRUNNING | PREPORTED)) == 0) { fp = pp; do { if (fp->p_flags & PSTOPPED) fp->p_flags |= PREPORTED; } while ((fp = fp->p_friends) != pp); while (fp->p_pid != fp->p_jobid) fp = fp->p_friends; if (jobflags & PSTOPPED) { if (pcurrent && pcurrent != fp) pprevious = pcurrent; pcurrent = fp; } else pclrcurr(fp); if (jobflags & PFOREGND) { if (jobflags & (PSIGNALED | PSTOPPED | PPTIME) ||#ifdef IIASA jobflags & PAEXITED ||#endif !eq(dcwd->di_name, fp->p_cwd->di_name)) { ; /* print in pjwait */ } /* PWP: print a newline after ^C */ else if (jobflags & PINTERRUPTED) { (void) vis_fputc('\r' | QUOTE, cshout); (void) fputc('\n', cshout); } } else { if (jobflags & PNOTIFY || adrof(STRnotify)) { (void) vis_fputc('\r' | QUOTE, cshout); (void) fputc('\n', cshout); (void) pprint(pp, NUMBER | NAME | REASON); if ((jobflags & PSTOPPED) == 0) pflush(pp); } else { fp->p_flags |= PNEEDNOTE; neednote++; } } } goto loop;}voidpnote(){ register struct process *pp; int flags; sigset_t omask; neednote = 0; for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) { if (pp->p_flags & PNEEDNOTE) { omask = sigblock(sigmask(SIGCHLD)); pp->p_flags &= ~PNEEDNOTE; flags = pprint(pp, NUMBER | NAME | REASON); if ((flags & (PRUNNING | PSTOPPED)) == 0) pflush(pp); (void) sigsetmask(omask); } }}/* * pwait - wait for current job to terminate, maintaining integrity * of current and previous job indicators. */voidpwait(){ register struct process *fp, *pp; sigset_t omask; /* * Here's where dead procs get flushed. */ omask = sigblock(sigmask(SIGCHLD)); for (pp = (fp = &proclist)->p_next; pp != NULL; pp = (fp = pp)->p_next) if (pp->p_pid == 0) { fp->p_next = pp->p_next; xfree((ptr_t) pp->p_command); if (pp->p_cwd && --pp->p_cwd->di_count == 0) if (pp->p_cwd->di_next == 0) dfree(pp->p_cwd); xfree((ptr_t) pp); pp = fp; } (void) sigsetmask(omask); pjwait(pcurrjob);}/* * pjwait - wait for a job to finish or become stopped * It is assumed to be in the foreground state (PFOREGND) */voidpjwait(pp) register struct process *pp;{ register struct process *fp; int jobflags, reason; sigset_t omask; while (pp->p_pid != pp->p_jobid) pp = pp->p_friends; fp = pp; do { if ((fp->p_flags & (PFOREGND | PRUNNING)) == PRUNNING) (void) fprintf(csherr, "BUG: waiting for background job!\n"); } while ((fp = fp->p_friends) != pp); /* * Now keep pausing as long as we are not interrupted (SIGINT), and the * target process, or any of its friends, are running */ fp = pp; omask = sigblock(sigmask(SIGCHLD)); for (;;) { (void) sigblock(sigmask(SIGCHLD)); jobflags = 0; do jobflags |= fp->p_flags; while ((fp = (fp->p_friends)) != pp); if ((jobflags & PRUNNING) == 0) break;#ifdef JOBDEBUG (void) fprintf(csherr, "starting to sigpause for SIGCHLD on %d\n", fp->p_pid);#endif /* JOBDEBUG */ (void) sigpause(omask & ~sigmask(SIGCHLD)); } (void) sigsetmask(omask); if (tpgrp > 0) /* get tty back */ (void) tcsetpgrp(FSHTTY, tpgrp); if ((jobflags & (PSIGNALED | PSTOPPED | PTIME)) || !eq(dcwd->di_name, fp->p_cwd->di_name)) { if (jobflags & PSTOPPED) { (void) fputc('\n', cshout); if (adrof(STRlistjobs)) { Char *jobcommand[3]; jobcommand[0] = STRjobs; if (eq(value(STRlistjobs), STRlong)) jobcommand[1] = STRml; else jobcommand[1] = NULL; jobcommand[2] = NULL; dojobs(jobcommand, NULL); (void) pprint(pp, SHELLDIR); } else (void) pprint(pp, AREASON | SHELLDIR); } else (void) pprint(pp, AREASON | SHELLDIR); } if ((jobflags & (PINTERRUPTED | PSTOPPED)) && setintr && (!gointr || !eq(gointr, STRminus))) { if ((jobflags & PSTOPPED) == 0) pflush(pp); pintr1(0); /* NOTREACHED */ } reason = 0; fp = pp; do { if (fp->p_reason) reason = fp->p_flags & (PSIGNALED | PINTERRUPTED) ? fp->p_reason | META : fp->p_reason; } while ((fp = fp->p_friends) != pp); if ((reason != 0) && (adrof(STRprintexitvalue))) { (void) fprintf(cshout, "Exit %d\n", reason); } set(STRstatus, putn(reason)); if (reason && exiterr) exitstat(); pflush(pp);}/* * dowait - wait for all processes to finish */void/*ARGSUSED*/dowait(v, t) Char **v; struct command *t;{ register struct process *pp; sigset_t omask; pjobs++; omask = sigblock(sigmask(SIGCHLD));loop: for (pp = proclist.p_next; pp; pp = pp->p_next) if (pp->p_pid && /* pp->p_pid == pp->p_jobid && */ pp->p_flags & PRUNNING) { (void) sigpause((sigset_t) 0); goto loop; } (void) sigsetmask(omask); pjobs = 0;}/* * pflushall - flush all jobs from list (e.g. at fork()) */static voidpflushall(){ register struct process *pp; for (pp = proclist.p_next; pp != NULL; pp = pp->p_next) if (pp->p_pid) pflush(pp);}/* * pflush - flag all process structures in the same job as the * the argument process for deletion. The actual free of the * space is not done here since pflush is called at interrupt level. */static voidpflush(pp) register struct process *pp;{ register struct process *np; register int idx; if (pp->p_pid == 0) { (void) fprintf(csherr, "BUG: process flushed twice"); return; } while (pp->p_pid != pp->p_jobid) pp = pp->p_friends; pclrcurr(pp); if (pp == pcurrjob) pcurrjob = 0; idx = pp->p_index; np = pp; do { np->p_index = np->p_pid = 0; np->p_flags &= ~PNEEDNOTE; } while ((np = np->p_friends) != pp); if (idx == pmaxindex) { for (np = proclist.p_next, idx = 0; np; np = np->p_next) if (np->p_index > idx) idx = np->p_index; pmaxindex = idx; }}/* * pclrcurr - make sure the given job is not the current or previous job; * pp MUST be the job leader */static voidpclrcurr(pp) register struct process *pp;{ if (pp == pcurrent) if (pprevious != NULL) { pcurrent = pprevious; pprevious = pgetcurr(pp); } else { pcurrent = pgetcurr(pp); pprevious = pgetcurr(pp); } else if (pp == pprevious) pprevious = pgetcurr(pp);}/* +4 here is 1 for '\0', 1 ea for << >& >> */static Char command[PMAXLEN + 4];static int cmdlen;static Char *cmdp;/* * palloc - allocate a process structure and fill it up. * an important assumption is made that the process is running. */voidpalloc(pid, t) int pid; register struct command *t;{ register struct process *pp; int i; pp = (struct process *) xcalloc(1, (size_t) sizeof(struct process)); pp->p_pid = pid; pp->p_flags = t->t_dflg & F_AMPERSAND ? PRUNNING : PRUNNING | PFOREGND; if (t->t_dflg & F_TIME) pp->p_flags |= PPTIME;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -