diff options
-rw-r--r-- | include/libc.h | 3 | ||||
-rw-r--r-- | include/thread.h | 2 | ||||
-rw-r--r-- | man/man3/thread.3 | 18 | ||||
-rw-r--r-- | src/lib9/mkfile | 1 | ||||
-rw-r--r-- | src/lib9/pin.c | 11 | ||||
-rw-r--r-- | src/libthread/thread.c | 52 |
6 files changed, 87 insertions, 0 deletions
diff --git a/include/libc.h b/include/libc.h index 96b3f0c2..6a04b7b0 100644 --- a/include/libc.h +++ b/include/libc.h @@ -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 diff --git a/include/thread.h b/include/thread.h index 2a84e619..2301191d 100644 --- a/include/thread.h +++ b/include/thread.h @@ -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. diff --git a/man/man3/thread.3 b/man/man3/thread.3 index 92abb3f3..5145a543 100644 --- a/man/man3/thread.3 +++ b/man/man3/thread.3 @@ -37,6 +37,8 @@ threadmain, threadnotify, threadid, threadpid, +threadpin, +threadunpin, threadsetgrp, threadsetname, threadsetstate, @@ -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) @@ -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 diff --git a/src/lib9/mkfile b/src/lib9/mkfile index 143ca7db..ca615435 100644 --- a/src/lib9/mkfile +++ b/src/lib9/mkfile @@ -128,6 +128,7 @@ LIB9OFILES=\ nulldir.$O\ open.$O\ opentemp.$O\ + pin.$O\ pipe.$O\ post9p.$O\ postnote.$O\ diff --git a/src/lib9/pin.c b/src/lib9/pin.c new file mode 100644 index 00000000..3b15d3b8 --- /dev/null +++ b/src/lib9/pin.c @@ -0,0 +1,11 @@ +#include <u.h> +#include <libc.h> + +static void +nop(void) +{ +} + +void (*_pin)(void) = nop; +void (*_unpin)(void) = nop; + diff --git a/src/libthread/thread.c b/src/libthread/thread.c index acd56fa2..48dd3e18 100644 --- a/src/libthread/thread.c +++ b/src/libthread/thread.c @@ -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); @@ -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) { @@ -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; @@ -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; @@ -652,6 +690,8 @@ main(int argc, char **argv) _rsleep = threadrsleep; _rwakeup = threadrwakeup; _notejmpbuf = threadnotejmp; + _pin = threadpin; + _unpin = threadunpin; _pthreadinit(); p = procalloc(); @@ -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) { |