code: 9ferno

Download patch

ref: 0977f294bab0345ba43fbf674449fd8e996c5719
parent: 22e770f3183a6afa8064a75cf9aaae21de8eac08
author: 9ferno <gophone2015@gmail.com>
date: Tue Oct 26 16:08:08 EDT 2021

import 9front pid management

--- a/dis/init
+++ b/dis/init
@@ -9,7 +9,6 @@
 bind -c '#e' /env
 
 load std
-
 mount {mntgen} /n
 
 # checked these to get this working
@@ -229,9 +228,9 @@
 	#	special networking setup, disk setup
 	#	avoids putting machine specific stuff in devroot
 	and {! ~ $"sysname ''} {
-			ftest -f /lib/init/$sysname }{
-			/lib/init/$sysname
-		}
+		ftest -f /lib/init/$sysname }{
+		sh /lib/init/$sysname
+	}
 }
 
 # if I add /lib/sh/profile to devroot,
--- a/lib/init/bootcd
+++ b/lib/init/bootcd
@@ -14,5 +14,3 @@
 ndb/dns -r
 ndb/cs
 #bind -a '#scs' /net
-
-
--- a/os/init/disinit.b
+++ b/os/init/disinit.b
@@ -50,6 +50,7 @@
 	sys->bind("#S", "/dev", sys->MAFTER);	# Disks
 #	sys->bind("#T","/dev",sys->MAFTER);		# Touchscreen
 #	sys->bind("#W","/dev",sys->MAFTER);		# Flash
+#	sys->bind("#o", "/proc", sys->MREPL);	# proc device
 
 	# set clock
 	#	does not handle bootp provided time source
--- a/os/pc64/errstr.h
+++ b/os/pc64/errstr.h
@@ -29,6 +29,7 @@
 char Ehungup[] = "i/o on hungup channel";
 char Ebadctl[] = "bad process or channel control request";
 char Enodev[] = "no free devices";
+char Eprocdied[] = "process exited";
 char Enoenv[] = "no free environment resources";
 char Ethread[] = "thread exited";
 char Estopped[] = "thread must be stopped";
@@ -54,6 +55,7 @@
 char Enobitstore[] = "out of screen memory";
 char Egreg[] = "jim'll fix it";
 char Ebadspec[] = "bad attach specifier";
+char Enoreg[] = "process has no saved registers";
 char Enoattach[] = "mount/attach disallowed";
 char Eshortstat[] = "stat buffer too small";
 char Ebadstat[] = "malformed stat buffer";
--- a/os/pc64/main.c
+++ b/os/pc64/main.c
@@ -299,6 +299,8 @@
 
 	strcpy(p->text, "interp");
 
+	pidalloc(p);
+
 	/*
 	 * Kernel Stack
 	 *
@@ -336,6 +338,8 @@
 		pcnt = 70;
 	conf.ialloc = (((conf.npage*(100-pcnt))/100)/2)*BY2PG;
 	conf.nproc = 100 + ((conf.npage*BY2PG)/MiB)*5;
+	if(conf.nproc > 2000)
+		conf.nproc = 2000;
 	print("conf.npage %zd conf.ialloc %zud conf.nproc %d\n",
 			conf.npage, conf.ialloc, conf.nproc);
 	USED(maxmem);
--- a/os/pc64/pc64
+++ b/os/pc64/pc64
@@ -6,6 +6,7 @@
 	env
 	mnt
 	pipe
+#	proc
 	prog
 	rtc
 	srv
--- a/os/port/error.h
+++ b/os/port/error.h
@@ -29,6 +29,7 @@
 extern char Ehungup[];		/* i/o on hungup channel */
 extern char Ebadctl[];		/* bad process or channel control request */
 extern char Enodev[];		/* no free devices */
+extern char Eprocdied[];	/* process exited */
 extern char Enoenv[];		/* no free environment resources */
 extern char Ethread[];		/* thread exited */
 extern char Estopped[];		/* thread must be stopped */
