on master help sign in
Added fork (but not working properly yet)
commitc02a58c5f5ab87d8f2b3a2a66997e892b82c09cd authorEdwin Brady <eb@cs.st-andrews.ac.uk> dateSat 22 Sep 2012, 12:58 (14 years ago) parent2303235
11 files changed+197−5
lib/io.idr+3 rts/idris_main.c+1 rts/idris_rts.c+155 rts/idris_rts.h+26−1 src/IRTS/CodegenC.hs+3−1 src/IRTS/Compiler.hs+3 src/IRTS/Defunctionalise.hs+1 src/IRTS/Lang.hs+1−1 src/Idris/Primitives.hs+2 src/Main.hs+1−1 src/Util/System.hs+1−1
lib/io.idr+3
@@ -47,4 +47,7 @@ mkForeign : Foreign x -> x
4747mkLazyForeign : Foreign x -> x
4848-- mkForeign and mkLazyForeign compiled as primitives
4949
50+fork : |(thread:IO ()) -> IO Ptr
51+fork x = io_return prim__vm -- compiled specially
52+
5053
rts/idris_main.c+1
@@ -5,4 +5,5 @@ int main(int argc, char* argv[]) {
55#ifdef IDRIS_TRACE
66 gcInfo(vm, 1);
77#endif
8+ terminate(vm);
89}
rts/idris_rts.c+155
@@ -3,6 +3,8 @@
33#include <string.h>
44#include <unistd.h>
55#include <stdarg.h>
6+#include <assert.h>
7+#include <pthread.h>
68
79#include "idris_rts.h"
810#include "idris_gc.h"
@@ -31,9 +33,32 @@ VM* init_vm(int stack_size, size_t heap_size) {
3133 vm -> heap_growth = heap_size;
3234 vm -> ret = NULL;
3335 vm -> reg1 = NULL;
36+
37+ vm -> inbox = malloc(1024*sizeof(VAL));
38+ vm -> inbox_end = vm -> inbox + 1024;
39+ vm -> inbox_ptr = vm -> inbox;
40+ vm -> inbox_write = vm -> inbox;
41+
42+ pthread_mutex_init(&(vm -> inbox_lock), NULL);
43+ pthread_mutex_init(&(vm -> inbox_block), NULL);
44+ pthread_cond_init(&(vm -> inbox_waiting), NULL);
45+
3446 return vm;
3547}
3648
49+void terminate(VM* vm) {
50+ free(vm->inbox);
51+ free(vm->valstack);
52+ free(vm->intstack);
53+ free(vm->floatstack);
54+ free(vm->heap);
55+ if (vm->oldheap != NULL) { free(vm->oldheap); }
56+ pthread_mutex_destroy(&(vm -> inbox_lock));
57+ pthread_mutex_destroy(&(vm -> inbox_block));
58+ pthread_cond_destroy(&(vm -> inbox_waiting));
59+ free(vm);
60+}
61+
3762void* allocate(VM* vm, size_t size) {
3863// return malloc(size);
3964 if ((size & 7)!=0) {
@@ -305,6 +330,136 @@ VAL idris_strRev(VM* vm, VAL str) {
305330 return cl;
306331}
307332
333+typedef struct {
334+ VM* vm;
335+ func fn;
336+ VAL arg;
337+} ThreadData;
338+
339+void* runThread(void* arg) {
340+ ThreadData* td = (ThreadData*)arg;
341+ VM* vm = td->vm;
342+
343+ printf("We're off\n");
344+
345+ TOP(0) = td->arg;
346+ BASETOP(0);
347+ ADDTOP(1);
348+ td->fn(vm, NULL);
349+
350+ printf("We're done\n");
351+ free(td);
352+}
353+
354+void* vmThread(VM* callvm, func f, VAL arg) {
355+ VM* vm = init_vm(callvm->stack_max - callvm->valstack, callvm->heap_size);
356+ pthread_t t;
357+ pthread_attr_t attr;
358+ size_t stacksize;
359+
360+ pthread_attr_init(&attr);
361+ pthread_attr_getstacksize (&attr, &stacksize);
362+ pthread_attr_setstacksize (&attr, stacksize*64);
363+ printf("Default stack size = %li\n", stacksize);
364+
365+ ThreadData *td = malloc(sizeof(ThreadData));
366+ td->vm = vm;
367+ td->fn = f;
368+ td->arg = copyTo(vm, arg);
369+
370+ dumpVal(arg);
371+ dumpVal(td->arg);
372+
373+ printf("Threading\n");
374+ pthread_create(&t, &attr, runThread, td);
375+ return vm;
376+}
377+
378+// VM is assumed to be a different vm from the one x lives on (so we don't need
379+// to worry about gc moving things, as the VM x is on will not be allocating)
380+
381+VAL copyTo(VM* vm, VAL x) {
382+ int i;
383+ VAL* argptr;
384+ Closure* cl;
385+ if (x==NULL || ISINT(x)) {
386+ return x;
387+ }
388+ switch(x->ty) {
389+ case CON:
390+ cl = allocCon(vm, x->info.c.arity);
391+ cl->info.c.tag = x->info.c.tag;
392+ cl->info.c.arity = x->info.c.arity;
393+
394+ argptr = (VAL*)(cl->info.c.args);
395+ for(i = 0; i < x->info.c.arity; ++i) {
396+ *argptr = copyTo(vm, *((VAL*)(x->info.c.args)+i)); // recursive version
397+ argptr++;
398+ }
399+ break;
400+ case FLOAT:
401+ cl = MKFLOAT(vm, x->info.f);
402+ break;
403+ case STRING:
404+ cl = MKSTR(vm, x->info.str);
405+ break;
406+ case BIGINT:
407+ cl = MKBIGM(vm, x->info.ptr);
408+ break;
409+ case PTR:
410+ cl = MKPTR(vm, x->info.ptr);
411+ break;
412+ case FWD:
413+ assert(0); // We're in trouble if this happens...
414+ return x->info.ptr;
415+ }
416+ return cl;
417+}
418+
419+// Add a message to another VM's message queue
420+void sendMessage(VM* sender, VM* dest, VAL msg) {
421+ VAL dmsg = copyTo(dest, msg);
422+ pthread_mutex_lock(&(dest->inbox_lock));
423+
424+ *(dest->inbox_write) = dmsg;
425+
426+ dest->inbox_write++;
427+ if (dest->inbox_write >= dest->inbox_end) {
428+ dest->inbox_write = dest->inbox;
429+ }
430+
431+ if (dest->inbox_write == dest->inbox_ptr) {
432+ fprintf(stderr, "Inbox full"); // Maybe grow it instead...
433+ exit(-1);
434+ }
435+
436+ // Wake up the other thread
437+ pthread_cond_signal(&(dest->inbox_waiting));
438+
439+ pthread_mutex_unlock(&(dest->inbox_lock));
440+}
441+
442+// block until there is a message in the queue
443+VAL recvMessage(VM* vm) {
444+ pthread_mutex_lock(&vm->inbox_block);
445+ pthread_cond_wait(&vm->inbox_waiting, &vm->inbox_block);
446+
447+ VAL msg = *(vm->inbox_ptr);
448+ if (msg != NULL) {
449+ pthread_mutex_lock(&(vm->inbox_lock));
450+ *(vm->inbox_ptr) = NULL;
451+ vm->inbox_ptr++;
452+ if (vm->inbox_ptr >= vm->inbox_end) {
453+ vm->inbox_ptr = vm->inbox;
454+ }
455+ pthread_mutex_unlock(&(vm->inbox_lock));
456+ } else {
457+ fprintf(stderr, "No messages waiting");
458+ exit(-1);
459+ }
460+
461+ pthread_mutex_unlock(&vm->inbox_block);
462+}
308463
309464void stackOverflow() {
310465 fprintf(stderr, "Stack overflow");
rts/idris_rts.h+26−1
@@ -6,11 +6,12 @@
66#include <string.h>
77#include <unistd.h>
88#include <stdarg.h>
9+#include <pthread.h>
910
1011// Closures
1112
1213typedef enum {
13− CON, INT, BIGINT, FLOAT, STRING, UNIT, PTR, FWD
14+ CON, INT, BIGINT, FLOAT, STRING, UNIT, PTR, MSG, FWD
1415} ClosureType;
1516
1617typedef struct {
@@ -45,6 +46,17 @@ typedef struct {
4546 char* heap_next;
4647 char* heap_end;
4748 VAL* stack_max;
49+
50+ pthread_mutex_t inbox_lock;
51+ pthread_mutex_t inbox_block;
52+ pthread_cond_t inbox_waiting;
53+
54+ VAL* inbox; // Block of memory for storing messages
55+ VAL* inbox_end; // End of block of memory
56+
57+ VAL* inbox_ptr; // Next message to read
58+ VAL* inbox_write; // Location of next message to write
59+
4860 size_t heap_size;
4961 size_t heap_growth;
5062 int allocations;
@@ -53,7 +65,10 @@ typedef struct {
5365 VAL reg1;
5466} VM;
5567
68+// Create a new VM
5669VM* init_vm(int stack_size, size_t heap_size);
70+// Clean up a VM once it's no longer needed
71+void terminate(VM* vm);
5772
5873// Functions all take a pointer to their VM, and previous stack base,
5974// and return nothing.
@@ -118,6 +133,16 @@ void SLIDE(VM* vm, int args);
118133void* allocate(VM* vm, size_t size);
119134void* allocCon(VM* vm, int arity);
120135
136+void* vmThread(VM* callvm, func f, VAL arg);
137+
138+// Copy a structure to another vm's heap
139+VAL copyTo(VM* newVM, VAL x);
140+
141+// Add a message to another VM's message queue
142+void sendMessage(VM* sender, VM* dest, VAL msg);
143+// block until there is a message in the queue
144+VAL recvMessage(VM* vm);
145+
121146void dumpVal(VAL r);
122147void dumpStack(VM* vm);
123148
src/IRTS/CodegenC.hs+3−1
@@ -44,7 +44,7 @@ codegenC defs out exec incs objs libs dbg
4444 gccDbg dbg ++
4545 " " ++ tmpn ++
4646 " `idris --link` `idris --include` " ++ libs ++
47− " -lidris_rts -lgmp -o " ++ out
47+ " -o " ++ out
4848 -- putStrLn cout
4949 exit <- system gcc
5050 when (exit /= ExitSuccess) $
@@ -237,5 +237,7 @@ doOp v LStdIn [] = v ++ "MKPTR(vm, stdin)"
237237doOp v LStdOut [] = v ++ "MKPTR(vm, stdout)"
238238doOp v LStdErr [] = v ++ "MKPTR(vm, stderr)"
239239
240+doOp v LFork [x] = v ++ "vmThread(vm, " ++ cname (MN 0 "EVAL") ++ ", " ++ creg x ++ ")"
241+doOp v LVMPtr [] = v ++ "MKPTR(vm, vm)"
240242doOp v LNoOp [x] = ""
241243doOp _ _ _ = "FAIL"
src/IRTS/Compiler.hs+3
@@ -114,6 +114,9 @@ instance ToIR (TT Name) where
114114 | (P _ (UN "lazy") _, [_, arg]) <- unApply tm
115115 = do arg' <- ir' env arg
116116 return $ LLazyExp arg'
117+ | (P _ (UN "fork") _, [arg]) <- unApply tm
118+ = do arg' <- ir' env arg
119+ return $ LOp LFork [LLazyExp arg']
117120 | (P _ (UN "prim__IO") _, [v]) <- unApply tm
118121 = do v' <- ir' env v
119122 return v'
src/IRTS/Defunctionalise.hs+1
@@ -63,6 +63,7 @@ addApps defs (n, LFun _ args e) = (n, LFun n args (aa args e))
6363 aa env (LCase e alts) = LCase (eEVAL (aa env e)) (map (aaAlt env) alts)
6464 aa env (LConst c) = LConst c
6565 aa env (LForeign l t n args) = LForeign l t n (map (aaF env) args)
66+ aa env (LOp LFork args) = LOp LFork (map (aa env) args)
6667 aa env (LOp f args) = LOp f (map (eEVAL . (aa env)) args)
6768 aa env (LError e) = LError e
6869
src/IRTS/Lang.hs+1−1
@@ -36,7 +36,7 @@ data PrimFn = LPlus | LMinus | LTimes | LDiv | LEq | LLt | LLe | LGt | LGe
3636
3737 | LStrHead | LStrTail | LStrCons | LStrIndex | LStrRev
3838 | LStdIn | LStdOut | LStdErr
39− | LNoOp
39+ | LFork | LVMPtr | LNoOp
4040 deriving (Show, Eq)
4141
4242-- Supported target languages for foreign calls
src/Idris/Primitives.hs+2
@@ -163,6 +163,8 @@ primitives =
163163 (1, LStrRev) total,
164164 Prim (UN "prim__readString") (ty [PtrType] StrType) 1 (p_cantreduce)
165165 (1, LReadStr) partial,
166+ Prim (UN "prim__vm") (ty [] PtrType) 0 (p_cantreduce)
167+ (0, LVMPtr) total,
166168 -- Streams
167169 Prim (UN "prim__stdin") (ty [] PtrType) 0 (p_cantreduce)
168170 (0, LStdIn) partial,
src/Main.hs+1−1
@@ -130,7 +130,7 @@ showver = do putStrLn $ "Idris version " ++ ver
130130 exitWith ExitSuccess
131131
132132showLibs = do dir <- getDataDir
133− putStrLn $ "-L" ++ dir ++ "/rts -lidris_rts"
133+ putStrLn $ "-L" ++ dir ++ "/rts -lidris_rts -lgmp -lpthread"
134134 exitWith ExitSuccess
135135
136136showIncs = do dir <- getDataDir
src/Util/System.hs+1−1
@@ -21,7 +21,7 @@ tempfile = do env <- environment "TMPDIR"
2121 let dir = case env of
2222 Nothing -> "/tmp"
2323 (Just d) -> d
24− openTempFile dir "esc"
24+ openTempFile dir "idris"
2525
2626environment :: String -> IO (Maybe String)
2727environment x = catchIO (do e <- getEnv x