Plan 9 from Bell Labs’s /usr/web/sources/extra/9hist/port/devkprof.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


## diffname port/devkprof.c 1990/03292
## diff -e /dev/null /n/bootesdump/1990/03292/sys/src/9/68020/devkprof.c
0a
#include "syslibc.h"
#include "lock.h"
#include "mem.h"
#include "chan.h"
#include "proc.h"
#include "user.h"
#include "errno.h"
#include "dev.h"
#include "misc.h"
#include "lint.h"

#include "devtab.h"

#define	MAXPC	(100*1024L)
#define	RES	8
#define	LRES	3
#define	NBUF	(MAXPC>>LRES)

long		timerbuf[NBUF];

enum{
	Kprofdirqid,
	Kprofdataqid,
	Kprofstartqid,
	Kprofstartclrqid,
	Kprofstopqid,
	Nkproftab=Kprofstopqid,
	Kprofmaxqid,
};
Dirtab kproftab[Nkproftab]={
	"kpdata",	Kprofdataqid,		NBUF*sizeof timerbuf[0],
	"kpstart",	Kprofstartqid,		0,
	"kpstartclr",	Kprofstartclrqid,	0,
	"kpstop",	Kprofstopqid,		0,
};

void
kprofinit(void)
{
	if((((unsigned long)&etext)-KTZERO)>MAXPC)
		print("kernel profiling limited to %lud\n", MAXPC);
}

Chan *
kprofattach(char *spec)
{
	return devattach('k', spec);
}
Chan *
kprofclone(Chan *c, Chan *nc)
{
	return devclone('k', c, nc);
}

int
kprofwalk(Chan *c, char *name)
{
	return devwalk(c, name, kproftab, (long)Nkproftab, devgen);
}

void
kprofstat(Chan *c, Dir *db)
{
	devstat(c, db, kproftab, (long)Nkproftab, devgen);
}

Chan *
kprofopen(Chan *c, int omode, int amode)
{
	if(amode==Aattach)
		return c;
	omode&=~Otrunc;
	if(omode==Oexecute)
		errjmp(Eperm);
	if(((c->qid&CHDIR) || c->qid==Kprofdataqid) && omode!=Oread)
		errjmp(Eisdir);
	c->mode=omode|OPEN;
	c->offset=0;
	return c;
}

void
kprofcreate(Chan *c, char *name, int omode, ulong perm)
{
	Unused(c);
	Unused(name);
	Unused(omode);
	Unused(perm);
	devunk();
}

void
kprofremove(Chan *c)
{
	Unused(c);
	devunk();
}

void
kprofwstat(Chan *c, Dir *dp)
{
	Unused(c);
	Unused(dp);
	devunk();
}

void
kprofclose(Chan *c)
{
	Unused(c);
}

long
kprofread(Chan *c, char *a, long n)
{
	switch((int)(c->qid&~CHDIR)){
	case Kprofdirqid:
		return devdirread(c, a, n, kproftab, (long)Nkproftab, devgen);
		break;
	case Kprofdataqid:
		if(c->offset>=NBUF*sizeof timerbuf[0]){
			n=0;
			break;
		}
		if(c->offset+n>NBUF*sizeof timerbuf[0])
			n=NBUF*sizeof timerbuf[0]-c->offset;
		memcpy(a, ((char *)timerbuf)+c->offset, n);
		break;
	default:
		n=0;
		break;
	}
	c->offset+=n;
	return n;
}

long
kprofwrite(Chan *c, char *a, long n)
{
	Unused(a);
	switch((int)(c->qid&~CHDIR)){
	case Kprofstartclrqid:
		memset((char *)timerbuf, 0, NBUF*sizeof timerbuf[0]);
	case Kprofstartqid:
		consstarttimer();
		break;
	case Kprofstopqid:
		consstoptimer();
		break;
	default:
		devunk();
	}
	c->offset+=n;
	return n;
}

void
kproftimer(ulong pc)
{
	timerbuf[0]++;
	if(KTZERO<=pc && pc<KTZERO+MAXPC){
		pc-=KTZERO;
		pc>>=LRES;
		timerbuf[pc]++;
	}
}
.
## diffname port/devkprof.c 1990/0330
## diff -e /n/bootesdump/1990/03292/sys/src/9/68020/devkprof.c /n/bootesdump/1990/0330/sys/src/9/68020/devkprof.c
162,163c
		pc -= KTZERO;
		pc >>= LRES;
