Continue fighting pthreads.
Clean up thread library a bit too.
This commit is contained in:
parent
c6687d4591
commit
7966faa931
19 changed files with 539 additions and 654 deletions
|
|
@ -1,45 +1,46 @@
|
|||
#include "threadimpl.h"
|
||||
|
||||
Pqueue _threadpq;
|
||||
int _threadprocs;
|
||||
int __pthread_nonstandard_stacks;
|
||||
Pqueue _threadpq; /* list of all procs */
|
||||
int _threadnprocs; /* count of procs */
|
||||
|
||||
static int nextID(void);
|
||||
static int newthreadid(void);
|
||||
static int newprocid(void);
|
||||
|
||||
/*
|
||||
* Create and initialize a new Thread structure attached to a given proc.
|
||||
*/
|
||||
void
|
||||
_stackfree(void *v)
|
||||
{
|
||||
free(v);
|
||||
}
|
||||
|
||||
static int
|
||||
newthread(Proc *p, void (*f)(void *arg), void *arg, uint stacksize, char *name, int grp)
|
||||
int
|
||||
_newthread(Proc *p, void (*f)(void *arg), void *arg, uint stacksize,
|
||||
char *name, int grp)
|
||||
{
|
||||
int id;
|
||||
Thread *t;
|
||||
char *s;
|
||||
|
||||
__pthread_nonstandard_stacks = 1;
|
||||
if(stacksize < 32)
|
||||
sysfatal("bad stacksize %d", stacksize);
|
||||
t = _threadmalloc(sizeof(Thread), 1);
|
||||
t->lastfd = -1;
|
||||
s = _threadmalloc(stacksize, 0);
|
||||
t->stk = (uchar*)s;
|
||||
t->stksize = stacksize;
|
||||
_threaddebugmemset(s, 0xFE, stacksize);
|
||||
_threadinitstack(t, f, arg);
|
||||
t->proc = p;
|
||||
t->grp = grp;
|
||||
t->id = id = newthreadid();
|
||||
if(name)
|
||||
t->cmdname = strdup(name);
|
||||
t->id = nextID();
|
||||
id = t->id;
|
||||
t->next = (Thread*)~0;
|
||||
_threaddebug(DBGSCHED, "create thread %d.%d name %s", p->pid, t->id, 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);
|
||||
p->nthreads++;
|
||||
if(p->threads.head == nil)
|
||||
|
|
@ -49,14 +50,110 @@ newthread(Proc *p, void (*f)(void *arg), void *arg, uint stacksize, char *name,
|
|||
t->prevt->nextt = t;
|
||||
}
|
||||
p->threads.tail = t;
|
||||
t->next = (Thread*)~0;
|
||||
|
||||
/*
|
||||
* 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(_threadnprocs == 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 = _threadstartproc;
|
||||
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
|
||||
nextID(void)
|
||||
newthreadid(void)
|
||||
{
|
||||
static Lock l;
|
||||
static int id;
|
||||
|
|
@ -67,102 +164,20 @@ nextID(void)
|
|||
unlock(&l);
|
||||
return i;
|
||||
}
|
||||
|
||||
int
|
||||
procrfork(void (*f)(void *), void *arg, uint stacksize, int rforkflag)
|
||||
{
|
||||
Proc *p;
|
||||
int id;
|
||||
|
||||
p = _threadgetproc();
|
||||
assert(p->newproc == nil);
|
||||
p->newproc = _newproc(f, arg, stacksize, nil, p->thread->grp, rforkflag);
|
||||
id = p->newproc->threads.head->id;
|
||||
_sched();
|
||||
return id;
|
||||
}
|
||||
|
||||
int
|
||||
proccreate(void (*f)(void*), void *arg, uint stacksize)
|
||||
{
|
||||
Proc *p;
|
||||
|
||||
p = _threadgetproc();
|
||||
if(p->idle){
|
||||
fprint(2, "cannot create procs once there is an idle thread\n");
|
||||
werrstr("cannot create procs once there is an idle thread");
|
||||
return -1;
|
||||
}
|
||||
return procrfork(f, arg, stacksize, 0);
|
||||
}
|
||||
|
||||
void
|
||||
_freeproc(Proc *p)
|
||||
{
|
||||
Thread *t, *nextt;
|
||||
|
||||
for(t = p->threads.head; t; t = nextt){
|
||||
if(t->cmdname)
|
||||
free(t->cmdname);
|
||||
assert(t->stk != nil);
|
||||
_stackfree(t->stk);
|
||||
nextt = t->nextt;
|
||||
free(t);
|
||||
}
|
||||
free(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* 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)
|
||||
{
|
||||
return newthread(_threadgetproc(), f, arg, stacksize, nil, threadgetgrp());
|
||||
}
|
||||
|
||||
int
|
||||
threadcreateidle(void (*f)(void *arg), void *arg, uint stacksize)
|
||||
{
|
||||
int id;
|
||||
|
||||
if(_threadprocs!=1){
|
||||
fprint(2, "cannot have idle thread in multi-proc program\n");
|
||||
werrstr("cannot have idle thread in multi-proc program");
|
||||
return -1;
|
||||
}
|
||||
id = newthread(_threadgetproc(), f, arg, stacksize, nil, threadgetgrp());
|
||||
_threaddebug(DBGSCHED, "idle is %d", id);
|
||||
_threadidle();
|
||||
return id;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create and initialize a new Proc structure with a single Thread
|
||||
* running inside it. Add the Proc to the global process list.
|
||||
* Allocate a new proc id.
|
||||
*/
|
||||
Proc*
|
||||
_newproc(void (*f)(void *arg), void *arg, uint stacksize, char *name, int grp, int rforkflag)
|
||||
static int
|
||||
newprocid(void)
|
||||
{
|
||||
Proc *p;
|
||||
static Lock l;
|
||||
static int id;
|
||||
int i;
|
||||
|
||||
p = _threadmalloc(sizeof *p, 1);
|
||||
p->pid = -1;
|
||||
p->rforkflag = rforkflag;
|
||||
newthread(p, f, arg, stacksize, name, grp);
|
||||
|
||||
lock(&_threadpq.lock);
|
||||
if(_threadpq.head == nil)
|
||||
_threadpq.head = p;
|
||||
else
|
||||
*_threadpq.tail = p;
|
||||
_threadpq.tail = &p->next;
|
||||
|
||||
if(_threadprocs == 1)
|
||||
_threadmultiproc();
|
||||
_threadprocs++;
|
||||
unlock(&_threadpq.lock);
|
||||
return p;
|
||||
lock(&l);
|
||||
i = ++id;
|
||||
unlock(&l);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue