reinit; VM and 9p core mostly done
This commit is contained in:
commit
6fa747864e
11 changed files with 581 additions and 0 deletions
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
kuro
|
||||
kurosrvr
|
7
build
Executable file
7
build
Executable file
|
@ -0,0 +1,7 @@
|
|||
#!/bin/rc
|
||||
|
||||
mk
|
||||
|
||||
mv 6.out kurosrvr
|
||||
cp kurosrvr kuro
|
||||
rm *.6
|
35
client.c
Normal file
35
client.c
Normal 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
102
dat.h
Normal 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
20
fns.h
Normal 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
75
kuro.c
Normal 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
24
mkfile
Normal 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
132
node.c
Normal 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
42
nodetable.c
Normal 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
122
srv.c
Normal 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
20
util.c
Normal 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;
|
||||
}
|
Loading…
Reference in a new issue