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

📄 job.c

📁 早期freebsd实现
💻 C
📖 第 1 页 / 共 5 页
字号:
    GNode          *gn;	    	    /* The target whose commands need				     * verifying */    void    	  (*abortProc) __P((const char *, ...));   			/* Function to abort with message */{    if (OP_NOP(gn->type) && Lst_IsEmpty (gn->commands) &&	(gn->type & OP_LIB) == 0) {	/*	 * No commands. Look for .DEFAULT rule from which we might infer	 * commands 	 */	if ((DEFAULT != NILGNODE) && !Lst_IsEmpty(DEFAULT->commands)) {	    /*	     * Make only looks for a .DEFAULT if the node was never the	     * target of an operator, so that's what we do too. If	     * a .DEFAULT was given, we substitute its commands for gn's	     * commands and set the IMPSRC variable to be the target's name	     * The DEFAULT node acts like a transformation rule, in that	     * gn also inherits any attributes or sources attached to	     * .DEFAULT itself.	     */	    Make_HandleUse(DEFAULT, gn);	    Var_Set (IMPSRC, Var_Value (TARGET, gn), gn);	} else if (Dir_MTime (gn) == 0) {	    /*	     * The node wasn't the target of an operator we have no .DEFAULT	     * rule to go on and the target doesn't already exist. There's	     * nothing more we can do for this branch. If the -k flag wasn't	     * given, we stop in our tracks, otherwise we just don't update	     * this node's parents so they never get examined. 	     */	    if (gn->type & OP_OPTIONAL) {		printf ("make: don't know how to make %s (ignored)\n",			gn->name);	    } else if (keepgoing) {		printf ("make: don't know how to make %s (continuing)\n",			gn->name);		return (FALSE);	    } else {		(*abortProc) ("make: don't know how to make %s. Stop",			     gn->name);		return(FALSE);	    }	}    }    return (TRUE);}#ifdef RMT_WILL_WATCH/*- *----------------------------------------------------------------------- * JobLocalInput -- *	Handle a pipe becoming readable. Callback function for Rmt_Watch * * Results: *	None * * Side Effects: *	JobDoOutput is called. *	 *----------------------------------------------------------------------- *//*ARGSUSED*/static voidJobLocalInput(stream, job)    int	    stream; 	/* Stream that's ready (ignored) */    Job	    *job;   	/* Job to which the stream belongs */{    JobDoOutput(job, FALSE);}#endif /* RMT_WILL_WATCH *//*- *----------------------------------------------------------------------- * JobExec -- *	Execute the shell for the given job. Called from JobStart and *	JobRestart. * * Results: *	None. * * Side Effects: *	A shell is executed, outputs is altered and the Job structure added *	to the job table. * *----------------------------------------------------------------------- */static voidJobExec(job, argv)    Job	    	  *job; 	/* Job to execute */    char    	  **argv;{    int	    	  cpid;	    	/* ID of new child */        if (DEBUG(JOB)) {	int 	  i;		printf("Running %s %sly\n", job->node->name,	       job->flags&JOB_REMOTE?"remote":"local");	printf("\tCommand: ");	for (i = 0; argv[i] != (char *)NULL; i++) {	    printf("%s ", argv[i]);	}	printf("\n");    }        /*     * Some jobs produce no output and it's disconcerting to have     * no feedback of their running (since they produce no output, the     * banner with their name in it never appears). This is an attempt to     * provide that feedback, even if nothing follows it.     */    if ((lastNode != job->node) && (job->flags & JOB_FIRST) &&	!(job->flags & JOB_SILENT))    {	printf(targFmt, job->node->name);	lastNode = job->node;    }    #ifdef RMT_NO_EXEC    if (job->flags & JOB_REMOTE) {	goto jobExecFinish;    }#endif /* RMT_NO_EXEC */    if ((cpid =  vfork()) == -1) {	Punt ("Cannot fork");    } else if (cpid == 0) {	/*	 * Must duplicate the input stream down to the child's input and	 * reset it to the beginning (again). Since the stream was marked	 * close-on-exec, we must clear that bit in the new input.	 */	(void) dup2(fileno(job->cmdFILE), 0);	fcntl(0, F_SETFD, 0);	lseek(0, 0, L_SET);		if (usePipes) {	    /*	     * Set up the child's output to be routed through the pipe	     * we've created for it.	     */	    (void) dup2 (job->outPipe, 1);	} else {	    /*	     * We're capturing output in a file, so we duplicate the	     * descriptor to the temporary file into the standard	     * output.	     */	    (void) dup2 (job->outFd, 1);	}	/*	 * The output channels are marked close on exec. This bit was	 * duplicated by the dup2 (on some systems), so we have to clear	 * it before routing the shell's error output to the same place as	 * its standard output.	 */	fcntl(1, F_SETFD, 0);	(void) dup2 (1, 2);#ifdef USE_PGRP	/*	 * We want to switch the child into a different process family so	 * we can kill it and all its descendants in one fell swoop,	 * by killing its process family, but not commit suicide.	 */		(void) setpgrp(0, getpid());#endif USE_PGRP	(void) execv (shellPath, argv);	(void) write (2, "Could not execute shell\n",		 sizeof ("Could not execute shell"));	_exit (1);    } else {	job->pid = cpid;	if (usePipes && (job->flags & JOB_FIRST) ) {	    /*	     * The first time a job is run for a node, we set the current	     * position in the buffer to the beginning and mark another	     * stream to watch in the outputs mask	     */	    job->curPos = 0;	    #ifdef RMT_WILL_WATCH	    Rmt_Watch(job->inPipe, JobLocalInput, job);#else	    FD_SET(job->inPipe, &outputs);#endif /* RMT_WILL_WATCH */	}	if (job->flags & JOB_REMOTE) {	    job->rmtID = 0;	} else {	    nLocal += 1;	    /*	     * XXX: Used to not happen if CUSTOMS. Why?	     */	    if (job->cmdFILE != stdout) {		fclose(job->cmdFILE);		job->cmdFILE = NULL;	    }	}    }#ifdef RMT_NO_EXECjobExecFinish:    #endif    /*     * Now the job is actually running, add it to the table.     */    nJobs += 1;    (void)Lst_AtEnd (jobs, (ClientData)job);    if (nJobs == maxJobs) {	jobFull = TRUE;    }}/*- *----------------------------------------------------------------------- * JobMakeArgv -- *	Create the argv needed to execute the shell for a given job. *	 * * Results: * * Side Effects: * *----------------------------------------------------------------------- */static voidJobMakeArgv(job, argv)    Job	    	  *job;    char	  **argv;{    int	    	  argc;    static char	  args[10]; 	/* For merged arguments */        argv[0] = shellName;    argc = 1;    if ((commandShell->exit && (*commandShell->exit != '-')) ||	(commandShell->echo && (*commandShell->echo != '-')))    {	/*	 * At least one of the flags doesn't have a minus before it, so	 * merge them together. Have to do this because the *(&(@*#*&#$#	 * Bourne shell thinks its second argument is a file to source.	 * Grrrr. Note the ten-character limitation on the combined arguments.	 */	(void)sprintf(args, "-%s%s",		      ((job->flags & JOB_IGNERR) ? "" :		       (commandShell->exit ? commandShell->exit : "")),		      ((job->flags & JOB_SILENT) ? "" :		       (commandShell->echo ? commandShell->echo : "")));	if (args[1]) {	    argv[argc] = args;	    argc++;	}    } else {	if (!(job->flags & JOB_IGNERR) && commandShell->exit) {	    argv[argc] = commandShell->exit;	    argc++;	}	if (!(job->flags & JOB_SILENT) && commandShell->echo) {	    argv[argc] = commandShell->echo;	    argc++;	}    }    argv[argc] = (char *)NULL;}/*- *----------------------------------------------------------------------- * JobRestart -- *	Restart a job that stopped for some reason.  * * Results: *	None. * * Side Effects: *	jobFull will be set if the job couldn't be run. * *----------------------------------------------------------------------- */static voidJobRestart(job)    Job 	  *job;    	/* Job to restart */{    if (job->flags & JOB_REMIGRATE) {	if (DEBUG(JOB)) {	    printf("Remigrating %x\n", job->pid);	}	if (nLocal != maxLocal) {		/*		 * Job cannot be remigrated, but there's room on the local		 * machine, so resume the job and note that another		 * local job has started.		 */		if (DEBUG(JOB)) {		    printf("resuming on local machine\n");	        }		KILL(job->pid, SIGCONT);		nLocal +=1;		job->flags &= ~(JOB_REMIGRATE|JOB_RESUME);	} else {		/*		 * Job cannot be restarted. Mark the table as full and		 * place the job back on the list of stopped jobs.		 */		if (DEBUG(JOB)) {		    printf("holding\n");		}		(void)Lst_AtFront(stoppedJobs, (ClientData)job);		jobFull = TRUE;		if (DEBUG(JOB)) {		    printf("Job queue is full.\n");		}		return;	}		(void)Lst_AtEnd(jobs, (ClientData)job);	nJobs += 1;	if (nJobs == maxJobs) {	    jobFull = TRUE;	    if (DEBUG(JOB)) {		printf("Job queue is full.\n");	    }	}    } else if (job->flags & JOB_RESTART) {	/*	 * Set up the control arguments to the shell. This is based on the	 * flags set earlier for this job. If the JOB_IGNERR flag is clear,	 * the 'exit' flag of the commandShell is used to cause it to exit	 * upon receiving an error. If the JOB_SILENT flag is clear, the	 * 'echo' flag of the commandShell is used to get it to start echoing	 * as soon as it starts processing commands. 	 */	char	  *argv[4];		JobMakeArgv(job, argv);		if (DEBUG(JOB)) {	    printf("Restarting %s...", job->node->name);	}	if (((nLocal >= maxLocal) && ! (job->flags & JOB_SPECIAL))) {		/*		 * Can't be exported and not allowed to run locally -- put it		 * back on the hold queue and mark the table full		 */		if (DEBUG(JOB)) {		    printf("holding\n");		}		(void)Lst_AtFront(stoppedJobs, (ClientData)job);		jobFull = TRUE;		if (DEBUG(JOB)) {		    printf("Job queue is full.\n");		}		return;	} else {		/*		 * Job may be run locally.		 */		if (DEBUG(JOB)) {		    printf("running locally\n");		}		job->flags &= ~JOB_REMOTE;	}	JobExec(job, argv);    } else {	/*	 * The job has stopped and needs to be restarted. Why it stopped,	 * we don't know...	 */	if (DEBUG(JOB)) {	    printf("Resuming %s...", job->node->name);	}	if (((job->flags & JOB_REMOTE) ||	     (nLocal < maxLocal) ||	     (((job->flags & JOB_SPECIAL)) &&	      (maxLocal == 0))) &&	    (nJobs != maxJobs))	{	    /*	     * If the job is remote, it's ok to resume it as long as the	     * maximum concurrency won't be exceeded. If it's local and	     * we haven't reached the local concurrency limit already (or the	     * job must be run locally and maxLocal is 0), it's also ok to	     * resume it.	     */	    Boolean error;	    extern int errno;	    union wait status;	    #ifdef RMT_WANTS_SIGNALS	    if (job->flags & JOB_REMOTE) {		error = !Rmt_Signal(job, SIGCONT);	    } else#endif	/* RMT_WANTS_SIGNALS */		error = (KILL(job->pid, SIGCONT) != 0);	    if (!error) {		/*		 * Make sure the user knows we've continued the beast and		 * actually put the thing in the job table.		 */		job->flags |= JOB_CONTINUING;		status.w_termsig = SIGCONT;		JobFinish(job, status);				job->flags &= ~(JOB_RESUME|JOB_CONTINUING);		if (DEBUG(JOB)) {		    printf("done\n");		}	    } else {		Error("couldn't resume %s: %s",		    job->node->name, strerror(errno));		status.w_status = 0;		status.w_retcode = 1;		JobFinish(job, status);	    }	} else {	    /*	     * Job cannot be restarted. Mark the table as full and	     * place the job back on the list of stopped jobs.	     */	    if (DEBUG(JOB)) {		printf("table full\n");	    }	    (void)Lst_AtFront(stoppedJobs, (ClientData)job);	    jobFull = TRUE;	    if (DEBUG(JOB)) {		printf("Job queue is full.\n");	    }	}    }}/*- *----------------------------------------------------------------------- * JobStart  -- *	Start a target-creation process going for the target described *	by the graph node gn.  * * Results: *	JOB_ERROR if there was an error in the commands, JOB_FINISHED *	if there isn't actually anything left to do for the job and *	JOB_RUNNING if the job has been started. * * Side Effects:

⌨️ 快捷键说明

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