sh.proc.c

来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 1,167 行 · 第 1/2 页

C
1,167
字号
#ifndef lintstatic char *sccsid = "@(#)sh.proc.c	4.3  (ULTRIX)        11/13/90";#endif/************************************************************************ *                                                                      * *                      Copyright (c) 1988 by                           * *              Digital Equipment Corporation, Maynard, MA              * *                      All rights reserved.                            * *                                                                      * *   This software is furnished under a license and may be used and     * *   copied  only  in accordance with the terms of such license and     * *   with the  inclusion  of  the  above  copyright  notice.   This     * *   software  or  any  other copies thereof may not be provided or     * *   otherwise made available to any other person.  No title to and     * *   ownership of the software is hereby transferred.                   * *                                                                      * *   The information in this software is subject to change  without     * *   notice  and should not be construed as a commitment by Digital     * *   Equipment Corporation.                                             * *                                                                      * *   Digital assumes no responsibility for the use  or  reliability     * *   of its software on equipment which is not supplied by Digital.     * *                                                                      * ************************************************************************//* ------------------------------------------------------------------ *//* | Copyright Unpublished, MIPS Computer Systems, Inc.  All Rights | *//* | Reserved.  This software contains proprietary and confidential | *//* | information of MIPS and its suppliers.  Use, disclosure or     | *//* | reproduction is prohibited without the prior express written   | *//* | consent of MIPS.                                               | *//* ------------------------------------------------------------------ *//* $Header: sh.proc.c,v 1.4 87/04/06 21:00:16 dce Exp $ */#include "sh.h"#include "sh.dir.h"#include "sh.proc.h"#include <sys/wait.h>#include <sys/ioctl.h>/* * C Shell - functions that manage processes, handling hanging, termination * Modification History * * 005 - Bob Fontaine - Mon Oct 22 13:46:48 EDT 1990 *    Fix typo from 003.  Must increment the pointer to the users input *    so that the % sign is not part of the job number. * * 004 - Bob Fontaine - Fri Jun 22 09:53:01 EDT 1990 *	Changed call to internal printf routine to csh_printf to avoid *	 confusion with library routine. * * 003 - Bob Fontaine - Thu Jun 21 10:22:20 EDT 1990 *	pstart routine used to just search for a job in the proc list *	that matched the second digit in the job number entered by the user. *	(ie job 11 would map to job 1).  Fix is to look at the entire  *	string the user entered.  QAR # 957 * * 002 - Gary A. Gaudet - Tue Jan  2 11:56:15 EST 1990 *	added retrun value checks fro ioctl() *	added some (castings) * * 01 Sat Aug 13 15:28:57 EDT 1988, Gary A. Gaudet *	merging mips & ultrix for 8 bit clean and bug fixes */#define BIGINDEX	9	/* largest desirable job index *//* * 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! */pchild(){	register struct process *pp;	register struct process	*fp;	register int pid;	union wait w;	int jobflags;	struct rusage ru;loop:	pid = wait3(&w, ((setintr && intty) ? WNOHANG|WUNTRACED:WNOHANG), &ru);	if (pid <= 0) {		if (errno == EINTR) {			errno = 0;			goto loop;		}		pnoprocesses = pid == -1;		return;	}	for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next)		if (pid == pp->p_pid)			goto found;	goto loop;found:	if (pid == atoi(value("child")))		unsetv("child");	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("time"))			(void) gettimeofday(&pp->p_etime, (struct timezone *)0);		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("time") &&		    fp->p_rusage.ru_utime.tv_sec+fp->p_rusage.ru_stime.tv_sec >=		     atoi(value("time")))			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 */			}/*		else if ((jobflags & (PTIME|PSTOPPED)) == PTIME)				ptprint(fp);*/		} else {			if (jobflags&PNOTIFY || adrof("notify")) {				putchar ('\r' | QUOTE);				putchar ('\n');				(void) pprint(pp, NUMBER|NAME|REASON|NOISEOK);				if ((jobflags&PSTOPPED) == 0)					pflush(pp);			} else {				fp->p_flags |= PNEEDNOTE;				neednote++;			}		}	}	goto loop;}pnote(){	register struct process *pp;	int flags, omask;	neednote = 0;	for (pp = proclist.p_next; pp != PNULL; pp = pp->p_next) {		if (pp->p_flags & PNEEDNOTE) {			omask = sigblock(sigmask(SIGCHLD));			pp->p_flags &= ~PNEEDNOTE;			flags = pprint(pp, NUMBER|NAME|REASON|NOISEOK);			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. */pwait(){	register struct process *fp, *pp;	int omask;	/*	 * Here's where dead procs get flushed.	 */	omask = sigblock(sigmask(SIGCHLD));	for (pp = (fp = &proclist)->p_next; pp != PNULL; pp = (fp = pp)->p_next)		if (pp->p_pid == 0) {			fp->p_next = pp->p_next;			xfree(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((char *)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) */pjwait(pp)	register struct process *pp;{	register struct process *fp;	int jobflags, reason, omask;	while (pp->p_pid != pp->p_jobid)		pp = pp->p_friends;	fp = pp;	do {		if ((fp->p_flags&(PFOREGND|PRUNNING)) == PRUNNING)			csh_printf("BUG: waiting for background job!\n"); /* 004 RNF */	} 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 (;;) {		jobflags = 0;		do			jobflags |= fp->p_flags;		while ((fp = (fp->p_friends)) != pp);		if ((jobflags & PRUNNING) == 0)			break;		sigpause(sigblock(0) &~ sigmask(SIGCHLD));	}	(void) sigsetmask(omask);	if (tpgrp > 0)			/* get tty back */		if (ioctl(FSHTTY, TIOCSPGRP, (char *)&tpgrp)) {	/* 002 - GAG */			Perror ("ioctl");		}	if ((jobflags&(PSIGNALED|PSTOPPED|PTIME)) ||	     !eq(dcwd->di_name, fp->p_cwd->di_name)) {		if (jobflags&PSTOPPED)			csh_printf("\n");			/* 004 RNF */		(void) pprint(pp, AREASON|SHELLDIR);	}	if ((jobflags&(PINTERRUPTED|PSTOPPED)) && setintr &&	    (!gointr || !eq(gointr, "-"))) {		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 | QUOTE : fp->p_reason;	} while ((fp = fp->p_friends) != pp);	set("status", putn(reason));	if (reason && exiterr)		exitstat();	pflush(pp);}/* * dowait - wait for all processes to finish */dowait(){	register struct process *pp;	int 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) {			sigpause(0);			goto loop;		}	(void) sigsetmask(omask);	pjobs = 0;}/* * pflushall - flush all jobs from list (e.g. at fork()) */pflushall(){	register struct process	*pp;	for (pp = proclist.p_next; pp != PNULL; 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. */pflush(pp)	register struct process	*pp;{	register struct process *np;	register int index;	if (pp->p_pid == 0) {		csh_printf("BUG: process flushed twice");	/* 004 RNF */		return;	}	while (pp->p_pid != pp->p_jobid)		pp = pp->p_friends;	pclrcurr(pp);	if (pp == pcurrjob)		pcurrjob = 0;	index = pp->p_index;	np = pp;	do {		np->p_index = np->p_pid = 0;		np->p_flags &= ~PNEEDNOTE;	} while ((np = np->p_friends) != pp);	if (index == pmaxindex) {		for (np = proclist.p_next, index = 0; np; np = np->p_next)			if (np->p_index > index)				index = np->p_index;		pmaxindex = index;	}}/* * pclrcurr - make sure the given job is not the current or previous job; *	pp MUST be the job leader */pclrcurr(pp)	register struct process *pp;{	if (pp == pcurrent)		if (pprevious != PNULL) {			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 << >& >> */char	command[PMAXLEN+4];int	cmdlen;char	*cmdp;/* * palloc - allocate a process structure and fill it up. *	an important assumption is made that the process is running. */palloc(pid, t)	int pid;	register struct command *t;{	register struct process	*pp;	int i;	pp = (struct process *)calloc((unsigned)1, (unsigned)sizeof(struct process));	pp->p_pid = pid;	pp->p_flags = t->t_dflg & FAND ? PRUNNING : PRUNNING|PFOREGND;	if (t->t_dflg & FTIME)		pp->p_flags |= PPTIME;	cmdp = command;	cmdlen = 0;	padd(t);	*cmdp++ = 0;	if (t->t_dflg & FPOU) {		pp->p_flags |= PPOU;		if (t->t_dflg & FDIAG)			pp->p_flags |= PDIAG;	}	pp->p_command = savestr(command);	if (pcurrjob) {		struct process *fp;		/* careful here with interrupt level */		pp->p_cwd = 0;		pp->p_index = pcurrjob->p_index;		pp->p_friends = pcurrjob;		pp->p_jobid = pcurrjob->p_pid;		for (fp = pcurrjob; fp->p_friends != pcurrjob; fp = fp->p_friends)			;		fp->p_friends = pp;	} else {		pcurrjob = pp;		pp->p_jobid = pid;		pp->p_friends = pp;		pp->p_cwd = dcwd;		dcwd->di_count++;		if (pmaxindex < BIGINDEX)			pp->p_index = ++pmaxindex;		else {			struct process *np;			for (i = 1; ; i++) {				for (np = proclist.p_next; np; np = np->p_next)					if (np->p_index == i)						goto tryagain;				pp->p_index = i;				if (i > pmaxindex)					pmaxindex = i;				break;						tryagain:;			}		}		if (pcurrent == PNULL)			pcurrent = pp;		else if (pprevious == PNULL)			pprevious = pp;	}	pp->p_next = proclist.p_next;	proclist.p_next = pp;	(void) gettimeofday(&pp->p_btime, (struct timezone *)0);}padd(t)	register struct command *t;{	char **argp;	if (t == 0)		return;	switch (t->t_dtyp) {	case TPAR:		pads("( ");		padd(t->t_dspr);		pads(" )");		break;	case TCOM:		for (argp = t->t_dcom; *argp; argp++) {			pads(*argp);			if (argp[1])				pads(" ");		}		break;	case TOR:	case TAND:	case TFIL:	case TLST:		padd(t->t_dcar);		switch (t->t_dtyp) {		case TOR:			pads(" || ");			break;		case TAND:			pads(" && ");			break;		case TFIL:			pads(" | ");			break;		case TLST:			pads("; ");			break;		}		padd(t->t_dcdr);		return;	}	if ((t->t_dflg & FPIN) == 0 && t->t_dlef) {		pads((t->t_dflg & FHERE) ? " << " : " < ");		pads(t->t_dlef);	}	if ((t->t_dflg & FPOU) == 0 && t->t_drit) {		pads((t->t_dflg & FCAT) ? " >>" : " >");		if (t->t_dflg & FDIAG)			pads("&");		pads(" ");		pads(t->t_drit);	}}pads(cp)	char *cp;{	register int i = strlen(cp);	if (cmdlen >= PMAXLEN)		return;	if (cmdlen + i >= PMAXLEN) {		(void) strcpy(cmdp, " ...");		cmdlen = PMAXLEN;		cmdp += 4;		return;	}	(void) strcpy(cmdp, cp);	cmdp += i;	cmdlen += i;}/* * psavejob - temporarily save the current job on a one level stack *	so another job can be created.  Used for { } in exp6 *	and `` in globbing. */psavejob(){	pholdjob = pcurrjob;	pcurrjob = PNULL;}/* * prestjob - opposite of psavejob.  This may be missed if we are interrupted *	somewhere, but pendjob cleans up anyway. */prestjob(){	pcurrjob = pholdjob;	pholdjob = PNULL;}/* * pendjob - indicate that a job (set of commands) has been completed *	or is about to begin. */pendjob(){	register struct process *pp, *tp;	if (pcurrjob && (pcurrjob->p_flags&(PFOREGND|PSTOPPED)) == 0) {		pp = pcurrjob;		while (pp->p_pid != pp->p_jobid)			pp = pp->p_friends;		csh_printf("[%d]", pp->p_index);		/* 004 RNF */		tp = pp;		do {			csh_printf(" %d", pp->p_pid);		/* 004 RNF */			pp = pp->p_friends;		} while (pp != tp);		csh_printf("\n");				/* 004 RNF */	}	pholdjob = pcurrjob = 0;}/* * pprint - print a job */pprint(pp, flag)	register struct process	*pp;{	register status, reason;	struct process *tp;	extern char *linp, linbuf[];	int jobflags, pstatus;	char *format;	while (pp->p_pid != pp->p_jobid)		pp = pp->p_friends;

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?