summaryrefslogtreecommitdiff
path: root/rts/CheckUnload.c
diff options
context:
space:
mode:
Diffstat (limited to 'rts/CheckUnload.c')
-rw-r--r--rts/CheckUnload.c10
1 files changed, 8 insertions, 2 deletions
diff --git a/rts/CheckUnload.c b/rts/CheckUnload.c
index fcbe0f6156..d67696a061 100644
--- a/rts/CheckUnload.c
+++ b/rts/CheckUnload.c
@@ -357,11 +357,16 @@ static ObjectCode *findOC(OCSectionIndices *s_indices, const void *addr) {
static bool markObjectLive(void *data STG_UNUSED, StgWord key, const void *value STG_UNUSED) {
ObjectCode *oc = (ObjectCode*)key;
- if (oc->mark == object_code_mark_bit) {
+
+ // N.B. we may be called by the parallel GC and therefore this must be
+ // thread-safe. To avoid taking the linker_mutex in the fast path
+ // (when the object is already marked) we do an atomic exchange here and
+ // only take the lock in the case that the object is unmarked.
+ if (xchg(&oc->mark, object_code_mark_bit) == object_code_mark_bit) {
return true; // for hash table iteration
}
- oc->mark = object_code_mark_bit;
+ ACQUIRE_LOCK(&linker_mutex);
// Remove from 'old_objects' list
if (oc->prev != NULL) {
// TODO(osa): Maybe 'prev' should be a pointer to the referencing
@@ -381,6 +386,7 @@ static bool markObjectLive(void *data STG_UNUSED, StgWord key, const void *value
objects->prev = oc;
}
objects = oc;
+ RELEASE_LOCK(&linker_mutex);
// Mark its dependencies
iterHashTable(oc->dependencies, NULL, markObjectLive);