Example #1
0
File: job.c Project: UNGLinux/Obase
void
print_errors()
{
	LstNode ln;
	struct error_info *p;
	const char *type;

	for (ln = Lst_First(&errorsList); ln != NULL; ln = Lst_Adv(ln)) {
		p = (struct error_info *)Lst_Datum(ln);
		switch(p->reason) {
		case JOB_EXITED:
			type = "Exit status";
			break;
		case JOB_SIGNALED:
			type = "Received signal";
			break;
		default:
			type = "Should not happen";
			break;
		}
	if (p->n->origin.lineno)
		Error(" %s %d (%s, line %lu of %s)",
		    type, p->code, p->n->name, p->n->origin.lineno, p->n->origin.fname);
	else
		Error(" %s %d (%s)", type, p->code, p->n->name);
	}
}
Example #2
0
static void
TargPrintNode(GNode *gn, bool full)
{
	if (OP_NOP(gn->type))
		return;
	switch((gn->special & SPECIAL_MASK)) {
	case SPECIAL_SUFFIXES:
	case SPECIAL_PHONY:
	case SPECIAL_ORDER:
	case SPECIAL_NOTHING:
	case SPECIAL_MAIN:
	case SPECIAL_IGNORE:
		return;
	default:
		break;
	}
	if (full) {
		printf("# %d unmade prerequisites\n", gn->unmade);
		if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) {
			if (!is_out_of_date(gn->mtime)) {
				printf("# last modified %s: %s\n",
				      time_to_string(&gn->mtime),
				      status_to_string(gn));
			} else if (gn->built_status != UNKNOWN) {
				printf("# non-existent (maybe): %s\n",
				    status_to_string(gn));
			} else {
				printf("# unmade\n");
			}
		}
	}
	if (!Lst_IsEmpty(&gn->parents)) {
		printf("# parent targets: ");
		Lst_Every(&gn->parents, TargPrintName);
		fputc('\n', stdout);
	}
	if (gn->impliedsrc)
		printf("# implied prerequisite: %s\n", gn->impliedsrc->name);

	printf("%-16s", gn->name);
	switch (gn->type & OP_OPMASK) {
	case OP_DEPENDS:
		printf(": "); break;
	case OP_FORCE:
		printf("! "); break;
	case OP_DOUBLEDEP:
		printf(":: "); break;
	}
	Targ_PrintType(gn->type);
	Lst_Every(&gn->children, TargPrintName);
	fputc('\n', stdout);
	Lst_Every(&gn->commands, Targ_PrintCmd);
	printf("\n\n");
	if (gn->type & OP_DOUBLEDEP) {
		LstNode ln;

		for (ln = Lst_First(&gn->cohorts); ln != NULL; ln = Lst_Adv(ln))
			TargPrintNode((GNode *)Lst_Datum(ln), full);
	}
}
Example #3
0
File: job.c Project: UNGLinux/Obase
/*-
 *-----------------------------------------------------------------------
 * Job_AbortAll --
 *	Abort all currently running jobs without handling output or anything.
 *	This function is to be called only in the event of a major
 *	error. Most definitely NOT to be called from JobInterrupt.
 *
 * Side Effects:
 *	All children are killed, not just the firstborn
 *-----------------------------------------------------------------------
 */