.
153d
151c
		error(0, Ebadusefd);
.
148c
		duartstoptimer();
.
145c
		duartstarttimer();
.
140d
133d
125,126c
		if(c->offset+n > NBUF*sizeof timerbuf[0])
			n = NBUF*sizeof timerbuf[0]-c->offset;
.
121,122c
		if(c->offset >= NBUF*sizeof timerbuf[0]){
			n = 0;
.
118,119c
		return devdirread(c, a, n, kproftab, Nkproftab, devgen);
.
114c
kprofread(Chan *c, void *a, long n)
.
112a
void
kprofuserstr(Error *e, char *buf)
{
	consuserstr(e, buf);
}

void	 
kproferrstr(Error *e, char *buf)
{
	rooterrstr(e, buf);
}

.
110d
102,104c
	error(0, Eperm);
.
100c
kprofwstat(Chan *c, char *dp)
.
95,96c
	error(0, Eperm);
.
85,89c
	error(0, Eperm);
.
70,78c
	if(c->qid == CHDIR){
		if(omode != OREAD)
			error(0, Eperm);
	}
	c->mode = openmode(omode);
	c->flag |= COPEN;
	c->offset = 0;
.
68c
kprofopen(Chan *c, int omode)
.
62c
kprofstat(Chan *c, char *db)
.
52c
	return devclone(c, nc);
.
47c
	return devattach('t', spec);
.
39a
	extern void *etext;
.
37a
kprofreset(void)
{
}

void
.
31,34c
	"kpdata",	Kprofdataqid,		NBUF*sizeof timerbuf[0],	0600,
	"kpstart",	Kprofstartqid,		0,		0600,
	"kpstartclr",	Kprofstartclrqid,	0,		0600,
	"kpstop",	Kprofstopqid,		0,		0600,
.
12c
#include	"devtab.h"
.
1,10c
#include	"u.h"
#include	"lib.h"
#include	"mem.h"
#include	"dat.h"
#include	"fns.h"
#include	"errno.h"
.
## diffname port/devkprof.c 1990/0331
## diff -e /n/bootesdump/1990/0330/sys/src/9/68020/devkprof.c /n/bootesdump/1990/0331/sys/src/9/68020/devkprof.c
165c
	} else
		timerbuf[1]++;
.
## diffname port/devkprof.c 1990/0928
## diff -e /n/bootesdump/1990/0331/sys/src/9/68020/devkprof.c /n/bootesdump/1990/0928/sys/src/9/68020/devkprof.c
159a
	extern ulong splpc;

.
## diffname port/devkprof.c 1990/1004
## diff -e /n/bootesdump/1990/0928/sys/src/9/68020/devkprof.c /n/bootesdump/1990/1004/sys/src/9/68020/devkprof.c
160c
	/*
	 *  if the pc is coming out of slplo pr splx, then use
	 *  the pc saved when we went splhi.
	 */
	if(pc>=(ulong)spllo && pc<=(ulong)spldone)
		pc = m->splpc;
.
35a
	kprofp = kproftimer;
.
32a
void kproftimer(ulong);

.
## diffname port/devkprof.c 1991/0318
## diff -e /n/bootesdump/1991/0201/sys/src/9/68020/devkprof.c /n/bootesdump/1991/0318/sys/src/9/gnot/devkprof.c
133c
		memmove(a, ((char *)timerbuf)+c->offset, n);
.
## diffname port/devkprof.c 1991/0411
## diff -e /n/bootesdump/1991/0318/sys/src/9/gnot/devkprof.c /n/bootesdump/1991/0411/sys/src/9/gnot/devkprof.c
143c
kprofwrite(Chan *c, char *a, long n, ulong offset)
.
131,133c
		if(offset+n > NBUF*sizeof timerbuf[0])
			n = NBUF*sizeof timerbuf[0]-offset;
		memmove(a, ((char *)timerbuf)+offset, n);
