Commit Diff


commit - c181e39eeab0eb8cad274b7b22ce5343bd55630d
commit + 8d82ccefd2b4b058e20ae0a7e3d9ef9b6b8cf8c3
blob - 197f12b54d646eb2eaf297eaacfe923aec2b9a43 (mode 644)
blob + /dev/null
--- src/libthread/Linux-386-asm.s
+++ /dev/null
@@ -1,7 +0,0 @@
-.globl _tas
-_tas:
-	movl $0xCAFEBABE, %eax
-	movl 4(%esp), %ecx
-	xchgl %eax, 0(%ecx)
-	ret
-
blob - 721ea43b5e9b8c3569a13825f5a8510b3b01c47e (mode 644)
blob + /dev/null
--- src/libthread/Linux-arm-asm.s
+++ /dev/null
@@ -1,10 +0,0 @@
- 
-.globl _tas
-_tas:
-	mov	r3, #0xCA000000
-	add	r3, r3, #0xFE0000
-	add	r3, r3, #0xBA00
-	add	r3, r3, #0xBE
-	swp	r3, r3, [r0]
-	mov	r0, r3
-	mov	pc, lr
blob - d6e21c157b50a515a08e33e31a949dafa41e08a2 (mode 644)
blob + /dev/null
--- src/libthread/Linux-power-asm.s
+++ /dev/null
@@ -1,16 +0,0 @@
-	.globl	_tas
-_tas:
-	li	%r0, 0
-	mr	%r4, %r3
-	lis	%r5, 0xcafe
-	ori	%r5, %r5, 0xbabe
-1:
-	lwarx	%r3, %r0, %r4
-	cmpwi	%r3, 0
-	bne	2f
-	stwcx.	%r5, %r0, %r4
-	bne-	1b
-2:
-	sync
-	blr
-
blob - 422a1b244b8895849f71086bb85a5a00cd648655 (mode 644)
blob + /dev/null
--- src/libthread/Linux-sparc64-asm.s
+++ /dev/null
@@ -1,16 +0,0 @@
-! Actually sparc32 assembly. 
-! Debian's sparc64 port is a 32-bit user space.
-
-	.section	".text", #alloc, #execinstr
-	.align		8
-	.skip		16
-	.global _tas
-!	.type	_tas,2
-_tas:
-	or	%g0,1,%o1
-	swap	[%o0],%o1	! o0 points to lock; key is first word
-	retl
-	mov	%o1, %o0
-
-   	.size	_tas,(.-_tas)
-
blob - 31577e876dc7be7d2c6d59e67e02887eadf5c25c (mode 644)
blob + /dev/null
--- src/libthread/Linux.c
+++ /dev/null
@@ -1,462 +0,0 @@
-#include "threadimpl.h"
-
-#undef exits
-#undef _exits
-
-static int
-timefmt(Fmt *fmt)
-{
-	static char *mon[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
-		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
-	vlong ns;
-	Tm tm;
-	ns = nsec();
-	tm = *localtime(time(0));
-	return fmtprint(fmt, "%s %2d %02d:%02d:%02d.%03d",
-		mon[tm.mon], tm.mday, tm.hour, tm.min, tm.sec,
-		(int)(ns%1000000000)/1000000);
-}
-
-/*
- * spin locks
- */
-extern int _tas(int*);
-
-void
-_threadunlock(Lock *l, ulong pc)
-{
-	USED(pc);
-
-	l->held = 0;
-}
-
-int
-_threadlock(Lock *l, int block, ulong pc)
-{
-	int i;
-static int first=1;
-if(first) {first=0; fmtinstall('\001', timefmt);}
-
-	USED(pc);
-
-	/* once fast */
-	if(!_tas(&l->held))
-		return 1;
-	if(!block)
-		return 0;
-
-	/* a thousand times pretty fast */
-	for(i=0; i<1000; i++){
-		if(!_tas(&l->held))
-			return 1;
-		sched_yield();
-	}
-	/* now increasingly slow */
-	for(i=0; i<10; i++){
-		if(!_tas(&l->held))
-			return 1;
-		usleep(1);
-	}
-fprint(2, "%\001 %s: lock loop1 %p from %lux\n", argv0, l, pc);
-	for(i=0; i<10; i++){
-		if(!_tas(&l->held))
-			return 1;
-		usleep(10);
-	}
-fprint(2, "%\001 %s: lock loop2 %p from %lux\n", argv0, l, pc);
-	for(i=0; i<10; i++){
-		if(!_tas(&l->held))
-			return 1;
-		usleep(100);
-	}
-fprint(2, "%\001 %s: lock loop3 %p from %lux\n", argv0, l, pc);
-	for(i=0; i<10; i++){
-		if(!_tas(&l->held))
-			return 1;
-		usleep(1000);
-	}
-fprint(2, "%\001 %s: lock loop4 %p from %lux\n", argv0, l, pc);
-	for(i=0; i<10; i++){
-		if(!_tas(&l->held))
-			return 1;
-		usleep(10*1000);
-	}
-fprint(2, "%\001 %s: lock loop5 %p from %lux\n", argv0, l, pc);
-	for(i=0; i<1000; i++){
-		if(!_tas(&l->held))
-			return 1;
-		usleep(100*1000);
-	}
-fprint(2, "%\001 %s: lock loop6 %p from %lux\n", argv0, l, pc);
-	/* take your time */
-	while(_tas(&l->held))
-		usleep(1000*1000);
-	return 1;
-}
-
-/*
- * sleep and wakeup
- */
-static void
-ign(int x)
-{
-	USED(x);
-}
-
-static void /*__attribute__((constructor))*/
-ignusr1(int restart)
-{
-	struct sigaction sa;
-
-	memset(&sa, 0, sizeof sa);
-	sa.sa_handler = ign;
-	sigemptyset(&sa.sa_mask);
-	sigaddset(&sa.sa_mask, SIGUSR1);
-	if(restart)
-		sa.sa_flags = SA_RESTART;
-	sigaction(SIGUSR1, &sa, nil);
-}
-
-void
-_procsleep(_Procrendez *r)
-{
-	sigset_t mask;
-
-	/*
-	 * Go to sleep.
-	 *
-	 * Block USR1, set the handler to interrupt system calls,
-	 * unlock the vouslock so our waker can wake us,
-	 * and then suspend.
-	 */
-again:
-	r->asleep = 1;
-	r->pid = getpid();
-
-	sigprocmask(SIG_SETMASK, nil, &mask);
-	sigaddset(&mask, SIGUSR1);
-	sigprocmask(SIG_SETMASK, &mask, nil);
-	ignusr1(0);
-	unlock(r->l);
-	sigdelset(&mask, SIGUSR1);
-	sigsuspend(&mask);
-
-	/*
-	 * We're awake.  Make USR1 not interrupt system calls.
-	 */
-	lock(r->l);
-	ignusr1(1);
-	if(r->asleep && r->pid == getpid()){
-		/* Didn't really wake up - signal from something else */
-		goto again;
-	}
-}
-
-void
-_procwakeupandunlock(_Procrendez *r)
-{
-	int pid;
-
-	pid = 0;
-	if(r->asleep){
-		r->asleep = 0;
-		assert(r->pid >= 1);
-		pid = r->pid;
-	}
-	assert(r->l);
-	unlock(r->l);
-	if(pid)
-		kill(pid, SIGUSR1);
-}
-
-/*
- * process creation and exit
- */
-typedef struct Stackfree Stackfree;
-struct Stackfree
-{
-	Stackfree	*next;
-	int	pid;
-	int	pid1;
-};
-static Lock stacklock;
-static Stackfree *stackfree;
-
-static void
-delayfreestack(uchar *stk, int pid, int pid1)
-{
-	Stackfree *sf;
-
-	sf = (Stackfree*)stk;
-	sf->pid = pid;
-	sf->pid1 = pid1;
-	lock(&stacklock);
-	sf->next = stackfree;
-	stackfree = sf;
-	unlock(&stacklock);
-}
-
-static void
-dofreestacks(void)
-{
-	Stackfree *sf, *last, *next;
-
-	if(stackfree==nil || !canlock(&stacklock))
-		return;
-
-	for(last=nil,sf=stackfree; sf; last=sf,sf=next){
-		next = sf->next;
-		if(sf->pid >= 1 && kill(sf->pid, 0) < 0 && errno == ESRCH)
-		if(sf->pid1 >= 1 && kill(sf->pid1, 0) < 0 && errno == ESRCH){
-			free(sf);
-			if(last)
-				last->next = next;
-			else
-				stackfree = next;
-			sf = last;
-		}
-	}
-	unlock(&stacklock);
-}
-
-static int
-startprocfn(void *v)
-{
-	void **a;
-	uchar *stk;
-	void (*fn)(void*);
-	Proc *p;
-	int pid0, pid1;
-
-	a = (void**)v;
-	fn = a[0];
-	p = a[1];
-	stk = a[2];
-	pid0 = (int)a[4];
-	pid1 = getpid();
-	free(a);
-	p->osprocid = pid1;
-
-	(*fn)(p);
-
-	delayfreestack(stk, pid0, pid1);
-	_exit(0);
-	return 0;
-}
-
-/*
- * indirect through here so that parent need not wait for child zombie
- *
- * slight race - if child exits and then another process starts before we
- * manage to exit, we'll be running on a freed stack.
- */
-static int
-trampnowait(void *v)
-{
-	void **a;
-	int *kidpid;
-
-	a = (void*)v;
-	kidpid = a[3];
-	a[4] = (void*)getpid();
-	*kidpid = clone(startprocfn, a[2]+65536-512, CLONE_VM|CLONE_FILES, a);
-	_exit(0);
-	return 0;
-}
-
-void
-_procstart(Proc *p, void (*fn)(Proc*))
-{
-	void **a;
-	uchar *stk;
-	int pid, kidpid, status;
-
-	dofreestacks();
-	a = malloc(5*sizeof a[0]);
-	if(a == nil)
-		sysfatal("_procstart malloc: %r");
-	stk = malloc(65536);
-	if(stk == nil)
-		sysfatal("_procstart malloc stack: %r");
-
-	a[0] = fn;
-	a[1] = p;
-	a[2] = stk;
-	a[3] = &kidpid;
-	kidpid = -1;
-
-	pid = clone(trampnowait, stk+65536-16, CLONE_VM|CLONE_FILES, a);
-	if(pid > 0)
-		if(wait4(pid, &status, __WALL, 0) < 0)
-			fprint(2, "ffork wait4: %r\n");
-	if(pid < 0 || kidpid < 0){
-		fprint(2, "_procstart clone: %r\n");
-		abort();
-	}
-}
-
-static char *threadexitsmsg;
-void
-sigusr2handler(int s)
-{
-/*	fprint(2, "%d usr2 %d\n", time(0), getpid()); */
-	if(threadexitsmsg)
-		_exits(threadexitsmsg);
-}
-
-void
-threadexitsall(char *msg)
-{
-	static int pid[1024];
-	int i, npid, mypid;
-	Proc *p;
-
-	if(msg == nil)
-		msg = "";
-
-	/*
-	 * Only one guy, ever, gets to run this.
-	 * If two guys do it, inevitably they end up
-	 * tripping over each other in the underlying
-	 * C library exit() implementation, which is
-	 * trying to run the atexit handlers and apparently
-	 * not thread safe.  This has been observed on
-	 * both Linux and OpenBSD.  Sigh.
-	 */
-	{
-		static Lock onelock;
-		if(!canlock(&onelock))
-			_exits(threadexitsmsg);
-		threadexitsmsg = msg;
-	}
-
-	mypid = getpid();
-	lock(&_threadprocslock);
-	npid = 0;
-	for(p=_threadprocs; p; p=p->next)
-		if(p->osprocid != mypid && p->osprocid >= 1)
-			pid[npid++] = p->osprocid;
-	for(i=0; i<npid; i++)
-		kill(pid[i], SIGUSR2);
-	unlock(&_threadprocslock);
-	exits(msg);
-}
-
-/*
- * per-process data, indexed by pid
- *
- * could use modify_ldt and a segment register
- * to avoid the many calls to getpid(), but i don't
- * care -- this is compatibility code.  linux 2.6 with
- * nptl is a good enough pthreads to avoid this whole file.
- */
-typedef struct Perproc Perproc;
-struct Perproc
-{
-	int		pid;
-	Proc	*proc;
-};
-
-static Lock perlock;
-static Perproc perproc[1024];
-#define P ((Proc*)-1)
-
-static Perproc*
-myperproc(void)
-{
-	int i, pid, h;
-	Perproc *p;
-
-	pid = getpid();
-	h = pid%nelem(perproc);
-	for(i=0; i<nelem(perproc); i++){
-		p = &perproc[(i+h)%nelem(perproc)];
-		if(p->pid == pid)
-			return p;
-		if(p->pid == 0){
-			print("found 0 at %d (h=%d)\n", (i+h)%nelem(perproc), h);
-			break;
-		}
-	}
-	fprint(2, "myperproc %d (%s): cannot find self\n", pid, argv0);
-	abort();
-	return nil;
-}
-
-static Perproc*
-newperproc(void)
-{
-	int i, pid, h;
-	Perproc *p;
-
-	lock(&perlock);
-	pid = getpid();
-	h = pid%nelem(perproc);
-	for(i=0; i<nelem(perproc); i++){
-		p = &perproc[(i+h)%nelem(perproc)];
-		if(p->pid == pid || p->pid == -1 || p->pid == 0){
-			p->pid = pid;
-			unlock(&perlock);
-			return p;
-		}
-	}
-	fprint(2, "newperproc %d: out of procs\n", pid);
-	abort();
-	return nil;
-}
-
-Proc*
-_threadproc(void)
-{
-	return myperproc()->proc;
-}
-
-void
-_threadsetproc(Proc *p)
-{
-	Perproc *pp;
-
-	if(p)
-		p->osprocid = getpid();
-	pp = newperproc();
-	pp->proc = p;
-	if(p == nil)
-		pp->pid = -1;
-}
-
-void
-_pthreadinit(void)
-{
-	signal(SIGUSR2, sigusr2handler);
-}
-
-void
-_threadpexit(void)
-{
-	_exit(0);
-}
-
-#ifdef __arm__
-void
-makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...)
-{
-	int i, *sp;
-	va_list arg;
-
-	sp = (int*)uc->uc_stack.ss_sp+uc->uc_stack.ss_size/4;
-	va_start(arg, argc);
-	for(i=0; i<4 && i<argc; i++)
-		uc->uc_mcontext.gregs[i] = va_arg(arg, uint);
-	va_end(arg);
-	uc->uc_mcontext.gregs[13] = (uint)sp;
-	uc->uc_mcontext.gregs[14] = (uint)fn;
-}
-
-int
-swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
-{
-	if(getcontext(oucp) == 0)
-		setcontext(ucp);
-	return 0;
-}
-#endif
blob - 37dabe9c909f047f45cd39c8daf9ec699061528c
blob + 31577e876dc7be7d2c6d59e67e02887eadf5c25c
--- src/libthread/NetBSD.c
+++ src/libthread/NetBSD.c
@@ -1 +1,462 @@
-#include "Linux.c"
+#include "threadimpl.h"
+
+#undef exits
+#undef _exits
+
+static int
+timefmt(Fmt *fmt)
+{
+	static char *mon[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+		"Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+	vlong ns;
+	Tm tm;
+	ns = nsec();
+	tm = *localtime(time(0));
+	return fmtprint(fmt, "%s %2d %02d:%02d:%02d.%03d",
+		mon[tm.mon], tm.mday, tm.hour, tm.min, tm.sec,
+		(int)(ns%1000000000)/1000000);
+}
+
+/*
+ * spin locks
+ */
+extern int _tas(int*);
+
+void
+_threadunlock(Lock *l, ulong pc)
+{
+	USED(pc);
+
+	l->held = 0;
+}
+
+int
+_threadlock(Lock *l, int block, ulong pc)
+{
+	int i;
+static int first=1;
+if(first) {first=0; fmtinstall('\001', timefmt);}
+
+	USED(pc);
+
+	/* once fast */
+	if(!_tas(&l->held))
+		return 1;
+	if(!block)
+		return 0;
+
+	/* a thousand times pretty fast */
+	for(i=0; i<1000; i++){
+		if(!_tas(&l->held))
+			return 1;
+		sched_yield();
+	}
+	/* now increasingly slow */
+	for(i=0; i<10; i++){
+		if(!_tas(&l->held))
+			return 1;
+		usleep(1);
+	}
+fprint(2, "%\001 %s: lock loop1 %p from %lux\n", argv0, l, pc);
+	for(i=0; i<10; i++){
+		if(!_tas(&l->held))
+			return 1;
+		usleep(10);
+	}
+fprint(2, "%\001 %s: lock loop2 %p from %lux\n", argv0, l, pc);
+	for(i=0; i<10; i++){
+		if(!_tas(&l->held))
+			return 1;
+		usleep(100);
+	}
+fprint(2, "%\001 %s: lock loop3 %p from %lux\n", argv0, l, pc);
+	for(i=0; i<10; i++){
+		if(!_tas(&l->held))
+			return 1;
+		usleep(1000);
+	}
+fprint(2, "%\001 %s: lock loop4 %p from %lux\n", argv0, l, pc);
+	for(i=0; i<10; i++){
+		if(!_tas(&l->held))
+			return 1;
+		usleep(10*1000);
+	}
+fprint(2, "%\001 %s: lock loop5 %p from %lux\n", argv0, l, pc);
+	for(i=0; i<1000; i++){
+		if(!_tas(&l->held))
+			return 1;
+		usleep(100*1000);
+	}
+fprint(2, "%\001 %s: lock loop6 %p from %lux\n", argv0, l, pc);
+	/* take your time */
+	while(_tas(&l->held))
+		usleep(1000*1000);
+	return 1;
+}
+
+/*
+ * sleep and wakeup
+ */
+static void
+ign(int x)
+{
+	USED(x);
+}
+
+static void /*__attribute__((constructor))*/
+ignusr1(int restart)
+{
+	struct sigaction sa;
+
+	memset(&sa, 0, sizeof sa);
+	sa.sa_handler = ign;
+	sigemptyset(&sa.sa_mask);
+	sigaddset(&sa.sa_mask, SIGUSR1);
+	if(restart)
+		sa.sa_flags = SA_RESTART;
+	sigaction(SIGUSR1, &sa, nil);
+}
+
+void
+_procsleep(_Procrendez *r)
+{
+	sigset_t mask;
+
+	/*
+	 * Go to sleep.
+	 *
+	 * Block USR1, set the handler to interrupt system calls,
+	 * unlock the vouslock so our waker can wake us,
+	 * and then suspend.
+	 */
+again:
+	r->asleep = 1;
+	r->pid = getpid();
+
+	sigprocmask(SIG_SETMASK, nil, &mask);
+	sigaddset(&mask, SIGUSR1);
+	sigprocmask(SIG_SETMASK, &mask, nil);
+	ignusr1(0);
+	unlock(r->l);
+	sigdelset(&mask, SIGUSR1);
+	sigsuspend(&mask);
+
+	/*
+	 * We're awake.  Make USR1 not interrupt system calls.
+	 */
+	lock(r->l);
+	ignusr1(1);
+	if(r->asleep && r->pid == getpid()){
+		/* Didn't really wake up - signal from something else */
+		goto again;
+	}
+}
+
+void
+_procwakeupandunlock(_Procrendez *r)
+{
+	int pid;
+
+	pid = 0;
+	if(r->asleep){
+		r->asleep = 0;
+		assert(r->pid >= 1);
+		pid = r->pid;
+	}
+	assert(r->l);
+	unlock(r->l);
+	if(pid)
+		kill(pid, SIGUSR1);
+}
+
+/*
+ * process creation and exit
+ */
+typedef struct Stackfree Stackfree;
+struct Stackfree
+{
+	Stackfree	*next;
+	int	pid;
+	int	pid1;
+};
+static Lock stacklock;
+static Stackfree *stackfree;
+
+static void
+delayfreestack(uchar *stk, int pid, int pid1)
+{
+	Stackfree *sf;
+
+	sf = (Stackfree*)stk;
+	sf->pid = pid;
+	sf->pid1 = pid1;
+	lock(&stacklock);
+	sf->next = stackfree;
+	stackfree = sf;
+	unlock(&stacklock);
+}
+
+static void
+dofreestacks(void)
+{
+	Stackfree *sf, *last, *next;
+
+	if(stackfree==nil || !canlock(&stacklock))
+		return;
+
+	for(last=nil,sf=stackfree; sf; last=sf,sf=next){
+		next = sf->next;
+		if(sf->pid >= 1 && kill(sf->pid, 0) < 0 && errno == ESRCH)
+		if(sf->pid1 >= 1 && kill(sf->pid1, 0) < 0 && errno == ESRCH){
+			free(sf);
+			if(last)
+				last->next = next;
+			else
+				stackfree = next;
+			sf = last;
+		}
+	}
+	unlock(&stacklock);
+}
+
+static int
+startprocfn(void *v)
+{
+	void **a;
+	uchar *stk;
+	void (*fn)(void*);
+	Proc *p;
+	int pid0, pid1;
+
+	a = (void**)v;
+	fn = a[0];
+	p = a[1];
+	stk = a[2];
+	pid0 = (int)a[4];
+	pid1 = getpid();
+	free(a);
+	p->osprocid = pid1;
+
+	(*fn)(p);
+
+	delayfreestack(stk, pid0, pid1);
+	_exit(0);
+	return 0;
+}
+
+/*
+ * indirect through here so that parent need not wait for child zombie
+ *
+ * slight race - if child exits and then another process starts before we
+ * manage to exit, we'll be running on a freed stack.
+ */
+static int
+trampnowait(void *v)
+{
+	void **a;
+	int *kidpid;
+
+	a = (void*)v;
+	kidpid = a[3];
+	a[4] = (void*)getpid();
+	*kidpid = clone(startprocfn, a[2]+65536-512, CLONE_VM|CLONE_FILES, a);
+	_exit(0);
+	return 0;
+}
+
+void
+_procstart(Proc *p, void (*fn)(Proc*))
+{
+	void **a;
+	uchar *stk;
+	int pid, kidpid, status;
+
+	dofreestacks();
+	a = malloc(5*sizeof a[0]);
+	if(a == nil)
+		sysfatal("_procstart malloc: %r");
+	stk = malloc(65536);
+	if(stk == nil)
+		sysfatal("_procstart malloc stack: %r");
+
+	a[0] = fn;
+	a[1] = p;
+	a[2] = stk;
+	a[3] = &kidpid;
+	kidpid = -1;
+
+	pid = clone(trampnowait, stk+65536-16, CLONE_VM|CLONE_FILES, a);
+	if(pid > 0)
+		if(wait4(pid, &status, __WALL, 0) < 0)
+			fprint(2, "ffork wait4: %r\n");
+	if(pid < 0 || kidpid < 0){
+		fprint(2, "_procstart clone: %r\n");
+		abort();
+	}
+}
+
+static char *threadexitsmsg;
+void
+sigusr2handler(int s)
+{
+/*	fprint(2, "%d usr2 %d\n", time(0), getpid()); */
+	if(threadexitsmsg)
+		_exits(threadexitsmsg);
+}
+
+void
+threadexitsall(char *msg)
+{
+	static int pid[1024];
+	int i, npid, mypid;
+	Proc *p;
+
+	if(msg == nil)
+		msg = "";
+
+	/*
+	 * Only one guy, ever, gets to run this.
+	 * If two guys do it, inevitably they end up
+	 * tripping over each other in the underlying
+	 * C library exit() implementation, which is
+	 * trying to run the atexit handlers and apparently
+	 * not thread safe.  This has been observed on
+	 * both Linux and OpenBSD.  Sigh.
+	 */
+	{
+		static Lock onelock;
+		if(!canlock(&onelock))
+			_exits(threadexitsmsg);
+		threadexitsmsg = msg;
+	}
+
+	mypid = getpid();
+	lock(&_threadprocslock);
+	npid = 0;
+	for(p=_threadprocs; p; p=p->next)
+		if(p->osprocid != mypid && p->osprocid >= 1)
+			pid[npid++] = p->osprocid;
+	for(i=0; i<npid; i++)
+		kill(pid[i], SIGUSR2);
+	unlock(&_threadprocslock);
+	exits(msg);
+}
+
+/*
+ * per-process data, indexed by pid
+ *
+ * could use modify_ldt and a segment register
+ * to avoid the many calls to getpid(), but i don't
+ * care -- this is compatibility code.  linux 2.6 with
+ * nptl is a good enough pthreads to avoid this whole file.
+ */
+typedef struct Perproc Perproc;
+struct Perproc
+{
+	int		pid;
+	Proc	*proc;
+};
+
+static Lock perlock;
+static Perproc perproc[1024];
+#define P ((Proc*)-1)
+
+static Perproc*
+myperproc(void)
+{
+	int i, pid, h;
+	Perproc *p;
+
+	pid = getpid();
+	h = pid%nelem(perproc);
+	for(i=0; i<nelem(perproc); i++){
+		p = &perproc[(i+h)%nelem(perproc)];
+		if(p->pid == pid)
+			return p;
+		if(p->pid == 0){
+			print("found 0 at %d (h=%d)\n", (i+h)%nelem(perproc), h);
+			break;
+		}
+	}
+	fprint(2, "myperproc %d (%s): cannot find self\n", pid, argv0);
+	abort();
+	return nil;
+}
+
+static Perproc*
+newperproc(void)
+{
+	int i, pid, h;
+	Perproc *p;
+
+	lock(&perlock);
+	pid = getpid();
+	h = pid%nelem(perproc);
+	for(i=0; i<nelem(perproc); i++){
+		p = &perproc[(i+h)%nelem(perproc)];
+		if(p->pid == pid || p->pid == -1 || p->pid == 0){
+			p->pid = pid;
+			unlock(&perlock);
+			return p;
+		}
+	}
+	fprint(2, "newperproc %d: out of procs\n", pid);
+	abort();
+	return nil;
+}
+
+Proc*
+_threadproc(void)
+{
+	return myperproc()->proc;
+}
+
+void
+_threadsetproc(Proc *p)
+{
+	Perproc *pp;
+
+	if(p)
+		p->osprocid = getpid();
+	pp = newperproc();
+	pp->proc = p;
+	if(p == nil)
+		pp->pid = -1;
+}
+
+void
+_pthreadinit(void)
+{
+	signal(SIGUSR2, sigusr2handler);
+}
+
+void
+_threadpexit(void)
+{
+	_exit(0);
+}
+
+#ifdef __arm__
+void
+makecontext(ucontext_t *uc, void (*fn)(void), int argc, ...)
+{
+	int i, *sp;
+	va_list arg;
+
+	sp = (int*)uc->uc_stack.ss_sp+uc->uc_stack.ss_size/4;
+	va_start(arg, argc);
+	for(i=0; i<4 && i<argc; i++)
+		uc->uc_mcontext.gregs[i] = va_arg(arg, uint);
+	va_end(arg);
+	uc->uc_mcontext.gregs[13] = (uint)sp;
+	uc->uc_mcontext.gregs[14] = (uint)fn;
+}
+
+int
+swapcontext(ucontext_t *oucp, const ucontext_t *ucp)
+{
+	if(getcontext(oucp) == 0)
+		setcontext(ucp);
+	return 0;
+}
+#endif
blob - 31c4c7e5d754dcc0a948dc9188b14d2bdfc1dfdf
blob + a083fd013fe9741647b61ee5888dc96d49aa5487
--- src/libthread/mkfile
+++ src/libthread/mkfile
@@ -16,7 +16,6 @@ OFILES=\
 <$PLAN9/src/mksyslib
 
 HFILES=thread.h threadimpl.h
-NetBSD.$O: Linux.c
 
 tprimes: test/tprimes.$O
 	9l -o $target test/$target.$O