This commit is contained in:
rsc 2006-06-26 05:47:59 +00:00
parent f936548b5e
commit df970459f9
6 changed files with 87 additions and 0 deletions

View file

@ -417,6 +417,9 @@ extern long p9time(long*);
extern void needstack(int); extern void needstack(int);
extern char* readcons(char*, char*, int); extern char* readcons(char*, char*, int);
extern void (*_pin)(void);
extern void (*_unpin)(void);
#ifndef NOPLAN9DEFINES #ifndef NOPLAN9DEFINES
#define atexit p9atexit #define atexit p9atexit
#define atexitdont p9atexitdont #define atexitdont p9atexitdont

View file

@ -25,6 +25,8 @@ void _threadsleep(Rendez*);
_Thread *_threadwakeup(Rendez*); _Thread *_threadwakeup(Rendez*);
#define yield threadyield #define yield threadyield
int threadid(void); int threadid(void);
void _threadpin(void);
void _threadunpin(void);
/* /*
* I am tired of making this mistake. * I am tired of making this mistake.

View file

@ -37,6 +37,8 @@ threadmain,
threadnotify, threadnotify,
threadid, threadid,
threadpid, threadpid,
threadpin,
threadunpin,
threadsetgrp, threadsetgrp,
threadsetname, threadsetname,
threadsetstate, threadsetstate,
@ -84,6 +86,8 @@ int threadcreate(void (*fn)(void*), void *arg, uint stacksize)
void threadexits(char *status) void threadexits(char *status)
void threadexitsall(char *status) void threadexitsall(char *status)
void yield(void) void yield(void)
int threadpin(void)
int threadunpin(void)
.XX .XX
int threadid(void) int threadid(void)
int threadgrp(void) int threadgrp(void)
@ -260,6 +264,20 @@ System calls such as
block the entire proc; block the entire proc;
all threads in a proc block until the system call finishes. all threads in a proc block until the system call finishes.
.PP .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. 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. Thread ids are not reused; they are unique across the life of the program.
.I Threadid .I Threadid

View file

@ -128,6 +128,7 @@ LIB9OFILES=\
nulldir.$O\ nulldir.$O\
open.$O\ open.$O\
opentemp.$O\ opentemp.$O\
pin.$O\
pipe.$O\ pipe.$O\
post9p.$O\ post9p.$O\
postnote.$O\ postnote.$O\

11
src/lib9/pin.c Normal file
View file

@ -0,0 +1,11 @@
#include <u.h>
#include <libc.h>
static void
nop(void)
{
}
void (*_pin)(void) = nop;
void (*_unpin)(void) = nop;

View file

@ -12,6 +12,7 @@ static void addproc(Proc*);
static void delproc(Proc*); static void delproc(Proc*);
static void addthread(_Threadlist*, _Thread*); static void addthread(_Threadlist*, _Thread*);
static void delthread(_Threadlist*, _Thread*); static void delthread(_Threadlist*, _Thread*);
static int onlist(_Threadlist*, _Thread*);
static void addthreadinproc(Proc*, _Thread*); static void addthreadinproc(Proc*, _Thread*);
static void delthreadinproc(Proc*, _Thread*); static void delthreadinproc(Proc*, _Thread*);
static void contextswitch(Context *from, Context *to); static void contextswitch(Context *from, Context *to);
@ -254,6 +255,32 @@ threadexits(char *msg)
_threadswitch(); _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 static void
contextswitch(Context *from, Context *to) contextswitch(Context *from, Context *to)
{ {
@ -273,6 +300,14 @@ procscheduler(Proc *p)
/* print("s %p\n", p); */ /* print("s %p\n", p); */
lock(&p->lock); lock(&p->lock);
for(;;){ 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){ while((t = p->runqueue.head) == nil){
if(p->nthread == 0) if(p->nthread == 0)
goto Out; goto Out;
@ -291,6 +326,9 @@ procscheduler(Proc *p)
_procsleep(&p->runrend); _procsleep(&p->runrend);
_threaddebug("scheduler wake"); _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); delthread(&p->runqueue, t);
unlock(&p->lock); unlock(&p->lock);
p->thread = t; p->thread = t;
@ -652,6 +690,8 @@ main(int argc, char **argv)
_rsleep = threadrsleep; _rsleep = threadrsleep;
_rwakeup = threadrwakeup; _rwakeup = threadrwakeup;
_notejmpbuf = threadnotejmp; _notejmpbuf = threadnotejmp;
_pin = threadpin;
_unpin = threadunpin;
_pthreadinit(); _pthreadinit();
p = procalloc(); p = procalloc();
@ -697,6 +737,18 @@ delthread(_Threadlist *l, _Thread *t)
l->tail = t->prev; 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 static void
addthreadinproc(Proc *p, _Thread *t) addthreadinproc(Proc *p, _Thread *t)
{ {