reinit; VM and 9p core mostly done

This commit is contained in:
Iris Lightshard 2024-01-22 00:50:23 -07:00
commit 6fa747864e
Signed by: nilix
GPG key ID: F54E0D40695271D4
11 changed files with 581 additions and 0 deletions

2
.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
kuro
kurosrvr

7
build Executable file
View file

@ -0,0 +1,7 @@
#!/bin/rc
mk
mv 6.out kurosrvr
cp kurosrvr kuro
rm *.6

35
client.c Normal file
View file

@ -0,0 +1,35 @@
#include "dat.h"
#include "fns.h"
static char mtpt[256] = {0};
void kuro9p_set_mtpt(char* path) {
strcpy(mtpt, path);
}
void kuro9p_write(char* path, char* data, int len) {
int fd;
char fullpath[256];
strcpy(fullpath, mtpt);
strcat(fullpath, path);
fd = open(fullpath, OWRITE);
if (fd >= 0) {
write(fd, data, len);
close(fd);
}
}
char* kuro9p_read(char* path, char* buf, int len) {
int fd;
char fullpath[256];
strcpy(fullpath, mtpt);
strcat(fullpath, path);
fd = open(fullpath, OREAD);
if (fd >= 0) {
read(fd, buf, len);
close(fd);
}
return buf;
}

102
dat.h Normal file
View file

@ -0,0 +1,102 @@
#include <u.h>
#include <libc.h>
#include <stdio.h>
#include <fcall.h>
#include <thread.h>
#include <9p.h>
#include <draw.h>
#include <cursor.h>
#include <mouse.h>
#include <keyboard.h>
typedef enum {
CTL = 1
} FileType;
typedef enum {
KURO_RUNS = 0,
KURO_QUITS
} WindowStatus;
typedef enum {
PORT_MOUSE,
PORT_RESIZE,
PORT_KBD,
PORT_STATUS,
TOTAL_PORTS
} Port;
typedef enum {
INIT,
OPEN_FILE,
SAVE_FILE,
MOUSE,
KEYBOARD,
SCROLL,
CURSOR,
SELECT,
INSERT,
DELETE,
CUT,
COPY,
PASTE,
EXEC,
PLUMB,
INDICATE,
SPLIT,
PARTITION,
TOTAL_OPCODES
} Opcode;
typedef enum {
TAGF,
BODYF,
SHELLF,
TOTAL_SUBF
} SubFrame;
typedef struct Aux {
FileType type;
char* data;
int count;
} Aux;
typedef struct {
Opcode opcode;
void* data;
} Instruction;
typedef void (*Handler)(void*, void*);
typedef struct {
uvlong id;
WindowStatus status;
Image* img;
Screen* screen;
char filepath[512];
Rune* tag;
uint tag_len;
Rune* body;
uint body_len;
} KuroMemory;
typedef struct {
uvlong id;
int fd;
Channel* cpu; /* chan(Instruction) */
Handler* handlers;
KuroMemory* memory;
Channel* status; /* chan(WidowStatus) */
} Node;
typedef struct NodeRef NodeRef;
struct NodeRef {
int fd[2];
uvlong id;
NodeRef* next;
};
typedef struct {
NodeRef* data[256];
} NodeTable;

20
fns.h Normal file
View file

@ -0,0 +1,20 @@
int strequ(char* s1, char* s2);
char* strcsw(char* s, char a, char b);
char* uvlong_to_hex(uvlong input, char* buf);
void start_9p(char* mtpt);
void kuro9p_set_mtpt(char* mtpt);
void kuro9p_write(char* path, char* data, int len);
char* kuro9p_read(char* path, char* buf, int len);
void nodetbl_add(NodeTable* self, NodeRef* node);
void nodetbl_del(NodeTable* self, uvlong id);
void node_setup(Node* self, uvlong id, int fd, Handler* handlers, KuroMemory* memory);
void node_execute(Node* self);
void node_loop(void* data);
Node* create_node(uvlong id, int fd, int new, char* filename);
void supervise_node(Node* self);
void node_cleanup(Node* self);
void memory_cleanup(KuroMemory* self);

75
kuro.c Normal file
View file

