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