int main(int argc, char *argv[]) { return sched(argc, argv); }
int waitup(int echildok, int *retstatus) { Envy *e; int pid; int slot; Symtab *s; Word *w; Job *j; char buf[ERRMAX]; Bufblock *bp; int uarg = 0; int done; Node *n; Process *p; extern int runerrs; /* first check against the proces slist */ if(retstatus) for(p = phead; p; p = p->f) if(p->pid == *retstatus){ *retstatus = p->status; pdelete(p); return(-1); } again: /* rogue processes */ pid = waitfor(buf); if(pid == -1){ if(echildok > 0) return(1); else { fprint(2, "mk: (waitup %d) ", echildok); perror("mk wait"); Exit(); } } if(DEBUG(D_EXEC)) fprint(1, "waitup got pid=%d, status='%s'\n", pid, buf); if(retstatus && pid == *retstatus){ *retstatus = buf[0]? 1:0; return(-1); } slot = pidslot(pid); if(slot < 0){ if(DEBUG(D_EXEC)) fprint(2, "mk: wait returned unexpected process %d\n", pid); pnew(pid, buf[0]? 1:0); goto again; } j = events[slot].job; usage(); nrunning--; events[slot].pid = -1; if(buf[0]){ e = buildenv(j, slot); bp = newbuf(); shprint(j->r->recipe, e, bp); front(bp->start); fprint(2, "mk: %s: exit status=%s", bp->start, buf); freebuf(bp); for(n = j->n, done = 0; n; n = n->next) if(n->flags&DELETE){ if(done++ == 0) fprint(2, ", deleting"); fprint(2, " '%s'", n->name); delete(n->name); } fprint(2, "\n"); if(kflag){ runerrs++; uarg = 1; } else { jobs = 0; Exit(); } } for(w = j->t; w; w = w->next){ if((s = symlook(w->s, S_NODE, 0)) == 0) continue; /* not interested in this node */ update(uarg, s->u.ptr); } if(nrunning < nproclimit) sched(); return(0); }
Image* attachimage(int type, Chan *c, int color, uintptr base, usize len) { Image *i, **l; /* reclaim any free channels from reclaimed segments */ if(imagealloc.nfreechan) imagechanreclaim(); lock(&imagealloc); /* * Search the image cache for remains of the text from a previous * or currently running incarnation */ for(i = ihash(c->qid.path); i; i = i->hash) { if(c->qid.path == i->qid.path) { lock(i); if(eqqid(c->qid, i->qid) && eqqid(c->mqid, i->mqid) && c->mchan == i->mchan && c->dev->dc == i->dc) { //subtype goto found; } unlock(i); } } /* * imagereclaim dumps pages from the free list which are cached by image * structures. This should free some image structures. */ while(!(i = lruimage())) { unlock(&imagealloc); imagereclaim(); sched(); lock(&imagealloc); } lock(i); incref(c); i->c = c; i->dc = c->dev->dc; //subtype i->qid = c->qid; i->mqid = c->mqid; i->mchan = c->mchan; i->color = color; l = &ihash(c->qid.path); i->hash = *l; *l = i; found: imageused(i); unlock(&imagealloc); if(i->s == 0) { /* Disaster after commit in exec */ if(waserror()) { unlock(i); pexit(Enovmem, 1); } i->s = newseg(type, base, len); i->s->image = i; i->s->color = color; i->ref++; poperror(); } else incref(i->s); return i; }
int chunker_cmd( chunker_t *chunker, cmd_t cmd, disk_t *dp, char *mesg) { char *cmdline = NULL; char number[NUM_STR_SIZE]; char chunksize[NUM_STR_SIZE]; char use[NUM_STR_SIZE]; char *o; int activehd=0; assignedhd_t **h=NULL; char *features; char *qname; char *qdest; switch(cmd) { case START: cmdline = vstralloc(cmdstr[cmd], " ", mesg, "\n", NULL); break; case PORT_WRITE: if(dp && sched(dp) && sched(dp)->holdp) { h = sched(dp)->holdp; activehd = sched(dp)->activehd; } if (dp && h) { qname = quote_string(dp->name); qdest = quote_string(sched(dp)->destname); h[activehd]->disk->allocated_dumpers++; g_snprintf(number, SIZEOF(number), "%d", sched(dp)->level); g_snprintf(chunksize, SIZEOF(chunksize), "%lld", (long long)holdingdisk_get_chunksize(h[0]->disk->hdisk)); g_snprintf(use, SIZEOF(use), "%lld", (long long)h[0]->reserved); features = am_feature_to_string(dp->host->features); o = optionstr(dp, dp->host->features, NULL); if ( o == NULL ) { error(_("problem with option string, check the dumptype definition.\n")); } cmdline = vstralloc(cmdstr[cmd], " ", disk2serial(dp), " ", qdest, " ", dp->host->hostname, " ", features, " ", qname, " ", number, " ", sched(dp)->dumpdate, " ", chunksize, " ", dp->program, " ", use, " |", o, "\n", NULL); amfree(features); amfree(o); amfree(qdest); amfree(qname); } else { error(_("%s command without disk and holding disk.\n"), cmdstr[cmd]); /*NOTREACHED*/ } break; case CONTINUE: if(dp && sched(dp) && sched(dp)->holdp) { h = sched(dp)->holdp; activehd = sched(dp)->activehd; } if(dp && h) { qname = quote_string(dp->name); qdest = quote_string(h[activehd]->destname); h[activehd]->disk->allocated_dumpers++; g_snprintf(chunksize, SIZEOF(chunksize), "%lld", (long long)holdingdisk_get_chunksize(h[activehd]->disk->hdisk)); g_snprintf(use, SIZEOF(use), "%lld", (long long)(h[activehd]->reserved - h[activehd]->used)); cmdline = vstralloc(cmdstr[cmd], " ", disk2serial(dp), " ", qdest, " ", chunksize, " ", use, "\n", NULL ); amfree(qdest); amfree(qname); } else { cmdline = stralloc2(cmdstr[cmd], "\n"); } break; case QUIT: case ABORT: { char *q = quote_string(mesg); cmdline = vstralloc(cmdstr[cmd], " ", q, "\n", NULL); amfree(q); } break; case DONE: case FAILED: if( dp ) { cmdline = vstralloc(cmdstr[cmd], " ", disk2serial(dp), "\n", NULL); } else { cmdline = vstralloc(cmdstr[cmd], "\n"); } break; default: error(_("Don't know how to send %s command to chunker"), cmdstr[cmd]); /*NOTREACHED*/ } /* * Note: cmdline already has a '\n'. */ g_printf(_("driver: send-cmd time %s to %s: %s"), walltime_str(curclock()), chunker->name, cmdline); fflush(stdout); if (full_write(chunker->fd, cmdline, strlen(cmdline)) < strlen(cmdline)) { g_printf(_("writing %s command: %s\n"), chunker->name, strerror(errno)); fflush(stdout); amfree(cmdline); return 0; } if (cmd == QUIT) aclose(chunker->fd); amfree(cmdline); return 1; }
void update_info_dumper( disk_t *dp, off_t origsize, off_t dumpsize, time_t dumptime) { int level, i; info_t info; stats_t *infp; perf_t *perfp; char *conf_infofile; level = sched(dp)->level; conf_infofile = config_dir_relative(getconf_str(CNF_INFOFILE)); if (open_infofile(conf_infofile)) { error(_("could not open info db \"%s\""), conf_infofile); /*NOTREACHED*/ } amfree(conf_infofile); get_info(dp->host->hostname, dp->name, &info); /* Clean up information about this and higher-level dumps. This assumes that update_info_dumper() is always run before update_info_taper(). */ for (i = level; i < DUMP_LEVELS; ++i) { infp = &info.inf[i]; infp->size = (off_t)-1; infp->csize = (off_t)-1; infp->secs = (time_t)-1; infp->date = (time_t)-1; infp->label[0] = '\0'; infp->filenum = 0; } /* now store information about this dump */ infp = &info.inf[level]; infp->size = origsize; infp->csize = dumpsize; infp->secs = dumptime; infp->date = sched(dp)->timestamp; if(level == 0) perfp = &info.full; else perfp = &info.incr; /* Update the stats, but only if the new values are meaningful */ if(dp->compress != COMP_NONE && origsize > (off_t)0) { newperf(perfp->comp, (double)dumpsize/(double)origsize); } if(dumptime > (time_t)0) { if((off_t)dumptime >= dumpsize) newperf(perfp->rate, 1); else newperf(perfp->rate, (double)dumpsize/(double)dumptime); } if(origsize >= (off_t)0 && getconf_int(CNF_RESERVE)<100) { info.command = NO_COMMAND; } if (origsize >= (off_t)0 && level == info.last_level) { info.consecutive_runs++; } else if (origsize >= (off_t)0 || level < info.last_level) { info.last_level = level; info.consecutive_runs = 1; } if(origsize >= (off_t)0 && dumpsize >= (off_t)0) { for(i=NB_HISTORY-1;i>0;i--) { info.history[i] = info.history[i-1]; } info.history[0].level = level; info.history[0].size = origsize; info.history[0].csize = dumpsize; info.history[0].date = sched(dp)->timestamp; info.history[0].secs = dumptime; } if (put_info(dp->host->hostname, dp->name, &info)) { int save_errno = errno; g_fprintf(stderr, _("infofile update failed (%s,'%s'): %s\n"), dp->host->hostname, dp->name, strerror(save_errno)); log_add(L_ERROR, _("infofile update failed (%s,'%s'): %s\n"), dp->host->hostname, dp->name, strerror(save_errno)); error(_("infofile update failed (%s,'%s'): %s\n"), dp->host->hostname, dp->name, strerror(save_errno)); /*NOTREACHED*/ } close_infofile(); }
Image* attachimage(int type, Chan *c, ulong base, ulong len) { Image *i, **l; /* reclaim any free channels from reclaimed segments */ if(imagealloc.nfreechan) imagechanreclaim(); lock(&imagealloc.lk); /* * Search the image cache for remains of the text from a previous * or currently running incarnation */ for(i = ihash(c->qid.path); i; i = i->hash) { if(c->qid.path == i->qid.path) { lock(&i->ref.lk); if(eqqid(c->qid, i->qid) && eqqid(c->mqid, i->mqid) && c->mchan == i->mchan && c->type == i->type) { goto found; } unlock(&i->ref.lk); } } /* * imagereclaim dumps pages from the free list which are cached by image * structures. This should free some image structures. */ while(!(i = imagealloc.free)) { unlock(&imagealloc.lk); imagereclaim(); sched(); lock(&imagealloc.lk); } imagealloc.free = i->next; lock(&i->ref.lk); incref(&c->ref); i->c = c; i->type = c->type; i->qid = c->qid; i->mqid = c->mqid; i->mchan = c->mchan; l = &ihash(c->qid.path); i->hash = *l; *l = i; found: unlock(&imagealloc.lk); if(i->s == 0) { /* Disaster after commit in exec */ if(waserror()) { unlock(&i->ref.lk); pexit(Enovmem, 1); } i->s = newseg(type, base, len); i->s->image = i; i->ref.ref++; poperror(); } else incref(&i->s->ref); return i; }
int dumper_cmd( dumper_t *dumper, cmd_t cmd, disk_t *dp, char *mesg) { char *cmdline = NULL; char number[NUM_STR_SIZE]; char numberport[NUM_STR_SIZE]; char *o; char *device; char *features; char *qname; char *qmesg; switch(cmd) { case START: cmdline = vstralloc(cmdstr[cmd], " ", mesg, "\n", NULL); break; case PORT_DUMP: if(dp && dp->device) { device = dp->device; } else { device = "NODEVICE"; } if (dp != NULL) { application_t *application = NULL; char *plugin; char *qplugin; char *qamandad_path; char *qclient_username; char *qclient_port; char *qssh_keys; if (dp->application != NULL) { application = lookup_application(dp->application); g_assert(application != NULL); } device = quote_string((dp->device) ? dp->device : "NODEVICE"); qname = quote_string(dp->name); g_snprintf(number, SIZEOF(number), "%d", sched(dp)->level); g_snprintf(numberport, SIZEOF(numberport), "%d", dumper->output_port); features = am_feature_to_string(dp->host->features); if (am_has_feature(dp->host->features, fe_req_xml)) { o = xml_optionstr(dp, dp->host->features, NULL, 1); if (application) { char *xml_app; xml_app = xml_application(dp, application, dp->host->features); vstrextend(&o, xml_app, NULL); amfree(xml_app); } o = quote_string(o); } else { o = optionstr(dp, dp->host->features, NULL); } if ( o == NULL ) { error(_("problem with option string, check the dumptype definition.\n")); } g_assert(dp->program); if (0 == strcmp(dp->program, "APPLICATION")) { g_assert(application != NULL); plugin = application_get_plugin(application); } else { plugin = dp->program; } qplugin = quote_string(plugin); qamandad_path = quote_string(dp->amandad_path); qclient_username = quote_string(dp->client_username); qclient_port = quote_string(dp->client_port); qssh_keys = quote_string(dp->ssh_keys); dbprintf("security_driver %s\n", dp->auth); cmdline = vstralloc(cmdstr[cmd], " ", disk2serial(dp), " ", numberport, " ", dp->host->hostname, " ", features, " ", qname, " ", device, " ", number, " ", sched(dp)->dumpdate, " ", qplugin, " ", qamandad_path, " ", qclient_username, " ", qclient_port, " ", qssh_keys, " ", dp->auth, " ", data_path_to_string(dp->data_path), " |", o, "\n", NULL); amfree(qplugin); amfree(qamandad_path); amfree(qclient_username); amfree(qclient_port); amfree(qssh_keys); amfree(features); amfree(o); amfree(qname); amfree(device); } else { error(_("PORT-DUMP without disk pointer\n")); /*NOTREACHED*/ } break; case QUIT: case ABORT: qmesg = quote_string(mesg); cmdline = vstralloc(cmdstr[cmd], " ", qmesg, "\n", NULL ); amfree(qmesg); break; default: error(_("Don't know how to send %s command to dumper"), cmdstr[cmd]); /*NOTREACHED*/ } /* * Note: cmdline already has a '\n'. */ if(dumper->down) { g_printf(_("driver: send-cmd time %s ignored to down dumper %s: %s"), walltime_str(curclock()), dumper->name, cmdline); } else { g_printf(_("driver: send-cmd time %s to %s: %s"), walltime_str(curclock()), dumper->name, cmdline); fflush(stdout); if (full_write(dumper->fd, cmdline, strlen(cmdline)) < strlen(cmdline)) { g_printf(_("writing %s command: %s\n"), dumper->name, strerror(errno)); fflush(stdout); amfree(cmdline); return 0; } if (cmd == QUIT) aclose(dumper->fd); } amfree(cmdline); return 1; }
/* * if waking a sleeping process, this routine must hold both * p->rlock and r->lock. However, it can't know them in * the same order as wakeup causing a possible lock ordering * deadlock. We break the deadlock by giving up the p->rlock * lock if we can't get the r->lock and retrying. */ int postnote(Proc *p, int dolock, char *n, int flag) { Mpl pl; int ret; Rendez *r; Proc *d, **l; if(dolock) qlock(&p->debug); if(flag != NUser && (p->notify == 0 || p->notified)) p->nnote = 0; ret = 0; if(p->nnote < NNOTE) { strcpy(p->note[p->nnote].msg, n); p->note[p->nnote++].flag = flag; ret = 1; } p->notepending = 1; /* NIX */ if(p->state == Exotic){ /* it could be that the process is not running * in the AC when we interrupt the AC, but then * we'd only get an extra interrupt in the AC, and * nothing should happen. */ intrac(p); } if(dolock) qunlock(&p->debug); /* this loop is to avoid lock ordering problems. */ for(;;){ pl = splhi(); lock(&p->rlock); r = p->r; /* waiting for a wakeup? */ if(r == nil) break; /* no */ /* try for the second lock */ if(canlock(r)){ if(p->state != Wakeme || r->p != p) panic("postnote: state %d %d %d", r->p != p, p->r != r, p->state); p->r = nil; r->p = nil; ready(p); unlock(r); break; } /* give other process time to get out of critical section and try again */ unlock(&p->rlock); splx(pl); sched(); } unlock(&p->rlock); splx(pl); if(p->state != Rendezvous){ if(p->state == Semdown) ready(p); return ret; } /* Try and pull out of a rendezvous */ lock(p->rgrp); if(p->state == Rendezvous) { p->rendval = ~0; l = &REND(p->rgrp, p->rendtag); for(d = *l; d; d = d->rendhash) { if(d == p) { *l = p->rendhash; break; } l = &d->rendhash; } ready(p); } unlock(p->rgrp); return ret; }
void pexit(char *exitstr, int freemem) { Proc *p; Segment **s, **es; int32_t utime, stime; Waitq *wq, *f, *next; Fgrp *fgrp; Egrp *egrp; Rgrp *rgrp; Pgrp *pgrp; Chan *dot; if(0 && up->nfullq > 0) iprint(" %s=%d", up->text, up->nfullq); if(0 && up->nicc > 0) iprint(" [%s nicc %ud tctime %ulld actime %ulld]\n", up->text, up->nicc, up->tctime, up->actime); if(up->syscalltrace != nil) free(up->syscalltrace); up->syscalltrace = nil; up->alarm = 0; if (up->tt) timerdel(up); if(up->trace) proctrace(up, SDead, 0); /* nil out all the resources under lock (free later) */ qlock(&up->debug); fgrp = up->fgrp; up->fgrp = nil; egrp = up->egrp; up->egrp = nil; rgrp = up->rgrp; up->rgrp = nil; pgrp = up->pgrp; up->pgrp = nil; dot = up->dot; up->dot = nil; qunlock(&up->debug); if(fgrp) closefgrp(fgrp); if(egrp) closeegrp(egrp); if(rgrp) closergrp(rgrp); if(dot) cclose(dot); if(pgrp) closepgrp(pgrp); /* * if not a kernel process and have a parent, * do some housekeeping. */ if(up->kp == 0) { p = up->parent; if(p == 0) { if(exitstr == 0) exitstr = "unknown"; panic("boot process died: %s", exitstr); } while(waserror()) ; wq = smalloc(sizeof(Waitq)); poperror(); wq->w.pid = up->pid; utime = up->time[TUser] + up->time[TCUser]; stime = up->time[TSys] + up->time[TCSys]; wq->w.time[TUser] = tk2ms(utime); wq->w.time[TSys] = tk2ms(stime); wq->w.time[TReal] = tk2ms(sys->ticks - up->time[TReal]); if(exitstr && exitstr[0]) snprint(wq->w.msg, sizeof(wq->w.msg), "%s %d: %s", up->text, up->pid, exitstr); else wq->w.msg[0] = '\0'; lock(&p->exl); /* * Check that parent is still alive. */ if(p->pid == up->parentpid && p->state != Broken) { p->nchild--; p->time[TCUser] += utime; p->time[TCSys] += stime; /* * If there would be more than 128 wait records * processes for my parent, then don't leave a wait * record behind. This helps prevent badly written * daemon processes from accumulating lots of wait * records. */ if(p->nwait < 128) { wq->next = p->waitq; p->waitq = wq; p->nwait++; wq = nil; wakeup(&p->waitr); } } unlock(&p->exl); if(wq) free(wq); } if(!freemem) addbroken(up); qlock(&up->seglock); es = &up->seg[NSEG]; for(s = up->seg; s < es; s++) { if(*s) { putseg(*s); *s = 0; } } qunlock(&up->seglock); lock(&up->exl); /* Prevent my children from leaving waits */ psunhash(up); up->pid = 0; wakeup(&up->waitr); unlock(&up->exl); for(f = up->waitq; f; f = next) { next = f->next; free(f); } /* release debuggers */ qlock(&up->debug); if(up->pdbg) { wakeup(&up->pdbg->sleep); up->pdbg = 0; } qunlock(&up->debug); /* Sched must not loop for these locks */ lock(&procalloc); lock(&pga); stopac(); edfstop(up); up->state = Moribund; sched(); panic("pexit"); }
/* * if waking a sleeping process, this routine must hold both * p->rlock and r->lock. However, it can't know them in * the same order as wakeup causing a possible lock ordering * deadlock. We break the deadlock by giving up the p->rlock * lock if we can't get the r->lock and retrying. */ int postnote(Proc *p, int dolock, char *n, int flag) { int s, ret; Rendez *r; Proc *d, **l; if(dolock) qlock(&p->debug); if(flag != NUser && (p->notify == 0 || p->notified)) p->nnote = 0; ret = 0; if(p->nnote < NNOTE) { strcpy(p->note[p->nnote].msg, n); p->note[p->nnote++].flag = flag; ret = 1; } p->notepending = 1; if(dolock) qunlock(&p->debug); /* this loop is to avoid lock ordering problems. */ for(;;){ s = splhi(); lock(&p->rlock); r = p->r; /* waiting for a wakeup? */ if(r == nil) break; /* no */ /* try for the second lock */ if(canlock(r)){ if(p->state != Wakeme || r->p != p) panic("postnote: state %d %d %d", r->p != p, p->r != r, p->state); p->r = nil; r->p = nil; ready(p); unlock(r); break; } /* give other process time to get out of critical section and try again */ unlock(&p->rlock); splx(s); sched(); } unlock(&p->rlock); splx(s); if(p->state != Rendezvous) return ret; /* Try and pull out of a rendezvous */ lock(p->rgrp); if(p->state == Rendezvous) { p->rendval = ~0; l = &REND(p->rgrp, p->rendtag); for(d = *l; d; d = d->rendhash) { if(d == p) { *l = p->rendhash; break; } l = &d->rendhash; } ready(p); } unlock(p->rgrp); return ret; }
/* * add a block to a queue obeying flow control */ long qbwrite(Queue *q, Block *b) { int n, dowakeup; Proc *p; n = BLEN(b); if(q->bypass != nil){ (*q->bypass)(q->arg, b); return n; } dowakeup = 0; if(waserror()){ freeb(b); nexterror(); } ilock(q); /* give up if the queue is closed */ if(q->state & Qclosed){ iunlock(q); error(q->err); } /* don't queue over the limit */ if(q->len >= q->limit && q->noblock){ iunlock(q); freeb(b); poperror(); return n; } /* queue the block */ if(q->bfirst != nil) q->blast->next = b; else q->bfirst = b; q->blast = b; b->next = nil; q->len += BALLOC(b); q->dlen += n; QDEBUG checkb(b, "qbwrite"); /* make sure other end gets awakened */ if(q->state & Qstarve){ q->state &= ~Qstarve; dowakeup = 1; } iunlock(q); poperror(); /* get output going again */ if(q->kick != nil && (dowakeup || (q->state&Qkick))) q->kick(q->arg); /* wakeup anyone consuming at the other end */ if(dowakeup){ p = wakeup(&q->rr); /* if we just wokeup a higher priority process, let it run */ if(p != nil && p->priority > up->priority) sched(); } /* * flow control, before allowing the process to continue and * queue more. We do this here so that postnote can only * interrupt us after the data has been queued. This means that * things like 9p flushes and ssl messages will not be disrupted * by software interrupts. */ qflow(q); return n; }
pid_t sched_fork() { sched_task = sched_task_fork; sched(); return (pid_t)current_proc->syscall_retvalue; }
uintptr sysrfork(va_list list) { Proc *p; int n, i; Fgrp *ofg; Pgrp *opg; Rgrp *org; Egrp *oeg; ulong pid, flag; Mach *wm; flag = va_arg(list, ulong); /* Check flags before we commit */ if((flag & (RFFDG|RFCFDG)) == (RFFDG|RFCFDG)) error(Ebadarg); if((flag & (RFNAMEG|RFCNAMEG)) == (RFNAMEG|RFCNAMEG)) error(Ebadarg); if((flag & (RFENVG|RFCENVG)) == (RFENVG|RFCENVG)) error(Ebadarg); if((flag&RFPROC) == 0) { if(flag & (RFMEM|RFNOWAIT)) error(Ebadarg); if(flag & (RFFDG|RFCFDG)) { ofg = up->fgrp; if(flag & RFFDG) up->fgrp = dupfgrp(ofg); else up->fgrp = dupfgrp(nil); closefgrp(ofg); } if(flag & (RFNAMEG|RFCNAMEG)) { opg = up->pgrp; up->pgrp = newpgrp(); if(flag & RFNAMEG) pgrpcpy(up->pgrp, opg); /* inherit noattach */ up->pgrp->noattach = opg->noattach; closepgrp(opg); } if(flag & RFNOMNT) up->pgrp->noattach = 1; if(flag & RFREND) { org = up->rgrp; up->rgrp = newrgrp(); closergrp(org); } if(flag & (RFENVG|RFCENVG)) { oeg = up->egrp; up->egrp = smalloc(sizeof(Egrp)); up->egrp->ref = 1; if(flag & RFENVG) envcpy(up->egrp, oeg); closeegrp(oeg); } if(flag & RFNOTEG) up->noteid = pidalloc(0); return 0; } p = newproc(); p->scallnr = up->scallnr; p->s = up->s; p->nerrlab = 0; p->slash = up->slash; p->dot = up->dot; incref(p->dot); memmove(p->note, up->note, sizeof(p->note)); p->privatemem = up->privatemem; p->noswap = up->noswap; p->nnote = up->nnote; p->notified = 0; p->lastnote = up->lastnote; p->notify = up->notify; p->ureg = up->ureg; p->dbgreg = 0; /* Abort the child process on error */ if(waserror()){ p->kp = 1; kprocchild(p, abortion, 0); ready(p); nexterror(); } /* Make a new set of memory segments */ n = flag & RFMEM; qlock(&p->seglock); if(waserror()){ qunlock(&p->seglock); nexterror(); } for(i = 0; i < NSEG; i++) if(up->seg[i] != nil) p->seg[i] = dupseg(up->seg, i, n); qunlock(&p->seglock); poperror(); /* File descriptors */ if(flag & (RFFDG|RFCFDG)) { if(flag & RFFDG) p->fgrp = dupfgrp(up->fgrp); else p->fgrp = dupfgrp(nil); } else { p->fgrp = up->fgrp; incref(p->fgrp); } /* Process groups */ if(flag & (RFNAMEG|RFCNAMEG)) { p->pgrp = newpgrp(); if(flag & RFNAMEG) pgrpcpy(p->pgrp, up->pgrp); /* inherit noattach */ p->pgrp->noattach = up->pgrp->noattach; } else { p->pgrp = up->pgrp; incref(p->pgrp); } if(flag & RFNOMNT) p->pgrp->noattach = 1; if(flag & RFREND) p->rgrp = newrgrp(); else { incref(up->rgrp); p->rgrp = up->rgrp; } /* Environment group */ if(flag & (RFENVG|RFCENVG)) { p->egrp = smalloc(sizeof(Egrp)); p->egrp->ref = 1; if(flag & RFENVG) envcpy(p->egrp, up->egrp); } else { p->egrp = up->egrp; incref(p->egrp); } p->hang = up->hang; p->procmode = up->procmode; if(up->procctl == Proc_tracesyscall) p->procctl = Proc_tracesyscall; poperror(); /* abortion */ /* Craft a return frame which will cause the child to pop out of * the scheduler in user mode with the return register zero */ forkchild(p, up->dbgreg); p->parent = up; if((flag&RFNOWAIT) == 0){ p->parentpid = up->pid; lock(&up->exl); up->nchild++; unlock(&up->exl); } if((flag&RFNOTEG) == 0) p->noteid = up->noteid; pid = p->pid; memset(p->time, 0, sizeof(p->time)); p->time[TReal] = MACHP(0)->ticks; kstrdup(&p->text, up->text); kstrdup(&p->user, up->user); procfork(p); /* * since the bss/data segments are now shareable, * any mmu info about this process is now stale * (i.e. has bad properties) and has to be discarded. */ flushmmu(); p->basepri = up->basepri; p->priority = up->basepri; p->fixedpri = up->fixedpri; p->mp = up->mp; wm = up->wired; if(wm) procwired(p, wm->machno); ready(p); sched(); return pid; }
// Give up the CPU for one scheduling round. void yield(void) { acquire(&ptable.lock); //DOC: yieldlock SetProcessRunnable(proc); sched(); release(&ptable.lock); }
int sys_sigwait() { (CURRENT_TASK() )->state = TASK_SIGWAIT; sched(); return -EINTR; }
void kthread_exit() { struct proc *p; int threadsCounter=0; acquire(&ptable.lock); if(proc == initproc) panic("init exiting"); int i=0; for(;i<64;i++) { if(proc->sleepingThreads[i]!=0) wakeup1(proc->sleepingThreads[i]); } for(p = ptable.proc; p < &ptable.proc[NPROC]; p++) { if(p->pid==proc->pid && p->state!=ZOMBIE && p->state!=UNUSED) { threadsCounter++; } } if(threadsCounter==1) { for(p = ptable.proc; p < &ptable.proc[NPROC]; p++) if(p->state == ZOMBIE && p->pid ==proc->pid && proc->threadId != p->threadId){ kfree(p->kstack); p->kstack = 0; p->state = UNUSED; p->pid = 0; p->parent = 0; p->name[0] = 0; p->killed = 0; } release(&ptable.lock); New_exit(); return ; } // Jump into the scheduler, never to return. proc->state = ZOMBIE; sched(); panic("zombie exit"); }