shithub: drawcpu

Download patch

ref: f6da1ab12d14fe4db7a76f390d6dfc85de660f1c
parent: 4fd46455350c3e29718f8fdd6d709f3c72b4abb4
author: halfwit <michaelmisch1985@gmail.com>
date: Thu Nov 20 18:57:42 EST 2025

Much more progress, just CD seems broken at the moment

--- a/TODO
+++ b/TODO
@@ -6,7 +6,7 @@
  - [ ] Use ScreenCaptureKit to get at the video/audio. Handle resizes the other direction
  - [ ] define the gui interface
  - [ ] Fully fledged note handling
- - [ ] up->parent integration into /proc
+ - [x] up->parent integration into /proc
 
 Kernel space needs:
  - [x] devcmd   - #C: OS(1) commands, we already run on host
@@ -21,5 +21,4 @@
  - [x] devssl   - #D: needed, ssl
  - [x] devtls   - #a: needed, tls
  - [ ] devproc  - #p: needed, /proc, overlay any existing 
- - [ ] devbin   - #9: needed, just a path that can use PLAN9 environment variable
  - [x] devtab   - # meta: needed add/remove any devices that we add/remove, from here as well
--- a/include/proc.h
+++ b/include/proc.h
@@ -1,4 +1,3 @@
 extern void step(void);
 int loadtext(char *, int, char **);
-void inittos(void);
 void resetvfp(void);
\ No newline at end of file
--- a/kern/Makefile
+++ b/kern/Makefile
@@ -19,6 +19,7 @@
 	devip.$O\
 	devmnt.$O\
 	devpipe.$O\
+	devproc.$O\
 	devroot.$O\
 	devssl.$O\
 	devtab.$O\
--- a/kern/arm.c
+++ b/kern/arm.c
@@ -484,7 +484,37 @@
 step(void)
 {
     u32int instr;
+    char *state;
     Segment *seg;
+
+    switch(up->procctl) {
+    case Proc_traceme:
+    	//if(up->nnote == 0)
+		//	return;
+        /* No break */
+    case Proc_stopme:
+		up->procctl = 0;
+		//state = up->psstate;
+		//up->psstate = statename[Stopped];
+		/* free a waiting debugger */
+		//spllo();
+		//qlock(&up->debug);
+		//if(up->pdbg != nil) {
+		//	wakeup(&up->pdbg->sleep);
+		//	up->pdbg = nil;
+		//}
+		//qunlock(&up->debug);
+		//splhi();
+		//up->state = Stopped;
+		//sched();
+		//up->psstate = state;
+		return;
+	case Proc_exitme:
+    	pexit("Killed", 1);
+	case Proc_exitbig:
+    	pprint("Killed: Insufficient physical memory\n");
+		pexit("Killed: Insufficient physical memory", 1);
+    }
 
     instr = *(u32int*) vaddr(up->R[15], 4, &seg);
     segunlock(seg);
--- a/kern/await.c
+++ b/kern/await.c
@@ -1,7 +1,12 @@
+#include "u.h"
+#include "lib.h"
+#include "dat.h"
+#include "fns.h"
+#include "error.h"
+#include "user.h"
+#include "sys.h"
+#include "proc.h"
 
-#include <u.h>
-#include <libc.h>
-
 #include <signal.h>
 #include <sys/types.h>
 #include <sys/wait.h>
@@ -81,56 +86,8 @@
 	return 0;
 }
 
-static int
-_await(int pid4, char *str, int n, int opt)
-{
-	int pid, status, cd;
-	struct rusage ru;
-	char buf[128], tmp[64];
-	ulong u, s;
-
-	for(;;){
-		/* On Linux, pid==-1 means anyone; on SunOS, it's pid==0. */
-		if(pid4 == -1)
-			pid = wait3(&status, opt, &ru);
-		else
-			pid = wait4(pid4, &status, opt, &ru);
-		if(pid <= 0)
-			return -1;
-		u = ru.ru_utime.tv_sec*1000+((ru.ru_utime.tv_usec+500)/1000);
-		s = ru.ru_stime.tv_sec*1000+((ru.ru_stime.tv_usec+500)/1000);
-		if(WIFEXITED(status)){
-			status = WEXITSTATUS(status);
-			if(status)
-				snprint(buf, sizeof buf, "%d %lud %lud %lud %d", pid, u, s, u+s, status);
-			else
-				snprint(buf, sizeof buf, "%d %lud %lud %lud ''", pid, u, s, u+s, status);
-			strecpy(str, str+n, buf);
-			return strlen(str);
-		}
-		if(WIFSIGNALED(status)){
-			cd = WCOREDUMP(status);
-			snprint(buf, sizeof buf, "%d %lud %lud %lud 'signal: %s%s'", pid, u, s, u+s, _p9sigstr(WTERMSIG(status), tmp), cd ? " (core dumped)" : "");
-			strecpy(str, str+n, buf);
-			return strlen(str);
-		}
-	}
-}
-
 int
-await(char *str, int n)
+await(char *p, int n)
 {
-	return _await(-1, str, n, 0);
-}
-
-int
-awaitnohang(char *str, int n)
-{
-	return _await(-1, str, n, WNOHANG);
-}
-
-int
-awaitfor(int pid, char *str, int n)
-{
-	return _await(pid, str, n, 0);
+	return osawait(up, p, n);
 }
--- a/kern/chan.c
+++ b/kern/chan.c
@@ -1469,7 +1469,6 @@
 		}
 
 		/* create failed */
-		cclose(cnew);
 		putmhead(m);
 		if(omode & OEXCL)
 			nexterror();
--- a/kern/dat.h
+++ b/kern/dat.h
@@ -405,11 +405,20 @@
 
 enum
 {
+	Dead = 0,
+	Moribund,
+	Ready,
 	Running,
-	Rendezvous,
 	Wakeme,
-	Dead,
+	Broken,
 	Stopped,
+	Rendezvous,
+
+	Proc_stopme = 1, 	/* devproc requests */
+	Proc_exitme,
+	Proc_traceme,
+	Proc_exitbig,
+	Proc_tracesyscall,
 };
 
 struct Fd
@@ -475,7 +484,9 @@
 
 	Proc	*qnext;
 	Proc    *parent;
