}
}
+STATIC GC_on_collection_event_proc GC_on_collection_event = 0;
+
+GC_API void GC_CALL GC_set_on_collection_event(GC_on_collection_event_proc fn)
+{
+ /* fn may be 0 (means no event notifier). */
+ DCL_LOCK_STATE;
+ LOCK();
+ GC_on_collection_event = fn;
+ UNLOCK();
+}
+
+GC_API GC_on_collection_event_proc GC_CALL GC_get_on_collection_event(void)
+{
+ GC_on_collection_event_proc fn;
+ DCL_LOCK_STATE;
+ LOCK();
+ fn = GC_on_collection_event;
+ UNLOCK();
+ return fn;
+}
/*
* Stop the world garbage collection. Assumes lock held. If stop_func is
ASSERT_CANCEL_DISABLED();
if (GC_dont_gc || (*stop_func)()) return FALSE;
if (GC_on_collection_event)
- GC_on_collection_event(GC_EVENT_START, NULL);
+ GC_on_collection_event(GC_EVENT_START);
if (GC_incremental && GC_collection_in_progress()) {
GC_COND_LOG_PRINTF(
"GC_try_to_collect_inner: finishing collection in progress\n");
}
# endif
if (GC_on_collection_event)
- GC_on_collection_event(GC_EVENT_END, NULL);
+ GC_on_collection_event(GC_EVENT_END);
return(TRUE);
}
# ifdef THREADS
if (GC_on_collection_event)
- GC_on_collection_event(GC_EVENT_PRE_STOP_WORLD, NULL);
+ GC_on_collection_event(GC_EVENT_PRE_STOP_WORLD);
# endif
STOP_WORLD();
# ifdef THREADS
if (GC_on_collection_event)
- GC_on_collection_event(GC_EVENT_POST_STOP_WORLD, NULL);
+ GC_on_collection_event(GC_EVENT_POST_STOP_WORLD);
# endif
# ifdef THREAD_LOCAL_ALLOC
/* Mark from all roots. */
if (GC_on_collection_event)
- GC_on_collection_event(GC_EVENT_MARK_START, NULL);
+ GC_on_collection_event(GC_EVENT_MARK_START);
/* Minimize junk left in my registers and on the stack */
GC_clear_a_few_frames();
# ifdef THREADS
if (GC_on_collection_event)
- GC_on_collection_event(GC_EVENT_PRE_START_WORLD, NULL);
+ GC_on_collection_event(GC_EVENT_PRE_START_WORLD);
# endif
START_WORLD();
# ifdef THREADS
if (GC_on_collection_event)
- GC_on_collection_event(GC_EVENT_POST_START_WORLD, NULL);
+ GC_on_collection_event(GC_EVENT_POST_START_WORLD);
# endif
/* TODO: Notify GC_EVENT_MARK_ABANDON */
(*GC_check_heap)();
}
if (GC_on_collection_event)
- GC_on_collection_event(GC_EVENT_MARK_END, NULL);
+ GC_on_collection_event(GC_EVENT_MARK_END);
# ifdef THREAD_LOCAL_ALLOC
GC_world_stopped = FALSE;
# ifdef THREADS
if (GC_on_collection_event)
- GC_on_collection_event(GC_EVENT_PRE_START_WORLD, NULL);
+ GC_on_collection_event(GC_EVENT_PRE_START_WORLD);
# endif
START_WORLD();
# ifdef THREADS
if (GC_on_collection_event)
- GC_on_collection_event(GC_EVENT_POST_START_WORLD, NULL);
+ GC_on_collection_event(GC_EVENT_POST_START_WORLD);
# endif
# ifndef SMALL_CONFIG
}
if (!found)
GC_mach_threads_count++;
- if (GC_on_collection_event)
- GC_on_collection_event(GC_EVENT_THREAD_SUSPENDED, (void *)thread);
+ if (GC_on_thread_event)
+ GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED, (void *)thread);
}
return changed;
}
kern_result = thread_suspend(p->stop_info.mach_thread);
if (kern_result != KERN_SUCCESS)
ABORT("thread_suspend failed");
- if (GC_on_collection_event)
- GC_on_collection_event(GC_EVENT_THREAD_SUSPENDED,
- (void *)p->stop_info.mach_thread);
+ if (GC_on_thread_event)
+ GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED,
+ (void *)p->stop_info.mach_thread);
}
}
}
kern_result = thread_resume(thread);
if (kern_result != KERN_SUCCESS)
ABORT("thread_resume failed");
- if (GC_on_collection_event)
- GC_on_collection_event(GC_EVENT_THREAD_UNSUSPENDED, (void *)thread);
+ if (GC_on_thread_event)
+ GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED, (void *)thread);
}
/* Caller holds allocation lock, and has held it continuously since */
GC_EVENT_THREAD_UNSUSPENDED
} GC_EventType;
-typedef void (GC_CALLBACK * GC_on_collection_event_proc)(GC_EventType, void*);
+typedef void (GC_CALLBACK * GC_on_collection_event_proc)(GC_EventType);
/* Invoked to indicate progress through the */
- /* collection process. */
- /* Called with the world stopped (and the */
- /* allocation lock held). May be 0. */
+ /* collection process. Not used for thread */
+ /* suspend/resume notifications. Called with */
+ /* the GC lock held (or, even, the world */
+ /* stopped). May be 0 (means no notifier). */
GC_API void GC_CALL GC_set_on_collection_event(GC_on_collection_event_proc);
GC_API GC_on_collection_event_proc GC_CALL GC_get_on_collection_event(void);
+ /* Both the supplied setter and the getter */
+ /* acquire the GC lock (to avoid data races). */
+
+#ifdef GC_THREADS
+ typedef void (GC_CALLBACK * GC_on_thread_event_proc)(GC_EventType,
+ void * /* thread_id */);
+ /* Invoked when a thread is suspended or */
+ /* resumed during collection. Called with the */
+ /* GC lock held (and the world stopped */
+ /* partially). May be 0 (means no notifier). */
+ GC_API void GC_CALL GC_set_on_thread_event(GC_on_thread_event_proc);
+ GC_API GC_on_thread_event_proc GC_CALL GC_get_on_thread_event(void);
+ /* Both the supplied setter and the getter */
+ /* acquire the GC lock (to avoid data races). */
+#endif
GC_API GC_ATTR_DEPRECATED int GC_find_leak;
/* Do not actually garbage collect, but simply */
# endif
# endif
+#ifdef THREADS
+ GC_EXTERN GC_on_thread_event_proc GC_on_thread_event;
+#endif
+
/* Abandon ship */
# ifdef PCR
# define ABORT(s) PCR_Base_Panic(s)
/* Print an address map of the process. */
#endif
-GC_EXTERN GC_on_collection_event_proc GC_on_collection_event;
-
#ifndef SHORT_DBG_HDRS
GC_EXTERN GC_bool GC_findleak_delay_free;
/* Do not immediately deallocate object on */
/* GC_parallel is initialized at start-up. */
return GC_parallel;
}
-#endif
+
+ GC_INNER GC_on_thread_event_proc GC_on_thread_event = 0;
+
+ GC_API void GC_CALL GC_set_on_thread_event(GC_on_thread_event_proc fn)
+ {
+ /* fn may be 0 (means no event notifier). */
+ DCL_LOCK_STATE;
+ LOCK();
+ GC_on_thread_event = fn;
+ UNLOCK();
+ }
+
+ GC_API GC_on_thread_event_proc GC_CALL GC_get_on_thread_event(void)
+ {
+ GC_on_thread_event_proc fn;
+ DCL_LOCK_STATE;
+ LOCK();
+ fn = GC_on_thread_event;
+ UNLOCK();
+ return fn;
+ }
+#endif /* THREADS */
/* Setter and getter functions for the public R/W function variables. */
/* These functions are synchronized (like GC_set_warn_proc() and */
return fn;
}
-GC_INNER GC_on_collection_event_proc GC_on_collection_event = 0;
-
-GC_API void GC_CALL GC_set_on_collection_event(GC_on_collection_event_proc fn)
-{
- /* fn may be 0 (means no event notifier). */
- DCL_LOCK_STATE;
- LOCK();
- GC_on_collection_event = fn;
- UNLOCK();
-}
-
-GC_API GC_on_collection_event_proc GC_CALL GC_get_on_collection_event(void)
-{
- GC_on_collection_event_proc fn;
- DCL_LOCK_STATE;
- LOCK();
- fn = GC_on_collection_event;
- UNLOCK();
- return fn;
-}
-
GC_API void GC_CALL GC_set_finalizer_notifier(GC_finalizer_notifier_proc fn)
{
/* fn may be 0 (means no finalizer notifier). */
if (pthread_stackseg_np(p->id, &stack))
ABORT("pthread_stackseg_np failed");
p -> stop_info.stack_ptr = (ptr_t)stack.ss_sp - stack.ss_size;
-
- if (GC_on_collection_event)
- GC_on_collection_event(GC_EVENT_THREAD_SUSPENDED,
- (void *)p->id);
+ if (GC_on_thread_event)
+ GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED,
+ (void *)p->id);
}
# else
# ifndef PLATFORM_ANDROID
n_live_threads--;
break;
case 0:
- if (GC_on_collection_event)
- GC_on_collection_event(GC_EVENT_THREAD_SUSPENDED,
- (void *)thread_id);
+ if (GC_on_thread_event)
+ GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED,
+ (void *)thread_id);
break;
default:
ABORT_ARG1("pthread_kill failed at suspend",
num_used++;
if (GC_nacl_thread_parked[i] == 1) {
num_threads_parked++;
- if (GC_on_collection_event)
- GC_on_collection_event(GC_EVENT_THREAD_SUSPENDED,
- (void *)(word)i);
+ if (GC_on_thread_event)
+ GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED, (void *)(word)i);
}
}
}
# ifdef GC_OPENBSD_UTHREADS
if (pthread_resume_np(p -> id) != 0)
ABORT("pthread_resume_np failed");
- if (GC_on_collection_event)
- GC_on_collection_event(GC_EVENT_THREAD_UNSUSPENDED,
- (void *)p->id);
+ if (GC_on_thread_event)
+ GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED, (void *)p->id);
# else
# ifndef PLATFORM_ANDROID
thread_id = p -> id;
n_live_threads--;
break;
case 0:
- if (GC_on_collection_event)
- GC_on_collection_event(GC_EVENT_THREAD_UNSUSPENDED,
- (void *)thread_id);
+ if (GC_on_thread_event)
+ GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED,
+ (void *)thread_id);
break;
default:
ABORT_ARG1("pthread_kill failed at resume",
GC_log_printf("World starting...\n");
# endif
GC_nacl_park_threads_now = 0;
- if (GC_on_collection_event)
- GC_on_collection_event(GC_EVENT_THREAD_UNSUSPENDED, NULL);
+ if (GC_on_thread_event)
+ GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED, NULL);
/* TODO: Send event for every unsuspended thread. */
# endif
}
# if defined(MPROTECT_VDB)
AO_CLEAR(&GC_fault_handler_lock);
# endif
- if (GC_on_collection_event)
- GC_on_collection_event(GC_EVENT_THREAD_SUSPENDED, THREAD_HANDLE(t));
+ if (GC_on_thread_event)
+ GC_on_thread_event(GC_EVENT_THREAD_SUSPENDED, THREAD_HANDLE(t));
}
#if defined(GC_ASSERTIONS) && !defined(CYGWIN32)
if (ResumeThread(THREAD_HANDLE(t)) == (DWORD)-1)
ABORT("ResumeThread failed");
t -> suspended = FALSE;
- if (GC_on_collection_event)
- GC_on_collection_event(GC_EVENT_THREAD_UNSUSPENDED,
- THREAD_HANDLE(t));
+ if (GC_on_thread_event)
+ GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED, THREAD_HANDLE(t));
}
}
} else {
ABORT("ResumeThread failed");
UNPROTECT_THREAD(t);
t -> suspended = FALSE;
- if (GC_on_collection_event)
- GC_on_collection_event(GC_EVENT_THREAD_UNSUSPENDED,
- THREAD_HANDLE(t));
+ if (GC_on_thread_event)
+ GC_on_thread_event(GC_EVENT_THREAD_UNSUSPENDED, THREAD_HANDLE(t));
}
}
}