On Thursday, August 1, 2013 9:43:52 PM UTC-5, luser droog wrote:
>
> So I plan to simulate multiple threads in a single OS-thread.
>
>
>
> Here's a very simple mock-up of how I imagine this to work.
>
> Functions (tasks) are not pre-empted during execution, so each thread
>
> can consider longer sequences of execution to be atomic.
>
>
>
Here's a more filled-out sketch of the same setjmp/longjmp
multitasking in an interpreter framework.
All functions pass-in a context structure, so there are
virtually no global variables (excepting the jmpbuf, and
string vectors corresponding to type and error enums).
vm.c:
#define _BSD_SOURCE
#define _GNU_SOURCE
#include <setjmp.h>
#include <stdbool.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "ob.h"
#define GLOBAL_FILE "global.img"
inline byte type(OBJ q) { return q.tag & typemask; }
/* constructors */
OBJ null = { .tag = nulltype };
OBJ mark = { .tag = marktype };
OBJ consbool (bool b) {
OBJ o = { .tag = booleantype };
o.BOOL.val = b;
return o;
}
OBJ consint (integer i) {
OBJ o = { .tag = integertype };
o.INT.val = i;
return o;
}
OBJ consreal (real r) {
OBJ o = { .tag = realtype };
o.REAL.val = r;
return o;
}
/* virtual memory space */
typedef struct memspace {
byte *base;
ulong used, max;
} memspace;
int pagesize /*= getpagesize()*/;
bool meminit (memspace *spc, int fd) {
spc->base = mmap( NULL,
spc->max = pagesize,
PROT_READ|PROT_WRITE,
fd!=-1?
MAP_SHARED:
MAP_SHARED|MAP_ANONYMOUS,
fd, 0 );
spc->used = 0;
return true;
}
addr memalloc (memspace *spc, ulong n) {
addr a;
if (spc->max - spc->used > n) {
int newmax = spc->max + (n/pagesize + 1)*pagesize;
spc->base = mremap(spc->base, spc->max, newmax, MREMAP_MAYMOVE);
spc->max = newmax;
}
a = spc->used;
spc->used += n;
return a;
}
/* machine state */
typedef struct mach {
memspace *vm[2]; /* 0-global, 1-local */
} mach;
bool machinit(mach *ma, memspace *glo) {
ma->vm[0] = glo;
ma->vm[1] = malloc(sizeof*ma->vm[1]);
return /*meminit(ma->vm, -1)
&& */meminit(ma->vm[1], -1);
}
bool init(mach *mp, int n) {
pagesize = getpagesize();
memspace *glo;
int memfil;
memfil = open( GLOBAL_FILE , O_RDWR);
if (memfil == -1) {
memfil = open( GLOBAL_FILE , O_CREAT|O_RDWR, 777);
}
glo = malloc(sizeof*glo);
meminit(glo, memfil);
int i;
for (i=0; i<n; i++)
machinit(mp+i, glo);
return true;
}
/* if LOCAL_BIT is set in an addr,
the address refers to local vm (ma->vm[1]) */
enum { LOCAL_BIT = 0x80000000 };
addr newbuf (mach *ma, int local, ulong n) {
addr a;
memspace *spc = ma->vm[local];
a = memalloc(spc, n);
if (local) a |= LOCAL_BIT;
return a;
}
inline byte *paddr(mach *ma, addr a) {
int local = !!(a & LOCAL_BIT);
return ma->vm[local]->base + (a & ~LOCAL_BIT);
}
addr newblock (mach *ma, ulong n) {
//add to delete list for currentsavelevel
}
inline OBJ srceval (mach *ma, OBJ q) {
//token
return q;
}
inline OBJ nameval (mach *ma, OBJ q) {
//load
return q;
}
inline OBJ arreval (mach *ma, OBJ q) {
//getinterval pushe
//get
return q;
}
inline OBJ opreval (mach *ma, OBJ q) {
//opexec
return q;
}
inline void liteval (mach *ma, OBJ q) {
//push
}
void eval (mach *ma) {
OBJ q /*= pope()*/;
if ( q.tag & exe ) switch (type(q)) {
default: break;
case filetype:
case stringtype: q = srceval(ma,q); return;
case nametype: q = nameval(ma,q); return;
case arraytype: q = arreval(ma,q); return;
case operatortype: q = opreval(ma,q); return;
}
liteval(ma,q); return;
}
jmp_buf taskswitch;
bool taskswitchvalid = false;
void run (mach *ma, int num_mach) {
static int i = 0;
if (setjmp(taskswitch))
i = (i+1) % num_mach;
taskswitchvalid = true;
while(!ma[i].quit)
eval(ma+i);
taskswitchvalid = false;
}
enum { NUM_MACHINES = 2 };
mach ines[NUM_MACHINES];
int main(int argc, char *argv[]) {
init(ines, NUM_MACHINES);
run(ines, NUM_MACHINES);
return 0;
}
/* eof */
ob.h:
typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned long dword;
typedef long integ;
typedef float real;
typedef dword addr;
#define TYPES(_) \
_(invalid) \
_(null) \
_(mark) \
_(boolean) \
_(integer) \
_(real) \
_(string) \
_(name) \
_(array) \
_(dict) \
_(file) \
_(operator) \
_(packedarray) \
/* end TYPES */
#define AS_TYPE(X) X ## type ,
enum type { TYPES(AS_TYPE) };
enum tagmask {
exe = 0x8000,
Aread = 0x4000,
Awrite = 0x2000,
Aexec = 0x1000,
typemask = 0x00FF,
};
//#define type(o) ((o).tag & typemask)
typedef struct {
word tag;
} MARK;
typedef struct {
word tag;
byte val;
} BOOL;
typedef struct {
word tag;
integ val;
} INT;
typedef struct {
word tag;
real val;
} REAL;
typedef struct {
word tag;
word siz;
addr adr;
} STR;
typedef struct {
word tag;
word siz;
addr adr;
} ARR;
typedef struct {
word tag;
word siz;
addr adr;
} DIC;
typedef struct {
word tag;
word siz;
addr adr;
} FIL;
typedef struct {
word tag;
word opcode;
} OP;
typedef union {
byte tag;
INT INT;
MARK MARK;
BOOL BOOL;
REAL REAL;
STR STR;
ARR ARR;
DIC DIC;
FIL FIL;
OP OP;
} OBJ;