⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 job.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
/* * Copyright (c) 1988, 1989, 1990, 1993 *	The Regents of the University of California.  All rights reserved. * Copyright (c) 1989 by Berkeley Softworks * All rights reserved. * * This code is derived from software contributed to Berkeley by * Adam de Boor. * * 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[] = "@(#)job.c	8.2 (Berkeley) 3/19/94";#endif /* not lint *//*- * job.c -- *	handle the creation etc. of our child processes. * * Interface: *	Job_Make  	    	Start the creation of the given target. * *	Job_CatchChildren   	Check for and handle the termination of any *	    	  	    	children. This must be called reasonably *	    	  	    	frequently to keep the whole make going at *	    	  	    	a decent clip, since job table entries aren't *	    	  	    	removed until their process is caught this way. *	    	  	    	Its single argument is TRUE if the function *	    	  	    	should block waiting for a child to terminate. * *	Job_CatchOutput	    	Print any output our children have produced. *	    	  	    	Should also be called fairly frequently to *	    	  	    	keep the user informed of what's going on. *	    	  	    	If no output is waiting, it will block for *	    	  	    	a time given by the SEL_* constants, below, *	    	  	    	or until output is ready. * *	Job_Init  	    	Called to intialize this module. in addition, *	    	  	    	any commands attached to the .BEGIN target *	    	  	    	are executed before this function returns. *	    	  	    	Hence, the makefile must have been parsed *	    	  	    	before this function is called. * *	Job_Full  	    	Return TRUE if the job table is filled. * *	Job_Empty 	    	Return TRUE if the job table is completely *	    	  	    	empty. * *	Job_ParseShell	    	Given the line following a .SHELL target, parse *	    	  	    	the line as a shell specification. Returns *	    	  	    	FAILURE if the spec was incorrect. * *	Job_End	  	    	Perform any final processing which needs doing. *	    	  	    	This includes the execution of any commands *	    	  	    	which have been/were attached to the .END *	    	  	    	target. It should only be called when the *	    	  	    	job table is empty. * *	Job_AbortAll	    	Abort all currently running jobs. It doesn't *	    	  	    	handle output or do anything for the jobs, *	    	  	    	just kills them. It should only be called in *	    	  	    	an emergency, as it were. * *	Job_CheckCommands   	Verify that the commands for a target are *	    	  	    	ok. Provide them if necessary and possible. * *	Job_Touch 	    	Update a target without really updating it. * *	Job_Wait  	    	Wait for all currently-running jobs to finish. */#include <sys/types.h>#include <sys/stat.h>#include <sys/file.h>#include <sys/time.h>#include <sys/wait.h>#include <errno.h>#include <fcntl.h>#include <signal.h>#include <stdio.h>#include <string.h>#include "make.h"#include "hash.h"#include "dir.h"#include "job.h"#include "pathnames.h"extern int  errno;/* * error handling variables  */static int     	errors = 0;	    /* number of errors reported */static int    	aborting = 0;	    /* why is the make aborting? */#define ABORT_ERROR	1   	    /* Because of an error */#define ABORT_INTERRUPT	2   	    /* Because it was interrupted */#define ABORT_WAIT	3   	    /* Waiting for jobs to finish *//* * post-make command processing. The node postCommands is really just the * .END target but we keep it around to avoid having to search for it * all the time. */static GNode   	  *postCommands;    /* node containing commands to execute when				     * everything else is done */static int     	  numCommands; 	    /* The number of commands actually printed				     * for a target. Should this number be				     * 0, no shell will be executed. *//* * Return values from JobStart. */#define JOB_RUNNING	0   	/* Job is running */#define JOB_ERROR 	1   	/* Error in starting the job */#define JOB_FINISHED	2   	/* The job is already finished */#define JOB_STOPPED	3   	/* The job is stopped *//* * tfile is the name of a file into which all shell commands are put. It is * used over by removing it before the child shell is executed. The XXXXX in * the string are replaced by the pid of the make process in a 5-character * field with leading zeroes.  */static char     tfile[] = TMPPAT;/* * Descriptions for various shells. */static Shell    shells[] = {    /*     * CSH description. The csh can do echo control by playing     * with the setting of the 'echo' shell variable. Sadly,     * however, it is unable to do error control nicely.     */{    "csh",    TRUE, "unset verbose", "set verbose", "unset verbose", 10,    FALSE, "echo \"%s\"\n", "csh -c \"%s || exit 0\"",    "v", "e",},    /*     * SH description. Echo control is also possible and, under     * sun UNIX anyway, one can even control error checking.     */{    "sh",    TRUE, "set -", "set -v", "set -", 5,    FALSE, "echo \"%s\"\n", "sh -c '%s || exit 0'\n",    "v", "e",},    /*     * UNKNOWN.     */{    (char *)0,    FALSE, (char *)0, (char *)0, (char *)0, 0,    FALSE, (char *)0, (char *)0,    (char *)0, (char *)0,}};static Shell 	*commandShell = &shells[DEFSHELL];/* this is the shell to						   * which we pass all						   * commands in the Makefile.						   * It is set by the						   * Job_ParseShell function */static char   	*shellPath = (char *) NULL,	  /* full pathname of						   * executable image */               	*shellName;	      	      	  /* last component of shell */static int  	maxJobs;    	/* The most children we can run at once */static int  	maxLocal;    	/* The most local ones we can have */static int     	nJobs;	    	/* The number of children currently running */static int  	nLocal;    	/* The number of local children */static Lst     	jobs;		/* The structures that describe them */static Boolean	jobFull;    	/* Flag to tell when the job table is full. It				 * is set TRUE when (1) the total number of				 * running jobs equals the maximum allowed or				 * (2) a job can only be run locally, but				 * nLocal equals maxLocal */#ifndef RMT_WILL_WATCHstatic fd_set  	outputs;    	/* Set of descriptors of pipes connected to				 * the output channels of children */#endifstatic GNode   	*lastNode;	/* The node for which output was most recently				 * produced. */static char    	*targFmt;   	/* Format string to use to head output from a				 * job when it's not the most-recent job heard				 * from */#define TARG_FMT  "--- %s ---\n" /* Default format *//* * When JobStart attempts to run a job remotely but can't, and isn't allowed * to run the job locally, or when Job_CatchChildren detects a job that has * been migrated home, the job is placed on the stoppedJobs queue to be run * when the next job finishes.  */static Lst    stoppedJobs;	/* Lst of Job structures describing				 * jobs that were stopped due to concurrency				 * limits or migration home */#if defined(USE_PGRP) && defined(SYSV)#define KILL(pid,sig)	killpg (-(pid),(sig))#else# if defined(USE_PGRP)#define KILL(pid,sig)	killpg ((pid),(sig))# else#define KILL(pid,sig)	kill ((pid),(sig))# endif#endifstatic int JobCondPassSig __P((Job *, int));static void JobPassSig __P((int));static int JobCmpPid __P((Job *, int));static int JobPrintCommand __P((char *, Job *));static int JobSaveCommand __P((char *, GNode *));static void JobFinish __P((Job *, union wait));static void JobExec __P((Job *, char **));static void JobMakeArgv __P((Job *, char **));static void JobRestart __P((Job *));static int JobStart __P((GNode *, int, Job *));static void JobDoOutput __P((Job *, Boolean));static Shell *JobMatchShell __P((char *));static void JobInterrupt __P((int));/*- *----------------------------------------------------------------------- * JobCondPassSig -- *	Pass a signal to a job if the job is remote or if USE_PGRP *	is defined. * * Results: *	=== 0 * * Side Effects: *	None, except the job may bite it. * *----------------------------------------------------------------------- */static intJobCondPassSig(job, signo)    Job	    	*job;	    /* Job to biff */    int	    	signo;	    /* Signal to send it */{#ifdef RMT_WANTS_SIGNALS    if (job->flags & JOB_REMOTE) {	(void)Rmt_Signal(job, signo);    } else {	KILL(job->pid, signo);    }#else    /*     * Assume that sending the signal to job->pid will signal any remote     * job as well.     */    KILL(job->pid, signo);#endif    return(0);}/*- *----------------------------------------------------------------------- * JobPassSig -- *	Pass a signal on to all remote jobs and to all local jobs if *	USE_PGRP is defined, then die ourselves. * * Results: *	None. * * Side Effects: *	We die by the same signal. *	 *----------------------------------------------------------------------- */static voidJobPassSig(signo)    int	    signo;	/* The signal number we've received */{    int	    mask;        Lst_ForEach(jobs, JobCondPassSig, (ClientData)signo);    /*     * Deal with proper cleanup based on the signal received. We only run     * the .INTERRUPT target if the signal was in fact an interrupt. The other     * three termination signals are more of a "get out *now*" command.     */    if (signo == SIGINT) {	JobInterrupt(TRUE);    } else if ((signo == SIGHUP) || (signo == SIGTERM) || (signo == SIGQUIT)) {	JobInterrupt(FALSE);    }        /*     * Leave gracefully if SIGQUIT, rather than core dumping.     */    if (signo == SIGQUIT) {	Finish(0);    }        /*     * Send ourselves the signal now we've given the message to everyone else.     * Note we block everything else possible while we're getting the signal.     * This ensures that all our jobs get continued when we wake up before     * we take any other signal.     */    mask = sigblock(0);    (void) sigsetmask(~0 & ~(1 << (signo-1)));    signal(signo, SIG_DFL);    kill(getpid(), signo);    Lst_ForEach(jobs, JobCondPassSig, (ClientData)SIGCONT);    sigsetmask(mask);    signal(signo, JobPassSig);}/*- *----------------------------------------------------------------------- * JobCmpPid  -- *	Compare the pid of the job with the given pid and return 0 if they *	are equal. This function is called from Job_CatchChildren via *	Lst_Find to find the job descriptor of the finished job. * * Results: *	0 if the pid's match * * Side Effects: *	None *----------------------------------------------------------------------- */static intJobCmpPid (job, pid)    int             pid;	/* process id desired */    Job            *job;	/* job to examine */{    return (pid - job->pid);}/*- *----------------------------------------------------------------------- * JobPrintCommand  -- *	Put out another command for the given job. If the command starts *	with an @ or a - we process it specially. In the former case, *	so long as the -s and -n flags weren't given to make, we stick *	a shell-specific echoOff command in the script. In the latter, *	we ignore errors for the entire job, unless the shell has error *	control. *	If the command is just "..." we take all future commands for this *	job to be commands to be executed once the entire graph has been *	made and return non-zero to signal that the end of the commands *	was reached. These commands are later attached to the postCommands *	node and executed by Job_End when all things are done. *	This function is called from JobStart via Lst_ForEach. * * Results: *	Always 0, unless the command was "..." * * Side Effects: *	If the command begins with a '-' and the shell has no error control, *	the JOB_IGNERR flag is set in the job descriptor. *	If the command is "..." and we're not ignoring such things, *	tailCmds is set to the successor node of the cmd. *	numCommands is incremented if the command is actually printed. *----------------------------------------------------------------------- */static intJobPrintCommand (cmd, job)    char     	  *cmd;	    	    /* command string to print */    Job           *job;	    	    /* job for which to print it */{    Boolean	  noSpecials;	    /* true if we shouldn't worry about				     * inserting special commands into				     * the input stream. */    Boolean       shutUp = FALSE;   /* true if we put a no echo command				     * into the command file */    Boolean	  errOff = FALSE;   /* true if we turned error checking				     * off before printing the command				     * and need to turn it back on */    char       	  *cmdTemplate;	    /* Template to use when printing the				     * command */    char    	  *cmdStart;	    /* Start of expanded command */    LstNode 	  cmdNode;  	    /* Node for replacing the command */    noSpecials = (noExecute && ! (job->node->type & OP_MAKE));    if (strcmp (cmd, "...") == 0) {	job->node->type |= OP_SAVE_CMDS; 	if ((job->flags & JOB_IGNDOTS) == 0) {	    job->tailCmds = Lst_Succ (Lst_Member (job->node->commands,						  (ClientData)cmd));	    return (1);	}	return (0);    }#define DBPRINTF(fmt, arg) if (DEBUG(JOB)) printf (fmt, arg); fprintf (job->cmdFILE, fmt, arg)    numCommands += 1;    /*     * For debugging, we replace each command with the result of expanding     * the variables in the command.     */    cmdNode = Lst_Member (job->node->commands, (ClientData)cmd);    cmdStart = cmd = Var_Subst (NULL, cmd, job->node, FALSE);    Lst_Replace (cmdNode, (ClientData)cmdStart);    cmdTemplate = "%s\n";    /*     * Check for leading @' and -'s to control echoing and error checking.     */    while (*cmd == '@' || *cmd == '-') {	if (*cmd == '@') {	    shutUp = TRUE;

⌨️ 快捷键说明

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