Subversion Repositories planix.SVN

Rev

Rev 2 | Blame | Compare with Previous | Last modification | View Log | RSS feed

#include <u.h>
#include <libc.h>
#include <thread.h>
#include "threadimpl.h"

Pqueue _threadpq;

static int
nextID(void)
{
        static Lock l;
        static int id;
        int i;

        lock(&l);
        i = ++id;
        unlock(&l);
        return i;
}
        
/*
 * Create and initialize a new Thread structure attached to a given proc.
 */
static int
newthread(Proc *p, void (*f)(void *arg), void *arg, uint stacksize, char *name, int grp)
{
        int id;
        Thread *t;

        if(stacksize < 32)
                sysfatal("bad stacksize %d", stacksize);
        t = _threadmalloc(sizeof(Thread), 1);
        t->stksize = stacksize;
        t->stk = _threadmalloc(stacksize, 0);
        memset(t->stk, 0xFE, stacksize);
        _threadinitstack(t, f, arg);
        t->grp = grp;
        if(name)
                t->cmdname = strdup(name);
        t->id = nextID();
        id = t->id;
        t->next = (Thread*)~0;
        t->proc = p;
        _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
                *p->threads.tail = t;
        p->threads.tail = &t->nextt;
        t->nextt = nil;
        t->state = Ready;
        _threadready(t);
        unlock(&p->lock);
        return id;
}

/* 
 * 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;
}

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);
                free(t->stk);
                nextt = t->nextt;
                free(t);
        }
        free(p);
}

void
_freethread(Thread *t)
{
        Proc *p;
        Thread **l;

        p = t->proc;
        lock(&p->lock);
        for(l=&p->threads.head; *l; l=&(*l)->nextt){
                if(*l == t){
                        *l = t->nextt;
                        if(*l == nil)
                                p->threads.tail = l;
                        break;
                }
        }
        unlock(&p->lock);
        if (t->cmdname)
                free(t->cmdname);
        assert(t->stk != nil);
        free(t->stk);
        free(t);
}