diff options
Diffstat (limited to 'src/libthread/create.c')
-rw-r--r-- | src/libthread/create.c | 182 |
1 files changed, 182 insertions, 0 deletions
diff --git a/src/libthread/create.c b/src/libthread/create.c new file mode 100644 index 00000000..ab803a2c --- /dev/null +++ b/src/libthread/create.c @@ -0,0 +1,182 @@ +#include "threadimpl.h" + +#define free +Pqueue _threadpq; + +static int nextID(void); + +/* + * Create and initialize a new Thread structure attached to a given proc. + */ + +typedef struct Stack Stack; +struct Stack { + ulong magic; + Thread *thr; + Stack *next; + uchar buf[STKSIZE-12]; +}; + +static Stack *stkfree; +static Lock stklock; + +void +_stackfree(void *v) +{ + Stack *s; + + s = v; + lock(&stklock); + s->thr = nil; + s->magic = 0; + s->next = stkfree; + stkfree = s; + unlock(&stklock); +} + +static Stack* +stackalloc(void) +{ + char *buf; + Stack *s; + int i; + + lock(&stklock); + while(stkfree == nil){ + unlock(&stklock); + assert(STKSIZE == sizeof(Stack)); + buf = malloc(STKSIZE+128*STKSIZE); + s = (Stack*)(((ulong)buf+STKSIZE)&~(STKSIZE-1)); + for(i=0; i<128; i++) + _stackfree(&s[i]); + lock(&stklock); + } + s = stkfree; + stkfree = stkfree->next; + unlock(&stklock); + s->magic = STKMAGIC; + return s; +} + +static int +newthread(Proc *p, void (*f)(void *arg), void *arg, uint stacksize, char *name, int grp) +{ + int id; + Thread *t; + Stack *s; + + if(stacksize < 32) + sysfatal("bad stacksize %d", stacksize); + t = _threadmalloc(sizeof(Thread), 1); + s = stackalloc(); + s->thr = t; + t->stk = (char*)s; + t->stksize = STKSIZE; + _threaddebugmemset(s->buf, 0xFE, sizeof s->buf); + _threadinitstack(t, f, arg); + t->proc = p; + t->grp = grp; + 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); + lock(&p->lock); + 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->state = Ready; + _threadready(t); + unlock(&p->lock); + return id; +} + +static int +nextID(void) +{ + static Lock l; + static int id; + int i; + + lock(&l); + i = ++id; + 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) +{ + 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((Stack*)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()); +} + +/* + * 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 (*f)(void *arg), void *arg, uint stacksize, char *name, int grp, int rforkflag) +{ + Proc *p; + + 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; + unlock(&_threadpq.lock); + return p; +} + |