pin
diff --git a/include/libc.h b/include/libc.h index 96b3f0c..6a04b7b 100644 --- a/include/libc.h +++ b/include/libc.h
@@ -417,6 +417,9 @@ 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 2a84e61..2301191 100644 --- a/include/thread.h +++ b/include/thread.h
@@ -25,6 +25,8 @@ _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 92abb3f..5145a54 100644 --- a/man/man3/thread.3 +++ b/man/man3/thread.3
@@ -37,6 +37,8 @@ threadnotify, threadid, threadpid, +threadpin, +threadunpin, threadsetgrp, threadsetname, threadsetstate, @@ -84,6 +86,8 @@ 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 @@ 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 143ca7d..ca61543 100644 --- a/src/lib9/mkfile +++ b/src/lib9/mkfile
@@ -128,6 +128,7 @@ 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 0000000..3b15d3b --- /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 acd56fa..48dd3e1 100644 --- a/src/libthread/thread.c +++ b/src/libthread/thread.c
@@ -12,6 +12,7 @@ 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 @@ _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 @@ /* 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 @@ _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 @@ _rsleep = threadrsleep; _rwakeup = threadrwakeup; _notejmpbuf = threadnotejmp; + _pin = threadpin; + _unpin = threadunpin; _pthreadinit(); p = procalloc(); @@ -697,6 +737,18 @@ 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) {