@@ -37,9 +37,18 @@ VM* init_vm(int stack_size, size_t heap_size,
37 vm->inbox_ptr = vm->inbox;
37 vm->inbox_ptr = vm->inbox;
38 vm->inbox_write = vm->inbox;
38 vm->inbox_write = vm->inbox;
40+ // The allocation lock must be reentrant. The lock exists to ensure that
41+ // no memory is allocated during the message sending process, but we also
42+ // check the lock in calls to allocate.
43+ // The problem comes when we use requireAlloc to guarantee a chunk of memory
44+ // first: this sets the lock, and since it is not reentrant, we get a deadlock.
45+ pthread_mutexattr_t rec_attr;
46+ pthread_mutexattr_init(&rec_attr);
47+ pthread_mutexattr_settype(&rec_attr, PTHREAD_MUTEX_RECURSIVE);
40 pthread_mutex_init(&(vm->inbox_lock), NULL);
49 pthread_mutex_init(&(vm->inbox_lock), NULL);
41 pthread_mutex_init(&(vm->inbox_block), NULL);
50 pthread_mutex_init(&(vm->inbox_block), NULL);
42− pthread_mutex_init(&(vm->alloc_lock), NULL);
51+ pthread_mutex_init(&(vm->alloc_lock), &rec_attr);
43 pthread_cond_init(&(vm->inbox_waiting), NULL);
52 pthread_cond_init(&(vm->inbox_waiting), NULL);
45 vm->max_threads = max_threads;
54 vm->max_threads = max_threads;
@@ -72,14 +81,14 @@ void idris_requireAlloc(VM* vm, size_t size) {
74 int lock = vm->processes > 0;
83 int lock = vm->processes > 0;
75− if (lock) { // not message passing
84+ if (lock) { // We only need to lock if we're in concurrent mode
76 pthread_mutex_lock(&vm->alloc_lock);
85 pthread_mutex_lock(&vm->alloc_lock);
80void idris_doneAlloc(VM* vm) {
89void idris_doneAlloc(VM* vm) {
81 int lock = vm->processes > 0;
90 int lock = vm->processes > 0;
82− if (lock) { // not message passing
91+ if (lock) { // We only need to lock if we're in concurrent mode
83 pthread_mutex_unlock(&vm->alloc_lock);
92 pthread_mutex_unlock(&vm->alloc_lock);