void
Job_AbortAll(void)
{
	LstNode ln;	/* element in job table */
	Job *job;	/* the job descriptor in that element */
	int foo;

	aborting = ABORT_ERROR;

	if (nJobs) {
		for (ln = Lst_First(&runningJobs); ln != NULL;
		    ln = Lst_Adv(ln)) {
			job = (Job *)Lst_Datum(ln);

			/*
			 * kill the child process with increasingly drastic
			 * signals to make darn sure it's dead.
			 */
			killpg(job->pid, SIGINT);
			killpg(job->pid, SIGKILL);
		}
	}

	/*
	 * Catch as many children as want to report in at first, then give up
	 */
	while (waitpid(WAIT_ANY, &foo, WNOHANG) > 0)
		continue;
}
Example #4
0
File: job.c Project: UNGLinux/Obase
static bool
expensive_commands(Lst l)
{
	LstNode ln;
	for (ln = Lst_First(l); ln != NULL; ln = Lst_Adv(ln))
		if (expensive_command(Lst_Datum(ln)))
			return true;
	return false;
}
Example #5
0
void
expand_commands(GNode *gn)
{
    LstNode ln;
    char *cmd;

    for (ln = Lst_First(&gn->commands); ln != NULL; ln = Lst_Adv(ln)) {
        cmd = Var_Subst(Lst_Datum(ln), &gn->context, false);
        Lst_AtEnd(&gn->expanded, cmd);
    }
}
Example #6
0
File: job.c Project: UNGLinux/Obase
/* this is safe from interrupts, actually */
void
parallel_handler(int signo)
{
	int save_errno = errno;
	LstNode ln;
	for (ln = Lst_First(&job_pids); ln != NULL; ln = Lst_Adv(ln)) {
	    	struct job_pid *p = Lst_Datum(ln);
		killpg(p->pid, signo);
	}
	errno = save_errno;

	switch(signo) {
	case SIGINT:
		got_SIGINT++;
		got_signal = 1;
		return;
	case SIGHUP:
		got_SIGHUP++;
		got_signal = 1;
		return;
	case SIGQUIT:
		got_SIGQUIT++;
		got_signal = 1;
		return;
	case SIGTERM:
		got_SIGTERM++;
		got_signal = 1;
		return;
	case SIGTSTP:
		got_SIGTSTP++;
		got_signal = 1;
		break;
	case SIGTTOU:
		got_SIGTTOU++;
		got_signal = 1;
		break;
	case SIGTTIN:
		got_SIGTTIN++;
		got_signal = 1;
		break;
	case SIGWINCH:
		got_SIGWINCH++;
		got_signal = 1;
		break;
	case SIGCONT:
		got_SIGCONT++;
		got_signal = 1;
		break;
	}
	(void)killpg(getpid(), signo);

	(void)signal(signo, SIG_DFL);
	errno = save_errno;
}
Example #7
0
/*-
 *-----------------------------------------------------------------------
 * CondDoMake --
 *	Handle the 'make' function for conditionals.
 *
 * Results:
 *	true if the given target is being made.
 *-----------------------------------------------------------------------
 */
static bool
CondDoMake(struct Name *arg)
{
	LstNode ln;

	for (ln = Lst_First(create); ln != NULL; ln = Lst_Adv(ln)) {
		char *s = (char *)Lst_Datum(ln);
		if (Str_Matchi(s, strchr(s, '\0'), arg->s, arg->e))
			return true;
	}

	return false;
}
Example #8
0
/*-
 *---------------------------------------------------------------------
 * ParseDoOp  --
 *	Apply the parsed operator to the given target node. Used in a
 *	Array_Find call by ParseDoDependency once all targets have
 *	been found and their operator parsed. If the previous and new
 *	operators are incompatible, a major error is taken.
 *
 * Side Effects:
 *	The type field of the node is altered to reflect any new bits in
 *	the op.
 *---------------------------------------------------------------------
 */