+	Proc    *child;
 	int     nchild;
+	int     procctl;
 	
 	void	(*fn)(void*);
 	void	*arg;
--- a/kern/devproc.c
+++ b/kern/devproc.c
@@ -14,7 +14,6 @@
 	Qargs,
 	Qctl,
 	Qfd,
-	Qmem,
 	Qnote,
 	Qnoteid,
 	Qnotepg,
@@ -21,14 +20,11 @@
 	Qns,
 	Qppid,
 	Qproc,
-	Qregs,
 	Qsegment,
 	Qstatus,
-	Qtext,
 	Qwait,
 	Qprofile,
 	Qsyscall,
-	Qwatchpt,
 };
 
 enum
@@ -48,7 +44,6 @@
 	CMstartsyscall,
 	CMstop,
 	CMwaitstop,
-	CMwired,
 	CMtrace,
 	CMinterrupt,
 	CMnointerrupt,
@@ -84,7 +79,6 @@
 	"args",		{Qargs},	0,			0660,
 	"ctl",		{Qctl},		0,			0000,
 	"fd",		{Qfd},		0,			0444,
-	"mem",		{Qmem},		0,			0000,
 	"note",		{Qnote},	0,			0000,
 	"noteid",	{Qnoteid},	0,			0664,
 	"notepg",	{Qnotepg},	0,			0000,
@@ -91,14 +85,11 @@
 	"ns",		{Qns},		0,			0444,
 	"ppid",		{Qppid},	0,			0444,
 	"proc",		{Qproc},	0,			0400,
-	"regs",		{Qregs},	REGSIZE,	0000,
 	"segment",	{Qsegment},	0,			0444,
 	"status",	{Qstatus},	STATSIZE,	0444,
-	"text",		{Qtext},	0,			0000,
 	"wait",		{Qwait},	0,			0400,
 	"profile",	{Qprofile},	0,			0400,
 	"syscall",	{Qsyscall},	0,			0400,	
-	"watchpt",	{Qwatchpt},	0,			0600,
 };
 
 static
@@ -118,7 +109,6 @@
 	CMstartsyscall,	"startsyscall",	1,
 	CMstop,			"stop",			1,
 	CMwaitstop,		"waitstop",		1,
-	CMwired,		"wired",		2,
 	CMtrace,		"trace",		0,
 	CMinterrupt,	"interrupt",	1,
 	CMnointerrupt,	"nointerrupt",	1,
@@ -127,6 +117,87 @@
 /* Segment type from dat.h */
 static char *sname[]={ "Text", "Data", "Bss", "Stack", "Shared", "Phys", "Fixed", "Sticky" };
 
+static void
+nonone(Proc *p)
+{
+	if(p == up)
+		return;
+	if(strcmp(up->user, "none") != 0)
+		return;
+	if(iseve())
+		return;
+	error(Eperm);
+}
+
+static void
+procstopwait(Proc *p, int ctl)
+{
+	char *state;
+	int pid;
+/*
+	if(p->pdbg != nil)
+		error(Einuse);
+	if(procstopped(p) || p->state == Broken)
+		return;
+	pid = p->pid;
+	if(pid == 0)
+		error(Eprocdied);
+	if(ctl != 0)
+		p->procctl = ctl;
+	if(p == up)
+		return;
+	p->pdbg = up;
+	qunlock(&p->debug);
+	state = up->psstate;
+	up->psstate = "Stopwait";
+	if(waserror()) {
+		up->psstate = state;
+		qlock(&p->debug);
+		if(p->pdbg == up)
+			p->pdbg = nil;
+		nexterror();
+	}
+	sleep(&up->sleep, procstopped, p);
+	poperror();
+	up->psstate = state;
+	qlock(&p->debug);
+	if(p->pid != pid)
+		error(Eprocdied);
+*/
+}
+
+static void
+procctlclosefiles(Proc *p, int all, int fd)
+{
+	Fgrp *f;
+	Chan *c;
+
+	if(fd < 0)
+		error(Ebadfd);
+	f = p->fgrp;
+	if(f == nil)
+		error(Eprocdied);
+
+	incref(f);
+	lock(f);
+	while(fd <= f->maxfd){
+		c = f->fd[fd];
+		if(c != nil){
+			f->fd[fd] = nil;
+			unlock(f);
+			qunlock(&p->debug);
+			cclose(c);
+			qlock(&p->debug);
+			lock(f);
+		}
+		if(!all)
+			break;
+		fd++;
+	}
+	unlock(f);
+	closefgrp(f);
+}
+
 static int
 procgen(Chan *c, char *name, Dirtab *tab, int nd, int s, Dir *dp)
 {
@@ -135,7 +206,6 @@
 	char *ename;
 	Segment *q;
 	ulong pid, path, perm, len;
-
 	if(s == DEVDOTDOT){
 		mkqid(&qid, Qdir, 0, QTDIR);
 		devdir(c, qid, "#p", 0, eve, 0555, dp);
@@ -155,7 +225,7 @@
 			pid = strtol(name, &ename, 10);
 			if(pid==0 || ename[0]!='\0')
 				return -1;
-			s = procindex(pid);
+			s = pid;
 			if(s < 0)
 				return -1;
 		}
@@ -203,26 +273,105 @@
 	len = tab->length;
 	switch(QID(c->qid)) {
 	case Qwait:
-		len = p->nwait;	/* incorrect size, but >0 means there's something to read */
+	//	len = p->nwait;	/* incorrect size, but >0 means there's something to read */
 		break;
 	case Qprofile:
-		q = p->seg[TSEG];
-		if(q != nil && q->profile != nil) {
-			len = (q->size-q->start)>>LRESPROF;
-			len *= sizeof(*q->profile);
-		}
+	//	q = p->seg[TSEG];
+	//	if(q != nil && q->profile != nil) {
+	//		len = (q->size-q->start)>>LRESPROF;
+	//		len *= sizeof(*q->profile);
+	//	}
 		break;
-	case Qwatchpt:
-		len = lenwatchpt(p);
-		break;
 	}
-
+len = 0;
 	mkqid(&qid, path|tab->qid.path, c->qid.vers, QTFILE);
 	devdir(c, qid, tab->name, len, p->user, perm, dp);
 	return 1;
 }
 
