version 1.78, 2007/09/17 12:42:09 |
version 1.79, 2007/09/18 07:45:25 |
|
|
short flags; /* Flags to control treatment of job */ |
short flags; /* Flags to control treatment of job */ |
#define JOB_IGNERR 0x001 /* Ignore non-zero exits */ |
#define JOB_IGNERR 0x001 /* Ignore non-zero exits */ |
#define JOB_SILENT 0x002 /* no output */ |
#define JOB_SILENT 0x002 /* no output */ |
#define JOB_SPECIAL 0x004 /* Target is a special one. i.e., always run */ |
#define JOB_SPECIAL 0x004 /* Target is a special one. i.e. run it locally |
/* it even when the table is full */ |
* if we can't export it and maxLocal is 0 */ |
#define JOB_IGNDOTS 0x008 /* Ignore "..." lines when processing */ |
#define JOB_IGNDOTS 0x008 /* Ignore "..." lines when processing |
/* commands */ |
* commands */ |
#define JOB_FIRST 0x020 /* Job is first job for the node */ |
#define JOB_FIRST 0x020 /* Job is first job for the node */ |
#define JOB_RESTART 0x080 /* Job needs to be completely restarted */ |
#define JOB_RESTART 0x080 /* Job needs to be completely restarted */ |
#define JOB_RESUME 0x100 /* Job needs to be resumed b/c it stopped, */ |
#define JOB_RESUME 0x100 /* Job needs to be resumed b/c it stopped, |
/* for some reason */ |
* for some reason */ |
#define JOB_CONTINUING 0x200 /* We are in the process of resuming this job */ |
#define JOB_CONTINUING 0x200 /* We are in the process of resuming this job. |
/* Used to avoid infinite recursion between */ |
* Used to avoid infinite recursion between |
/* JobFinish and JobRestart */ |
* JobFinish and JobRestart */ |
int inPipe; /* Input side of pipe associated |
int inPipe; /* Input side of pipe associated |
* with job's output channel */ |
* with job's output channel */ |
int outPipe; /* Output side of pipe associated with |
int outPipe; /* Output side of pipe associated with |
|
|
|
|
|
|
static int maxJobs; /* The most children we can run at once */ |
static int maxJobs; /* The most children we can run at once */ |
|
static int maxLocal; /* The most local ones we can have */ |
static int nJobs = 0; /* The number of children currently running */ |
static int nJobs = 0; /* The number of children currently running */ |
|
static int nLocal; /* The number of local children */ |
static LIST jobs; /* The structures that describe them */ |
static LIST jobs; /* The structures that describe them */ |
static bool jobFull; /* Flag to tell when the job table is full. */ |
static bool jobFull; /* Flag to tell when the job table is full. It |
|
* is set true when (1) the total number of |
|
* running jobs equals the maximum allowed or |
|
* (2) a job can only be run locally, but |
|
* nLocal equals maxLocal */ |
static fd_set *outputsp; /* Set of descriptors of pipes connected to |
static fd_set *outputsp; /* Set of descriptors of pipes connected to |
* the output channels of children */ |
* the output channels of children */ |
static int outputsn; |
static int outputsn; |
|
|
(long)job->pid); |
(long)job->pid); |
(void)fflush(stdout); |
(void)fflush(stdout); |
} |
} |
|
nLocal++; |
if (nJobs == maxJobs) { |
if (nJobs == maxJobs) { |
jobFull = true; |
jobFull = true; |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
|
|
} |
} |
} |
} |
|
|
|
nLocal += 1; |
/* |
/* |
* Now the job is actually running, add it to the table. |
* Now the job is actually running, add it to the table. |
*/ |
*/ |
|
|
job->node->name); |
job->node->name); |
(void)fflush(stdout); |
(void)fflush(stdout); |
} |
} |
if (nJobs >= maxJobs && !(job->flags & JOB_SPECIAL)) { |
if (nLocal >= maxLocal && !(job->flags & JOB_SPECIAL)) { |
/* |
/* |
* Can't be exported and not allowed to run locally -- |
* Can't be exported and not allowed to run locally -- put |
* put it back on the hold queue and mark the table |
* it back on the hold queue and mark the table full |
* full |
*/ |
*/ |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void)fprintf(stdout, "holding\n"); |
(void)fprintf(stdout, "holding\n"); |
(void)fflush(stdout); |
(void)fflush(stdout); |
} |
} |
Lst_AtFront(&stoppedJobs, job); |
Lst_AtFront(&stoppedJobs, job); |
jobFull = true; |
jobFull = true; |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void)fprintf(stdout, "Job queue is full.\n"); |
(void)fprintf(stdout, "Job queue is full.\n"); |
(void)fflush(stdout); |
(void)fflush(stdout); |
} |
} |
return; |
return; |
|
} else { |
} else { |
/* |
/* |
* Job may be run locally. |
* Job may be run locally. |
*/ |
*/ |
if (DEBUG(JOB)) { |
if (DEBUG(JOB)) { |
(void)fprintf(stdout, "running locally\n"); |
(void)fprintf(stdout, "running locally\n"); |
(void)fflush(stdout); |
(void)fflush(stdout); |
} |
} |
} |
} |
JobExec(job, argv); |
JobExec(job, argv); |
} else { |
} else { |
|
|
(void)fprintf(stdout, "Resuming %s...", job->node->name); |
(void)fprintf(stdout, "Resuming %s...", job->node->name); |
(void)fflush(stdout); |
(void)fflush(stdout); |
} |
} |
if (nJobs != maxJobs || (job->flags & JOB_SPECIAL)) { |
if ((nLocal < maxLocal || ((job->flags & JOB_SPECIAL) && |
|
maxLocal == 0)) && nJobs != maxJobs) { |
/* |
/* |
* If we haven't reached the concurrency limit already, |
* If we haven't reached the concurrency limit already |
* it's ok to resume the job. |
* (or maxLocal is 0), it's ok to resume the job. |
*/ |
*/ |
bool error; |
bool error; |
int status; |
int status; |
|
|
|
|
local = true; |
local = true; |
|
|
if (nJobs >= maxJobs && !(job->flags & JOB_SPECIAL)) { |
if (local && nLocal >= maxLocal && !(job->flags & JOB_SPECIAL) && |
/* we've hit the limit of concurrency, so put the job on hold |
maxLocal != 0) { |
* until some other job finishes. |
/* |
|
* The job can only be run locally, but we've hit the limit of |
|
* local concurrency, so put the job on hold until some other |
|
* job finishes. Note that the special jobs (.BEGIN, .INTERRUPT |
|
* and .END) may be run locally even when the local limit has |
|
* been reached (e.g. when maxLocal == 0), though they will be |
|
* exported if at all possible. In addition, any target marked |
|
* with .NOEXPORT will be run locally if maxLocal is 0. |
*/ |
*/ |
jobFull = true; |
jobFull = true; |
|
|
|
|
} |
} |
job->flags |= JOB_RESTART; |
job->flags |= JOB_RESTART; |
Lst_AtEnd(&stoppedJobs, job); |
Lst_AtEnd(&stoppedJobs, job); |
|
} else { |
|
if (nLocal >= maxLocal && local) { |
|
/* |
|
* If we're running this job locally as a special case |
|
* (see above), at least say the table is full. |
|
*/ |
|
jobFull = true; |
|
if (DEBUG(JOB)) { |
|
(void)fprintf(stdout, |
|
"Local job queue is full.\n"); |
|
(void)fflush(stdout); |
|
} |
|
} |
|
JobExec(job, argv); |
} |
} |
return JOB_RUNNING; |
return JOB_RUNNING; |
} |
} |
|
|
/* |
/* |
* Don't even bother if we know there's no one around. |
* Don't even bother if we know there's no one around. |
*/ |
*/ |
if (nJobs == 0) { |
if (nLocal == 0) { |
return; |
return; |
} |
} |
|
|
|
|
(void)fflush(stdout); |
(void)fflush(stdout); |
} |
} |
jobFull = false; |
jobFull = false; |
|
nLocal--; |
} |
} |
|
|
JobFinish(job, &status); |
JobFinish(job, &status); |
|
|
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
*/ |
*/ |
void |
void |
Job_Init(int maxproc) |
Job_Init(int maxproc, int maxlocal) |
{ |
{ |
int tfd; |
int tfd; |
|
|
|
|
Static_Lst_Init(&jobs); |
Static_Lst_Init(&jobs); |
Static_Lst_Init(&stoppedJobs); |
Static_Lst_Init(&stoppedJobs); |
maxJobs = maxproc; |
maxJobs = maxproc; |
|
maxLocal = maxlocal; |
|
nJobs = 0; |
|
nLocal = 0; |
jobFull = false; |
jobFull = false; |
|
|
aborting = 0; |
aborting = 0; |