Blob


1 #include <u.h>
2 #include <libc.h>
3 #include <ctype.h>
4 #include <auth.h>
5 #include <fcall.h>
6 #include <draw.h>
7 #include <thread.h>
8 #include <mouse.h>
9 #include <keyboard.h>
11 typedef struct Graph Graph;
12 typedef struct Machine Machine;
14 enum
15 {
16 Ncolor = 6,
17 Ysqueeze = 2, /* vertical squeezing of label text */
18 Labspace = 2, /* room around label */
19 Dot = 2, /* height of dot */
20 Opwid = 5, /* strlen("add ") or strlen("drop ") */
21 Nlab = 3, /* max number of labels on y axis */
22 Lablen = 16, /* max length of label */
23 Lx = 4, /* label tick length */
25 STACK = 8192,
26 XSTACK = 32768,
27 };
29 enum
30 {
31 Vbattery,
32 Vcontext,
33 Vcpu,
34 Vether,
35 Vethererr,
36 Vetherin,
37 Vetherout,
38 Vfault,
39 Vfork,
40 Vidle,
41 Vintr,
42 Vload,
43 Vmem,
44 Vswap,
45 Vsys,
46 Vsyscall,
47 Vuser,
48 Nvalue,
49 };
51 char*
52 labels[Nvalue] =
53 {
54 "battery",
55 "context",
56 "cpu",
57 "ether",
58 "ethererr",
59 "etherin",
60 "etherout",
61 "fault",
62 "fork",
63 "idle",
64 "intr",
65 "load",
66 "mem",
67 "swap",
68 "sys",
69 "syscall",
70 "user",
71 };
73 struct Graph
74 {
75 int colindex;
76 Rectangle r;
77 int *data;
78 int ndata;
79 char *label;
80 int value;
81 void (*update)(Graph*, long, ulong);
82 Machine *mach;
83 int overflow;
84 Image *overtmp;
85 ulong vmax;
86 };
88 struct Machine
89 {
90 char *name;
91 int fd;
92 int pid;
93 int dead;
94 int absolute[Nvalue];
95 ulong last[Nvalue];
96 ulong val[Nvalue][2];
97 ulong load;
98 ulong nload;
99 };
101 char *menu2str[Nvalue+1];
102 char xmenu2str[Nvalue+1][40];
104 Menu menu2 = {menu2str, 0};
105 int present[Nvalue];
106 Image *cols[Ncolor][3];
107 Graph *graph;
108 Machine *mach;
109 Font *mediumfont;
110 char *fontname;
111 char *mysysname;
112 char argchars[] = "bcCeEfiIlmnsw";
113 int pids[1024];
114 int parity; /* toggled to avoid patterns in textured background */
115 int nmach;
116 int ngraph; /* totaly number is ngraph*nmach */
117 double scale = 1.0;
118 int logscale = 0;
119 int ylabels = 0;
120 int oldsystem = 0;
121 int sleeptime = 1000;
122 int changedvmax;
124 Mousectl *mc;
125 Keyboardctl *kc;
127 void
128 killall(char *s)
130 int i;
132 for(i=0; i<nmach; i++)
133 if(mach[i].pid)
134 postnote(PNPROC, mach[i].pid, "kill");
135 threadexitsall(s);
138 void*
139 emalloc(ulong sz)
141 void *v;
142 v = malloc(sz);
143 if(v == nil) {
144 fprint(2, "stats: out of memory allocating %ld: %r\n", sz);
145 killall("mem");
147 memset(v, 0, sz);
148 return v;
151 void*
152 erealloc(void *v, ulong sz)
154 v = realloc(v, sz);
155 if(v == nil) {
156 fprint(2, "stats: out of memory reallocating %ld: %r\n", sz);
157 killall("mem");
159 return v;
162 char*
163 estrdup(char *s)
165 char *t;
166 if((t = strdup(s)) == nil) {
167 fprint(2, "stats: out of memory in strdup(%.10s): %r\n", s);
168 killall("mem");
170 return t;
173 void
174 mkcol(int i, int c0, int c1, int c2)
176 cols[i][0] = allocimagemix(display, c0, DWhite);
177 cols[i][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c1);
178 cols[i][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, c2);
181 void
182 colinit(void)
184 if(fontname)
185 mediumfont = openfont(display, fontname);
186 if(mediumfont == nil)
187 mediumfont = openfont(display, "/lib/font/bit/pelm/latin1.8.font");
188 if(mediumfont == nil)
189 mediumfont = font;
191 /* Peach */
192 mkcol(0, 0xFFAAAAFF, 0xFFAAAAFF, 0xBB5D5DFF);
193 /* Aqua */
194 mkcol(1, DPalebluegreen, DPalegreygreen, DPurpleblue);
195 /* Yellow */
196 mkcol(2, DPaleyellow, DDarkyellow, DYellowgreen);
197 /* Green */
198 mkcol(3, DPalegreen, DMedgreen, DDarkgreen);
199 /* Blue */
200 mkcol(4, 0x00AAFFFF, 0x00AAFFFF, 0x0088CCFF);
201 /* Grey */
202 cols[5][0] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xEEEEEEFF);
203 cols[5][1] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0xCCCCCCFF);
204 cols[5][2] = allocimage(display, Rect(0,0,1,1), CMAP8, 1, 0x888888FF);
207 void
208 label(Point p, int dy, char *text)
210 char *s;
211 Rune r[2];
212 int w, maxw, maxy;
214 p.x += Labspace;
215 maxy = p.y+dy;
216 maxw = 0;
217 r[1] = '\0';
218 for(s=text; *s; ){
219 if(p.y+mediumfont->height-Ysqueeze > maxy)
220 break;
221 w = chartorune(r, s);
222 s += w;
223 w = runestringwidth(mediumfont, r);
224 if(w > maxw)
225 maxw = w;
226 runestring(screen, p, display->black, ZP, mediumfont, r);
227 p.y += mediumfont->height-Ysqueeze;
231 Point
232 paritypt(int x)
234 return Pt(x+parity, 0);
237 Point
238 datapoint(Graph *g, int x, ulong v, ulong vmax)
240 Point p;
241 double y;
243 p.x = x;
244 y = ((double)v)/(vmax*scale);
245 if(logscale){
246 /*
247 * Arrange scale to cover a factor of 1000.
248 * vmax corresponds to the 100 mark.
249 * 10*vmax is the top of the scale.
250 */
251 if(y <= 0.)
252 y = 0;
253 else{
254 y = log10(y);
255 /* 1 now corresponds to the top; -2 to the bottom; rescale */
256 y = (y+2.)/3.;
259 p.y = g->r.max.y - Dy(g->r)*y - Dot;
260 if(p.y < g->r.min.y)
261 p.y = g->r.min.y;
262 if(p.y > g->r.max.y-Dot)
263 p.y = g->r.max.y-Dot;
264 return p;
267 void
268 drawdatum(Graph *g, int x, ulong prev, ulong v, ulong vmax)
270 int c;
271 Point p, q;
273 c = g->colindex;
274 p = datapoint(g, x, v, vmax);
275 q = datapoint(g, x, prev, vmax);
276 if(p.y < q.y){
277 draw(screen, Rect(p.x, g->r.min.y, p.x+1, p.y), cols[c][0], nil, paritypt(p.x));
278 draw(screen, Rect(p.x, p.y, p.x+1, q.y+Dot), cols[c][2], nil, ZP);
279 draw(screen, Rect(p.x, q.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP);
280 }else{
281 draw(screen, Rect(p.x, g->r.min.y, p.x+1, q.y), cols[c][0], nil, paritypt(p.x));
282 draw(screen, Rect(p.x, q.y, p.x+1, p.y+Dot), cols[c][2], nil, ZP);
283 draw(screen, Rect(p.x, p.y+Dot, p.x+1, g->r.max.y), cols[c][1], nil, ZP);
288 void
289 redraw(Graph *g, int vmax)
291 int i, c;
293 if(vmax != g->vmax){
294 g->vmax = vmax;
295 changedvmax = 1;
297 c = g->colindex;
298 draw(screen, g->r, cols[c][0], nil, paritypt(g->r.min.x));
299 for(i=1; i<Dx(g->r); i++)
300 drawdatum(g, g->r.max.x-i, g->data[i-1], g->data[i], vmax);
301 drawdatum(g, g->r.min.x, g->data[i], g->data[i], vmax);
302 g->overflow = 0;
305 void
306 update1(Graph *g, long v, ulong vmax)
308 char buf[32];
309 int overflow;
311 if(v < 0)
312 v = 0;
313 if(vmax != g->vmax){
314 g->vmax = vmax;
315 changedvmax = 1;
317 if(g->overflow && g->overtmp!=nil)
318 draw(screen, g->overtmp->r, g->overtmp, nil, g->overtmp->r.min);
319 draw(screen, g->r, screen, nil, Pt(g->r.min.x+1, g->r.min.y));
320 drawdatum(g, g->r.max.x-1, g->data[0], v, vmax);
321 memmove(g->data+1, g->data, (g->ndata-1)*sizeof(g->data[0]));
322 g->data[0] = v;
323 g->overflow = 0;
324 if(logscale)
325 overflow = (v>10*vmax*scale);
326 else
327 overflow = (v>vmax*scale);
328 if(overflow && g->overtmp!=nil){
329 g->overflow = 1;
330 draw(g->overtmp, g->overtmp->r, screen, nil, g->overtmp->r.min);
331 sprint(buf, "%ld", v);
332 string(screen, g->overtmp->r.min, display->black, ZP, mediumfont, buf);
336 void
337 usage(void)
339 fprint(2, "usage: stats [-LY] [-F font] [-O] [-S scale] [-W winsize] [-%s] [machine...]\n", argchars);
340 threadexitsall("usage");
343 void
344 addgraph(int n)
346 Graph *g, *ograph;
347 int i, j;
348 static int nadd;
350 if(n > Nvalue)
351 abort();
352 /* avoid two adjacent graphs of same color */
353 if(ngraph>0 && graph[ngraph-1].colindex==nadd%Ncolor)
354 nadd++;
355 ograph = graph;
356 graph = emalloc(nmach*(ngraph+1)*sizeof(Graph));
357 for(i=0; i<nmach; i++)
358 for(j=0; j<ngraph; j++)
359 graph[i*(ngraph+1)+j] = ograph[i*ngraph+j];
360 free(ograph);
361 ngraph++;
362 for(i=0; i<nmach; i++){
363 g = &graph[i*ngraph+(ngraph-1)];
364 memset(g, 0, sizeof(Graph));
365 g->value = n;
366 g->label = menu2str[n]+Opwid;
367 g->update = update1; /* no other update functions yet */
368 g->mach = &mach[i];
369 g->colindex = nadd%Ncolor;
371 present[n] = 1;
372 nadd++;
375 void
376 dropgraph(int which)
378 Graph *ograph;
379 int i, j, n;
381 if(which > nelem(menu2str))
382 abort();
383 /* convert n to index in graph table */
384 n = -1;
385 for(i=0; i<ngraph; i++)
386 if(strcmp(menu2str[which]+Opwid, graph[i].label) == 0){
387 n = i;
388 break;
390 if(n < 0){
391 fprint(2, "stats: internal error can't drop graph\n");
392 killall("error");
394 ograph = graph;
395 graph = emalloc(nmach*(ngraph-1)*sizeof(Graph));
396 for(i=0; i<nmach; i++){
397 for(j=0; j<n; j++)
398 graph[i*(ngraph-1)+j] = ograph[i*ngraph+j];
399 free(ograph[i*ngraph+j].data);
400 freeimage(ograph[i*ngraph+j].overtmp);
401 for(j++; j<ngraph; j++)
402 graph[i*(ngraph-1)+j-1] = ograph[i*ngraph+j];
404 free(ograph);
405 ngraph--;
406 present[which] = 0;
409 int initmach(Machine*, char*);
411 int
412 addmachine(char *name)
414 if(ngraph > 0){
415 fprint(2, "stats: internal error: ngraph>0 in addmachine()\n");
416 usage();
418 if(mach == nil)
419 nmach = 0; /* a little dance to get us started with local machine by default */
420 mach = erealloc(mach, (nmach+1)*sizeof(Machine));
421 memset(mach+nmach, 0, sizeof(Machine));
422 if (initmach(mach+nmach, name)){
423 nmach++;
424 return 1;
425 } else
426 return 0;
429 void
430 newvalue(Machine *m, int i, ulong *v, ulong *vmax)
432 ulong now;
434 if(m->last[i] == 0)
435 m->last[i] = m->val[i][0];
437 if(i == Vload){
438 /*
439 * Invert the ewma to obtain the 5s load statistics.
440 * Ewma is load' = (1884/2048)*load + (164/2048)*last5s, so we do
441 * last5s = (load' - (1884/2048)*load) / (164/2048).
442 */
443 if(++m->nload%5 == 0){
444 now = m->val[i][0];
445 m->load = (now - (((vlong)m->last[i]*1884)/2048)) * 2048 / 164;
446 m->last[i] = now;
448 *v = m->load;
449 *vmax = m->val[i][1];
450 }else if(m->absolute[i]){
451 *v = m->val[i][0];
452 *vmax = m->val[i][1];
453 }else{
454 now = m->val[i][0];
455 *v = (vlong)((now - m->last[i])*sleeptime)/1000;
456 m->last[i] = now;
457 *vmax = m->val[i][1];
459 if(*vmax == 0)
460 *vmax = 1;
463 void
464 labelstrs(Graph *g, char strs[Nlab][Lablen], int *np)
466 int j;
467 ulong vmax;
469 vmax = g->vmax;
470 if(logscale){
471 for(j=1; j<=2; j++)
472 sprint(strs[j-1], "%g", scale*pow(10., j)*(double)vmax/100.);
473 *np = 2;
474 }else{
475 for(j=1; j<=3; j++)
476 sprint(strs[j-1], "%g", scale*(double)j*(double)vmax/4.0);
477 *np = 3;
481 int
482 labelwidth(void)
484 int i, j, n, w, maxw;
485 char strs[Nlab][Lablen];
487 maxw = 0;
488 for(i=0; i<ngraph; i++){
489 /* choose value for rightmost graph */
490 labelstrs(&graph[ngraph*(nmach-1)+i], strs, &n);
491 for(j=0; j<n; j++){
492 w = stringwidth(mediumfont, strs[j]);
493 if(w > maxw)
494 maxw = w;
497 return maxw;
500 void
501 resize(void)
503 int i, j, k, n, startx, starty, x, y, dx, dy, ly, ondata, maxx, wid, nlab;
504 Graph *g;
505 Rectangle machr, r;
506 ulong v, vmax;
507 char buf[128], labs[Nlab][Lablen];
509 draw(screen, screen->r, display->white, nil, ZP);
511 /* label left edge */
512 x = screen->r.min.x;
513 y = screen->r.min.y + Labspace+mediumfont->height+Labspace;
514 dy = (screen->r.max.y - y)/ngraph;
515 dx = Labspace+stringwidth(mediumfont, "0")+Labspace;
516 startx = x+dx+1;
517 starty = y;
518 for(i=0; i<ngraph; i++,y+=dy){
519 draw(screen, Rect(x, y-1, screen->r.max.x, y), display->black, nil, ZP);
520 draw(screen, Rect(x, y, x+dx, screen->r.max.y), cols[graph[i].colindex][0], nil, paritypt(x));
521 label(Pt(x, y), dy, graph[i].label);
522 draw(screen, Rect(x+dx, y, x+dx+1, screen->r.max.y), cols[graph[i].colindex][2], nil, ZP);
525 /* label top edge */
526 dx = (screen->r.max.x - startx)/nmach;
527 for(x=startx, i=0; i<nmach; i++,x+=dx){
528 draw(screen, Rect(x-1, starty-1, x, screen->r.max.y), display->black, nil, ZP);
529 j = dx/stringwidth(mediumfont, "0");
530 // n = mach[i].nproc;
531 n = 1;
532 if(n>1 && j>=1+3+(n>10)+(n>100)){ /* first char of name + (n) */
533 j -= 3+(n>10)+(n>100);
534 if(j <= 0)
535 j = 1;
536 snprint(buf, sizeof buf, "%.*s(%d)", j, mach[i].name, n);
537 }else
538 snprint(buf, sizeof buf, "%.*s", j, mach[i].name);
539 string(screen, Pt(x+Labspace, screen->r.min.y + Labspace), display->black, ZP, mediumfont, buf);
542 maxx = screen->r.max.x;
544 /* label right, if requested */
545 if(ylabels && dy>Nlab*(mediumfont->height+1)){
546 wid = labelwidth();
547 if(wid < (maxx-startx)-30){
548 /* else there's not enough room */
549 maxx -= 1+Lx+wid;
550 draw(screen, Rect(maxx, starty, maxx+1, screen->r.max.y), display->black, nil, ZP);
551 y = starty;
552 for(j=0; j<ngraph; j++, y+=dy){
553 /* choose value for rightmost graph */
554 g = &graph[ngraph*(nmach-1)+j];
555 labelstrs(g, labs, &nlab);
556 r = Rect(maxx+1, y, screen->r.max.x, y+dy-1);
557 if(j == ngraph-1)
558 r.max.y = screen->r.max.y;
559 draw(screen, r, cols[g->colindex][0], nil, paritypt(r.min.x));
560 for(k=0; k<nlab; k++){
561 ly = y + (dy*(nlab-k)/(nlab+1));
562 draw(screen, Rect(maxx+1, ly, maxx+1+Lx, ly+1), display->black, nil, ZP);
563 ly -= mediumfont->height/2;
564 string(screen, Pt(maxx+1+Lx, ly), display->black, ZP, mediumfont, labs[k]);
570 /* create graphs */
571 for(i=0; i<nmach; i++){
572 machr = Rect(startx+i*dx, starty, maxx, screen->r.max.y);
573 if(i < nmach-1)
574 machr.max.x = startx+(i+1)*dx - 1;
575 y = starty;
576 for(j=0; j<ngraph; j++, y+=dy){
577 g = &graph[i*ngraph+j];
578 /* allocate data */
579 ondata = g->ndata;
580 g->ndata = Dx(machr)+1; /* may be too many if label will be drawn here; so what? */
581 g->data = erealloc(g->data, g->ndata*sizeof(ulong));
582 if(g->ndata > ondata)
583 memset(g->data+ondata, 0, (g->ndata-ondata)*sizeof(ulong));
584 /* set geometry */
585 g->r = machr;
586 g->r.min.y = y;
587 g->r.max.y = y+dy - 1;
588 if(j == ngraph-1)
589 g->r.max.y = screen->r.max.y;
590 draw(screen, g->r, cols[g->colindex][0], nil, paritypt(g->r.min.x));
591 g->overflow = 0;
592 r = g->r;
593 r.max.y = r.min.y+mediumfont->height;
594 r.max.x = r.min.x+stringwidth(mediumfont, "9999999");
595 freeimage(g->overtmp);
596 g->overtmp = nil;
597 if(r.max.x <= g->r.max.x)
598 g->overtmp = allocimage(display, r, screen->chan, 0, -1);
599 newvalue(g->mach, g->value, &v, &vmax);
600 redraw(g, vmax);
604 flushimage(display, 1);
607 void
608 eresized(int new)
610 lockdisplay(display);
611 if(new && getwindow(display, Refnone) < 0) {
612 fprint(2, "stats: can't reattach to window\n");
613 killall("reattach");
615 resize();
616 unlockdisplay(display);
619 void
620 mousethread(void *v)
622 Mouse m;
623 int i;
625 USED(v);
627 while(readmouse(mc) == 0){
628 m = mc->m;
629 if(m.buttons == 4){
630 for(i=0; i<Nvalue; i++)
631 if(present[i])
632 memmove(menu2str[i], "drop ", Opwid);
633 else
634 memmove(menu2str[i], "add ", Opwid);
635 lockdisplay(display);
636 i = menuhit(3, mc, &menu2, nil);
637 if(i >= 0){
638 if(!present[i])
639 addgraph(i);
640 else if(ngraph > 1)
641 dropgraph(i);
642 resize();
644 unlockdisplay(display);
649 void
650 resizethread(void *v)
652 USED(v);
654 while(recv(mc->resizec, 0) == 1){
655 lockdisplay(display);
656 if(getwindow(display, Refnone) < 0)
657 sysfatal("attach to window: %r");
658 resize();
659 unlockdisplay(display);
663 void
664 keyboardthread(void *v)
666 Rune r;
668 while(recv(kc->c, &r) == 1)
669 if(r == 0x7F || r == 'q')
670 killall("quit");
673 void machproc(void*);
674 void updateproc(void*);
676 void
677 threadmain(int argc, char *argv[])
679 int i, j;
680 char *s;
681 ulong nargs;
682 char args[100];
684 nmach = 1;
685 mysysname = sysname();
686 if(mysysname == nil){
687 fprint(2, "stats: can't find sysname: %r\n");
688 threadexitsall("sysname");
691 nargs = 0;
692 ARGBEGIN{
693 case 'T':
694 s = ARGF();
695 if(s == nil)
696 usage();
697 i = atoi(s);
698 if(i > 0)
699 sleeptime = 1000*i;
700 break;
701 case 'S':
702 s = ARGF();
703 if(s == nil)
704 usage();
705 scale = atof(s);
706 if(scale <= 0.)
707 usage();
708 break;
709 case 'L':
710 logscale++;
711 break;
712 case 'F':
713 fontname = EARGF(usage());
714 break;
715 case 'Y':
716 ylabels++;
717 break;
718 case 'O':
719 oldsystem = 1;
720 break;
721 case 'W':
722 winsize = EARGF(usage());
723 break;
724 default:
725 if(nargs>=sizeof args || strchr(argchars, ARGC())==nil)
726 usage();
727 args[nargs++] = ARGC();
728 }ARGEND
730 for(i=0; i<Nvalue; i++){
731 menu2str[i] = xmenu2str[i];
732 snprint(xmenu2str[i], sizeof xmenu2str[i], "add %s", labels[i]);
735 if(argc == 0){
736 mach = emalloc(nmach*sizeof(Machine));
737 initmach(&mach[0], mysysname);
738 }else{
739 for(i=j=0; i<argc; i++)
740 addmachine(argv[i]);
743 for(i=0; i<nmach; i++)
744 proccreate(machproc, &mach[i], STACK);
746 for(i=0; i<nargs; i++)
747 switch(args[i]){
748 default:
749 fprint(2, "stats: internal error: unknown arg %c\n", args[i]);
750 usage();
751 case 'b':
752 addgraph(Vbattery);
753 break;
754 case 'c':
755 addgraph(Vcontext);
756 break;
757 case 'C':
758 addgraph(Vcpu);
759 break;
760 case 'e':
761 addgraph(Vether);
762 break;
763 case 'E':
764 addgraph(Vetherin);
765 addgraph(Vetherout);
766 break;
767 case 'f':
768 addgraph(Vfault);
769 break;
770 case 'i':
771 addgraph(Vintr);
772 break;
773 case 'I':
774 addgraph(Vload);
775 addgraph(Vidle);
776 break;
777 case 'l':
778 addgraph(Vload);
779 break;
780 case 'm':
781 addgraph(Vmem);
782 break;
783 case 'n':
784 addgraph(Vetherin);
785 addgraph(Vetherout);
786 addgraph(Vethererr);
787 break;
788 case 's':
789 addgraph(Vsyscall);
790 break;
791 case 'w':
792 addgraph(Vswap);
793 break;
796 if(ngraph == 0)
797 addgraph(Vload);
799 for(i=0; i<nmach; i++)
800 for(j=0; j<ngraph; j++)
801 graph[i*ngraph+j].mach = &mach[i];
803 if(initdraw(0, nil, "stats") < 0)
804 sysfatal("initdraw: %r");
805 colinit();
806 if((mc = initmouse(nil, screen)) == nil)
807 sysfatal("initmouse: %r");
808 if((kc = initkeyboard(nil)) == nil)
809 sysfatal("initkeyboard: %r");
811 display->locking = 1;
812 threadcreate(keyboardthread, nil, XSTACK);
813 threadcreate(mousethread, nil, XSTACK);
814 threadcreate(resizethread, nil, XSTACK);
815 proccreate(updateproc, nil, XSTACK);
816 resize();
817 unlockdisplay(display);
820 void
821 updateproc(void *z)
823 int i;
824 ulong v, vmax;
826 USED(z);
827 for(;;){
828 parity = 1-parity;
829 lockdisplay(display);
830 for(i=0; i<nmach*ngraph; i++){
831 newvalue(graph[i].mach, graph[i].value, &v, &vmax);
832 graph[i].update(&graph[i], v, vmax);
834 if(changedvmax){
835 changedvmax = 0;
836 resize();
838 flushimage(display, 1);
839 unlockdisplay(display);
840 sleep(sleeptime);
844 void
845 machproc(void *v)
847 char buf[256], *f[4], *p;
848 int i, n, t;
849 Machine *m;
851 m = v;
852 t = 0;
853 for(;;){
854 n = read(m->fd, buf+t, sizeof buf-t);
855 m->dead = 0;
856 if(n <= 0)
857 break;
858 t += n;
859 while((p = memchr(buf, '\n', t)) != nil){
860 *p++ = 0;
861 n = tokenize(buf, f, nelem(f));
862 if(n >= 3){
863 for(i=0; i<Nvalue; i++){
864 if(strcmp(labels[i], f[0]) == 0){
865 if(*f[1] == '='){
866 m->absolute[i] = 1;
867 f[1]++;
869 m->val[i][0] = strtoul(f[1], 0, 0);
870 m->val[i][1] = strtoul(f[2], 0, 0);
874 t -= (p-buf);
875 memmove(buf, p, t);
878 if(m->fd){
879 close(m->fd);
880 m->fd = -1;
882 if(m->pid){
883 postnote(PNPROC, m->pid, "kill");
884 m->pid = 0;
888 int
889 initmach(Machine *m, char *name)
891 char *args[5], *q;
892 int p[2], kfd[3], pid;
894 m->name = name;
895 if(strcmp(name, mysysname) == 0)
896 name = nil;
898 if(pipe(p) < 0)
899 sysfatal("pipe: %r");
901 memset(args, 0, sizeof args);
902 args[0] = "auxstats";
903 if(name){
904 args[1] = name;
905 if((q = strchr(name, ':')) != nil){
906 *q++ = 0;
907 args[2] = q;
910 kfd[0] = open("/dev/null", OREAD);
911 kfd[1] = p[1];
912 kfd[2] = dup(2, -1);
913 if((pid = threadspawn(kfd, "auxstats", args)) < 0){
914 fprint(2, "spawn: %r\n");
915 close(kfd[0]);
916 close(p[0]);
917 close(p[1]);
918 return 0;
920 m->fd = p[0];
921 m->pid = pid;
922 if((q = strchr(m->name, '.')) != nil)
923 *q = 0;
924 return 1;