#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);
}
syntax highlighted by Code2HTML, v. 0.9.1