mirror of
https://github.com/9fans/plan9port.git
synced 2025-01-12 11:10:07 +00:00
pin
This commit is contained in:
parent
f936548b5e
commit
df970459f9
6 changed files with 87 additions and 0 deletions
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
11
src/lib9/pin.c
Normal file
|
@ -0,0 +1,11 @@
|
|||
#include <u.h>
|
||||
#include <libc.h>
|
||||
|
||||
static void
|
||||
nop(void)
|
||||
{
|
||||
}
|
||||
|
||||
void (*_pin)(void) = nop;
|
||||
void (*_unpin)(void) = nop;
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
Loading…
Reference in a new issue