+
 static void
+int2flag(int flag, char *s)
+{
+	if(flag == 0){
+		*s = '\0';
+		return;
+	}
+	*s++ = '-';
+	if(flag & MAFTER)
+		*s++ = 'a';
+	if(flag & MBEFORE)
+		*s++ = 'b';
+	if(flag & MCREATE)
+		*s++ = 'c';
+	if(flag & MCACHE)
+		*s++ = 'C';
+	*s = '\0';
+}
+
+static int
+readns1(Chan *c, Proc *p, char *buf, int nbuf)
+{
+	Pgrp *pg;
+	Mount *t, *cm;
+	Mhead *f, *mh;
+	ulong minid, bestmid;
+	char flag[10], *srv;
+	int i;
+
+	pg = p->pgrp;
+	if(pg == nil || p->dot == nil || p->pid != PID(c->qid))
+		error(Eprocdied);
+
+	bestmid = ~0;
+	minid = c->nrock;
+	if(minid == bestmid)
+		return 0;
+
+	rlock(&pg->ns);
+
+	mh = nil;
+	cm = nil;
+	for(i = 0; i < MNTHASH; i++) {
+		for(f = pg->mnthash[i]; f != nil; f = f->hash) {
+			rlock(&f->lock);
+			for(t = f->mount; t != nil; t = t->next) {
+				if(t->mountid >= minid && t->mountid < bestmid) {
+					bestmid = t->mountid;
+					cm = t;
+					mh = f;
+				}
+			}
+			runlock(&f->lock);
+		}
+	}
+
+	if(bestmid == ~0) {
+		c->nrock = bestmid;
+		i = snprint(buf, nbuf, "cd %q\n", p->dot->path->s);
+	} else {
+		c->nrock = bestmid+1;
+
+		int2flag(cm->mflag, flag);
+		if(strcmp(cm->to->path->s, "#M") == 0){
+			//srv = cm->to->mchan->srvname;
+			if(srv == nil)
+				srv = cm->to->mchan->path->s;
+			i = snprint(buf, nbuf, *cm->spec?
+				"mount %s %q %q %q\n": "mount %s %q %q\n", flag,
+				srv, mh->from->path->s, cm->spec);
+		}else{
+			i = snprint(buf, nbuf, "bind %s %q %q\n", flag,
+				cm->to->path->s, mh->from->path->s);
+		}
+	}
+
+	runlock(&pg->ns);
+
+	return i;
+}
+
+static void
 procinit(void)
 {
 	return;
@@ -231,7 +380,13 @@
 static Chan*
 procattach(char *spec)
 {
-	return devattach('p', spec);
+	Chan *c;
+
+	c = devattach('p', spec);
+	c->qid.path = Qdir;
+	c->qid.vers = 0;
+	c->qid.type = QTDIR;
+	return c;
 }
 
 static Walkqid*
@@ -254,23 +409,23 @@
 	if(QID(c->qid) == Qtrace){
 		if (omode0 != OREAD || !iseve()) 
 			error(Eperm);
-		lock(&tlock);
-		if (waserror()){
-			topens--;
-			unlock(&tlock);
-			nexterror();
-		}
-		if (topens++ > 0)
-			error("already open");
-		if (tevents == nil){
-			tevents = (Traceevent*)malloc(sizeof(Traceevent) * Nevents);
-			if(tevents == nil)
-				error(Enomem);
-			tproduced = tconsumed = 0;
-		}
-		proctrace = _proctrace;
-		unlock(&tlock);
-		poperror();
+	//	lock(&tlock);
+	//	if (waserror()){
+	//		topens--;
+	//		unlock(&tlock);
+	//		nexterror();
+	//	}
+	//	if (topens++ > 0)
+	//		error("already open");
+	//	if (tevents == nil){
+	//		tevents = (Traceevent*)malloc(sizeof(Traceevent) * Nevents);
+	//		if(tevents == nil)
+	//			error(Enomem);
+	//		tproduced = tconsumed = 0;
+	//	}
+	//	proctrace = _proctrace;
+	//	unlock(&tlock);
+	//	poperror();
 
 		c->mode = openmode(omode0);
 		c->flag |= COPEN;
@@ -279,7 +434,7 @@
 	}
 		
 	p = proctab(SLOT(c->qid));
-	eqlock(&p->debug);
+	qlock(&p->debug);
 	if(waserror()){
 		qunlock(&p->debug);
 		nexterror();
@@ -291,16 +446,6 @@
 	omode = openmode(omode0);
 
 	switch(QID(c->qid)){
-	case Qtext:
-		if(omode != OREAD)
-			error(Eperm);
-		nonone(p);
-		qunlock(&p->debug);
-		poperror();
-		tc = proctext(c, p);
-		tc->offset = 0;
-		cclose(c);
-		return tc;
 
 	case Qstatus:
 	case Qppid:
@@ -324,16 +469,13 @@
 		break;
 
 	case Qnotepg:
-		if(p->kp || omode != OWRITE)
-			error(Eperm);
-		pid = p->noteid;
+		//if(p->kp || omode != OWRITE)
+		//	error(Eperm); 
+		//pid = p->noteid;
 		break;
 
-	case Qmem:
-	case Qregs:
 	case Qprofile:
 	case Qsyscall:	
-	case Qwatchpt:
 		break;
 
 	default:
@@ -353,13 +495,6 @@
 		nexterror();
 	}
 	
-	switch(QID(c->qid)){
-	case Qwatchpt:
-		if((omode0 & OTRUNC) != 0)
-			clearwatchpt(p);
-		break;
-	}
-	
 	poperror();
 	qunlock(&p->debug);
 	poperror();
@@ -382,27 +517,27 @@
 	offset = off;
 	if(c->qid.type & QTDIR)
 		return devdirread(c, va, n, 0, 0, procgen);
-
+	
 	if(QID(c->qid) == Qtrace){
-		int navail, ne;
+	//	int navail, ne;
 
-		if(!eventsavailable(nil))
-			return 0;
+	//	if(!eventsavailable(nil))
+	//		return 0;
 
-		rptr = (uchar*)va;
-		navail = tproduced - tconsumed;
-		if(navail > n / sizeof(Traceevent))
-			navail = n / sizeof(Traceevent);
-		while(navail > 0) {
-			ne = ((tconsumed & Emask) + navail > Nevents)? 
-					Nevents - (tconsumed & Emask): navail;
-			memmove(rptr, &tevents[tconsumed & Emask], 
-					ne * sizeof(Traceevent));
+	//	rptr = (uchar*)va;
+	//	navail = tproduced - tconsumed;
+	//	if(navail > n / sizeof(Traceevent))
+	//		navail = n / sizeof(Traceevent);
+	//	while(navail > 0) {
+	//		ne = ((tconsumed & Emask) + navail > Nevents)? 
+	//				Nevents - (tconsumed & Emask): navail;
+	//		memmove(rptr, &tevents[tconsumed & Emask], 
+	//				ne * sizeof(Traceevent));
 
-			tconsumed += ne;
-			rptr += ne * sizeof(Traceevent);
-			navail -= ne;
-		}
+	//		tconsumed += ne;
+	//		rptr += ne * sizeof(Traceevent);
+	//		navail -= ne;
+	//	}
 		return rptr - (uchar*)va;
 	}
 
@@ -411,54 +546,28 @@
 		error(Eprocdied);
 
 	switch(QID(c->qid)){
-	case Qmem:
-		addr = off2addr(off);
-		if(addr < KZERO)
-			return procctlmemio(c, p, addr, va, n, 1);
-
-		if(!iseve() || poolisoverlap(secrmem, (uchar*)addr, n))
-			error(Eperm);
-
-		// validate kernel addresses
-		if(addr < (uintptr)end) {
-			if(addr+n > (uintptr)end)
-				n = (uintptr)end - addr;
-			memmove(va, (char*)addr, n);
-			return n;
-		}
-		for(i=0; i<nelem(conf.mem); i++){
-			Confmem *cm = &conf.mem[i];
-			// klimit-1 because klimit might be zero!
-			if(cm->kbase <= addr && addr <= cm->klimit-1){
-				if(addr+n >= cm->klimit-1)
-					n = cm->klimit - addr;
-				memmove(va, (char*)addr, n);
-				return n;
-			}
-		}
-		
-		error(Ebadarg);
-
 	case Qctl:
 		return readnum(offset, va, n, p->pid, NUMSIZE);
 
 	case Qnoteid:
-		return readnum(offset, va, n, p->noteid, NUMSIZE);
+		return readnum(offset, va, n, p->notein, NUMSIZE);
 
 	case Qppid:
-		return readnum(offset, va, n, p->parentpid, NUMSIZE);
+		if(!p->parent)
+			return readnum(offset, va, n, 0, NUMSIZE);
+		return readnum(offset, va, n, p->parent->pid, NUMSIZE);
 
 	case Qprofile:
-		s = p->seg[TSEG];
-		if(s == nil || s->profile == nil)
-			error("profile is off");
-		i = (s->size-s->start)>>LRESPROF;
-		i *= sizeof(s->profile[0]);
-		if(i < 0 || offset >= i)
-			return 0;
-		if(offset+n > i)
-			n = i - offset;
-		memmove(va, ((char*)s->profile)+offset, n);
+	//	s = p->seg[TSEG];
+	//	if(s == nil || s->profile == nil)
+	//		error("profile is off");
+	//	i = (s->size-s->start)>>LRESPROF;
+	//	i *= sizeof(s->profile[0]);
+	//	if(i < 0 || offset >= i)
+	//		return 0;
+	//	if(offset+n > i)
+	//		n = i - offset;
+	//	memmove(va, ((char*)s->profile)+offset, n);
 		return n;
 
 	case Qproc:
@@ -474,15 +583,10 @@
 		memmove(va, rptr+offset, n);
 		return n;
 
-	case Qregs:
-		rptr = (uchar*)p->dbgreg;
-		rsize = REGSIZE;
-		goto regread;
-
 	case Qstatus:
-		sps = p->psstate;
-		if(sps == nil)
-			sps = statename[p->state];
+	//	sps = p->psstate;
+	//	if(sps == nil)
+	//		sps = statename[p->state];
 		/* NOTE: We don't have any p->time tracking
 		         this is handled by the pthreads/windows
 		j = snprint(statbuf, sizeof(statbuf),
@@ -518,52 +622,52 @@
 				"%-6s %c%c %8p %8p %4ld\n",
 				sname[s->type&SG_TYPE],
 				s->type&SG_FAULT ? 'F' : (s->type&SG_RONLY ? 'R' : ' '),
-				s->profile ? 'P' : ' ',
+				' ', //s->profile ? 'P' : ' ',
 				s->start, s->size, s->ref);
 		}
 		goto statbufread;
 
 	case Qwait:
-		if(!canqlock(&p->qwaitr))
-			error(Einuse);
+	//	if(!canqlock(&p->qwaitr))
+	//		error(Einuse);
 
-		if(waserror()) {
-			qunlock(&p->qwaitr);
-			nexterror();
-		}
+	//	if(waserror()) {
+	//		qunlock(&p->qwaitr);
+	//		nexterror();
+	//	}
 
-		lock(&p->exl);
-		while(p->waitq == nil && p->pid == PID(c->qid)) {
-			if(up == p && p->nchild == 0) {
-				unlock(&p->exl);
-				error(Enochild);
-			}
-			unlock(&p->exl);
-			sleep(&p->waitr, prochaswaitq, c);
-			lock(&p->exl);
-		}
-		if(p->pid != PID(c->qid)){
-			unlock(&p->exl);
-			error(Eprocdied);
-		}
-		wq = p->waitq;
-		p->waitq = wq->next;
-		p->nwait--;
-		unlock(&p->exl);
+	//	lock(&p->exl);
+	//	while(p->waitq == nil && p->pid == PID(c->qid)) {
+	//		if(up == p && p->nchild == 0) {
+	//			unlock(&p->exl);
+	//			error(Enochild);
+	//		}
+	//		unlock(&p->exl);
+	//		sleep(&p->waitr, prochaswaitq, c);
+	//		lock(&p->exl);
+	//	}
+	//	if(p->pid != PID(c->qid)){
+	//		unlock(&p->exl);
+	//		error(Eprocdied);
+	//	}
+	//	wq = p->waitq;
+	//	p->waitq = wq->next;
+	//	p->nwait--;
+	//	unlock(&p->exl);
 
-		qunlock(&p->qwaitr);
-		poperror();
+	//	qunlock(&p->qwaitr);
+	//	poperror();
 
-		j = snprint(statbuf, sizeof(statbuf), "%d %lud %lud %lud %q",
-			wq->w.pid,
-			wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
-			wq->w.msg);
-		free(wq);
-		offset = 0;
+	//	j = snprint(statbuf, sizeof(statbuf), "%d %lud %lud %lud %q",
+	//		wq->w.pid,
+	//		wq->w.time[TUser], wq->w.time[TSys], wq->w.time[TReal],
+	//		wq->w.msg);
+	//	free(wq);
+	//	offset = 0;
 		goto statbufread;
 	}
 
-	eqlock(&p->debug);
+	qlock(&p->debug);
 	if(waserror()){
 		qunlock(&p->debug);
 		nexterror();
@@ -579,8 +683,8 @@
 		do {
 			if(QID(c->qid) == Qns)
 				j = readns1(c, p, statbuf, sizeof(statbuf));
-			else
-				j = readfd1(c, p, statbuf, sizeof(statbuf));
+	//		else
+	//			j = readfd1(c, p, statbuf, sizeof(statbuf));
 			if(j == 0)
 				break;
 			c->mrock += j;
@@ -596,43 +700,37 @@
 		goto statbufread;
 	
 	case Qargs:
-		j = procargs(p, statbuf, sizeof(statbuf));
+	//	j = procargs(p, statbuf, sizeof(statbuf));
 		qunlock(&p->debug);
 		poperror();
 		goto statbufread;
 
-	case Qwatchpt:
-		j = readwatchpt(p, statbuf, sizeof(statbuf));
-		qunlock(&p->debug);
-		poperror();
-		goto statbufread;
-
 	case Qsyscall:
-		if(p->syscalltrace != nil)
-			n = readstr(offset, va, n, p->syscalltrace);
-		else
-			n = 0;
+	//	if(p->syscalltrace != nil)
+	//		n = readstr(offset, va, n, p->syscalltrace);
+	//	else
+	//		n = 0;
 		break;
 
 	case Qnote:
-		if(n < 1)	/* must accept at least the '\0' */
-			error(Etoosmall);
-		if(p->nnote == 0)
-			n = 0;
-		else {
-			assert(p->note[0] != nil);
-			i = strlen(p->note[0]->msg) + 1;
-			if(i < n)
-				n = i;
-			memmove(va, p->note[0]->msg, n-1);
-			((char*)va)[n-1] = '\0';
-			freenote(p->note[0]);
-			if(--p->nnote == 0)
-				p->notepending = 0;
-			else
-				memmove(&p->note[0], &p->note[1], p->nnote*sizeof(Note*));
-			p->note[p->nnote] = nil;
-		}
+	//	if(n < 1)	/* must accept at least the '\0' */
+	//		error(Etoosmall);
+	//	if(p->nnote == 0)
+	//		n = 0;
+	//	else {
+	//		assert(p->note[0] != nil);
+	//		i = strlen(p->note[0]->msg) + 1;
+	//		if(i < n)
+	//			n = i;
+	//		memmove(va, p->note[0]->msg, n-1);
+	//		((char*)va)[n-1] = '\0';
+	//		freenote(p->note[0]);
+	//		if(--p->nnote == 0)
+	//			p->notepending = 0;
+	//		else
+	//			memmove(&p->note[0], &p->note[1], p->nnote*sizeof(Note*));
+	//		p->note[p->nnote] = nil;
+	//	}
 		break;
 
 	default:
@@ -663,11 +761,16 @@
 			error(Etoobig);
 		memmove(buf, va, n);
 		buf[n] = 0;
-		postnotepg(NOTEID(c->qid), buf, NUser);
+	//	postnotepg(NOTEID(c->qid), buf, NUser);
 		return n;
 	}
 
 	p = proctab(SLOT(c->qid));
+	qlock(&p->debug);
+	if(waserror()){
+		qunlock(&p->debug);
+		nexterror();
+	}
 	if(p->pid != PID(c->qid))
 		error(Eprocdied);
 
@@ -677,26 +780,11 @@
 			error(Etoobig);
 		memmove(buf, va, n);
 		buf[n] = 0;
-		kstrdup(&p->args, buf);
-		p->nargs = 0;
-		p->setargs = 1;
+	//	kstrdup(&p->args, buf);
+	//	p->nargs = 0;
+	//	p->setargs = 1;
 		break;
 
-	case Qmem:
-		if(p->state != Stopped)
-			error(Ebadctl);
-		n = procctlmemio(c, p, off2addr(off), va, n, 0);
-		break;
-
-	case Qregs:
-		if(offset >= REGSIZE)
-			n = 0;
-		else if(offset+n > REGSIZE)
-			n = REGSIZE - offset;
-		if(p->dbgreg == nil)
-			error(Enoreg);
-		setregisters(p->dbgreg, (char*)(p->dbgreg)+offset, va, n);
-		break;
 	case Qctl:
 		procctlreq(p, va, n);
 		break;
@@ -715,7 +803,7 @@
 			error(Etoobig);
 		memmove(buf, va, n);
 		buf[n] = 0;
-		changenoteid(p, atoi(buf));
+	//	changenoteid(p, atoi(buf));
 		break;
 
 	default:
@@ -723,13 +811,36 @@
 		error(Egreg);
 	}
 	poperror();
+	qunlock(&p->debug);
 	return n;
 }
 
