#include <9pm/u.h> #include <9pm/libc.h> #include <9pm/ns.h> #include <9pm/thread.h> #include <9pm/threadimpl.h> struct Pqueue _threadpq; int procrfork(void (*f)(void *), void *arg, uint stacksize, int rforkflag) { Tproc *p, *np; p = _threadgetproc(); np = _newproc(f, arg, stacksize, nil, p->curthread->grp, rforkflag); _threaddebug(DBGPROC, "newproc, switch stacks"); p->arg = np; np->sysproc.err = np->sysproc.errbuf0; np->sysproc.fgrp = p->sysproc.fgrp; np->sysproc.pgrp = p->sysproc.pgrp; np->sysproc.egrp = p->sysproc.egrp; incref(&np->sysproc.egrp->ref); incref(&np->sysproc.fgrp->ref); incref(&np->sysproc.pgrp->ref); np->sysproc.slash = p->sysproc.slash; np->sysproc.dot = p->sysproc.dot; incref(&np->sysproc.slash->ref); incref(&np->sysproc.dot->ref); return _threadswtch(p->curthread->env, p->oldenv, DOPROC); /* id of new proc */ } int proccreate(void (*f)(void*), void *arg, uint stacksize) { return procrfork(f, arg, stacksize, 0); } static int nextID(void) { static Lock l; static id; int i; lock(&l); i = ++id; unlock(&l); return i; } /* * Create and initialize a new Thread structure attached to a given proc. */ static Thread* newthread(Tproc *p, void (*f)(void *arg), void *arg, uint stacksize, char *name, int grp) { Thread *t; if(stacksize < 32) sysfatal("bad stacksize %d", stacksize); t = _threadmalloc(sizeof(Thread), 1); t->stksize = stacksize; t->stk = _threadmalloc(stacksize, 0); memset(t->stk, 0xFE, stacksize); _threadinitstack(t, f, arg); t->grp = grp; if(name) t->cmdname = strdup(name); t->id = nextID(); t->next = (Thread*)~0; t->proc = p; lock(&p->threadlk); p->nthreads++; if(p->threads.head == nil) p->threads.head = t; else p->threads.tail->nextt = t; p->threads.tail = t; unlock(&p->threadlk); return t; } /* * Create a new thread and schedule it to run. * The thread grp is inherited from the currently running thread. */ int threadcreate(void (*f)(void *arg), void *arg, uint stacksize) { Thread *t; Tproc *p; p = _threadgetproc(); if((t = newthread(p, f, arg, stacksize, nil, threadgetgrp())) == nil) return -1; t->state = Runnable; _threaddebug(DBGPROC, "scheduling new thread %d.%d", p->pid, t->id); _threadputq(&p->runnable, t); return t->id; } /* * Create and initialize a new Tproc structure with a single Thread * running inside it. Add the Tproc to the global process list. */ Tproc* _newproc(void (*f)(void *arg), void *arg, uint stacksize, char *name, int grp, int rforkflag) { Tproc *p; Thread *t; p = _threadmalloc(sizeof *p, 1); p->pid = -1; p->rforkflag = rforkflag; p->sysproc.err = p->sysproc.errbuf0; t = newthread(p, f, arg, stacksize, name, grp); t->state = Running; p->curthread = t; assert(p->curthread != nil); lock(&_threadpq.lk); if(_threadpq.head == nil) _threadpq.head = p; else _threadpq.tail->next = p; _threadpq.tail = p; unlock(&_threadpq.lk); _osnewproc(p); return p; } void _freeproc(Tproc *p) { Thread *t, *nextt; _osfreeproc(p); for (t = p->threads.head; t; t = nextt) { if (t->cmdname) free(t->cmdname); threadassert(t->stk != nil); free(t->stk); nextt = t->nextt; free(t); } if(p->sysproc.pgrp) closepgrp(p->sysproc.pgrp); if(p->sysproc.fgrp) closefgrp(p->sysproc.fgrp); free(p->sysproc.wd); free(p); } void _freethread(Thread *t) { Tproc *p; Thread *r, *pr; int BUG_SHARED_ACCESSES_HERE; p = t->proc; threadassert(_threadgetproc() == p); pr = nil; for (r = p->threads.head; r; r = r->nextt) { if (r == t) break; pr = r; } threadassert(r != nil); if (pr) pr->nextt = r->nextt; else p->threads.head = r->nextt; if (p->threads.tail == r) p->threads.tail = pr; if (t->cmdname) free(t->cmdname); threadassert(t->stk != nil); free(t->stk); free(t); }