static int
ParseDoOp(GNode **gnp, unsigned int op)
{
	GNode *gn = *gnp;
	/*
	 * If the dependency mask of the operator and the node don't match and
	 * the node has actually had an operator applied to it before, and the
	 * operator actually has some dependency information in it, complain.
	 */
	if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) &&
	    !OP_NOP(gn->type) && !OP_NOP(op)) {
		Parse_Error(PARSE_FATAL, 
		    "Inconsistent dependency operator for target %s\n"
		    "\t(was %s%s, now %s%s)",
		    gn->name, gn->name, operator_string(gn->type), 
		    gn->name, operator_string(op));
		return 0;
	}

	if (op == OP_DOUBLEDEP && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) {
		/* If the node was the object of a :: operator, we need to
		 * create a new instance of it for the children and commands on
		 * this dependency line. The new instance is placed on the
		 * 'cohorts' list of the initial one (note the initial one is
		 * not on its own cohorts list) and the new instance is linked
		 * to all parents of the initial instance.  */
		GNode *cohort;
		LstNode ln;

		cohort = Targ_NewGN(gn->name);
		/* Duplicate links to parents so graph traversal is simple.
		 * Perhaps some type bits should be duplicated?
		 *
		 * Make the cohort invisible as well to avoid duplicating it
		 * into other variables. True, parents of this target won't
		 * tend to do anything with their local variables, but better
		 * safe than sorry.  */
		for (ln = Lst_First(&gn->parents); ln != NULL; ln = Lst_Adv(ln))
			ParseLinkSrc((GNode *)Lst_Datum(ln), cohort);
		cohort->type = OP_DOUBLEDEP|OP_INVISIBLE;
		Lst_AtEnd(&gn->cohorts, cohort);

		/* Replace the node in the targets list with the new copy */
		*gnp = cohort;
		gn = cohort;
	}
	/* We don't want to nuke any previous flags (whatever they were) so we
	 * just OR the new operator into the old.  */
	gn->type |= op;
	return 1;
}
Example #9
0
File: make.c Project: aharri/base
static void
requeue_successors(GNode *gn)
{
	LstNode ln;
	/* Deal with successor nodes. If any is marked for making and has an
	 * unmade count of 0, has not been made and isn't in the examination
	 * queue, it means we need to place it in the queue as it restrained
	 * itself before.	*/
	for (ln = Lst_First(&gn->successors); ln != NULL; ln = Lst_Adv(ln)) {
		GNode	*succ = (GNode *)Lst_Datum(ln);

		if (succ->must_make && succ->unmade == 0 
		    && succ->built_status == UNKNOWN)
			Array_PushNew(&toBeMade, succ);
	}
}
Example #10
0
void
Make_HandleUse(GNode	*cgn,	/* The .USE node */
               GNode	*pgn)	/* The target of the .USE node */
{
    GNode	*gn;	/* A child of the .USE node */
    LstNode	ln;	/* An element in the children list */


    assert(cgn->type & (OP_USE|OP_TRANSFORM));

    if ((cgn->type & OP_USE) || Lst_IsEmpty(&pgn->commands)) {
        /* .USE or transformation and target has no commands
         * -- append the child's commands to the parent.  */
        Lst_Concat(&pgn->commands, &cgn->commands);
    }

    for (ln = Lst_First(&cgn->children); ln != NULL;
            ln = Lst_Adv(ln)) {
        gn = (GNode *)Lst_Datum(ln);

        if (Lst_AddNew(&pgn->children, gn)) {
            Lst_AtEnd(&gn->parents, pgn);
            pgn->unmade++;
        }
    }

    pgn->type |= cgn->type & ~(OP_OPMASK|OP_USE|OP_TRANSFORM);

    /*
     * This child node is now "made", so we decrement the count of
     * unmade children in the parent... We also remove the child
     * from the parent's list to accurately reflect the number of
     * decent children the parent has. This is used by Make_Run to
     * decide whether to queue the parent or examine its children...
     */
    if (cgn->type & OP_USE)
        pgn->unmade--;

    /* if the parent node doesn't have any location, then inherit the
     * use stuff, since that gives us better error messages.
     */
    if (!pgn->lineno) {
        pgn->lineno = cgn->lineno;
        pgn->fname = cgn->fname;
    }
}
Example #11
0
void
Targ_FindList(Lst nodes, Lst names)
{
	LstNode ln;
	GNode *gn;
	char *name;

	for (ln = Lst_First(names); ln != NULL; ln = Lst_Adv(ln)) {
		name = (char *)Lst_Datum(ln);
		gn = Targ_FindNode(name, TARG_CREATE);
		/* Note: Lst_AtEnd must come before the Lst_Concat so the nodes
		 * are added to the list in the order in which they were
		 * encountered in the makefile.  */
		Lst_AtEnd(nodes, gn);
		if (gn->type & OP_DOUBLEDEP)
			Lst_Concat(nodes, &gn->cohorts);
	}
}
Example #12
0
File: job.c Project: UNGLinux/Obase
void
handle_all_jobs_output(void)
{
	int nfds;
	struct timeval timeout;
	LstNode ln, ln2;
	Job *job;
	int i;
	int status;

	/* no jobs */
	if (Lst_IsEmpty(&runningJobs))
		return;

	(void)fflush(stdout);

	memcpy(actual_mask, output_mask, mask_size);
	timeout.tv_sec = SEL_SEC;
	timeout.tv_usec = SEL_USEC;

	nfds = select(largest_fd+1, actual_mask, NULL, NULL, &timeout);
	handle_all_signals();
	for (ln = Lst_First(&runningJobs); nfds && ln != NULL; ln = ln2) {
	    	ln2 = Lst_Adv(ln);
		job = (Job *)Lst_Datum(ln);
		job->flags &= ~JOB_DIDOUTPUT;
		for (i = 1; i >= 0; i--) {
			if (FD_ISSET(job->in[i].fd, actual_mask)) {
				nfds--;
				handle_job_output(job, i, false);
			}
		}
		if (job->flags & JOB_DIDOUTPUT) {
			if (waitpid(job->pid, &status, WNOHANG) == job->pid) {
				remove_job(ln, status);
			} else {
				Lst_Requeue(&runningJobs, ln);
			}
		}
	}
}
Example #13
0
File: make.c Project: aharri/base
static bool
has_unmade_predecessor(GNode *gn)
{
	LstNode ln;

	if (Lst_IsEmpty(&gn->preds))
		return false;


	for (ln = Lst_First(&gn->preds); ln != NULL; ln = Lst_Adv(ln)) {
		GNode	*pgn = (GNode *)Lst_Datum(ln);

		if (pgn->must_make && pgn->built_status == UNKNOWN) {
			if (DEBUG(MAKE))
				printf("predecessor %s not made yet.\n", 
				    pgn->name);
			return true;
		}
	}
	return false;
}
Example #14
0
File: job.c Project: UNGLinux/Obase
/*-
 *-----------------------------------------------------------------------
 * JobInterrupt --
 *	Handle the receipt of an interrupt.
 *
 * Side Effects:
 *	All children are killed. Another job will be started if the
 *	.INTERRUPT target was given.
 *-----------------------------------------------------------------------
 */