@@ -54,6 +55,7 @@
 extern char Enobitstore[];	/* out of screen memory */
 extern char Egreg[];		/* jim'll fix it */
 extern char Ebadspec[];		/* bad attach specifier */
+extern char Enoreg[];		/* process has no saved registers */
 extern char Enoattach[];	/* mount/attach disallowed */
 extern char Eshortstat[];	/* stat buffer too small */
 extern char Ebadstat[];		/* malformed stat buffer */
--- a/os/port/portdat.h
+++ b/os/port/portdat.h
@@ -503,7 +503,7 @@
 	void*		iprog;
 	Osenv*		env;
 	Osenv		defenv;
-	s32		swipend;	/* software interrupt pending for Prog */
+	s32		swipend;	/* software interrupt pending for Prog TODO replace with notepending? */
 	Lock		sysio;		/* note handler lock */
 	char*		psstate;	/* What /proc/#/status reports */
 	s32		pid;
@@ -557,6 +557,16 @@
 	s64	pcycles;
 
 	PMMU;				/* TODO obsolete? machine specific mmu state */
+
+	/* TODO 9front fields that need to incorporated into 9ferno */
+	/* TODO replace swiproc() with postnote() */
+	u32	noteid;		/* Equivalent of note group */
+	QLock	debug;		/* to access debugging elements of User */
+	int	trace;		/* process being traced? */
+	ulong	procmode;	/* proc device default file mode */
+	int	privatemem;	/* proc does not let anyone read mem */
+	int	noswap;		/* process is not swappable */
+	int	hang;		/* hang at next exec for debug */
 };
 
 enum
--- a/os/port/portfns.h
+++ b/os/port/portfns.h
@@ -202,6 +202,7 @@
 ulong		perfticks(void);
 void		pexit(char*, int);
 void		pgrpcpy(Pgrp*, Pgrp*);
+ulong		pidalloc(Proc*);
 #define		poperror()		up->nerrlab--
 int		poolread(char*, int, u64);
 void		poolsize(Pool *, u64, int);
@@ -212,6 +213,7 @@
 void		printinit(void);
 void		procctl(Proc*);
 void		procdump(void);
+int		procindex(ulong);
 void		procinit(void);
 Proc*		proctab(int);
 void	(*proctrace)(Proc*, int, vlong); 
@@ -274,8 +276,10 @@
 int		setcolor(u32, u32, u32, u32);
 int		setlabel(Label*);
 void		setmalloctag(void*, uintptr);
+ulong		setnoteid(Proc*, ulong);
 int		setpri(int);
 void		setrealloctag(void*, uintptr);
+void		setupwatchpts(Proc*, Watchpt*, int);
 void	showconf(void);
 char*		skipslash(char*);
 void		sleep(Rendez*, int(*)(void*), void*);
--- a/os/port/proc.c
+++ b/os/port/proc.c
@@ -6,7 +6,7 @@
 #include	"../port/error.h"
 #include	<interp.h>
 
-Ref	pidalloc;
+/* Ref	pidalloc; */
 int	schedgain = 30;	/* units in seconds */
 int	nrdy;
 
@@ -13,6 +13,7 @@
 ulong	delayedscheds;	/* statistics */
 ulong	skipscheds;
 ulong	preempts;
+s32	prevpid;
 
 /* bitmap of priorities of procs ready to run. When any process is
  * queued, the bit corresponding to that priority gets set.
@@ -33,7 +34,6 @@
  * Now, inferno maintains multiple Schedq based on priority.
  */
 static Schedq	runq[Nrq];
-static ulong	runvec;
 int	nrdy;
 
 char *statename[] =
@@ -53,6 +53,9 @@
 	"Waitrelease",
 };
 
+static void pidinit(void);
+static void pidfree(Proc*);
+
 /*
  * The kernel scheduler state is in m->sched. It is set to the address
  * of schedinit().
@@ -390,6 +393,16 @@
 	if(pt != nil)
 		pt(p, SRun, 0);
 */