@ -0,0 +1,75 @@
#include "dat.h"
#include "fns.h"
static char* mtpt;
int threadmaybackground(void) {
return 1;
}
void threadmain(int argc, char **argv)
{
/* we want to strip any path elements off the executable name */
char exe_name[256] = {0};
char* exe_base;
uvlong node_id = 0;
int client_fd = -1;
int newwin = 0;
char client_9p_str[256] = {0};
strcpy(exe_name, argv[0]);
exe_base = utfrrune(exe_name, '/');
if (exe_base) {
exe_base++;
} else {
exe_base = exe_name;
}
/* if we are the server, serve the filetree on 9p */
if (strequ(exe_base, "kurosrvr")) {
if (argc > 1) {
start_9p(argv[1]);
} else {
sysfatal("usage: kurosrvr mtpt");
}
} else if (strequ(exe_base, "kuro")) {
mtpt = getenv("KURO_MTPT");
if (mtpt == nil) {
sysfatal("KURO_MTPT not set");
}
kuro9p_set_mtpt(mtpt);
print("KURO_MTPT=%s\n", mtpt);
ARGBEGIN{
case 'n':
newwin=1;
break;
case 'i':
sscanf(ARGF(), "%d", &node_id);
break;
case 'p':
sscanf(ARGF(), "%d", &client_fd);
break;
}ARGEND
strcpy(client_9p_str, "new");
if (argv[0]) {
strcat(client_9p_str, " ");
strcat(client_9p_str, argv[0]);
}
if (node_id > 0 && client_fd >= 0) {
supervise_node(create_node(node_id, client_fd, newwin, argv[0]));
} else {
/* if node_id or client_id are missing, ask the server to fork us with them, and forward the filename */
print("9pstr=%s\n", client_9p_str);
kuro9p_write("/ctl", client_9p_str, strlen(client_9p_str));
}
} else {
sysfatal("invoke as kurosrvr to start the background service or kuro to start an application window");
}
}

24
mkfile Normal file
View file

@ -0,0 +1,24 @@
</$objtype/mkfile
BIN=/$objtype/bin
TARG=kuro
OFILES=\
kuro.$O\
srv.$O\
client.$O\
util.$O\
node.$O\
nodetable.$O\
HFILES=dat.h\
fns.h\
UPDATE=\
mkfile\
$HFILES\
${OFILES:%.$O=%.c}\
</sys/src/cmd/mkone
$O.out: /$objtype/lib/libframe.a /$objtype/lib/libdraw.a /$objtype/lib/libthread.a

132
node.c Normal file
View file

@ -0,0 +1,132 @@
#include "dat.h"
#include "fns.h"
void node_setup(Node* self, uvlong id, int fd, Handler* handlers, KuroMemory* memory) {
if (self) {
self->id = id;
self->fd = fd;
self->handlers = handlers;
self->memory = memory;
self->cpu = chancreate(sizeof(Instruction), 0);
self->status = chancreate(sizeof(WindowStatus), 0);
}
}
void node_loop(void* data) {
Node* self = (Node*)data;
Instruction x;
for (;;) {
recv(self->cpu, &x);
if (self->handlers[x.opcode]) {
(*(self->handlers[x.opcode]))(self, x.data);
switch(self->memory->status) {
case KURO_QUITS:
nbsend(self->status, 0);
threadexits(0);
default:
break;
}
flushimage(self->memory->screen->display, 1);
}
}
}
void node_execute(Node* self) {
threadcreate(node_loop, self, 1024);
}
Node* create_node(uvlong id, int fd, int new, char* filename) {
if (new) {
newwindow("-dx 600 -dy 600");
}
initdraw(nil, nil, "kuro");
KuroMemory* self = (KuroMemory*)malloc(sizeof(KuroMemory));
Node* node = (Node*)malloc(sizeof(Node));
Handler* handlers = (Handler*)malloc(TOTAL_OPCODES * sizeof(Handler*));
node_setup(node, id, fd, handlers, self);
self->img = screen;
self->screen = _screen;
strcpy(self->filepath, filename);
/* node_execute runs the node on a separate thread */
node_execute(node);
return node;
}
void supervise_node(Node* self) {
Mousectl* mctl;
Keyboardctl* kctl;
Mouse mouse;
int resize[2];
WindowStatus status;
Rune kbd;
if ((mctl = initmouse(nil, screen)) == nil) {
sysfatal("couldn't initialize mctl");
}
if ((kctl = initkeyboard(nil)) == nil) {
sysfatal("couldn't initialize kctl");
}
Alt alts[TOTAL_PORTS + 1] = {
{mctl->c, &mouse, CHANRCV},
{mctl->resizec, resize, CHANRCV},
{kctl->c, &kbd, CHANRCV},
{self->status, &status, CHANRCV},
{nil, nil, CHANEND}
};
for (;;) {
switch (alt(alts)) {
case PORT_MOUSE:
print("got a mouse event");
break;
case PORT_RESIZE:
lockdisplay(display);
if (getwindow(display, Refnone) < 0)
sysfatal("couldn't resize");
unlockdisplay(display);
print("got a resize event");
break;
case PORT_KBD:
print("got a keypress");
break;
case PORT_STATUS:
switch(status) {
case KURO_QUITS:
print("VM died - let's clean up the data");
goto cleanup;
default:
break;
}
break;
}
}
cleanup:
node_cleanup(self);
}
void node_cleanup(Node* self) {
if (self) {
memory_cleanup(self->memory);
chanfree(self->cpu);
chanfree(self->status);
/* TODO: send message on self->fd to tell the server to remove us from NodeTable and filetree */
/* handlers array is shared between all the nodes */
free(self);
}
}
void memory_cleanup(KuroMemory* self) {
if (self) {
/* do we need to free the img and screen? */
}
}

