try to implement the daemonize hack.
diff --git a/src/libthread/386.c b/src/libthread/386.c
index fb4c674..313c2be 100644
--- a/src/libthread/386.c
+++ b/src/libthread/386.c
@@ -1,6 +1,6 @@
+#if defined(__linux__)
 #include "ucontext.c"
-
-#ifdef OLD
+#else
 
 #include "threadimpl.h"
 /*
diff --git a/src/libthread/create.c b/src/libthread/create.c
index 290c52a..d2f4be2 100644
--- a/src/libthread/create.c
+++ b/src/libthread/create.c
@@ -18,6 +18,9 @@
 
 	t = _threadmalloc(sizeof(Thread), 1);
 	t->proc = p;
+	t->nextproc = p;
+	t->homeproc = p;
+
 	t->grp = grp;
 	t->id = id = newthreadid();
 	if(name)
@@ -42,15 +45,7 @@
 	 * Add thread to proc.
 	 */
 	lock(&p->lock);
-	p->nthreads++;
-	if(p->threads.head == nil)
-		p->threads.head = t;
-	else{
-		t->prevt = p->threads.tail;
-		t->prevt->nextt = t;
-	}
-	p->threads.tail = t;
-	t->next = (Thread*)~0;
+	_procaddthread(p, t);
 
 	/*
 	 * Mark thread as ready to run.
@@ -123,7 +118,7 @@
 {
 	int id;
 
-	assert(_threadnprocs == 1);
+	assert(_threadpq.head->next == nil);	/* only 1 */
 
 	id = threadcreate(f, arg, stacksize);
 	_threaddebug(DBGSCHED, "idle is %d", id);
@@ -181,3 +176,36 @@
 	return i;
 }
 
+/*
+ * Add thread to proc's list.
+ */
+void
+_procaddthread(Proc *p, Thread *t)
+{
+	p->nthreads++;
+	if(p->threads.head == nil)
+		p->threads.head = t;
+	else{
+		t->prevt = p->threads.tail;
+		t->prevt->nextt = t;
+	}
+	p->threads.tail = t;
+	t->next = (Thread*)~0;
+}
+
+/*
+ * Remove thread from proc's list.
+ */
+void
+_procdelthread(Proc *p, Thread *t)
+{
+	if(t->prevt)
+		t->prevt->nextt = t->nextt;
+	else
+		p->threads.head = t->nextt;
+	if(t->nextt)
+		t->nextt->prevt = t->prevt;
+	else
+		p->threads.tail = t->prevt;
+	p->nthreads--;
+}
diff --git a/src/libthread/exec-unix.c b/src/libthread/exec-unix.c
index 73a2faf..f69fedc 100644
--- a/src/libthread/exec-unix.c
+++ b/src/libthread/exec-unix.c
@@ -4,7 +4,7 @@
 #include "threadimpl.h"
 
 static void efork(int[3], int[2], char*, char**);