+/*
+ *  called with p->debug locked.
+ */
+void
+killproc(Proc *p, int ctl)
+{
+	int new;
+
+	if(p->pid == 0 || p->kp)
+		return;
+	if(ctl != 0)
+		p->procctl = ctl;
+	new = up->notein + 1;
+	if((new - up->noteout) % NNOTE == 0)
+		return;
+	strncpy(up->notes[up->notein % NNOTE], "sys: killed", ERRMAX - 1);
+	up->notein = new;
+	//if(p->state == Stopped)
+	//	ready(p);
+}
+
+
 static void
 procclose(Chan *c)
 {
-	Segio *sio;
+	//Segio *sio;
 
 	if((c->flag & COPEN) == 0)
 		return;
@@ -736,21 +847,13 @@
 
 	switch(QID(c->qid)){
 	case Qtrace:
-		lock(&tlock);
-		if(topens > 0)
-			topens--;
-		if(topens == 0)
-			proctrace = nil;
-		unlock(&tlock);
+	//	lock(&tlock);
+	//	if(topens > 0)
+	//		topens--;
+	//	if(topens == 0)
+	//		proctrace = nil;
+	//	unlock(&tlock);
 		return;
-	case Qmem:
-		sio = c->aux;
-		if(sio != nil){
-			c->aux = nil;
-			segio(sio, nil, nil, 0, 0, 0);
-			free(sio);
-		}
-		return;
 	}
 }
 
