From a6a63a147e4e28a1ac700938c6e7694c6de97e5d Mon Sep 17 00:00:00 2001 From: Peter Stephenson Date: Thu, 13 Nov 2003 14:34:33 +0000 Subject: 19242: Make job table dynamically reallocatable. --- Src/Modules/parameter.c | 12 ++-- Src/Zle/compctl.c | 2 +- Src/builtin.c | 4 +- Src/exec.c | 12 +++- Src/init.c | 9 ++- Src/jobs.c | 188 +++++++++++++++++++++++++++++++++++++++--------- Src/prompt.c | 4 +- Src/signals.c | 2 +- Src/zsh.h | 7 +- 9 files changed, 187 insertions(+), 53 deletions(-) (limited to 'Src') diff --git a/Src/Modules/parameter.c b/Src/Modules/parameter.c index eb03b9d7d..5a09bd23c 100644 --- a/Src/Modules/parameter.c +++ b/Src/Modules/parameter.c @@ -1181,7 +1181,7 @@ getpmjobtext(HashTable ht, char *name) pm->old = NULL; pm->level = 0; - if ((job = atoi(name)) >= 1 && job < MAXJOB && + if ((job = atoi(name)) >= 1 && job <= maxjob && jobtab[job].stat && jobtab[job].procs && !(jobtab[job].stat & STAT_NOPRINT)) pm->u.str = pmjobtext(job); @@ -1210,7 +1210,7 @@ scanpmjobtexts(HashTable ht, ScanFunc func, int flags) pm.old = NULL; pm.level = 0; - for (job = 1; job < MAXJOB; job++) { + for (job = 1; job <= maxjob; job++) { if (jobtab[job].stat && jobtab[job].procs && !(jobtab[job].stat & STAT_NOPRINT)) { if (func != scancountparams) { @@ -1291,7 +1291,7 @@ getpmjobstate(HashTable ht, char *name) pm->old = NULL; pm->level = 0; - if ((job = atoi(name)) >= 1 && job < MAXJOB && + if ((job = atoi(name)) >= 1 && job <= maxjob && jobtab[job].stat && jobtab[job].procs && !(jobtab[job].stat & STAT_NOPRINT)) pm->u.str = pmjobstate(job); @@ -1320,7 +1320,7 @@ scanpmjobstates(HashTable ht, ScanFunc func, int flags) pm.old = NULL; pm.level = 0; - for (job = 1; job < MAXJOB; job++) { + for (job = 1; job <= maxjob; job++) { if (jobtab[job].stat && jobtab[job].procs && !(jobtab[job].stat & STAT_NOPRINT)) { if (func != scancountparams) { @@ -1366,7 +1366,7 @@ getpmjobdir(HashTable ht, char *name) pm->old = NULL; pm->level = 0; - if ((job = atoi(name)) >= 1 && job < MAXJOB && + if ((job = atoi(name)) >= 1 && job <= maxjob && jobtab[job].stat && jobtab[job].procs && !(jobtab[job].stat & STAT_NOPRINT)) pm->u.str = pmjobdir(job); @@ -1395,7 +1395,7 @@ scanpmjobdirs(HashTable ht, ScanFunc func, int flags) pm.old = NULL; pm.level = 0; - for (job = 1; job < MAXJOB; job++) { + for (job = 1; job <= maxjob; job++) { if (jobtab[job].stat && jobtab[job].procs && !(jobtab[job].stat & STAT_NOPRINT)) { if (func != scancountparams) { diff --git a/Src/Zle/compctl.c b/Src/Zle/compctl.c index f55deff5c..6e8fcb982 100644 --- a/Src/Zle/compctl.c +++ b/Src/Zle/compctl.c @@ -3631,7 +3631,7 @@ makecomplistflags(Compctl cc, char *s, int incmd, int compadd) int i; char *j; - for (i = 0; i < MAXJOB; i++) + for (i = 0; i <= maxjob; i++) if ((jobtab[i].stat & STAT_INUSE) && jobtab[i].procs && jobtab[i].procs->text) { int stopped = jobtab[i].stat & STAT_STOPPED; diff --git a/Src/builtin.c b/Src/builtin.c index 3f6295639..23946aba3 100644 --- a/Src/builtin.c +++ b/Src/builtin.c @@ -3981,11 +3981,11 @@ checkjobs(void) { int i; - for (i = 1; i < MAXJOB; i++) + for (i = 1; i <= maxjob; i++) if (i != thisjob && (jobtab[i].stat & STAT_LOCKED) && !(jobtab[i].stat & STAT_NOPRINT)) break; - if (i < MAXJOB) { + if (i <= maxjob) { if (jobtab[i].stat & STAT_STOPPED) { #ifdef USE_SUSPENDED diff --git a/Src/exec.c b/Src/exec.c index 2d9f7ed26..bb4194d52 100644 --- a/Src/exec.c +++ b/Src/exec.c @@ -216,7 +216,10 @@ zfork(void) { pid_t pid; - if (thisjob >= MAXJOB - 1) { + /* + * Is anybody willing to explain this test? + */ + if (thisjob >= jobtabsize - 1 && !expandjobtab()) { zerr("job table full", NULL, 0); return -1; } @@ -1024,7 +1027,12 @@ execpline(Estate state, wordcode slcode, int how, int last1) ipipe[0] = ipipe[1] = opipe[0] = opipe[1] = 0; child_block(); - /* get free entry in job table and initialize it */ + /* + * Get free entry in job table and initialize it. + * This is currently the only call to initjob(), so this + * is also the only place where we can expand the job table + * under us. + */ if ((thisjob = newjob = initjob()) == -1) { child_unblock(); return 1; diff --git a/Src/init.c b/Src/init.c index 0befe5e9b..b4b7e6f97 100644 --- a/Src/init.c +++ b/Src/init.c @@ -1207,7 +1207,7 @@ zsh_main(int argc, char **argv) setlocale(LC_ALL, ""); #endif - init_hackzero(argv, environ); + init_jobs(argv, environ); /* * Provisionally set up the type table to allow metafication. @@ -1261,6 +1261,13 @@ zsh_main(int argc, char **argv) init_misc(); for (;;) { + /* + * See if we can free up some of jobtab. + * We only do this at top level, because if we are + * executing stuff we may refer to them by job pointer. + */ + maybeshrinkjobtab(); + do loop(1,0); while (tok != ENDINPUT && (tok != LEXERR || isset(SHINSTDIN))); diff --git a/Src/jobs.c b/Src/jobs.c index 5599d549f..be44158c6 100644 --- a/Src/jobs.c +++ b/Src/jobs.c @@ -59,7 +59,17 @@ mod_export int prevjob; /* the job table */ /**/ -mod_export struct job jobtab[MAXJOB]; +mod_export struct job *jobtab; + +/* Size of the job table. */ + +/**/ +mod_export size_t jobtabsize; + +/* The highest numbered job in the jobtable */ + +/**/ +mod_export size_t maxjob; /* If we have entered a subshell, the original shell's job table. */ static struct job *oldjobtab; @@ -135,7 +145,7 @@ findproc(pid_t pid, Job *jptr, Process *pptr, int aux) Process pn; int i; - for (i = 1; i < MAXJOB; i++) + for (i = 1; i <= maxjob; i++) { for (pn = aux ? jobtab[i].auxprocs : jobtab[i].procs; pn; pn = pn->next) @@ -168,7 +178,7 @@ super_job(int sub) { int i; - for (i = 1; i < MAXJOB; i++) + for (i = 1; i <= maxjob; i++) if ((jobtab[i].stat & STAT_SUPERJOB) && jobtab[i].other == sub && jobtab[i].gleader) @@ -446,14 +456,14 @@ setprevjob(void) { int i; - for (i = MAXJOB - 1; i; i--) + for (i = maxjob; i; i--) if ((jobtab[i].stat & STAT_INUSE) && (jobtab[i].stat & STAT_STOPPED) && !(jobtab[i].stat & STAT_SUBJOB) && i != curjob && i != thisjob) { prevjob = i; return; } - for (i = MAXJOB - 1; i; i--) + for (i = maxjob; i; i--) if ((jobtab[i].stat & STAT_INUSE) && !(jobtab[i].stat & STAT_SUBJOB) && i != curjob && i != thisjob) { prevjob = i; @@ -650,7 +660,10 @@ printjob(Job jn, int lng, int synch) if (jn->stat & STAT_NOPRINT) return; - if (jn < jobtab || jn >= jobtab + MAXJOB) + /* + * Wow, what a hack. Did I really write this? --- pws + */ + if (jn < jobtab || jn >= jobtab + jobtabsize) job = jn - oldjobtab; else job = jn - jobtab; @@ -838,15 +851,24 @@ freejob(Job jn, int deleting) zsfree(jn->pwd); jn->pwd = NULL; if (jn->stat & STAT_WASSUPER) { + /* careful in case we shrink and move the job table */ + int job = jn - jobtab; if (deleting) deletejob(jobtab + jn->other); else freejob(jobtab + jn->other, 0); + jn = jobtab + job; } jn->gleader = jn->other = 0; jn->stat = jn->stty_in_env = 0; jn->filelist = NULL; jn->ty = NULL; + + /* Find the new highest job number. */ + if (maxjob == jn - jobtab) { + while (maxjob && !(jobtab[maxjob].stat & STAT_INUSE)) + maxjob--; + } } /* @@ -932,7 +954,7 @@ havefiles(void) { int i; - for (i = 1; i < MAXJOB; i++) + for (i = 1; i <= maxjob; i++) if (jobtab[i].stat && jobtab[i].filelist) return 1; return 0; @@ -1032,7 +1054,7 @@ clearjobtab(int monitor) { int i; - for (i = 1; i < MAXJOB; i++) { + for (i = 1; i <= maxjob; i++) { /* * See if there is a jobtable worth saving. * We never free the saved version; it only happens @@ -1054,6 +1076,21 @@ clearjobtab(int monitor) memset(jobtab, 0, sizeof(jobtab)); /* zero out table */ } +static int initnewjob(int i) +{ + jobtab[i].stat = STAT_INUSE; + if (jobtab[i].pwd) { + zsfree(jobtab[i].pwd); + jobtab[i].pwd = NULL; + } + jobtab[i].gleader = 0; + + if (i > maxjob) + maxjob = i; + + return i; +} + /* Get a free entry in the job table and initialize it. */ /**/ @@ -1062,16 +1099,12 @@ initjob(void) { int i; - for (i = 1; i < MAXJOB; i++) - if (!jobtab[i].stat) { - jobtab[i].stat = STAT_INUSE; - if (jobtab[i].pwd) { - zsfree(jobtab[i].pwd); - jobtab[i].pwd = NULL; - } - jobtab[i].gleader = 0; - return i; - } + for (i = 1; i < jobtabsize; i++) + if (!jobtab[i].stat) + return initnewjob(i); + + if (expandjobtab()) + return initnewjob(i); zerr("job table full or recursion limit exceeded", NULL, 0); return -1; @@ -1083,7 +1116,7 @@ setjobpwd(void) { int i; - for (i = 1; i < MAXJOB; i++) + for (i = 1; i <= maxjob; i++) if (jobtab[i].stat && !jobtab[i].pwd) jobtab[i].pwd = ztrdup(pwd); } @@ -1144,7 +1177,7 @@ scanjobs(void) { int i; - for (i = 1; i < MAXJOB; i++) + for (i = 1; i <= maxjob; i++) if (jobtab[i].stat & STAT_CHANGED) printjob(jobtab + i, 0, 1); } @@ -1220,7 +1253,7 @@ getjob(char *s, char *prog) /* a digit here means we have a job number */ if (idigit(*s)) { jobnum = atoi(s); - if (jobnum && jobnum < MAXJOB && jobtab[jobnum].stat && + if (jobnum && jobnum <= maxjob && jobtab[jobnum].stat && !(jobtab[jobnum].stat & STAT_SUBJOB) && jobnum != thisjob) { returnval = jobnum; goto done; @@ -1233,7 +1266,7 @@ getjob(char *s, char *prog) if (*s == '?') { struct process *pn; - for (jobnum = MAXJOB - 1; jobnum >= 0; jobnum--) + for (jobnum = maxjob; jobnum >= 0; jobnum--) if (jobtab[jobnum].stat && !(jobtab[jobnum].stat & STAT_SUBJOB) && jobnum != thisjob) for (pn = jobtab[jobnum].procs; pn; pn = pn->next) @@ -1267,17 +1300,33 @@ getjob(char *s, char *prog) static char *hackzero; static int hackspace; -/* Initialise the jobs -Z system. The technique is borrowed from perl: * - * check through the argument and environment space, to see how many of * - * the strings are in contiguous space. This determines the value of * - * hackspace. */ + +/* Initialise job handling. */ /**/ void -init_hackzero(char **argv, char **envp) +init_jobs(char **argv, char **envp) { char *p, *q; - + size_t init_bytes = MAXJOBS_ALLOC*sizeof(struct job); + + /* + * Initialise the job table. If this fails, we're in trouble. + */ + jobtab = (struct job *)zalloc(init_bytes); + if (!jobtab) { + zerr("failed to allocate job table, aborting.", NULL, 0); + exit(1); + } + jobtabsize = MAXJOBS_ALLOC; + memset(jobtab, 0, init_bytes); + + /* + * Initialise the jobs -Z system. The technique is borrowed from + * perl: check through the argument and environment space, to see + * how many of the strings are in contiguous space. This determines + * the value of hackspace. + */ hackzero = *argv; p = strchr(hackzero, 0); while(*++argv) { @@ -1296,6 +1345,77 @@ init_hackzero(char **argv, char **envp) hackspace = p - hackzero; } + +/* + * We have run out of space in the job table. + * Expand it by an additional MAXJOBS_ALLOC slots. + */ + +/* + * An arbitrary limit on the absolute maximum size of the job table. + * This prevents us taking over the entire universe. + * Ought to be a multiple of MAXJOBS_ALLOC, but doesn't need to be. + */ +#define MAX_MAXJOBS 1000 + +/**/ +int +expandjobtab(void) +{ + size_t newsize = jobtabsize + MAXJOBS_ALLOC; + struct job *newjobtab; + + if (newsize > MAX_MAXJOBS) + return 0; + + newjobtab = (struct job *)zrealloc(jobtab, newsize * sizeof(struct job)); + if (!newjobtab) + return 0; + + /* + * Clear the new section of the table; this is necessary for + * the jobs to appear unused. + */ + memset(newjobtab + jobtabsize, 0, MAXJOBS_ALLOC * sizeof(struct job)); + + jobtab = newjobtab; + jobtabsize = newsize; + + return 1; +} + + +/* + * See if we can reduce the job table. We can if we go over + * a MAXJOBS_ALLOC boundary. However, we leave a boundary, + * currently 20 jobs, so that we have a place for immediate + * expansion and don't play ping pong with the job table size. + */ + +/**/ +void +maybeshrinkjobtab(void) +{ + size_t jobbound; + + queue_signals(); + jobbound = maxjob + MAXJOBS_ALLOC - (maxjob % MAXJOBS_ALLOC); + if (jobbound < jobtabsize && jobbound > maxjob + 20) { + struct job *newjobtab; + + /* Hope this can't fail, but anyway... */ + newjobtab = (struct job *)zrealloc(jobtab, + jobbound*sizeof(struct job)); + + if (newjobtab) { + jobtab = newjobtab; + jobtabsize = jobbound; + } + } + unqueue_signals(); +} + + /* bg, disown, fg, jobs, wait: most of the job control commands are * * here. They all take the same type of argument. Exception: wait can * * take a pid or a job specifier, whereas the others only work on jobs. */ @@ -1365,17 +1485,17 @@ bin_fg(char *name, char **argv, Options ops, int func) } else if (func == BIN_JOBS) { /* List jobs. */ struct job *jobptr; - int maxjob, ignorejob; + int curmaxjob, ignorejob; if (unset(MONITOR) && oldmaxjob) { jobptr = oldjobtab; - maxjob = oldmaxjob; + curmaxjob = oldmaxjob; ignorejob = 0; } else { jobptr = jobtab; - maxjob = MAXJOB; + curmaxjob = maxjob; ignorejob = thisjob; } - for (job = 0; job != maxjob; job++, jobptr++) + for (job = 0; job != curmaxjob; job++, jobptr++) if (job != ignorejob && jobptr->stat) { if ((!OPT_ISSET(ops,'r') && !OPT_ISSET(ops,'s')) || (OPT_ISSET(ops,'r') && OPT_ISSET(ops,'s')) || @@ -1387,7 +1507,7 @@ bin_fg(char *name, char **argv, Options ops, int func) unqueue_signals(); return 0; } else { /* Must be BIN_WAIT, so wait for all jobs */ - for (job = 0; job != MAXJOB; job++) + for (job = 0; job <= maxjob; job++) if (job != thisjob && jobtab[job].stat) zwaitjob(job, SIGINT); unqueue_signals(); @@ -1731,7 +1851,7 @@ findjobnam(char *s) { int jobnum; - for (jobnum = MAXJOB - 1; jobnum >= 0; jobnum--) + for (jobnum = maxjob; jobnum >= 0; jobnum--) if (!(jobtab[jobnum].stat & (STAT_SUBJOB | STAT_NOPRINT)) && jobtab[jobnum].stat && jobtab[jobnum].procs && jobnum != thisjob && jobtab[jobnum].procs->text && strpfx(s, jobtab[jobnum].procs->text)) diff --git a/Src/prompt.c b/Src/prompt.c index 1b847f879..7f964aad5 100644 --- a/Src/prompt.c +++ b/Src/prompt.c @@ -291,7 +291,7 @@ putpromptchar(int doprint, int endchar) test = 1; break; case 'j': - for (numjobs = 0, j = 1; j < MAXJOB; j++) + for (numjobs = 0, j = 1; j <= maxjob; j++) if (jobtab[j].stat && jobtab[j].procs && !(jobtab[j].stat & STAT_NOPRINT)) numjobs++; if (numjobs >= arg) @@ -383,7 +383,7 @@ putpromptchar(int doprint, int endchar) bp += strlen(bp); break; case 'j': - for (numjobs = 0, j = 1; j < MAXJOB; j++) + for (numjobs = 0, j = 1; j <= maxjob; j++) if (jobtab[j].stat && jobtab[j].procs && !(jobtab[j].stat & STAT_NOPRINT)) numjobs++; addbufspc(DIGBUFSIZE); diff --git a/Src/signals.c b/Src/signals.c index 86a5de748..6863421fe 100644 --- a/Src/signals.c +++ b/Src/signals.c @@ -582,7 +582,7 @@ killrunjobs(int from_signal) if (unset(HUP)) return; - for (i = 1; i < MAXJOB; i++) + for (i = 1; i <= maxjob; i++) if ((from_signal || i != thisjob) && (jobtab[i].stat & STAT_LOCKED) && !(jobtab[i].stat & STAT_NOPRINT) && !(jobtab[i].stat & STAT_STOPPED)) { diff --git a/Src/zsh.h b/Src/zsh.h index 158717dea..f60fa5f45 100644 --- a/Src/zsh.h +++ b/Src/zsh.h @@ -684,10 +684,6 @@ struct eccstr { /* Definitions for job table and job control */ /********************************************/ -#ifdef NEED_LINUX_TASKS_H -#include -#endif - /* entry in the job table */ struct job { @@ -731,6 +727,9 @@ struct timeinfo { #define JOBTEXTSIZE 80 +/* Size to initialise the job table to, and to increment it by when needed. */ +#define MAXJOBS_ALLOC (50) + /* node in job process lists */ struct process { -- cgit 1.4.1