pin
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)
 {