static mono_native_thread_return_t thread_func (void *thread_data) { thread_init_func (thread_data); mono_mutex_lock (&lock); for (;;) { /* * It's important that we check the continue idle flag with the lock held. * Suppose we didn't check with the lock held, and the result is FALSE. The * main thread might then set continue idle and signal us before we can take * the lock, and we'd lose the signal. */ gboolean do_idle = continue_idle_job (); SgenThreadPoolJob *job = get_job_and_set_in_progress (); if (!job && !do_idle) { /* * pthread_cond_wait() can return successfully despite the condition * not being signalled, so we have to run this in a loop until we * really have work to do. */ mono_cond_wait (&work_cond, &lock); continue; } mono_mutex_unlock (&lock); if (job) { job->func (thread_data, job); mono_mutex_lock (&lock); SGEN_ASSERT (0, job->state == STATE_IN_PROGRESS, "The job should still be in progress."); job->state = STATE_DONE; remove_job (job); /* * Only the main GC thread will ever wait on the done condition, so we don't * have to broadcast. */ mono_cond_signal (&done_cond); } else { SGEN_ASSERT (0, do_idle, "Why did we unlock if we still have to wait for idle?"); SGEN_ASSERT (0, idle_job_func, "Why do we have idle work when there's no idle job function?"); do { idle_job_func (thread_data); do_idle = continue_idle_job (); } while (do_idle && !job_queue.next_slot); mono_mutex_lock (&lock); if (!do_idle) mono_cond_signal (&done_cond); } } }
void sgen_thread_pool_idle_signal (void) { SGEN_ASSERT (0, idle_job_func, "Why are we signaling idle without an idle function?"); mono_mutex_lock (&lock); if (continue_idle_job_func ()) mono_cond_signal (&work_cond); mono_mutex_unlock (&lock); }
void sgen_thread_pool_job_enqueue (SgenThreadPoolJob *job) { mono_mutex_lock (&lock); sgen_pointer_queue_add (&job_queue, job); /* * FIXME: We could check whether there is a job in progress. If there is, there's * no need to signal the condition, at least as long as we have only one thread. */ mono_cond_signal (&work_cond); mono_mutex_unlock (&lock); }
static gboolean worker_try_unpark (void) { gboolean res = FALSE; guint len; mono_mutex_lock (&threadpool->parked_threads_lock); len = threadpool->parked_threads->len; if (len > 0) { mono_cond_t *cond = (mono_cond_t*) g_ptr_array_index (threadpool->parked_threads, len - 1); mono_cond_signal (cond); res = TRUE; } mono_mutex_unlock (&threadpool->parked_threads_lock); return res; }
static void ensure_cleanedup (void) { if (status == STATUS_NOT_INITIALIZED && InterlockedCompareExchange (&status, STATUS_CLEANED_UP, STATUS_NOT_INITIALIZED) == STATUS_NOT_INITIALIZED) return; if (status == STATUS_INITIALIZING) { while (status == STATUS_INITIALIZING) mono_thread_info_yield (); } if (status == STATUS_CLEANED_UP) return; if (status == STATUS_CLEANING_UP || InterlockedCompareExchange (&status, STATUS_CLEANING_UP, STATUS_INITIALIZED) != STATUS_INITIALIZED) { while (status == STATUS_CLEANING_UP) mono_thread_info_yield (); g_assert (status == STATUS_CLEANED_UP); return; } /* we make the assumption along the code that we are * cleaning up only if the runtime is shutting down */ g_assert (mono_runtime_is_shutting_down ()); /* Unpark all worker threads */ mono_mutex_lock (&threadpool->parked_threads_lock); for (;;) { guint i; ThreadPoolCounter counter = COUNTER_READ (); if (counter._.active == 0 && counter._.parked == 0) break; if (counter._.active == 1) { MonoInternalThread *thread = mono_thread_internal_current (); if (thread->threadpool_thread) { /* if there is only one active thread * left and it's the current one */ break; } } for (i = 0; i < threadpool->parked_threads->len; ++i) { mono_cond_t *cond = (mono_cond_t*) g_ptr_array_index (threadpool->parked_threads, i); mono_cond_signal (cond); } mono_mutex_unlock (&threadpool->parked_threads_lock); usleep (1000); mono_mutex_lock (&threadpool->parked_threads_lock); } mono_mutex_unlock (&threadpool->parked_threads_lock); while (monitor_status != MONITOR_STATUS_NOT_RUNNING) usleep (1000); g_ptr_array_free (threadpool->domains, TRUE); mono_mutex_destroy (&threadpool->domains_lock); g_ptr_array_free (threadpool->parked_threads, TRUE); mono_mutex_destroy (&threadpool->parked_threads_lock); g_ptr_array_free (threadpool->working_threads, TRUE); mono_mutex_destroy (&threadpool->working_threads_lock); mono_mutex_destroy (&threadpool->heuristic_lock); g_free (threadpool->heuristic_hill_climbing.samples); g_free (threadpool->heuristic_hill_climbing.thread_counts); rand_free (threadpool->heuristic_hill_climbing.random_interval_generator); g_free (threadpool->cpu_usage_state); g_assert (threadpool); g_free (threadpool); threadpool = NULL; g_assert (!threadpool); status = STATUS_CLEANED_UP; }