replace coroutine to setjmp
This commit is contained in:
parent
aea52f9e63
commit
3181653d92
11
Makefile
11
Makefile
@ -1,18 +1,11 @@
|
|||||||
CC=tcc
|
CC=tcc
|
||||||
CFLAGS= -c -Wall -g -Wextra
|
CFLAGS= -c -Wall -g -Wextra
|
||||||
SRC:=$(wildcard *.c)
|
|
||||||
OBJ:=$(SRC:.c=.o)
|
|
||||||
|
|
||||||
all: gb
|
all: gb
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
make clean -C co/
|
rm -f *.o
|
||||||
rm -f $(OBJ)
|
|
||||||
rm -f gb
|
rm -f gb
|
||||||
|
|
||||||
%.o: %.c gb.h
|
|
||||||
$(CC) $(CFLAGS) -o $@ $<
|
|
||||||
|
|
||||||
gb: $(OBJ)
|
gb: $(OBJ)
|
||||||
make all -C co/
|
$(CC) jmp.S *.c -lSDL2 -o gb
|
||||||
$(CC) co/*.o *.o -lucontext -lSDL2 -g -o gb
|
|
||||||
|
|||||||
15
co/Makefile
15
co/Makefile
@ -1,15 +0,0 @@
|
|||||||
CC=tcc
|
|
||||||
CFLAGS= -c -Wall -g
|
|
||||||
SRC:=$(wildcard *.c)
|
|
||||||
OBJ:=$(SRC:.c=.o)
|
|
||||||
|
|
||||||
all: co
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -f $(OBJ)
|
|
||||||
|
|
||||||
%.o: %.c
|
|
||||||
$(CC) $(CFLAGS) -o $@ $<
|
|
||||||
|
|
||||||
co: $(OBJ)
|
|
||||||
|
|
||||||
@ -1,2 +0,0 @@
|
|||||||
# coroutine library
|
|
||||||
https://github.com/Hojun-Cho/coroutine
|
|
||||||
356
co/channel.c
356
co/channel.c
@ -1,356 +0,0 @@
|
|||||||
#include "taskimpl.h"
|
|
||||||
|
|
||||||
Channel*
|
|
||||||
newchan(int elemsize, int bufsize)
|
|
||||||
{
|
|
||||||
Channel* c;
|
|
||||||
|
|
||||||
c = malloc(sizeof *c + bufsize * elemsize);
|
|
||||||
if (c == 0) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
*c = (Channel){
|
|
||||||
.elemsize = elemsize,
|
|
||||||
.bufsize = bufsize,
|
|
||||||
.nbuf = 0,
|
|
||||||
.buf = (uchar*)&c[1],
|
|
||||||
};
|
|
||||||
return c;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
deletechan(Channel* c)
|
|
||||||
{
|
|
||||||
if (c == 0)
|
|
||||||
return;
|
|
||||||
free(c->name);
|
|
||||||
free(c->asend.a);
|
|
||||||
free(c->arecv.a);
|
|
||||||
free(c);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
addarray(Altarray* a, Alt* alt)
|
|
||||||
{
|
|
||||||
if (a->n == a->m) {
|
|
||||||
a->m += 16;
|
|
||||||
a->a = realloc(a->a, a->m * sizeof a->a[0]);
|
|
||||||
if (a->a == nil) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
a->a[a->n++] = alt;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
amove(void* dst, void* src, uint n)
|
|
||||||
{
|
|
||||||
if (dst) {
|
|
||||||
if (src == nil)
|
|
||||||
memset(dst, 0, n);
|
|
||||||
else
|
|
||||||
memmove(dst, src, n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
delarray(Altarray* a, int i)
|
|
||||||
{
|
|
||||||
--a->n;
|
|
||||||
a->a[i] = a->a[a->n];
|
|
||||||
}
|
|
||||||
|
|
||||||
static enum chan_op
|
|
||||||
otherop(enum chan_op op)
|
|
||||||
{
|
|
||||||
return (CHANSND + CHANRCV) - op;
|
|
||||||
}
|
|
||||||
|
|
||||||
static Altarray*
|
|
||||||
chanarray(Channel* c, enum chan_op op)
|
|
||||||
{
|
|
||||||
switch (op) {
|
|
||||||
default:
|
|
||||||
return nil;
|
|
||||||
case CHANSND:
|
|
||||||
return &c->asend;
|
|
||||||
case CHANRCV:
|
|
||||||
return &c->arecv;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* 3 players: sender, reciver, 'channel itself'
|
|
||||||
* if chann.empty
|
|
||||||
* send(send to reciver);
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
altcopy(Alt* s, Alt* r)
|
|
||||||
{
|
|
||||||
Channel* c;
|
|
||||||
uchar* cp;
|
|
||||||
|
|
||||||
if (s == nil && r == nil)
|
|
||||||
return;
|
|
||||||
assert(s != nil); /* sender must not nil */
|
|
||||||
c = s->c;
|
|
||||||
if (s->op == CHANRCV) {
|
|
||||||
Alt* t = s;
|
|
||||||
s = r;
|
|
||||||
r = t;
|
|
||||||
}
|
|
||||||
assert(s == nil || s->op == CHANSND); /* sender */
|
|
||||||
assert(r == nil || r->op == CHANRCV); /* reciver */
|
|
||||||
|
|
||||||
/* Channel is unbufferd */
|
|
||||||
if (s && r && c->nbuf == 0) {
|
|
||||||
amove(r->v, s->v, c->elemsize);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (r) {
|
|
||||||
/* recive buffred data first */
|
|
||||||
cp = c->buf + c->off * c->elemsize;
|
|
||||||
amove(r->v, cp, c->elemsize);
|
|
||||||
--c->nbuf;
|
|
||||||
if (++c->off == c->bufsize)
|
|
||||||
c->off = 0;
|
|
||||||
}
|
|
||||||
if (s) {
|
|
||||||
cp = c->buf + (c->off + c->nbuf) % c->bufsize * c->elemsize;
|
|
||||||
amove(cp, s->v, c->elemsize);
|
|
||||||
++c->nbuf;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
altdeque(Alt* a)
|
|
||||||
{
|
|
||||||
Altarray* ar;
|
|
||||||
|
|
||||||
ar = chanarray(a->c, a->op);
|
|
||||||
if (ar == nil) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (uint i = 0; i < ar->n; ++i) {
|
|
||||||
if (ar->a[i] == a) {
|
|
||||||
delarray(ar, i);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* can't find self in altdq */
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
altqueue(Alt* a)
|
|
||||||
{
|
|
||||||
Altarray* ar;
|
|
||||||
|
|
||||||
ar = chanarray(a->c, a->op);
|
|
||||||
addarray(ar, a);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
altalldeque(Alt* a)
|
|
||||||
{
|
|
||||||
for (int i = 0; a[i].op != CHANEND && a[i].op != CHANNOBLK; i++) {
|
|
||||||
if (a[i].op != CHANNOP)
|
|
||||||
altdeque(&a[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
altexec(Alt* a)
|
|
||||||
{
|
|
||||||
Altarray* ar;
|
|
||||||
Channel* c;
|
|
||||||
|
|
||||||
c = a->c;
|
|
||||||
ar = chanarray(c, otherop(a->op));
|
|
||||||
if (ar && ar->n) {
|
|
||||||
int i = rand() % ar->n; /* find any other palyer */
|
|
||||||
Alt* other = ar->a[i];
|
|
||||||
altcopy(a, other); /* copy data to other's buffer */
|
|
||||||
altalldeque(other->xalt); /* delete because now request is completed */
|
|
||||||
other->xalt[0].xalt = other;
|
|
||||||
taskready(other->task);
|
|
||||||
} else
|
|
||||||
altcopy(a, nil); /* if channel is unbufferd then do nothing */
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
altcanexec(Alt* a)
|
|
||||||
{
|
|
||||||
Channel* c;
|
|
||||||
|
|
||||||
if (a->op == CHANNOP)
|
|
||||||
return 0;
|
|
||||||
c = a->c;
|
|
||||||
if (c->bufsize == 0) {
|
|
||||||
Altarray* ar = chanarray(c, otherop(a->op));
|
|
||||||
return ar && ar->n;
|
|
||||||
}
|
|
||||||
switch (a->op) {
|
|
||||||
default:
|
|
||||||
return 0;
|
|
||||||
case CHANSND:
|
|
||||||
return c->nbuf < c->bufsize;
|
|
||||||
case CHANRCV:
|
|
||||||
return c->nbuf > 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
chanalt(Alt* a)
|
|
||||||
{
|
|
||||||
int i, j, ncan, n, canblock;
|
|
||||||
Task* t;
|
|
||||||
|
|
||||||
assertstack(512);
|
|
||||||
for (i = 0; a[i].op != CHANEND && a[i].op != CHANNOBLK; ++i)
|
|
||||||
;
|
|
||||||
n = i;
|
|
||||||
canblock = (a[i].op == CHANEND);
|
|
||||||
t = taskrunning;
|
|
||||||
for (i = 0; i < n; ++i) {
|
|
||||||
a[i].task = t;
|
|
||||||
a[i].xalt = a;
|
|
||||||
}
|
|
||||||
ncan = 0;
|
|
||||||
for (i = 0; i < n; i++) {
|
|
||||||
if (altcanexec(&a[i])) {
|
|
||||||
ncan++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ncan) {
|
|
||||||
j = rand() % ncan;
|
|
||||||
for (i = 0; i < n; ++i) {
|
|
||||||
if (altcanexec(&a[i])) {
|
|
||||||
if (j-- == 0) {
|
|
||||||
altexec(&a[i]);
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (canblock == 0)
|
|
||||||
return -1;
|
|
||||||
for (i = 0; i < n; ++i) {
|
|
||||||
if (a[i].op != CHANNOP)
|
|
||||||
altqueue(&a[i]);
|
|
||||||
}
|
|
||||||
taskswitch();
|
|
||||||
return a[0].xalt - a; /* calculate offset */
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
_chanop(Channel* c, int op, void* p, int canblock)
|
|
||||||
{
|
|
||||||
Alt ar[2];
|
|
||||||
|
|
||||||
ar[0] = (Alt){
|
|
||||||
.c = c,
|
|
||||||
.op = op,
|
|
||||||
.v = p,
|
|
||||||
};
|
|
||||||
ar[1] = (Alt){
|
|
||||||
.op = canblock ? CHANEND : CHANNOBLK,
|
|
||||||
};
|
|
||||||
if (chanalt(ar) < 0)
|
|
||||||
return -1;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
chansend(Channel* c, void* v)
|
|
||||||
{
|
|
||||||
return _chanop(c, CHANSND, v, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
chanbsend(Channel* c, void* v)
|
|
||||||
{
|
|
||||||
return _chanop(c, CHANSND, v, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
chanrecv(Channel* c, void* v)
|
|
||||||
{
|
|
||||||
return _chanop(c, CHANRCV, v, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
chanbrecv(Channel* c, void* v)
|
|
||||||
{
|
|
||||||
return _chanop(c, CHANSND, v, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
chansendp(Channel* c, void* v)
|
|
||||||
{
|
|
||||||
return _chanop(c, CHANSND, &v, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
void*
|
|
||||||
chanrecvp(Channel* c)
|
|
||||||
{
|
|
||||||
void* v;
|
|
||||||
|
|
||||||
_chanop(c, CHANRCV, &v, 1);
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
channbsendp(Channel* c, void* v)
|
|
||||||
{
|
|
||||||
return _chanop(c, CHANSND, (void*)&v, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void*
|
|
||||||
channbrecvp(Channel* c)
|
|
||||||
{
|
|
||||||
void* v;
|
|
||||||
|
|
||||||
_chanop(c, CHANRCV, &v, 0);
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
chansendul(Channel* c, ulong v)
|
|
||||||
{
|
|
||||||
return _chanop(c, CHANSND, &v, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
ulong
|
|
||||||
chanrecvul(Channel* c)
|
|
||||||
{
|
|
||||||
ulong v;
|
|
||||||
|
|
||||||
_chanop(c, CHANRCV, &v, 1);
|
|
||||||
return v;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
channbsendul(Channel* c, ulong v)
|
|
||||||
{
|
|
||||||
return _chanop(c, CHANSND, &v, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
channbrecvul(Channel* c, ulong v)
|
|
||||||
{
|
|
||||||
return _chanop(c, CHANRCV, &v, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
channbsend(Channel* c, void* v)
|
|
||||||
{
|
|
||||||
return _chanop(c, CHANSND, v, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
channbrecv(Channel* c, void* v)
|
|
||||||
{
|
|
||||||
return _chanop(c, CHANRCV, v, 0);
|
|
||||||
}
|
|
||||||
60
co/qlock.c
60
co/qlock.c
@ -1,60 +0,0 @@
|
|||||||
#include "taskimpl.h"
|
|
||||||
|
|
||||||
int
|
|
||||||
_qlock(QLock* l, int block)
|
|
||||||
{
|
|
||||||
if (l->owner == nil) {
|
|
||||||
l->owner = taskrunning;
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if (!block)
|
|
||||||
return 0;
|
|
||||||
addtask(&l->waiting, taskrunning);
|
|
||||||
taskswitch(); /* wait until own lock */
|
|
||||||
if (l->owner != taskrunning) {
|
|
||||||
/* TODO: */
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
qlock(QLock* l)
|
|
||||||
{
|
|
||||||
_qlock(l, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
canqlock(QLock* l)
|
|
||||||
{
|
|
||||||
return _qlock(l, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
qunlock(QLock* l)
|
|
||||||
{
|
|
||||||
Task* ready;
|
|
||||||
|
|
||||||
if (l->owner == nil) {
|
|
||||||
/* TODO: */
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
l->owner = ready = l->waiting.head;
|
|
||||||
if (l->owner != nil) {
|
|
||||||
deltask(&l->waiting, ready);
|
|
||||||
taskready(ready);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
QLock*
|
|
||||||
newqlock()
|
|
||||||
{
|
|
||||||
QLock* l;
|
|
||||||
|
|
||||||
l = malloc(sizeof *l);
|
|
||||||
if (l == nil)
|
|
||||||
exit(1);
|
|
||||||
l->owner = 0;
|
|
||||||
l->waiting = (Tasklist){ 0 };
|
|
||||||
return l;
|
|
||||||
}
|
|
||||||
54
co/rendez.c
54
co/rendez.c
@ -1,54 +0,0 @@
|
|||||||
#include "taskimpl.h"
|
|
||||||
|
|
||||||
void
|
|
||||||
tasksleep(Rendez* r)
|
|
||||||
{
|
|
||||||
addtask(&r->waiting, taskrunning);
|
|
||||||
if (r->l)
|
|
||||||
qunlock(r->l);
|
|
||||||
taskswitch();
|
|
||||||
if (r->l)
|
|
||||||
qlock(r->l);
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
_taskwakeup(Rendez* r, int all)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
Task* t;
|
|
||||||
|
|
||||||
for (i = 0;; ++i) {
|
|
||||||
if (i == 1 && !all)
|
|
||||||
break;
|
|
||||||
if ((t = r->waiting.head) == nil)
|
|
||||||
break;
|
|
||||||
deltask(&r->waiting, t);
|
|
||||||
taskready(t);
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
taskwakeup(Rendez* r)
|
|
||||||
{
|
|
||||||
return _taskwakeup(r, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
taskwakeupall(Rendez* r)
|
|
||||||
{
|
|
||||||
return _taskwakeup(r, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
Rendez*
|
|
||||||
newrendez(QLock* l)
|
|
||||||
{
|
|
||||||
Rendez* r;
|
|
||||||
|
|
||||||
r = malloc(sizeof *r);
|
|
||||||
if (r == nil)
|
|
||||||
exit(1);
|
|
||||||
r->l = l;
|
|
||||||
r->waiting = (Tasklist){ 0 };
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
253
co/task.c
253
co/task.c
@ -1,253 +0,0 @@
|
|||||||
#include "taskimpl.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
int taskcount;
|
|
||||||
int taskidgen;
|
|
||||||
int tasknswitch;
|
|
||||||
int taskexitval;
|
|
||||||
|
|
||||||
Task* taskrunning;
|
|
||||||
ucontext_t taskschedcontext;
|
|
||||||
Tasklist taskrunqueue;
|
|
||||||
Task** alltask;
|
|
||||||
int nalltask;
|
|
||||||
|
|
||||||
static void
|
|
||||||
contextswitch(ucontext_t* from, ucontext_t* to);
|
|
||||||
void
|
|
||||||
assertstack(uint n);
|
|
||||||
|
|
||||||
static void
|
|
||||||
taskinfo(int s)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
Task* t;
|
|
||||||
char* extra;
|
|
||||||
|
|
||||||
for (i = 0; i < nalltask; ++i) {
|
|
||||||
t = alltask[i];
|
|
||||||
if (t == taskrunning)
|
|
||||||
extra = " (running)";
|
|
||||||
else if (t->ready)
|
|
||||||
extra = " (ready)";
|
|
||||||
else
|
|
||||||
extra = "";
|
|
||||||
printf("%s\n", extra);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
taskstart(uint x, uint y)
|
|
||||||
{
|
|
||||||
Task* t;
|
|
||||||
ulong z;
|
|
||||||
|
|
||||||
z = x << 16;
|
|
||||||
z <<= 16;
|
|
||||||
z |= y;
|
|
||||||
t = (Task*)z;
|
|
||||||
t->startfn(t->startarg);
|
|
||||||
taskexit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
static Task*
|
|
||||||
taskalloc(void (*fn)(void*), void* arg, uint stk)
|
|
||||||
{
|
|
||||||
Task* t;
|
|
||||||
sigset_t zero;
|
|
||||||
uint x, y;
|
|
||||||
ulong z;
|
|
||||||
|
|
||||||
if ((t = malloc(sizeof *t + stk)) == nil) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
*t = (Task){
|
|
||||||
.stk = (uchar*)(&t[1]),
|
|
||||||
.stksize = stk,
|
|
||||||
.id = ++taskidgen,
|
|
||||||
.startfn = fn,
|
|
||||||
.startarg = arg,
|
|
||||||
};
|
|
||||||
sigemptyset(&zero);
|
|
||||||
sigprocmask(SIG_BLOCK, &zero, &t->uc.uc_sigmask);
|
|
||||||
if (getcontext(&t->uc)) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
t->uc.uc_stack.ss_sp = t->stk + 8;
|
|
||||||
t->uc.uc_stack.ss_size = t->stksize - 64;
|
|
||||||
|
|
||||||
z = (ulong)t;
|
|
||||||
y = z;
|
|
||||||
z >>= 16;
|
|
||||||
x = z >> 16;
|
|
||||||
makecontext(&t->uc, (void (*)())taskstart, 2, x, y);
|
|
||||||
return t;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
taskcreate(void (*fn)(void*), void* arg, uint stk)
|
|
||||||
{
|
|
||||||
int id;
|
|
||||||
Task* t;
|
|
||||||
|
|
||||||
t = taskalloc(fn, arg, stk);
|
|
||||||
taskcount++;
|
|
||||||
id = t->id;
|
|
||||||
if (nalltask % 64 == 0) {
|
|
||||||
alltask = realloc(alltask, (nalltask + 64) * sizeof(alltask[0]));
|
|
||||||
if (alltask == 0) {
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
t->alltaskslot = nalltask;
|
|
||||||
alltask[nalltask++] = t;
|
|
||||||
taskready(t);
|
|
||||||
return id;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
taskready(Task* t)
|
|
||||||
{
|
|
||||||
t->ready = 1;
|
|
||||||
addtask(&taskrunqueue, t);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
taskswitch(void)
|
|
||||||
{
|
|
||||||
assertstack(0);
|
|
||||||
contextswitch(&taskrunning->uc, &taskschedcontext);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
taskyield(void)
|
|
||||||
{
|
|
||||||
int n;
|
|
||||||
|
|
||||||
n = tasknswitch;
|
|
||||||
taskready(taskrunning);
|
|
||||||
taskswitch();
|
|
||||||
return tasknswitch - n - 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
taskexit(int val)
|
|
||||||
{
|
|
||||||
taskexitval = val;
|
|
||||||
taskrunning->exiting = 1;
|
|
||||||
taskswitch();
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
taskexitall(int val)
|
|
||||||
{
|
|
||||||
exit(val);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
deltask(Tasklist* l, Task* t)
|
|
||||||
{
|
|
||||||
if (t->prev)
|
|
||||||
t->prev->next = t->next;
|
|
||||||
else
|
|
||||||
l->head = t->next;
|
|
||||||
if (t->next)
|
|
||||||
t->next->prev = t->prev;
|
|
||||||
else
|
|
||||||
l->tail = t->prev;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
addtask(Tasklist* l, Task* t)
|
|
||||||
{
|
|
||||||
if (l->tail) {
|
|
||||||
l->tail->next = t;
|
|
||||||
t->prev = l->tail;
|
|
||||||
} else {
|
|
||||||
l->head = t;
|
|
||||||
t->prev = nil;
|
|
||||||
}
|
|
||||||
l->tail = t;
|
|
||||||
t->next = nil;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
contextswitch(ucontext_t* from, ucontext_t* to)
|
|
||||||
{
|
|
||||||
if (swapcontext(from, to) < 0) {
|
|
||||||
printf("swapcontext is fail\n");
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
assertstack(uint n)
|
|
||||||
{
|
|
||||||
Task* t;
|
|
||||||
|
|
||||||
t = taskrunning;
|
|
||||||
if ((uchar*)&t <= (uchar*)t->stk || (uchar*)&t - (uchar*)t->stk < 256 + n) {
|
|
||||||
/* satck over flow */
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
taskscheduler(void)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
Task* t;
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
if (taskcount == 0)
|
|
||||||
exit(taskexitval);
|
|
||||||
t = taskrunqueue.head;
|
|
||||||
if (t == nil) {
|
|
||||||
/* nothing to do */
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
deltask(&taskrunqueue, t); /* delete from runqueue */
|
|
||||||
t->ready = 0;
|
|
||||||
taskrunning = t;
|
|
||||||
tasknswitch++;
|
|
||||||
contextswitch(&taskschedcontext, &t->uc);
|
|
||||||
taskrunning = nil; /* ready for next task */
|
|
||||||
if (t->exiting) {
|
|
||||||
taskcount--;
|
|
||||||
i = t->alltaskslot;
|
|
||||||
alltask[i] = alltask[--nalltask];
|
|
||||||
alltask[i]->alltaskslot = i;
|
|
||||||
free(t);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static char* argv0;
|
|
||||||
static int taskargc;
|
|
||||||
static char** taskargv;
|
|
||||||
int mainstacksize;
|
|
||||||
|
|
||||||
static void
|
|
||||||
taskmainstart(void* v)
|
|
||||||
{
|
|
||||||
taskmain(taskargc, taskargv);
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
main(int argc, char** argv)
|
|
||||||
{
|
|
||||||
struct sigaction sa, osa;
|
|
||||||
|
|
||||||
memset(&sa, 0, sizeof(sigaction));
|
|
||||||
sa.sa_handler = taskinfo;
|
|
||||||
sa.sa_flags = SA_RESTART;
|
|
||||||
sigaction(SIGQUIT, &sa, &osa);
|
|
||||||
/*sigaction(SIGINFO, &sa, &osa);*/
|
|
||||||
argv0 = argv[0];
|
|
||||||
taskargc = argc;
|
|
||||||
taskargv = argv;
|
|
||||||
mainstacksize = 256 * 1024;
|
|
||||||
taskcreate(taskmainstart, nil, mainstacksize);
|
|
||||||
taskscheduler();
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
138
co/task.h
138
co/task.h
@ -1,138 +0,0 @@
|
|||||||
#ifndef _TASK_H_
|
|
||||||
#define _TASK_H_
|
|
||||||
|
|
||||||
typedef struct Task Task;
|
|
||||||
typedef struct Tasklist Tasklist;
|
|
||||||
|
|
||||||
struct Tasklist
|
|
||||||
{
|
|
||||||
Task* head;
|
|
||||||
Task* tail;
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct QLock
|
|
||||||
{
|
|
||||||
Task* owner;
|
|
||||||
Tasklist waiting;
|
|
||||||
} QLock;
|
|
||||||
|
|
||||||
void
|
|
||||||
taskmain(int argc, char** argv);
|
|
||||||
int
|
|
||||||
taskyield(void);
|
|
||||||
void
|
|
||||||
taskexitall(int val);
|
|
||||||
int
|
|
||||||
taskcreate(void (*fn)(void*), void* arg, unsigned int stk);
|
|
||||||
void
|
|
||||||
taskready(Task* t);
|
|
||||||
void
|
|
||||||
taskexit(int val);
|
|
||||||
void
|
|
||||||
taskswitch(void);
|
|
||||||
void
|
|
||||||
assertstack(unsigned int n);
|
|
||||||
|
|
||||||
void
|
|
||||||
qlock(QLock*);
|
|
||||||
int
|
|
||||||
canqlock(QLock*);
|
|
||||||
void
|
|
||||||
qunlock(QLock*);
|
|
||||||
QLock*
|
|
||||||
newqlock();
|
|
||||||
|
|
||||||
typedef struct Rendez Rendez;
|
|
||||||
struct Rendez
|
|
||||||
{
|
|
||||||
QLock* l;
|
|
||||||
Tasklist waiting;
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
tasksleep(Rendez*);
|
|
||||||
int
|
|
||||||
taskwakeup(Rendez*);
|
|
||||||
int
|
|
||||||
taskwakeupall(Rendez*);
|
|
||||||
Rendez*
|
|
||||||
newrendez(QLock* l);
|
|
||||||
|
|
||||||
extern Task* taskrunning;
|
|
||||||
extern int taskcount;
|
|
||||||
|
|
||||||
typedef struct Alt Alt;
|
|
||||||
typedef struct Altarray Altarray;
|
|
||||||
typedef struct Channel Channel;
|
|
||||||
|
|
||||||
enum chan_op
|
|
||||||
{
|
|
||||||
CHANEND,
|
|
||||||
CHANSND,
|
|
||||||
CHANRCV,
|
|
||||||
CHANNOP,
|
|
||||||
CHANNOBLK,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Alt
|
|
||||||
{
|
|
||||||
Channel* c;
|
|
||||||
void* v;
|
|
||||||
enum chan_op op;
|
|
||||||
Task* task;
|
|
||||||
Alt* xalt;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Altarray
|
|
||||||
{
|
|
||||||
Alt** a;
|
|
||||||
unsigned int n;
|
|
||||||
unsigned int m;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Channel
|
|
||||||
{
|
|
||||||
unsigned int bufsize;
|
|
||||||
unsigned int elemsize;
|
|
||||||
unsigned char* buf;
|
|
||||||
unsigned int nbuf;
|
|
||||||
unsigned int off;
|
|
||||||
Altarray asend;
|
|
||||||
Altarray arecv;
|
|
||||||
char* name;
|
|
||||||
};
|
|
||||||
|
|
||||||
Channel*
|
|
||||||
newchan(int elemsize, int bufsize);
|
|
||||||
void
|
|
||||||
deletechan(Channel* c);
|
|
||||||
int
|
|
||||||
chansend(Channel* c, void* v);
|
|
||||||
int
|
|
||||||
chanbsend(Channel* c, void* v);
|
|
||||||
int
|
|
||||||
chanrecv(Channel* c, void* v);
|
|
||||||
int
|
|
||||||
chanbrecv(Channel* c, void* v);
|
|
||||||
int
|
|
||||||
chansendp(Channel* c, void* v);
|
|
||||||
void*
|
|
||||||
chanrecvp(Channel* c);
|
|
||||||
int
|
|
||||||
channbsend(Channel* c, void* v);
|
|
||||||
int
|
|
||||||
channbsendp(Channel* c, void* v);
|
|
||||||
void*
|
|
||||||
channbrecvp(Channel* c);
|
|
||||||
int
|
|
||||||
channbrecv(Channel* c, void* v);
|
|
||||||
int
|
|
||||||
chansendul(Channel* c, unsigned long v);
|
|
||||||
unsigned long
|
|
||||||
chanrecvul(Channel* c);
|
|
||||||
int
|
|
||||||
channbsendul(Channel* c, unsigned long v);
|
|
||||||
int
|
|
||||||
channbrecvul(Channel* c, unsigned long v);
|
|
||||||
|
|
||||||
#endif
|
|
||||||
@ -1,44 +0,0 @@
|
|||||||
#include "task.h"
|
|
||||||
#include <assert.h>
|
|
||||||
#include <signal.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <ucontext.h>
|
|
||||||
|
|
||||||
#define nil ((void*)0)
|
|
||||||
#define nelem(x) (sizeof(x) / sizeof((x)[0]))
|
|
||||||
|
|
||||||
typedef unsigned long ulong;
|
|
||||||
typedef unsigned int uint;
|
|
||||||
typedef unsigned char uchar;
|
|
||||||
typedef unsigned long long uvlong;
|
|
||||||
typedef long long vlong;
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
STACK = 8192,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Task
|
|
||||||
{
|
|
||||||
Task* next;
|
|
||||||
Task* prev;
|
|
||||||
Task* allnext;
|
|
||||||
Task* allprev;
|
|
||||||
ucontext_t uc;
|
|
||||||
uvlong alarmtime;
|
|
||||||
uint id;
|
|
||||||
uchar* stk;
|
|
||||||
uint stksize;
|
|
||||||
int exiting;
|
|
||||||
int alltaskslot;
|
|
||||||
int ready;
|
|
||||||
void (*startfn)(void*);
|
|
||||||
void* startarg;
|
|
||||||
};
|
|
||||||
|
|
||||||
void
|
|
||||||
deltask(Tasklist* l, Task* t);
|
|
||||||
|
|
||||||
void
|
|
||||||
addtask(Tasklist* l, Task* t);
|
|
||||||
7
gb.c
7
gb.c
@ -1,5 +1,4 @@
|
|||||||
#include "gb.h"
|
#include "gb.h"
|
||||||
#include "co/task.h"
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
@ -146,8 +145,8 @@ colinit(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
int
|
||||||
taskmain(int argc, char* argv[])
|
main(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
loadrom(romname = argv[1]);
|
loadrom(romname = argv[1]);
|
||||||
colinit();
|
colinit();
|
||||||
@ -155,7 +154,7 @@ taskmain(int argc, char* argv[])
|
|||||||
initevent();
|
initevent();
|
||||||
meminit();
|
meminit();
|
||||||
reset();
|
reset();
|
||||||
taskcreate(pputask, 0, 32768);
|
ppuinit();
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
int t = step();
|
int t = step();
|
||||||
|
|||||||
8
gb.h
8
gb.h
@ -134,6 +134,12 @@ enum
|
|||||||
|
|
||||||
enum { NEVENT = 2 };
|
enum { NEVENT = 2 };
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
REG_RIP = 7,
|
||||||
|
REG_RSP = 6,
|
||||||
|
};
|
||||||
|
|
||||||
typedef uint8_t u8;
|
typedef uint8_t u8;
|
||||||
typedef uint16_t u16;
|
typedef uint16_t u16;
|
||||||
typedef int8_t i8;
|
typedef int8_t i8;
|
||||||
@ -210,7 +216,7 @@ hblanktick(void*);
|
|||||||
void
|
void
|
||||||
ppusync(void);
|
ppusync(void);
|
||||||
void
|
void
|
||||||
pputask(void*);
|
ppuinit(void);
|
||||||
|
|
||||||
/* cpu */
|
/* cpu */
|
||||||
int
|
int
|
||||||
|
|||||||
30
jmp.S
Normal file
30
jmp.S
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
.global psetjmp
|
||||||
|
.type psetjmp,@function
|
||||||
|
psetjmp:
|
||||||
|
mov %rbx,(%rdi) /* rdi is jmp_buf, move registers onto it */
|
||||||
|
mov %rbp,8(%rdi)
|
||||||
|
mov %r12,16(%rdi)
|
||||||
|
mov %r13,24(%rdi)
|
||||||
|
mov %r14,32(%rdi)
|
||||||
|
mov %r15,40(%rdi)
|
||||||
|
lea 8(%rsp),%rdx /* this is our rsp WITHOUT current ret addr */
|
||||||
|
mov %rdx,48(%rdi)
|
||||||
|
mov (%rsp),%rdx /* save return addr ptr for new rip */
|
||||||
|
mov %rdx,56(%rdi)
|
||||||
|
xor %eax,%eax /* always return 0 */
|
||||||
|
ret
|
||||||
|
|
||||||
|
.global plongjmp
|
||||||
|
.type plongjmp,@function
|
||||||
|
plongjmp:
|
||||||
|
xor %eax,%eax
|
||||||
|
cmp $1,%esi /* CF = val ? 0 : 1 */
|
||||||
|
adc %esi,%eax /* eax = val + !val */
|
||||||
|
mov (%rdi),%rbx /* rdi is the jmp_buf, restore regs from it */
|
||||||
|
mov 8(%rdi),%rbp
|
||||||
|
mov 16(%rdi),%r12
|
||||||
|
mov 24(%rdi),%r13
|
||||||
|
mov 32(%rdi),%r14
|
||||||
|
mov 40(%rdi),%r15
|
||||||
|
mov 48(%rdi),%rsp
|
||||||
|
jmp *56(%rdi)
|
||||||
32
ppu.c
32
ppu.c
@ -1,15 +1,17 @@
|
|||||||
#include "co/task.h"
|
|
||||||
#include "gb.h"
|
#include "gb.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#define ryield() {if(psetjmp(renderjmp) == 0) plongjmp(mainjmp, 1);}
|
||||||
|
#define myield() {if(psetjmp(mainjmp) == 0) plongjmp(renderjmp, 1);}
|
||||||
#define eat(nc) \
|
#define eat(nc) \
|
||||||
if (cyc <= nc) { \
|
if (cyc <= nc) { \
|
||||||
for (i = 0; i < nc; i++) \
|
for (i = 0; i < nc; i++) \
|
||||||
if (--cyc == 0) \
|
if (--cyc == 0) \
|
||||||
taskyield(); \
|
ryield(); \
|
||||||
} else \
|
} else \
|
||||||
cyc -= nc;
|
cyc -= nc;
|
||||||
|
|
||||||
|
typedef void *jmp_buf[10];
|
||||||
typedef struct sprite sprite;
|
typedef struct sprite sprite;
|
||||||
struct sprite
|
struct sprite
|
||||||
{
|
{
|
||||||
@ -31,6 +33,7 @@ enum
|
|||||||
TILSPR = 0x04,
|
TILSPR = 0x04,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
jmp_buf mainjmp,renderjmp;
|
||||||
u8 ppustate, ppuy, ppuw;
|
u8 ppustate, ppuy, ppuw;
|
||||||
u64 hblclock, rendclock;
|
u64 hblclock, rendclock;
|
||||||
static int cyc, ppux, ppux0;
|
static int cyc, ppux, ppux0;
|
||||||
@ -39,14 +42,19 @@ sprite spr[10], *sprm;
|
|||||||
Var ppuvars[] = {VAR(ppustate), VAR(ppuy), VAR(hblclock), VAR(rendclock),
|
Var ppuvars[] = {VAR(ppustate), VAR(ppuy), VAR(hblclock), VAR(rendclock),
|
||||||
{nil, 0, 0}};
|
{nil, 0, 0}};
|
||||||
|
|
||||||
void
|
extern int psetjmp(jmp_buf buf);
|
||||||
pputask(void* _)
|
extern void plongjmp(jmp_buf buf, int v);
|
||||||
|
|
||||||
|
static void
|
||||||
|
ppurender(void)
|
||||||
{
|
{
|
||||||
int x, y, i, n, m, win;
|
int x, y, i, n, m, win;
|
||||||
u16 ta, ca, chr;
|
u16 ta, ca, chr;
|
||||||
u8 tile;
|
u8 tile;
|
||||||
u32 sr[8], *picp;
|
u32 sr[8], *picp;
|
||||||
|
|
||||||
|
ryield();
|
||||||
|
|
||||||
for (;;) {
|
for (;;) {
|
||||||
eat(6 * 2);
|
eat(6 * 2);
|
||||||
m = 168 + (reg[SCX] & 7);
|
m = 168 + (reg[SCX] & 7);
|
||||||
@ -82,7 +90,7 @@ pputask(void* _)
|
|||||||
if (cyc <= 2 * 8) {
|
if (cyc <= 2 * 8) {
|
||||||
for (i = 0; i < 2 * 8; ++i)
|
for (i = 0; i < 2 * 8; ++i)
|
||||||
if (--cyc == 0)
|
if (--cyc == 0)
|
||||||
taskyield();
|
ryield();
|
||||||
y = ppuy + reg[SCY] << 1 & 14;
|
y = ppuy + reg[SCY] << 1 & 14;
|
||||||
ta = 0x1800 | reg[LCDC] << 7 & 0x400 | ppuy + reg[SCY] << 2 & 0x3E0 |
|
ta = 0x1800 | reg[LCDC] << 7 & 0x400 | ppuy + reg[SCY] << 2 & 0x3E0 |
|
||||||
ta & 0x1F;
|
ta & 0x1F;
|
||||||
@ -108,7 +116,7 @@ pputask(void* _)
|
|||||||
m = 175 - reg[WX];
|
m = 175 - reg[WX];
|
||||||
goto restart;
|
goto restart;
|
||||||
}
|
}
|
||||||
taskyield();
|
ryield();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -211,7 +219,7 @@ ppusync(void)
|
|||||||
return;
|
return;
|
||||||
cyc = clock - rendclock;
|
cyc = clock - rendclock;
|
||||||
if (cyc != 0)
|
if (cyc != 0)
|
||||||
taskyield();
|
myield();
|
||||||
sprites();
|
sprites();
|
||||||
rendclock = clock;
|
rendclock = clock;
|
||||||
}
|
}
|
||||||
@ -287,3 +295,13 @@ hblanktick(void* _)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
ppuinit(void)
|
||||||
|
{
|
||||||
|
static u8 stk[8192];
|
||||||
|
|
||||||
|
renderjmp[REG_RSP] = stk + sizeof(stk) - 64;
|
||||||
|
renderjmp[REG_RIP] = ppurender;
|
||||||
|
myield();
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user