tpin - plan9port - [fork] Plan 9 from user space
 (HTM) git clone git://src.adamsgaard.dk/plan9port
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) README
 (DIR) LICENSE
       ---
 (DIR) commit df970459f9b37386fbfd4b7f3646825c8029caa8
 (DIR) parent f936548b5e1dc6cff6e422867a4265c64ebbcfd1
 (HTM) Author: rsc <devnull@localhost>
       Date:   Mon, 26 Jun 2006 05:47:59 +0000
       
       pin
       
       Diffstat:
         M include/libc.h                      |       3 +++
         M include/thread.h                    |       2 ++
         M man/man3/thread.3                   |      18 ++++++++++++++++++
         M src/lib9/mkfile                     |       1 +
         A src/lib9/pin.c                      |      11 +++++++++++
         M src/libthread/thread.c              |      52 +++++++++++++++++++++++++++++++
       
       6 files changed, 87 insertions(+), 0 deletions(-)
       ---
 (DIR) diff --git a/include/libc.h b/include/libc.h
       t@@ -417,6 +417,9 @@ extern        long        p9time(long*);
        extern        void        needstack(int);
        extern        char*        readcons(char*, char*, int);
        
       +extern        void        (*_pin)(void);
       +extern        void        (*_unpin)(void);
       +
        #ifndef NOPLAN9DEFINES
        #define atexit                p9atexit
        #define atexitdont        p9atexitdont
 (DIR) diff --git a/include/thread.h b/include/thread.h
       t@@ -25,6 +25,8 @@ void                _threadsleep(Rendez*);
        _Thread        *_threadwakeup(Rendez*);
        #define        yield                threadyield
        int                threadid(void);
       +void                _threadpin(void);
       +void                _threadunpin(void);
        
        /*
         * I am tired of making this mistake.
 (DIR) diff --git a/man/man3/thread.3 b/man/man3/thread.3
       t@@ -37,6 +37,8 @@ threadmain,
        threadnotify,
        threadid,
        threadpid,
       +threadpin,
       +threadunpin,
        threadsetgrp,
        threadsetname,
        threadsetstate,
       t@@ -84,6 +86,8 @@ int        threadcreate(void (*fn)(void*), void *arg, uint stacksize)
        void        threadexits(char *status)
        void        threadexitsall(char *status)
        void        yield(void)
       +int        threadpin(void)
       +int        threadunpin(void)
        .XX
        int        threadid(void)
        int        threadgrp(void)
       t@@ -260,6 +264,20 @@ System calls such as
        block the entire proc;
        all threads in a proc block until the system call finishes.
        .PP
       +.I Threadpin
       +disables scheduling inside a proc, `pinning' the current
       +thread as the only runnable one in the current proc.
       +.I Threadunpin
       +reenables scheduling, allowing other procs to run once the current
       +thread relinquishes the processor.
       +.I Threadpin
       +and
       +.I threadunpin
       +can lead to deadlock.
       +Used carefully, they can make library routines that use
       +.B qlocks
       +appear atomic relative to the current proc, like a system call.
       +.PP
        As mentioned above, each thread has a unique integer thread id.
        Thread ids are not reused; they are unique across the life of the program.
        .I Threadid
 (DIR) diff --git a/src/lib9/mkfile b/src/lib9/mkfile
       t@@ -128,6 +128,7 @@ LIB9OFILES=\
                nulldir.$O\
                open.$O\
                opentemp.$O\
       +        pin.$O\
                pipe.$O\
                post9p.$O\
                postnote.$O\
 (DIR) diff --git a/src/lib9/pin.c b/src/lib9/pin.c
       t@@ -0,0 +1,11 @@
       +#include <u.h>
       +#include <libc.h>
       +
       +static void
       +nop(void)
       +{
       +}
       +
       +void (*_pin)(void) = nop;
       +void (*_unpin)(void) = nop;
       +
 (DIR) diff --git a/src/libthread/thread.c b/src/libthread/thread.c
       t@@ -12,6 +12,7 @@ static        void                addproc(Proc*);
        static        void                delproc(Proc*);
        static        void                addthread(_Threadlist*, _Thread*);
        static        void                delthread(_Threadlist*, _Thread*);
       +static        int                onlist(_Threadlist*, _Thread*);
        static        void                addthreadinproc(Proc*, _Thread*);
        static        void                delthreadinproc(Proc*, _Thread*);
        static        void                contextswitch(Context *from, Context *to);
       t@@ -254,6 +255,32 @@ threadexits(char *msg)
                _threadswitch();
        }
        
       +void
       +threadpin(void)
       +{
       +        Proc *p;
       +
       +        p = proc();
       +        if(p->pinthread){
       +                fprint(2, "already pinning a thread - %p %p\n", p->pinthread, p->thread);
       +                assert(0);
       +        }
       +        p->pinthread = p->thread;
       +}
       +
       +void
       +threadunpin(void)
       +{
       +        Proc *p;
       +
       +        p = proc();
       +        if(p->pinthread != p->thread){
       +                fprint(2, "wrong pinthread - %p %p\n", p->pinthread, p->thread);
       +                assert(0);
       +        }
       +        p->pinthread = nil;
       +}
       +
        static void
        contextswitch(Context *from, Context *to)
        {
       t@@ -273,6 +300,14 @@ procscheduler(Proc *p)
        /*        print("s %p\n", p); */
                lock(&p->lock);
                for(;;){
       +                if((t = p->pinthread) != nil){
       +                        while(!onlist(&p->runqueue, t)){
       +                                p->runrend.l = &p->lock;
       +                                _threaddebug("scheduler sleep (pin)");
       +                                _procsleep(&p->runrend);
       +                                _threaddebug("scheduler wake (pin)");
       +                        }
       +                }else
                        while((t = p->runqueue.head) == nil){
                                if(p->nthread == 0)
                                        goto Out;
       t@@ -291,6 +326,9 @@ procscheduler(Proc *p)
                                _procsleep(&p->runrend);
                                _threaddebug("scheduler wake");
                        }
       +                if(p->pinthread && p->pinthread != t)
       +                        fprint(2, "p->pinthread %p t %p\n", p->pinthread, t);
       +                assert(p->pinthread == nil || p->pinthread == t);
                        delthread(&p->runqueue, t);
                        unlock(&p->lock);
                        p->thread = t;
       t@@ -652,6 +690,8 @@ main(int argc, char **argv)
                _rsleep = threadrsleep;
                _rwakeup = threadrwakeup;
                _notejmpbuf = threadnotejmp;
       +        _pin = threadpin;
       +        _unpin = threadunpin;
        
                _pthreadinit();
                p = procalloc();
       t@@ -697,6 +737,18 @@ delthread(_Threadlist *l, _Thread *t)
                        l->tail = t->prev;
        }
        
       +/* inefficient but rarely used */
       +static int
       +onlist(_Threadlist *l, _Thread *t)
       +{
       +        _Thread *tt;
       +
       +        for(tt = l->head; tt; tt=tt->next)
       +                if(tt == t)
       +                        return 1;
       +        return 0;
       +}
       +
        static void
        addthreadinproc(Proc *p, _Thread *t)
        {