ref: 0977f294bab0345ba43fbf674449fd8e996c5719
parent: 22e770f3183a6afa8064a75cf9aaae21de8eac08
author: 9ferno <[email protected]>
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;
}