+/*	if(p->pid != prevpid){
+		prevpid = p->pid;
+		if(p->type == Interp && p->iprog != nil){
+			print(" %d:%s,%d ",
+				p->pid, p->text, ((Prog*)p->iprog)->pid);
+		}else
+			print(" %d:%s", p->pid, p->text);
+	}else
+		print(".");
+*/
 	return p;
 }
 
@@ -407,9 +420,8 @@
 }
 
 /*
- * TODO
- *	add procwired() to set p->wired
- *  pid reuse
+ * not using memset 0 on the Proc structure
+ * to avoid leaking KSTACK
  */
 Proc*
 newproc(void)
@@ -451,10 +463,13 @@
 	p->mp = 0;
 	p->wired = 0;
 	p->edf = nil;
+	p->noteid = 0;
+	p->trace = 0;
 
-	p->pid = incref(&pidalloc);
+	/* replaced with pidalloc() in kproc */
+/*	p->pid = incref(&pidalloc);
 	if(p->pid == 0)
-		panic("pidalloc");
+		panic("pidalloc"); */
 	if(p->kstack == 0)
 		p->kstack = smalloc(KSTACK);
 	addprog(p);
@@ -482,6 +497,7 @@
 		p->qnext = p+1;
 	p->qnext = 0;
 
+	pidinit();
 	/* debugkey('p', "processes", procdump, 0); */
 }
 
@@ -643,7 +659,10 @@
 	return p;
 }
 
-
+/* TODO replace with postnote()
+ * man 9 tsleep of inferno
+ * man 9 postnote of 9front
+ */
 void
 swiproc(Proc *p, int interp)
 {
@@ -697,11 +716,15 @@
 /*
 	edfstop(up);
 */
+	qlock(&up->debug);
+	pidfree(up);
+	qunlock(&up->debug);
 	up->state = Moribund;
 	sched();
 	panic("pexit");
 }
 
+/* 9front uses a macro for this. why? */
 Proc*
 proctab(int i)
 {
@@ -753,6 +776,8 @@
 /* TODO		freebroken(); */
 		resrcwait("no procs for kproc");
 	}
+
+	qlock(&p->debug);
 	p->psstate = 0;
 	p->kp = 1;
 
@@ -778,10 +803,24 @@
 		p->env->egrp = eg;
 	}
 
+/*	p->nnote = 0;
+	p->notify = nil;
+	p->notified = 0;
+	p->notepending = 0;*/
+
+	p->procmode = 0640;
+	p->privatemem = 1;
+	p->noswap = 1;
+	p->hang = 0;
+	p->kp = 1;
 	kprocchild(p, func, arg);
 
 	strcpy(p->text, name);
 
+	pidalloc(p);
+
+	qunlock(&p->debug);
+
 	ready(p);
 }
 
