3m: add missing lock in write barrier

When a future triggers a write barrier, a lock is needed to prevent a
race between the future thread and other threads in the same place (on
most platforms).

Thanks to Dominik Pantůček for tracking down this bug.
This commit is contained in:
Matthew Flatt 2020-05-09 07:40:22 -06:00
parent 567fd9e866
commit fae20b4b89
3 changed files with 22 additions and 1 deletions

View File

@ -780,6 +780,9 @@ static void NewGC_initialize(NewGC *newgc, NewGC *inheritgc, NewGC *parentgc) {
#ifdef MZ_USE_PLACES
mzrt_mutex_create(&newgc->child_total_lock);
#endif
#ifdef USE_MUTEX_FOR_MODIFIED_PAGES
mzrt_mutex_create(&newgc->modified_pages_lock);
#endif
}
/* NOTE This method sets the constructed GC as the new Thread Specific GC. */
@ -1089,11 +1092,17 @@ static int designate_modified_gc(NewGC *gc, void *p)
}
if (page) {
#ifdef USE_MUTEX_FOR_MODIFIED_PAGES
mzrt_mutex_lock(gc->modified_pages_lock);
#endif
page->mprotected = 0;
mmu_write_unprotect_page(gc->mmu, page->addr, real_page_size(page), page_mmu_type(page), &page->mmu_src_block);
if (!page->back_pointers)
set_has_back_pointers(gc, page);
gc->modified_unprotects++;
#ifdef USE_MUTEX_FOR_MODIFIED_PAGES
mzrt_mutex_unlock(gc->modified_pages_lock);
#endif
errno = saved_errno;
return 1;
} else {

View File

@ -53,6 +53,10 @@ enum {
AGE_GEN_INC = 4 /* used for naming a finalizer set */
};
#if defined(MZ_USE_FUTURES) && !defined(OS_X)
# define USE_MUTEX_FOR_MODIFIED_PAGES
#endif
typedef struct mpage {
struct mpage *next;
struct mpage *prev;
@ -396,7 +400,11 @@ typedef struct NewGC {
uintptr_t child_gc_cumulative;
uintptr_t child_gc_max;
uintptr_t place_memory_limit; /* set to propagate a custodian limit from a parent place */
uintptr_t place_memory_limit; /* set to propagate a custodian limit from a parent place */
#ifdef USE_MUTEX_FOR_MODIFIED_PAGES
mzrt_mutex *modified_pages_lock;
#endif
#if MZ_GC_BACKTRACE
void *bt_source;

View File

@ -427,6 +427,10 @@ static void macosx_init_exception_handler(int isMASTERGC)
{
kern_return_t retval;
/* Note: the `designate_modified` function relies on the fact that
all exceptions (at least within a place) go through the same
handler thread, so it can skip the lock on modified pages. */
if (!isMASTERGC) {
GC_attach_current_thread_exceptions_to_handler();
return;