summary refs log tree commit diff
path: root/Src
diff options
context:
space:
mode:
Diffstat (limited to 'Src')
-rw-r--r--Src/Modules/parameter.c12
-rw-r--r--Src/Zle/compctl.c2
-rw-r--r--Src/builtin.c4
-rw-r--r--Src/exec.c12
-rw-r--r--Src/init.c9
-rw-r--r--Src/jobs.c188
-rw-r--r--Src/prompt.c4
-rw-r--r--Src/signals.c2
-rw-r--r--Src/zsh.h7
9 files changed, 187 insertions, 53 deletions
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 <linux/tasks.h>
-#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 {