2003-09-30 17:47:42 +00:00
|
|
|
#include "threadimpl.h"
|
|
|
|
|
|
2004-09-23 03:01:36 +00:00
|
|
|
Pqueue _threadpq; /* list of all procs */
|
|
|
|
|
int _threadnprocs; /* count of procs */
|
2003-12-06 18:05:27 +00:00
|
|
|
|
2004-09-23 03:01:36 +00:00
|
|
|
static int newthreadid(void);
|
|
|
|
|
static int newprocid(void);
|
2003-09-30 17:47:42 +00:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Create and initialize a new Thread structure attached to a given proc.
|
|
|
|
|
*/
|
2004-09-23 03:01:36 +00:00
|
|
|
int
|
|
|
|
|
_newthread(Proc *p, void (*f)(void *arg), void *arg, uint stacksize,
|
|
|
|
|
char *name, int grp)
|
2003-09-30 17:47:42 +00:00
|
|
|
{
|
|
|
|
|
int id;
|
|
|
|
|
Thread *t;
|
|
|
|
|
|
|
|
|
|
t = _threadmalloc(sizeof(Thread), 1);
|
|
|
|
|
t->proc = p;
|
2004-10-22 18:45:08 +00:00
|
|
|
t->nextproc = p;
|
|
|
|
|
t->homeproc = p;
|
|
|
|
|
|
2003-09-30 17:47:42 +00:00
|
|
|
t->grp = grp;
|
2004-09-23 03:01:36 +00:00
|
|
|
t->id = id = newthreadid();
|
2003-09-30 17:47:42 +00:00
|
|
|
if(name)
|
2004-09-23 03:01:36 +00:00
|
|
|
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.
|
|
|
|
|
*/
|
2003-09-30 17:47:42 +00:00
|
|
|
lock(&p->lock);
|
2004-10-22 18:45:08 +00:00
|
|
|
_procaddthread(p, t);
|
2004-09-23 03:01:36 +00:00
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Mark thread as ready to run.
|
|
|
|
|
*/
|
2003-09-30 17:47:42 +00:00
|
|
|
t->state = Ready;
|
|
|
|
|
_threadready(t);
|
|
|
|
|
unlock(&p->lock);
|
2004-09-23 03:01:36 +00:00
|
|
|
|
2003-09-30 17:47:42 +00:00
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
|
2004-09-23 03:01:36 +00:00
|
|
|
/*
|
|
|
|
|
* Free a Thread structure.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
_threadfree(Thread *t)
|
2003-09-30 17:47:42 +00:00
|
|
|
{
|
2004-09-23 03:01:36 +00:00
|
|
|
free(t->stk);
|
|
|
|
|
free(t->name);
|
|
|
|
|
free(t);
|
2003-09-30 17:47:42 +00:00
|
|
|
}
|
|
|
|
|
|
2004-09-23 03:01:36 +00:00
|
|
|
/*
|
|
|
|
|
* 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)
|
2003-09-30 17:47:42 +00:00
|
|
|
{
|
2003-12-06 18:05:27 +00:00
|
|
|
Proc *p;
|
|
|
|
|
|
2004-09-23 03:01:36 +00:00
|
|
|
/*
|
|
|
|
|
* 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;
|
2003-09-30 17:47:42 +00:00
|
|
|
}
|
|
|
|
|
|
2004-09-23 03:01:36 +00:00
|
|
|
/*
|
|
|
|
|
* 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)
|
2003-09-30 17:47:42 +00:00
|
|
|
{
|
2004-09-23 03:01:36 +00:00
|
|
|
return _newthread(_threadgetproc(), f, arg, stacksize, nil, threadgetgrp());
|
2003-09-30 17:47:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
2004-09-23 03:01:36 +00:00
|
|
|
* Allocate a new idle thread. Only allowed in a single-proc program.
|
2003-09-30 17:47:42 +00:00
|
|
|
*/
|
|
|
|
|
int
|
2004-09-23 03:01:36 +00:00
|
|
|
threadcreateidle(void (*f)(void *arg), void *arg, uint stacksize)
|
2003-09-30 17:47:42 +00:00
|
|
|
{
|
2004-09-23 03:01:36 +00:00
|
|
|
int id;
|
|
|
|
|
|
2004-10-22 18:45:08 +00:00
|
|
|
assert(_threadpq.head->next == nil); /* only 1 */
|
2004-09-23 03:01:36 +00:00
|
|
|
|
|
|
|
|
id = threadcreate(f, arg, stacksize);
|
|
|
|
|
_threaddebug(DBGSCHED, "idle is %d", id);
|
|
|
|
|
_threadsetidle(id);
|
|
|
|
|
return id;
|
2003-09-30 17:47:42 +00:00
|
|
|
}
|
|
|
|
|
|
2004-09-23 03:01:36 +00:00
|
|
|
/*
|
|
|
|
|
* Threadcreate, but do it inside a fresh proc.
|
|
|
|
|
*/
|
2003-12-06 18:05:27 +00:00
|
|
|
int
|
2004-09-23 03:01:36 +00:00
|
|
|
proccreate(void (*f)(void*), void *arg, uint stacksize)
|
2003-12-06 18:05:27 +00:00
|
|
|
{
|
|
|
|
|
int id;
|
2004-09-23 03:01:36 +00:00
|
|
|
Proc *p, *np;
|
2003-12-06 18:05:27 +00:00
|
|
|
|
2004-09-23 03:01:36 +00:00
|
|
|
p = _threadgetproc();
|
|
|
|
|
np = _newproc();
|
|
|
|
|
p->newproc = np;
|
|
|
|
|
p->schedfn = _threadstartproc;
|
|
|
|
|
id = _newthread(np, f, arg, stacksize, nil, p->thread->grp);
|
|
|
|
|
_sched(); /* call into scheduler to create proc XXX */
|
2003-12-06 18:05:27 +00:00
|
|
|
return id;
|
|
|
|
|
}
|
|
|
|
|
|
2003-09-30 17:47:42 +00:00
|
|
|
/*
|
2004-09-23 03:01:36 +00:00
|
|
|
* Allocate a new thread id.
|
2003-09-30 17:47:42 +00:00
|
|
|
*/
|
2004-09-23 03:01:36 +00:00
|
|
|
static int
|
|
|
|
|
newthreadid(void)
|
2003-09-30 17:47:42 +00:00
|
|
|
{
|
2004-09-23 03:01:36 +00:00
|
|
|
static Lock l;
|
|
|
|
|
static int id;
|
|
|
|
|
int i;
|
2003-09-30 17:47:42 +00:00
|
|
|
|
2004-09-23 03:01:36 +00:00
|
|
|
lock(&l);
|
|
|
|
|
i = ++id;
|
|
|
|
|
unlock(&l);
|
|
|
|
|
return i;
|
|
|
|
|
}
|
2003-09-30 17:47:42 +00:00
|
|
|
|
2004-09-23 03:01:36 +00:00
|
|
|
/*
|
|
|
|
|
* Allocate a new proc id.
|
|
|
|
|
*/
|
|
|
|
|
static int
|
|
|
|
|
newprocid(void)
|
|
|
|
|
{
|
|
|
|
|
static Lock l;
|
|
|
|
|
static int id;
|
|
|
|
|
int i;
|
2004-04-29 17:13:24 +00:00
|
|
|
|
2004-09-23 03:01:36 +00:00
|
|
|
lock(&l);
|
|
|
|
|
i = ++id;
|
|
|
|
|
unlock(&l);
|
|
|
|
|
return i;
|
2003-09-30 17:47:42 +00:00
|
|
|
}
|
|
|
|
|
|
2004-10-22 18:45:08 +00:00
|
|
|
/*
|
|
|
|
|
* 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--;
|
|
|
|
|
}
|