blob: 4e6bc6de2263575a932e63ff5396938bfa2134e2 [file] [log] [blame]
#include "threadimpl.h"
Pqueue _threadpq; /* list of all procs */
int _threadnprocs; /* count of procs */
static int newthreadid(void);
static int newprocid(void);
/*
* Create and initialize a new Thread structure attached to a given proc.
*/
int
_newthread(Proc *p, void (*f)(void *arg), void *arg, uint stacksize,
char *name, int grp)
{
int id;
Thread *t;
t = _threadmalloc(sizeof(Thread), 1);
t->proc = p;
t->nextproc = p;
t->homeproc = p;
t->grp = grp;
t->id = id = newthreadid();
if(name)
t->name = strdup(name);
_threaddebug(DBGSCHED, "create thread %d.%d name %s", p->id, id, name);
/*
* Allocate and clear stack.
*/
if(stacksize < 1024)
sysfatal("bad stacksize %d", stacksize);
t->stk = _threadmalloc(stacksize, 0);
t->stksize = stacksize;
_threaddebugmemset(t->stk, 0xFE, stacksize);
/*
* Set up t->context to call f(arg).
*/
_threadinitstack(t, f, arg);
/*
* Add thread to proc.
*/
lock(&p->lock);
_procaddthread(p, t);
/*
* Mark thread as ready to run.
*/
t->state = Ready;
_threadready(t);
unlock(&p->lock);
return id;
}
/*
* Free a Thread structure.
*/
void
_threadfree(Thread *t)
{
free(t->stk);
free(t->name);
free(t);
}
/*
* Create and initialize a new Proc structure with a single Thread
* running inside it. Add the Proc to the global process list.
*/
Proc*
_newproc(void)
{
Proc *p;
/*
* Allocate.
*/
p = _threadmalloc(sizeof *p, 1);
p->id = newprocid();
/*
* Add to list. Record if we're now multiprocess.
*/
lock(&_threadpq.lock);
if(_threadpq.head == nil)
_threadpq.head = p;
else
*_threadpq.tail = p;
_threadpq.tail = &p->next;
if(_threadnprocs == 1)
_threadmultiproc();
_threadnprocs++;
unlock(&_threadpq.lock);
return p;
}
/*
* Allocate a new thread running f(arg) on a stack of size stacksize.
* Return the thread id. The thread group inherits from the current thread.
*/
int
threadcreate(void (*f)(void*), void *arg, uint stacksize)
{
return _newthread(_threadgetproc(), f, arg, stacksize, nil, threadgetgrp());
}
/*
* Allocate a new idle thread. Only allowed in a single-proc program.
*/
int
threadcreateidle(void (*f)(void *arg), void *arg, uint stacksize)
{
int id;
assert(_threadpq.head->next == nil); /* only 1 */
id = threadcreate(f, arg, stacksize);
_threaddebug(DBGSCHED, "idle is %d", id);
_threadsetidle(id);
return id;
}
/*
* Threadcreate, but do it inside a fresh proc.
*/
int
proccreate(void (*f)(void*), void *arg, uint stacksize)
{
int id;
Proc *p, *np;
p = _threadgetproc();
np = _newproc();
p->newproc = np;
p->schedfn = _kthreadstartproc;
id = _newthread(np, f, arg, stacksize, nil, p->thread->grp);
_sched(); /* call into scheduler to create proc XXX */
return id;
}
/*
* Allocate a new thread id.
*/
static int
newthreadid(void)
{
static Lock l;
static int id;
int i;
lock(&l);
i = ++id;
unlock(&l);
return i;
}
/*
* Allocate a new proc id.
*/
static int
newprocid(void)
{
static Lock l;
static int id;
int i;
lock(&l);
i = ++id;
unlock(&l);
return i;
}
/*
* Add thread to proc's list.
*/
void
_procaddthread(Proc *p, Thread *t)
{
p->nthreads++;
if(p->threads.head == nil)
p->threads.head = t;
else{
t->prevt = p->threads.tail;
t->prevt->nextt = t;
}
p->threads.tail = t;
t->next = (Thread*)~0;
}
/*
* Remove thread from proc's list.
*/
void
_procdelthread(Proc *p, Thread *t)
{
if(t->prevt)
t->prevt->nextt = t->nextt;
else
p->threads.head = t->nextt;
if(t->nextt)
t->nextt->prevt = t->prevt;
else
p->threads.tail = t->prevt;
p->nthreads--;
}