static void
JobInterrupt(bool runINTERRUPT,	/* true if commands for the .INTERRUPT
				 * target should be executed */
    int signo)			/* signal received */
{
	LstNode ln;		/* element in job table */
	Job *job; 		/* job descriptor in that element */

	aborting = ABORT_INTERRUPT;

	for (ln = Lst_First(&runningJobs); ln != NULL; ln = Lst_Adv(ln)) {
		job = (Job *)Lst_Datum(ln);

		if (!Targ_Precious(job->node)) {
			const char *file = job->node->path == NULL ?
			    job->node->name : job->node->path;
			if (!noExecute && eunlink(file) != -1) {
				Error("*** %s removed", file);
			}
		}
		if (job->pid) {
			debug_printf("JobInterrupt passing signal to "
			    "child %ld.\n", (long)job->pid);
			killpg(job->pid, signo);
		}
	}

	if (runINTERRUPT && !touchFlag) {
		if ((interrupt_node->type & OP_DUMMY) == 0) {
			ignoreErrors = false;

			JobStart(interrupt_node, 0);
			loop_handle_running_jobs();
		}
	}
	exit(signo);
}
Example #15
0
/*-
 *---------------------------------------------------------------------
 * ParseDoSrc  --
 *	Given the name of a source, figure out if it is an attribute
 *	and apply it to the targets if it is. Else decide if there is
 *	some attribute which should be applied *to* the source because
 *	of some special target and apply it if so. Otherwise, make the
 *	source be a child of the targets in the list 'targets'
 *
 * Side Effects:
 *	Operator bits may be added to the list of targets or to the source.
 *	The targets may have a new source added to their lists of children.
 *---------------------------------------------------------------------
 */
