void showjobs(int change, int mode) { int jobno; struct job *jp; TRACE(("showjobs(%d) called\n", change)); checkzombies(); for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) { if (! jp->used) continue; if (jp->nprocs == 0) { freejob(jp); continue; } if (change && ! jp->changed) continue; showjob(jp, mode); jp->changed = 0; /* Hack: discard jobs for which $! has not been referenced * in interactive mode when they terminate. */ if (jp->state == JOBDONE && !jp->remembered && (iflag || jp != bgjob)) { freejob(jp); } } }
void freejobs() { struct job *jp; collectjobs(WNOHANG); if (jobnote) { int savefd = setb(2); for (jp = joblst; jp; jp = jp->j_nxtp) { if (jp->j_flag & J_NOTIFY) { if (jp->j_jid) printjob(jp, PR_DFL); else if (jp->j_flag & J_FOREGND) printjob(jp, PR_STAT); else printjob(jp, PR_STAT|PR_PGID); } } (void) setb(savefd); } if (jobdone) { for (jp = joblst; jp; jp = jp->j_nxtp) { if (jp->j_flag & J_DONE) freejob(jp); } } }
int waitcmd(int argc, char **argv) { struct job *job; int status, retval; struct job *jp; nextopt(""); if (!*argptr) { /* wait for all jobs */ jp = jobtab; if (jobs_invalid) return 0; for (;;) { if (jp >= jobtab + njobs) { /* no running procs */ return 0; } if (!jp->used || jp->state != JOBRUNNING) { jp++; continue; } if (dowait(WBLOCK, NULL) == -1) return 128 + SIGINT; jp = jobtab; } } retval = 127; /* XXXGCC: -Wuninitialized */ for (; *argptr; argptr++) { job = getjob(*argptr, 1); if (!job) { retval = 127; continue; } /* loop until process terminated or stopped */ while (job->state == JOBRUNNING) { if (dowait(WBLOCK|WNOFREE, job) == -1) return 128 + SIGINT; } status = job->ps[job->nprocs ? job->nprocs - 1 : 0].status; if (WIFEXITED(status)) retval = WEXITSTATUS(status); #if JOBS else if (WIFSTOPPED(status)) retval = WSTOPSIG(status) + 128; #endif else { /* XXX: limits number of signals */ retval = WTERMSIG(status) + 128; } if (!iflag) freejob(job); } return retval; }
struct job * makejob(union node *node, int nprocs) { int i; struct job *jp; if (jobs_invalid) { for (i = njobs, jp = jobtab ; --i >= 0 ; jp++) { if (jp->used) freejob(jp); } jobs_invalid = 0; } for (i = njobs, jp = jobtab ; ; jp++) { if (--i < 0) { INTOFF; if (njobs == 0) { jobtab = ckmalloc(4 * sizeof jobtab[0]); } else { jp = ckmalloc((njobs + 4) * sizeof jobtab[0]); memcpy(jp, jobtab, njobs * sizeof jp[0]); /* Relocate `ps' pointers */ for (i = 0; i < njobs; i++) if (jp[i].ps == &jobtab[i].ps0) jp[i].ps = &jp[i].ps0; ckfree(jobtab); jobtab = jp; } jp = jobtab + njobs; for (i = 4 ; --i >= 0 ; ) jobtab[njobs++].used = 0; INTON; break; } if (jp->used == 0) break; } INTOFF; jp->state = JOBRUNNING; jp->used = 1; jp->changed = 0; jp->nprocs = 0; #if JOBS jp->jobctl = jobctl; set_curjob(jp, 1); #endif if (nprocs > 1) { jp->ps = ckmalloc(nprocs * sizeof (struct procstat)); } else { jp->ps = &jp->ps0; } INTON; TRACE(("makejob(0x%lx, %d) returns %%%d\n", (long)node, nprocs, jp - jobtab + 1)); return jp; }
int waitforjob(struct job *jp) { #if JOBS int mypgrp = getpgrp(); #endif int status; int st; INTOFF; TRACE(("waitforjob(%%%d) called\n", jp - jobtab + 1)); while (jp->state == JOBRUNNING) { dowait(WBLOCK, jp); } #if JOBS if (jp->jobctl) { if (tcsetpgrp(ttyfd, mypgrp) == -1) error("Cannot set tty process group (%s) at %d", strerror(errno), __LINE__); } if (jp->state == JOBSTOPPED && curjob != jp - jobtab) set_curjob(jp, 2); #endif status = jp->ps[jp->nprocs - 1].status; /* convert to 8 bits */ if (WIFEXITED(status)) st = WEXITSTATUS(status); #if JOBS else if (WIFSTOPPED(status)) st = WSTOPSIG(status) + 128; #endif else st = WTERMSIG(status) + 128; TRACE(("waitforjob: job %d, nproc %d, status %x, st %x\n", jp - jobtab + 1, jp->nprocs, status, st )); #if JOBS if (jp->jobctl) { /* * This is truly gross. * If we're doing job control, then we did a TIOCSPGRP which * caused us (the shell) to no longer be in the controlling * session -- so we wouldn't have seen any ^C/SIGINT. So, we * intuit from the subprocess exit status whether a SIGINT * occurred, and if so interrupt ourselves. Yuck. - mycroft */ if (WIFSIGNALED(status) && WTERMSIG(status) == SIGINT) raise(SIGINT); } #endif if (! JOBS || jp->state == JOBDONE) freejob(jp); INTON; return st; }
int waitcmd(int argc, char **argv) { struct job *job; int status, retval; struct job *jp; if (argc > 1) { job = getjob(argv[1]); } else { job = NULL; } /* * Loop until a process is terminated or stopped, or a SIGINT is * received. */ in_waitcmd++; do { if (job != NULL) { if (job->state) { status = job->ps[job->nprocs - 1].status; if (WIFEXITED(status)) retval = WEXITSTATUS(status); #if JOBS else if (WIFSTOPPED(status)) retval = WSTOPSIG(status) + 128; #endif else retval = WTERMSIG(status) + 128; if (! iflag) freejob(job); in_waitcmd--; return retval; } } else { for (jp = jobtab ; ; jp++) { if (jp >= jobtab + njobs) { /* no running procs */ in_waitcmd--; return 0; } if (jp->used && jp->state == 0) break; } } } while (dowait(1, (struct job *)NULL) != -1); in_waitcmd--; return 0; }
void showjobs(int change, int sformat, int lformat) { int jobno; struct job *jp; TRACE(("showjobs(%d) called\n", change)); while (dowait(0, (struct job *)NULL) > 0); for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) { if (! jp->used) continue; if (jp->nprocs == 0) { freejob(jp); continue; } if (change && ! jp->changed) continue; showjob(jp, 0, sformat, lformat); jp->changed = 0; if (jp->state == JOBDONE) { freejob(jp); } } }
void showjobs(struct output *out, int mode) { int jobno; struct job *jp; int silent = 0, gotpid; TRACE(("showjobs(%x) called\n", mode)); /* If not even one one job changed, there is nothing to do */ gotpid = dowait(0, NULL); while (dowait(0, NULL) > 0) continue; #ifdef JOBS /* * Check if we are not in our foreground group, and if not * put us in it. */ if (mflag && gotpid != -1 && tcgetpgrp(ttyfd) != getpid()) { if (tcsetpgrp(ttyfd, getpid()) == -1) error("Cannot set tty process group (%s) at %d", strerror(errno), __LINE__); TRACE(("repaired tty process group\n")); silent = 1; } #endif if (jobs_invalid) return; for (jobno = 1, jp = jobtab ; jobno <= njobs ; jobno++, jp++) { if (!jp->used) continue; if (jp->nprocs == 0) { freejob(jp); continue; } if ((mode & SHOW_CHANGED) && !jp->changed) continue; if (silent && jp->changed) { jp->changed = 0; continue; } showjob(out, jp, mode); } }
static void io(void) { long n; uint8_t mdata[IOHDRSZ + Maxfdata]; struct job *job; pthread_attr_t pth_attr; /* * each request is handled via a thread. Somewhat less efficient than * the old cs but way cleaner. */ pthread_attr_init(&pth_attr); pthread_attr_setdetachstate(&pth_attr, PTHREAD_CREATE_DETACHED); for (;;) { n = read9pmsg(mfd[0], mdata, sizeof(mdata)); if (n <= 0) error(1, 0, "%s: %r", "mount read"); job = newjob(); if (convM2S(mdata, n, &job->request) != n) { fprintf(stderr, "convM2S went south: format error %ux %ux %ux %ux %ux", mdata[0], mdata[1], mdata[2], mdata[3], mdata[4]); error(1, 0, "format error %ux %ux %ux %ux %ux", mdata[0], mdata[1], mdata[2], mdata[3], mdata[4]); freejob(job); continue; } /* stash the thread in the job so we can join them all * later if we want to. */ if (pthread_create(&job->thread, &pth_attr, &job_thread, job)) { error(1, 0, "%s: %r", "Failed to create job"); continue; } } }
/* main parallism function */ void worker() { int i,j; for(;;) { /* find work */ if (!(cj = freejob()) && !(cj = steal())) return; if (cj->status == JOB_DONE) // done return; /* do work */ cj->status = JOB_TAKEN; p_head = p_tail = 0; slow_crunch(); /* aftermath */ switch (cj->status) { case JOB_BLOCKED: add_jobarray(cj); cj = 0; break; case JOB_DONE: if (!cj->jid && master) // done return; else { send_done(cj); free(cj); } break; case JOB_CANCELLED: free(cj); } } }
static void showjob(struct output *out, struct job *jp, int mode) { int procno; int st; struct procstat *ps; int col; char s[64]; #if JOBS if (mode & SHOW_PGID) { /* just output process (group) id of pipeline */ outfmt(out, "%ld\n", (long)jp->ps->pid); return; } #endif procno = jp->nprocs; if (!procno) return; if (mode & SHOW_PID) mode |= SHOW_MULTILINE; if ((procno > 1 && !(mode & SHOW_MULTILINE)) || (mode & SHOW_SIGNALLED)) { /* See if we have more than one status to report */ ps = jp->ps; st = ps->status; do { int st1 = ps->status; if (st1 != st) /* yes - need multi-line output */ mode |= SHOW_MULTILINE; if (st1 == -1 || !(mode & SHOW_SIGNALLED) || WIFEXITED(st1)) continue; if (WIFSTOPPED(st1) || ((st1 = WTERMSIG(st1) & 0x7f) && st1 != SIGINT && st1 != SIGPIPE)) mode |= SHOW_ISSIG; } while (ps++, --procno); procno = jp->nprocs; } if (mode & SHOW_SIGNALLED && !(mode & SHOW_ISSIG)) { if (jp->state == JOBDONE && !(mode & SHOW_NO_FREE)) { TRACE(("showjob: freeing job %d\n", jp - jobtab + 1)); freejob(jp); } return; } for (ps = jp->ps; --procno >= 0; ps++) { /* for each process */ if (ps == jp->ps) fmtstr(s, 16, "[%ld] %c ", (long)(jp - jobtab + 1), #if JOBS jp == jobtab + curjob ? '+' : curjob != -1 && jp == jobtab + jobtab[curjob].prev_job ? '-' : #endif ' '); else fmtstr(s, 16, " " ); col = strlen(s); if (mode & SHOW_PID) { fmtstr(s + col, 16, "%ld ", (long)ps->pid); col += strlen(s + col); } if (ps->status == -1) { scopy("Running", s + col); } else if (WIFEXITED(ps->status)) { st = WEXITSTATUS(ps->status); if (st) fmtstr(s + col, 16, "Done(%d)", st); else fmtstr(s + col, 16, "Done"); } else { #if JOBS if (WIFSTOPPED(ps->status)) st = WSTOPSIG(ps->status); else /* WIFSIGNALED(ps->status) */ #endif st = WTERMSIG(ps->status); st &= 0x7f; if (st < NSIG && sys_siglist[st]) scopyn(sys_siglist[st], s + col, 32); else fmtstr(s + col, 16, "Signal %d", st); if (WCOREDUMP(ps->status)) { col += strlen(s + col); scopyn(" (core dumped)", s + col, 64 - col); } } col += strlen(s + col); outstr(s, out); do { outc(' ', out); col++; } while (col < 30); outstr(ps->cmd, out); if (mode & SHOW_MULTILINE) { if (procno > 0) { outc(' ', out); outc('|', out); } } else { while (--procno >= 0) outfmt(out, " | %s", (++ps)->cmd ); } outc('\n', out); } flushout(out); jp->changed = 0; if (jp->state == JOBDONE && !(mode & SHOW_NO_FREE)) freejob(jp); }
static int statjob(struct job *jp, int stat, int fg, int rc) { pid_t tgid; int done = 0; if (WIFCONTINUED(stat)) { if (jp->j_flag & J_STOPPED) { jp->j_flag &= ~(J_STOPPED|J_SIGNALED|J_SAVETTY); jp->j_flag |= J_RUNNING; if (!fg && jp->j_jid) { jp->j_flag |= J_NOTIFY; jobnote++; } } } else if (WIFSTOPPED(stat)) { jp->j_xval = WSTOPSIG(stat); jp->j_flag &= ~J_RUNNING; jp->j_flag |= (J_SIGNALED|J_STOPPED); jp->j_pgid = getpgid(jp->j_pid); jp->j_tgid = jp->j_pgid; if (fg) { if (tgid = settgid(mypgid, jp->j_pgid)) jp->j_tgid = tgid; else { jp->j_flag |= J_SAVETTY; tcgetattr(0, &jp->j_stty); (void) tcsetattr(0, TCSANOW, &mystty); } } if (jp->j_jid) { jp->j_flag |= J_NOTIFY; jobnote++; } } else { jp->j_flag &= ~J_RUNNING; jp->j_flag |= J_DONE; done++; jobdone++; if (WIFSIGNALED(stat)) { jp->j_xval = WTERMSIG(stat); jp->j_flag |= J_SIGNALED; if (WCOREDUMP(stat)) jp->j_flag |= J_DUMPED; if (!fg || jp->j_xval != SIGINT) { jp->j_flag |= J_NOTIFY; jobnote++; } } else { /* WIFEXITED */ jp->j_xval = WEXITSTATUS(stat); jp->j_flag &= ~J_SIGNALED; if (!fg && jp->j_jid) { jp->j_flag |= J_NOTIFY; jobnote++; } } if (fg) { if (!settgid(mypgid, jp->j_pgid) || !settgid(mypgid, getpgid(jp->j_pid))) tcgetattr(0, &mystty); } } if (rc) { exitval = jp->j_xval; if (jp->j_flag & J_SIGNALED) exitval |= SIGFLG; exitset(); } if (done && !(jp->j_flag & J_NOTIFY)) freejob(jp); return (done); }
/* message handling routine */ void p_handle(int b) { int i,k,len,tid,tag; jobinfo *j; jobinfo tj; pvm_bufinfo(b,&len,&tag,&tid); switch (tag) { case TAG_HELLO: if (master) { wtid = realloc(wtid,sizeof(int) * ++nw); wtid[nw-1] = tid; for (i=1;i<nw;i++) { pvm_initsend(0); k = i << BASE_SHIFT; pvm_pkint(&k,1,1); pvm_pkint(&nw,1,1); pvm_pkint(wtid,nw,1); pvm_send(wtid[i],TAG_WORKERS); } } break; case TAG_WORKERS: pvm_upkint(&nextjid,1,1); nextjid <<= BASE_SHIFT; pvm_upkint(&nw,1,1); free(wtid); wtid = malloc(sizeof(int) * nw); pvm_upkint(wtid,nw,1); break; case TAG_KILL: die("Received TAG_KILL. Too lazy to do anything useful.\n"); case TAG_REQUEST: if (j = freejob()) { pvm_initsend(0); pkjobinfo_active(j); pvm_send(tid,TAG_JOB); add_stolen(tid,j->jid); free(j); } else if (!victim(tid)) { pvm_initsend(0); pvm_send(tid,TAG_NO_JOB); } break; case TAG_DONE: upkjobinfo_done(&tj); if (cj && cj->jid == tj.pjid) slow_absorb(cj,&tj.s); else if (!tj.jid && master) { j = malloc(sizeof(jobinfo)); *j = tj; add_jobarray(j); } else if ((i = find_jobarray(tj.pjid)) >= 0) { slow_absorb(ja[i],&tj.s); if (ja[i]->status == JOB_DONE && !(!ja[i]->jid && master)) { send_done(ja[i]); free(ja[i]); del_jobarray(i); } } else if (tj.tid = find_stolen(tj.pjid)) // if 0, job was cancelled send_done(&tj); break; case TAG_CANCEL: pvm_upkint(&k,1,1); if (cj && cj->jid == k) { cj->status = JOB_CANCELLED; if (p_head > 0) cancel_children(cj); p_head = 1000; add_stolen(0,cj->jid); } else if ((i = find_jobarray(k)) >= 0) { cancel_children(ja[i]); add_stolen(0,ja[i]->jid); free(ja[i]); del_jobarray(i); } else if (tid = find_stolen(k)) send_cancel(tid,k); break; case TAG_STAT: default: die("Warning: ignoring invalid message\n"); } }
static void *job_thread(void *arg) { struct mfile *mf; struct job *job = arg; spinlock_lock(&dblock); mf = newfid(job->request.fid); if (debug) fprintf(stderr, "CS:%F", &job->request); switch (job->request.type) { default: fprintf(stderr, "CS:unknown request type %d", job->request.type); break; case Tversion: rversion(job); break; case Tauth: rauth(job); break; case Tflush: rflush(job); break; case Tattach: rattach(job, mf); break; case Twalk: rwalk(job, mf); break; case Topen: ropen(job, mf); break; case Tcreate: rcreate(job, mf); break; case Tread: rread(job, mf); break; case Twrite: rwrite(job, mf); break; case Tclunk: rclunk(job, mf); break; case Tremove: rremove(job, mf); break; case Tstat: rstat(job, mf); break; case Twstat: rwstat(job, mf); break; } spinlock_unlock(&dblock); freejob(job); if (debug) fprintf(stderr, "CS:Job done\n"); return 0; }
void io(void) { volatile long n; volatile uchar mdata[IOHDRSZ + Maxfdata]; Job *volatile job; Mfile *volatile mf; volatile Request req; memset(&req, 0, sizeof req); /* * a slave process is sometimes forked to wait for replies from other * servers. The master process returns immediately via a longjmp * through 'mret'. */ if(setjmp(req.mret)) putactivity(0); req.isslave = 0; stop = 0; while(!stop){ procsetname("%d %s/dns Twrites of %d 9p rpcs read; %d alarms", stats.qrecvd9p, mntpt, stats.qrecvd9prpc, stats.alarms); n = read9pmsg(mfd[0], mdata, sizeof mdata); if(n<=0){ dnslog("error reading 9P from %s: %r", mntpt); sleep(2000); /* don't thrash after read error */ return; } stats.qrecvd9prpc++; job = newjob(); if(convM2S(mdata, n, &job->request) != n){ freejob(job); continue; } mf = newfid(job->request.fid, 0); if(debug) dnslog("%F", &job->request); getactivity(&req, 0); req.aborttime = timems() + Maxreqtm; req.from = "9p"; switch(job->request.type){ default: warning("unknown request type %d", job->request.type); break; case Tversion: rversion(job); break; case Tauth: rauth(job); break; case Tflush: rflush(job); break; case Tattach: rattach(job, mf); break; case Twalk: rwalk(job, mf); break; case Topen: ropen(job, mf); break; case Tcreate: rcreate(job, mf); break; case Tread: rread(job, mf); break; case Twrite: /* &req is handed to dnresolve() */ rwrite(job, mf, &req); break; case Tclunk: rclunk(job, mf); break; case Tremove: rremove(job, mf); break; case Tstat: rstat(job, mf); break; case Twstat: rwstat(job, mf); break; } freejob(job); /* * slave processes die after replying */ if(req.isslave){ putactivity(0); _exits(0); } putactivity(0); } /* kill any udp server, notifier, etc. processes */ postnote(PNGROUP, getpid(), "die"); sleep(1000); }
void ioproc0(void *v) { long n; Mfile *mf; uchar mdata[IOHDRSZ + Maxfdata]; Request req; Job *job; USED(v); for(;;){ n = read9pmsg(mfd[0], mdata, sizeof mdata); if(n <= 0){ syslog(0, logfile, "error reading mntpt: %r"); break; } job = newjob(); if(convM2S(mdata, n, &job->request) != n){ freejob(job); continue; } if(debug) syslog(0, logfile, "%F", &job->request); getactivity(&req); req.aborttime = now + 60; /* don't spend more than 60 seconds */ mf = nil; switch(job->request.type){ case Tversion: case Tauth: case Tflush: break; case Tattach: mf = newfid(job->request.fid, 1); if(mf == nil){ sendmsg(job, "fid in use"); goto skip; } break; default: mf = newfid(job->request.fid, 0); if(mf == nil){ sendmsg(job, "unknown fid"); goto skip; } break; } switch(job->request.type){ default: syslog(1, logfile, "unknown request type %d", job->request.type); break; case Tversion: rversion(job); break; case Tauth: rauth(job); break; case Tflush: rflush(job); break; case Tattach: rattach(job, mf); break; case Twalk: rwalk(job, mf); break; case Topen: ropen(job, mf); break; case Tcreate: rcreate(job, mf); break; case Tread: rread(job, mf); break; case Twrite: rwrite(job, mf, &req); break; case Tclunk: rclunk(job, mf); break; case Tremove: rremove(job, mf); break; case Tstat: rstat(job, mf); break; case Twstat: rwstat(job, mf); break; } skip: freejob(job); putactivity(); } }