/* BKG_JOBSTATUS -- Print the status of one or more background jobs. * format jobno, elapsed clock time, status, user command, e.g.: * * [1] 1:34 Running command_1 * [2] 14:09 Stopped command_2 * [3] 1:34 +Done command_3 * [4] 1:34 Exit 23 command_4 * * A job will remain in the job table until another job is submitted which uses * the same slot. */ void bkg_jobstatus ( FILE *fp, /* output file */ int job /* job(s) */ ) { register struct _bkgjob *bk; register int j, n, ch; register char *ip; long seconds; char *outstr = NULL; bkg_update (1); for (bk=jobtable, j=1; j <= NBKG; j++, bk++) if ((job == 0 && bk->b_jobno) || job == j) { /* Print jobno. */ fprintf (fp, " [%d] ", j); /* If the clock is still running b_clock contains the start * time. If the job terminated it contains the elapsed time * at job termination. */ if (busy(j)) seconds = c_clktime (bk->b_clock); else seconds = bk->b_clock; fprintf (fp, "%6.0m ", (float)seconds / 60.0); fputc ((j == lastjobno) ? '+' : ' ', fp); /* Print job status. */ if (busy(j)) { if (bk->b_flags & J_SERVICE) outstr = "Stopped"; else outstr = "Running"; } else if (bk->b_flags & J_KILLED) { outstr = "Killed"; } else if (bk->b_exitcode == OK) { outstr = "Done"; } else sprintf (outstr, "Exit %d", bk->b_exitcode); fprintf (fp, "%-10s", outstr); /* Finally, print user command followed by newline. */ n = c_envgeti ("ttyncols") - (8 + 8 + 10) - 1; ip = bk->b_cmd; while (--n >= 0 && (ch = *ip++) != EOS) if (ch == '\n' || ch == '\t') fputc (' ', fp); else fputc (ch, fp); fputc ('\n', fp); } }
/* BKG_WAIT -- Wait for a background job to terminate. If job=0, wait for * all bkg jobs to terminate. */ void bkg_wait (register int job) { register int j; int active_jobs; if (job < 0 || job > NBKG) return; do { bkg_update (1); if (job && !busy(job)) return; else { for (active_jobs=0, j=1; j <= NBKG; j++) if (busy (j)) { active_jobs++; c_tsleep (WAIT_PERIOD); break; } } } while (active_jobs); }
/* BKG_KILL -- Kill a background job. If job=0, kill all background jobs. * If the job cannot be killed assume it is because it died unexpectedly. */ void bkg_kill (int job) { register struct _bkgjob *bk; register int j; bkg_update (1); if (job < 0 || job > NBKG) eprintf ("[%d] invalid job number\n", job); else { for (bk=jobtable, j=1; j <= NBKG; j++, bk++) { if ((job == 0 && busy(j)) || job == j) { if (!busy(j)) eprintf ("[%d] not in use\n", j); else if (c_prkill (bk->b_jobno) == ERR) bkg_close (j, 2); else { bk->b_flags |= J_KILLED; bkg_close (j, 2); } } } } }
/* BKG_JOBACTIVE -- Determine if a background job is active, i.e., if the * job is still running. It does not matter if the job is waiting for * service. */ int bkg_jobactive (int job) { bkg_update (1); return (busy (job)); }
/* BKG_SPAWN -- Spawn a new background job. Called by main() when we have * seen an '&'. */ void bkg_spawn ( char *cmd /* command entered by user to spawn job */ ) { register struct _bkgjob *bk; register int jobno, stat; char clprocess[SZ_PATHNAME]; char *wbkgfile(); char *bkgfile; /* Find first unused slot in a circular search. */ bkg_update (1); jobno = (lastjobno == NBKG) ? 1 : lastjobno + 1; while (jobno != lastjobno) { if (!busy (jobno)) break; if (jobno++ >= NBKG) jobno = 1; } if (jobno == lastjobno) cl_error (E_UERR, "no more background job slots"); /* Write bkgfile. Delete any dreg bkg communication files. */ bkg_delfiles (jobno); bkgfile = wbkgfile (jobno, cmd, NULL); /* Spawn bkg job. */ sprintf (clprocess, "%s%s", CLDIR, CLPROCESS); intr_disable(); jobtable[jobno-1].b_jobno = stat = c_propdpr (findexe (firstask->t_curpack, clprocess), bkgfile, bkgmsg); if (stat == NULL) { c_delete (bkgfile); intr_enable(); cl_error (E_IERR, "cannot spawn background CL"); } else { bk = &jobtable[jobno-1]; bk->b_flags = J_RUNNING; bk->b_clock = c_clktime (0L); bk->b_verbose = 2; strncpy (bk->b_cmd, cmd, SZ_CMD); *(bk->b_cmd+SZ_CMD) = EOS; intr_enable(); } eprintf ("[%d]\n", lastjobno = jobno); /* Make a logfile entry, saying we started the background job. */ if (keeplog() && log_background()) { char buf[SZ_LINE]; sprintf (buf, "Start [%d]", jobno); putlog (0, buf); } }
/* EXECUTE -- Each loop corresponds to an exec in the interpreted code. * This occurs when a script task or process is ready to run. In background * mode, we skip the preliminaries and jump right in and interpret the * compiled code. */ static void execute (int mode) { int parsestat; XINT old_parhead; char *curcmd(); alldone = 0; gologout = 0; if (mode == BACKGROUND) { if (setjmp (jumpcom)) onerr(); goto bkg; } /* Called when control stack contains only the firsttask. ONEOF sets * alldone true when eof/bye is seen and currentask=firstask, * terminating the loop and returning to main. */ do { /* Bkg_update() checks for blocked or finished bkg jobs and prints * a message if it finds one. This involves one or more access() * calls so don't call it more than every 5 seconds. The errenv * jump vector is used by cl_error() for error restart. The JUMPCOM * vector is used to intercept system errors which would otherwise * restart the CL. */ if (currentask->t_flags & T_INTERACTIVE) { static long last_clktime; if (c_clktime (last_clktime) > BKG_QUANTUM) { last_clktime = c_clktime (0L); bkg_update (1); } validerrenv = 1; setjmp (errenv); ninterrupts = 0; if (setjmp (jumpcom)) onerr(); } else if (!(currentask->t_flags & T_SCRIPT)) setjmp (intenv); pc = currentask->t_bascode; currentask->t_topd = topd; currentask->t_topcs = topcs; recursion = 0; errlev = 0; c_erract (OK); yeof = 0; /* In the new CL the parser needs to know more about parameters * than before. Hence param files may be read in during parsing. * Since we discard the dictionary after parsing we must unlink * these param files, and re-read them when the * program is run. This is inefficient but appears to work. */ old_parhead = parhead; if (gologout) yeof++; else { yy_startblock (LOG); /* start new history blk */ parsestat = yyparse(); /* parse command block */ topd = currentask->t_topd; /* discard addconst()'s */ topcs = currentask->t_topcs; /* discard compiler temps */ parhead = old_parhead; /* forget param files. */ if (parsestat != 0) cl_error (E_IERR, "parser gagged"); } if (dobkg) { bkg_spawn (curcmd()); } else { bkg: if (yeof) oneof(); /* restores previous task */ else { /* set stack above pc, point pc back to code */ topos = basos = pc - 1; pc = currentask->t_bascode; } if (!alldone) run(); /* run code starting at pc */ } } until (alldone); }