.
127c
		if(offset >= NBUF*sizeof timerbuf[0]){
.
121c
kprofread(Chan *c, void *a, long n, ulong offset)
.
## diffname port/devkprof.c 1991/0419
## diff -e /n/bootesdump/1991/0411/sys/src/9/gnot/devkprof.c /n/bootesdump/1991/0419/sys/src/9/gnot/devkprof.c
65a
Chan*
kprofclwalk(Chan *c, char *name)
{
	return devclwalk(c, name);
}

.
## diffname port/devkprof.c 1991/0421
## diff -e /n/bootesdump/1991/0419/sys/src/9/gnot/devkprof.c /n/bootesdump/1991/0421/sys/src/9/gnot/devkprof.c
27,30c
	"kpdata",	{Kprofdataqid},		NBUF*sizeof timerbuf[0],	0600,
	"kpstart",	{Kprofstartqid},	0,		0600,
	"kpstartclr",	{Kprofstartclrqid},	0,		0600,
	"kpstop",	{Kprofstopqid},		0,		0600,
.
## diffname port/devkprof.c 1991/0427
## diff -e /n/bootesdump/1991/0421/sys/src/9/gnot/devkprof.c /n/bootesdump/1991/0427/sys/src/9/gnot/devkprof.c
66,71d
## diffname port/devkprof.c 1991/1006
## diff -e /n/bootesdump/1991/1007/sys/src/9/gnot/devkprof.c /n/bootesdump/1991/1006/sys/src/9/port/devkprof.c
176c
		kprof.buf[1]++;
.
174c
		kprof.buf[pc]++;
.
170,172c
	kprof.buf[0]++;
	if(kprof.minpc<=pc && pc<kprof.maxpc){
		pc -= kprof.minpc;
.
162a
	if(kprof.time == 0)
		return;
.
155c
		error(Ebadusefd);
.
151,153d
145,149c
	switch((int)(c->qid.path&~CHDIR)){
	case Kprofctlqid:
		if(strncmp(a, "startclr", 8) == 0){
			memset((char *)kprof.buf, 0, kprof.nbuf*sizeof kprof.buf[0]);
			kprof.time = 1;
		}else if(strncmp(a, "start", 5) == 0)
			kprof.time = 1;
		else if(strncmp(a, "stop", 4) == 0)
			kprof.time = 0;
.
131,133c
		if(offset+n > end)
			n = end-offset;
		memmove(a, ((char *)kprof.buf)+offset, n);
.
127c
		end = kprof.nbuf*sizeof kprof.buf[0];
		if(offset >= end){
.
123c
	ulong end;
	switch((int)(c->qid.path&~CHDIR)){
.
108,119d
100c
	error(Eperm);
.
94c
	error(Eperm);
.
88c
	error(Eperm);
.
77c
			error(Eperm);
.
75c
	if(c->qid.path == CHDIR){
.
52c
	return devattach('T', spec);
.
44,46d
38c
	kprof.minpc = KTZERO;
	kprof.maxpc = (ulong)&etext;
	kprof.nbuf = (kprof.maxpc-kprof.minpc) >> LRES;
	kprof.buf = ialloc(kprof.nbuf*sizeof kprof.buf[0], 0);
	kproftab[0].length = kprof.nbuf*sizeof kprof.buf[0];
.
27,30c
	"kpdata",	{Kprofdataqid},		0,	0600,
	"kpctl",	{Kprofctlqid},		0,	0600,
.
20,23c
	Kprofctlqid,
	Nkproftab=Kprofctlqid,
.
15c
struct{
	int	minpc;
	int	maxpc;
	int	nbuf;
	int	time;
	ulong	*buf;
}kprof;
.
10,13c
#define	LRES	3		/* log of PC resolution */
.
## diffname port/devkprof.c 1991/1007
## diff -e /n/bootesdump/1991/1006/sys/src/9/port/devkprof.c /n/bootesdump/1991/1007/sys/src/9/port/devkprof.c
169c
		kprof.buf[1] += TK2MS(1);
.
167c
		kprof.buf[pc] += TK2MS(1);
.
163c
	kprof.buf[0] += TK2MS(1);
.
## diffname port/devkprof.c 1991/1009
## diff -e /n/bootesdump/1991/1007/sys/src/9/port/devkprof.c /n/bootesdump/1991/1009/sys/src/9/port/devkprof.c
153a
	extern void spldone(void);

.
## diffname port/devkprof.c 1991/1011
## diff -e /n/bootesdump/1991/1009/sys/src/9/port/devkprof.c /n/bootesdump/1991/1011/sys/src/9/port/devkprof.c
171c
		buf[1] += TK2MS(1);
.
169c
		buf[pc] += TK2MS(1);
.
165c
	buf = kprof.buf+kprof.nbuf*m->machno;
	buf[0] += TK2MS(1);
.
154a
	ulong *buf;
.
138c
			memset((char *)kprof.buf, 0, conf.nmach * kprof.nbuf*sizeof kprof.buf[0]);
.
116c
		end = conf.nmach * kprof.nbuf*sizeof kprof.buf[0];
.
40,41c
	kprof.buf = ialloc(conf.nmach * kprof.nbuf*sizeof kprof.buf[0], 0);
	kproftab[0].length = conf.nmach * kprof.nbuf*sizeof kprof.buf[0];
.
12c
struct
{
.
## diffname port/devkprof.c 1991/1115
## diff -e /n/bootesdump/1991/1011/sys/src/9/port/devkprof.c /n/bootesdump/1991/1115/sys/src/9/port/devkprof.c
106a
	USED(c);
.
100a
	USED(c, dp);
.
94a
	USED(c);
.
88a
	USED(c, name, omode, perm);
.
## diffname port/devkprof.c 1992/0111
## diff -e /n/bootesdump/1991/1115/sys/src/9/port/devkprof.c /n/bootesdump/1992/0111/sys/src/9/port/devkprof.c
6c
#include	"../port/error.h"
.
## diffname port/devkprof.c 1992/0122
## diff -e /n/bootesdump/1992/0111/sys/src/9/port/devkprof.c /n/bootesdump/1992/0122/sys/src/9/port/devkprof.c
178c
		kprof.buf[1] += TK2MS(1);
.
176c
		kprof.buf[pc] += TK2MS(1);
.
171,172c
	kprof.buf[0] += TK2MS(1);
.
165,166c
	 *  if the pc is coming out of slplo pr splx,
	 *  use the pc saved when we went splhi.
.
160d
143c
			memset((char *)kprof.buf, 0, kprof.nbuf*SZ);
.
131c
		n = 0;
.
129a

.
128c
		n &= ~(SZ-1);
		a = va;
		ea = a + n;
		bp = kprof.buf + offset/SZ;
		while(a < ea){
			w = *bp++;
			*a++ = w>>24;
			*a++ = w>>16;
			*a++ = w>>8;
			*a++ = w>>0;
		}
.
121c
		end = kprof.nbuf*SZ;
		if(offset & (SZ-1))
			error(Ebadarg);
.
119c
		return devdirread(c, va, n, kproftab, Nkproftab, devgen);

.
117c
	ulong w, *bp;
	uchar *a, *ea;

	switch(c->qid.path & ~CHDIR){
.
114c
kprofread(Chan *c, void *va, long n, ulong offset)
.
41,42c
	n = kprof.nbuf*SZ;
	kprof.buf = ialloc(n, 0);
	kproftab[0].length = n;
	if(SZ != sizeof kprof.buf[0])
		panic("kprof size");
.
37a
	ulong n;

.
10a
#define	SZ	4		/* sizeof of count cell; well known as 4 */
.
## diffname port/devkprof.c 1992/0123
## diff -e /n/bootesdump/1992/0122/sys/src/9/port/devkprof.c /n/bootesdump/1992/0123/sys/src/9/port/devkprof.c
198c
	}else
.
## diffname port/devkprof.c 1992/0124
## diff -e /n/bootesdump/1992/0123/sys/src/9/port/devkprof.c /n/bootesdump/1992/0124/sys/src/9/port/devkprof.c
187c
	 *  if the pc is coming out of spllo or splx,
.
## diffname port/devkprof.c 1992/0319
## diff -e /n/bootesdump/1992/0124/sys/src/9/port/devkprof.c /n/bootesdump/1992/0319/sys/src/9/port/devkprof.c
42c
	kprof.maxpc = (ulong)etext;
.
## diffname port/devkprof.c 1992/0321
## diff -e /n/bootesdump/1992/0319/sys/src/9/port/devkprof.c /n/bootesdump/1992/0321/sys/src/9/port/devkprof.c
2c
#include	"../port/lib.h"
.
## diffname port/devkprof.c 1992/0620
## diff -e /n/bootesdump/1992/0321/sys/src/9/port/devkprof.c /n/bootesdump/1992/0620/sys/src/9/port/devkprof.c
45c
	kprof.buf = xalloc(n);
.
## diffname port/devkprof.c 1992/0711
## diff -e /n/bootesdump/1992/0620/sys/src/9/port/devkprof.c /n/bootesdump/1992/0711/sys/src/9/port/devkprof.c
162a
	USED(offset);

.
## diffname port/devkprof.c 1992/0814
## diff -e /n/bootesdump/1992/0711/sys/src/9/port/devkprof.c /n/bootesdump/1992/0814/sys/src/9/port/devkprof.c
58a
	ulong n;

	/* allocate when first used */
	kprof.minpc = KTZERO;
	kprof.maxpc = (ulong)etext;
	kprof.nbuf = (kprof.maxpc-kprof.minpc) >> LRES;
	n = kprof.nbuf*SZ;
	if(kprof.buf == 0) {
		kprof.buf = xalloc(n);
		if(kprof.buf == 0)
			error(Enomem);
	}
	kproftab[0].length = n;
.
53a
	if(SZ != sizeof kprof.buf[0])
		panic("kprof size");
.
39,48d
## diffname port/devkprof.c 1993/0123
## diff -e /n/bootesdump/1992/0814/sys/src/9/port/devkprof.c /n/bootesdump/1993/0123/sys/src/9/port/devkprof.c
143,144c
		if(offset+n > tabend)
			n = tabend-offset;
.
139c
		if(offset >= tabend){
.
136c
		tabend = kprof.nbuf*SZ;
.
127c
	ulong tabend;
.
## diffname port/devkprof.c 1993/0501
## diff -e /n/bootesdump/1993/0123/sys/src/9/port/devkprof.c /n/fornaxdump/1993/0501/sys/src/brazil/port/devkprof.c
143,144c
		if(offset+n > end)
			n = end-offset;
.
139c
		if(offset >= end){
.
136c
		end = kprof.nbuf*SZ;
.
127c
	ulong end;
.
## diffname port/devkprof.c 1995/0108
## diff -e /n/fornaxdump/1993/0501/sys/src/brazil/port/devkprof.c /n/fornaxdump/1995/0108/sys/src/brazil/port/devkprof.c
183a
}

long
kprofbwrite(Chan *c, Block *bp, ulong offset)
{
	return devbwrite(c, bp, offset);
.
164a
Block*
kprofbread(Chan *c, long n, ulong offset)
{
	return devbread(c, n, offset);
}

.
## diffname port/devkprof.c 1995/0804
## diff -e /n/fornaxdump/1995/0108/sys/src/brazil/port/devkprof.c /n/fornaxdump/1995/0804/sys/src/brazil/port/devkprof.c
174,175d
172c
kprofwrite(Chan *c, char *a, long n, ulong)
.
121d
114d
112c
kprofwstat(Chan*, char*)
.
107d
105c
kprofremove(Chan*)
.
100d
98c
kprofcreate(Chan*, char*, int, ulong)
.
## diffname port/devkprof.c 1995/0808
## diff -e /n/fornaxdump/1995/0804/sys/src/brazil/port/devkprof.c /n/fornaxdump/1995/0808/sys/src/brazil/port/devkprof.c
116c
kprofclose(Chan*)
.
## diffname port/devkprof.c 1996/0223
## diff -e /n/fornaxdump/1995/0808/sys/src/brazil/port/devkprof.c /n/fornaxdump/1996/0223/sys/src/brazil/port/devkprof.c
8d
## diffname port/devkprof.c 1997/0327
## diff -e /n/fornaxdump/1996/0223/sys/src/brazil/port/devkprof.c /n/emeliedump/1997/0327/sys/src/brazil/port/devkprof.c
185,212c
Dev kprofdevtab = {
	devreset,
	kprofinit,
	kprofattach,
	devclone,
	kprofwalk,
	kprofstat,
	kprofopen,
	devcreate,
	kprofclose,
	kprofread,
	devbread,
	kprofwrite,
	devbwrite,
	devremove,
	devwstat,
};
.
160,166c
static long
.
128c
		return devdirread(c, va, n, kproftab, nelem(kproftab), devgen);
.
119c
static long
.
96,114c
static void
.
83c
static Chan*
.
80c
	devstat(c, db, kproftab, nelem(kproftab), devgen);
.
77c
static void
.
74c
	return devwalk(c, name, kproftab, nelem(kproftab), devgen);
.
71c
static int
.
65,69d
47c
static Chan*
.
44a
	kproftimer = _kproftimer;
.
40c
static void
.
37a
	extern void spldone(void);

	if(kprof.time == 0)
		return;
	/*
	 *  if the pc is coming out of spllo or splx,
	 *  use the pc saved when we went splhi.
	 */
	if(pc>=(ulong)spllo && pc<=(ulong)spldone)
		pc = m->splpc;

	kprof.buf[0] += TK2MS(1);
	if(kprof.minpc<=pc && pc<kprof.maxpc){
		pc -= kprof.minpc;
		pc >>= LRES;
		kprof.buf[pc] += TK2MS(1);
	}else
		kprof.buf[1] += TK2MS(1);
.
33,36c
static void
_kproftimer(ulong pc)
.
28c
Dirtab kproftab[]={
.
25,26d
## diffname port/devkprof.c 1997/0408
## diff -e /n/emeliedump/1997/0327/sys/src/brazil/port/devkprof.c /n/emeliedump/1997/0408/sys/src/brazil/port/devkprof.c
171a
	'T',
	"kprof",

.
## diffname port/devkprof.c 1998/0319
## diff -e /n/emeliedump/1997/0408/sys/src/brazil/port/devkprof.c /n/emeliedump/1998/0319/sys/src/brazil/port/devkprof.c
153c
kprofwrite(Chan *c, char *a, long n, vlong)
.
116a
	ulong offset = off;
.
112c
kprofread(Chan *c, void *va, long n, vlong off)
.
## diffname port/devkprof.c 1999/0320
## diff -e /n/emeliedump/1998/0319/sys/src/brazil/port/devkprof.c /n/emeliedump/1999/0320/sys/src/brazil/port/devkprof.c
154c
kprofwrite(Chan *c, void *a, long n, vlong)
.
## diffname port/devkprof.c 2001/0127
## diff -e /n/emeliedump/1999/0320/sys/src/brazil/port/devkprof.c /n/emeliedump/2001/0127/sys/src/9/port/devkprof.c
44c
	if(up && up->kppc)
		pc = up->kppc;
.
## diffname port/devkprof.c 2001/0331
## diff -e /n/emeliedump/2001/0127/sys/src/9/port/devkprof.c /n/emeliedump/2001/0331/sys/src/9/port/devkprof.c
174c
	'K',
.
79c
	return devattach('K', spec);
.
## diffname port/devkprof.c 2001/0527
## diff -e /n/emeliedump/2001/0331/sys/src/9/port/devkprof.c /n/emeliedump/2001/0527/sys/src/9/port/devkprof.c
180d
157c
	switch((int)(c->qid.path)){
.
120c
	switch((int)c->qid.path){
.
97c
	if(c->qid.type == QTDIR){
.
91c
	return devstat(c, db, n, kproftab, nelem(kproftab), devgen);
.
88,89c
static int
kprofstat(Chan *c, uchar *db, int n)
.
85c
	return devwalk(c, nc, name, nname, kproftab, nelem(kproftab), devgen);
.
82,83c
static Walkqid*
kprofwalk(Chan *c, Chan *nc, char **name, int nname)
.
78c
	kproftab[1].length = n;
.
44,45c

.
26a
	".",	{Kprofdirqid, 0, QTDIR},		0,	DMDIR|0600,
.
## diffname port/devkprof.c 2001/0529
## diff -e /n/emeliedump/2001/0527/sys/src/9/port/devkprof.c /n/emeliedump/2001/0529/sys/src/9/port/devkprof.c
27c
	".",	{Kprofdirqid, 0, QTDIR},		0,	DMDIR|0550,
.
## diffname port/devkprof.c 2002/0109
## diff -e /n/emeliedump/2001/0529/sys/src/9/port/devkprof.c /n/emeliedump/2002/0109/sys/src/9/port/devkprof.c
178a
	devshutdown,
.

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to [email protected].