-static int
+int
 _threadexec(Channel *pidc, int fd[3], char *prog, char *args[], int freeargs)
 {
 	int pfd[2];
@@ -88,14 +88,14 @@
 void
 threadexec(Channel *pidc, int fd[3], char *prog, char *args[])
 {
-	if(_threadexec(pidc, fd, prog, args, 0) >= 0)
+	if(_callthreadexec(pidc, fd, prog, args, 0) >= 0)
 		threadexits(nil);
 }
 
 int
 threadspawn(int fd[3], char *prog, char *args[])
 {
-	return _threadexec(nil, fd, prog, args, 0);
+	return _callthreadexec(nil, fd, prog, args, 0);
 }
 
 /*
@@ -128,7 +128,7 @@
 	args[n] = 0;
 	va_end(arg);
 
-	if(_threadexec(pidc, fd, f, args, 1) >= 0)
+	if(_callthreadexec(pidc, fd, f, args, 1) >= 0)
 		threadexits(nil);
 }
 
diff --git a/src/libthread/fdwait.c b/src/libthread/fdwait.c
index 8768e60..a46ea45 100644
--- a/src/libthread/fdwait.c
+++ b/src/libthread/fdwait.c
@@ -163,7 +163,7 @@
 
 	if(!setup){
 		setup = 1;
-		threadcreateidle(pollidle, nil, 16384);
+		proccreate(pollidle, nil, 16384);
 	}
 }
 
diff --git a/src/libthread/main.c b/src/libthread/main.c
index 83ee177..ec08543 100644
--- a/src/libthread/main.c
+++ b/src/libthread/main.c
@@ -11,7 +11,11 @@
 	char **argv;
 };
 
+int _threadmainpid;
 int mainstacksize;
+int _callsthreaddaemonize;
+static int passtomainpid;
+
 extern void (*_sysfatal)(char*, va_list);
 
 static void
@@ -25,15 +29,53 @@
 	threadexits("threadmain");
 }
 
+static void
+passer(void *x, char *msg)
+{
+	USED(x);
+	Waitmsg *w;
+
+	if(strcmp(msg, "sys: usr2") == 0)
+		_exit(0);	/* daemonize */
+	else if(strcmp(msg, "sys: child") == 0){
+		w = wait();
+		if(w == nil)
+			_exit(1);
+		_exit(atoi(w->msg));
+	}else
+		postnote(PNPROC, passtomainpid, msg);
+}
+
 int
 main(int argc, char **argv)
 {
+	int pid;
 	Mainarg a;
 	Proc *p;
+	sigset_t mask;
 
 	/*
-	 * XXX Do daemonize hack here.
+	 * Do daemonize hack here.
 	 */
+	if(_callsthreaddaemonize){
+		passtomainpid = getpid();
+		switch(pid = fork()){
+		case -1:
+			sysfatal("fork: %r");
+
+		case 0:
+			/* continue executing */
+			_threadmainpid = getppid();
+			break;
+
+		default:
+			/* wait for signal USR2 */
+			notify(passer);
+			for(;;)
+				pause();
+			_exit(0);
+		}
+	}
 
 	/*
 	 * Instruct QLock et al. to use our scheduling functions
diff --git a/src/libthread/mkfile b/src/libthread/mkfile
index 20d08e0..e51d195 100644
--- a/src/libthread/mkfile
+++ b/src/libthread/mkfile
@@ -1,13 +1,15 @@
 <$PLAN9/src/mkhdr
 
 LIB=libthread.a
-
+THREAD=`sh ./thread.sh`
 OFILES=\
 	$OBJTYPE.$O\
+	$THREAD.$O\
 	asm-$SYSNAME-$OBJTYPE.$O\
 	channel.$O\
 	chanprint.$O\
 	create.$O\
+	daemon.$O\
 	debug.$O\
 	exec-unix.$O\
 	exit.$O\
@@ -28,7 +30,6 @@
 	memset.$O\
 	memsetd.$O\
 	note.$O\
-	pthread.$O\
 	read9pmsg.$O\
 	ref.$O\
 	sched.$O\
@@ -69,3 +70,4 @@
 
 CFLAGS=$CFLAGS $VG
 
+Linux-clone.$O: execproc.ch exit-getpid.ch proctab.ch procstack.ch
diff --git a/src/libthread/note.c b/src/libthread/note.c
index 94bf236..ed40c08 100644
--- a/src/libthread/note.c
+++ b/src/libthread/note.c
@@ -1,5 +1,6 @@
 #include "threadimpl.h"
 
+
 int	_threadnopasser;
 
 #define	NFN		33
diff --git a/src/libthread/pthread.c b/src/libthread/pthread.c
index a914f43..8d661c1 100644
--- a/src/libthread/pthread.c
+++ b/src/libthread/pthread.c
@@ -45,6 +45,25 @@
 }
 
 /*
+ * Called to start a new proc.
+ */
+void
+_threadstartproc(Proc *p)
+{
+	Proc *np;
+	pthread_t tid;
+	sigset_t all;
+
+	np = p->newproc;
+	sigfillset(&all);
+	pthread_sigmask(SIG_SETMASK, &all, nil);
+	if(pthread_create(&tid, nil, (void*(*)(void*))_threadscheduler, 
+			np) < 0)
+		sysfatal("pthread_create: %r");
+	np->pthreadid = tid;
+}
+
+/*
  * Called to associate p with the current pthread.
  */
 void
@@ -87,9 +106,10 @@
 
 /*
  * Separate process to wait for child messages.
+ * Also runs signal handlers.
  */
-Channel *_threadexecchan;
-void
+static Channel *_threadexecchan;
+static void
 _threadwaitproc(void *v)
 {
 	Channel *c;
@@ -124,6 +144,9 @@
 {
 }
 
+/*
+ * Called from mainlauncher before threadmain.
+ */
 void
 _threadmaininit(void)
 {
@@ -141,27 +164,12 @@
 	unlock(&_threadpq.lock);
 }
 
+/*
+ * Called after forking the exec child.
+ */
 void
 _threadafterexec(void)
 {
 	nbsendul(_threadexecchan, 1);
 }
 
-/*
- * Called to start a new proc.
- */
-void
-_threadstartproc(Proc *p)
-{
-	Proc *np;
-	pthread_t tid;
-	sigset_t all;
-
-	np = p->newproc;
-	sigfillset(&all);
-	pthread_sigmask(SIG_SETMASK, &all, nil);
-	if(pthread_create(&tid, nil, (void*(*)(void*))_threadscheduler, 
-			np) < 0)
-		sysfatal("pthread_create: %r");
-	np->pthreadid = tid;
-}
diff --git a/src/libthread/sched.c b/src/libthread/sched.c
index 55898f0..7e43019 100644
--- a/src/libthread/sched.c
+++ b/src/libthread/sched.c
@@ -51,28 +51,43 @@
 
 		/*
 		 * If thread needs to die, kill it.
+		 * t->proc == p may not be true if we're
+		 * trying to jump into the exec proc (see exec-unix.c).
 		 */
 		if(t->moribund){
 			_threaddebug(DBGSCHED, "moribund %d.%d", p->id, t->id);
+			if(t->moribund != 1)
+				print("moribund broke %p %d\n", &t->moribund, t->moribund);
 			assert(t->moribund == 1);
 			t->state = Dead;
-			if(t->prevt)
-				t->prevt->nextt = t->nextt;
-			else
-				p->threads.head = t->nextt;
-			if(t->nextt)
-				t->nextt->prevt = t->prevt;
-			else
-				p->threads.tail = t->prevt;
+			_procdelthread(p, t);
 			unlock(&p->lock);
 			_threadfree(t);
-			p->nthreads--;
 			t = nil;
 			continue;
 		}
+
+		/*
+		 * If the thread has asked to move to another proc,
+		 * let it go (only to be used in *very* special situations).
+		if(t->nextproc != p)
+			_procdelthread(p, t);
+		 */
+
 		unlock(&p->lock);
 
 		/*
+		 * If the thread has asked to move to another proc,
+		 * add it to the new proc.
+		 */
+		if(t->nextproc != p){
+		//	lock(&t->nextproc->lock);
+		//	_procaddthread(t->nextproc, t);
+		//	unlock(&t->nextproc->lock);
+			t->proc = t->nextproc;
+		}
+
+		/*
 		 * If there is a request to run a function on the 
 		 * scheduling stack, do so.
 		 */
@@ -87,7 +102,7 @@
 		 * Move the thread along.
 		 */
 		t->state = t->nextstate;
-		_threaddebug(DBGSCHED, "moveon %d.%d", p->id, t->id);
+		_threaddebug(DBGSCHED, "moveon %d.%d", t->proc->id, t->id);
 		if(t->state == Ready)
 			_threadready(t);
 	}
diff --git a/src/libthread/texec.c b/src/libthread/texec.c
index bcfabee..c9682e3 100644
--- a/src/libthread/texec.c
+++ b/src/libthread/texec.c
@@ -22,15 +22,20 @@
 {
 	Channel *c;
 	Waitmsg *w;
+	int (*mk)(void(*)(void*), void*, uint);
 
+	mk = threadcreate;
 	ARGBEGIN{
 	case 'D':
 		_threaddebuglevel = ~0;
 		break;
+	case 'p':
+		mk = proccreate;
+		break;
 	}ARGEND
 
 	c = threadwaitchan();
-	proccreate(doexec, argv, 8192);
+	mk(doexec, argv, 8192);
 	w = recvp(c);
 	if(w == nil)
 		print("exec/recvp failed: %r\n");
diff --git a/src/libthread/threadimpl.h b/src/libthread/threadimpl.h
index 7c9a66b..8d7a7a7 100644
--- a/src/libthread/threadimpl.h
+++ b/src/libthread/threadimpl.h
@@ -70,11 +70,13 @@
 	int		asleep;		/* thread is in _threadsleep */
 	Label	context;		/* for context switches */
 	int 		grp;			/* thread group */
+	Proc		*homeproc;	/* ``home'' proc */
 	int		id;			/* thread id */
 	int		moribund;	/* thread needs to die */
 	char		*name;		/* name of thread */
 	Thread	*next;		/* next on ready queue */
 	Thread	*nextt;		/* next on list of threads in this proc */
+	Proc		*nextproc;	/* next proc in which to run (rarely changes) */
 	State		nextstate;		/* next run state */
 	Proc		*proc;		/* proc of this thread */
 	Thread	*prevt;		/* prev on list of threads in this proc */
@@ -117,6 +119,7 @@
 	Thread	*thread;		/* running thread */
 	Thread	*idle;			/* idle thread */
 	int		id;
+	int		procid;
 
 	int		needexec;
 	Execargs	exec;		/* exec argument */
@@ -195,7 +198,9 @@
 void		_threadstartproc(Proc*);
 void		_threadexitproc(char*);
 void		_threadexitallproc(char*);
+void		_threadefork(int[3], int[2], char*, char**);
 
+extern int			_threadmainpid;
 extern int			_threadnprocs;
 extern int			_threaddebuglevel;
 extern char*		_threadexitsallstatus;
@@ -214,3 +219,11 @@
 extern void _threaddebugmemset(void*, int, int);
 extern int _threadprocs;
 extern void _threadstacklimit(void*, void*);
+extern void _procdelthread(Proc*, Thread*);
+extern void _procaddthread(Proc*, Thread*);
+
+extern void _threadafterexec(void);
+extern void _threadmaininit(void);
+extern void _threadfirstexec(void);
+extern int _threadexec(Channel*, int[3], char*, char*[], int);
+extern int _callthreadexec(Channel*, int[3], char*, char*[], int);