@@ -1020,4 +1059,208 @@
 getpid(void)
 {
 	return up->pid;
+}
+
+/*
+ *  A Pid structure is a reference counted hashtable entry
+ *  with "pid" being the key and "procindex" being the value.
+ *  A entry is allocated atomically by changing the key from
+ *  negative or zero to the positive process id number.
+ *  Pid's outlive ther Proc's as long as other processes hold
+ *  a reference to them such as noteid or parentpid.
+ *  This prevents pid reuse when the pid generator wraps.
+ */
+typedef struct Pid Pid;
+struct Pid
+{
+	Ref;
+	long	pid;
+	int	procindex;
+};
+
+enum {
+	PIDMASK = 0x7FFFFFFF,
+	PIDSHIFT = 4,	/* log2 bucket size of the hash table */
+};
+
+static Pid *pidhashtab;
+static ulong pidhashmask;
+
+static void
+pidinit(void)
+{
+	/*
+	 * allocate 3 times conf.nproc Pid structures for the hash table
+	 * and round up to a power of two as each process can reference
+	 * up to 3 unique Pid structures:
+	 *	- pid
+	 *	- noteid
+	 *	- parentpid
+	 */
+	pidhashmask = 1<<PIDSHIFT;
+	while(pidhashmask < conf.nproc*3)
+		pidhashmask <<= 1;
+
+	pidhashtab = xalloc(pidhashmask * sizeof(pidhashtab[0]));
+	if(pidhashtab == nil){
+		xsummary();
+		panic("cannot allocate pid hashtable of size %lud", pidhashmask);
+	}
+
+	/* make it a mask */
+	pidhashmask--;
+}
+
+static Pid*
+pidlookup(long pid)
+{
+	Pid *i, *e;
+	long o;
+
+	i = &pidhashtab[(pid<<PIDSHIFT) & pidhashmask];
+	for(e = &i[1<<PIDSHIFT]; i < e; i++){
+		o = i->pid;
+		if(o == pid)
+			return i;
+		if(o == 0)
+			break;
+	}
+	return nil;
+}
+
+/*
+ *  increment the reference count of a pid (pid>0)
+ *  or allocate a new one (pid<=0)
+ */
+static Pid*
+pidadd(long pid)
+{
+	Pid *i, *e;
+	long o;
+
+	if(pid > 0){
+		i = pidlookup(pid);
+		if(i != nil)
+			incref(i);
+		return i;
+	}
+Again:
+	do {
+		static Ref gen;
+		pid = incref(&gen) & PIDMASK;
+	} while(pid == 0 || pidlookup(pid) != nil);
+
+	i = &pidhashtab[(pid<<PIDSHIFT) & pidhashmask];
+	for(e = &i[1<<PIDSHIFT]; i < e; i++){
+		while((o = i->pid) <= 0){
+			if(cmpswap((s32*)&i->pid, o, pid)){
+				incref(i);
+				return i;
+			}
+		}
+	}
+	/* bucket full, try a different pid */
+	goto Again;
+}
+
+/*
+ *  decrement reference count of a pid and free it
+ *  when no references are remaining
+ */
+static void
+piddel(Pid *i)
+{
+	if(decref(i))
+		return;
+	i->pid = -1;	/* freed */
+}
+
+int
+procindex(ulong pid)
+{
+	Pid *i;
+
+	i = pidlookup(pid);
+	if(i != nil){
+		int x = i->procindex;
+		if(proctab(x)->pid == pid)
+			return x;
+	}
+	return -1;
+}
+
+ulong
+setnoteid(Proc *p, ulong noteid)
+{
+	Pid *i, *o;
+
+	/*
+	 * avoid allocating a new pid when we are the only
+	 * user of the noteid
+	 */
+	o = pidlookup(p->noteid);
+	if(noteid == 0 && o->ref == 1)
+		return o->pid;
+
+	i = pidadd(noteid);
+	if(i == nil)
+		error(Ebadarg);
+	piddel(o);
+	return p->noteid = i->pid;
+}
+
+/*
+static ulong
+setparentpid(Proc *p, Proc *pp)
+{
+	Pid *i;
+
+	i = pidadd(pp->pid);
+	return p->parentpid = i->pid;
+} */
+
+/*
+ *  allocate pid, noteid and parentpid to a process
+ */
+ulong
+pidalloc(Proc *p)
+{
+	Pid *i;
+
+	/* skip for the boot process */
+/*	if(up != nil)
+		setparentpid(p, up);*/
+	i = pidadd(0);
+	i->procindex = (int)(p - procalloc.arena);
+
+	if(p->noteid == 0){
+		incref(i);
+		p->noteid = i->pid;
+	} else
+		pidadd(p->noteid);
+
+	return p->pid = i->pid;
+}
+
+/*
+ *  release pid, noteid and parentpid from a process
+ */
+static void
+pidfree(Proc *p)
+{
+	Pid *i;
+
+	i = pidlookup(p->pid);
+	piddel(i);
+
+	if(p->noteid != p->pid)
+		i = pidlookup(p->noteid);
+	piddel(i);
+
+/*	if(p->parentpid != 0)
+		piddel(pidlookup(p->parentpid));
+
+	p->pid = p->noteid = p->parentpid = 0;
+*/
+	p->pid = p->noteid = 0;
 }