void sgen_workers_start_all_workers (void) { int i; if (!sgen_collection_is_parallel ()) return; if (sgen_get_major_collector ()->init_worker_thread) sgen_get_major_collector ()->init_worker_thread (workers_gc_thread_data.major_collector_data); g_assert (!workers_gc_in_progress); workers_gc_in_progress = TRUE; workers_marking = FALSE; workers_done_posted = 0; if (workers_started) { if (workers_num_waiting != workers_num) g_error ("Expecting all %d sgen workers to be parked, but only %d are", workers_num, workers_num_waiting); workers_wake_up_all (); return; } for (i = 0; i < workers_num; ++i) workers_start_worker (i); workers_started = TRUE; }
static void workers_start_all_workers (void) { int i; if (!collection_is_parallel ()) return; if (major_collector.init_worker_thread) major_collector.init_worker_thread (workers_gc_thread_data.major_collector_data); g_assert (!workers_gc_in_progress); workers_gc_in_progress = TRUE; workers_marking = FALSE; workers_done_posted = 0; if (workers_started) { g_assert (workers_num_waiting == workers_num); workers_wake_up_all (); return; } for (i = 0; i < workers_num; ++i) workers_start_worker (i); workers_started = TRUE; }
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 (); }
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 (); }
void sgen_workers_wait_for_jobs (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); } }
void sgen_workers_start_marking (void) { if (!sgen_collection_is_parallel ()) return; g_assert (workers_started && workers_gc_in_progress); g_assert (!workers_marking); workers_marking = TRUE; workers_wake_up_all (); }
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; }
void sgen_workers_join (void) { int i; if (!sgen_collection_is_parallel ()) return; g_assert (sgen_gray_object_queue_is_empty (&workers_gc_thread_data.private_gray_queue)); g_assert (sgen_gray_object_queue_is_empty (&workers_distribute_gray_queue)); g_assert (workers_gc_in_progress); workers_gc_in_progress = FALSE; if (workers_num_waiting == workers_num) { /* * All the workers might have shut down at this point * and posted the done semaphore but we don't know it * 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. */ workers_wake_up_all (); } MONO_SEM_WAIT (&workers_done_sem); 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_done_posted); g_assert (!workers_gc_thread_data.stealable_stack_fill); g_assert (sgen_gray_object_queue_is_empty (&workers_gc_thread_data.private_gray_queue)); for (i = 0; i < workers_num; ++i) { g_assert (!workers_data [i].stealable_stack_fill); g_assert (sgen_gray_object_queue_is_empty (&workers_data [i].private_gray_queue)); } }
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); new_state.data.gc_in_progress = 0; } while (!set_state (old_state, new_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. */ 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 (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; } /* 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); g_assert (sgen_gray_object_queue_is_empty (&workers_data [i].private_gray_queue)); } }
void sgen_workers_wake_up_all (void) { g_assert (workers_state.data.gc_in_progress); workers_wake_up_all (); }