version 1.118, 2009/08/16 09:50:13 |
version 1.119, 2010/07/15 10:37:32 |
|
|
char buffer[JOB_BUFSIZE]; |
char buffer[JOB_BUFSIZE]; |
size_t pos; |
size_t pos; |
}; |
}; |
|
|
typedef struct Job_ { |
typedef struct Job_ { |
pid_t pid; /* The child's process ID */ |
pid_t pid; /* The child's process ID */ |
GNode *node; /* The target the child is making */ |
GNode *node; /* The target the child is making */ |
|
|
|
|
/* data structure linked to job handling through select */ |
/* data structure linked to job handling through select */ |
static fd_set *output_mask = NULL; /* File descriptors to look for */ |
static fd_set *output_mask = NULL; /* File descriptors to look for */ |
|
|
static fd_set *actual_mask = NULL; /* actual select argument */ |
static fd_set *actual_mask = NULL; /* actual select argument */ |
static int largest_fd = -1; |
static int largest_fd = -1; |
static size_t mask_size = 0; |
static size_t mask_size = 0; |
|
|
|
|
static void handle_all_jobs_output(void); |
static void handle_all_jobs_output(void); |
|
|
/* handle_job_output(job, n, finish): |
/* handle_job_output(job, n, finish): |
* n = 0 or 1 (stdout/stderr), set finish to retrieve everything. |
* n = 0 or 1 (stdout/stderr), set finish to retrieve everything. |
*/ |
*/ |
static void handle_job_output(Job *, int, bool); |
static void handle_job_output(Job *, int, bool); |
|
|
static void print_partial_buffer(struct job_pipe *, Job *, FILE *, size_t); |
static void print_partial_buffer(struct job_pipe *, Job *, FILE *, size_t); |
static void print_partial_buffer_and_shift(struct job_pipe *, Job *, FILE *, |
static void print_partial_buffer_and_shift(struct job_pipe *, Job *, FILE *, |
size_t); |
size_t); |
static bool print_complete_lines(struct job_pipe *, Job *, FILE *, size_t); |
static bool print_complete_lines(struct job_pipe *, Job *, FILE *, size_t); |
|
|
|
|
if (p->n->lineno) |
if (p->n->lineno) |
Error(" %s %d (%s, line %lu of %s)", |
Error(" %s %d (%s, line %lu of %s)", |
type, p->code, p->n->name, p->n->lineno, p->n->fname); |
type, p->code, p->n->name, p->n->lineno, p->n->fname); |
else |
else |
Error(" %s %d (%s)", type, p->code, p->n->name); |
Error(" %s %d (%s)", type, p->code, p->n->name); |
} |
} |
} |
} |
|
|
banner(Job *job, FILE *out) |
banner(Job *job, FILE *out) |
{ |
{ |
if (job->node != lastNode) { |
if (job->node != lastNode) { |
if (DEBUG(JOBBANNER)) |
if (DEBUG(JOBBANNER)) |
(void)fprintf(out, "--- %s ---\n", job->node->name); |
(void)fprintf(out, "--- %s ---\n", job->node->name); |
lastNode = job->node; |
lastNode = job->node; |
} |
} |
|
|
va_end(va); |
va_end(va); |
} |
} |
} |
} |
|
|
static void |
static void |
close_job_pipes(Job *job) |
close_job_pipes(Job *job) |
{ |
{ |
|
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* process_job_status -- |
* process_job_status -- |
* Do processing for the given job including updating |
* Do processing for the given job including updating |
* parents and starting new jobs as available/necessary. |
* parents and starting new jobs as available/necessary. |
* |
* |
* Side Effects: |
* Side Effects: |
* Some nodes may be put on the toBeMade queue. |
* Some nodes may be put on the toBeMade queue. |
|
|
int reason, code; |
int reason, code; |
bool done; |
bool done; |
|
|
debug_printf("Process %ld (%s) exited with status %d.\n", |
debug_printf("Process %ld (%s) exited with status %d.\n", |
(long)job->pid, job->node->name, status); |
(long)job->pid, job->node->name, status); |
/* parse status */ |
/* parse status */ |
if (WIFEXITED(status)) { |
if (WIFEXITED(status)) { |
|
|
|
|
if (done || DEBUG(JOB)) { |
if (done || DEBUG(JOB)) { |
if (reason == JOB_EXITED) { |
if (reason == JOB_EXITED) { |
debug_printf("Process %ld (%s) exited.\n", |
debug_printf("Process %ld (%s) exited.\n", |
(long)job->pid, job->node->name); |
(long)job->pid, job->node->name); |
if (code != 0) { |
if (code != 0) { |
banner(job, stdout); |
banner(job, stdout); |
(void)fprintf(stdout, "*** Error code %d %s\n", |
(void)fprintf(stdout, "*** Error code %d %s\n", |
code, |
code, |
(job->node->type & OP_IGNORE) ? |
(job->node->type & OP_IGNORE) ? |
"(ignored)" : ""); |
"(ignored)" : ""); |
|
|
if (job->node->type & OP_IGNORE) { |
if (job->node->type & OP_IGNORE) { |
|
|
} |
} |
} else if (DEBUG(JOB)) { |
} else if (DEBUG(JOB)) { |
(void)fprintf(stdout, |
(void)fprintf(stdout, |
"*** %ld (%s) Completed successfully\n", |
"*** %ld (%s) Completed successfully\n", |
(long)job->pid, job->node->name); |
(long)job->pid, job->node->name); |
} |
} |
} else { |
} else { |
|
|
} |
} |
free(job); |
free(job); |
|
|
if (errors && !keepgoing && |
if (errors && !keepgoing && |
aborting != ABORT_INTERRUPT) |
aborting != ABORT_INTERRUPT) |
aborting = ABORT_ERROR; |
aborting = ABORT_ERROR; |
|
|
|
|
Finish(errors); |
Finish(errors); |
} |
} |
|
|
static void |
static void |
prepare_pipe(struct job_pipe *p, int *fd) |
prepare_pipe(struct job_pipe *p, int *fd) |
{ |
{ |
p->pos = 0; |
p->pos = 0; |
(void)fcntl(fd[0], F_SETFD, FD_CLOEXEC); |
(void)fcntl(fd[0], F_SETFD, FD_CLOEXEC); |
p->fd = fd[0]; |
p->fd = fd[0]; |
close(fd[1]); |
close(fd[1]); |
|
|
if (output_mask == NULL || p->fd > largest_fd) { |
if (output_mask == NULL || p->fd > largest_fd) { |
|
|
ofdn = howmany(largest_fd+1, NFDBITS); |
ofdn = howmany(largest_fd+1, NFDBITS); |
|
|
if (fdn != ofdn) { |
if (fdn != ofdn) { |
output_mask = emult_realloc(output_mask, fdn, |
output_mask = emult_realloc(output_mask, fdn, |
sizeof(fd_mask)); |
sizeof(fd_mask)); |
memset(((char *)output_mask) + ofdn * sizeof(fd_mask), |
memset(((char *)output_mask) + ofdn * sizeof(fd_mask), |
0, (fdn-ofdn) * sizeof(fd_mask)); |
0, (fdn-ofdn) * sizeof(fd_mask)); |
actual_mask = emult_realloc(actual_mask, fdn, |
actual_mask = emult_realloc(actual_mask, fdn, |
sizeof(fd_mask)); |
sizeof(fd_mask)); |
mask_size = fdn * sizeof(fd_mask); |
mask_size = fdn * sizeof(fd_mask); |
} |
} |
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* JobExec -- |
* JobExec -- |
* Execute the shell for the given job. Called from JobStart |
* Execute the shell for the given job. Called from JobStart |
* |
* |
* Side Effects: |
* Side Effects: |
* A shell is executed, outputs is altered and the Job structure added |
* A shell is executed, outputs is altered and the Job structure added |
|
|
|
|
setup_engine(1); |
setup_engine(1); |
|
|
/* Create the pipe by which we'll get the shell's output. |
/* Create the pipe by which we'll get the shell's output. |
*/ |
*/ |
if (pipe(fdout) == -1) |
if (pipe(fdout) == -1) |
Punt("Cannot create pipe: %s", strerror(errno)); |
Punt("Cannot create pipe: %s", strerror(errno)); |
|
|
|
|
(void)fprintf(stdout, "Running %ld (%s)\n", (long)cpid, |
(void)fprintf(stdout, "Running %ld (%s)\n", (long)cpid, |
job->node->name); |
job->node->name); |
for (ln = Lst_First(&job->node->commands); ln != NULL ; |
for (ln = Lst_First(&job->node->commands); ln != NULL ; |
ln = Lst_Adv(ln)) |
ln = Lst_Adv(ln)) |
fprintf(stdout, "\t%s\n", (char *)Lst_Datum(ln)); |
fprintf(stdout, "\t%s\n", (char *)Lst_Datum(ln)); |
(void)fflush(stdout); |
(void)fflush(stdout); |
|
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
static void |
static void |
handle_pipe(struct job_pipe *p, |
handle_pipe(struct job_pipe *p, |
Job *job, FILE *out, bool finish) |
Job *job, FILE *out, bool finish) |
{ |
{ |
int nr; /* number of bytes read */ |
int nr; /* number of bytes read */ |
|
|
* Notes: |
* Notes: |
* We do waits, blocking or not, according to the wisdom of our |
* We do waits, blocking or not, according to the wisdom of our |
* caller, until there are no more children to report. For each |
* caller, until there are no more children to report. For each |
* job, call process_job_status to finish things off. |
* job, call process_job_status to finish things off. |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
void |
void |
|
|
* Job_Full -- |
* Job_Full -- |
* See if the job table is full. It is considered full |
* See if the job table is full. It is considered full |
* if we are in the process of aborting OR if we have |
* if we are in the process of aborting OR if we have |
* reached/exceeded our quota. |
* reached/exceeded our quota. |
* |
* |
* Results: |
* Results: |
* true if the job table is full, false otherwise |
* true if the job table is full, false otherwise |
|
|
{ |
{ |
if (Job_Full() || expensive_job) |
if (Job_Full() || expensive_job) |
return false; |
return false; |
else |
else |
return true; |
return true; |
} |
} |
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* Job_Empty -- |
* Job_Empty -- |
* See if the job table is empty. |
* See if the job table is empty. |
* |
* |
* Results: |
* Results: |
* true if it is. false if it ain't. |
* true if it is. false if it ain't. |
|
|
aborting = ABORT_ERROR; |
aborting = ABORT_ERROR; |
|
|
if (nJobs) { |
if (nJobs) { |
for (ln = Lst_First(&runningJobs); ln != NULL; |
for (ln = Lst_First(&runningJobs); ln != NULL; |
ln = Lst_Adv(ln)) { |
ln = Lst_Adv(ln)) { |
job = (Job *)Lst_Datum(ln); |
job = (Job *)Lst_Datum(ln); |
|
|