X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mono%2Fmetadata%2Fsgen-workers.c;h=f54362656101a765c0a40309c9b90e301846d95e;hb=83dfb12187ae97c436498c5d67f0c4db907ec66d;hp=2d48745762b3b7fe21b29a48c2de3226d2b8ece7;hpb=003488cc2a75981f8d9e1a5a46f8ad2adbdc4a38;p=mono.git diff --git a/mono/metadata/sgen-workers.c b/mono/metadata/sgen-workers.c index 2d48745762b..f5436265610 100644 --- a/mono/metadata/sgen-workers.c +++ b/mono/metadata/sgen-workers.c @@ -24,6 +24,7 @@ #include "metadata/sgen-gc.h" #include "metadata/sgen-workers.h" +#include "metadata/sgen-thread-pool.h" #include "utils/mono-counters.h" static int workers_num; @@ -33,273 +34,175 @@ static void *workers_gc_thread_major_collector_data = NULL; static SgenSectionGrayQueue workers_distribute_gray_queue; static gboolean workers_distribute_gray_queue_inited; -static volatile gboolean workers_marking = FALSE; -static gboolean workers_started = FALSE; +enum { + STATE_NOT_WORKING, + STATE_WORKING, + STATE_NURSERY_COLLECTION +} WorkersStateName; typedef union { gint32 value; struct { - /* - * Decremented by the main thread and incremented by - * worker threads. - */ - guint32 num_waiting : 8; - /* Set by worker threads and reset by the main thread. */ - guint32 done_posted : 1; - /* Set by the main thread. */ - guint32 gc_in_progress : 1; + guint state : 4; /* WorkersStateName */ } data; } State; static volatile State workers_state; -static MonoSemType workers_waiting_sem; -static MonoSemType workers_done_sem; - -static volatile int workers_job_queue_num_entries = 0; -static volatile JobQueueEntry *workers_job_queue = NULL; -static LOCK_DECLARE (workers_job_queue_mutex); -static int workers_num_jobs_enqueued = 0; -static volatile int workers_num_jobs_finished = 0; - -static long long stat_workers_stolen_from_self_lock; -static long long stat_workers_stolen_from_self_no_lock; -static long long stat_workers_stolen_from_others; -static long long stat_workers_num_waited; +static guint64 stat_workers_num_finished; static gboolean set_state (State old_state, State new_state) { + if (old_state.data.state == STATE_NURSERY_COLLECTION) + SGEN_ASSERT (0, new_state.data.state != STATE_NOT_WORKING, "Can't go from nursery collection to not working"); + return InterlockedCompareExchange (&workers_state.value, new_state.value, old_state.value) == old_state.value; } static void -workers_wake_up (int max) +assert_not_working (State state) { - int i; + SGEN_ASSERT (0, state.data.state == STATE_NOT_WORKING, "Can only signal enqueue work when in no work state"); - for (i = 0; i < max; ++i) { - State old_state, new_state; - do { - old_state = new_state = workers_state; - /* - * We must not wake workers up once done has - * been posted. - */ - if (old_state.data.done_posted) - return; - if (old_state.data.num_waiting == 0) - return; - --new_state.data.num_waiting; - } while (!set_state (old_state, new_state)); - MONO_SEM_POST (&workers_waiting_sem); - } } static void -workers_wake_up_all (void) -{ - workers_wake_up (workers_num); -} - -void -sgen_workers_wake_up_all (void) +assert_working (State state, gboolean from_worker) { - g_assert (workers_state.data.gc_in_progress); - workers_wake_up_all (); + SGEN_ASSERT (0, state.data.state == STATE_WORKING, "A worker can't wait without being in working state"); } static void -workers_wait (void) +assert_nursery_collection (State state, gboolean from_worker) { - State old_state, new_state; - ++stat_workers_num_waited; - do { - old_state = new_state = workers_state; - /* - * Only the last worker thread awake can set the done - * posted flag, and since we're awake and haven't set - * it yet, it cannot be set. - */ - g_assert (!old_state.data.done_posted); - ++new_state.data.num_waiting; - /* - * This is the only place where we use - * workers_gc_in_progress in the worker threads. - */ - if (new_state.data.num_waiting == workers_num && !old_state.data.gc_in_progress) - new_state.data.done_posted = 1; - } while (!set_state (old_state, new_state)); - mono_memory_barrier (); - if (new_state.data.done_posted) - MONO_SEM_POST (&workers_done_sem); - MONO_SEM_WAIT (&workers_waiting_sem); + SGEN_ASSERT (0, state.data.state == STATE_NURSERY_COLLECTION, "Must be in the nursery collection state"); } -static gboolean -collection_needs_workers (void) +static void +assert_working_or_nursery_collection (State state) { - return sgen_collection_is_concurrent (); + if (state.data.state == STATE_WORKING) + assert_working (state, TRUE); + else + assert_nursery_collection (state, TRUE); } -void -sgen_workers_enqueue_job (JobFunc func, void *data) +static void +workers_signal_enqueue_work (gboolean from_nursery_collection) { - int num_entries; - JobQueueEntry *entry; + State old_state = workers_state; + State new_state = old_state; + gboolean did_set_state; - if (!collection_needs_workers ()) { - func (NULL, data); - return; - } + if (from_nursery_collection) + assert_nursery_collection (old_state, FALSE); + else + assert_not_working (old_state); - g_assert (workers_state.data.gc_in_progress); + new_state.data.state = STATE_WORKING; - entry = sgen_alloc_internal (INTERNAL_MEM_JOB_QUEUE_ENTRY); - entry->func = func; - entry->data = data; + did_set_state = set_state (old_state, new_state); + SGEN_ASSERT (0, did_set_state, "Nobody else should be mutating the state"); - mono_mutex_lock (&workers_job_queue_mutex); - entry->next = workers_job_queue; - workers_job_queue = entry; - num_entries = ++workers_job_queue_num_entries; - ++workers_num_jobs_enqueued; - mono_mutex_unlock (&workers_job_queue_mutex); + sgen_thread_pool_idle_signal (); +} - workers_wake_up (num_entries); +static void +workers_signal_enqueue_work_if_necessary (void) +{ + if (workers_state.data.state == STATE_NOT_WORKING) + workers_signal_enqueue_work (FALSE); } void -sgen_workers_wait_for_jobs (void) +sgen_workers_ensure_awake (void) { - // FIXME: implement this properly - while (workers_num_jobs_finished < workers_num_jobs_enqueued) { - State state = workers_state; - g_assert (state.data.gc_in_progress); - g_assert (!state.data.done_posted); - if (state.data.num_waiting == workers_num) - workers_wake_up_all (); - g_usleep (1000); - } + SGEN_ASSERT (0, workers_state.data.state != STATE_NURSERY_COLLECTION, "Can't wake workers during nursery collection"); + workers_signal_enqueue_work_if_necessary (); } -static gboolean -workers_dequeue_and_do_job (WorkerData *data) +static void +worker_finish (void) { - JobQueueEntry *entry; - - /* - * At this point the GC might not be running anymore. We - * could have been woken up by a job that was then taken by - * another thread, after which the collection finished, so we - * first have to successfully dequeue a job before doing - * anything assuming that the collection is still ongoing. - */ - - if (!workers_job_queue_num_entries) - return FALSE; - - mono_mutex_lock (&workers_job_queue_mutex); - entry = (JobQueueEntry*)workers_job_queue; - if (entry) { - workers_job_queue = entry->next; - --workers_job_queue_num_entries; - } - mono_mutex_unlock (&workers_job_queue_mutex); - - if (!entry) - return FALSE; + State old_state, new_state; - g_assert (collection_needs_workers ()); + ++stat_workers_num_finished; - entry->func (data, entry->data); - sgen_free_internal (entry, INTERNAL_MEM_JOB_QUEUE_ENTRY); + do { + new_state = old_state = workers_state; - SGEN_ATOMIC_ADD (workers_num_jobs_finished, 1); + assert_working_or_nursery_collection (old_state); - return TRUE; + /* We are the last thread to go to sleep. */ + if (old_state.data.state == STATE_WORKING) + new_state.data.state = STATE_NOT_WORKING; + } while (!set_state (old_state, new_state)); } static gboolean -workers_steal (WorkerData *data, WorkerData *victim_data, gboolean lock) +collection_needs_workers (void) { - SgenGrayQueue *queue = &data->private_gray_queue; - int num, n; - - g_assert (!queue->first); + return sgen_collection_is_concurrent (); +} - if (!victim_data->stealable_stack_fill) - return FALSE; +void +sgen_workers_enqueue_job (SgenThreadPoolJob *job) +{ + if (!collection_needs_workers ()) { + job->func (NULL, job); + sgen_thread_pool_job_free (job); + return; + } - if (lock && mono_mutex_trylock (&victim_data->stealable_stack_mutex)) - return FALSE; + sgen_thread_pool_job_enqueue (job); +} - n = num = (victim_data->stealable_stack_fill + 1) / 2; - /* We're stealing num entries. */ +void +sgen_workers_wait_for_jobs_finished (void) +{ + sgen_thread_pool_wait_for_all_jobs (); +} - while (n > 0) { - int m = MIN (SGEN_GRAY_QUEUE_SECTION_SIZE, n); - n -= m; +void +sgen_workers_signal_start_nursery_collection_and_wait (void) +{ + State old_state, new_state; - sgen_gray_object_alloc_queue_section (queue); - memcpy (queue->first->entries, - victim_data->stealable_stack + victim_data->stealable_stack_fill - num + n, - sizeof (GrayQueueEntry) * m); - queue->first->size = m; + do { + new_state = old_state = workers_state; - /* - * DO NOT move outside this loop - * Doing so trigger "assert not reached" in sgen-scan-object.h : we use the queue->cursor - * to compute the size of the first section during section allocation (via alloc_prepare_func - * -> workers_gray_queue_share_redirect -> sgen_gray_object_dequeue_section) which will be then - * set to 0, because queue->cursor is still pointing to queue->first->entries [-1], thus - * losing objects in the gray queue. - */ - queue->cursor = queue->first->entries + queue->first->size - 1; - } + new_state.data.state = STATE_NURSERY_COLLECTION; - victim_data->stealable_stack_fill -= num; + if (old_state.data.state == STATE_NOT_WORKING) { + assert_not_working (old_state); + } else { + assert_working (old_state, FALSE); + } + } while (!set_state (old_state, new_state)); - if (lock) - mono_mutex_unlock (&victim_data->stealable_stack_mutex); + sgen_thread_pool_idle_wait (); - if (data == victim_data) { - if (lock) - stat_workers_stolen_from_self_lock += num; - else - stat_workers_stolen_from_self_no_lock += num; - } else { - stat_workers_stolen_from_others += num; - } + old_state = workers_state; + assert_nursery_collection (old_state, FALSE); +} - return num != 0; +void +sgen_workers_signal_finish_nursery_collection (void) +{ + assert_nursery_collection (workers_state, FALSE); + workers_signal_enqueue_work (TRUE); } static gboolean workers_get_work (WorkerData *data) { SgenMajorCollector *major; - int i; g_assert (sgen_gray_object_queue_is_empty (&data->private_gray_queue)); - /* Try to steal from our own stack. */ - if (workers_steal (data, data, TRUE)) - return TRUE; - - /* From another worker. */ - for (i = data->index + 1; i < workers_num + data->index; ++i) { - WorkerData *victim_data = &workers_data [i % workers_num]; - g_assert (data != victim_data); - if (workers_steal (data, victim_data, TRUE)) - return TRUE; - } - - /* - * If we're concurrent or parallel, from the workers - * distribute gray queue. - */ + /* If we're concurrent, steal from the workers distribute gray queue. */ major = sgen_get_major_collector (); if (major->is_concurrent) { GrayQueueSection *section = sgen_section_gray_queue_dequeue (&workers_distribute_gray_queue); @@ -314,51 +217,6 @@ workers_get_work (WorkerData *data) return FALSE; } -static void -workers_gray_queue_share_redirect (SgenGrayQueue *queue) -{ - GrayQueueSection *section; - WorkerData *data = queue->alloc_prepare_data; - - if (data->stealable_stack_fill) { - /* - * There are still objects in the stealable stack, so - * wake up any workers that might be sleeping - */ - if (workers_state.data.gc_in_progress) - workers_wake_up_all (); - return; - } - - /* The stealable stack is empty, so fill it. */ - mono_mutex_lock (&data->stealable_stack_mutex); - - while (data->stealable_stack_fill < STEALABLE_STACK_SIZE && - (section = sgen_gray_object_dequeue_section (queue))) { - int num = MIN (section->size, STEALABLE_STACK_SIZE - data->stealable_stack_fill); - - memcpy (data->stealable_stack + data->stealable_stack_fill, - section->entries + section->size - num, - sizeof (GrayQueueEntry) * num); - - section->size -= num; - data->stealable_stack_fill += num; - - if (section->size) - sgen_gray_object_enqueue_section (queue, section); - else - sgen_gray_object_free_queue_section (section); - } - - if (sgen_gray_object_queue_is_empty (queue)) - workers_steal (data, data, FALSE); - - mono_mutex_unlock (&data->stealable_stack_mutex); - - if (workers_state.data.gc_in_progress) - workers_wake_up_all (); -} - static void concurrent_enqueue_check (char *obj) { @@ -370,67 +228,66 @@ concurrent_enqueue_check (char *obj) static void init_private_gray_queue (WorkerData *data) { - sgen_gray_object_queue_init_with_alloc_prepare (&data->private_gray_queue, - sgen_get_major_collector ()->is_concurrent ? concurrent_enqueue_check : NULL, - workers_gray_queue_share_redirect, data); + sgen_gray_object_queue_init (&data->private_gray_queue, + sgen_get_major_collector ()->is_concurrent ? concurrent_enqueue_check : NULL); } -static mono_native_thread_return_t -workers_thread_func (void *data_untyped) +static void +thread_pool_init_func (void *data_untyped) { WorkerData *data = data_untyped; SgenMajorCollector *major = sgen_get_major_collector (); mono_thread_info_register_small_id (); + if (!major->is_concurrent) + return; + if (major->init_worker_thread) major->init_worker_thread (data->major_collector_data); init_private_gray_queue (data); +} - for (;;) { - gboolean did_work = FALSE; - - while (workers_dequeue_and_do_job (data)) { - did_work = TRUE; - /* FIXME: maybe distribute the gray queue here? */ - } +static gboolean +marker_idle_func (void *data_untyped) +{ + WorkerData *data = data_untyped; + SgenMajorCollector *major = sgen_get_major_collector (); - if (workers_marking && (!sgen_gray_object_queue_is_empty (&data->private_gray_queue) || workers_get_work (data))) { - SgenObjectOperations *ops = sgen_concurrent_collection_in_progress () - ? &major->major_concurrent_ops - : &major->major_ops; - ScanCopyContext ctx = { ops->scan_object, NULL, &data->private_gray_queue }; + if (workers_state.data.state != STATE_WORKING) + return FALSE; - g_assert (!sgen_gray_object_queue_is_empty (&data->private_gray_queue)); + SGEN_ASSERT (0, sgen_get_current_collection_generation () != GENERATION_NURSERY, "Why are we doing work while there's a nursery collection happening?"); - while (!sgen_drain_gray_stack (32, ctx)) - workers_gray_queue_share_redirect (&data->private_gray_queue); - g_assert (sgen_gray_object_queue_is_empty (&data->private_gray_queue)); + if (!sgen_gray_object_queue_is_empty (&data->private_gray_queue) || workers_get_work (data)) { + SgenObjectOperations *ops = sgen_concurrent_collection_in_progress () + ? &major->major_concurrent_ops + : &major->major_ops; + ScanCopyContext ctx = { ops->scan_object, NULL, &data->private_gray_queue }; - init_private_gray_queue (data); + SGEN_ASSERT (0, !sgen_gray_object_queue_is_empty (&data->private_gray_queue), "How is our gray queue empty if we just got work?"); - did_work = TRUE; - } + sgen_drain_gray_stack (32, ctx); - if (!did_work) - workers_wait (); + return TRUE; } - /* dummy return to make compilers happy */ - return NULL; + worker_finish (); + + return FALSE; } static void -init_distribute_gray_queue (gboolean locked) +init_distribute_gray_queue (void) { if (workers_distribute_gray_queue_inited) { g_assert (sgen_section_gray_queue_is_empty (&workers_distribute_gray_queue)); - g_assert (!workers_distribute_gray_queue.locked == !locked); + g_assert (workers_distribute_gray_queue.locked); return; } - sgen_section_gray_queue_init (&workers_distribute_gray_queue, locked, + sgen_section_gray_queue_init (&workers_distribute_gray_queue, TRUE, sgen_get_major_collector ()->is_concurrent ? concurrent_enqueue_check : NULL); workers_distribute_gray_queue_inited = TRUE; } @@ -438,19 +295,21 @@ init_distribute_gray_queue (gboolean locked) void sgen_workers_init_distribute_gray_queue (void) { - if (!collection_needs_workers ()) - return; - - init_distribute_gray_queue (sgen_get_major_collector ()->is_concurrent); + SGEN_ASSERT (0, sgen_get_major_collector ()->is_concurrent && collection_needs_workers (), + "Why should we init the distribute gray queue if we don't need it?"); + init_distribute_gray_queue (); } void sgen_workers_init (int num_workers) { int i; + void *workers_data_ptrs [num_workers]; - if (!sgen_get_major_collector ()->is_concurrent) + if (!sgen_get_major_collector ()->is_concurrent) { + sgen_thread_pool_init (num_workers, thread_pool_init_func, NULL, NULL); return; + } //g_print ("initing %d workers\n", num_workers); @@ -459,10 +318,7 @@ sgen_workers_init (int num_workers) workers_data = sgen_alloc_internal_dynamic (sizeof (WorkerData) * num_workers, INTERNAL_MEM_WORKER_DATA, TRUE); memset (workers_data, 0, sizeof (WorkerData) * num_workers); - MONO_SEM_INIT (&workers_waiting_sem, 0); - MONO_SEM_INIT (&workers_done_sem, 0); - - init_distribute_gray_queue (sgen_get_major_collector ()->is_concurrent); + init_distribute_gray_queue (); if (sgen_get_major_collector ()->alloc_worker_data) workers_gc_thread_major_collector_data = sgen_get_major_collector ()->alloc_worker_data (); @@ -470,204 +326,85 @@ sgen_workers_init (int num_workers) for (i = 0; i < workers_num; ++i) { workers_data [i].index = i; - /* private gray queue is inited by the thread itself */ - mono_mutex_init (&workers_data [i].stealable_stack_mutex); - workers_data [i].stealable_stack_fill = 0; - if (sgen_get_major_collector ()->alloc_worker_data) workers_data [i].major_collector_data = sgen_get_major_collector ()->alloc_worker_data (); - } - - LOCK_INIT (workers_job_queue_mutex); - - sgen_register_fixed_internal_mem_type (INTERNAL_MEM_JOB_QUEUE_ENTRY, sizeof (JobQueueEntry)); - - mono_counters_register ("Stolen from self lock", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_workers_stolen_from_self_lock); - mono_counters_register ("Stolen from self no lock", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_workers_stolen_from_self_no_lock); - mono_counters_register ("Stolen from others", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_workers_stolen_from_others); - mono_counters_register ("# workers waited", MONO_COUNTER_GC | MONO_COUNTER_LONG, &stat_workers_num_waited); -} -/* only the GC thread is allowed to start and join workers */ + workers_data_ptrs [i] = &workers_data [i]; + } -static void -workers_start_worker (int index) -{ - g_assert (index >= 0 && index < workers_num); + sgen_thread_pool_init (num_workers, thread_pool_init_func, marker_idle_func, workers_data_ptrs); - g_assert (!workers_data [index].thread); - mono_native_thread_create (&workers_data [index].thread, workers_thread_func, &workers_data [index]); + mono_counters_register ("# workers finished", MONO_COUNTER_GC | MONO_COUNTER_ULONG, &stat_workers_num_finished); } void sgen_workers_start_all_workers (void) { - State old_state, new_state; - int i; - if (!collection_needs_workers ()) return; if (sgen_get_major_collector ()->init_worker_thread) sgen_get_major_collector ()->init_worker_thread (workers_gc_thread_major_collector_data); - old_state = new_state = workers_state; - g_assert (!old_state.data.gc_in_progress); - new_state.data.gc_in_progress = TRUE; - - workers_marking = FALSE; - - g_assert (workers_job_queue_num_entries == 0); - workers_num_jobs_enqueued = 0; - workers_num_jobs_finished = 0; - - if (workers_started) { - g_assert (old_state.data.done_posted); - if (old_state.data.num_waiting != workers_num) { - g_error ("Expecting all %d sgen workers to be parked, but only %d are", - workers_num, old_state.data.num_waiting); - } - - /* Clear the done posted flag */ - new_state.data.done_posted = 0; - if (!set_state (old_state, new_state)) - g_assert_not_reached (); - - workers_wake_up_all (); - return; - } - - g_assert (!old_state.data.done_posted); - - if (!set_state (old_state, new_state)) - g_assert_not_reached (); - - for (i = 0; i < workers_num; ++i) - workers_start_worker (i); - - workers_started = TRUE; -} - -gboolean -sgen_workers_have_started (void) -{ - return workers_state.data.gc_in_progress; -} - -void -sgen_workers_start_marking (void) -{ - if (!collection_needs_workers ()) - return; - - g_assert (workers_started && workers_state.data.gc_in_progress); - g_assert (!workers_marking); - - workers_marking = TRUE; - - workers_wake_up_all (); + workers_signal_enqueue_work (FALSE); } void sgen_workers_join (void) { - State old_state, new_state; int i; if (!collection_needs_workers ()) return; - do { - old_state = new_state = workers_state; - g_assert (old_state.data.gc_in_progress); - g_assert (!old_state.data.done_posted); + sgen_thread_pool_wait_for_all_jobs (); - new_state.data.gc_in_progress = 0; - } while (!set_state (old_state, new_state)); + for (;;) { + SGEN_ASSERT (0, workers_state.data.state != STATE_NURSERY_COLLECTION, "Can't be in nursery collection when joining"); + sgen_thread_pool_idle_wait (); + assert_not_working (workers_state); - if (new_state.data.num_waiting == workers_num) { /* - * All the workers have shut down but haven't posted - * the done semaphore yet, or, if we come from below, - * haven't done all their work yet. - * - * It's not a big deal to wake them up again - they'll - * just do one iteration of their loop trying to find - * something to do and then go back to waiting again. + * Checking whether there is still work left and, if not, going to sleep, + * are two separate actions that are not performed atomically by the + * workers. Therefore there's a race condition where work can be added + * after they've checked for work, and before they've gone to sleep. */ - reawaken: - workers_wake_up_all (); - } - MONO_SEM_WAIT (&workers_done_sem); - - old_state = new_state = workers_state; - g_assert (old_state.data.num_waiting == workers_num); - g_assert (old_state.data.done_posted); + if (sgen_section_gray_queue_is_empty (&workers_distribute_gray_queue)) + break; - if (workers_job_queue_num_entries || !sgen_section_gray_queue_is_empty (&workers_distribute_gray_queue)) { - /* - * There's a small race condition that we avoid here. - * It's possible that a worker thread runs out of - * things to do, so it goes to sleep. Right at that - * moment a new job is enqueued, but the thread is - * still registered as running. Now the threads are - * joined, and we wait for the semaphore. Only at - * this point does the worker go to sleep, and posts - * the semaphore, because workers_gc_in_progress is - * already FALSE. The job is still in the queue, - * though. - * - * Clear the done posted flag. - */ - new_state.data.done_posted = 0; - if (!set_state (old_state, new_state)) - g_assert_not_reached (); - goto reawaken; + workers_signal_enqueue_work (FALSE); } /* At this point all the workers have stopped. */ - workers_marking = FALSE; - if (sgen_get_major_collector ()->reset_worker_data) { for (i = 0; i < workers_num; ++i) sgen_get_major_collector ()->reset_worker_data (workers_data [i].major_collector_data); } - g_assert (workers_job_queue_num_entries == 0); g_assert (sgen_section_gray_queue_is_empty (&workers_distribute_gray_queue)); - for (i = 0; i < workers_num; ++i) { - g_assert (!workers_data [i].stealable_stack_fill); + for (i = 0; i < workers_num; ++i) g_assert (sgen_gray_object_queue_is_empty (&workers_data [i].private_gray_queue)); - } } gboolean sgen_workers_all_done (void) { - State state = workers_state; - /* - * Can only be called while the collection is still in - * progress, i.e., before done has been posted. - */ - g_assert (state.data.gc_in_progress); - g_assert (!state.data.done_posted); - return state.data.num_waiting == workers_num; + return workers_state.data.state == STATE_NOT_WORKING; } gboolean -sgen_is_worker_thread (MonoNativeThreadId thread) +sgen_workers_are_working (void) { - int i; - - if (sgen_get_major_collector ()->is_worker_thread && sgen_get_major_collector ()->is_worker_thread (thread)) - return TRUE; + return workers_state.data.state == STATE_WORKING; +} - for (i = 0; i < workers_num; ++i) { - if (workers_data [i].thread == thread) - return TRUE; - } - return FALSE; +void +sgen_workers_wait (void) +{ + sgen_thread_pool_idle_wait (); + SGEN_ASSERT (0, sgen_workers_all_done (), "Why are the workers not done after we wait for them?"); } SgenSectionGrayQueue*