ref: f5595b832b2be50d7d641fbaa7085d07f649feb2
parent: d20bb0fcd322e5f690f0ae5f35758845680a1560
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Mon Jan 5 06:40:34 EST 2026
stats: automatic reconnect (thanks rodri) Do machinit() in their own process and have a supervisor restart processes as needed. This means connect can now run in parallel and disconnected status is indicated by hourglass in the column title.
--- a/sys/src/cmd/stats.c
+++ b/sys/src/cmd/stats.c
@@ -66,6 +66,8 @@
char *shortname;
int pid;
+ int nproc;
+
int statsfd;
int swapfd;
int etherfd[10];
@@ -75,8 +77,6 @@
uvlong devswap[10];
uvlong devsysstat[10];
uvlong prevsysstat[10];
- int nproc;
- int lgproc;
uvlong netetherstats[9];
uvlong prevetherstats[9];
uvlong batterystats[2];
@@ -214,19 +214,12 @@
int sleeptime = 1000;
int batteryperiod = 10000;
int tempperiod = 1000;
+int superpid = 0;
void
killall(void)
{- int i;
-
- if(mach == nil)
- return;
- for(i=0; i<nmach; i++){- if(mach[i].pid <= 0)
- continue;
- postnote(PNPROC, mach[i].pid, "kill");
- }
+ postnote(PNGROUP, superpid, "kill");
}
void*
@@ -233,9 +226,8 @@
emalloc(ulong sz)
{void *v;
- v = malloc(sz);
- if(v == nil)
- sysfatal("out of memory allocating %ld: %r", sz);+ if((v = malloc(sz)) == nil)
+ sysfatal("malloc: %r");memset(v, 0, sz);
return v;
}
@@ -243,9 +235,8 @@
void*
erealloc(void *v, ulong sz)
{- v = realloc(v, sz);
- if(v == nil)
- sysfatal("out of memory reallocating %ld: %r", sz);+ if((v = realloc(v, sz)) == nil && sz != 0)
+ sysfatal("realloc: %r");return v;
}
@@ -252,10 +243,9 @@
char*
estrdup(char *s)
{- char *t;
- if((t = strdup(s)) == nil)
- sysfatal("out of memory in strdup(%.10s): %r", s);- return t;
+ if((s = strdup(s)) == nil)
+ sysfatal("strdup: %r");+ return s;
}
void
@@ -285,19 +275,38 @@
cols[5][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x888888FF);
}
+void
+checkhung(void)
+{+ static char Ehungup[] = "i/o on hungup channel";
+ char err[ERRMAX];
+
+ rerrstr(err, sizeof(err));
+ if(strncmp(err, Ehungup, sizeof(Ehungup)-1) == 0)
+ exits("restart"); /* let supervisor handle restart */+}
+
int
+eopen(char *name, int mode)
+{+ int fd;
+
+ if((fd = open(name, mode)) < 0)
+ checkhung();
+ return fd;
+}
+
+int
loadbuf(Machine *m, int *fd)
{int n;
-
if(*fd < 0)
return 0;
seek(*fd, 0, 0);
n = read(*fd, m->buf, sizeof m->buf-1);
- if(n <= 0){- close(*fd);
- *fd = -1;
+ if(n < 0){+ checkhung();
return 0;
}
m->bufp = m->buf;
@@ -650,59 +659,66 @@
return i;
}
-int
-initmach(Machine *m, char *name)
+void
+initmach(Machine *m)
{int n, i, j, fd;
uvlong a[MAXNUM];
- char *p, mpt[256], buf[256];
+ char *p, buf[256];
Dir *d;
- static char *archplaces[] = {- "/dev",
- "/mnt/pm",
- "/mnt/apm", /* battery only */
+ static char *batteries[] = {+ "dev/battery",
+ "mnt/pm/battery",
+ "mnt/apm/battery",
};
-
- p = strchr(name, '!');
+ static char *cputemps[] = {+ "dev/cputemp",
+ "mnt/pm/cputemp",
+ };
+ p = strchr(m->name, '!');
if(p)
p++;
else
- p = name;
- m->name = estrdup(p);
- m->shortname = shortname(p);
+ p = m->name;
if(strcmp(p, mysysname) == 0)
- strcpy(mpt, "");
+ strcpy(buf, "/");
else{Waitmsg *w;
int pid;
- snprint(mpt, sizeof mpt, "/n/%s", p);
+ rfork(RFNAMEG);
+ snprint(buf, sizeof buf, "/n/%s/", p);
pid = fork();
switch(pid){case -1:
- fprint(2, "can't fork: %r\n");
- return 0;
+ sysfatal("fork: %r");case 0:
- execl("/bin/rimport", "rimport", name, "/", mpt, nil);- fprint(2, "can't exec: %r\n");
- exits("exec");+ close(2), open("/dev/null", OWRITE); /* >[2] /dev/null */+ execl("/bin/rimport", "rimport", m->name, "/", buf, nil);+ sysfatal("exec: %r");}
- w = wait();
- if(w == nil || w->pid != pid || w->msg[0] != '\0'){+ while((w = wait()) != nil){+ if(w->pid == pid)
+ break;
free(w);
- return 0;
}
+ if(w == nil || w->msg[0] != '\0'){+ free(w);
+ exits("restart"); /* supervisor restarts */+ }
free(w);
}
+ if(chdir(buf) < 0){+ checkhung();
+ sysfatal("chdir: %r");+ }
- snprint(buf, sizeof buf, "%s/dev/swap", mpt);
- m->swapfd = open(buf, OREAD);
+ m->swapfd = eopen("dev/swap", OREAD);if(loadbuf(m, &m->swapfd) && readswap(m, a))
memmove(m->devswap, a, sizeof m->devswap);
- snprint(buf, sizeof buf, "%s/dev/sysstat", mpt);
- m->statsfd = open(buf, OREAD);
+ m->statsfd = eopen("dev/sysstat", OREAD); if(loadbuf(m, &m->statsfd)){for(n=0; readnums(m, nelem(m->devsysstat), a, 0); n++)
;
@@ -709,18 +725,16 @@
m->nproc = n;
}else
m->nproc = 1;
- m->lgproc = ilog10(m->nproc);
/* find all the ethernets */
n = 0;
- snprint(buf, sizeof buf, "%s/net/", mpt);
- if((fd = open(buf, OREAD)) >= 0){+ if((fd = eopen("net/", OREAD)) >= 0){ for(d = nil; (i = dirread(fd, &d)) > 0; free(d)){ for(j=0; j<i; j++){if(strncmp(d[j].name, "ether", 5))
continue;
- snprint(buf, sizeof buf, "%s/net/%s/stats", mpt, d[j].name);
- if((m->etherfd[n] = open(buf, OREAD)) < 0)
+ snprint(buf, sizeof buf, "net/%s/stats", d[j].name);
+ if((m->etherfd[n] = eopen(buf, OREAD)) < 0)
continue;
if(++n >= nelem(m->etherfd))
break;
@@ -728,24 +742,22 @@
if(n >= nelem(m->etherfd))
break;
}
+ if(i < 0)
+ checkhung();
close(fd);
}
while(n < nelem(m->etherfd))
m->etherfd[n++] = -1;
- for(i=0; i < nelem(archplaces); i++){- snprint(buf, sizeof buf, "%s/%s/battery", mpt, archplaces[i]);
- m->batteryfd = open(buf, OREAD);
- if(m->batteryfd < 0)
+ for(i=0; i < nelem(batteries); i++){+ if((m->batteryfd = eopen(batteries[i], OREAD)) < 0)
continue;
if(loadbuf(m, &m->batteryfd) && readnums(m, nelem(m->batterystats), a, 0))
memmove(m->batterystats, a, sizeof(m->batterystats));
break;
}
- for(i=0; i < nelem(archplaces); i++){- snprint(buf, sizeof buf, "%s/%s/cputemp", mpt, archplaces[i]);
- m->tempfd = open(buf, OREAD);
- if(m->tempfd < 0)
+ for(i=0; i < nelem(cputemps); i++){+ if((m->tempfd = eopen(cputemps[i], OREAD)) < 0)
continue;
if(loadbuf(m, &m->tempfd))
for(n=0; n < nelem(m->temp) && readnums(m, 2, a, 0); n++)
@@ -752,7 +764,6 @@
m->temp[n] = a[0];
break;
}
- return 1;
}
int
@@ -824,6 +835,7 @@
memset(m->devsysstat, 0, sizeof m->devsysstat);
for(n=0; n<m->nproc && readnums(m, nelem(m->devsysstat), a, 0); n++)
vadd(m->devsysstat, a, nelem(m->devsysstat));
+ if(init) memmove(m->prevsysstat, m->devsysstat, sizeof m->devsysstat);
}
if(needether(init)){memmove(m->prevetherstats, m->netetherstats, sizeof m->netetherstats);
@@ -832,6 +844,7 @@
if(loadbuf(m, &m->etherfd[n]) && readnums(m, nelem(m->netetherstats), a, 1))
vadd(m->netetherstats, a, nelem(m->netetherstats));
}
+ if(init) memmove(m->prevetherstats, m->netetherstats, sizeof m->netetherstats);
}
if(needbattery(init)){if(loadbuf(m, &m->batteryfd) && readnums(m, nelem(m->batterystats), a, 0))
@@ -864,8 +877,6 @@
{*v = m->devswap[Mem];
*vmax = m->devswap[Maxmem];
- if(*vmax == 0)
- *vmax = 1;
}
void
@@ -873,8 +884,6 @@
{*v = m->devswap[Swap];
*vmax = m->devswap[Maxswap];
- if(*vmax == 0)
- *vmax = 1;
}
void
@@ -882,8 +891,6 @@
{*v = m->devswap[Reclaim];
*vmax = m->devswap[Maxreclaim];
- if(*vmax == 0)
- *vmax = 1;
}
void
@@ -891,8 +898,6 @@
{*v = m->devswap[Kern];
*vmax = m->devswap[Maxkern];
- if(*vmax == 0)
- *vmax = 1;
}
void
@@ -900,8 +905,6 @@
{*v = m->devswap[Draw];
*vmax = m->devswap[Maxdraw];
- if(*vmax == 0)
- *vmax = 1;
}
void
@@ -973,7 +976,8 @@
void
idleval(Machine *m, uvlong *v, uvlong *vmax, int)
{- *v = m->devsysstat[Idle]/m->nproc;
+ *v = m->devsysstat[Idle];
+ if(m->nproc) *v /= m->nproc;
*vmax = 100;
}
@@ -980,7 +984,8 @@
void
inintrval(Machine *m, uvlong *v, uvlong *vmax, int)
{- *v = m->devsysstat[InIntr]/m->nproc;
+ *v = m->devsysstat[InIntr];
+ if(m->nproc) *v /= m->nproc;
*vmax = 100;
}
@@ -1123,18 +1128,45 @@
{mach = erealloc(mach, (nmach+1)*sizeof(Machine));
memset(mach+nmach, 0, sizeof(Machine));
- if (initmach(mach+nmach, name))
- nmach++;
+ mach[nmach].name = estrdup(name);
+ mach[nmach].shortname = shortname(name);
+ nmach++;
}
+int
+drawtitle(Machine *m)
+{+ int j, n, l, x, y, dx;
+ char buf[128];
+
+ x = screen->r.min.x+Labspace+stringwidth(font, "0")+Labspace+1;
+ y = screen->r.min.y+Labspace+font->height+Labspace;
+ dx = (screen->r.max.x-x)/nmach;
+ x += (m-mach)*dx;
+ draw(screen, Rect(x, screen->r.min.y, x+dx, y-1), display->white, nil, ZP);
+ j = dx/stringwidth(font, "0");
+ n = m->nproc;
+ if(n>1 && j>=1+3+(l = ilog10(n))){ /* first char of name + (n) */+ j -= 3+l;
+ if(j <= 0)
+ j = 1;
+ snprint(buf, sizeof buf, "%.*s(%d)", j, m->shortname, n);
+ }else if(n > 0){+ snprint(buf, sizeof buf, "%.*s", j, m->shortname);
+ }else{+ snprint(buf, sizeof buf, "%.*s ⌛", j, m->shortname);
+ }
+ string(screen, Pt(x+Labspace, screen->r.min.y + Labspace), display->black, ZP, font, buf);
+ return x;
+}
+
void
resize(void)
{- int i, j, n, startx, starty, x, y, dx, dy, ondata, maxx;
+ int i, j, startx, starty, x, y, dx, dy, ondata, maxx;
Graph *g;
Rectangle machr, r;
uvlong v, vmax;
- char buf[128];
draw(screen, screen->r, display->white, nil, ZP);
@@ -1153,19 +1185,12 @@
}
/* label top edge */
- dx = (screen->r.max.x - startx)/nmach;
- for(x=startx, i=0; i<nmach; i++,x+=dx){+ dx = screen->r.max.x - startx;
+ startx = x = drawtitle(mach);
+ for(i=1; i<nmach; i++){+ dx = drawtitle(mach+i) - x;
+ x += dx;
draw(screen, Rect(x-1, starty-1, x, screen->r.max.y), display->black, nil, ZP);
- j = dx/stringwidth(font, "0");
- n = mach[i].nproc;
- if(n>1 && j>=1+3+mach[i].lgproc){ /* first char of name + (n) */- j -= 3+mach[i].lgproc;
- if(j <= 0)
- j = 1;
- snprint(buf, sizeof buf, "%.*s(%d)", j, mach[i].shortname, n);
- }else
- snprint(buf, sizeof buf, "%.*s", j, mach[i].shortname);
- string(screen, Pt(x+Labspace, screen->r.min.y + Labspace), display->black, ZP, font, buf);
}
maxx = screen->r.max.x;
@@ -1214,6 +1239,42 @@
flushimage(display, 1);
}
+int
+machproc(Machine *m, int delay)
+{+ int pid;
+
+ m->nproc = 0;
+ if((pid = rfork(RFPROC|RFMEM|RFFDG)) == 0){+ procsetname("%s", m->shortname);+ if(delay){+ lockdisplay(display);
+ drawtitle(m);
+ flushimage(display, 1);
+ unlockdisplay(display);
+ sleep(delay);
+ }
+ initmach(m);
+ readmach(m, 1);
+ lockdisplay(display);
+ drawtitle(m);
+ for(;;) {+ parity = pid++ & 1;
+ updatemach(m);
+ flushimage(display, 1);
+ unlockdisplay(display);
+
+ sleep(sleeptime);
+
+ readmach(m, 0);
+ lockdisplay(display);
+ }
+ }
+ if(pid < 0)
+ sysfatal("rfork: %r");+ return pid;
+}
+
void
eresized(int new)
{@@ -1228,6 +1289,8 @@
main(int argc, char *argv[])
{Event e;
+ Waitmsg *w;
+ Machine *m;
int i, j;
double secs;
char args[100];
@@ -1270,7 +1333,6 @@
if(argc == 0){addmachine(mysysname);
}else{- rfork(RFNAMEG);
for(i=0; i<argc; i++)
addmachine(argv[i]);
}
@@ -1352,30 +1414,35 @@
}
if(initdraw(nil, nil, "stats") < 0)
- sysfatal("initdraw failed: %r");+ sysfatal("initdraw: %r");colinit();
einit(Emouse|Ekeyboard);
resize();
unlockdisplay(display);
- atexit(killall);
- for(i=0; i<nmach; i++){- if((j = rfork(RFPROC|RFMEM)) == 0){- procsetname("%s", mach[i].shortname);- readmach(&mach[i], 1);
- for(;;) {- lockdisplay(display);
- parity = j++ & 1;
- updatemach(&mach[i]);
- flushimage(display, 1);
- unlockdisplay(display);
-
- sleep(sleeptime);
- readmach(&mach[i], 0);
- }
+ switch(j = rfork(RFPROC|RFMEM|RFNOTEG)){+ case -1:
+ sysfatal("fork: %r");+ case 0:
+ procsetname("supervisor");+ for(m = mach; m < mach+nmach; m++)
+ m->pid = machproc(m, 0);
+ while((w = wait()) != nil){+ /* replace child labourer like it's the 1830s */
+ for(m = mach; m < mach+nmach; m++)
+ if(m->pid == w->pid){+ if(strstr(w->msg, "restart") != nil)
+ m->pid = machproc(m, 5000);
+ else
+ m->pid = 0;
+ break;
+ }
+ free(w);
}
- mach[i].pid = j;
+ sysfatal("no children left");}
+ superpid = j;
+ atexit(killall);
for(;;)
switch(eread(Emouse|Ekeyboard, &e)){--
⑨