static void
ParseDoSrc(
    struct growableArray *targets,
    struct growableArray *sources,
    int 	tOp,	/* operator (if any) from special targets */
    const char	*src,	/* name of the source to handle */
    const char *esrc)
{
	GNode *gn = Targ_FindNodei(src, esrc, TARG_CREATE);
	if ((gn->special & SPECIAL_SOURCE) != 0) {
		if (gn->special_op) {
			Array_FindP(targets, ParseDoOp, gn->special_op);
			return;
		} else {
			assert((gn->special & SPECIAL_MASK) == SPECIAL_WAIT);
			waiting++;
			return;
		}
	}

	switch (specType) {
	case SPECIAL_MAIN:
		/*
		 * If we have noted the existence of a .MAIN, it means we need
		 * to add the sources of said target to the list of things
		 * to create.  Note that this will only be invoked if the user
		 * didn't specify a target on the command line. This is to
		 * allow #ifmake's to succeed, or something...
		 */
		Lst_AtEnd(create, gn->name);
		/*
		 * Add the name to the .TARGETS variable as well, so the user
		 * can employ that, if desired.
		 */
		Var_Append(".TARGETS", gn->name);
		return;

	case SPECIAL_ORDER:
		/*
		 * Create proper predecessor/successor links between the
		 * previous source and the current one.
		 */
		if (predecessor != NULL) {
			Lst_AtEnd(&predecessor->successors, gn);
			Lst_AtEnd(&gn->preds, predecessor);
		}
		predecessor = gn;
		break;

	default:
		/*
		 * In the case of a source that was the object of a :: operator,
		 * the attribute is applied to all of its instances (as kept in
		 * the 'cohorts' list of the node) or all the cohorts are linked
		 * to all the targets.
		 */
		apply_op(targets, tOp, gn);
		if ((gn->type & OP_OPMASK) == OP_DOUBLEDEP) {
			LstNode	ln;

			for (ln=Lst_First(&gn->cohorts); ln != NULL;
			    ln = Lst_Adv(ln)){
			    	apply_op(targets, tOp,
				    (GNode *)Lst_Datum(ln));
			}
		}
		break;
	}

	gn->order = waiting;
	Array_AtEnd(sources, gn);
	if (waiting)
		Array_Find(sources, ParseAddDep, gn);
}
Example #16
0
For *
For_Eval(const char *line)
{
	const char	*ptr = line;
	const char	*wrd;
	char	*sub;
	const char	*endVar;
	For 	*arg;
	unsigned long n;

	while (ISSPACE(*ptr))
		ptr++;

	/* Parse loop.  */

	arg = emalloc(sizeof(*arg));
	arg->nvars = 0;
	Lst_Init(&arg->vars);

	for (;;) {
		/* Grab the variables.  */
		for (wrd = ptr; *ptr && !ISSPACE(*ptr); ptr++)
			continue;
		if (ptr - wrd == 0) {
			Parse_Error(PARSE_FATAL, "Syntax error in for");
			return 0;
		}
		endVar = ptr++;
		while (ISSPACE(*ptr))
			ptr++;
		/* End of variable list ? */
		if (endVar - wrd == 2 && wrd[0] == 'i' && wrd[1] == 'n')
			break;
		Lst_AtEnd(&arg->vars, Var_NewLoopVar(wrd, endVar));
		arg->nvars++;
	}
	if (arg->nvars == 0) {
		Parse_Error(PARSE_FATAL, "Missing variable in for");
		return 0;
	}

	/* Make a list with the remaining words.  */
	sub = Var_Subst(ptr, NULL, false);
	if (DEBUG(FOR)) {
		LstNode ln;
		(void)fprintf(stderr, "For: Iterator ");
		for (ln = Lst_First(&arg->vars); ln != NULL; ln = Lst_Adv(ln))
			(void)fprintf(stderr, "%s ",
			    Var_LoopVarName(Lst_Datum(ln)));
		(void)fprintf(stderr, "List %s\n", sub);
	}

	Lst_Init(&arg->lst);
	n = build_words_list(&arg->lst, sub);
	free(sub);
	if (arg->nvars != 1 && n % arg->nvars != 0) {
		LstNode ln;

		Parse_Error(PARSE_FATAL, "Wrong number of items in for loop");
		(void)fprintf(stderr, "%lu items for %d variables:", 
		    n, arg->nvars);
		for (ln = Lst_First(&arg->lst); ln != NULL; ln = Lst_Adv(ln)) {
			char *p = Lst_Datum(ln);

			(void)fprintf(stderr, " %s", p);
		}
		(void)fprintf(stderr, "\n");
		return 0;
	}
	arg->lineno = Parse_Getlineno();
	arg->level = 1;
	Buf_Init(&arg->buf, 0);

	return arg;
}
Example #17
0
void
Make_DoAllVar(GNode *gn)
{
    GNode *child;
    LstNode ln;
    BUFFER allsrc, oodate;
    char *target;
    bool do_oodate;
    int oodate_count, allsrc_count = 0;

    oodate_count = 0;
    allsrc_count = 0;

    for (ln = Lst_First(&gn->children); ln != NULL; ln = Lst_Adv(ln)) {
        child = (GNode *)Lst_Datum(ln);
        if ((child->type & (OP_EXEC|OP_USE|OP_INVISIBLE)) != 0)
            continue;
        if (OP_NOP(child->type) ||
                (target = Var(TARGET_INDEX, child)) == NULL) {
            /*
             * this node is only source; use the specific pathname
             * for it
             */
            target = child->path != NULL ? child->path :
                     child->name;
        }

        /*
         * It goes in the OODATE variable if the parent is younger than
         * the child or if the child has been modified more recently
         * than the start of the make.  This is to keep make from
         * getting confused if something else updates the parent after
         * the make starts (shouldn't happen, I know, but sometimes it
         * does). In such a case, if we've updated the kid, the parent
         * is likely to have a modification time later than that of the
         * kid and anything that relies on the OODATE variable will be
         * hosed.
         */
        do_oodate = false;
        if (gn->type & OP_JOIN) {
            if (child->built_status == MADE)
                do_oodate = true;
        } else if (is_strictly_before(gn->mtime, child->mtime) ||
                   (!is_strictly_before(child->mtime, now) &&
                    child->built_status == MADE))
            do_oodate = true;
        if (do_oodate) {
            oodate_count++;
            if (oodate_count == 1)
                Var(OODATE_INDEX, gn) = target;
            else {
                if (oodate_count == 2) {
                    Buf_Init(&oodate, 0);
                    Buf_AddString(&oodate,
                                  Var(OODATE_INDEX, gn));
                }
                Buf_AddSpace(&oodate);
                Buf_AddString(&oodate, target);
            }
        }
        allsrc_count++;
        if (allsrc_count == 1)
            Var(ALLSRC_INDEX, gn) = target;
        else {
            if (allsrc_count == 2) {
                Buf_Init(&allsrc, 0);
                Buf_AddString(&allsrc,
                              Var(ALLSRC_INDEX, gn));
            }
            Buf_AddSpace(&allsrc);
            Buf_AddString(&allsrc, target);
        }
    }

    if (allsrc_count > 1)
        Var(ALLSRC_INDEX, gn) = Buf_Retrieve(&allsrc);
    if (oodate_count > 1)
        Var(OODATE_INDEX, gn) = Buf_Retrieve(&oodate);

    if (gn->impliedsrc)
        Var(IMPSRC_INDEX, gn) = Var(TARGET_INDEX, gn->impliedsrc);

    if (gn->type & OP_JOIN)
        Var(TARGET_INDEX, gn) = Var(ALLSRC_INDEX, gn);
}
Example #18
0
File: job.c Project: UNGLinux/Obase
/*-
 *-----------------------------------------------------------------------
 * JobExec --
 *	Execute the shell for the given job. Called from JobStart
 *
 * Side Effects:
 *	A shell is executed, outputs is altered and the Job structure added
 *	to the job table.
 *-----------------------------------------------------------------------
 */