@@ -779,7 +882,7 @@
 		error(Eshortstat);
 
 	p = proctab(SLOT(c->qid));
-	eqlock(&p->debug);
+	qlock(&p->debug);
 	if(waserror()){
 		qunlock(&p->debug);
 		nexterror();
@@ -843,75 +946,76 @@
 		procctlclosefiles(p, 1, 0);
 		break;
 	case CMhang:
-		p->hang = 1;
+	//	p->hang = 1;
 		break;
 	case CMkill:
-		killproc(p, Proc_exitme);
+	//	killproc(p, Proc_exitme);
 		break;
 	case CMnohang:
-		p->hang = 0;
+	//	p->hang = 0;
 		break;
 	case CMnoswap:
-		p->noswap = 1;
+	//	p->noswap = 1;
 		break;
+// TODO: procpriority --> osprocpriority call
 	case CMpri:
-		pri = atoi(cb->f[1]);
-		if(pri > PriNormal && !iseve())
-			error(Eperm);
-		procpriority(p, pri, 0);
+	//	pri = atoi(cb->f[1]);
+	//	if(pri > PriNormal && !iseve())
+	//		error(Eperm);
+	//	procpriority(p, pri, 0);
 		break;
 	case CMfixedpri:
-		pri = atoi(cb->f[1]);
-		if(pri > PriNormal && !iseve())
-			error(Eperm);
-		procpriority(p, pri, 1);
+	//	pri = atoi(cb->f[1]);
+	//	if(pri > PriNormal && !iseve())
+	//		error(Eperm);
+	//	procpriority(p, pri, 1);
 		break;
 	case CMprivate:
-		p->privatemem = 1;
+	//	p->privatemem = 1;
 		/*
 		 * pages will now get marked private
 		 * when faulted in for writing
 		 * so force a tlb flush.
 		 */
-		p->newtlb = 1;
-		if(p == up)
-			flushmmu();
+	//	p->newtlb = 1;
+	//	if(p == up)
+	//		flushmmu();
 		break;
 	case CMprofile:
-		s = p->seg[TSEG];
-		if(s == nil || (s->type&SG_TYPE) != SG_TEXT)	/* won't expand */
-			error(Egreg);
-		eqlock(s);
-		npc = (s->size-s->start)>>LRESPROF;
-		if(s->profile == nil){
-			s->profile = malloc(npc*sizeof(*s->profile));
-			if(s->profile == nil){
-				qunlock(s);
-				error(Enomem);
-			}
-		} else {
-			memset(s->profile, 0, npc*sizeof(*s->profile));
-		}
-		qunlock(s);
+	//	s = p->seg[TSEG];
+	//	if(s == nil || (s->type&SG_TYPE) != SG_TEXT)	/* won't expand */
+	//		error(Egreg);
+	//	qlock(s);
+	//	npc = (s->size-s->start)>>LRESPROF;
+	//	if(s->profile == nil){
+	//		s->profile = malloc(npc*sizeof(*s->profile));
+	//		if(s->profile == nil){
+	//			qunlock(s);
+	//			error(Enomem);
+	//		}
+	//	} else {
+	//		memset(s->profile, 0, npc*sizeof(*s->profile));
+	//	}
+	//	qunlock(s);
 		break;
 	case CMstart:
-		if(p->state != Stopped)
-			error(Ebadctl);
-		ready(p);
+		//if(p->state != Stopped)
+		//	error(Ebadctl);
+		//ready(p);
 		break;
 	case CMstartstop:
-		if(p->state != Stopped)
-			error(Ebadctl);
-		p->procctl = Proc_traceme;
-		ready(p);
-		procstopwait(p, Proc_traceme);
+		//if(p->state != Stopped)
+		//	error(Ebadctl);
+		//p->procctl = Proc_traceme;
+		//ready(p);
+		//procstopwait(p, Proc_traceme);
 		break;
 	case CMstartsyscall:
-		if(p->state != Stopped)
-			error(Ebadctl);
-		p->procctl = Proc_tracesyscall;
-		ready(p);
-		procstopwait(p, Proc_tracesyscall);
+		//if(p->state != Stopped)
+		//	error(Ebadctl);
+		//p->procctl = Proc_tracesyscall;
+		//ready(p);
+		//procstopwait(p, Proc_tracesyscall);
 		break;
 	case CMstop:
 		procstopwait(p, Proc_stopme);
@@ -919,29 +1023,26 @@
 	case CMwaitstop:
 		procstopwait(p, 0);
 		break;
-	case CMwired:
-		procwired(p, atoi(cb->f[1]));
-		break;
 	case CMtrace:
-		switch(cb->nf){
-		case 1:
-			p->trace ^= 1;
-			break;
-		case 2:
-			p->trace = (atoi(cb->f[1]) != 0);
-			break;
-		default:
-			error("args");
-		}
+	//	switch(cb->nf){
+	//	case 1:
+	//		p->trace ^= 1;
+	//		break;
+	//	case 2:
+	//		p->trace = (atoi(cb->f[1]) != 0);
+	//		break;
+	//	default:
+	//		error("args");
+	//	}
 		break;
 	case CMinterrupt:
-		procinterrupt(p);
+	//	procinterrupt(p);
 		break;
 	case CMnointerrupt:
-		if(p->nnote == 0)
-			p->notepending = 0;
-		else
-			error("notes pending");
+	//	if(p->nnote == 0)
+	//		p->notepending = 0;
+	//	else
+	//		error("notes pending");
 		break;
 	}
 
