on master help sign in
Fix deadlock in RTS when using allocation in native code

When marking a section of memory for allocation using requireAlloc, any requests to the allocate function (which would generally happen from native code, such as the SDL library) would try and acquire the same allocation lock. The fix makes this a reentrant lock.

commitaa911216474b8eff4144318291f511d8d6ae281c authorSimon Fowler <sf37@st-andrews.ac.uk> dateTue 1 Apr 2014, 11:08 (13 years ago) parentd763c9c
1 file changed+12−3
rts/idris_rts.c+12−3
rts/idris_rts.c+12−3
@@ -37,9 +37,18 @@ VM* init_vm(int stack_size, size_t heap_size,
3737 vm->inbox_ptr = vm->inbox;
3838 vm->inbox_write = vm->inbox;
3939
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);
48+
4049 pthread_mutex_init(&(vm->inbox_lock), NULL);
4150 pthread_mutex_init(&(vm->inbox_block), NULL);
42− pthread_mutex_init(&(vm->alloc_lock), NULL);
51+ pthread_mutex_init(&(vm->alloc_lock), &rec_attr);
4352 pthread_cond_init(&(vm->inbox_waiting), NULL);
4453
4554 vm->max_threads = max_threads;
@@ -72,14 +81,14 @@ void idris_requireAlloc(VM* vm, size_t size) {
7281 }
7382
7483 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
7685 pthread_mutex_lock(&vm->alloc_lock);
7786 }
7887}
7988
8089void idris_doneAlloc(VM* vm) {
8190 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
8392 pthread_mutex_unlock(&vm->alloc_lock);
8493 }
8594}