Proc* newproc(void) { char msg[64]; Proc *p; lock(&procalloc); for(;;) { if((p = procalloc.free) != nil) break; snprint(msg, sizeof msg, "no procs; %s forking", up != nil ? up->text: "kernel"); unlock(&procalloc); resrcwait(msg); lock(&procalloc); } procalloc.free = p->qnext; unlock(&procalloc); p->state = Scheding; p->psstate = "New"; p->mach = nil; p->eql = nil; p->qnext = nil; p->nchild = 0; p->nwait = 0; p->waitq = nil; p->parent = nil; p->pgrp = nil; p->egrp = nil; p->fgrp = nil; p->rgrp = nil; p->pdbg = nil; p->fpstate = FPinit; p->kp = 0; p->procctl = 0; p->syscalltrace = nil; p->notepending = 0; p->ureg = nil; p->privatemem = 0; p->noswap = 0; p->errstr = p->errbuf0; p->syserrstr = p->errbuf1; p->errbuf0[0] = '\0'; p->errbuf1[0] = '\0'; p->nlocks = 0; p->delaysched = 0; p->trace = 0; kstrdup(&p->user, "*nouser"); kstrdup(&p->text, "*notext"); kstrdup(&p->args, ""); p->nargs = 0; p->setargs = 0; memset(p->seg, 0, sizeof p->seg); p->parentpid = 0; p->noteid = pidalloc(p); if(p->kstack == nil) p->kstack = smalloc(KSTACK); /* sched params */ p->mp = nil; p->wired = nil; procpriority(p, PriNormal, 0); p->cpu = 0; p->lastupdate = MACHP(0)->ticks*Scaling; p->edf = nil; return p; }
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; }