@@ -962,55 +1063,51 @@
 	Segment *s;
 	int i;
 
-	eqlock(&p->seglock);
+	qlock(&p->seglock);
 	if(waserror()) {
 		qunlock(&p->seglock);
 		nexterror();
 	}
-	if(p->state <= New || p->pid != PID(c->qid))
+	if(p->pid != PID(c->qid))
 		error(Eprocdied);
-	s = seg(p, offset, 1);
-	if(s == nil)
-		error(Ebadarg);
-	if(waserror()){
-		qunlock(s);
-		nexterror();
-	}
-	for(i = 0; i < NSEG; i++) {
-		if(p->seg[i] == s)
-			break;
-	}
-	if(i == NSEG)
-		error(Egreg);	/* segment gone */
-	if(!read && (s->type&SG_TYPE) == SG_TEXT) {
-		p->seg[i] = txt2data(s);
-		qunlock(s);
-		putseg(s);
-		s = p->seg[i];
-	} else {
-		qunlock(s);
-	}
-	poperror();
-	incref(s);		/* for us while we copy */
+	//s = seg(p, offset, 1);
+	//if(s == nil)
+	//	error(Ebadarg);
+	//if(waserror()){
+	//	qunlock(s);
+	//	nexterror();
+	//}
+	//for(i = 0; i < NSEG; i++) {
+	//	if(p->seg[i] == s)
+	//		break;
+	//}
+	//if(i == NSEG)
+	//	error(Egreg);	/* segment gone */
+	//if(!read && (s->type&SG_TYPE) == SG_TEXT) {
+	//	p->seg[i] = txt2data(s);
+	//	qunlock(s);
+	//	putseg(s);
+	//	s = p->seg[i];
+	//} else {
+	//	qunlock(s);
+	//}
+	//poperror();
+	//incref(s);		/* for us while we copy */
 	qunlock(&p->seglock);
 	poperror();
 