static void
JobExec(Job *job)
{
	pid_t cpid; 	/* ID of new child */
	struct job_pid *p;
	int fds[4];
	int *fdout = fds;
	int *fderr = fds+2;
	int i;

	banner(job, stdout);

	setup_engine(1);

	/* Create the pipe by which we'll get the shell's output.
	 */
	if (pipe(fdout) == -1)
		Punt("Cannot create pipe: %s", strerror(errno));

	if (pipe(fderr) == -1)
		Punt("Cannot create pipe: %s", strerror(errno));

	block_signals();
	if ((cpid = fork()) == -1) {
		Punt("Cannot fork");
		unblock_signals();
	} else if (cpid == 0) {
		supervise_jobs = false;
		/* standard pipe code to route stdout and stderr */
		close(fdout[0]);
		if (dup2(fdout[1], 1) == -1)
			Punt("Cannot dup2(outPipe): %s", strerror(errno));
		if (fdout[1] != 1)
			close(fdout[1]);
		close(fderr[0]);
		if (dup2(fderr[1], 2) == -1)
			Punt("Cannot dup2(errPipe): %s", strerror(errno));
		if (fderr[1] != 2)
			close(fderr[1]);

		/*
		 * 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)setpgid(0, getpid());

		if (random_delay)
			if (!(nJobs == 1 && no_jobs_left()))
				usleep(random() % random_delay);

		setup_all_signals(SigHandler, SIG_DFL);
		unblock_signals();
		/* this exits directly */
		run_gnode_parallel(job->node);
		/*NOTREACHED*/
	} else {
		supervise_jobs = true;
		job->pid = cpid;

		/* we set the current position in the buffers to the beginning
		 * and mark another stream to watch in the outputs mask
		 */
		for (i = 0; i < 2; i++)
			prepare_pipe(&job->in[i], fds+2*i);
	}
	/*
	 * Now the job is actually running, add it to the table.
	 */
	nJobs++;
	Lst_AtEnd(&runningJobs, job);
	if (job->flags & JOB_IS_EXPENSIVE)
		expensive_job = true;
	p = emalloc(sizeof(struct job_pid));
	p->pid = cpid;
	Lst_AtEnd(&job_pids, p);
	job->p = Lst_Last(&job_pids);

	unblock_signals();
	if (DEBUG(JOB)) {
		LstNode ln;

		(void)fprintf(stdout, "Running %ld (%s)\n", (long)cpid,
		    job->node->name);
		for (ln = Lst_First(&job->node->commands); ln != NULL ;
		    ln = Lst_Adv(ln))
		    	fprintf(stdout, "\t%s\n", (char *)Lst_Datum(ln));
		(void)fflush(stdout);
	}

}
Example #19
0
File: make.c Project: aharri/base
/*-
 *-----------------------------------------------------------------------
 * Make_Update	--
 *	Perform update on the parents of a node. Used by JobFinish once
 *	a node has been dealt with and by MakeStartJobs if it finds an
 *	up-to-date node.
 *
 * Results:
 *	Always returns 0
 *
 * Side Effects:
 *	The unmade field of pgn is decremented and pgn may be placed on
 *	the toBeMade queue if this field becomes 0.
 *
 *	If the child was made, the parent's childMade field will be set true
 *	and its cmtime set to now.
 *
 *	If the child wasn't made, the cmtime field of the parent will be
 *	altered if the child's mtime is big enough.
 *
 *-----------------------------------------------------------------------
 */
