@@ -37,15 +37,18 @@ VM* init_vm(int stack_size, size_t heap_size,
37 vm->reg1 = NULL;
37 vm->reg1 = NULL;
39 vm->inbox = malloc(1024*sizeof(VAL));
39 vm->inbox = malloc(1024*sizeof(VAL));
40+ memset(vm->inbox, 0, 1024*sizeof(VAL));
40 vm->inbox_end = vm->inbox + 1024;
41 vm->inbox_end = vm->inbox + 1024;
41 vm->inbox_ptr = vm->inbox;
42 vm->inbox_ptr = vm->inbox;
42 vm->inbox_write = vm->inbox;
43 vm->inbox_write = vm->inbox;
44 pthread_mutex_init(&(vm->inbox_lock), NULL);
45 pthread_mutex_init(&(vm->inbox_lock), NULL);
45 pthread_mutex_init(&(vm->inbox_block), NULL);
46 pthread_mutex_init(&(vm->inbox_block), NULL);
47+ pthread_mutex_init(&(vm->alloc_lock), NULL);
46 pthread_cond_init(&(vm->inbox_waiting), NULL);
48 pthread_cond_init(&(vm->inbox_waiting), NULL);
48 vm->max_threads = max_threads;
50 vm->max_threads = max_threads;
51 // Assumption: there's enough space for this in the initial heap.
54 // Assumption: there's enough space for this in the initial heap.
@@ -73,8 +76,14 @@ void terminate(VM* vm) {
76−void* allocate(VM* vm, size_t size) {
79+void* allocate(VM* vm, size_t size, int outerlock) {
77// return malloc(size);
80// return malloc(size);
81+ int lock = vm->processes > 0 && !outerlock;
83+ if (lock) { // not message passing
84+ pthread_mutex_lock(&vm->alloc_lock);
78 if ((size & 7)!=0) {
87 if ((size & 7)!=0) {
79 size = 8 + ((size >> 3) << 3);
88 size = 8 + ((size >> 3) << 3);
@@ -84,15 +93,23 @@ void* allocate(VM* vm, size_t size) {
84 *((size_t*)(vm->heap_next)) = size + sizeof(size_t);
93 *((size_t*)(vm->heap_next)) = size + sizeof(size_t);
85 vm -> heap_next += size + sizeof(size_t);
94 vm -> heap_next += size + sizeof(size_t);
86 memset(ptr, 0, size);
95 memset(ptr, 0, size);
96+ if (lock) { // not message passing
97+ pthread_mutex_unlock(&vm->alloc_lock);
87 return ptr;
99 return ptr;
89− gc(vm);
101+ idris_gc(vm);
102+ if (lock) { // not message passing
103+ pthread_mutex_unlock(&vm->alloc_lock);
90− return allocate(vm, size);
105+ return allocate(vm, size, 0);
94−void* allocCon(VM* vm, int arity) {
110+void* allocCon(VM* vm, int arity, int outer) {
95− Closure* cl = allocate(vm, sizeof(Closure) + sizeof(VAL)*arity);
111+ Closure* cl = allocate(vm, sizeof(Closure) + sizeof(VAL)*arity,
96 SETTY(cl, CON);
113 SETTY(cl, CON);
97 if (arity == 0) {
114 if (arity == 0) {
98 cl -> info.c.args = NULL;
115 cl -> info.c.args = NULL;
@@ -106,7 +123,7 @@ void* allocCon(VM* vm, int arity) {
108VAL MKFLOAT(VM* vm, double val) {
125VAL MKFLOAT(VM* vm, double val) {
109− Closure* cl = allocate(vm, sizeof(Closure));
126+ Closure* cl = allocate(vm, sizeof(Closure), 0);
110 SETTY(cl, FLOAT);
127 SETTY(cl, FLOAT);
111 cl -> info.f = val;
128 cl -> info.f = val;
112 return cl;
129 return cl;
@@ -114,7 +131,7 @@ VAL MKFLOAT(VM* vm, double val) {
115VAL MKSTR(VM* vm, char* str) {
132VAL MKSTR(VM* vm, char* str) {
116 Closure* cl = allocate(vm, sizeof(Closure) + // Type) + sizeof(char*) +
133 Closure* cl = allocate(vm, sizeof(Closure) + // Type) + sizeof(char*) +
117− sizeof(char)*strlen(str)+1);
134+ sizeof(char)*strlen(str)+1, 0);
118 SETTY(cl, STRING);
135 SETTY(cl, STRING);
119 cl -> info.str = (char*)cl + sizeof(Closure);
136 cl -> info.str = (char*)cl + sizeof(Closure);
@@ -123,7 +140,31 @@ VAL MKSTR(VM* vm, char* str) {
125VAL MKPTR(VM* vm, void* ptr) {
142VAL MKPTR(VM* vm, void* ptr) {
126− Closure* cl = allocate(vm, sizeof(Closure));
143+ Closure* cl = allocate(vm, sizeof(Closure), 0);
145+ cl -> info.ptr = ptr;
149+VAL MKFLOATc(VM* vm, double val) {
150+ Closure* cl = allocate(vm, sizeof(Closure), 1);
156+VAL MKSTRc(VM* vm, char* str) {
157+ Closure* cl = allocate(vm, sizeof(Closure) + // Type) + sizeof(char*) +
158+ sizeof(char)*strlen(str)+1, 1);
160+ cl -> info.str = (char*)cl + sizeof(Closure);
162+ strcpy(cl -> info.str, str);
166+VAL MKPTRc(VM* vm, void* ptr) {
167+ Closure* cl = allocate(vm, sizeof(Closure), 1);
127 SETTY(cl, PTR);
168 SETTY(cl, PTR);
128 cl -> info.ptr = ptr;
169 cl -> info.ptr = ptr;
129 return cl;
170 return cl;
@@ -211,7 +252,7 @@ void dumpVal(VAL v) {
213VAL idris_castIntStr(VM* vm, VAL i) {
254VAL idris_castIntStr(VM* vm, VAL i) {
214− Closure* cl = allocate(vm, sizeof(Closure) + sizeof(char)*16);
255+ Closure* cl = allocate(vm, sizeof(Closure) + sizeof(char)*16, 0);
215 SETTY(cl, STRING);
256 SETTY(cl, STRING);
216 cl -> info.str = (char*)cl + sizeof(Closure);
257 cl -> info.str = (char*)cl + sizeof(Closure);
217 sprintf(cl -> info.str, "%d", (int)(GETINT(i)));
258 sprintf(cl -> info.str, "%d", (int)(GETINT(i)));
@@ -228,7 +269,7 @@ VAL idris_castStrInt(VM* vm, VAL i) {
230VAL idris_castFloatStr(VM* vm, VAL i) {
271VAL idris_castFloatStr(VM* vm, VAL i) {
231− Closure* cl = allocate(vm, sizeof(Closure) + sizeof(char)*32);
272+ Closure* cl = allocate(vm, sizeof(Closure) + sizeof(char)*32, 0);
232 SETTY(cl, STRING);
273 SETTY(cl, STRING);
233 cl -> info.str = (char*)cl + sizeof(Closure);
274 cl -> info.str = (char*)cl + sizeof(Closure);
234 sprintf(cl -> info.str, "%g", GETFLOAT(i));
275 sprintf(cl -> info.str, "%g", GETFLOAT(i));
@@ -244,7 +285,8 @@ VAL idris_concat(VM* vm, VAL l, VAL r) {
244 char *ls = GETSTR(l);
285 char *ls = GETSTR(l);
245 // dumpVal(l);
286 // dumpVal(l);
246 // printf("\n");
287 // printf("\n");
247− Closure* cl = allocate(vm, sizeof(Closure) + strlen(ls) + strlen(rs) + 1);
288+ Closure* cl = allocate(vm, sizeof(Closure) + strlen(ls) + strlen(rs) + 1,
248 SETTY(cl, STRING);
290 SETTY(cl, STRING);
249 cl -> info.str = (char*)cl + sizeof(Closure);
291 cl -> info.str = (char*)cl + sizeof(Closure);
250 strcpy(cl -> info.str, ls);
292 strcpy(cl -> info.str, ls);
@@ -319,7 +361,7 @@ VAL idris_strTail(VM* vm, VAL str) {
319VAL idris_strCons(VM* vm, VAL x, VAL xs) {
361VAL idris_strCons(VM* vm, VAL x, VAL xs) {
320 char *xstr = GETSTR(xs);
362 char *xstr = GETSTR(xs);
321 Closure* cl = allocate(vm, sizeof(Closure) +
363 Closure* cl = allocate(vm, sizeof(Closure) +
322− strlen(xstr) + 2);
364+ strlen(xstr) + 2, 0);
323 SETTY(cl, STRING);
365 SETTY(cl, STRING);
324 cl -> info.str = (char*)cl + sizeof(Closure);
366 cl -> info.str = (char*)cl + sizeof(Closure);
325 cl -> info.str[0] = (char)(GETINT(x));
367 cl -> info.str[0] = (char)(GETINT(x));
@@ -334,7 +376,7 @@ VAL idris_strIndex(VM* vm, VAL str, VAL i) {
334VAL idris_strRev(VM* vm, VAL str) {
376VAL idris_strRev(VM* vm, VAL str) {
335 char *xstr = GETSTR(str);
377 char *xstr = GETSTR(str);
336 Closure* cl = allocate(vm, sizeof(Closure) +
378 Closure* cl = allocate(vm, sizeof(Closure) +
337− strlen(xstr) + 1);
379+ strlen(xstr) + 1, 0);
338 SETTY(cl, STRING);
380 SETTY(cl, STRING);
339 cl -> info.str = (char*)cl + sizeof(Closure);
381 cl -> info.str = (char*)cl + sizeof(Closure);
340 int y = 0;
382 int y = 0;
@@ -348,7 +390,8 @@ VAL idris_strRev(VM* vm, VAL str) {
350typedef struct {
392typedef struct {
351− VM* vm;
393+ VM* vm; // thread's VM
394+ VM* callvm; // calling thread's VM
354} ThreadData;
397} ThreadData;
@@ -356,13 +399,16 @@ typedef struct {
356void* runThread(void* arg) {
399void* runThread(void* arg) {
357 ThreadData* td = (ThreadData*)arg;
400 ThreadData* td = (ThreadData*)arg;
358 VM* vm = td->vm;
401 VM* vm = td->vm;
402+ VM* callvm = td->callvm;
360 TOP(0) = td->arg;
404 TOP(0) = td->arg;
361 BASETOP(0);
405 BASETOP(0);
362 ADDTOP(1);
406 ADDTOP(1);
363 td->fn(vm, NULL);
407 td->fn(vm, NULL);
408+ callvm->processes--;
365 free(td);
410 free(td);
366 return NULL;
412 return NULL;
@@ -370,6 +416,7 @@ void* vmThread(VM* callvm, func f, VAL arg) {
370 VM* vm = init_vm(callvm->stack_max - callvm->valstack, callvm->heap_size,
416 VM* vm = init_vm(callvm->stack_max - callvm->valstack, callvm->heap_size,
371 callvm->max_threads,
417 callvm->max_threads,
372 0, NULL);
418 0, NULL);
419+ vm->processes=1; // since it can send and receive messages
373 pthread_t t;
420 pthread_t t;
374 pthread_attr_t attr;
421 pthread_attr_t attr;
375// size_t stacksize;
422// size_t stacksize;
@@ -380,16 +427,18 @@ void* vmThread(VM* callvm, func f, VAL arg) {
381 ThreadData *td = malloc(sizeof(ThreadData));
428 ThreadData *td = malloc(sizeof(ThreadData));
382 td->vm = vm;
429 td->vm = vm;
430+ td->callvm = callvm;
383 td->fn = f;
431 td->fn = f;
384 td->arg = copyTo(vm, arg);
432 td->arg = copyTo(vm, arg);
434+ callvm->processes++;
386 pthread_create(&t, &attr, runThread, td);
436 pthread_create(&t, &attr, runThread, td);
387// usleep(100);
437// usleep(100);
388 return vm;
438 return vm;
391−// VM is assumed to be a different vm from the one x lives on (so we don't need
441+// VM is assumed to be a different vm from the one x lives on
392−// to worry about gc moving things, as the VM x is on will not be allocating)
394VAL copyTo(VM* vm, VAL x) {
443VAL copyTo(VM* vm, VAL x) {
@@ -400,7 +449,7 @@ VAL copyTo(VM* vm, VAL x) {
401 switch(GETTY(x)) {
450 switch(GETTY(x)) {
402 case CON:
451 case CON:
403− cl = allocCon(vm, x->info.c.arity);
452+ cl = allocCon(vm, x->info.c.arity, 1);
404 cl->info.c.tag = x->info.c.tag;
453 cl->info.c.tag = x->info.c.tag;
405 cl->info.c.arity = x->info.c.arity;
454 cl->info.c.arity = x->info.c.arity;
@@ -411,16 +460,16 @@ VAL copyTo(VM* vm, VAL x) {
413 case FLOAT:
462 case FLOAT:
414− cl = MKFLOAT(vm, x->info.f);
463+ cl = MKFLOATc(vm, x->info.f);
416 case STRING:
465 case STRING:
417− cl = MKSTR(vm, x->info.str);
466+ cl = MKSTRc(vm, x->info.str);
419 case BIGINT:
468 case BIGINT:
420− cl = MKBIGM(vm, x->info.ptr);
469+ cl = MKBIGMc(vm, x->info.ptr);
422 case PTR:
471 case PTR:
423− cl = MKPTR(vm, x->info.ptr);
472+ cl = MKPTRc(vm, x->info.ptr);
426 assert(0); // We're in trouble if this happens...
475 assert(0); // We're in trouble if this happens...
@@ -433,12 +482,26 @@ void idris_sendMessage(VM* sender, VM* dest, VAL msg) {
433 // FIXME: If GC kicks in in the middle of the copy, we're in trouble.
482 // FIXME: If GC kicks in in the middle of the copy, we're in trouble.
434 // Probably best check there is enough room in advance. (How?)
483 // Probably best check there is enough room in advance. (How?)
485+ // Also a problem if we're allocating at the same time as the
486+ // destination thread (which is very likely)
487+ // Should the inbox be a different memory space?
489+ // So: we try to copy, if a collection happens, we do the copy again
490+ // under the assumption there's enough space this time.
492+ int gcs = dest->collections;
493+ pthread_mutex_lock(&dest->alloc_lock);
436 VAL dmsg = copyTo(dest, msg);
494 VAL dmsg = copyTo(dest, msg);
495+ pthread_mutex_unlock(&dest->alloc_lock);
497+ if (dest->collections>gcs) {
498+ // a collection will have invalidated the copy
499+ pthread_mutex_lock(&dest->alloc_lock);
500+ dmsg = copyTo(dest, msg); // try again now there's room...
501+ pthread_mutex_unlock(&dest->alloc_lock);
439−// printf("Sending [lock]...\n");
440 pthread_mutex_lock(&(dest->inbox_lock));
504 pthread_mutex_lock(&(dest->inbox_lock));
442 *(dest->inbox_write) = dmsg;
505 *(dest->inbox_write) = dmsg;
444 dest->inbox_write++;
507 dest->inbox_write++;