| #include "threadimpl.h" |
| |
| Pqueue _threadpq; |
| int _threadprocs; |
| |
| static int nextID(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 id; |
| Thread *t; |
| char *s; |
| |
| if(stacksize < 32) |
| sysfatal("bad stacksize %d", stacksize); |
| t = _threadmalloc(sizeof(Thread), 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; |
| 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) |
| { |
| 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. |
| */ |
| 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; |
| if(_threadprocs == 1) |
| _threadmultiproc(); |
| _threadprocs++; |
| unlock(&_threadpq.lock); |
| return p; |
| } |
| |