commit 0513366ff3f257540c112bef1ad71975cbae9e18
parent d9aeebc9c944482cd9e40f7666f5f4226aa5c04d
Author: Roberto E. Vargas Caballero <k0ga@shike2.com>
Date: Tue, 8 Sep 2020 15:06:47 +0200
devproc: Add devproc
This device driver helps to inspect and interact with
processes and tasks.
Change-Id: I1faa120078a150b6a7995957cc724442527ceadc
Diffstat:
4 files changed, 309 insertions(+), 0 deletions(-)
diff --git a/src/kernel/arch/hosted/9os b/src/kernel/arch/hosted/9os
@@ -7,4 +7,5 @@ dev
blk
dummyblk
ar
+ proc
end
diff --git a/src/kernel/arch/hosted/kernel.c b/src/kernel/arch/hosted/kernel.c
@@ -71,6 +71,8 @@ namespace(void)
panic("bind:/dev/cons");
if (bind("#b", "/dev/blk") < 0)
panic("bind:/dev/blk");
+ if (bind("#p", "/proc") < 0)
+ panic("bind:/proc");
if ((fd = open("/dev/cons/ctl", O_WRITE)) < 0)
panic("open:/dev/cons/ctl write");
diff --git a/src/kernel/dev/devproc.c b/src/kernel/dev/devproc.c
@@ -0,0 +1,304 @@
+#include <9os/9os.h>
+#include <9os/io.h>
+#include <libk.h>
+
+#include "dev.h"
+
+#define PATH(b, p, t) \
+ ((unsigned long long) (b) << 32 | \
+ (unsigned long long) (p) << 16 | \
+ (unsigned long long) (t))
+
+#define TYPE(q) (((q.path) >> 32) & 0xFF)
+#define PROC(q) (((q.path) >> 16) & 0xFFFF)
+#define TASK(q) ((q.path) & 0xFFFF)
+
+enum procqid {
+ Qprocfs,
+ Qprocdir,
+ Qtaskdir,
+
+ Qprocattr,
+ Qprocstatus,
+ Qproctask,
+ Qtaskattr,
+ Qtaskstatus,
+};
+
+static const Dirtab procdirtab[] = {
+ {"attr", QID(CHFILE, 0, Qprocattr), 0, O_READ},
+ {"status", QID(CHFILE, 0, Qprocstatus), 0, O_READ},
+};
+
+static const Dirtab tasktab[] = {
+ {"attr", QID(CHFILE, 0, Qtaskattr), 0, O_READ},
+ {"status", QID(CHFILE, 0, Qtaskstatus), 0, O_READ},
+};
+
+static int
+procfsgen(Chan *c, const Dirtab *tab, int ntab, int n, Dir *dir)
+{
+ Proc *p;
+ char nam[NAMELEN];
+
+ if ((p = getnproc(n)) == NULL)
+ return 0;
+
+ ksnprint(nam, NAMELEN, "%d", p->pid);
+ mkentry(c, dir,
+ nam, 0,
+ QID(CHDIR, 0, PATH(Qprocdir, p->pid, 0)),
+ O_READ);
+
+ return 1;
+}
+
+static int
+procdirgen(Chan *c, const Dirtab *tab, int ntab, int n, Dir *dir)
+{
+ Proc *pp;
+ Task *tp;
+ int r;
+ char nam[NAMELEN];
+
+ if ((pp = getproc(PROC(c->qid))) == NULL)
+ panic("procdirgen");
+
+ r = devgen(c, procdirtab, NELEM(procdirtab), n, dir);
+ if (r) {
+ dir->qid.path = PATH(dir->qid.path, pp->pid, 0);
+ return 1;
+ }
+
+ n -= NELEM(procdirtab);
+ if ((tp = getntask(pp, n)) == NULL)
+ return 0;
+
+ ksnprint(nam, NAMELEN, "%d", tp->tid);
+ mkentry(c, dir,
+ nam, 0,
+ QID(CHDIR, 0, PATH(Qtaskdir, pp->pid, tp->tid)),
+ O_READ);
+
+ return 1;
+}
+
+static int
+taskgen(Chan *c, const Dirtab *tab, int ntab, int n, Dir *dir)
+{
+ int pid = PROC(c->qid);
+ int tid = TASK(c->qid);
+
+ if (!devgen(c, tasktab, NELEM(tasktab), n, dir))
+ return 0;
+ dir->qid.path = PATH(dir->qid.path, pid, tid);
+
+ return 1;
+}
+
+static int
+procgen(Chan *c, const Dirtab *tab, int ntab, int n, Dir *dir)
+{
+ switch (TYPE(c->qid)) {
+ case Qprocfs:
+ return procfsgen(c, tab, ntab, n, dir);
+ case Qprocdir:
+ return procdirgen(c, tab, ntab, n, dir);
+ case Qtaskdir:
+ return taskgen(c, tab, ntab, n, dir);
+ default:
+ return 0;
+ }
+}
+
+static int
+procwalk(Chan *c, const char *name)
+{
+ return devwalk(c, name, NULL, 0, procgen);
+}
+
+static int
+procattrread(Chan *c, void *buf, int n)
+{
+ int len;
+ Proc *pp;
+ char tmp[1024];
+
+ if ((pp = getproc(PROC(c->qid))) == NULL)
+ panic("procattrread:getproc");
+
+ len = ksnprint(tmp,
+ sizeof(tmp),
+ "name: %s\n"
+ "pid: %d\n"
+ "period: %ld\n"
+ "duration: %ld\n"
+ "affinity: %lx\n"
+ "entry: %p\n"
+ "system: %s\n",
+ pp->name,
+ pp->pid,
+ pp->period,
+ pp->duration,
+ pp->affinity,
+ pp->entry,
+ (pp->flags & PSYSTEM) ? "yes" : "no");
+
+ if (len == sizeof(tmp))
+ panic("procattrread:len");
+ return buf2chan(c, buf, tmp, n, len);
+}
+
+static int
+procstatusread(Chan *c, void *buf, int n)
+{
+ int len;
+ Proc *pp;
+ static char *modes[] = {
+ [PDISABLED] = "disabled",
+ [PCOLD_START] = "cold_start",
+ [PWARM_START] = "warm_boot",
+ [PIDLE] = "idle",
+ [PNORMAL] = "normal",
+ };
+ static char *starts[] = {
+ [SNORMAL] = "normal",
+ };
+ char tmp[1024];
+
+ if ((pp = getproc(PROC(c->qid))) == NULL)
+ panic("procstatusread:getproc");
+
+ len = ksnprint(tmp,
+ sizeof(tmp),
+ "locklevel: %d\n"
+ "mode: %s\n"
+ "start: %s\n"
+ "ehandler: %p\n",
+ pp->locklevel,
+ modes[pp->mode],
+ starts[pp->start],
+ pp->errhdl);
+
+ if (len == sizeof(tmp))
+ panic("procstatusread:len");
+ return buf2chan(c, buf, tmp, n, len);
+}
+
+static int
+taskattrread(Chan *c, void *buf, int n)
+{
+ int len;
+ Proc *pp;
+ Task *tp;
+ char tmp[1024];
+
+ if ((pp = getproc(PROC(c->qid))) == NULL)
+ panic("bad process");
+ if ((tp = gettask(pp, TASK(c->qid))) == NULL)
+ panic("");
+
+ len = ksnprint(tmp,
+ sizeof(tmp),
+ "name: %s\n"
+ "tid: %d\n"
+ "entry: %p\n"
+ "stack size: %zd\n"
+ "base prio: %d\n"
+ "period: %ld\n"
+ "capacity: %ld\n"
+ "deadline: %ld\n",
+ tp->name,
+ tp->tid,
+ tp->entry,
+ tp->stack,
+ tp->prio,
+ tp->period,
+ tp->capacity,
+ tp->deadline);
+
+ if (len == sizeof(tmp))
+ panic("temporary buffer too short");
+ return buf2chan(c, buf, tmp, n, len);
+}
+
+static int
+taskstatusread(Chan *c, void *buf, int n)
+{
+ int len;
+ Proc *pp;
+ Task *tp;
+ char tmp[1024];
+ static char *states[] = {
+ [TDORMANT] = "dormant",
+ [TREADY] = "ready",
+ [TRUNNING] = "running",
+ [TWAITING] = "waiting",
+ [FAULTED] = "faulted",
+ };
+
+ if ((pp = getproc(PROC(c->qid))) == NULL)
+ panic("taskstatusread:getproc");
+
+ if ((tp = gettask(pp, TASK(c->qid))) == NULL)
+ panic("taskstatusread:gettask");
+
+ len = ksnprint(tmp,
+ sizeof(tmp),
+ "prio: %d\n"
+ "flags: %x\n"
+ "deadline time: %ld\n"
+ "state: %s\n"
+ "affinity: %lx\n"
+ "retained prio: %d\n",
+ tp->prio,
+ tp->flags,
+ tp->deadtime,
+ states[tp->state],
+ tp->affinity,
+ tp->retainprio);
+
+ if (len == sizeof(tmp))
+ panic("temporary buffer too short");
+ return buf2chan(c, buf, tmp, n, len);
+}
+
+static int
+procread(Chan *c, void *buf, int n)
+{
+ switch (TYPE(c->qid)) {
+ case Qprocfs:
+ case Qprocdir:
+ case Qtaskdir:
+ return dirread(c, buf, n, NULL, 0, procgen);
+ case Qprocattr:
+ return procattrread(c, buf, n);
+ case Qprocstatus:
+ return procstatusread(c, buf, n);
+ case Qtaskattr:
+ return taskattrread(c, buf, n);
+ case Qtaskstatus:
+ return taskstatusread(c, buf, n);
+ default:
+ panic("procread");
+ }
+}
+
+static int
+procstat(Chan *c, char *file, unsigned char *buf, int n)
+{
+ return devstat(c, file, buf, n, NULL, 0, procgen);
+}
+
+const Dev procdevtab = {
+ .id = 'p',
+ .stat = procstat,
+ .clone = devclone,
+ .attach = devattach,
+ .walk = procwalk,
+ .read = procread,
+ .write = deverrwrite,
+ .mount = deverrmount,
+ .seek = devseek,
+ .sync = devsync,
+};
diff --git a/src/kernel/dev/devroot.c b/src/kernel/dev/devroot.c
@@ -15,6 +15,7 @@ enum Orootqid {
Qdevblk,
Qarfs,
Qfip,
+ Qproc,
Qblobs,
Qblobctl,
};
@@ -27,6 +28,7 @@ static const Dirtab dirtab[] = {
{"blobs", QID(CHDIR, 0, Qblobs), 0, O_READ},
{"arfs", QID(CHDIR, 0, Qarfs), 0, O_READ},
{"fip", QID(CHDIR, 0, Qfip), 0, O_READ},
+ {"proc", QID(CHDIR, 0, Qproc), 0, O_READ},
};
static const Dirtab devfstab[] = {