void
Make_Update(GNode *cgn)	/* the child node */
{
	GNode	*pgn;	/* the parent node */
	LstNode	ln;	/* Element in parents list */

	/*
	 * If the child was actually made, see what its modification time is
	 * now -- some rules won't actually update the file. If the file still
	 * doesn't exist, make its mtime now.
	 */
	if (cgn->built_status != UPTODATE) {
		/*
		 * This is what Make does and it's actually a good thing, as it
		 * allows rules like
		 *
		 *	cmp -s y.tab.h parse.h || cp y.tab.h parse.h
		 *
		 * to function as intended. Unfortunately, thanks to the
		 * stateless nature of NFS, there are times when the
		 * modification time of a file created on a remote machine
		 * will not be modified before the local stat() implied by
		 * the Dir_MTime occurs, thus leading us to believe that the
		 * file is unchanged, wreaking havoc with files that depend
		 * on this one.
		 */
		if (noExecute || is_out_of_date(Dir_MTime(cgn)))
			ts_set_from_now(cgn->mtime);
		if (DEBUG(MAKE))
			printf("update time: %s\n", time_to_string(cgn->mtime));
	}

	/* SIB: this is where I should mark the build as finished */
	cgn->build_lock = false;
	for (ln = Lst_First(&cgn->parents); ln != NULL; ln = Lst_Adv(ln)) {
		pgn = (GNode *)Lst_Datum(ln);
		/* SIB: there should be a siblings loop there */
		pgn->unmade--;
		if (pgn->must_make) {
			if (DEBUG(MAKE))
				printf("%s--=%d ", 
				    pgn->name, pgn->unmade);

			if ( ! (cgn->type & (OP_EXEC|OP_USE))) {
				if (cgn->built_status == MADE) {
					pgn->childMade = true;
					if (is_strictly_before(pgn->cmtime,
					    cgn->mtime))
						pgn->cmtime = cgn->mtime;
				} else {
					(void)Make_TimeStamp(pgn, cgn);
				}
			}
			if (pgn->unmade == 0) {
				/*
				 * Queue the node up -- any unmade
				 * predecessors will be dealt with in
				 * MakeStartJobs.
				 */
				if (DEBUG(MAKE))
					printf("QUEUING ");
				Array_Push(&toBeMade, pgn);
			} else if (pgn->unmade < 0) {
				Error("Child %s discovered graph cycles through %s", cgn->name, pgn->name);
			}
		}
	}
	if (DEBUG(MAKE))
		printf("\n");
	requeue_successors(cgn);
}
Example #20
0
/*-
 * main --
 *	The main function, for obvious reasons. Initializes variables
 *	and a few modules, then parses the arguments give it in the
 *	environment and on the command line. Reads the system makefile
 *	followed by either Makefile, makefile or the file given by the
 *	-f argument. Sets the .MAKEFLAGS PMake variable based on all the
 *	flags it has received by then uses either the Make or the Compat
 *	module to create the initial list of targets.
 *
 * Results:
 *	If -q was given, exits -1 if anything was out-of-date. Else it exits
 *	0.
 *
 * Side Effects:
 *	The program exits when done. Targets are created. etc. etc. etc.
 */