-	if(waserror()) {
-		putseg(s);
-		nexterror();
-	}
-	offset -= s->base;
-	putseg(s);
-	poperror();
-
-	if(!read)
-		p->newtlb = 1;
-
+	//if(waserror()) {
+	//	putseg(s);
+	//	nexterror();
+	//}
+	//offset -= s->start;
+	//putseg(s);
+	//poperror(); 
 	return n;
 }
 
 Dev procdevtab = {
-	'P',
+	'p',
 	"proc",
 
 	devreset,
@@ -1024,6 +1121,7 @@
 	procclose,
 	procread,
 	devbread,
+	procwrite,
 	devbwrite,
 	devremove,
 	procwstat,
--- a/kern/devtab.c
+++ b/kern/devtab.c
@@ -16,7 +16,7 @@
 extern Dev lfddevtab;
 extern Dev cmddevtab;
 extern Dev envdevtab;
-//extern Dev procdevtab;
+extern Dev procdevtab;
 
 Dev *devtab[] = {
 	&rootdevtab,
@@ -31,7 +31,7 @@
 	&lfddevtab,
 	&cmddevtab,
 	&envdevtab,
-//	&procdevtab,
+	&procdevtab,
 	0
 };
 
--- a/kern/fns.h
+++ b/kern/fns.h
@@ -142,7 +142,7 @@
 void		oscmdfree(void*);
 void		oserrstr(void);
 void		oserror(void);
-void		osexit(void);
+void		osexit(char*);
 Block*		packblock(Block*);
 Block*		padblock(Block*, int);
 void		panic(char*, ...);
@@ -249,6 +249,7 @@
 void		osmsleep(int);
 ulong   	ticks(void);
 void	    osproc(Proc*);
+int         osawait(Proc *, char *, int);
 void	    osnewproc(Proc*);
 void	    procsleep(void);
 void	    procwakeup(Proc*);
--- a/kern/posix.c
+++ b/kern/posix.c
@@ -37,6 +37,8 @@
 #include "mem.h"
 #include <a.out.h>
 
+pthread_t thids[64];
+
 typedef struct Oproc Oproc;
 struct Oproc
 {
@@ -78,6 +80,24 @@
 	signal(SIGPIPE, SIG_IGN);
 }
 
+int
+osawait(Proc *proc, char *str, int n)
+{
+	void *msg;
+	int pid;
+	ulong time[3] = {1000, 1000, 1000};
+
+	if(!proc->child)
+		return -1;
+	pid = proc->child->pid;
+	if(pthread_join(thids[pid], &msg) != 0)
+		return -1;
+
+	// TODO: Actual TUser, TSys, TReal
+	snprint(str, n, "%d %ux %lud %lud %lud %q", pid, time[0], time[1], time[2], msg);
+	return sizeof(str);
+}
+
 void
 osnewproc(Proc *p)
 {
@@ -148,14 +168,16 @@
 		oserrstr();
 		panic("osproc: %r");
 	}
+
+	thids[p->pid] = pid;
 	sched_yield();
 }
 
 void
-osexit(void)
+osexit(char *ret)
 {
 	pthread_setspecific(prdakey, 0);
-	pthread_exit(0);
+	pthread_exit(ret);
 }
 
 void
--- a/kern/procinit.c
+++ b/kern/procinit.c
@@ -42,6 +42,18 @@
 	return p;
 }
 
