commit df970459f9b37386fbfd4b7f3646825c8029caa8 from: rsc date: Mon Jun 26 05:47:59 2006 UTC pin commit - f936548b5e1dc6cff6e422867a4265c64ebbcfd1 commit + df970459f9b37386fbfd4b7f3646825c8029caa8 blob - 96b3f0c237c861a8c284ed808f591d44e682e63e blob + 6a04b7b0b25673fd343594abe7a379d520386c65 --- include/libc.h +++ 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 blob - 2a84e619461835702aaad40c00ce682aad8fc691 blob + 2301191d7738c27508f6cab69b9a3e7b02de0fcc --- include/thread.h +++ 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. blob - 92abb3f3c4165af235fbb35dcf7c193ae9de8861 blob + 5145a5432a1f49d9cb7bf0ec3eb2be8d1aea12dd --- man/man3/thread.3 +++ 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 st void threadexits(char *status) void threadexitsall(char *status) void yield(void) +int threadpin(void) +int threadunpin(void) .XX int threadid(void) int threadgrp(void) @@ -259,6 +263,20 @@ System calls such as .IR read (3) 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. blob - 143ca7dba06229e63e4f0ffa8a034efc6f3af54a blob + ca615435012dae92e388b6597dfa0f7afbdf3385 --- src/lib9/mkfile +++ src/lib9/mkfile @@ -128,6 +128,7 @@ LIB9OFILES=\ nulldir.$O\ open.$O\ opentemp.$O\ + pin.$O\ pipe.$O\ post9p.$O\ postnote.$O\ blob - /dev/null blob + 3b15d3b8aa4fb259ed7e21e02f3eb4d4a9a77bdd (mode 644) --- /dev/null +++ src/lib9/pin.c @@ -0,0 +1,11 @@ +#include +#include + +static void +nop(void) +{ +} + +void (*_pin)(void) = nop; +void (*_unpin)(void) = nop; + blob - acd56fa2ef285dede473a9f06fced8be142aa41a blob + 48dd3e18ea167d6072d9d6d425acb6f7f8257bca --- src/libthread/thread.c +++ 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); @@ -252,6 +253,32 @@ threadexits(char *msg) utfecpy(p->msg, p->msg+sizeof p->msg, msg); proc()->thread->exiting = 1; _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 @@ -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) {