void wakeup(Seconds_t t, register List_t* p) { register Alarms_t* a; register Alarms_t* z; register Alarms_t* x; Alarms_t* alarms; Seconds_t now; alarms = trap.alarms; now = CURSECS; if (t) { t += now; if (!p) p = cons(catrule(external.interrupt, ".", fmtsignal(-SIGALRM), 1), NiL); } if (p) { do { x = 0; for (z = 0, a = trap.alarms; a; z = a, a = a->next) if (a->rule == p->rule) { x = a; if (z) z->next = a->next; else trap.alarms = a->next; break; } if (t) { if (!x) { if (x = trap.freealarms) trap.freealarms = trap.freealarms->next; else x = newof(0, Alarms_t, 1, 0); x->rule = p->rule; } x->time = t; x->next = 0; for (z = 0, a = trap.alarms; a; z = a, a = a->next) if (t <= a->time) { x->next = a; break; } if (z) z->next = x; else trap.alarms = x; } } while (p = p->next); } else if (a = trap.alarms) { trap.alarms = 0; while (x = a->next) a = x; a->next = trap.freealarms; trap.freealarms = a; } if (trap.alarms != alarms) setwakeup(); }
int handle(void) { register int sig; register Rule_t* r; register Alarms_t* a; char* s; char* w; Var_t* v; Seconds_t t; if (!state.caught) return 0; while (state.caught) { state.caught = 0; for (sig = 1; sig <= sig_info.sigmax; sig++) if (trap.caught[sig]) { trap.caught[sig] = 0; /* * flush the output streams */ sfsync(sfstderr); sfsync(sfstdout); /* * continue if already in finish */ if (state.finish) { if (!state.interrupt) state.interrupt = sig; for (sig = 1; sig <= sig_info.sigmax; sig++) trap.caught[sig] = 0; return 0; } /* * check user trap (some cannot be trapped) */ w = 0; if (!state.compileonly) switch (sig) { case SIGALRM: s = fmtsignal(-sig); t = CURSECS; while ((a = trap.alarms) && a->time <= t) { trap.alarms = a->next; r = a->rule; a->next = trap.freealarms; trap.freealarms = a; maketop(r, (P_dontcare|P_force|P_ignore|P_repeat)|((r->property & P_make)?0:P_foreground), s); } setwakeup(); continue; default: s = fmtsignal(-sig); if ((r = catrule(external.interrupt, ".", s, 0)) || (r = getrule(external.interrupt))) { if (!(r->property & P_functional)) v = setvar(external.interrupt, s, 0); maketop(r, (P_dontcare|P_force|P_ignore|P_repeat)|((r->property & P_make)?0:P_foreground), s); if (r->property & P_functional) v = getvar(r->name); w = v->value; if (r->status == EXISTS && (streq(w, s) || streq(w, "continue"))) { message((-1, "trap %s handler %s status CONTINUE return %s", s, r->name, w)); continue; } message((-1, "trap %s handler %s status TERMINATE return %s", s, r->name, w)); } /*FALLTHROUGH*/ #ifdef SIGILL case SIGILL: #endif #ifdef SIGIOT case SIGIOT: #endif #ifdef SIGEMT case SIGEMT: #endif #ifdef SIGBUS case SIGBUS: #endif #ifdef SIGSEGV case SIGSEGV: #endif break; } /* * terminate outstanding jobs */ terminate(); /* * the interpreter resumes without exit */ if (state.interpreter) { if (state.waiting) return 1; longjmp(state.resume.label, 1); } /* * if external.interrupt=""|"exit" then exit * otherwise terminate via original signal */ if (w && (!*w || streq(w, "exit"))) state.interrupt = 0; else if (!state.interrupt) state.interrupt = sig; finish(3); /* * shouldn't get here */ exit(3); } } return 1; }
void trigger(register Rule_t* r, Rule_t* a, char* action, Flags_t flags) { register Joblist_t* job; register List_t* p; List_t* prereqs; int n; /* * update flags */ if (!a) a = r; if (state.exec && !state.touch || (a->property & P_always) && (!state.never || (flags & CO_URGENT))) flags |= CO_ALWAYS; if ((a->property | r->property) & P_local) flags |= CO_LOCAL; if (!state.jobs || (r->property & P_foreground) || (r->property & (P_make|P_functional)) == P_functional || (r->dynamic & D_hasmake)) flags |= CO_FOREGROUND|CO_LOCAL; if (state.keepgoing || state.unwind) flags |= CO_KEEPGOING; if (state.silent) flags |= CO_SILENT; if (state.ignore) flags |= CO_IGNORE; if (r->property & (P_functional|P_read)) flags |= CO_DATAFILE; if (action) { message((-1, "triggering %s action%s%s", r->name, r == a ? null : " using ", r == a ? null : a->name)); if (state.exec) jobs.triggered = r; r->dynamic |= D_triggered; if ((r->property & (P_joint|P_target)) == (P_joint|P_target)) for (p = r->prereqs->rule->prereqs; p; p = p->next) p->rule->dynamic |= D_triggered; if (!*action) action = 0; } if (state.coshell && (action && !(r->property & P_make) || (flags & CO_FOREGROUND))) { /* * the make thread blocks when too many jobs are outstanding */ n = (flags & CO_FOREGROUND) ? 0 : (state.jobs - 1); while ((cozombie(state.coshell) || cojobs(state.coshell) > n) && block(0)); if ((flags & CO_FOREGROUND) && r->active && r->active->parent && r->active->parent->prereqs && copending(state.coshell) > cojobs(state.coshell)) serial(r, r->active->parent->prereqs); } prereqs = r->prereqs; if (r->active && r->active->primary) { prereqs = cons(getrule(r->active->primary), prereqs); flags |= CO_PRIMARY; } if (r->property & P_make) { if (r->property & P_local) { r->status = EXISTS; return; } /* * make actions are done immediately, bypassing the job queue */ if (prereqs && complete(NiL, prereqs, NiL, 0)) r->status = (r->property & P_dontcare) ? IGNORE : FAILED; else { if (action && cancel(r, prereqs)) r->status = EXISTS; else if ((r->dynamic & (D_hasbefore|D_triggered)) == (D_hasbefore|D_triggered) && (makebefore(r) || complete(NiL, prereqs, NiL, 0))) r->status = (r->property & P_dontcare) ? IGNORE : FAILED; else { if (r->property & P_functional) setvar(r->name, null, 0); if (action) switch (parse(NiL, action, r->name, NiL)) { case EXISTS: if (!(r->property & (P_state|P_virtual))) statetime(r, 0); break; case FAILED: r->status = (r->property & P_dontcare) ? IGNORE : FAILED; break; case TOUCH: r->time = internal.internal->time; break; case UPDATE: if ((r->property & (P_state|P_virtual)) != (P_state|P_virtual)) r->time = CURTIME; break; } if (r->status == UPDATE) r->status = EXISTS; } } if ((r->property & (P_joint|P_target)) == (P_joint|P_target)) for (p = r->prereqs->rule->prereqs; p; p = p->next) if (p->rule != r) { p->rule->status = r->status; p->rule->time = r->time; } if ((r->dynamic & (D_hasafter|D_triggered)) == (D_hasafter|D_triggered)) { if (r->status == FAILED) { if (hasafter(r, P_failure) && !makeafter(r, P_failure) && !complete(NiL, prereqs, NiL, 0)) r->status = EXISTS; } else if (hasafter(r, P_after) && (makeafter(r, P_after) || complete(NiL, prereqs, NiL, 0))) r->status = (r->property & P_dontcare) ? IGNORE : FAILED; } } else { /* * only one repeat action at a time */ if ((r->property & P_repeat) && (r->property & (P_before|P_after)) && !(r->dynamic & D_hassemaphore)) { a = catrule(internal.semaphore->name, ".", r->name, 1); a->semaphore = 2; r->prereqs = append(r->prereqs, cons(a, NiL)); r->dynamic |= D_hassemaphore; } /* * check if any prerequisites are blocking execution * FAILED prerequisites cause the target to fail too */ n = READY; for (;;) { for (p = prereqs; p; p = p->next) { if ((a = p->rule)->dynamic & D_alias) a = makerule(a->name); if (a->property & P_after) continue; switch (a->status) { case FAILED: if (a->property & P_repeat) continue; r->status = (r->property & P_dontcare) ? IGNORE : FAILED; if ((r->property & (P_joint|P_target)) == (P_joint|P_target)) for (p = r->prereqs->rule->prereqs; p; p = p->next) if (p->rule != r) p->rule->status = (p->rule->property & P_dontcare) ? IGNORE : FAILED; return; case MAKING: if (a->active) error(1, "%s: prerequisite %s is active", r->name, a->name); else n = BLOCKED; break; } } if (n != READY) break; if (action) { if (cancel(r, prereqs)) return; if ((r->dynamic & D_intermediate) && r->must == 1) { n = INTERMEDIATE; jobs.intermediate++; break; } } if ((r->dynamic & (D_hasbefore|D_triggered)) != (D_hasbefore|D_triggered)) break; if (makebefore(r)) { r->status = (r->property & P_dontcare) ? IGNORE : FAILED; if ((r->property & (P_joint|P_target)) == (P_joint|P_target)) for (p = r->prereqs->rule->prereqs; p; p = p->next) if (p->rule != r) p->rule->status = (p->rule->property & P_dontcare) ? IGNORE : FAILED; return; } } if (action || n != READY) { /* * allocate a job cell and add to job list * the first READY job from the top is executed next */ if (job = jobs.freejob) jobs.freejob = jobs.freejob->next; else job = newof(0, Joblist_t, 1, 0); if (flags & CO_URGENT) { job->prev = 0; if (job->next = jobs.firstjob) jobs.firstjob->prev = job; else jobs.lastjob = job; jobs.firstjob = job; } else { job->next = 0; if (job->prev = jobs.lastjob) jobs.lastjob->next = job; else jobs.firstjob = job; jobs.lastjob = job; } /* * fill in the info */ job->target = r; job->prereqs = prereqs; job->status = n; job->flags = flags; job->action = action; r->status = MAKING; if ((r->property & (P_joint|P_target)) == (P_joint|P_target)) for (p = r->prereqs->rule->prereqs; p; p = p->next) if (p->rule != r) p->rule->status = r->status; if (n == READY) { execute(job); if (r->dynamic & D_hasafter) save(job); } else save(job); jobstatus(); } else { if (r->status == UPDATE) r->status = EXISTS; if ((r->property & (P_joint|P_target)) == (P_joint|P_target)) for (p = r->prereqs->rule->prereqs; p; p = p->next) if (p->rule->status == UPDATE) p->rule->status = EXISTS; if ((r->dynamic & (D_hasafter|D_triggered)) == (D_hasafter|D_triggered)) { if (r->status == FAILED) { if (hasafter(r, P_failure) && !makeafter(r, P_failure) && !complete(NiL, prereqs, NiL, 0)) r->status = EXISTS; } else if (hasafter(r, P_after) && (makeafter(r, P_after) || complete(NiL, prereqs, NiL, 0))) r->status = (r->property & P_dontcare) ? IGNORE : FAILED; if (r->status == EXISTS) { char* t; Sfio_t* tmp; tmp = sfstropen(); edit(tmp, r->name, KEEP, DELETE, DELETE); if (*(t = sfstruse(tmp))) newfile(r, t, r->time); sfstrclose(tmp); } } } if (r->dynamic & D_triggered) { r->time = CURTIME; if ((r->property & (P_joint|P_target)) == (P_joint|P_target)) for (p = r->prereqs->rule->prereqs; p; p = p->next) p->rule->time = r->time; } } }