#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; }