int
main(int argc, char **argv)
{
	static LIST targs;	/* target nodes to create */
	bool outOfDate = true;	/* false if all targets up to date */
	char *machine = figure_out_MACHINE();
	char *machine_arch = figure_out_MACHINE_ARCH();
	char *machine_cpu = figure_out_MACHINE_CPU();
	const char *syspath = _PATH_DEFSYSPATH;
	char *p;
	static struct dirs d;
	bool read_depend = true;/* false if we don't want to read .depend */

	MainParseChdir(argc, argv);
	setup_CURDIR_OBJDIR(&d, machine);

	esetenv("PWD", d.object);
	unsetenv("CDPATH");

	Static_Lst_Init(create);
	Static_Lst_Init(&makefiles);
	Static_Lst_Init(&varstoprint);
	Static_Lst_Init(&targs);

	beSilent = false;		/* Print commands as executed */
	ignoreErrors = false;		/* Pay attention to non-zero returns */
	noExecute = false;		/* Execute all commands */
	keepgoing = false;		/* Stop on error */
	allPrecious = false;		/* Remove targets when interrupted */
	queryFlag = false;		/* This is not just a check-run */
	noBuiltins = false;		/* Read the built-in rules */
	touchFlag = false;		/* Actually update targets */
	debug = 0;			/* No debug verbosity, please. */

	maxJobs = DEFMAXJOBS;
	compatMake = false;		/* No compat mode */


	/*
	 * Initialize all external modules.
	 */
	Init();

	if (d.object != d.current)
		Dir_AddDir(defaultPath, d.current);
	Var_Set(".CURDIR", d.current);
	Var_Set(".OBJDIR", d.object);
	Parse_setcurdir(d.current);
	Targ_setdirs(d.current, d.object);

	/*
	 * Initialize various variables.
	 *	MAKE also gets this name, for compatibility
	 *	.MAKEFLAGS gets set to the empty string just in case.
	 *	MFLAGS also gets initialized empty, for compatibility.
	 */
	Var_Set("MAKE", argv[0]);
	Var_Set(".MAKE", argv[0]);
	Var_Set(MAKEFLAGS, "");
	Var_Set("MFLAGS", "");
	Var_Set("MACHINE", machine);
	Var_Set("MACHINE_ARCH", machine_arch);
	Var_Set("MACHINE_CPU", machine_cpu);

	/*
	 * First snag any flags out of the MAKEFLAGS environment variable.
	 */
	Main_ParseArgLine(getenv("MAKEFLAGS"));
	
	basedirectory = getenv("MAKEBASEDIRECTORY");
	if (basedirectory == NULL)
		setenv("MAKEBASEDIRECTORY", d.current, 0);

	MainParseArgs(argc, argv);

	/*
	 * Be compatible if user did not specify -j
	 */
	if (!forceJobs)
		compatMake = true;

	/* And set up everything for sub-makes */
	Var_AddCmdline(MAKEFLAGS);


	/*
	 * Set up the .TARGETS variable to contain the list of targets to be
	 * created. If none specified, make the variable empty -- the parser
	 * will fill the thing in with the default or .MAIN target.
	 */
	if (!Lst_IsEmpty(create)) {
		LstNode ln;

		for (ln = Lst_First(create); ln != NULL; ln = Lst_Adv(ln)) {
			char *name = (char *)Lst_Datum(ln);

			if (strcmp(name, "depend") == 0)
				read_depend = false;

			Var_Append(".TARGETS", name);
		}
	} else
		Var_Set(".TARGETS", "");


	/*
	 * If no user-supplied system path was given (through the -m option)
	 * add the directories from the DEFSYSPATH (more than one may be given
	 * as dir1:...:dirn) to the system include path.
	 */
	if (Lst_IsEmpty(systemIncludePath))
	    add_dirpath(systemIncludePath, syspath);

	read_all_make_rules(noBuiltins, read_depend, &makefiles, &d);

	Var_Append("MFLAGS", Var_Value(MAKEFLAGS));

	/* Install all the flags into the MAKEFLAGS env variable. */
	if (((p = Var_Value(MAKEFLAGS)) != NULL) && *p)
		esetenv("MAKEFLAGS", p);

	setup_VPATH();

	process_suffixes_after_makefile_is_read();

	if (dumpData) {
		dump_data();
		exit(0);
	}

	/* Print the initial graph, if the user requested it.  */
	if (DEBUG(GRAPH1))
		dump_data();

	/* Print the values of any variables requested by the user.  */
	if (!Lst_IsEmpty(&varstoprint)) {
		LstNode ln;

		for (ln = Lst_First(&varstoprint); ln != NULL;
		    ln = Lst_Adv(ln)) {
			char *value = Var_Value((char *)Lst_Datum(ln));

			printf("%s\n", value ? value : "");
		}
	} else {
		/* Have now read the entire graph and need to make a list
		 * of targets to create. If none was given on the command
		 * line, we consult the parsing module to find the main
		 * target(s) to create.  */
		if (Lst_IsEmpty(create))
			Parse_MainName(&targs);
		else
			Targ_FindList(&targs, create);

		Job_Init(maxJobs);
		/* If the user has defined a .BEGIN target, execute the commands
		 * attached to it.  */
		if (!queryFlag)
			Job_Begin();
		if (compatMake)
			/* Compat_Init will take care of creating all the
			 * targets as well as initializing the module.  */
			Compat_Run(&targs);
		else {
			/* Traverse the graph, checking on all the targets.  */
			outOfDate = Make_Run(&targs);
		}
	}

	/* print the graph now it's been processed if the user requested it */
	if (DEBUG(GRAPH2))
		post_mortem();

	if (queryFlag && outOfDate)
		return 1;
	else
		return 0;
}