@@ -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");