Commit Diff


commit - 7788fd54094693384ef5c92c475656dba8819feb
commit + 1544f90960275dc9211bde30329c3258e0e1bf38
blob - 313c2be5fa5ee8932e6022879936268ce7cfbc9a (mode 644)
blob + /dev/null
--- src/libthread/386.c
+++ /dev/null
@@ -1,62 +0,0 @@
-#if defined(__linux__)
-#include "ucontext.c"
-#else
-
-#include "threadimpl.h"
-/*
- * To use this you need some patches to Valgrind that
- * let it help out with detecting stack overflow. 
- */
-#ifdef USEVALGRIND
-#include <valgrind/memcheck.h>
-#endif
-
-static void
-launcher386(void (*f)(void *arg), void *arg)
-{
-	Proc *p;
-	Thread *t;
-
-	p = _threadgetproc();
-	t = p->thread;
-	_threadstacklimit(t->stk, t->stk+t->stksize);
-
-	(*f)(arg);
-	threadexits(nil);
-}
-
-void
-_threadinitstack(Thread *t, void (*f)(void*), void *arg)
-{
-	ulong *tos;
-
-	tos = (ulong*)&t->stk[t->stksize&~7];
-	*--tos = (ulong)arg;
-	*--tos = (ulong)f;
-	t->sched.pc = (ulong)launcher386;
-	t->sched.sp = (ulong)tos - 8;		/* old PC and new PC */
-}
-
-void
-_threadinswitch(int enter)
-{
-	USED(enter);
-#ifdef USEVALGRIND
-	if(enter)
-		VALGRIND_SET_STACK_LIMIT(0, 0, 0);
-	else
-		VALGRIND_SET_STACK_LIMIT(0, 0, 1);
-#endif
-}
-
-void
-_threadstacklimit(void *bottom, void *top)
-{
-	USED(bottom);
-	USED(top);
-
-#ifdef USEVALGRIND
-	VALGRIND_SET_STACK_LIMIT(1, bottom, top);
-#endif
-}
-#endif
blob - /dev/null
blob + 2cbb443729dde56b7af17a6e338ee32de1c2d459 (mode 644)
--- /dev/null
+++ src/libthread/exec.c
@@ -0,0 +1,153 @@
+#include "u.h"
+#include <errno.h>
+#include "libc.h"
+#include "thread.h"
+#include "threadimpl.h"
+
+static Lock thewaitlock;
+static Channel *thewaitchan;
+static Channel *dowaitchan;
+
+/* BUG - start waitproc on first exec, not when threadwaitchan is called */
+static void
+waitproc(void *v)
+{
+	Channel *c;
+	Waitmsg *w;
+
+	_threadsetsysproc();
+	for(;;){
+		while((w = wait()) == nil){
+			if(errno == ECHILD)
+				recvul(dowaitchan);
+		}
+		if((c = thewaitchan) != nil)
+			sendp(c, w);
+		else
+			free(w);
+	}
+}
+
+Channel*
+threadwaitchan(void)
+{
+	if(thewaitchan)
+		return thewaitchan;
+	lock(&thewaitlock);
+	if(thewaitchan){
+		unlock(&thewaitlock);
+		return thewaitchan;
+	}
+	thewaitchan = chancreate(sizeof(Waitmsg*), 4);
+	chansetname(thewaitchan, "threadwaitchan");
+	dowaitchan = chancreate(sizeof(ulong), 1);
+	chansetname(dowaitchan, "dowaitchan");
+	proccreate(waitproc, nil, STACK);
+	unlock(&thewaitlock);
+	return thewaitchan;
+}
+
+int
+threadspawn(int fd[3], char *cmd, char *argv[])
+{
+	int i, n, p[2], pid;
+	char exitstr[100];
+
+	if(pipe(p) < 0)
+		return -1;
+	if(fcntl(p[0], F_SETFD, 1) < 0 || fcntl(p[1], F_SETFD, 1) < 0){
+		close(p[0]);
+		close(p[1]);
+		return -1;
+	}
+	switch(pid = fork()){
+	case -1:
+		close(p[0]);
+		close(p[1]);
+		return -1;
+	case 0:
+		dup2(fd[0], 0);
+		dup2(fd[1], 1);
+		dup2(fd[2], 2);
+		for(i=3; i<100; i++)
+			if(i != p[1])
+				close(i);
+		execvp(cmd, argv);
+		fprint(p[1], "%d", errno);
+		close(p[1]);
+		_exit(0);
+	}
+
+	close(p[1]);
+	n = read(p[0], exitstr, sizeof exitstr-1);
+	close(p[0]);
+	if(n > 0){	/* exec failed */
+		exitstr[n] = 0;
+		errno = atoi(exitstr);
+		return -1;
+	}
+
+	close(fd[0]);
+	if(fd[1] != fd[0])
+		close(fd[1]);
+	if(fd[2] != fd[1] && fd[2] != fd[0])
+		close(fd[2]);
+	channbsendul(dowaitchan, 1);
+	return pid;
+}
+
+int
+_threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])
+{
+	int pid;
+
+	pid = threadspawn(fd, cmd, argv);
+	if(cpid){
+		if(pid < 0)
+			chansendul(cpid, ~0);
+		else
+			chansendul(cpid, pid);
+	}
+	return pid;
+}
+
+void
+threadexec(Channel *cpid, int fd[3], char *cmd, char *argv[])
+{
+	if(_threadexec(cpid, fd, cmd, argv) >= 0)
+		threadexits("threadexec");
+}
+
+void
+threadexecl(Channel *cpid, int fd[3], char *cmd, ...)
+{
+	char **argv, *s;
+	int n, pid;
+	va_list arg;
+
+	va_start(arg, cmd);
+	for(n=0; va_arg(arg, char*) != nil; n++)
+		;
+	n++;
+	va_end(arg);
+
+	argv = malloc(n*sizeof(argv[0]));
+	if(argv == nil){
+		if(cpid)
+			chansendul(cpid, ~0);
+		return;
+	}
+
+	va_start(arg, cmd);
+	for(n=0; (s=va_arg(arg, char*)) != nil; n++)
+		argv[n] = s;
+	argv[n] = 0;
+	va_end(arg);
+
+	pid = _threadexec(cpid, fd, cmd, argv);
+	free(argv);
+
+	if(pid >= 0)
+		threadexits("threadexecl");
+}
+
blob - 624518e07715768157dd775b8f66c60a5114a02b (mode 644)
blob + /dev/null
--- src/libthread/FreeBSD-386.s
+++ /dev/null
@@ -1,18 +0,0 @@
-
-.globl	_xinc
-_xinc:
-	movl 4(%esp), %eax
-	lock incl 0(%eax)
-	ret
-
-.globl	_xdec
-_xdec:
-	movl 4(%esp), %eax
-	lock decl 0(%eax)
-	jz iszero
-	movl %eax, 1
-	ret
-iszero:
-	movl %eax, 0
-	ret
-
blob - /dev/null
blob + 2ad80878a429de33d164fbd91f681f6d35be0b50 (mode 644)
--- /dev/null
+++ src/libthread/iorw.c
@@ -0,0 +1,178 @@
+#include <u.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <libc.h>
+#include <fcall.h>
+#include <thread.h>
+#include "ioproc.h"
+
+static long
+_ioclose(va_list *arg)
+{
+	int fd;
+
+	fd = va_arg(*arg, int);
+	return close(fd);
+}
+int
+ioclose(Ioproc *io, int fd)
+{
+	return iocall(io, _ioclose, fd);
+}
+
+static long
+_iodial(va_list *arg)
+{
+	char *addr, *local, *dir;
+	int *cdfp, fd;
+
+	addr = va_arg(*arg, char*);
+	local = va_arg(*arg, char*);
+	dir = va_arg(*arg, char*);
+	cdfp = va_arg(*arg, int*);
+
+	fd = dial(addr, local, dir, cdfp);
+	return fd;
+}
+int
+iodial(Ioproc *io, char *addr, char *local, char *dir, int *cdfp)
+{
+	return iocall(io, _iodial, addr, local, dir, cdfp);
+}
+
+static long
+_ioopen(va_list *arg)
+{
+	char *path;
+	int mode;
+
+	path = va_arg(*arg, char*);
+	mode = va_arg(*arg, int);
+	return open(path, mode);
+}
+int
+ioopen(Ioproc *io, char *path, int mode)
+{
+	return iocall(io, _ioopen, path, mode);
+}
+
+static long
+_ioread(va_list *arg)
+{
+	int fd;
+	void *a;
+	long n;
+
+	fd = va_arg(*arg, int);
+	a = va_arg(*arg, void*);
+	n = va_arg(*arg, long);
+	return read(fd, a, n);
+}
+long
+ioread(Ioproc *io, int fd, void *a, long n)
+{
+	return iocall(io, _ioread, fd, a, n);
+}
+
+static long
+_ioreadn(va_list *arg)
+{
+	int fd;
+	void *a;
+	long n;
+
+	fd = va_arg(*arg, int);
+	a = va_arg(*arg, void*);
+	n = va_arg(*arg, long);
+	n = readn(fd, a, n);
+	return n;
+}
+long
+ioreadn(Ioproc *io, int fd, void *a, long n)
+{
+	return iocall(io, _ioreadn, fd, a, n);
+}
+
+static long
+_iosleep(va_list *arg)
+{
+	long n;
+
+	n = va_arg(*arg, long);
+	return sleep(n);
+}
+int
+iosleep(Ioproc *io, long n)
+{
+	return iocall(io, _iosleep, n);
+}
+
+static long
+_iowrite(va_list *arg)
+{
+	int fd;
+	void *a;
+	long n, nn;
+
+	fd = va_arg(*arg, int);
+	a = va_arg(*arg, void*);
+	n = va_arg(*arg, long);
+	nn = write(fd, a, n);
+	return nn;
+}
+long
+iowrite(Ioproc *io, int fd, void *a, long n)
+{
+	return iocall(io, _iowrite, fd, a, n);
+}
+
+static long
+_iosendfd(va_list *arg)
+{
+	int n, fd, fd2;
+
+	fd = va_arg(*arg, int);
+	fd2 = va_arg(*arg, int);
+	n = sendfd(fd, fd2);
+	return n;
+}
+int
+iosendfd(Ioproc *io, int fd, int fd2)
+{
+	return iocall(io, _iosendfd, fd, fd2);
+}
+
+static long
+_iorecvfd(va_list *arg)
+{
+	int n, fd;
+
+	fd = va_arg(*arg, int);
+	n = recvfd(fd);
+	return n;
+}
+int
+iorecvfd(Ioproc *io, int fd)
+{
+	return iocall(io, _iorecvfd, fd);
+}
+
+static long
+_ioread9pmsg(va_list *arg)
+{
+	int fd;
+	void *a;
+	int n;
+	int r;
+
+	fd = va_arg(*arg, int);
+	a = va_arg(*arg, void*);
+	n = va_arg(*arg, int);
+	r = read9pmsg(fd, a, n);
+	return n;
+}
+int
+ioread9pmsg(Ioproc *io, int fd, void *a, int n)
+{
+	return iocall(io, _ioread9pmsg, fd, a, n);
+}
blob - 1f5e3bdeb7d436f0844d6940dcd8df8706ed26ae (mode 644)
blob + /dev/null
--- src/libthread/Linux-clone.c
+++ /dev/null
@@ -1,185 +0,0 @@
-#include <u.h>
-#include <errno.h>
-#include <sched.h>
-#include <sys/signal.h>
-#include <sys/wait.h>
-#include "threadimpl.h"
-
-#define procid()		getpid()
-#define procexited(id)	(kill((id), 0) < 0 && errno==ESRCH)
-
-static int multi;
-static Proc *theproc;
-
-/*
- * Run all execs forked from a special exec proc.
- */
-#include "execproc.ch"
-
-/*
- * Use _exits to exit one proc, and signals to tear everyone else down.
- */
-#include "exit-getpid.ch"
-
-/*
- * Use table for _threadmultiproc, _threadsetproc, _threadgetproc.
- */
-#include "proctab.ch"
-
-/*
- * Use per-process stack allocation code.
- */
-#include "procstack.ch"
-
-/*
- * Implement _threadstartproc using clone.
- * 
- * Cannot use this on newer kernels (2.6+) because
- * on those kernels clone allows you to set up a per-thread
- * segment using %gs, and the C library and compilers
- * assume that you've done this.  I don't want to learn
- * how to do this (the code below is scary enough),
- * so on those more recent kernels we use nptl (the
- * pthreads implementation), which is finally good enough.
- */
-
-/*
- * Trampoline to run f(arg).
- */
-static int
-tramp(void *v)
-{
-	void (*fn)(void*), *arg;
-	void **v2;
-	void *p;
-
-	v2 = v;
-	fn = v2[0];
-	arg = v2[1];
-	p = v2[2];
-	free(v2);
-	fn(arg);
-	abort();	/* not reached! */
-	return 0;
-}
-
-/*
- * Trampnowait runs in the child, and starts a granchild to run f(arg).
- * When trampnowait proc exits, the connection between the
- * grandchild running f(arg) and the parent/grandparent is lost, so the
- * grandparent need not worry about cleaning up a zombie
- * when the grandchild finally exits.
- */
-static int
-trampnowait(void *v)
-{
-	int pid;
-	int cloneflag;
-	void **v2;
-	int *pidp;
-	void *p;
-
-	v2 = v;
-	cloneflag = (int)v2[4];
-	pidp = v2[3];
-	p = v2[2];
-	pid = clone(tramp, p+fforkstacksize-512, cloneflag, v);
-	*pidp = pid;
-	_exit(0);
-	return 0;
-}
-
-static int
-ffork(int flags, void (*fn)(void*), void *arg)
-{
-	void **v;
-	char *p;
-	int cloneflag, pid, thepid, status, nowait;
-
-	p = mallocstack();
-	v = malloc(sizeof(void*)*5);
-	if(p==nil || v==nil){
-		freestack(p);
-		free(v);
-		return -1;
-	}
-	cloneflag = 0;
-	flags &= ~RFPROC;
-	if(flags&RFMEM){
-		cloneflag |= CLONE_VM;
-		flags &= ~RFMEM;
-	}
-	if(!(flags&RFFDG))
-		cloneflag |= CLONE_FILES;
-	else
-		flags &= ~RFFDG;
-	nowait = flags&RFNOWAIT;
-//	if(!(flags&RFNOWAIT))
-//		cloneflag |= SIGCHLD;
-//	else
-		flags &= ~RFNOWAIT;
-	if(flags){
-		fprint(2, "unknown rfork flags %x\n", flags);
-		freestack(p);
-		free(v);
-		return -1;
-	}
-	v[0] = fn;
-	v[1] = arg;
-	v[2] = p;
-	v[3] = &thepid;
-	v[4] = (void*)cloneflag;
-	thepid = -1;
-	pid = clone(nowait ? trampnowait : tramp, p+fforkstacksize-16, cloneflag, v);
-	if(pid > 0 && nowait){
-		if(wait4(pid, &status, __WALL, 0) < 0)
-			fprint(2, "ffork wait4: %r\n");
-	}else
-		thepid = pid;
-	if(thepid == -1)
-		freestack(p);
-	else{
-		((Stack*)p)->pid = thepid;
-	}
-	return thepid;
-}
-
-/*
- * Called to start a new proc.
- */
-void
-_threadstartproc(Proc *p)
-{
-	int pid;
-	Proc *np;
-
-	np = p->newproc;
-	pid = ffork(RFPROC|RFMEM|RFNOWAIT, _threadscheduler, np);
-	if(pid == -1)
-		sysfatal("starting new proc: %r");
-	np->pid = pid;
-}
-
-/*
- * Called to associate p with the current pthread.
- */
-void
-_threadinitproc(Proc *p)
-{
-	sigset_t mask;
-
-	p->pid = getpid();
-	sigemptyset(&mask);
-	sigaddset(&mask, WAITSIG);
-	sigprocmask(SIG_BLOCK, &mask, nil);
-	_threadsetproc(p);
-}
-
-/*
- * Called from mainlauncher before threadmain.
- */
-void
-_threadmaininit(void)
-{
-}
-
blob - /dev/null
blob + 30a0c9e17681a98b1bc4a7d2e6ce06c2650bdd69 (mode 644)
--- /dev/null
+++ src/libthread/qlock.c
@@ -0,0 +1,3 @@
+#include "u.h"
+#include "libc.h"
+
blob - 8bf69d6af9b8b0844389840746e10387e789f7b4 (mode 644)
blob + /dev/null
--- src/libthread/NOTICE
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * The authors of this software are Russ Cox, Sape Mullender, and Rob Pike.
- *		Copyright (c) 2003 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
- * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
-*/
-
-This is a Unix port of the Plan 9 thread library.
-
-Please send comments about the packaging
-to Russ Cox <rsc@post.harvard.edu>.
-
blob - /dev/null
blob + 73b600e7df015762cbe95af5a12dc59acf7a5d1e (mode 644)
--- /dev/null
+++ src/libthread/test/pthreadloop.c
@@ -0,0 +1,38 @@
+#include <pthread.h>
+#include <utf.h>
+#include <fmt.h>
+
+pthread_key_t key;
+
+void
+pexit(void *v)
+{
+	int s;
+
+	pthread_setspecific(key, (void*)1);
+	switch(fork()){
+	case -1:
+		fprint(2, "fork: %r\n");
+	case 0:
+		_exit(0);
+	default:
+		wait(&s);
+	}
+	pthread_exit(0);
+}
+
+int
+main(int argc, char *argv[])
+{
+	int i;
+	pthread_t pid;
+
+	pthread_key_create(&key, 0);
+	for(i=0;; i++){
+		print("%d\n", i);
+		if(pthread_create(&pid, 0, pexit, 0) < 0){
+			fprint(2, "pthread_create: %r\n");
+			abort();
+		}
+	}
+}
blob - /dev/null
blob + 91af5a73318cb73acd0c51a826a23a0868546ff5 (mode 644)
--- /dev/null
+++ src/libthread/test/tprimes.c
@@ -0,0 +1,80 @@
+#include "u.h"
+#include "libc.h"
+#include "thread.h"
+
+enum
+{
+	STACK = 8192
+};
+
+int max = 10000;
+int (*mk)(void (*fn)(void*), void *arg, uint stack);
+
+void
+countthread(void *v)
+{
+	uint i;
+	Channel *c;
+
+	c = v;
+	for(i=2;; i++){
+		sendul(c, i);
+	}
+}
+
+void
+filterthread(void *v)
+{
+	uint i, p;
+	Channel *c, *nextc;
+
+	c = v;
+	p = recvul(c);
+	print("%d\n", p);
+	if(p > max)
+		threadexitsall(0);
+	nextc = chancreate(sizeof(ulong), 0);
+	mk(filterthread, nextc, STACK);
+	for(;;){
+		i = recvul(c);
+		if(i%p)
+			sendul(nextc, i);
+	}
+}
+
+void
+usage(void)
+{
+	fprint(2, "usage: tprimes [-p] [max]\n");
+	threadexitsall("usage");
+}
+
+void
+threadmain(int argc, char **argv)
+{
+	Channel *c;
+	int nbuf;
+
+	nbuf = 0;
+	mk = threadcreate;
+	ARGBEGIN{
+	default:
+		usage();
+	case 'b':
+		nbuf = atoi(EARGF(usage()));
+		break;
+	case 'p':
+		mk = proccreate;
+		max = 1000;
+		break;
+	}ARGEND
+
+	if(argc == 1)
+		max = atoi(argv[0]);
+	else if(argc)
+		usage();
+
+	c = chancreate(sizeof(ulong), nbuf);
+	mk(countthread, c, STACK);
+	mk(filterthread, c, STACK);
+}
blob - /dev/null
blob + ed4df3c491c6e2fbc8af61eac7259fc2f776bc5b (mode 644)
--- /dev/null
+++ src/libthread/test/tspawn.c
@@ -0,0 +1,39 @@
+#include "u.h"
+#include "libc.h"
+#include "thread.h"
+
+void
+threadmain(int argc, char **argv)
+{
+	int fd[3];
+	Channel *c;
+	Waitmsg *w;
+
+	ARGBEGIN{
+	case 'D':
+		break;
+	}ARGEND
+
+	c = threadwaitchan();
+	fd[0] = dup(0, -1);
+	fd[1] = dup(1, -1);
+	fd[2] = dup(2, -1);
+	if(threadspawn(fd, argv[0], argv) < 0)
+		sysfatal("threadspawn: %r");
+	fd[0] = dup(0, -1);
+	fd[1] = dup(1, -1);
+	fd[2] = dup(2, -1);
+	if(threadspawn(fd, argv[0], argv) < 0)
+		sysfatal("threadspawn: %r");
+	w = recvp(c);
+	if(w == nil)
+		print("exec/recvp failed: %r\n");
+	else
+		print("%d %lud %lud %lud %s\n", w->pid, w->time[0], w->time[1], w->time[2], w->msg);
+	w = recvp(c);
+	if(w == nil)
+		print("exec/recvp failed: %r\n");
+	else
+		print("%d %lud %lud %lud %s\n", w->pid, w->time[0], w->time[1], w->time[2], w->msg);
+	threadexits(nil);
+}
blob - /dev/null
blob + 8835267fe312ee8b85ae4afd6ef7e8c9c03c80ab (mode 644)
--- /dev/null
+++ src/libthread/test/tspawnloop.c
@@ -0,0 +1,41 @@
+#include "u.h"
+#include "libc.h"
+#include "thread.h"
+
+void
+execproc(void *v)
+{
+	int i, fd[3];
+	char buf[100], *args[3];
+
+	i = (int)v;
+	sprint(buf, "%d", i);
+	fd[0] = dup(0, -1);
+	fd[1] = dup(1, -1);
+	fd[2] = dup(2, -1);
+	args[0] = "echo";
+	args[1] = buf;
+	args[2] = nil;
+	threadexec(nil, fd, args[0], args);
+}
+	
+void
+threadmain(int argc, char **argv)
+{
+	int i;
+	Channel *c;
+	Waitmsg *w;
+
+	ARGBEGIN{
+	case 'D':
+		break;
+	}ARGEND
+
+	c = threadwaitchan();
+	for(i=0;; i++){
+		proccreate(execproc, (void*)i, 16384);
+		w = recvp(c);
+		if(w == nil)
+			sysfatal("exec/recvp failed: %r");
+	}
+}
blob - 94d4db9abea7f3a8609f56e777f5ec240d367fb4 (mode 644)
blob + /dev/null
--- src/libthread/PowerMacintosh.c
+++ /dev/null
@@ -1,39 +0,0 @@
-#include "threadimpl.h"
-
-static void
-launcherpower(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7,
-	void (*f)(void *arg), void *arg)
-{
-	(*f)(arg);
-	threadexits(nil);
-}
-
-void
-_threadinitstack(Thread *t, void (*f)(void*), void *arg)
-{
-	ulong *tos, *stk;
-
-	tos = (ulong*)&t->stk[t->stksize&~7];
-	stk = tos;
-	--stk;
-	--stk;
-	--stk;
-	--stk;
-	*--stk = (ulong)arg;
-	*--stk = (ulong)f;
-	t->sched.pc = (ulong)launcherpower+LABELDPC;
-	t->sched.sp = (ulong)tos-80;
-}
-
-void
-_threadinswitch(int enter)
-{
-	USED(enter);
-}
-
-void
-_threadstacklimit(void *addr, void *addr2)
-{
-	USED(addr);
-}
-
blob - /dev/null
blob + 6989518101141831f71138faaca89295549e5872 (mode 644)
--- /dev/null
+++ src/libthread/thread.c
@@ -0,0 +1,535 @@
+#include "u.h"
+#include <linux/unistd.h>
+#include "libc.h"
+#include "thread.h"
+#include "threadimpl.h"
+
+       _syscall0(pid_t,gettid)
+
+int	_threaddebuglevel;
+
+static	uint		threadnproc;
+static	uint		threadnsysproc;
+static	Lock		threadnproclock;
+static	Ref		threadidref;
+
+static	void		addthread(_Threadlist*, _Thread*);
+static	void		delthread(_Threadlist*, _Thread*);
+static	void		addthreadinproc(Proc*, _Thread*);
+static	void		delthreadinproc(Proc*, _Thread*);
+static	void		contextswitch(Context *from, Context *to);
+static	void		scheduler(void*);
+
+static _Thread*
+getthreadnow(void)
+{
+	return proc()->thread;
+}
+_Thread	*(*threadnow)(void) = getthreadnow;
+
+static Proc*
+procalloc(void)
+{
+	Proc *p;
+
+	p = malloc(sizeof *p);
+	memset(p, 0, sizeof *p);
+	lock(&threadnproclock);
+	threadnproc++;
+	unlock(&threadnproclock);
+	return p;
+}
+
+static void
+threadstart(void *v)
+{
+	_Thread *t;
+
+	t = v;
+	t->startfn(t->startarg);
+	_threadexit();
+}
+
+static _Thread*
+threadalloc(void (*fn)(void*), void *arg, uint stack)
+{
+	_Thread *t;
+	sigset_t zero;
+
+	/* allocate the task and stack together */
+	t = malloc(sizeof *t+stack);
+	memset(t, 0, sizeof *t);
+	t->stk = (uchar*)(t+1);
+	t->stksize = stack;
+	t->id = incref(&threadidref);
+	t->startfn = fn;
+	t->startarg = arg;
+
+	/* do a reasonable initialization */
+	memset(&t->context.uc, 0, sizeof t->context.uc);
+	sigemptyset(&zero);
+	sigprocmask(SIG_BLOCK, &zero, &t->context.uc.uc_sigmask);
+
+	/* on Linux makecontext neglects floating point */
+	getcontext(&t->context.uc);
+
+	/* call makecontext to do the real work. */
+	/* leave a few words open on both ends */
+	t->context.uc.uc_stack.ss_sp = t->stk+8;
+	t->context.uc.uc_stack.ss_size = t->stksize-16;
+	makecontext(&t->context.uc, (void(*)())threadstart, 1, t);
+
+	return t;
+}
+
+_Thread*
+_threadcreate(Proc *p, void (*fn)(void*), void *arg, uint stack)
+{
+	_Thread *t;
+
+	t = threadalloc(fn, arg, stack);
+	t->proc = p;
+	addthreadinproc(p, t);
+	p->nthread++;
+	_threadready(t);
+	return t;
+}
+
+int
+threadcreate(void (*fn)(void*), void *arg, uint stack)
+{
+	_Thread *t;
+
+	t = _threadcreate(proc(), fn, arg, stack);
+	return t->id;
+}
+
+int
+proccreate(void (*fn)(void*), void *arg, uint stack)
+{
+	_Thread *t;
+	Proc *p;
+
+	p = procalloc();
+//print("pa %p\n", p);
+	t = _threadcreate(p, fn, arg, stack);
+//print("ps %p\n", p);
+	_procstart(p, scheduler);
+	return t->id;
+}
+
+void
+_threadswitch(void)
+{
+	Proc *p;
+
+	p = proc();
+	contextswitch(&p->thread->context, &p->schedcontext);
+}
+
+void
+_threadready(_Thread *t)
+{
+	Proc *p;
+
+	p = t->proc;
+	lock(&p->lock);
+	addthread(&p->runqueue, t);
+	_procwakeup(&p->runrend);
+	unlock(&p->lock);
+}
+
+void
+threadyield(void)
+{
+	_threadready(proc()->thread);
+	_threadswitch();
+}
+
+void
+_threadexit(void)
+{
+	proc()->thread->exiting = 1;
+	_threadswitch();
+}
+
+void
+threadexits(char *msg)
+{
+/*
+	Proc *p;
+
+	p = proc();
+	utfecpy(p->msg, p->msg+sizeof p->msg, msg);
+*/
+	_threadexit();
+}
+
+void
+threadexitsall(char *msg)
+{
+	if(msg && msg[0])
+		exit(1);
+	exit(0);
+}
+
+static void
+contextswitch(Context *from, Context *to)
+{
+	if(swapcontext(&from->uc, &to->uc) < 0){
+		fprint(2, "swapcontext failed: %r\n");
+		assert(0);
+	}
+}
+
+static void
+scheduler(void *v)
+{
+	_Thread *t;
+	Proc *p;
+
+	p = v;
+	setproc(p);
+	print("s %p %d\n", p, gettid());
+	p->tid = pthread_self();
+	pthread_detach(p->tid);
+	lock(&p->lock);
+	for(;;){
+		while((t = p->runqueue.head) == nil){
+			if(p->nthread == 0)
+				goto Out;
+			p->runrend.l = &p->lock;
+			_procsleep(&p->runrend);
+		}
+		delthread(&p->runqueue, t);
+		unlock(&p->lock);
+		p->thread = t;
+		// print("run %s %d\n", t->name, t->id);
+		contextswitch(&p->schedcontext, &t->context);
+		p->thread = nil;
+		lock(&p->lock);
+		if(t->exiting){
+			delthreadinproc(p, t);
+			p->nthread--;
+			free(t);
+		}
+	}
+
+Out:
+	lock(&threadnproclock);
+	if(p->sysproc)
+		--threadnsysproc;
+	if(--threadnproc == threadnsysproc)
+		exit(0);
+	unlock(&threadnproclock);
+	unlock(&p->lock);
+	free(p);
+	setproc(0);
+	print("e %p (tid %d)\n", p, gettid());
+	pthread_exit(nil);
+}
+
+void
+_threadsetsysproc(void)
+{
+	lock(&threadnproclock);
+	if(++threadnsysproc == threadnproc)
+		exit(0);
+	unlock(&threadnproclock);
+	proc()->sysproc = 1;
+}
+
+/*
+ * debugging
+ */
+void
+threadsetname(char *fmt, ...)
+{
+	va_list arg;
+	_Thread *t;
+
+	t = proc()->thread;
+	va_start(arg, fmt);
+	vsnprint(t->name, sizeof t->name, fmt, arg);
+	va_end(arg);
+}
+
+void
+threadsetstate(char *fmt, ...)
+{
+	va_list arg;
+	_Thread *t;
+
+	t = proc()->thread;
+	va_start(arg, fmt);
+	vsnprint(t->state, sizeof t->name, fmt, arg);
+	va_end(arg);
+}
+
+/*
+ * locking
+ */
+static int
+threadqlock(QLock *l, int block, ulong pc)
+{
+	lock(&l->l);
+	if(l->owner == nil){
+		l->owner = (*threadnow)();
+//print("qlock %p @%#x by %p\n", l, pc, l->owner);
+		unlock(&l->l);
+		return 1;
+	}
+	if(!block){
+		unlock(&l->l);
+		return 0;
+	}
+//print("qsleep %p @%#x by %p\n", l, pc, (*threadnow)());
+	addthread(&l->waiting, (*threadnow)());
+	unlock(&l->l);
+
+	_threadswitch();
+
+	if(l->owner != (*threadnow)()){
+		fprint(2, "qlock pc=0x%lux owner=%p self=%p oops\n", pc, l->owner, (*threadnow)());
+		abort();
+	}
+//print("qlock wakeup %p @%#x by %p\n", l, pc, (*threadnow)());
+	return 1;
+}
+
+static void
+threadqunlock(QLock *l, ulong pc)
+{
+	lock(&l->l);
+//print("qlock unlock %p @%#x by %p (owner %p)\n", l, pc, (*threadnow)(), l->owner);
+	if(l->owner == nil){
+		fprint(2, "qunlock pc=0x%lux owner=%p self=%p oops\n",
+			pc, l->owner, (*threadnow)());
+		abort();
+	}
+	if((l->owner = l->waiting.head) != nil){
+		delthread(&l->waiting, l->owner);
+		_threadready(l->owner);
+	}
+	unlock(&l->l);
+}
+
+static int
+threadrlock(RWLock *l, int block, ulong pc)
+{
+	USED(pc);
+
+	lock(&l->l);
+	if(l->writer == nil && l->wwaiting.head == nil){
+		l->readers++;
+		unlock(&l->l);
+		return 1;
+	}
+	if(!block){
+		unlock(&l->l);
+		return 0;
+	}
+	addthread(&l->rwaiting, (*threadnow)());
+	unlock(&l->l);
+	_threadswitch();
+	return 1;	
+}
+
+static int
+threadwlock(RWLock *l, int block, ulong pc)
+{
+	USED(pc);
+
+	lock(&l->l);
+	if(l->writer == nil && l->readers == 0){
+		l->writer = (*threadnow)();
+		unlock(&l->l);
+		return 1;
+	}
+	if(!block){
+		unlock(&l->l);
+		return 0;
+	}
+	addthread(&l->wwaiting, (*threadnow)());
+	unlock(&l->l);
+	_threadswitch();
+	return 1;
+}
+
+static void
+threadrunlock(RWLock *l, ulong pc)
+{
+	_Thread *t;
+
+	USED(pc);
+	lock(&l->l);
+	--l->readers;
+	if(l->readers == 0 && (t = l->wwaiting.head) != nil){
+		delthread(&l->wwaiting, t);
+		l->writer = t;
+		_threadready(t);
+	}
+	unlock(&l->l);
+}
+
+static void
+threadwunlock(RWLock *l, ulong pc)
+{
+	_Thread *t;
+
+	USED(pc);
+	lock(&l->l);
+	l->writer = nil;
+	assert(l->readers == 0);
+	while((t = l->rwaiting.head) != nil){
+		delthread(&l->rwaiting, t);
+		l->readers++;
+		_threadready(t);
+	}
+	if(l->readers == 0 && (t = l->wwaiting.head) != nil){
+		delthread(&l->wwaiting, t);
+		l->writer = t;
+		_threadready(t);
+	}
+	unlock(&l->l);
+}
+
+/*
+ * sleep and wakeup
+ */
+static void
+threadrsleep(Rendez *r, ulong pc)
+{
+	addthread(&r->waiting, proc()->thread);
+	qunlock(r->l);
+	_threadswitch();
+	qlock(r->l);
+}
+
+static int
+threadrwakeup(Rendez *r, int all, ulong pc)
+{
+	int i;
+	_Thread *t;
+
+	for(i=0;; i++){
+		if(i==1 && !all)
+			break;
+		if((t = r->waiting.head) == nil)
+			break;
+		delthread(&r->waiting, t);
+		_threadready(t);	
+	}
+	return i;
+}
+
+/*
+ * hooray for linked lists
+ */
+static void
+addthread(_Threadlist *l, _Thread *t)
+{
+	if(l->tail){
+		l->tail->next = t;
+		t->prev = l->tail;
+	}else{
+		l->head = t;
+		t->prev = nil;
+	}
+	l->tail = t;
+	t->next = nil;
+}
+
+static void
+delthread(_Threadlist *l, _Thread *t)
+{
+	if(t->prev)
+		t->prev->next = t->next;
+	else
+		l->head = t->next;
+	if(t->next)
+		t->next->prev = t->prev;
+	else
+		l->tail = t->prev;
+}
+
+static void
+addthreadinproc(Proc *p, _Thread *t)
+{
+	_Threadlist *l;
+
+	l = &p->allthreads;
+	if(l->tail){
+		l->tail->allnext = t;
+		t->allprev = l->tail;
+	}else{
+		l->head = t;
+		t->allprev = nil;
+	}
+	l->tail = t;
+	t->allnext = nil;
+}
+
+static void
+delthreadinproc(Proc *p, _Thread *t)
+{
+	_Threadlist *l;
+
+	l = &p->allthreads;
+	if(t->allprev)
+		t->allprev->allnext = t->allnext;
+	else
+		l->head = t->allnext;
+	if(t->allnext)
+		t->allnext->allprev = t->allprev;
+	else
+		l->tail = t->allprev;
+}
+
+void**
+procdata(void)
+{
+	return &proc()->udata;
+}
+
+static int threadargc;
+static char **threadargv;
+int mainstacksize;
+
+static void
+threadmainstart(void *v)
+{
+	USED(v);
+	threadmain(threadargc, threadargv);
+}
+
+int
+main(int argc, char **argv)
+{
+	Proc *p;
+
+	threadargc = argc;
+	threadargv = argv;
+
+	/*
+	 * Install locking routines into C library.
+	 */
+	_lock = _threadlock;
+	_unlock = _threadunlock;
+	_qlock = threadqlock;
+	_qunlock = threadqunlock;
+	_rlock = threadrlock;
+	_runlock = threadrunlock;
+	_wlock = threadwlock;
+	_wunlock = threadwunlock;
+	_rsleep = threadrsleep;
+	_rwakeup = threadrwakeup;
+
+	pthreadinit();
+	p = procalloc();
+	if(mainstacksize == 0)
+		mainstacksize = 65536;
+	_threadcreate(p, threadmainstart, nil, mainstacksize);
+	scheduler(p);
+	return 0;	/* not reached */
+}
blob - 8bf69d6af9b8b0844389840746e10387e789f7b4 (mode 644)
blob + /dev/null
--- src/libthread/README
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * The authors of this software are Russ Cox, Sape Mullender, and Rob Pike.
- *		Copyright (c) 2003 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
- * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
-*/
-
-This is a Unix port of the Plan 9 thread library.
-
-Please send comments about the packaging
-to Russ Cox <rsc@post.harvard.edu>.
-
blob - c503e1d63df2d6f33a9520eb67d18584ad9609ad (mode 644)
blob + /dev/null
--- src/libthread/asm-Darwin-PowerMacintosh.s
+++ /dev/null
@@ -1,80 +0,0 @@
-/* get FPR and VR use flags with sc 0x7FF3 */
-/* get vsave with mfspr reg, 256 */
-
-.text
-.align 2
-
-.globl	__setlabel
-
-__setlabel:				/* xxx: instruction scheduling */
-	mflr	r0
-	mfcr	r5
-	mfctr	r6
-	mfxer	r7
-	stw	r0, 0*4(r3)
-	stw	r5, 1*4(r3)
-	stw	r6, 2*4(r3)
-	stw	r7, 3*4(r3)
-
-	stw	r1, 4*4(r3)
-	stw	r2, 5*4(r3)
-
-	stw	r13, (0+6)*4(r3)	/* callee-save GPRs */
-	stw	r14, (1+6)*4(r3)	/* xxx: block move */
-	stw	r15, (2+6)*4(r3)
-	stw	r16, (3+6)*4(r3)
-	stw	r17, (4+6)*4(r3)
-	stw	r18, (5+6)*4(r3)
-	stw	r19, (6+6)*4(r3)
-	stw	r20, (7+6)*4(r3)
-	stw	r21, (8+6)*4(r3)
-	stw	r22, (9+6)*4(r3)
-	stw	r23, (10+6)*4(r3)
-	stw	r24, (11+6)*4(r3)
-	stw	r25, (12+6)*4(r3)
-	stw	r26, (13+6)*4(r3)
-	stw	r27, (14+6)*4(r3)
-	stw	r28, (15+6)*4(r3)
-	stw	r29, (16+6)*4(r3)
-	stw	r30, (17+6)*4(r3)
-	stw	r31, (18+6)*4(r3)
-
-	li	r3, 0			/* return */
-	blr
-
-.globl	__gotolabel
-
-__gotolabel:
-	lwz	r13, (0+6)*4(r3)	/* callee-save GPRs */
-	lwz	r14, (1+6)*4(r3)	/* xxx: block move */
-	lwz	r15, (2+6)*4(r3)
-	lwz	r16, (3+6)*4(r3)
-	lwz	r17, (4+6)*4(r3)
-	lwz	r18, (5+6)*4(r3)
-	lwz	r19, (6+6)*4(r3)
-	lwz	r20, (7+6)*4(r3)
-	lwz	r21, (8+6)*4(r3)
-	lwz	r22, (9+6)*4(r3)
-	lwz	r23, (10+6)*4(r3)
-	lwz	r24, (11+6)*4(r3)
-	lwz	r25, (12+6)*4(r3)
-	lwz	r26, (13+6)*4(r3)
-	lwz	r27, (14+6)*4(r3)
-	lwz	r28, (15+6)*4(r3)
-	lwz	r29, (16+6)*4(r3)
-	lwz	r30, (17+6)*4(r3)
-	lwz	r31, (18+6)*4(r3)
-
-	lwz	r1, 4*4(r3)
-	lwz	r2, 5*4(r3)
-
-	lwz	r0, 0*4(r3)
-	mtlr	r0
-	lwz	r0, 1*4(r3)
-	mtcr	r0			/* mtcrf 0xFF, r0 */
-	lwz	r0, 2*4(r3)
-	mtctr	r0
-	lwz	r0, 3*4(r3)
-	mtxer	r0
-	li	r3, 1
-	blr
blob - c815ac580e08bc7de133b32a147b8d1fcc277e88 (mode 644)
blob + /dev/null
--- src/libthread/asm-FreeBSD-386.s
+++ /dev/null
@@ -1,55 +0,0 @@
-.globl	_setlabel
-.type	_setlabel,@function
-
-_setlabel:
-	movl	4(%esp), %eax
-	movl	0(%esp), %edx
-	movl	%edx, 0(%eax)
-	movl	%ebx, 4(%eax)
-	movl	%esp, 8(%eax)
-	movl	%ebp, 12(%eax)
-	movl	%esi, 16(%eax)
-	movl	%edi, 20(%eax)
-	xorl	%eax, %eax
-	ret
-
-.globl	_gotolabel
-.type	_gotolabel,@function
-
-_gotolabel:
-	pushl $1
-	call _threadinswitch
-	popl %eax
-	movl	4(%esp), %edx
-	movl	0(%edx), %ecx
-	movl	4(%edx), %ebx
-	movl	8(%edx), %esp
-	movl	12(%edx), %ebp
-	movl	16(%edx), %esi
-	movl	20(%edx), %edi
-	movl	%ecx, 0(%esp)
-	pushl $0
-	call _threadinswitch
-	popl %eax
-	xorl	%eax, %eax
-	incl	%eax
-	ret
-
-
-# .globl	_xinc
-# _xinc:
-# 	movl 4(%esp), %eax
-# 	lock incl 0(%eax)
-# 	ret
-# 
-# .globl	_xdec
-# _xdec:
-# 	movl 4(%esp), %eax
-# 	lock decl 0(%eax)
-# 	jz iszero
-# 	movl $1, %eax
-# 	ret
-# iszero:
-# 	movl $0, %eax
-# 	ret
-# 
blob - 75d965bf758bcb35d7fdd6de8ba70e317664ba79 (mode 644)
blob + /dev/null
--- src/libthread/asm-Linux-386.s
+++ /dev/null
@@ -1 +0,0 @@
-.include "asm-FreeBSD-386.s"
blob - 00bfec3e155b48d2d0f43acb2838d34db5848e5a (mode 644)
blob + /dev/null
--- src/libthread/asm-Linux-power.s
+++ /dev/null
@@ -1,80 +0,0 @@
-/* get FPR and VR use flags with sc 0x7FF3 */
-/* get vsave with mfspr reg, 256 */
-
-.text
-.align 2
-
-.globl	_setlabel
-
-_setlabel:				/* xxx: instruction scheduling */
-	mflr	0
-	mfcr	5
-	mfctr	6
-	mfxer	7
-	stw	0, 0*4(3)
-	stw	5, 1*4(3)
-	stw	6, 2*4(3)
-	stw	7, 3*4(3)
-
-	stw	1, 4*4(3)
-	stw	2, 5*4(3)
-
-	stw	13, (0+6)*4(3)	/* callee-save GPRs */
-	stw	14, (1+6)*4(3)	/* xxx: block move */
-	stw	15, (2+6)*4(3)
-	stw	16, (3+6)*4(3)
-	stw	17, (4+6)*4(3)
-	stw	18, (5+6)*4(3)
-	stw	19, (6+6)*4(3)
-	stw	20, (7+6)*4(3)
-	stw	21, (8+6)*4(3)
-	stw	22, (9+6)*4(3)
-	stw	23, (10+6)*4(3)
-	stw	24, (11+6)*4(3)
-	stw	25, (12+6)*4(3)
-	stw	26, (13+6)*4(3)
-	stw	27, (14+6)*4(3)
-	stw	28, (15+6)*4(3)
-	stw	29, (16+6)*4(3)
-	stw	30, (17+6)*4(3)
-	stw	31, (18+6)*4(3)
-
-	li	3, 0			/* return */
-	blr
-
-.globl	_gotolabel
-
-_gotolabel:
-	lwz	13, (0+6)*4(3)	/* callee-save GPRs */
-	lwz	14, (1+6)*4(3)	/* xxx: block move */
-	lwz	15, (2+6)*4(3)
-	lwz	16, (3+6)*4(3)
-	lwz	17, (4+6)*4(3)
-	lwz	18, (5+6)*4(3)
-	lwz	19, (6+6)*4(3)
-	lwz	20, (7+6)*4(3)
-	lwz	21, (8+6)*4(3)
-	lwz	22, (9+6)*4(3)
-	lwz	23, (10+6)*4(3)
-	lwz	24, (11+6)*4(3)
-	lwz	25, (12+6)*4(3)
-	lwz	26, (13+6)*4(3)
-	lwz	27, (14+6)*4(3)
-	lwz	28, (15+6)*4(3)
-	lwz	29, (16+6)*4(3)
-	lwz	30, (17+6)*4(3)
-	lwz	31, (18+6)*4(3)
-
-	lwz	1, 4*4(3)
-	lwz	2, 5*4(3)
-
-	lwz	0, 0*4(3)
-	mtlr	0
-	lwz	0, 1*4(3)
-	mtcr	0			/* mtcrf 0xFF, r0 */
-	lwz	0, 2*4(3)
-	mtctr	0
-	lwz	0, 3*4(3)
-	mtxer	0
-	li	3, 1
-	blr
blob - 35e2ab6f87f746e3acc9434f2e5571c0184b4145 (mode 644)
blob + /dev/null
--- src/libthread/asm-OpenBSD-386.s
+++ /dev/null
@@ -1,49 +0,0 @@
-.globl	_setlabel
-.type	_setlabel,@function
-
-_setlabel:
-	movl	4(%esp), %eax
-	movl	0(%esp), %edx
-	movl	%edx, 0(%eax)
-	movl	%ebx, 4(%eax)
-	movl	%esp, 8(%eax)
-	movl	%ebp, 12(%eax)
-	movl	%esi, 16(%eax)
-	movl	%edi, 20(%eax)
-	xorl	%eax, %eax
-	ret
-
-.globl	_gotolabel
-.type	_gotolabel,@function
-
-_gotolabel:
-	movl	4(%esp), %edx
-	movl	0(%edx), %ecx
-	movl	4(%edx), %ebx
-	movl	8(%edx), %esp
-	movl	12(%edx), %ebp
-	movl	16(%edx), %esi
-	movl	20(%edx), %edi
-	xorl	%eax, %eax
-	incl	%eax
-	movl	%ecx, 0(%esp)
-	ret
-
-
-# .globl	_xinc
-# _xinc:
-# 	movl 4(%esp), %eax
-# 	lock incl 0(%eax)
-# 	ret
-# 
-# .globl	_xdec
-# _xdec:
-# 	movl 4(%esp), %eax
-# 	lock decl 0(%eax)
-# 	jz iszero
-# 	movl $1, %eax
-# 	ret
-# iszero:
-# 	movl $0, %eax
-# 	ret
-# 
blob - 3e95f02b430820640eede33e78c37603f3069f74 (mode 644)
blob + /dev/null
--- src/libthread/asm-SunOS-sun4u.s
+++ /dev/null
@@ -1,51 +0,0 @@
-.globl _setlabel
-.type  _setlabel,#function
-
-_setlabel:
-	ta	3
-	st	%i0, [%o0]
-	st	%i1, [%o0+4]
-	st	%i2, [%o0+8]
-	st	%i3, [%o0+12]
-	st	%i4, [%o0+16]
-	st	%i5, [%o0+20]
-	st	%i6, [%o0+24]
-	st	%i7, [%o0+28]
-	st	%l0, [%o0+32]
-	st	%l1, [%o0+36]
-	st	%l2, [%o0+40]
-	st	%l3, [%o0+44]
-	st	%l4, [%o0+48]
-	st	%l5, [%o0+52]
-	st	%l6, [%o0+56]
-	st	%l7, [%o0+60]
-	st	%sp, [%o0+64]
-	st	%o7, [%o0+68]
-	jmpl	%o7+8, %g0
-	or	%g0, %g0, %o0
-
-.globl _gotolabel
-.type	_gotolabel,#function
-
-_gotolabel:
-	ta	3
-	ld	[%o0], %i0
-	ld	[%o0+4], %i1
-	ld	[%o0+8], %i2
-	ld	[%o0+12], %i3
-	ld	[%o0+16], %i4
-	ld	[%o0+20], %i5
-	ld	[%o0+24], %i6
-	ld	[%o0+28], %i7
-	ld	[%o0+32], %l0
-	ld	[%o0+36], %l1
-	ld	[%o0+40], %l2
-	ld	[%o0+44], %l3
-	ld	[%o0+48], %l4
-	ld	[%o0+52], %l5
-	ld	[%o0+56], %l6
-	ld	[%o0+60], %l7
-	ld	[%o0+64], %sp
-	ld	[%o0+68], %o7
-	jmpl	%o7+8, %g0
-	or	%g0, 1, %o0
blob - b488dc9760bb00d7d12bdd1053b90c0d863b1c12 (mode 644)
blob + /dev/null
--- src/libthread/channel.c
+++ /dev/null
@@ -1,500 +0,0 @@
-#include "threadimpl.h"
-
-static Lock chanlock;		/* central channel access lock */
-
-static void enqueue(Alt*, Thread*);
-static void dequeue(Alt*);
-static int altexec(Alt*);
-
-int _threadhighnentry;
-int _threadnalt;
-
-static void
-setuserpc(ulong pc)
-{
-	Thread *t;
-
-	t = _threadgetproc()->thread;
-	if(t)
-		t->userpc = pc;
-}
-
-static int
-canexec(Alt *a)
-{
-	int i, otherop;
-	Channel *c;
-
-	c = a->c;
-	/* are there senders or receivers blocked? */
-	otherop = (CHANSND+CHANRCV) - a->op;
-	for(i=0; i<c->nentry; i++)
-		if(c->qentry[i] && c->qentry[i]->op==otherop && c->qentry[i]->thread->altc==nil){
-			_threaddebug(DBGCHAN, "can rendez alt %p chan %p", a, c);
-			return 1;
-		}
-
-	/* is there room in the channel? */
-	if((a->op==CHANSND && c->n < c->s)
-	|| (a->op==CHANRCV && c->n > 0)){
-		_threaddebug(DBGCHAN, "can buffer alt %p chan %p", a, c);
-		return 1;
-	}
-
-	return 0;
-}
-
-static void
-_chanfree(Channel *c)
-{
-	int i, inuse;
-
-	inuse = 0;
-	for(i = 0; i < c->nentry; i++)
-		if(c->qentry[i])
-			inuse = 1;
-	if(inuse)
-		c->freed = 1;
-	else{
-		if(c->qentry)
-			free(c->qentry);
-		free(c);
-	}
-}
-
-void
-chanfree(Channel *c)
-{
-	lock(&chanlock);
-	_chanfree(c);
-	unlock(&chanlock);
-}
-
-int
-chaninit(Channel *c, int elemsize, int elemcnt)
-{
-	if(elemcnt < 0 || elemsize <= 0 || c == nil)
-		return -1;
-	memset(c, 0, sizeof *c);
-	c->e = elemsize;
-	c->s = elemcnt;
-	_threaddebug(DBGCHAN, "chaninit %p", c);
-	return 1;
-}
-
-Channel*
-chancreate(int elemsize, int elemcnt)
-{
-	Channel *c;
-
-	if(elemcnt < 0 || elemsize <= 0)
-		return nil;
-	c = _threadmalloc(sizeof(Channel)+elemsize*elemcnt, 1);
-	c->e = elemsize;
-	c->s = elemcnt;
-	_threaddebug(DBGCHAN, "chancreate %p", c);
-	return c;
-}
-
-static int
-_alt(Alt *alts)
-{
-	Alt *a, *xa;
-	Channel *c;
-	int n;
-	Thread *t;
-
-	/*
-	 * The point of going splhi here is that note handlers
-	 * might reasonably want to use channel operations,
-	 * but that will hang if the note comes while we hold the
-	 * chanlock.  Instead, we delay the note until we've dropped
-	 * the lock.
-	 */
-
-	/*
-	 * T might be nil here -- the scheduler sends on threadwaitchan
-	 * directly (in non-blocking mode, of course!).
-	 */
-	t = _threadgetproc()->thread;
-	if((t && t->moribund) || _threadexitsallstatus)
-		yield();	/* won't return */
-	lock(&chanlock);
-
-	/* test whether any channels can proceed */
-	n = 0;
-	a = nil;
-
-	for(xa=alts; xa->op!=CHANEND && xa->op!=CHANNOBLK; xa++){
-		xa->entryno = -1;
-		if(xa->op == CHANNOP)
-			continue;
-
-		c = xa->c;
-		if(c==nil){
-			unlock(&chanlock);
-			return -1;
-		}
-		if(canexec(xa))
-			if(nrand(++n) == 0)
-				a = xa;
-	}
-
-	if(a==nil){
-		/* nothing can proceed */
-		if(xa->op == CHANNOBLK){
-			unlock(&chanlock);
-			_threadnalt++;
-			return xa - alts;
-		}
-
-		/* enqueue on all channels. */
-		t->altc = nil;
-		for(xa=alts; xa->op!=CHANEND; xa++){
-			if(xa->op==CHANNOP)
-				continue;
-			enqueue(xa, t);
-		}
-
-		/*
-		 * wait for successful rendezvous.
-		 * we can't just give up if the rendezvous
-		 * is interrupted -- someone else might come
-		 * along and try to rendezvous with us, so
-		 * we need to be here.
-		 *
-		 * actually, now we're assuming no interrupts.
-		 */
-	    /*Again:*/
-		t->alt = alts;
-		t->chan = Chanalt;
-		t->altrend.l = &chanlock;
-		_threadsleep(&t->altrend);
-
-		/* dequeue from channels, find selected one */
-		a = nil;
-		c = t->altc;
-		for(xa=alts; xa->op!=CHANEND; xa++){
-			if(xa->op==CHANNOP)
-				continue;
-			if(xa->c == c)
-				a = xa;
-			dequeue(xa);
-		}
-		unlock(&chanlock);
-		if(a == nil){	/* we were interrupted */
-			assert(c==(Channel*)~0);
-			return -1;
-		}
-	}else{
-		altexec(a);	/* unlocks chanlock, does splx */
-	}
-	if(t)
-		t->chan = Channone;
-	return a - alts;
-}
-
-int
-alt(Alt *alts)
-{
-	setuserpc(getcallerpc(&alts));
-	return _alt(alts);
-}
-
-static int
-runop(int op, Channel *c, void *v, int nb)
-{
-	int r;
-	Alt a[2];
-
-	/*
-	 * we could do this without calling alt,
-	 * but the only reason would be performance,
-	 * and i'm not convinced it matters.
-	 */
-	a[0].op = op;
-	a[0].c = c;
-	a[0].v = v;
-	a[1].op = CHANEND;
-	if(nb)
-		a[1].op = CHANNOBLK;
-	switch(r=_alt(a)){
-	case -1:	/* interrupted */
-		return -1;
-	case 1:	/* nonblocking, didn't accomplish anything */
-		assert(nb);
-		return 0;
-	case 0:
-		return 1;
-	default:
-		fprint(2, "ERROR: channel alt returned %d\n", r);
-		abort();
-		return -1;
-	}
-}
-
-int
-recv(Channel *c, void *v)
-{
-	setuserpc(getcallerpc(&c));
-	return runop(CHANRCV, c, v, 0);
-}
-
-int
-nbrecv(Channel *c, void *v)
-{
-	setuserpc(getcallerpc(&c));
-	return runop(CHANRCV, c, v, 1);
-}
-
-int
-send(Channel *c, void *v)
-{
-	setuserpc(getcallerpc(&c));
-	return runop(CHANSND, c, v, 0);
-}
-
-int
-nbsend(Channel *c, void *v)
-{
-	setuserpc(getcallerpc(&c));
-	return runop(CHANSND, c, v, 1);
-}
-
-static void
-channelsize(Channel *c, int sz)
-{
-	if(c->e != sz){
-		fprint(2, "expected channel with elements of size %d, got size %d\n",
-			sz, c->e);
-		abort();
-	}
-}
-
-int
-sendul(Channel *c, ulong v)
-{
-	setuserpc(getcallerpc(&c));
-	channelsize(c, sizeof(ulong));
-	return send(c, &v);
-}
-
-ulong
-recvul(Channel *c)
-{
-	ulong v;
-
-	setuserpc(getcallerpc(&c));
-	channelsize(c, sizeof(ulong));
-	if(runop(CHANRCV, c, &v, 0) < 0)
-		return ~0;
-	return v;
-}
-
-int
-sendp(Channel *c, void *v)
-{
-	setuserpc(getcallerpc(&c));
-	channelsize(c, sizeof(void*));
-	return runop(CHANSND, c, &v, 0);
-}
-
-void*
-recvp(Channel *c)
-{
-	void *v;
-
-	setuserpc(getcallerpc(&c));
-	channelsize(c, sizeof(void*));
-	if(runop(CHANRCV, c, &v, 0) < 0)
-		return nil;
-	return v;
-}
-
-int
-nbsendul(Channel *c, ulong v)
-{
-	setuserpc(getcallerpc(&c));
-	channelsize(c, sizeof(ulong));
-	return runop(CHANSND, c, &v, 1);
-}
-
-ulong
-nbrecvul(Channel *c)
-{
-	ulong v;
-
-	setuserpc(getcallerpc(&c));
-	channelsize(c, sizeof(ulong));
-	if(runop(CHANRCV, c, &v, 1) == 0)
-		return 0;
-	return v;
-}
-
-int
-nbsendp(Channel *c, void *v)
-{
-	setuserpc(getcallerpc(&c));
-	channelsize(c, sizeof(void*));
-	return runop(CHANSND, c, &v, 1);
-}
-
-void*
-nbrecvp(Channel *c)
-{
-	void *v;
-
-	setuserpc(getcallerpc(&c));
-	channelsize(c, sizeof(void*));
-	if(runop(CHANRCV, c, &v, 1) == 0)
-		return nil;
-	return v;
-}
-
-static int
-emptyentry(Channel *c)
-{
-	int i, extra;
-
-	assert((c->nentry==0 && c->qentry==nil) || (c->nentry && c->qentry));
-
-	for(i=0; i<c->nentry; i++)
-		if(c->qentry[i]==nil)
-			return i;
-
-	extra = 16;
-	c->nentry += extra;
-if(c->nentry > _threadhighnentry) _threadhighnentry = c->nentry;
-	c->qentry = realloc((void*)c->qentry, c->nentry*sizeof(c->qentry[0]));
-	if(c->qentry == nil)
-		sysfatal("realloc channel entries: %r");
-	_threadmemset(&c->qentry[i], 0, extra*sizeof(c->qentry[0]));
-	return i;
-}
-
-static void
-enqueue(Alt *a, Thread *t)
-{
-	int i;
-
-	_threaddebug(DBGCHAN, "Queueing alt %p on channel %p", a, a->c);
-	a->thread = t;
-	i = emptyentry(a->c);
-	a->c->qentry[i] = a;
-}
-
-static void
-dequeue(Alt *a)
-{
-	int i;
-	Channel *c;
-
-	c = a->c;
-	for(i=0; i<c->nentry; i++)
-		if(c->qentry[i]==a){
-			_threaddebug(DBGCHAN, "Dequeuing alt %p from channel %p", a, a->c);
-			c->qentry[i] = nil;
-			if(c->freed)
-				_chanfree(c);
-			return;
-		}
-}
-
-static void*
-altexecbuffered(Alt *a, int willreplace)
-{
-	uchar *v;
-	Channel *c;
-
-	c = a->c;
-	/* use buffered channel queue */
-	if(a->op==CHANRCV && c->n > 0){
-		_threaddebug(DBGCHAN, "buffer recv alt %p chan %p", a, c);
-		v = c->v + c->e*(c->f%c->s);
-		if(!willreplace)
-			c->n--;
-		c->f++;
-		return v;
-	}
-	if(a->op==CHANSND && c->n < c->s){
-		_threaddebug(DBGCHAN, "buffer send alt %p chan %p", a, c);
-		v = c->v + c->e*((c->f+c->n)%c->s);
-		if(!willreplace)
-			c->n++;
-		return v;
-	}
-	abort();
-	return nil;
-}
-
-static void
-altcopy(void *dst, void *src, int sz)
-{
-	if(dst){
-		if(src)
-			memmove(dst, src, sz);
-		else
-			_threadmemset(dst, 0, sz);
-	}
-}
-
-static int
-altexec(Alt *a)
-{
-	volatile Alt *b;
-	int i, n, otherop;
-	Channel *c;
-	void *me, *waiter, *buf;
-
-	c = a->c;
-
-	/* rendezvous with others */
-	otherop = (CHANSND+CHANRCV) - a->op;
-	n = 0;
-	b = nil;
-	me = a->v;
-	for(i=0; i<c->nentry; i++)
-		if(c->qentry[i] && c->qentry[i]->op==otherop && c->qentry[i]->thread->altc==nil)
-			if(nrand(++n) == 0)
-				b = c->qentry[i];
-	if(b != nil){
-		_threaddebug(DBGCHAN, "rendez %s alt %p chan %p alt %p", a->op==CHANRCV?"recv":"send", a, c, b);
-		waiter = b->v;
-		if(c->s && c->n){
-			/*
-			 * if buffer is full and there are waiters
-			 * and we're meeting a waiter,
-			 * we must be receiving.
-			 *
-			 * we use the value in the channel buffer,
-			 * copy the waiter's value into the channel buffer
-			 * on behalf of the waiter, and then wake the waiter.
-			 */
-			if(a->op!=CHANRCV)
-				abort();
-			buf = altexecbuffered(a, 1);
-			altcopy(me, buf, c->e);
-			altcopy(buf, waiter, c->e);
-		}else{
-			if(a->op==CHANRCV)
-				altcopy(me, waiter, c->e);
-			else
-				altcopy(waiter, me, c->e);
-		}
-		b->thread->altc = c;
-		_threadwakeup(&b->thread->altrend);
-		_threaddebug(DBGCHAN, "chanlock is %lud", *(ulong*)(void*)&chanlock);
-		_threaddebug(DBGCHAN, "unlocking the chanlock");
-		unlock(&chanlock);
-		return 1;
-	}
-
-	buf = altexecbuffered(a, 0);
-	if(a->op==CHANRCV)
-		altcopy(me, buf, c->e);
-	else
-		altcopy(buf, me, c->e);
-
-	unlock(&chanlock);
-	return 1;
-}
blob - 781c6f6fa46dccdf170d47712a656817b348421b (mode 644)
blob + /dev/null
--- src/libthread/chanprint.c
+++ /dev/null
@@ -1,20 +0,0 @@
-#include <u.h>
-#include <libc.h>
-#include <thread.h>
-
-int
-chanprint(Channel *c, char *fmt, ...)
-{
-	va_list arg;
-	char *p;
-	int n;
-
-	va_start(arg, fmt);
-	p = vsmprint(fmt, arg);
-	va_end(arg);
-	if(p == nil)
-		sysfatal("vsmprint failed: %r");
-	n = sendp(c, p);
-	yield();	/* let recipient handle message immediately */
-	return n;
-}
blob - 4e6bc6de2263575a932e63ff5396938bfa2134e2 (mode 644)
blob + /dev/null
--- src/libthread/create.c
+++ /dev/null
@@ -1,211 +0,0 @@
-#include "threadimpl.h"
-
-Pqueue _threadpq;	/* list of all procs */
-int _threadnprocs;	/* count of procs */
-
-static int newthreadid(void);
-static int newprocid(void);
-
-/*
- * Create and initialize a new Thread structure attached to a given proc.
- */
-int
-_newthread(Proc *p, void (*f)(void *arg), void *arg, uint stacksize, 
-	char *name, int grp)
-{
-	int id;
-	Thread *t;
-
-	t = _threadmalloc(sizeof(Thread), 1);
-	t->proc = p;
-	t->nextproc = p;
-	t->homeproc = p;
-
-	t->grp = grp;
-	t->id = id = newthreadid();
-	if(name)
-		t->name = strdup(name);
-	_threaddebug(DBGSCHED, "create thread %d.%d name %s", p->id, id, name);
-
-	/*
-	 * Allocate and clear stack.
-	 */
-	if(stacksize < 1024)
-		sysfatal("bad stacksize %d", stacksize);
-	t->stk = _threadmalloc(stacksize, 0);
-	t->stksize = stacksize;
-	_threaddebugmemset(t->stk, 0xFE, stacksize);
-
-	/*
-	 * Set up t->context to call f(arg).
-	 */
-	_threadinitstack(t, f, arg);
-
-	/*
-	 * Add thread to proc.
-	 */
-	lock(&p->lock);
-	_procaddthread(p, t);
-
-	/*
-	 * Mark thread as ready to run.
-	 */
-	t->state = Ready;
-	_threadready(t);
-	unlock(&p->lock);
-
-	return id;
-}
-
-/* 
- * Free a Thread structure.
- */
-void
-_threadfree(Thread *t)
-{
-	free(t->stk);
-	free(t->name);
-	free(t);
-}
-
-/*
- * Create and initialize a new Proc structure with a single Thread
- * running inside it.  Add the Proc to the global process list.
- */
-Proc*
-_newproc(void)
-{
-	Proc *p;
-
-	/*
-	 * Allocate.
-	 */
-	p = _threadmalloc(sizeof *p, 1);
-	p->id = newprocid();
-	
-	/*
-	 * Add to list.  Record if we're now multiprocess.
-	 */
-	lock(&_threadpq.lock);
-	if(_threadpq.head == nil)
-		_threadpq.head = p;
-	else
-		*_threadpq.tail = p;
-	_threadpq.tail = &p->next;
-	if(_threadnprocs == 1)
-		_threadmultiproc();
-	_threadnprocs++;
-	unlock(&_threadpq.lock);
-
-	return p;
-}
-
-/*
- * Allocate a new thread running f(arg) on a stack of size stacksize.
- * Return the thread id.  The thread group inherits from the current thread.
- */
-int
-threadcreate(void (*f)(void*), void *arg, uint stacksize)
-{
-	return _newthread(_threadgetproc(), f, arg, stacksize, nil, threadgetgrp());
-}
-
-/* 
- * Allocate a new idle thread.  Only allowed in a single-proc program.
- */
-int
-threadcreateidle(void (*f)(void *arg), void *arg, uint stacksize)
-{
-	int id;
-
-	assert(_threadpq.head->next == nil);	/* only 1 */
-
-	id = threadcreate(f, arg, stacksize);
-	_threaddebug(DBGSCHED, "idle is %d", id);
-	_threadsetidle(id);
-	return id;
-}
-
-/*
- * Threadcreate, but do it inside a fresh proc.
- */
-int
-proccreate(void (*f)(void*), void *arg, uint stacksize)
-{
-	int id;
-	Proc *p, *np;
-
-	p = _threadgetproc();
-	np = _newproc();
-	p->newproc = np;
-	p->schedfn = _kthreadstartproc;
-	id = _newthread(np, f, arg, stacksize, nil, p->thread->grp);
-	_sched();	/* call into scheduler to create proc XXX */
-	return id;
-}
-
-/*
- * Allocate a new thread id.
- */
-static int
-newthreadid(void)
-{
-	static Lock l;
-	static int id;
-	int i;
-
-	lock(&l);
-	i = ++id;
-	unlock(&l);
-	return i;
-}
-
-/*
- * Allocate a new proc id.
- */
-static int
-newprocid(void)
-{
-	static Lock l;
-	static int id;
-	int i;
-
-	lock(&l);
-	i = ++id;
-	unlock(&l);
-	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--;
-}
blob - 14b47c0031ca093e61cafeeb8ca29655aaada7bd (mode 644)
blob + /dev/null
--- src/libthread/debug.c
+++ /dev/null
@@ -1,48 +0,0 @@
-#include "threadimpl.h"
-
-int _threaddebuglevel;
-
-void
-__threaddebug(ulong flag, char *fmt, ...)
-{
-	char buf[128];
-	va_list arg;
-	Fmt f;
-	Proc *p;
-
-	if((_threaddebuglevel&flag) == 0)
-		return;
-
-	fmtfdinit(&f, 2, buf, sizeof buf);
-
-	p = _threadgetproc();
-	if(p==nil)
-		fmtprint(&f, "noproc ");
-	else if(p->thread)
-		fmtprint(&f, "%d.%d ", p->id, p->thread->id);
-	else
-		fmtprint(&f, "%d._ ", p->id);
-
-	va_start(arg, fmt);
-	fmtvprint(&f, fmt, arg);
-	va_end(arg);
-	fmtprint(&f, "\n");
-	fmtfdflush(&f);
-}
-
-void
-_threadassert(char *s)
-{
-	char buf[256];
-	int n;
-	Proc *p;
-
-	p = _threadgetproc();
-	if(p && p->thread)
-		n = sprint(buf, "%d.%d ", p->pid, p->thread->id);
-	else
-		n = 0;
-	snprint(buf+n, sizeof(buf)-n, "%s: assertion failed\n", s);
-	write(2, buf, strlen(buf));
-	abort();
-}
blob - e5848eaa4d674a99cbbac26d60681ac4faf53c67 (mode 644)
blob + /dev/null
--- src/libthread/exec-unix.c
+++ /dev/null
@@ -1,147 +0,0 @@
-#include <u.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include "threadimpl.h"
-
-static void efork(int[3], int[2], char*, char**);
-int
-_threadexec(Channel *pidc, int fd[3], char *prog, char *args[], int freeargs)
-{
-	int pfd[2];
-	int n, pid;
-	char exitstr[ERRMAX];
-
-	_threaddebug(DBGEXEC, "threadexec %s", prog);
-
-	/*
-	 * We want threadexec to behave like exec; if exec succeeds,
-	 * never return, and if it fails, return with errstr set.
-	 * Unfortunately, the exec happens in another proc since
-	 * we have to wait for the exec'ed process to finish.
-	 * To provide the semantics, we open a pipe with the 
-	 * write end close-on-exec and hand it to the proc that
-	 * is doing the exec.  If the exec succeeds, the pipe will
-	 * close so that our read below fails.  If the exec fails,
-	 * then the proc doing the exec sends the errstr down the
-	 * pipe to us.
-	 */
-	if(pipe(pfd) < 0)
-		goto Bad;
-	if(fcntl(pfd[0], F_SETFD, 1) < 0)
-		goto Bad;
-	if(fcntl(pfd[1], F_SETFD, 1) < 0)
-		goto Bad;
-
-	switch(pid = fork()){
-	case -1:
-		close(pfd[0]);
-		close(pfd[1]);
-		goto Bad;
-	case 0:
-		efork(fd, pfd, prog, args);
-		_threaddebug(DBGSCHED, "exit after efork");
-		_exit(0);
-	default:
-		if(freeargs)
-			free(args);
-		break;
-	}
-
-	close(pfd[1]);
-	if((n = read(pfd[0], exitstr, ERRMAX-1)) > 0){	/* exec failed */
-		exitstr[n] = '\0';
-		errstr(exitstr, ERRMAX);
-		close(pfd[0]);
-		goto Bad;
-	}
-	close(pfd[0]);
-	close(fd[0]);
-	if(fd[1] != fd[0])
-		close(fd[1]);
-	if(fd[2] != fd[1] && fd[2] != fd[0])
-		close(fd[2]);
-	if(pidc)
-		sendul(pidc, pid);
-
-	_threaddebug(DBGEXEC, "threadexec schedexecwait");
-	return pid;
-
-Bad:
-	_threaddebug(DBGEXEC, "threadexec bad %r");
-	if(pidc)
-		sendul(pidc, ~0);
-	return -1;
-}
-
-void
-threadexec(Channel *pidc, int fd[3], char *prog, char *args[])
-{
-	if(_kthreadexec(pidc, fd, prog, args, 0) >= 0)
-		threadexits(nil);
-}
-
-int
-threadspawn(int fd[3], char *prog, char *args[])
-{
-	return _kthreadexec(nil, fd, prog, args, 0);
-}
-
-/*
- * The &f+1 trick doesn't work on SunOS, so we might 
- * as well bite the bullet and do this correctly.
- */
-void
-threadexecl(Channel *pidc, int fd[3], char *f, ...)
-{
-	char **args, *s;
-	int n;
-	va_list arg;
-
-	va_start(arg, f);
-	for(n=0; va_arg(arg, char*) != 0; n++)
-		;
-	n++;
-	va_end(arg);
-
-	args = malloc(n*sizeof(args[0]));
-	if(args == nil){
-		if(pidc)
-			sendul(pidc, ~0);
-		return;
-	}
-
-	va_start(arg, f);
-	for(n=0; (s=va_arg(arg, char*)) != 0; n++)
-		args[n] = s;
-	args[n] = 0;
-	va_end(arg);
-
-	if(_kthreadexec(pidc, fd, f, args, 1) >= 0)
-		threadexits(nil);
-}
-
-static void
-efork(int stdfd[3], int fd[2], char *prog, char **args)
-{
-	char buf[ERRMAX];
-	int i;
-
-	_threaddebug(DBGEXEC, "_schedexec %s -- calling execv", prog);
-	dup(stdfd[0], 0);
-	dup(stdfd[1], 1);
-	dup(stdfd[2], 2);
-	for(i=3; i<40; i++)
-		if(i != fd[1])
-			close(i);
-	rfork(RFNOTEG);
-	execvp(prog, args);
-	_threaddebug(DBGEXEC, "_schedexec failed: %r");
-	rerrstr(buf, sizeof buf);
-	if(buf[0]=='\0')
-		strcpy(buf, "exec failed");
-	write(fd[1], buf, strlen(buf));
-	close(fd[1]);
-	_threaddebug(DBGSCHED, "_exits in exec-unix");
-	_exits(buf);
-}
-
blob - 4382be402347886592df25c8aafa044ed52a2f42 (mode 644)
blob + /dev/null
--- src/libthread/execproc.ch
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Set up a dedicated proc to handle calls to exec.
- * The proc also waits for child messages.  
- * This way, each proc scheduler need not worry
- * about calling wait in its main loop.
- * 
- * To be included from other files (e.g., Linux-clone.c).
- */
-
-typedef struct Xarg Xarg;
-struct Xarg
-{
-	Channel *pidc;
-	int fd[3];
-	char *prog;
-	char **args;
-	int freeargs;
-	Channel *ret;
-	int errn;
-	char errstr[ERRMAX];
-};
-
-static Proc *_threadexecproc;
-static Channel *_threadexecchan;
-static Lock threadexeclock;
-
-/*
- * Called to poll for any kids of this pthread.
- * We have a separate proc responsible for exec,
- * so this is a no-op.
- */
-void
-_threadwaitkids(Proc *p)
-{
-}
-
-#define WAITSIG SIGCHLD
-
-/*
- * Separate process to wait for child messages.
- * Also runs signal handlers and runs all execs.
- */
-static void
-nop(int sig)
-{
-	USED(sig);
-}
-
-static void
-_threadwaitproc(void *v)
-{
-	Channel *c;
-	Waitmsg *w;
-	sigset_t mask;
-	int ret, nkids;
-	Xarg *xa;
-
-	nkids = 0;
-
-	sigemptyset(&mask);
-	siginterrupt(WAITSIG, 1);
-	signal(WAITSIG, nop);
-	sigaddset(&mask, WAITSIG);
-	sigprocmask(SIG_BLOCK, &mask, nil);
-	USED(v);
-	for(;;){
-		while((nkids > 0 ? nbrecv : recv)(_threadexecchan, &xa) == 1){
-			ret = _threadexec(xa->pidc, xa->fd, xa->prog, xa->args, xa->freeargs);
-			if(ret > 0)
-				nkids++;
-			else{
-				rerrstr(xa->errstr, sizeof xa->errstr);
-				xa->errn = errno;
-			}
-			sendul(xa->ret, ret);
-		}
-		if(nkids > 0){
-			sigprocmask(SIG_UNBLOCK, &mask, nil);
-			w = wait();
-			sigprocmask(SIG_BLOCK, &mask, nil);
-			if(w == nil && errno == ECHILD){
-				fprint(2, "wait returned ECHILD but nkids=%d; reset\n", nkids);
-				nkids = 0;
-			}
-			if(w){
-				nkids--;
-				if((c = _threadwaitchan) != nil)
-					sendp(c, w);
-				else
-					free(w);
-			}
-		}
-	}
-}
-
-static void _kickexecproc(void);
-
-int
-_callthreadexec(Channel *pidc, int fd[3], char *prog, char *args[], int freeargs)
-{
-	int ret;
-	Xarg xa;
-
-	if(_threadexecchan == nil){
-		lock(&threadexeclock);
-		if(_threadexecchan == nil)
-			_threadfirstexec();
-		unlock(&threadexeclock);
-	}
-
-	xa.pidc = pidc;
-	xa.fd[0] = fd[0];
-	xa.fd[1] = fd[1];
-	xa.fd[2] = fd[2];
-	xa.prog = prog;
-	xa.args = args;
-	xa.freeargs = freeargs;
-	xa.ret = chancreate(sizeof(ulong), 1);
-	sendp(_threadexecchan, &xa);
-	_kickexecproc();
-	ret = recvul(xa.ret);
-	if(ret < 0){
-		werrstr("%s", xa.errstr);
-		errno = xa.errn;
-	}
-	chanfree(xa.ret);
-	return ret;
-}
-
-/* 
- * Called before the first exec.
- */
-void
-_threadfirstexec(void)
-{
-	int id;
-	Proc *p;
-
-	_threadexecchan = chancreate(sizeof(Xarg*), 1);
-	id = proccreate(_threadwaitproc, nil, 32*1024);
-
-	/*
-	 * Sleazy: decrement threadnprocs so that 
-	 * the existence of the _threadwaitproc proc
-	 * doesn't keep us from exiting.
-	 */
-	lock(&_threadpq.lock);
-	--_threadnprocs;
-	for(p=_threadpq.head; p; p=p->next)
-		if(p->threads.head && p->threads.head->id == id)
-			break;
-	if(p == nil)
-		sysfatal("cannot find exec proc");
-	unlock(&_threadpq.lock);
-	_threadexecproc = p;
-}
-
-/*
- * Called after the thread t has been rescheduled.
- * Kick the exec proc in case it is in the middle of a wait.
- */
-static void
-_kickexecproc(void)
-{
-	kill(_threadexecproc->pid, WAITSIG);
-}
-
-/*
- * Called before exec.
- */
-void
-_threadbeforeexec(void)
-{
-}
-
-/*
- * Called after exec.
- */
-void
-_threadafterexec(void)
-{
-}
-
blob - e2580ac77e38f8460b3bc68cbed606a149076935 (mode 644)
blob + /dev/null
--- src/libthread/exit-getpid.ch
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- * Implement threadexitsall by sending a signal to every proc.
- *
- * To be included from another C file (e.g., Linux-clone.c).
- */
-
-void
-_threadexitallproc(char *exitstr)
-{
-	Proc *p;
-	int mypid;
-
-	mypid = getpid();
-	lock(&_threadpq.lock);
-	for(p=_threadpq.head; p; p=p->next)
-		if(p->pid > 1 && p->pid != mypid)
-			kill(p->pid, SIGUSR2);
-	exits(exitstr);
-}
-
-void
-_threadexitproc(char *exitstr)
-{
-	_exits(exitstr);
-}
blob - 69f3f738b2770fa6ff44e44a5da9f581986399c2 (mode 644)
blob + /dev/null
--- src/libthread/exit.c
+++ /dev/null
@@ -1,44 +0,0 @@
-#include <u.h>
-#include <signal.h>
-#include "threadimpl.h"
-
-char *_threadexitsallstatus;
-Channel *_threadwaitchan;
-
-void
-threadexits(char *exitstr)
-{
-	Proc *p;
-	Thread *t;
-
-	p = _threadgetproc();
-	t = p->thread;
-	if(t == p->idle)
-		p->idle = nil;
-	t->moribund = 1;
-	_threaddebug(DBGSCHED, "threadexits %s", exitstr);
-	if(exitstr==nil)
-		exitstr="";
-	utfecpy(p->exitstr, p->exitstr+ERRMAX, exitstr);
-	_sched();
-}
-
-void
-threadexitsall(char *exitstr)
-{
-	_threaddebug(DBGSCHED, "threadexitsall %s", exitstr);
-	if(exitstr == nil)
-		exitstr = "";
-	_threadexitsallstatus = exitstr;
-	_threaddebug(DBGSCHED, "_threadexitsallstatus set to %p", _threadexitsallstatus);
-	/* leave */
-	_kthreadexitallproc(exitstr);
-}
-
-Channel*
-threadwaitchan(void)
-{
-	if(_threadwaitchan==nil)
-		_threadwaitchan = chancreate(sizeof(Waitmsg*), 16);
-	return _threadwaitchan;
-}
blob - d398341973c709d50e728ac3b3c90225c80713cf (mode 644)
blob + /dev/null
--- src/libthread/fdwait.c
+++ /dev/null
@@ -1,241 +0,0 @@
-#define NOPLAN9DEFINES
-#include <u.h>
-#include <libc.h>
-#include <thread.h>
-#include "threadimpl.h"
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-void
-fdwait()
-{
-	fd_set rfd, wfd, efd;
-
-	FD_ZERO(&rfd);
-	FD_ZERO(&wfd);
-	FD_ZERO(&efd);
-	if(mode=='w')
-		FD_SET(&wfd, fd);
-	else
-		FD_SET(&rfd, fd);
-	FD_SET(&efd, fd);
-	select(fd+1, &rfd, &wfd, &efd, nil);
-}
-
-void
-threadfdwaitsetup(void)
-{
-}
-
-void
-_threadfdwait(int fd, int rw, ulong pc)
-{
-	int i;
-
-	struct {
-		Channel c;
-		ulong x;
-		Alt *qentry[2];
-	} s;
-
-	threadfdwaitsetup();
-	chaninit(&s.c, sizeof(ulong), 1);
-	s.c.qentry = (volatile Alt**)s.qentry;
-	s.c.nentry = 2;
-	memset(s.qentry, 0, sizeof s.qentry);
-	for(i=0; i<npoll; i++)
-		if(pfd[i].fd == -1)
-			break;
-	if(i==npoll){
-		if(npoll >= nelem(polls)){
-			fprint(2, "Too many polled fds.\n");
-			abort();
-		}
-		npoll++;
-	}
-
-	pfd[i].fd = fd;
-	pfd[i].events = rw=='r' ? POLLIN : POLLOUT;
-	polls[i].c = &s.c;
-	if(0) fprint(2, "%s [%3d] fdwait %d %c list *0x%lux\n",
-		argv0, threadid(), fd, rw, pc);
-	if(pollpid)
-		postnote(PNPROC, pollpid, "interrupt");
-	recvul(&s.c);
-}
-
-void
-threadfdwait(int fd, int rw)
-{
-	_threadfdwait(fd, rw, getcallerpc(&fd));
-}
-
-void
-threadsleep(int ms)
-{
-	struct {
-		Channel c;
-		ulong x;
-		Alt *qentry[2];
-	} s;
-
-	threadfdwaitsetup();
-	chaninit(&s.c, sizeof(ulong), 1);
-	s.c.qentry = (volatile Alt**)s.qentry;
-	s.c.nentry = 2;
-	memset(s.qentry, 0, sizeof s.qentry);
-	
-	sleepchan[nsleep] = &s.c;
-	sleeptime[nsleep++] = p9nsec()/1000000+ms;
-	recvul(&s.c);
-}
-
-void
-threadfdnoblock(int fd)
-{
-	fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0)|O_NONBLOCK);
-}
-
-long
-threadread(int fd, void *a, long n)
-{
-	int nn;
-
-	threadfdnoblock(fd);
-again:
-	/*
-	 * Always call wait (i.e. don't optimistically try the read)
-	 * so that the scheduler gets a chance to run other threads.
-	 */
-	_threadfdwait(fd, 'r', getcallerpc(&fd));
-	errno = 0;
-	nn = read(fd, a, n);
-	if(nn <= 0){
-		if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
-			goto again;
-	}
-	return nn;
-}
-
-int
-threadrecvfd(int fd)
-{
-	int nn;
-
-	threadfdnoblock(fd);
-again:
-	/*
-	 * Always call wait (i.e. don't optimistically try the recvfd)
-	 * so that the scheduler gets a chance to run other threads.
-	 */
-	_threadfdwait(fd, 'r', getcallerpc(&fd));
-	nn = recvfd(fd);
-	if(nn < 0){
-		if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
-			goto again;
-	}
-	return nn;
-}
-
-int
-threadsendfd(int fd, int sfd)
-{
-	int nn;
-
-	threadfdnoblock(fd);
-again:
-	/*
-	 * Always call wait (i.e. don't optimistically try the sendfd)
-	 * so that the scheduler gets a chance to run other threads.
-	 */
-	_threadfdwait(fd, 'w', getcallerpc(&fd));
-	nn = sendfd(fd, sfd);
-	if(nn < 0){
-		if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
-			goto again;
-	}
-	return nn;
-}
-
-long
-threadreadn(int fd, void *a, long n)
-{
-	int tot, nn;
-
-	for(tot = 0; tot<n; tot+=nn){
-		nn = threadread(fd, (char*)a+tot, n-tot);
-		if(nn <= 0){
-			if(tot == 0)
-				return nn;
-			return tot;
-		}
-	}
-	return tot;
-}
-
-long
-_threadwrite(int fd, const void *a, long n)
-{
-	int nn;
-
-	threadfdnoblock(fd);
-again:
-	/*
-	 * Always call wait (i.e. don't optimistically try the write)
-	 * so that the scheduler gets a chance to run other threads.
-	 */
-	_threadfdwait(fd, 'w', getcallerpc(&fd));
-	nn = write(fd, a, n);
-	if(nn < 0){
-		if(errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)
-			goto again;
-	}
-	return nn;
-}
-
-long
-threadwrite(int fd, const void *a, long n)
-{
-	int tot, nn;
-
-	for(tot = 0; tot<n; tot+=nn){
-		nn = _threadwrite(fd, (char*)a+tot, n-tot);
-		if(nn <= 0){
-			if(tot == 0)
-				return nn;
-			return tot;
-		}
-	}
-	return tot;
-}
-
-int
-threadannounce(char *addr, char *dir)
-{
-	return p9announce(addr, dir);
-}
-
-int
-threadlisten(char *dir, char *newdir)
-{
-	int fd, ret;
-	extern int _p9netfd(char*);
-
-	fd = _p9netfd(dir);
-	if(fd < 0){
-		werrstr("bad 'directory' in listen: %s", dir);
-		return -1;
-	}
-	threadfdnoblock(fd);
-	while((ret = p9listen(dir, newdir)) < 0 && errno==EAGAIN)
-		_threadfdwait(fd, 'r', getcallerpc(&dir));
-	return ret;
-}
-
-int
-threadaccept(int cfd, char *dir)
-{
-	return p9accept(cfd, dir);
-}
-
blob - c4d23dad8abb84ab9cdf405f23d776b620cfdcc4 (mode 644)
blob + /dev/null
--- src/libthread/getpid.c
+++ /dev/null
@@ -1,7 +0,0 @@
-#include "threadimpl.h"
-extern int getfforkid(void);
-int
-_threadgetpid(void)
-{
-	return getfforkid();
-}
blob - c2aa03d0df45ad3e6208117705a35160a41fa8d5 (mode 644)
blob + /dev/null
--- src/libthread/id.c
+++ /dev/null
@@ -1,136 +0,0 @@
-#include "threadimpl.h"
-
-int
-threadid(void)
-{
-	return _threadgetproc()->thread->id;
-}
-
-int
-threadpid(int id)
-{
-	int pid;
-	Proc *p;
-	Thread *t;
-
-	if (id < 0)
-		return -1;
-	if (id == 0)
-		return _threadgetproc()->pid;
-	lock(&_threadpq.lock);
-	for (p = _threadpq.head; p->next; p = p->next){
-		lock(&p->lock);
-		for (t = p->threads.head; t; t = t->nextt)
-			if (t->id == id){
-				pid = p->pid;
-				unlock(&p->lock);
-				unlock(&_threadpq.lock);
-				return pid;
-			}
-		unlock(&p->lock);
-	}
-	unlock(&_threadpq.lock);
-	return -1;
-}
-
-int
-threadsetgrp(int ng)
-{
-	int og;
-	Thread *t;
-
-	t = _threadgetproc()->thread;
-	og = t->grp;
-	t->grp = ng;
-	return og;
-}
-
-int
-threadgetgrp(void)
-{
-	return _threadgetproc()->thread->grp;
-}
-
-void
-threadsetname(char *fmt, ...)
-{
-	Proc *p;
-	Thread *t;
-	va_list arg;
-
-	p = _threadgetproc();
-	t = p->thread;
-	if(t->name)
-		free(t->name);
-	va_start(arg, fmt);
-	t->name = vsmprint(fmt, arg);
-	va_end(arg);
-
-	_threaddebug(DBGSCHED, "set name %s", t->name);
-/* Plan 9 only 
-	if(p->nthreads == 1){
-		snprint(buf, sizeof buf, "#p/%d/args", getpid());
-		if((fd = open(buf, OWRITE)) >= 0){
-			snprint(buf, sizeof buf, "%s [%s]", argv0, name);
-			n = strlen(buf)+1;
-			s = strchr(buf, ' ');
-			if(s)
-				*s = '\0';
-			write(fd, buf, n);
-			close(fd);
-		}
-	}
-*/
-}
-
-char*
-threadgetname(void)
-{
-	return _threadgetproc()->thread->name;
-}
-
-void**
-threaddata(void)
-{
-	return &_threadgetproc()->thread->udata[0];
-}
-
-void**
-procdata(void)
-{
-	return &_threadgetproc()->udata;
-}
-
-static Lock privlock;
-static int privmask = 1;
-
-int
-tprivalloc(void)
-{
-	int i;
-
-	lock(&privlock);
-	for(i=0; i<NPRIV; i++)
-		if(!(privmask&(1<<i))){
-			privmask |= 1<<i;
-			unlock(&privlock);
-			return i;
-		}
-	unlock(&privlock);
-	return -1;
-}
-
-void
-tprivfree(int i)
-{
-	if(i < 0 || i >= NPRIV)
-		abort();
-	lock(&privlock);
-	privmask &= ~(1<<i);
-}
-
-void**
-tprivaddr(int i)
-{
-	return &_threadgetproc()->thread->udata[i];
-}
blob - e359c4d51eb4576520feae541ef88309135125b3 (mode 644)
blob + /dev/null
--- src/libthread/iocall.c
+++ /dev/null
@@ -1,55 +0,0 @@
-#include <u.h>
-#include <libc.h>
-#include <thread.h>
-#include "ioproc.h"
-
-long
-iocall(Ioproc *io, long (*op)(va_list*), ...)
-{
-	char e[ERRMAX];
-	int ret, inted;
-	Ioproc *msg;
-
-	if(send(io->c, &io) == -1){
-		werrstr("interrupted");
-		return -1;
-	}
-	assert(!io->inuse);
-	io->inuse = 1;
-	io->op = op;
-	va_start(io->arg, op);
-	msg = io;
-	inted = 0;
-	while(send(io->creply, &msg) == -1){
-		msg = nil;
-		inted = 1;
-	}
-	if(inted){
-		werrstr("interrupted");
-		return -1;
-	}
-
-	/*
-	 * If we get interrupted, we have stick around so that
-	 * the IO proc has someone to talk to.  Send it an interrupt
-	 * and try again.
-	 */
-	inted = 0;
-	while(recv(io->creply, nil) == -1){
-		inted = 1;
-		iointerrupt(io);
-	}
-	USED(inted);
-	va_end(io->arg);
-	ret = io->ret;
-	if(ret < 0)
-		strecpy(e, e+sizeof e, io->err);
-	io->inuse = 0;
-
-	/* release resources */
-	while(send(io->creply, &io) == -1)
-		;
-	if(ret < 0)
-		errstr(e, sizeof e);
-	return ret;
-}
blob - fbaabb7c9e6341c711175a5e3655291cfb2ce25e (mode 644)
blob + /dev/null
--- src/libthread/ioclose.c
+++ /dev/null
@@ -1,16 +0,0 @@
-#include "threadimpl.h"
-
-static long
-_ioclose(va_list *arg)
-{
-	int fd;
-
-	fd = va_arg(*arg, int);
-	return close(fd);
-}
-
-int
-ioclose(Ioproc *io, int fd)
-{
-	return iocall(io, _ioclose, fd);
-}
blob - 2e45cfe6291563f2b871026b48fabfe87eaa9fb3 (mode 644)
blob + /dev/null
--- src/libthread/iodial.c
+++ /dev/null
@@ -1,24 +0,0 @@
-#include "threadimpl.h"
-
-static long
-_iodial(va_list *arg)
-{
-	char *addr, *local, *dir;
-	int *cdfp, fd;
-
-	addr = va_arg(*arg, char*);
-	local = va_arg(*arg, char*);
-	dir = va_arg(*arg, char*);
-	cdfp = va_arg(*arg, int*);
-
-fprint(2, "before dial\n");
-	fd = dial(addr, local, dir, cdfp);
-fprint(2, "after dial\n");
-	return fd;
-}
-
-int
-iodial(Ioproc *io, char *addr, char *local, char *dir, int *cdfp)
-{
-	return iocall(io, _iodial, addr, local, dir, cdfp);
-}
blob - 219e581eaff1f45f156203495bd617065f6699f7 (mode 644)
blob + /dev/null
--- src/libthread/ioopen.c
+++ /dev/null
@@ -1,21 +0,0 @@
-#include <u.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include "threadimpl.h"
-
-static long
-_ioopen(va_list *arg)
-{
-	char *path;
-	int mode;
-
-	path = va_arg(*arg, char*);
-	mode = va_arg(*arg, int);
-	return open(path, mode);
-}
-
-int
-ioopen(Ioproc *io, char *path, int mode)
-{
-	return iocall(io, _ioopen, path, mode);
-}
blob - 4e4c32a8d82e9ff9188d81cd4b21dbc479d0551f (mode 644)
blob + /dev/null
--- src/libthread/ioproc.c
+++ /dev/null
@@ -1,77 +0,0 @@
-#include <u.h>
-#include <libc.h>
-#include <thread.h>
-#include "ioproc.h"
-
-enum
-{
-	STACK = 8192,
-};
-
-void
-iointerrupt(Ioproc *io)
-{
-	if(!io->inuse)
-		return;
-	threadint(io->tid);
-}
-
-static void
-xioproc(void *a)
-{
-	Ioproc *io, *x;
-	io = a;
-	/*
-	 * first recvp acquires the ioproc.
-	 * second tells us that the data is ready.
-	 */
-	for(;;){
-		while(recv(io->c, &x) == -1)
-			;
-		if(x == 0)	/* our cue to leave */
-			break;
-		assert(x == io);
-
-		/* caller is now committed -- even if interrupted he'll return */
-		while(recv(io->creply, &x) == -1)
-			;
-		if(x == 0)	/* caller backed out */
-			continue;
-		assert(x == io);
-
-		io->ret = io->op(&io->arg);
-		if(io->ret < 0)
-			rerrstr(io->err, sizeof io->err);
-		while(send(io->creply, &io) == -1)
-			;
-		while(recv(io->creply, &x) == -1)
-			;
-	}
-}
-
-Ioproc*
-ioproc(void)
-{
-	Ioproc *io;
-
-	io = mallocz(sizeof(*io), 1);
-	if(io == nil)
-		sysfatal("ioproc malloc: %r");
-	io->c = chancreate(sizeof(void*), 0);
-	io->creply = chancreate(sizeof(void*), 0);
-	io->tid = proccreate(xioproc, io, STACK);
-	return io;
-}
-
-void
-closeioproc(Ioproc *io)
-{
-	if(io == nil)
-		return;
-	iointerrupt(io);
-	while(send(io->c, 0) == -1)
-		;
-	chanfree(io->c);
-	chanfree(io->creply);
-	free(io);
-}
blob - f3a488d3ce493b2f4177ef1cc794b8c715a279b8 (mode 644)
blob + /dev/null
--- src/libthread/ioproc.h
+++ /dev/null
@@ -1,14 +0,0 @@
-#define ioproc_arg(io, type)	(va_arg((io)->arg, type))
-
-struct Ioproc
-{
-	int tid;
-	Channel *c, *creply;
-	int inuse;
-	long (*op)(va_list*);
-	va_list arg;
-	long ret;
-	char err[ERRMAX];
-	Ioproc *next;
-};
-
blob - 62b1be0306d57ee00e8916eb7d1c402f6f617ef9 (mode 644)
blob + /dev/null
--- src/libthread/ioread.c
+++ /dev/null
@@ -1,20 +0,0 @@
-#include "threadimpl.h"
-
-static long
-_ioread(va_list *arg)
-{
-	int fd;
-	void *a;
-	long n;
-
-	fd = va_arg(*arg, int);
-	a = va_arg(*arg, void*);
-	n = va_arg(*arg, long);
-	return read(fd, a, n);
-}
-
-long
-ioread(Ioproc *io, int fd, void *a, long n)
-{
-	return iocall(io, _ioread, fd, a, n);
-}
blob - b843f6033ed831dae0f4c7cd946f84c3d911420d (mode 644)
blob + /dev/null
--- src/libthread/ioreadn.c
+++ /dev/null
@@ -1,21 +0,0 @@
-#include "threadimpl.h"
-
-static long
-_ioreadn(va_list *arg)
-{
-	int fd;
-	void *a;
-	long n;
-
-	fd = va_arg(*arg, int);
-	a = va_arg(*arg, void*);
-	n = va_arg(*arg, long);
-	n = readn(fd, a, n);
-	return n;
-}
-
-long
-ioreadn(Ioproc *io, int fd, void *a, long n)
-{
-	return iocall(io, _ioreadn, fd, a, n);
-}
blob - 5575645440eb0c32ed9f83c1418f7580bec69a6d (mode 644)
blob + /dev/null
--- src/libthread/iosleep.c
+++ /dev/null
@@ -1,16 +0,0 @@
-#include "threadimpl.h"
-
-static long
-_iosleep(va_list *arg)
-{
-	long n;
-
-	n = va_arg(*arg, long);
-	return sleep(n);
-}
-
-int
-iosleep(Ioproc *io, long n)
-{
-	return iocall(io, _iosleep, n);
-}
blob - 593224c28835992db94b2bd6bc36aa2b108e0e06 (mode 644)
blob + /dev/null
--- src/libthread/iowrite.c
+++ /dev/null
@@ -1,22 +0,0 @@
-#include "threadimpl.h"
-
-static long
-_iowrite(va_list *arg)
-{
-	int fd;
-	void *a;
-	long n, nn;
-
-	fd = va_arg(*arg, int);
-	a = va_arg(*arg, void*);
-	n = va_arg(*arg, long);
-	nn = write(fd, a, n);
-fprint(2, "_iowrite %d %d %r\n", n, nn);
-	return nn;
-}
-
-long
-iowrite(Ioproc *io, int fd, void *a, long n)
-{
-	return iocall(io, _iowrite, fd, a, n);
-}
blob - 648bd66ec01ae94d4f11644755c7e1f6fbf9ae93 (mode 644)
blob + /dev/null
--- src/libthread/kill.c
+++ /dev/null
@@ -1,90 +0,0 @@
-#include <u.h>
-#include <signal.h>
-#include "threadimpl.h"
-
-static void tinterrupt(Proc*, Thread*);
-
-static void
-threadxxxgrp(int grp, int dokill)
-{
-	Proc *p;
-	Thread *t;
-
-	lock(&_threadpq.lock);
-	for(p=_threadpq.head; p; p=p->next){
-		lock(&p->lock);
-		for(t=p->threads.head; t; t=t->nextt)
-			if(t->grp == grp){
-				if(dokill)
-					t->moribund = 1;
-				tinterrupt(p, t);
-			}
-		unlock(&p->lock);
-	}
-	unlock(&_threadpq.lock);
-	_threadbreakrendez();
-}
-
-static void
-threadxxx(int id, int dokill)
-{
-	Proc *p;
-	Thread *t;
-
-	lock(&_threadpq.lock);
-	for(p=_threadpq.head; p; p=p->next){
-		lock(&p->lock);
-		for(t=p->threads.head; t; t=t->nextt)
-			if(t->id == id){
-				if(dokill)
-					t->moribund = 1;
-				tinterrupt(p, t);
-				unlock(&p->lock);
-				unlock(&_threadpq.lock);
-				_threadbreakrendez();
-				return;
-			}
-		unlock(&p->lock);
-	}
-	unlock(&_threadpq.lock);
-	_threaddebug(DBGNOTE, "Can't find thread to kill");
-	return;
-}
-
-void
-threadkillgrp(int grp)
-{
-	threadxxxgrp(grp, 1);
-}
-
-void
-threadkill(int id)
-{
-	threadxxx(id, 1);
-}
-
-void
-threadintgrp(int grp)
-{
-	threadxxxgrp(grp, 0);
-}
-
-void
-threadint(int id)
-{
-	threadxxx(id, 0);
-}
-
-static void
-tinterrupt(Proc *p, Thread *t)
-{
-	switch(t->state){
-	case Running:
-		kill(p->pid, SIGINT);
-	//	postnote(PNPROC, p->pid, "threadint");
-		break;
-	case Rendezvous:
-		_threadflagrendez(t);
-		break;
-	}
-}
blob - 5081f48f621705bc1ca9e3f0defa29d8f54e0984 (mode 644)
blob + /dev/null
--- src/libthread/label.h
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * setjmp and longjmp, but our own because some (stupid) c libraries
- * assume longjmp is only used to move up the stack, and error out
- * if you do otherwise.
- */
-
-typedef struct Label Label;
-#define LABELDPC 0
-
-#if defined(__linux__)
-#include <ucontext.h>
-struct Label
-{
-	ucontext_t uc;
-};
-#elif defined (__i386__) && (defined(__FreeBSD__) || defined(__linux__) || defined(__OpenBSD__))
-struct Label
-{
-	ulong pc;
-	ulong bx;
-	ulong sp;
-	ulong bp;
-	ulong si;
-	ulong di;
-};
-#elif defined(__APPLE__)
-struct Label
-{
-	ulong	pc;		/* lr */
-	ulong	cr;		/* mfcr */
-	ulong	ctr;		/* mfcr */
-	ulong	xer;		/* mfcr */
-	ulong	sp;		/* callee saved: r1 */
-	ulong	toc;		/* callee saved: r2 */
-	ulong	gpr[19];	/* callee saved: r13-r31 */
-// XXX: currently do not save vector registers or floating-point state
-//	ulong	pad;
-//	uvlong	fpr[18];	/* callee saved: f14-f31 */
-//	ulong	vr[4*12];	/* callee saved: v20-v31, 256-bits each */
-};
-#elif defined(__sun__)
-struct Label
-{
-	ulong	input[8];	/* %i registers */
-	ulong	local[8];	/* %l registers */
-	ulong	sp;		/* %o6 */
-	ulong	link;		/* %o7 */
-};
-#elif defined(__powerpc__)
-struct Label
-{
-	ulong	pc;		/* lr */
-	ulong	cr;		/* mfcr */
-	ulong	ctr;		/* mfcr */
-	ulong	xer;		/* mfcr */
-	ulong	sp;		/* callee saved: r1 */
-	ulong	toc;		/* callee saved: r2 */
-	ulong	gpr[19];	/* callee saved: r13-r31 */
-// XXX: currently do not save vector registers or floating-point state
-//	ulong	pad;
-//	uvlong	fpr[18];	/* callee saved: f14-f31 */
-//	ulong	vr[4*12];	/* callee saved: v20-v31, 256-bits each */
-};
-#else
-#error "Unknown or unsupported architecture"
-#endif
-
-
blob - 86e7506e8ba26bc7ce4bc3f6ba69bb5f846c626a (mode 644)
blob + /dev/null
--- src/libthread/lib.c
+++ /dev/null
@@ -1,35 +0,0 @@
-#include "threadimpl.h"
-
-static long totalmalloc;
-
-void*
-_threadmalloc(long size, int z)
-{
-	void *m;
-
-	m = malloc(size);
-	if (m == nil)
-		sysfatal("Malloc of size %ld failed: %r\n", size);
-	setmalloctag(m, getcallerpc(&size));
-	totalmalloc += size;
-	if (size > 1000000) {
-		fprint(2, "Malloc of size %ld, total %ld\n", size, totalmalloc);
-		abort();
-	}
-	if (z)
-		_threadmemset(m, 0, size);
-	return m;
-}
-
-void
-_threadsysfatal(char *fmt, va_list arg)
-{
-	char buf[1024];	/* size doesn't matter; we're about to exit */
-
-	vseprint(buf, buf+sizeof(buf), fmt, arg);
-	if(argv0)
-		fprint(2, "%s: %s\n", argv0, buf);
-	else
-		fprint(2, "%s\n", buf);
-	threadexitsall(buf);
-}
blob - bc4efd276ac21e63455814bf88b92ea10831e125 (mode 644)
blob + /dev/null
--- src/libthread/main.c
+++ /dev/null
@@ -1,98 +0,0 @@
-/*
- * Thread library.  
- */
-
-#include "threadimpl.h"
-
-typedef struct Mainarg Mainarg;
-struct Mainarg
-{
-	int argc;
-	char **argv;
-};
-
-int mainstacksize;
-
-extern void (*_sysfatal)(char*, va_list);
-extern Jmp *(*_notejmpbuf)(void);
-
-static void
-mainlauncher(void *arg)
-{
-	Mainarg *a;
-
-	a = arg;
-	_kmaininit();
-	threadmain(a->argc, a->argv);
-	threadexits("threadmain");
-}
-
-int
-main(int argc, char **argv)
-{
-	Mainarg a;
-	Proc *p;
-
-	/*
-	 * In pthreads, threadmain is actually run in a subprocess,
-	 * so that the main process can exit (if threaddaemonize is called).
-	 * The main process relays notes to the subprocess.
-	 * _Threadbackgroundsetup will return only in the subprocess.
-	 */
-	_threadbackgroundinit();
-
-	/*
-	 * Instruct QLock et al. to use our scheduling functions
-	 * so that they can operate at the thread level.
-	 */
-	_qlockinit(_threadsleep, _threadwakeup);
-
-	/*
-	 * Install our own _threadsysfatal which takes down
-	 * the whole confederation of procs.
-	 */
-	_sysfatal = _threadsysfatal;
-
-	/*
-	 * Install our own jump handler.
-	 */
-	_notejmpbuf = _threadgetjmp;
-
-	/*
-	 * Install our own signal handler.
-	 */
-	notify(_threadnote);
-
-	/*
-	 * Construct the initial proc running mainlauncher(&a).
-	 */
-	if(mainstacksize == 0)
-		mainstacksize = 32*1024;
-	a.argc = argc;
-	a.argv = argv;
-	p = _newproc();
-	_newthread(p, mainlauncher, &a, mainstacksize, "threadmain", 0);
-	_threadscheduler(p);
-	abort();	/* not reached */
-	return 0;
-}
-
-/*
- * No-op function here so that sched.o drags in main.o.
- */
-void
-_threadlinkmain(void)
-{
-}
-
-Jmp*
-_threadgetjmp(void)
-{
-	static Jmp j;
-	Proc *p;
-
-	p = _threadgetproc();
-	if(p == nil)
-		return &j;
-	return &p->sigjmp;
-}
blob - dd74fb6cc87c58f2814dcd4f3d9a445274f0e771 (mode 644)
blob + /dev/null
--- src/libthread/memset.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "threadimpl.h"
-#include <string.h>
-
-void
-_threadmemset(void *v, int c, int n)
-{
-	memset(v, c, n);
-}
blob - ef3f96050591da7967260351de718de504215df9 (mode 644)
blob + /dev/null
--- src/libthread/memsetd.c
+++ /dev/null
@@ -1,8 +0,0 @@
-#include "threadimpl.h"
-#include <string.h>
-
-void
-_threaddebugmemset(void *v, int c, int n)
-{
-	memset(v, c, n);
-}
blob - 6492bb931022862956197297c01dae48ce06e3c2 (mode 644)
blob + /dev/null
--- src/libthread/mkfile
+++ /dev/null
@@ -1,73 +0,0 @@
-<$PLAN9/src/mkhdr
-
-LIB=libthread.a
-SYSOFILES=`sh ./sysofiles.sh`
-OFILES=\
-	$SYSOFILES\
-	channel.$O\
-	chanprint.$O\
-	create.$O\
-	debug.$O\
-	exec-unix.$O\
-	exit.$O\
-	fdwait.$O\
-	getpid.$O\
-	id.$O\
-	iocall.$O\
-	ioclose.$O\
-	iodial.$O\
-	ioopen.$O\
-	ioproc.$O\
-	ioread.$O\
-	ioreadn.$O\
-	iosleep.$O\
-	iowrite.$O\
-	lib.$O\
-	main.$O\
-	memset.$O\
-	memsetd.$O\
-	read9pmsg.$O\
-	ref.$O\
-	sched.$O\
-	setproc.$O\
-	sleep.$O\
-
-HFILES=\
-	$PLAN9/include/thread.h\
-	label.h\
-	threadimpl.h\
-
-<$PLAN9/src/mksyslib
-
-tfork: tfork.$O $PLAN9/lib/$LIB
-	$LD -o tfork tfork.$O $LDFLAGS -lthread -l9
-
-tprimes: tprimes.$O $PLAN9/lib/$LIB
-	$LD -o tprimes tprimes.$O $LDFLAGS -lthread -l9
-
-texec: texec.$O $PLAN9/lib/$LIB
-	$LD -o texec texec.$O $LDFLAGS -lthread -l9
-
-tspawn: tspawn.$O $PLAN9/lib/$LIB
-	$LD -o tspawn tspawn.$O $LDFLAGS -lthread -l9
-
-trend: trend.$O $PLAN9/lib/$LIB
-	$LD -o trend trend.$O $LDFLAGS -lthread -l9
-
-tsignal: tsignal.$O $PLAN9/lib/$LIB
-	$LD -o tsignal tsignal.$O $LDFLAGS -lthread -l9
-
-CLEANFILES=$CLEANFILES tprimes texec
-
-asm-Linux-ppc.$O: asm-Linux-386.s
-asm-Linux-386.$O: asm-FreeBSD-386.s
-asm-NetBSD-386.$O: asm-FreeBSD-386.s
-asm-OpenBSD-386.$O: asm-FreeBSD-386.s
-
-# sorry
-VG=`test -d /home/rsc/pub/valgrind-debian && echo -DUSEVALGRIND`
-# VG=
-
-CFLAGS=$CFLAGS $VG
-
-Linux-clone.$O: execproc.ch exit-getpid.ch proctab.ch procstack.ch
blob - ed40c08fb5d956428270200a53d4cb5cf8642dbf (mode 644)
blob + /dev/null
--- src/libthread/note.c
+++ /dev/null
@@ -1,145 +0,0 @@
-#include "threadimpl.h"
-
-
-int	_threadnopasser;
-
-#define	NFN		33
-#define	ERRLEN	48
-typedef struct Note Note;
-struct Note
-{
-	Lock		inuse;
-	Proc		*proc;		/* recipient */
-	char		s[ERRMAX];	/* arg2 */
-};
-
-static Note	notes[128];
-static Note	*enotes = notes+nelem(notes);
-static int		(*onnote[NFN])(void*, char*);
-static int		onnotepid[NFN];
-static Lock	onnotelock;
-
-int
-threadnotify(int (*f)(void*, char*), int in)
-{
-	int i, topid;
-	int (*from)(void*, char*), (*to)(void*, char*);
-
-	if(in){
-		from = 0;
-		to = f;
-		topid = _threadgetproc()->pid;
-	}else{
-		from = f;
-		to = 0;
-		topid = 0;
-	}
-	lock(&onnotelock);
-	for(i=0; i<NFN; i++)
-		if(onnote[i]==from){
-			onnote[i] = to;
-			onnotepid[i] = topid;
-			break;
-		}
-	unlock(&onnotelock);
-	return i<NFN;
-}
-
-static void
-delayednotes(Proc *p, void *v)
-{
-	int i;
-	Note *n;
-	int (*fn)(void*, char*);
-
-	if(!p->pending)
-		return;
-
-	p->pending = 0;
-	for(n=notes; n<enotes; n++){
-		if(n->proc == p){
-			for(i=0; i<NFN; i++){
-				if(onnotepid[i]!=p->pid || (fn = onnote[i])==0)
-					continue;
-				if((*fn)(v, n->s))
-					break;
-			}
-			if(i==NFN){
-				_threaddebug(DBGNOTE, "Unhandled note %s, proc %p\n", n->s, p);
-				if(strcmp(n->s, "sys: child") == 0)
-					noted(NCONT);
-				fprint(2, "unhandled note %s, pid %d\n", n->s, p->pid);
-				if(v != nil)
-					noted(NDFLT);
-				else if(strncmp(n->s, "sys:", 4)==0)
-					abort();
-				threadexitsall(n->s);
-			}
-			n->proc = nil;
-			unlock(&n->inuse);
-		}
-	}
-}
-
-void
-_threadnote(void *v, char *s)
-{
-	Proc *p;
-	Note *n;
-
-	_threaddebug(DBGNOTE, "Got note %s", s);
-	if(strncmp(s, "sys:", 4) == 0)
-		noted(NDFLT);
-
-//	if(_threadexitsallstatus){
-//		_threaddebug(DBGNOTE, "Threadexitsallstatus = '%s'\n", _threadexitsallstatus);
-//		_exits(_threadexitsallstatus);
-//	}
-
-	if(strcmp(s, "threadint")==0 || strcmp(s, "interrupt")==0)
-		noted(NCONT);
-
-	p = _threadgetproc();
-	if(p == nil)
-		noted(NDFLT);
-
-	for(n=notes; n<enotes; n++)
-		if(canlock(&n->inuse))
-			break;
-	if(n==enotes)
-		sysfatal("libthread: too many delayed notes");
-	utfecpy(n->s, n->s+ERRMAX, s);
-	n->proc = p;
-	p->pending = 1;
-	if(!p->splhi)
-		delayednotes(p, v);
-	noted(NCONT);
-}
-
-int
-_procsplhi(void)
-{
-	int s;
-	Proc *p;
-
-	p = _threadgetproc();
-	s = p->splhi;
-	p->splhi = 1;
-	return s;
-}
-
-void
-_procsplx(int s)
-{
-	Proc *p;
-
-	p = _threadgetproc();
-	p->splhi = s;
-	if(s)
-		return;
-/*
-	if(p->pending)
-		delayednotes(p, nil);
-*/
-}
-
blob - bbc7dbbfb4d26443b024cd820345ee8445068b8f (mode 644)
blob + /dev/null
--- src/libthread/pid.c
+++ /dev/null
@@ -1,25 +0,0 @@
-	mypid = getpid();
-
-	/*
-	 * signal others.
-	 * copying all the pids first avoids other thread's
-	 * teardown procedures getting in the way.
-	 */
-	lock(&_threadpq.lock);
-	npid = 0;
-	for(p=_threadpq.head; p; p=p->next)
-		npid++;
-	pid = _threadmalloc(npid*sizeof(pid[0]), 0);
-	npid = 0;
-	for(p = _threadpq.head; p; p=p->next)
-		pid[npid++] = p->pid;
-	unlock(&_threadpq.lock);
-	for(i=0; i<npid; i++){
-		_threaddebug(DBGSCHED, "threadexitsall kill %d", pid[i]);
-		if(pid[i]==0 || pid[i]==-1)
-			fprint(2, "bad pid in threadexitsall: %d\n", pid[i]);
-		else if(pid[i] != mypid){
-			kill(pid[i], SIGTERM);
-		}
-	}
-
blob - b0a14e6f26e62ed1db7f609ff9bedeb44f1ca697 (mode 644)
blob + /dev/null
--- src/libthread/power.c
+++ /dev/null
@@ -1,40 +0,0 @@
-#include "threadimpl.h"
-
-static void
-launcherpower(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7,
-	void (*f)(void *arg), void *arg)
-{
-	(*f)(arg);
-	threadexits(nil);
-}
-
-void
-_threadinitstack(Thread *t, void (*f)(void*), void *arg)
-{
-	ulong *tos, *stk;
-
-	tos = (ulong*)&t->stk[t->stksize&~7];
-	stk = tos;
-	--stk;
-	--stk;
-	--stk;
-	--stk;
-	*--stk = (ulong)arg;
-	*--stk = (ulong)f;
-	t->sched.pc = (ulong)launcherpower+LABELDPC;
-	t->sched.sp = ((ulong)stk)-8;
-	*((ulong *)t->sched.sp) = 0;
-}
-
-void
-_threadinswitch(int enter)
-{
-	USED(enter);
-}
-
-void
-_threadstacklimit(void *addr, void *addr2)
-{
-	USED(addr);
-}
-
blob - ccf81866cec7b4ab9ef08e695cc7a19b39c53331 (mode 644)
blob + /dev/null
--- src/libthread/procstack.ch
+++ /dev/null
@@ -1,75 +0,0 @@
-static int fforkstacksize = 16384;
-
-typedef struct Stack Stack;
-struct Stack
-{
-	Stack *next;
-	Stack *fnext;
-	int pid;
-};
-
-static Lock stacklock;
-static Stack *freestacks;
-static Stack *allstacks;
-static int stackmallocs;
-static void gc(void);
-
-static void*
-mallocstack(void)
-{
-	Stack *p;
-
-	lock(&stacklock);
-top:
-	p = freestacks;
-	if(p)
-		freestacks = p->fnext;
-	else{
-		if(stackmallocs++%1 == 0)
-			gc();
-		if(freestacks)
-			goto top;
-		p = malloc(fforkstacksize);
-		p->next = allstacks;
-		allstacks = p;
-	}
-	if(p)
-		p->pid = 1;
-	unlock(&stacklock);
-	return p;
-}
-
-static void
-gc(void)
-{
-	Stack *p;
-
-	for(p=allstacks; p; p=p->next){
-		if(p->pid > 1 && procexited(p->pid)){
-			if(0) fprint(2, "reclaim stack from %d\n", p->pid);
-			p->pid = 0;
-		}
-		if(p->pid == 0){
-			p->fnext = freestacks;
-			freestacks = p;
-		}
-	}
-}
-
-static void
-freestack(void *v)
-{
-	Stack *p;
-
-	p = v;
-	if(p == nil)
-		return;
-	lock(&stacklock);
-	p->fnext = freestacks;
-	p->pid = 0;
-	freestacks = p;
-	unlock(&stacklock);
-	return;
-}
-
-
blob - b8dd2097466d2d37c48ca66d6968daf14696c7d8 (mode 644)
blob + /dev/null
--- src/libthread/proctab.c
+++ /dev/null
@@ -1,75 +0,0 @@
-#include "threadimpl.h"
-
-/* this will need work */
-enum
-{
-	PTABHASH = 257,
-};
-
-static int multi;
-static Proc *theproc;
-
-void
-_threadmultiproc(void)
-{
-	if(multi == 0){
-		multi = 1;
-		_threadsetproc(theproc);
-	}
-}
-
-static Lock ptablock;
-Proc *ptab[PTABHASH];
-
-void
-_threadsetproc(Proc *p)
-{
-	int h;
-
-	if(!multi){
-		theproc = p;
-		return;
-	}
-	lock(&ptablock);
-	h = ((unsigned)p->pid)%PTABHASH;
-	p->link = ptab[h];
-	unlock(&ptablock);
-	ptab[h] = p;
-}
-
-static Proc*
-__threadgetproc(int rm)
-{
-	Proc **l, *p;
-	int h, pid;
-
-	if(!multi)
-		return theproc;
-
-	pid = getpid();
-
-	lock(&ptablock);
-	h = ((unsigned)pid)%PTABHASH;
-	for(l=&ptab[h]; p=*l; l=&p->link){
-		if(p->pid == pid){
-			if(rm)
-				*l = p->link;
-			unlock(&ptablock);
-			return p;
-		}
-	}
-	unlock(&ptablock);
-	return nil;
-}
-
-Proc*
-_threadgetproc(void)
-{
-	return __threadgetproc(0);
-}
-
-Proc*
-_threaddelproc(void)
-{
-	return __threadgetproc(1);
-}
blob - d51543f991482d954b167ec681c8ac0a24264a38 (mode 644)
blob + /dev/null
--- src/libthread/proctab.ch
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Proc structure hash table indexed by proctabid() (usually getpid()).
- * No lock is necessary for lookups (important when called from signal
- * handlers).
- * 
- * To be included from other files (e.g., Linux-clone.c).
- */
-
-#define T ((void*)-1)
-
-enum
-{
-	PTABHASH = 1031,
-};
-
-static Lock ptablock;
-static Proc *proctab[PTABHASH];
-static Proc *theproc;
-static int multi;
-
-void
-_threadmultiproc(void)
-{
-	if(multi == 0){
-		multi = 1;
-		_threadsetproc(theproc);
-	}
-}
-
-void
-_threadsetproc(Proc *p)
-{
-	int i, h;
-	Proc **t;
-
-	if(!multi){
-		theproc = p;
-		return;
-	}
-	lock(&ptablock);
-	p->procid = procid();
-	h = p->procid%PTABHASH;
-	for(i=0; i<PTABHASH; i++){
-		t = &proctab[(h+i)%PTABHASH];
-		if(*t==nil || *t==T){
-			*t = p;
-			break;
-		}
-	}
-	unlock(&ptablock);
-	if(i == PTABHASH)
-		sysfatal("too many procs - proctab is full");
-}
-
-static Proc**
-_threadfindproc(int id)
-{
-	int i, h;
-	Proc **t;
-
-	if(!multi)
-		return &theproc;
-
-	h = id%PTABHASH;
-	for(i=0; i<PTABHASH; i++){
-		t = &proctab[(h+i)%PTABHASH];
-		if(*t != nil && *t != T && (*t)->procid == id){
-			unlock(&ptablock);
-			return t;
-		}
-	}
-	return nil;
-}
-
-Proc*
-_threadgetproc(void)
-{
-	Proc **t;
-
-	t = _threadfindproc(procid());
-	if(t == nil)
-		return nil;
-	return *t;
-}
-
-Proc*
-_threaddelproc(void)
-{
-	Proc **t, *p;
-
-	t = _threadfindproc(procid());
-	if(t == nil)
-		return nil;
-	p = *t;
-	*t = T;
-	return p;
-}
blob - 83d8b023576d6e0f3d0b0f4de42a7c8d05a59c31 (mode 644)
blob + /dev/null
--- src/libthread/pthread.c
+++ /dev/null
@@ -1,271 +0,0 @@
-#include <u.h>
-#include <errno.h>
-#include "threadimpl.h"
-
-/*
- * Basic kernel thread management.
- */
-static pthread_key_t key;
-
-void
-_kthreadinit(void)
-{
-	pthread_key_create(&key, 0);
-}
-
-void
-_kthreadsetproc(Proc *p)
-{
-	sigset_t all;
-
-	p->pthreadid = pthread_self();
-	sigfillset(&all);
-	pthread_sigmask(SIG_SETMASK, &all, nil);
-	pthread_setspecific(key, p);
-}
-
-Proc*
-_kthreadgetproc(void)
-{
-	return pthread_getspecific(key);
-}
-
-void
-_kthreadstartproc(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;
-}
-
-void
-_kthreadexitproc(char *exitstr)
-{
-	_threaddebug(DBGSCHED, "_pthreadexit");
-	pthread_exit(nil);
-}
-
-void
-_kthreadexitallproc(char *exitstr)
-{
-	_threaddebug(DBGSCHED, "_threadexitallproc");
-	exits(exitstr);
-}
-
-/*
- * Exec.  Pthreads does the hard work of making it possible
- * for any thread to do the waiting, so this is pretty easy.
- * We create a separate proc whose job is to wait for children
- * and deliver wait messages.
- */
-static Channel *_threadexecwaitchan;
-
-static void
-_threadwaitproc(void *v)
-{
-	Channel *c;
-	Waitmsg *w;
-
-	_threadinternalproc();
-
-	USED(v);
-	
-	for(;;){
-		w = wait();
-		if(w == nil){
-			if(errno == ECHILD)	/* wait for more */
-				recvul(_threadexecwaitchan);
-			continue;
-		}
-		if((c = _threadwaitchan) != nil)
-			sendp(c, w);
-		else
-			free(w);
-	}
-	fprint(2, "_threadwaitproc exits\n");	/* not reached */
-}
-
-
-/* 
- * Call _threadexec in the right conditions.
- */
-int
-_kthreadexec(Channel *c, int fd[3], char *prog, char *args[], int freeargs)
-{
-	static Lock lk;
-	int rv;
-
-	if(!_threadexecwaitchan){
-		lock(&lk);
-		if(!_threadexecwaitchan){
-			_threadexecwaitchan = chancreate(sizeof(ulong), 1);
-			proccreate(_threadwaitproc, nil, 32*1024);
-		}
-		unlock(&lk);
-	}
-	rv = _threadexec(c, fd, prog, args, freeargs);
-	nbsendul(_threadexecwaitchan, 1);
-	return rv;
-}
-
-/*
- * Some threaded applications want to run in the background.
- * Calling fork() and exiting in the parent will result in a child
- * with a single pthread (if we are using pthreads), and will screw
- * up our internal process info if we are using clone/rfork.
- * Instead, apps should call threadbackground(), which takes
- * care of this.
- * 
- * _threadbackgroundinit is called from main.
- */
-
-static int mainpid, passerpid;
-
-static void
-passer(void *x, char *msg)
-{
-	Waitmsg *w;
-
-	USED(x);
-	if(strcmp(msg, "sys: usr2") == 0)
-		_exit(0);	/* daemonize */
-	else if(strcmp(msg, "sys: child") == 0){
-		/* child exited => so should we */
-		w = wait();
-		if(w == nil)
-			_exit(1);
-		_exit(atoi(w->msg));
-	}else
-		postnote(PNGROUP, mainpid, msg);
-}
-
-void
-_threadbackgroundinit(void)
-{
-	int pid;
-	sigset_t mask;
-
-	sigfillset(&mask);
-	pthread_sigmask(SIG_BLOCK, &mask, 0);
-
-return;
-
-	passerpid = getpid();
-	switch(pid = fork()){
-	case -1:
-		sysfatal("fork: %r");
-
-	case 0:
-		rfork(RFNOTEG);
-		return;
-
-	default:
-		break;
-	}
-
-	mainpid = pid;
-	notify(passer);
-	notifyon("sys: child");
-	notifyon("sys: usr2");	/* should already be on */
-	for(;;)
-		pause();
-	_exit(0);
-}
-
-void
-threadbackground(void)
-{
-	if(passerpid <= 1)
-		return;
-	postnote(PNPROC, passerpid, "sys: usr2");
-}
-
-/*
- * Notes.
- */
-Channel *_threadnotechan;
-static ulong sigs;
-static Lock _threadnotelk;
-static void _threadnoteproc(void*);
-extern int _p9strsig(char*);
-extern char *_p9sigstr(int);
-
-Channel*
-threadnotechan(void)
-{
-	if(_threadnotechan == nil){
-		lock(&_threadnotelk);
-		if(_threadnotechan == nil){
-			_threadnotechan = chancreate(sizeof(char*), 1);
-			proccreate(_threadnoteproc, nil, 32*1024);
-		}
-		unlock(&_threadnotelk);
-	}
-	return _threadnotechan;
-}
-
-void
-_threadnote(void *x, char *msg)
-{
-	USED(x);
-
-	if(_threadexitsallstatus)
-		_kthreadexitproc(_threadexitsallstatus);
-
-	if(strcmp(msg, "sys: usr2") == 0)
-		noted(NCONT);
-
-	if(_threadnotechan == nil)
-		noted(NDFLT);
-
-	sigs |= 1<<_p9strsig(msg);
-	noted(NCONT);
-}
-
-void
-_threadnoteproc(void *x)
-{
-	int i;
-	sigset_t none;
-	Channel *c;
-
-	_threadinternalproc();
-	sigemptyset(&none);
-	pthread_sigmask(SIG_SETMASK, &none, 0);
-
-	c = _threadnotechan;
-	for(;;){
-		if(sigs == 0)
-			pause();
-		for(i=0; i<32; i++){
-			if((sigs&(1<<i)) == 0)
-				continue;
-			sigs &= ~(1<<i);
-			if(i == 0)
-				continue;
-			sendp(c, _p9sigstr(i));
-		}
-	}
-}
-
-void
-_threadschednote(void)
-{
-}
-
-void
-_kmaininit(void)
-{
-	sigset_t all;
-
-	sigfillset(&all);
-	pthread_sigmask(SIG_SETMASK, &all, 0);
-}
blob - 652fc82fad698958b43ab9d3373e9f49f5ae3ad1 (mode 644)
blob + /dev/null
--- src/libthread/read9pmsg.c
+++ /dev/null
@@ -1,32 +0,0 @@
-#include <u.h>
-#include <libc.h>
-#include <fcall.h>
-#include <thread.h>
-
-int
-threadread9pmsg(int fd, void *abuf, uint n)
-{
-	int m, len;
-	uchar *buf;
-
-	buf = abuf;
-
-	/* read count */
-	m = threadreadn(fd, buf, BIT32SZ);
-	if(m != BIT32SZ){
-		if(m < 0)
-			return -1;
-		return 0;
-	}
-
-	len = GBIT32(buf);
-	if(len <= BIT32SZ || len > n){
-		werrstr("bad length in 9P2000 message header");
-		return -1;
-	}
-	len -= BIT32SZ;
-	m = threadreadn(fd, buf+BIT32SZ, len);
-	if(m < len)
-		return 0;
-	return BIT32SZ+m;
-}
blob - a3b2cbae53acefe2830c7680aaa145e9562249cb (mode 644)
blob + /dev/null
--- src/libthread/ref.c
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Atomic reference counts - used by applications.
- *
- * We use locks to avoid the assembly of the Plan 9 versions.
- */
-
-#include "threadimpl.h"
-
-void
-incref(Ref *r)
-{
-	lock(&r->lk);
-	r->ref++;
-	unlock(&r->lk);
-}
-
-long
-decref(Ref *r)
-{
-	long n;
-
-	lock(&r->lk);
-	n = --r->ref;
-	unlock(&r->lk);
-	return n;
-}
blob - ac982da86645d289a17c03c786ef1fefdb9e7174 (mode 644)
blob + /dev/null
--- src/libthread/sched.c
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * Thread scheduler.
- */
-#include "threadimpl.h"
-
-static Thread *runthread(Proc*);
-static void schedexit(Proc*);
-
-/*
- * Main scheduling loop.
- */
-void
-_threadscheduler(void *arg)
-{
-	Proc *p;
-	Thread *t;
-
-	p = arg;
-
-	_threadlinkmain();
-	_threadsetproc(p);
-
-	for(;;){
-		/* 
-		 * Clean up zombie children.
-		 */
-
-		/*
-		 * Find next thread to run.
-		 */
-		_threaddebug(DBGSCHED, "runthread");
-		t = runthread(p);
-		if(t == nil)
-			schedexit(p);
-	
-		/*
-		 * If it's ready, run it (might instead be marked to die).
-		 */
-		lock(&p->lock);
-		if(t->state == Ready){
-			_threaddebug(DBGSCHED, "running %d.%d", p->id, t->id);
-			t->state = Running;
-			t->nextstate = Ready;
-			p->thread = t;
-			unlock(&p->lock);
-			_swaplabel(&p->context, &t->context);
-			lock(&p->lock);
-			p->thread = nil;
-		}
-
-		/*
-		 * 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;
-			_procdelthread(p, t);
-			unlock(&p->lock);
-			_threadfree(t);
-			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.
-		 */
-		if(p->schedfn){
-			_threaddebug(DBGSCHED, "schedfn");
-			p->schedfn(p);
-			p->schedfn = nil;
-			_threaddebug(DBGSCHED, "schedfn ended");
-		}
-
-		/*
-		 * Move the thread along.
-		 */
-		t->state = t->nextstate;
-		_threaddebug(DBGSCHED, "moveon %d.%d", t->proc->id, t->id);
-		if(t->state == Ready)
-			_threadready(t);
-	}
-}
-
-/*
- * Called by thread to give up control of processor to scheduler.
- */
-int
-_sched(void)
-{
-	Proc *p;
-	Thread *t;
-
-	p = _threadgetproc();
-	t = p->thread;
-	assert(t != nil);
-	_swaplabel(&t->context, &p->context);
-	return p->nsched++;
-}
-
-/*
- * Called by thread to yield the processor to other threads.
- * Returns number of other threads run between call and return.
- */
-int
-yield(void)
-{
-	Proc *p;
-	int nsched;
-
-	p = _threadgetproc();
-	nsched = p->nsched;
-	return _sched() - nsched;
-}
-
-/*
- * Choose the next thread to run.
- */
-static Thread*
-runthread(Proc *p)
-{
-	Thread *t;
-	Tqueue *q;
-
-	/*
-	 * No threads left?
-	 */
-	if(p->nthreads==0 || (p->nthreads==1 && p->idle))
-		return nil;
-
-	_threadschednote();
-	lock(&p->readylock);
-	q = &p->ready;
-	if(q->head == nil){
-		/*
-		 * Is this a single-process program with an idle thread?
-		 */
-		if(p->idle){
-			/*
-			 * The idle thread had better be ready!
-			 */
-			if(p->idle->state != Ready)
-				sysfatal("all threads are asleep");
-
-			/*
-			 * Run the idle thread.
-			 */
-			unlock(&p->readylock);
-			_threaddebug(DBGSCHED, "running idle thread", p->nthreads);
-			return p->idle;
-		}
-
-		/*
-		 * Wait until one of our threads is readied (by another proc!).
-		 */
-		q->asleep = 1;
-		p->rend.l = &p->readylock;
-		while(q->asleep){
-			_procsleep(&p->rend);
-			_threadschednote();
-		}
-
-		/*
-		 * Maybe we were awakened to exit?
-		 */
-		if(_threadexitsallstatus){
-			_threaddebug(DBGSCHED, "time to exit");
-			_exits(_threadexitsallstatus);
-		}
-		assert(q->head != nil);
-	}
-
-	t = q->head;
-	q->head = t->next;
-	unlock(&p->readylock);
-
-	return t;
-}
-
-/*
- * Add a newly-ready thread to its proc's run queue.
- */
-void
-_threadready(Thread *t)
-{
-	Tqueue *q;
-
-	/*
-	 * The idle thread does not go on the run queue.
-	 */
-	if(t == t->proc->idle){
-		_threaddebug(DBGSCHED, "idle thread is ready");
-		return;
-	}
-
-	assert(t->state == Ready);
-	_threaddebug(DBGSCHED, "readying %d.%d", t->proc->id, t->id);
-
-	/*
-	 * Add thread to run queue.
-	 */
-	q = &t->proc->ready;
-	lock(&t->proc->readylock);
-
-	t->next = nil;
-	if(q->head == nil)
-		q->head = t;
-	else
-		q->tail->next = t;
-	q->tail = t;
-
-	/*
-	 * Wake proc scheduler if it is sleeping.
-	 */
-	if(q->asleep){
-		assert(q->asleep == 1);
-		q->asleep = 0;
-		_procwakeup(&t->proc->rend);
-	}
-	unlock(&t->proc->readylock);
-}
-
-/*
- * Mark the given thread as the idle thread.
- * Since the idle thread was just created, it is sitting
- * somewhere on the ready queue.
- */
-void
-_threadsetidle(int id)
-{
-	Tqueue *q;
-	Thread *t, **l, *last;
-	Proc *p;
-
-	p = _threadgetproc();
-
-	lock(&p->readylock);
-
-	/*
-	 * Find thread on ready queue.
-	 */
-	q = &p->ready;
-	for(l=&q->head, last=nil; (t=*l) != nil; l=&t->next, last=t)
-		if(t->id == id)
-			break;
-	assert(t != nil);
-
-	/* 
-	 * Remove it from ready queue.
-	 */
-	*l = t->next;
-	if(t == q->head)
-		q->head = t->next;
-	if(t->next == nil)
-		q->tail = last;
-
-	/*
-	 * Set as idle thread.
-	 */
-	p->idle = t;
-	_threaddebug(DBGSCHED, "p->idle is %d\n", t->id);
-	unlock(&p->readylock);
-}
-
-/*
- * Mark proc as internal so that if all but internal procs exit, we exit.
- */
-void
-_threadinternalproc(void)
-{
-	Proc *p;
-
-	p = _threadgetproc();
-	if(p->internal)
-		return;
-	lock(&_threadpq.lock);
-	if(p->internal == 0){
-		p->internal = 1;
-		--_threadnprocs;
-	}
-	unlock(&_threadpq.lock);
-}
-
-static void
-schedexit(Proc *p)
-{
-	char ex[ERRMAX];
-	int n;
-	Proc **l;
-
-	_threaddebug(DBGSCHED, "exiting proc %d", p->id);
-	lock(&_threadpq.lock);
-	for(l=&_threadpq.head; *l; l=&(*l)->next){
-		if(*l == p){
-			*l = p->next;
-			if(*l == nil)
-				_threadpq.tail = l;
-			break;
-		}
-	}
-	if(p->internal)
-		n = _threadnprocs;
-	else
-		n = --_threadnprocs;
-	unlock(&_threadpq.lock);
-
-	strncpy(ex, p->exitstr, sizeof ex);
-	ex[sizeof ex-1] = '\0';
-	free(p);
-	if(n == 0){
-		_threaddebug(DBGSCHED, "procexit; no more procs");
-		_kthreadexitallproc(ex);
-	}else{
-		_threaddebug(DBGSCHED, "procexit");
-		_kthreadexitproc(ex);
-	}
-}
-
blob - 5f1e2a8d0bffafc72f0e57357f860dc43f97058e (mode 644)
blob + /dev/null
--- src/libthread/setproc.c
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Avoid using threading calls for single-proc programs.
- */
-
-#include "threadimpl.h"
-
-static int multi;
-static Proc *theproc;
-
-void
-_threadsetproc(Proc *p)
-{
-	if(!multi)
-		theproc = p;
-	else
-		_kthreadsetproc(p);
-}
-
-Proc*
-_threadgetproc(void)
-{
-	if(!multi)
-		return theproc;
-	return _kthreadgetproc();
-}
-
-void
-_threadmultiproc(void)
-{
-	if(multi)
-		return;
-
-	multi = 1;
-	_kthreadinit();
-	_threadsetproc(theproc);
-}
blob - 4b0d82a1ed1238f5eaee2a31a88cd919d90c530c (mode 644)
blob + /dev/null
--- src/libthread/sleep.c
+++ /dev/null
@@ -1,39 +0,0 @@
-#include "threadimpl.h"
-
-int _threadhighnrendez;
-int _threadnrendez;
-
-void
-_threadsleep(_Procrend *r)
-{
-	Thread *t;
-
-	t = _threadgetproc()->thread;
-	r->arg = t;
-	t->nextstate = Rendezvous;
-	t->asleep = 1;
-	unlock(r->l);
-	_sched();
-	t->asleep = 0;
-	lock(r->l);
-}
-
-void
-_threadwakeup(_Procrend *r)
-{
-	Thread *t;
-
-	t = r->arg;
-	while(t->state == Running)
-		sleep(0);
-	lock(&t->proc->lock);
-	if(t->state == Dead){
-		unlock(&t->proc->lock);
-		return;
-	}
-	assert(t->state == Rendezvous && t->asleep);
-	t->state = Ready;
-	_threadready(t);
-	unlock(&t->proc->lock);
-}
-
blob - 0d2d8d249457bc6fc296f9916c6d7eac69162c27 (mode 644)
blob + /dev/null
--- src/libthread/sun4u.c
+++ /dev/null
@@ -1,53 +0,0 @@
-#include "threadimpl.h"
-
-static void
-launchersparc(uint o0, uint o1, uint o2, uint o3,
-	uint o4, uint o5, uint o6, uint o7,
-	void (*f)(void *arg), void *arg)
-{
-	if(0) print("ls %x %x %x %x %x %x %x %x %x %x at %x\n",
-		o0, o1, o2, o3, o4, o5, o6, o7, f, arg, &o0);
-	(*f)(arg);
-	threadexits(nil);
-}
-
-void
-_threadinitstack(Thread *t, void (*f)(void*), void *arg)
-{
-	ulong *tos, *stk;
-
-	/*
-	 * This is a bit more complicated than it should be,
-	 * because we need to set things up so that gotolabel
-	 * (which executes a return) gets us into launchersparc.
-	 * So all the registers are going to be renamed before
-	 * we get there.  The input registers here become the
-	 * output registers there, which is useless.  
-	 * The input registers there are inaccessible, so we
-	 * have to give launchersparc enough arguments that
-	 * everything ends up in the stack.
-	 */
-	tos = (ulong*)&t->stk[t->stksize&~7];
-	stk = tos;
-	--stk;
-	*--stk = (ulong)arg;
-	*--stk = (ulong)f;
-	stk -= 25;	/* would love to understand this */
-	t->sched.link = (ulong)launchersparc - 8;
-	t->sched.input[6] = 0;
-	t->sched.sp = (ulong)stk;
-	if(0) print("tis %x %x at %x\n", f, arg, t->sched.sp);
-}
-
-void
-_threadinswitch(int enter)
-{
-	USED(enter);
-}
-
-void
-_threadstacklimit(void *addr, void *addr2)
-{
-	USED(addr);
-}
-
blob - 11b218145a2361146d8dc1e4c54a83955435aac7 (mode 644)
blob + /dev/null
--- src/libthread/sysofiles.sh
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh
-
-case "`uname`-`uname -r`" in
-Linux-2.[01234]*)
-	echo Linux-clone.o ucontext.o
-	exit 0
-	;;
-esac
-
-echo pthread.o ucontext.o
-exit 0
blob - c9682e35d7d1035174554824dc570b5032cf36e6 (mode 644)
blob + /dev/null
--- src/libthread/texec.c
+++ /dev/null
@@ -1,45 +0,0 @@
-#include <lib9.h>
-#include <thread.h>
-extern int _threaddebuglevel;
-
-void
-doexec(void *v)
-{
-	int fd[3];
-	char **argv = v;
-
-	fd[0] = dup(0, -1);
-	fd[1] = dup(1, -1);
-	fd[2] = dup(2, -1);
-	threadexec(nil, fd, argv[0], argv);
-	print("exec failed: %r\n");
-	sendp(threadwaitchan(), nil);
-	threadexits(nil);
-}
-
-void
-threadmain(int argc, char **argv)
-{
-	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();
-	mk(doexec, argv, 8192);
-	w = recvp(c);
-	if(w == nil)
-		print("exec/recvp failed: %r\n");
-	else
-		print("%d %lud %lud %lud %s\n", w->pid, w->time[0], w->time[1], w->time[2], w->msg);
-	threadexits(nil);
-}
blob - 0cbb4be93fd1d700622e04cd7762fe66eec5c251 (mode 644)
blob + /dev/null
--- src/libthread/tfork.c
+++ /dev/null
@@ -1,23 +0,0 @@
-#include <u.h>
-#include <libc.h>
-#include <thread.h>
-
-Channel *c;
-
-void
-f(void *v)
-{
-	recvp(c);
-}
-
-void
-threadmain(int argc, char **argv)
-{
-	int i;
-
-	c = chancreate(sizeof(ulong), 0);
-	for(i=0;; i++){
-		print("%d\n", i);
-		proccreate(f, nil, 8192);
-	}
-}
blob - 818b509febf47f393f0e2aed2b71f6ce5ae1113d (mode 644)
blob + /dev/null
--- src/libthread/thread.sh
+++ /dev/null
@@ -1,15 +0,0 @@
-#!/bin/sh
-
-if [ `uname` = Linux ]
-then
-	case `uname -r` in
-	2.[6789]*)
-		echo pthread
-		;;
-	*)
-		echo Linux-clone
-		;;
-	esac
-else
-	echo pthread
-fi
blob - 0ad4568e19e705ead79233b0c96045b19b7fda75 (mode 644)
blob + /dev/null
--- src/libthread/threadimpl.h
+++ /dev/null
@@ -1,241 +0,0 @@
-/* 
- * Some notes on locking:
- *
- *	All the locking woes come from implementing
- *	threadinterrupt (and threadkill).
- *
- *	_threadgetproc()->thread is always a live pointer.
- *	p->threads, p->ready, and _threadrgrp also contain
- * 	live thread pointers.  These may only be consulted
- *	while holding p->lock; in procs other than p, the
- *	pointers are only guaranteed to be live while the lock
- *	is still being held.
- *
- *	Thread structures can only be freed by the proc
- *	they belong to.  Threads marked with t->inrendez
- * 	need to be extracted from the _threadrgrp before
- *	being freed.
- */
-
-#include <u.h>
-#include <assert.h>
-#include <libc.h>
-#include <thread.h>
-#include "label.h"
-
-typedef struct Thread	Thread;
-typedef struct Proc		Proc;
-typedef struct Tqueue	Tqueue;
-typedef struct Pqueue	Pqueue;
-typedef struct Execargs	Execargs;
-typedef struct Jmp Jmp;
-
-/* sync with ../lib9/notify.c */
-struct Jmp
-{
-	p9jmp_buf b;
-};
-
-
-typedef enum
-{
-	Dead,
-	Running,
-	Ready,
-	Rendezvous,
-} State;
-	
-typedef enum
-{
-	Channone,
-	Chanalt,
-	Chansend,
-	Chanrecv,
-} Chanstate;
-
-enum
-{
-	NPRIV = 8,
-};
-
-struct Tqueue		/* Thread queue */
-{
-	int		asleep;
-	Thread	*head;
-	Thread	*tail;
-};
-
-struct Pqueue {		/* Proc queue */
-	Lock		lock;
-	Proc		*head;
-	Proc		**tail;
-};
-
-struct Thread
-{
-	Lock		lock;			/* protects thread data structure */
-
-	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 */
-	int		ret;			/* return value for Exec, Fork */
-	State		state;		/* run state */
-	uchar	*stk;			/* top of stack (lowest address of stack) */
-	uint		stksize;		/* stack size */
-	void*	udata[NPRIV];	/* User per-thread data pointer */
-
-	/*
-	 * for debugging only
-	 * (could go away without impacting correct behavior):
-	 */
-
-	Channel	*altc;
-	_Procrend	altrend;
-
-	Chanstate	chan;		/* which channel operation is current */
-	Alt		*alt;			/* pointer to current alt structure (debugging) */
-	ulong		userpc;
-	Channel	*c;
-
-};
-
-struct Execargs
-{
-	char		*prog;
-	char		**args;
-	int		fd[2];
-	int		*stdfd;
-};
-
-struct Proc
-{
-	Lock		lock;
-
-	Label	context;		/* for context switches */
-	Proc		*link;		/* in ptab */
-	int		splhi;		/* delay notes */
-	Thread	*thread;		/* running thread */
-	Thread	*idle;			/* idle thread */
-	int		id;
-	int		procid;
-
-	int		needexec;
-	Execargs	exec;		/* exec argument */
-	Proc		*newproc;	/* fork argument */
-	char		exitstr[ERRMAX];	/* exit status */
-
-	int		internal;
-	int		rforkflag;
-	int		nthreads;
-	Tqueue	threads;		/* All threads of this proc */
-	Tqueue	ready;		/* Runnable threads */
-	Lock		readylock;
-
-	int		blocked;		/* In a rendezvous */
-	int		pending;		/* delayed note pending */
-	int		nonotes;		/*  delay notes */
-	uint		nextID;		/* ID of most recently created thread */
-	Proc		*next;		/* linked list of Procs */
-
-	Jmp		sigjmp;		/* for notify implementation */
-
-	void		(*schedfn)(Proc*);	/* function to call in scheduler */
-
-	_Procrend	rend;	/* sleep here for more ready threads */
-
-	void		*arg;			/* passed between shared and unshared stk */
-	char		str[ERRMAX];	/* used by threadexits to avoid malloc */
-	char		errbuf[ERRMAX];	/* errstr */
-	Waitmsg		*waitmsg;
-
-	void*	udata;		/* User per-proc data pointer */
-	int		nsched;
-
-	/*
-	 * for debugging only
-	 */
-	int		pid;			/* process id */
-	int		pthreadid;		/* pthread id */
-};
-
-void		_swaplabel(Label*, Label*);
-Proc*	_newproc(void);
-int		_newthread(Proc*, void(*)(void*), void*, uint, char*, int);
-int		_sched(void);
-int		_schedexec(Execargs*);
-void		_schedexecwait(void);
-void		_schedexit(Proc*);
-int		_schedfork(Proc*);
-void		_threadfree(Thread*);
-void		_threadscheduler(void*);
-void		_systhreadinit(void);
-void		_threadassert(char*);
-void		__threaddebug(ulong, char*, ...);
-#define _threaddebug if(!_threaddebuglevel){}else __threaddebug
-void		_threadexitsall(char*);
-Proc*	_threadgetproc(void);
-extern void	_threadmultiproc(void);
-Proc*	_threaddelproc(void);
-void		_kthreadinitproc(Proc*);
-void		_threadsetproc(Proc*);
-void		_threadinitstack(Thread*, void(*)(void*), void*);
-void		_threadlinkmain(void);
-void*	_threadmalloc(long, int);
-void		_threadnote(void*, char*);
-void		_threadready(Thread*);
-void		_threadschednote(void);
-void		_threadsetidle(int);
-void		_threadsleep(_Procrend*);
-void		_threadwakeup(_Procrend*);
-void		_threadsignal(void);
-void		_threadsysfatal(char*, va_list);
-long		_xdec(long*);
-void		_xinc(long*);
-void		_threadremove(Proc*, Thread*);
-void		threadstatus(void);
-void		_threadefork(int[3], int[2], char*, char**);
-Jmp*		_threadgetjmp(void);
-void		_kthreadinit(void);
-void		_kthreadsetproc(Proc*);
-Proc*	_kthreadgetproc(void);
-void		_kthreadstartproc(Proc*);
-void		_kthreadexitproc(char*);
-void		_kthreadexitallproc(char*);
-void		_threadinternalproc(void);
-void		_threadbackgroundinit(void);
-void		_kmaininit(void);
-
-extern int			_threadnprocs;
-extern int			_threaddebuglevel;
-extern char*		_threadexitsallstatus;
-extern Pqueue		_threadpq;
-extern Channel*	_threadwaitchan;
-
-#define DBGAPPL	(1 << 0)
-#define DBGSCHED	(1 << 16)
-#define DBGCHAN	(1 << 17)
-#define DBGREND	(1 << 18)
-/* #define DBGKILL	(1 << 19) */
-#define DBGNOTE	(1 << 20)
-#define DBGEXEC	(1 << 21)
-
-extern void _threadmemset(void*, int, int);
-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 _threadmaininit(void);
-extern int _threadexec(Channel*, int[3], char*, char*[], int);
-extern int _kthreadexec(Channel*, int[3], char*, char*[], int);
blob - 89d30c0366bfb446f129c129948df9b8561af677 (mode 644)
blob + /dev/null
--- src/libthread/tprimes.c
+++ /dev/null
@@ -1,68 +0,0 @@
-#include <u.h>
-#include <libc.h>
-#include <thread.h>
-
-enum
-{
-	STACK = 8192
-};
-
-int quiet;
-int goal;
-int buffer;
-int (*fn)(void(*)(void*), void*, uint) = threadcreate;
-
-void
-primethread(void *arg)
-{
-	Channel *c, *nc;
-	int p, i;
-
-	c = arg;
-	p = recvul(c);
-	if(p > goal)
-		threadexitsall(nil);
-	if(!quiet)
-		print("%d\n", p);
-	nc = chancreate(sizeof(ulong), buffer);
-	(*fn)(primethread, nc, STACK);
-	for(;;){
-		i = recvul(c);
-		if(i%p)
-			sendul(nc, i);
-	}
-}
-
-extern int _threaddebuglevel;
-
-void
-threadmain(int argc, char **argv)
-{
-	int i;
-	Channel *c;
-
-	ARGBEGIN{
-	case 'D':
-		_threaddebuglevel = atoi(ARGF());
-		break;
-	case 'q':
-		quiet = 1;
-		break;
-	case 'b':
-		buffer = atoi(ARGF());
-		break;
-	case 'p':
-		fn = proccreate;
-		break;
-	}ARGEND
-
-	if(argc>0)
-		goal = atoi(argv[0]);
-	else
-		goal = 100;
-
-	c = chancreate(sizeof(ulong), buffer);
-	(*fn)(primethread, c, STACK);
-	for(i=2;; i++)
-		sendul(c, i);
-}
blob - 1ccf1a7968f29bc5c94e3923546c9b30036d7767 (mode 644)
blob + /dev/null
--- src/libthread/trend.c
+++ /dev/null
@@ -1,31 +0,0 @@
-#include <lib9.h>
-#include <thread.h>
-
-Channel *c[3];
-
-
-void
-pingpong(void *v)
-{
-	int n;
-	Channel **c;
-
-	c = v;
-	do{
-		n = recvul(c[0]);
-		sendul(c[1], n-1);
-	}while(n > 0);
-	exit(0);
-}
-
-void
-threadmain(int argc, char **argv)
-{
-	c[0] = chancreate(sizeof(ulong), 1);
-	c[1] = chancreate(sizeof(ulong), 1);
-	c[2] = c[0];
-
-	proccreate(pingpong, c, 16384);
-	threadcreate(pingpong, c+1, 16384);
-	sendul(c[0], atoi(argv[1]));
-}
blob - 9c64c46bd39eb5ee3d1dfe5dc8c9fc5d58742cdb (mode 644)
blob + /dev/null
--- src/libthread/tsignal.c
+++ /dev/null
@@ -1,43 +0,0 @@
-#include <u.h>
-#include <libc.h>
-#include <thread.h>
-
-extern int _threaddebuglevel;
-
-void
-usage(void)
-{
-	fprint(2, "usage: tsignal [-[ednf] note]*\n");
-	threadexitsall("usage");
-}
-
-void
-threadmain(int argc, char **argv)
-{
-	Channel *c;
-	char *msg;
-
-	ARGBEGIN{
-	case 'D':
-		_threaddebuglevel = ~0;
-		break;
-	default:
-		usage();
-	case 'e':
-		notifyenable(EARGF(usage()));
-		break;
-	case 'd':
-		notifydisable(EARGF(usage()));
-		break;
-	case 'n':
-		notifyon(EARGF(usage()));
-		break;
-	case 'f':
-		notifyoff(EARGF(usage()));
-		break;
-	}ARGEND
-
-	c = threadnotechan();
-	while((msg = recvp(c)) != nil)
-		print("note: %s\n", msg);
-}
blob - 97962c5daacd890fe09f8630dea07c224d1f24e5 (mode 644)
blob + /dev/null
--- src/libthread/tspawn.c
+++ /dev/null
@@ -1,41 +0,0 @@
-#include <lib9.h>
-#include <thread.h>
-extern int _threaddebuglevel;
-
-void
-doexec(void *v)
-{
-	int fd[3];
-	char **argv = v;
-
-	print("exec failed: %r\n");
-	sendp(threadwaitchan(), nil);
-	threadexits(nil);
-}
-
-void
-threadmain(int argc, char **argv)
-{
-	int fd[3];
-	Channel *c;
-	Waitmsg *w;
-
-	ARGBEGIN{
-	case 'D':
-		_threaddebuglevel = ~0;
-		break;
-	}ARGEND
-
-	c = threadwaitchan();
-	fd[0] = dup(0, -1);
-	fd[1] = dup(1, -1);
-	fd[2] = dup(2, -1);
-	if(threadspawn(fd, argv[0], argv) < 0)
-		sysfatal("threadspawn: %r");
-	w = recvp(c);
-	if(w == nil)
-		print("exec/recvp failed: %r\n");
-	else
-		print("%d %lud %lud %lud %s\n", w->pid, w->time[0], w->time[1], w->time[2], w->msg);
-	threadexits(nil);
-}
blob - 98e92ccfa727fddc1d6f6207bd226c435f505a96 (mode 644)
blob + /dev/null
--- src/libthread/ucontext.c
+++ /dev/null
@@ -1,49 +0,0 @@
-#include "threadimpl.h"
-
-static void
-launcher(void (*f)(void*), void *arg)
-{
-	f(arg);
-	threadexits(nil);
-}
-
-void
-_threadinitstack(Thread *t, void (*f)(void*), void *arg)
-{
-	sigset_t zero;
-
-	/* do a reasonable initialization */
-	memset(&t->context.uc, 0, sizeof t->context.uc);
-	sigemptyset(&zero);
-	sigprocmask(SIG_BLOCK, &zero, &t->context.uc.uc_sigmask);
-
-	/* call getcontext, because on Linux makecontext neglects floating point */
-	getcontext(&t->context.uc);
-
-	/* call makecontext to do the real work. */
-	/* leave a few words open on both ends */
-	t->context.uc.uc_stack.ss_sp = t->stk+8;
-	t->context.uc.uc_stack.ss_size = t->stksize-16;
-	makecontext(&t->context.uc, (void(*)())launcher, 2, f, arg);
-}
-
-void
-_threadinswitch(int enter)
-{
-	USED(enter);
-}
-
-void
-_threadstacklimit(void *bottom, void *top)
-{
-	USED(bottom);
-	USED(top);
-}
-
-void
-_swaplabel(Label *old, Label *new)
-{
-	if(swapcontext(&old->uc, &new->uc) < 0)
-		sysfatal("swapcontext: %r");
-}
-