42
nodetable.c Normal file
View file

@ -0,0 +1,42 @@
#include "dat.h"
#include "fns.h"
void nodetbl_add(NodeTable* self, NodeRef* node) {
int i;
NodeRef* n;
if (self && node) {
i = (int)(node->id%256);
n = self->data[i];
if (n && n->next) {
n = n->next;
}
if (n) {
n->next = node;
} else {
n = node;
}
}
}
void nodetbl_del(NodeTable* self, uvlong id) {
NodeRef* n;
NodeRef* nprev;
if (self) {
for(int i = 0; i <= 255; i++) {
n = self->data[i];
while (n && n->id != id && n->next) {
nprev = n;
n = n->next;
}
if (n->id == id) {
if (nprev) {
nprev->next = n->next;
}
free(n);
break;
}
}
}
}

122
srv.c Normal file
View file

@ -0,0 +1,122 @@
#include "dat.h"
#include "fns.h"
static NodeTable nodes;
static QLock id_lock;
static uvlong get_next_id(void) {
static uvlong id = 0;
uvlong next;
qlock(&id_lock);
next = ++id;
qunlock(&id_lock);
return next;
}
Aux* create_aux(FileType t) {
Aux* self = (Aux*)malloc(sizeof(Aux));
self->type = t;
self->data = nil;
self->count = 0;
return self;
}
void fs_destroy_file(File* f) {
Aux* a = (Aux*)f->aux;
if(a && a->data) {
free(a->data);
}
if (a) {
free (a);
}
}
void kuro_read(Req* r) {
Aux* a = (Aux*)r->fid->file->aux;
switch (a->type) {
case CTL:
default:
respond(r, nil);
break;
}
}
void new_window(char* filename, int new) {
int rw_fd[2];
char client_fd[32] = {0};
char client_id[32] = {0};
uvlong id;
NodeRef* noderef;
pipe(rw_fd);
id = get_next_id();
noderef = (NodeRef*)malloc(sizeof(NodeRef));
noderef->id = id;
noderef->fd[0] = rw_fd[0];
noderef->fd[1] = rw_fd[1];
nodetbl_add(&nodes, noderef);
sprintf(client_fd, "%d", rw_fd[1]);
sprintf(client_id, "%d", id);
rfork(RFNAMEG);
char* a[] = { "kuro", "-p", client_fd, "-i", client_id, new ? "-n" : filename, new ? filename : 0, 0 };
exec("./kuro", a);
}
void write_ctl(Req* r) {
char cmd[16] = {0};
char* c = r->ifcall.data;
int i;
for (i = 0; i < r->ifcall.count && *c != ' ' && *c != '\n'; i++) {
strncat(cmd, c, 1);
c++;
}
if (*c == ' ') {
c++;
}
/* maybe don't do this... */
strcsw(c, '\n', 0);
/* diagnostics for now */
print("cmd: %s\n", cmd);
print("arg: %s\n", c);
if (strequ(cmd, "new")) {
new_window(c, 1);
respond(r, nil);
} else {
print("unknown command...\n");
respond(r, nil);
}
}
void kuro_write(Req* r) {
Aux* a = (Aux*)r->fid->file->aux;
switch (a->type) {
case CTL:
write_ctl(r);
break;
default:
respond(r, nil);
break;
}
}
void start_9p(char* mtpt) {
if (mtpt) {
putenv("KURO_MTPT", mtpt);
Srv srv = { .read = kuro_read, .write = kuro_write };
Tree* tree = alloctree(nil, nil, DMDIR | 0777, fs_destroy_file);
srv.tree = tree;
closefile(createfile(tree->root, "ctl", nil, DMAPPEND | 0600, create_aux(CTL)));
closefile(createfile(tree->root, "nodes", nil, DMDIR | 0600, nil));
closefile(tree->root);
/* TODO: figure out how to kill the server cleanly so we don't need MREPL */
threadpostmountsrv(&srv, nil, mtpt, MREPL | MCREATE);
}
}

20
util.c Normal file
View file

@ -0,0 +1,20 @@
#include "dat.h"
#include "fns.h"
int strequ(char* s1, char* s2) {
return strcmp(s1, s2) == 0;
}
char* strcsw(char* s, char a, char b) {
int i = 0;
char c;
while ((c = s[i])) {
s[i++] = c == a ? b : c;
}
return s;
}
char* uvlong_to_hex(uvlong input, char* buf) {
sprintf(buf, "%08%x\0", input);
return buf;
}