+Proc*
+proctab(int i)
+{
+	Proc *p;
+
+	for(p = up; p != nil; p = p->parent) {
+		if(p->pid == i)
+			return p;
+	}
+	return nil;
+}
+
 int
 kproc(char *name, void (*fn)(void*), void *arg)
 {
@@ -53,6 +65,7 @@
 	p->slash = cclone(up->slash);
 	p->dot = cclone(up->dot);
 	p->rgrp = up->rgrp;
+	p->parent = up;
 	if(p->rgrp != nil)
 		incref(&p->rgrp->ref);
 	p->pgrp = up->pgrp;
@@ -75,7 +88,6 @@
 {
 	Proc *p = up;
 
-	USED(msg);
 	USED(freemem);
 
 	if(p->pgrp != nil){
@@ -95,5 +107,5 @@
 	cclose(p->slash);
 
 	free(p);
-	osexit();
+	osexit(msg);
 }
--- a/kern/seg.c
+++ b/kern/seg.c
@@ -43,11 +43,14 @@
 freesegs(void)
 {
 	Segment **s, *ss;
-	
+
 	for(s = up->seg; s < up->seg + NSEG; s++) {
 		if(*s == nil)
 			continue;
 		ss = *s;
+		// Assure we don't have any weird state
+		if(!ss->dref || ss->dref->ref == 0 || !&ss->ref.ref == 0)
+			continue;
 		if(decref(ss->dref) == 0)
 			free(ss->dref);
 		if(decref(&ss->ref) == 0)
@@ -133,7 +136,7 @@
 	case SG_DATA:		/* Copy on write plus demand load info */
 		if(segno == TSEG){
 			n = data2txt(s);
-			qunlock(s);
+			qunlock(&s->rw);
 			poperror();
 			return n;
 		}
@@ -145,12 +148,12 @@
 
 	if(n != nil && n != s)
     	memcpy(n->data, s->data, s->size);
-	qunlock(s);
+	qunlock(&s->rw);
 	poperror();
 	return n;
 sameseg:
 	incref(s);
-	qunlock(s);
+	qunlock(&s->rw);
 	poperror();
 	return s;
 }
--- a/kern/syscall.c
+++ b/kern/syscall.c
@@ -21,18 +21,6 @@
 	return p;
 }
 
-static char*
-estrdup(char *s)
-{
-	char *d;
-	int n;
-
-	n = strlen(s)+1;
-	d = emalloc(n);
-	memmove(d, s, n);
-	return d;
-}
-
 static u32int
 arg(int n)
 {
@@ -286,10 +274,16 @@
 static void
 _sysexits(void)
 {
-	if(arg(0) == 0)
-		exits(nil);
-	else
-		exits(vaddrnol(arg(0), 0));
+	if(arg(0) == 0) {
+		if(debug)
+			print("sysexits\n");
+		pexit("", 0);
+	} else {
+		if(debug)
+			print("sysexits: %s\n", vaddrnol(arg(0), 0));
+		pexit(vaddrnol(arg(0), 0), 0);		
+	}
+
 }
 
 static void
@@ -412,7 +406,9 @@
 		segunlock(seg2);
 	}
 	segunlock(seg1);
+
 	rc = loadtext(namet, argc, argvv);
+
 	for(i = 0; i < argc; i++)
 		free(argvv[i]);
 	free(argvv);
--- a/kern/sysproc.c
+++ b/kern/sysproc.c
@@ -290,6 +290,15 @@
     up->R[15] = ureg[17];
 }
 
+void
+inittos(Proc *p)
+{
+    ulong tos;
+
+    tos = (USTKTOP & ~7) - sizeof(Tos) * 2;
+    ((Tos *) vaddrnol(tos, sizeof(Tos)))->pid = p->pid;
+}
+
 static void
 initstack(int argc, char **argv)
 {
@@ -322,18 +331,9 @@
         ap += len;
     }
     *(ulong *) vaddrnol(sp, 4) = 0;
-	inittos();
+	inittos(up);
 }
 
-void
-inittos(void)
-{
-    ulong tos;
-
-    tos = (USTKTOP & ~7) - sizeof(Tos) * 2;
-    ((Tos *) vaddrnol(tos, sizeof(Tos)))->pid = up->pid;
-}
-
 static int
 loadscript(int fd, char *file, int argc, char **argv)
 {
@@ -394,7 +394,7 @@
     Exec hdr;
 	char buf[2];
     int fd;
-	
+
     fd = open(file, OREAD);
 	if(fd < 0) return -1;
 	if(pread(fd, buf, 2, 0) == 2 && buf[0] == '#' && buf[1] == '!')
@@ -589,8 +589,7 @@
 			pgrpcpy(p->pgrp, up->pgrp);
 		/* inherit notallowed */
 		memmove(p->pgrp->notallowed, up->pgrp->notallowed, sizeof p->pgrp->notallowed);
-	}
-	else {
+	} else {
 		p->pgrp = up->pgrp;
 		incref(p->pgrp);
 	}
@@ -610,23 +609,25 @@
 		p->egrp->ref.ref = 1;
 		if(flag & RFENVG)
 			envcpy(p->egrp, up->egrp);
-	}
-	else {
+	} else {
 		p->egrp = up->egrp;
 		incref(p->egrp);
 	}
 	p->fn = procrun;
+	p->parent = up;
 	p->arg = 0;
 
 	poperror();
 	if((flag&RFNOWAIT) == 0){
 		// TODO: Actually use parent + ppid
-		p->parent = up;
 		lock(&up->exl);
 		up->nchild++;
 		unlock(&up->exl);
 	}
 
+	inittos(p);
 	osproc(p);
+	up->child = p;
+
 	return p->pid;
 }
--- a/kern/wait.c
+++ b/kern/wait.c
@@ -35,19 +35,3 @@
 
 	return _wait(await(buf, sizeof buf-1), buf);
 }
-
-Waitmsg*
-waitnohang(void)
-{
-	char buf[256];
-
-	return _wait(awaitnohang(buf, sizeof buf-1), buf);
-}
-
-Waitmsg*
-waitfor(int pid)
-{
-	char buf[256];
-
-	return _wait(awaitfor(pid, buf, sizeof buf-1), buf);
-}
--- a/kern/win32.c
+++ b/kern/win32.c
@@ -106,7 +106,7 @@
 }
 
 void
-osexit(void)
+osexit(char *str)
 {
 	ExitThread(0);
 }
--- a/main.c
+++ b/main.c
@@ -120,8 +120,8 @@
 		panic("bind #I: %r");
 	if(bind("#U", "/root", MREPL|MCREATE) < 0)
 		panic("bind #U: %r");
-	//if(bind("#P", "/proc", MBEFORE) < 0)
-	//	panic("bind #P: %r");
+	if(bind("#p", "/proc", MBEFORE) < 0)
+		panic("bind #p: %r");
 	if(bind(smprint("/root/%s/arm", ninepath), "/arm", MREPL|MCREATE) < 0)
 		panic("bind arm: %r");
 	if(bind(smprint("/root/%s/rc", ninepath), "/rc", MREPL|MCREATE) < 0)
--