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 char* readcons(char*, char*, int);
extern void (*_pin)(void);
extern void (*_unpin)(void);
#ifndef NOPLAN9DEFINES
#define atexit p9atexit
#define atexitdont p9atexitdont

View file

@ -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.

View file

@ -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

View file

@ -128,6 +128,7 @@ LIB9OFILES=\
nulldir.$O\
open.$O\
opentemp.$O\
pin.$O\
pipe.$O\
post9p.$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 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)
{