Example #1
0
File: make.c Project: aharri/base
/*-
 *-----------------------------------------------------------------------
 * Make_Run --
 *	Initialize the nodes to remake and the list of nodes which are
 *	ready to be made by doing a breadth-first traversal of the graph
 *	starting from the nodes in the given list. Once this traversal
 *	is finished, all the 'leaves' of the graph are in the toBeMade
 *	queue.
 *	Using this queue and the Job module, work back up the graph,
 *	calling on MakeStartJobs to keep the job table as full as
 *	possible.
 *
 * Results:
 *	true if work was done. false otherwise.
 *
 * Side Effects:
 *	The must_make field of all nodes involved in the creation of the given
 *	targets is set to 1. The toBeMade list is set to contain all the
 *	'leaves' of these subgraphs.
 *-----------------------------------------------------------------------
 */
bool
Make_Run(Lst targs)		/* the initial list of targets */
{
	int errors;	/* Number of errors the Job module reports */
	GNode *gn;
	unsigned int i;
	bool cycle;

	/* wild guess at initial sizes */
	Array_Init(&toBeMade, 500);
	Array_Init(&examine, 150);
	ohash_init(&targets, 10, &gnode_info);
	if (DEBUG(PARALLEL))
		random_setup();

	add_targets_to_make(targs);
	if (queryFlag) {
		/*
		 * We wouldn't do any work unless we could start some jobs in
		 * the next loop... (we won't actually start any, of course,
		 * this is just to see if any of the targets was out of date)
		 */
		return MakeStartJobs();
	} else {
		/*
		 * Initialization. At the moment, no jobs are running and until
		 * some get started, nothing will happen since the remaining
		 * upward traversal of the graph is performed by the routines
		 * in job.c upon the finishing of a job. So we fill the Job
		 * table as much as we can before going into our loop.
		 */
		(void)MakeStartJobs();
	}

	/*
	 * Main Loop: The idea here is that the ending of jobs will take
	 * care of the maintenance of data structures and the waiting for output
	 * will cause us to be idle most of the time while our children run as
	 * much as possible. Because the job table is kept as full as possible,
	 * the only time when it will be empty is when all the jobs which need
	 * running have been run, so that is the end condition of this loop.
	 * Note that the Job module will exit if there were any errors unless
	 * the keepgoing flag was given.
	 */
	while (!Job_Empty()) {
		handle_running_jobs();
		(void)MakeStartJobs();
	}

	errors = Job_Finish();
	cycle = false;

	for (gn = ohash_first(&targets, &i); gn != NULL; 
	    gn = ohash_next(&targets, &i)) {
	    	if (has_been_built(gn))
			continue;
		cycle = true;
		errors++;
	    	printf("Error: target %s unaccounted for (%s)\n", 
		    gn->name, status_to_string(gn));
	}
	/*
	 * Print the final status of each target. E.g. if it wasn't made
	 * because some inferior reported an error.
	 */
	Lst_ForEach(targs, MakePrintStatus, &cycle);
	if (errors)
		Fatal("Errors while building");

	return true;
}
Example #2
0
File: job.c Project: UNGLinux/Obase
static void
process_job_status(Job *job, int status)
{
	int reason, code;
	bool	 done;

	debug_printf("Process %ld (%s) exited with status %d.\n",
	    (long)job->pid, job->node->name, status);
	/* parse status */
	if (WIFEXITED(status)) {
		reason = JOB_EXITED;
		code = WEXITSTATUS(status);
	} else if (WIFSIGNALED(status)) {
		reason = JOB_SIGNALED;
		code = WTERMSIG(status);
	} else {
		/* can't happen, set things to be bad. */
		reason = UNKNOWN;
		code = status;
	}

	if ((reason == JOB_EXITED &&
	     code != 0 && !(job->node->type & OP_IGNORE)) ||
	    reason == JOB_SIGNALED) {
		/*
		 * If it exited non-zero and either we're doing things our
		 * way or we're not ignoring errors, the job is finished.
		 * Similarly, if the shell died because of a signal
		 * the job is also finished. In these
		 * cases, finish out the job's output before printing the exit
		 * status...
		 */
		close_job_pipes(job);
		done = true;
	} else if (reason == JOB_EXITED) {
		/*
		 * Deal with ignored errors. We need to print a message telling
		 * of the ignored error as well as setting status.w_status to 0
		 * so the next command gets run. To do this, we set done to be
		 * true and the job exited non-zero.
		 */
		done = code != 0;
		close_job_pipes(job);
	} else {
		/*
		 * No need to close things down or anything.
		 */
		done = false;
	}

	if (done || DEBUG(JOB)) {
		if (reason == JOB_EXITED) {
			debug_printf("Process %ld (%s) exited.\n",
			    (long)job->pid, job->node->name);
			if (code != 0) {
				banner(job, stdout);
				(void)fprintf(stdout, "*** Error code %d %s\n",
				    code,
				    (job->node->type & OP_IGNORE) ?
				    "(ignored)" : "");

				if (job->node->type & OP_IGNORE) {
					reason = JOB_EXITED;
					code = 0;
				}
			} else if (DEBUG(JOB)) {
				(void)fprintf(stdout,
				    "*** %ld (%s) Completed successfully\n",
				    (long)job->pid, job->node->name);
			}
		} else {
			banner(job, stdout);
			(void)fprintf(stdout, "*** Signal %d\n", code);
		}

		(void)fflush(stdout);
	}

	done = true;

	if (done &&
	    aborting != ABORT_ERROR &&
	    aborting != ABORT_INTERRUPT &&
	    reason == JOB_EXITED && code == 0) {
		/* As long as we aren't aborting and the job didn't return a
		 * non-zero status that we shouldn't ignore, we call
		 * Make_Update to update the parents. */
		job->node->built_status = MADE;
		Make_Update(job->node);
	} else if (!(reason == JOB_EXITED && code == 0)) {
		register_error(reason, code, job);
	}
	free(job);

	if (errors && !keepgoing &&
	    aborting != ABORT_INTERRUPT)
		aborting = ABORT_ERROR;

	if (aborting == ABORT_ERROR && Job_Empty())
		Finish(errors);
}