static void file_mmap_init (void) { retry: switch (mmap_init_state) { case 0: if (InterlockedCompareExchange (&mmap_init_state, 1, 0) != 0) goto retry; named_regions = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL); mono_mutex_init (&named_regions_mutex); mono_atomic_store_release (&mmap_init_state, 2); break; case 1: do { g_usleep (1000); /* Been init'd by other threads, this is very rare. */ } while (mmap_init_state != 2); break; case 2: break; default: g_error ("Invalid init state %d", mmap_init_state); } }
/** * InitializeCriticalSection: * @section: The critical section to initialise * * Initialises a critical section. */ void InitializeCriticalSection(WapiCriticalSection *section) { int ret; mono_once(&attr_key_once, attr_init); ret = mono_mutex_init(§ion->mutex, &attr); g_assert (ret == 0); }
static void noshm_semaphores_init (void) { int i; for (i = 0; i < _WAPI_SHARED_SEM_COUNT; i++) mono_mutex_init (&noshm_sems [i]); }
void sgen_workers_init (int num_workers) { int i; if (!sgen_get_major_collector ()->is_parallel) return; //g_print ("initing %d workers\n", num_workers); workers_num = 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); sgen_gray_object_queue_init_with_alloc_prepare (&workers_distribute_gray_queue, workers_gray_queue_share_redirect, &workers_gc_thread_data); mono_mutex_init (&workers_gc_thread_data.stealable_stack_mutex, NULL); workers_gc_thread_data.stealable_stack_fill = 0; if (sgen_get_major_collector ()->alloc_worker_data) workers_gc_thread_data.major_collector_data = sgen_get_major_collector ()->alloc_worker_data (); for (i = 0; i < workers_num; ++i) { /* private gray queue is inited by the thread itself */ mono_mutex_init (&workers_data [i].stealable_stack_mutex, NULL); 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); }
void mono_counters_init (void) { if (initialized) return; mono_mutex_init (&counters_mutex); initialize_system_counters (); initialized = TRUE; }
void sgen_thread_pool_init (int num_threads, SgenThreadPoolThreadInitFunc init_func, SgenThreadPoolIdleJobFunc idle_func, SgenThreadPoolContinueIdleJobFunc continue_idle_func, void **thread_datas) { SGEN_ASSERT (0, num_threads == 1, "We only support 1 thread pool thread for now."); mono_mutex_init (&lock); mono_cond_init (&work_cond, NULL); mono_cond_init (&done_cond, NULL); thread_init_func = init_func; idle_job_func = idle_func; continue_idle_job_func = continue_idle_func; mono_native_thread_create (&thread, thread_func, thread_datas ? thread_datas [0] : NULL); }
void mono_profiler_startup (const char *desc) { MonoProfiler *prof = g_new0 (MonoProfiler, 1); mono_mutex_init (&mismatched_files_section); prof->mismatched_files_hash = g_hash_table_new (mismatched_files_guint32_hash, mismatched_files_guint32_equal); prof->saved_strings_hash = g_hash_table_new (NULL, NULL); prof->string_locations_hash = g_hash_table_new (mismatched_files_guint32_hash, mismatched_files_guint32_equal); mono_profiler_install (prof, profiler_shutdown); mono_profiler_install_runtime_initialized (runtime_initialized_cb); mono_profiler_install_iomap (mono_portability_iomap_event); mono_profiler_install_allocation (mono_portability_remember_alloc); mono_profiler_set_events (MONO_PROFILE_ALLOCATIONS | MONO_PROFILE_IOMAP_EVENTS); }
/* Returns a recursive mutex that is safe under suspension. A suspension safe mutex means one that can handle this scenario: mutex M thread 1: 1)lock M 2)suspend thread 2 3)unlock M 4)lock M thread 2: 5)lock M Say (1) happens before (5) and (5) happens before (2). This means that thread 2 was suspended by the kernel because it's waiting on mutext M. Thread 1 then proceed to suspend thread 2 and unlock/lock the mutex. If the kernel implements mutexes with FIFO wait lists, this means that thread 1 will be blocked waiting for thread 2 acquire the lock. Since thread 2 is suspended, we have a deadlock. A suspend safe mutex is an unfair lock but will schedule any runable thread that is waiting for a the lock. This problem was witnessed on OSX in mono/tests/thread-exit.cs. */ int mono_mutex_init_suspend_safe (mono_mutex_t *mutex) { #if defined(__APPLE__) int res; pthread_mutexattr_t attr; pthread_mutexattr_init (&attr); pthread_mutexattr_settype (&attr, PTHREAD_MUTEX_RECURSIVE); pthread_mutexattr_setpolicy_np (&attr, _PTHREAD_MUTEX_POLICY_FIRSTFIT); res = pthread_mutex_init (mutex, &attr); pthread_mutexattr_destroy (&attr); return res; #else return mono_mutex_init (mutex); #endif }
static void ensure_initialized (gboolean *enable_worker_tracking) { ThreadPoolHillClimbing *hc; const char *threads_per_cpu_env; gint threads_per_cpu; gint threads_count; if (enable_worker_tracking) { // TODO implement some kind of switch to have the possibily to use it *enable_worker_tracking = FALSE; } if (status >= STATUS_INITIALIZED) return; if (status == STATUS_INITIALIZING || InterlockedCompareExchange (&status, STATUS_INITIALIZING, STATUS_NOT_INITIALIZED) != STATUS_NOT_INITIALIZED) { while (status == STATUS_INITIALIZING) mono_thread_info_yield (); g_assert (status >= STATUS_INITIALIZED); return; } g_assert (!threadpool); threadpool = g_new0 (ThreadPool, 1); g_assert (threadpool); threadpool->domains = g_ptr_array_new (); mono_mutex_init_recursive (&threadpool->domains_lock); threadpool->parked_threads = g_ptr_array_new (); mono_mutex_init (&threadpool->parked_threads_lock); threadpool->working_threads = g_ptr_array_new (); mono_mutex_init (&threadpool->working_threads_lock); threadpool->heuristic_adjustment_interval = 10; mono_mutex_init (&threadpool->heuristic_lock); mono_rand_open (); hc = &threadpool->heuristic_hill_climbing; hc->wave_period = HILL_CLIMBING_WAVE_PERIOD; hc->max_thread_wave_magnitude = HILL_CLIMBING_MAX_WAVE_MAGNITUDE; hc->thread_magnitude_multiplier = (gdouble) HILL_CLIMBING_WAVE_MAGNITUDE_MULTIPLIER; hc->samples_to_measure = hc->wave_period * HILL_CLIMBING_WAVE_HISTORY_SIZE; hc->target_throughput_ratio = (gdouble) HILL_CLIMBING_BIAS; hc->target_signal_to_noise_ratio = (gdouble) HILL_CLIMBING_TARGET_SIGNAL_TO_NOISE_RATIO; hc->max_change_per_second = (gdouble) HILL_CLIMBING_MAX_CHANGE_PER_SECOND; hc->max_change_per_sample = (gdouble) HILL_CLIMBING_MAX_CHANGE_PER_SAMPLE; hc->sample_interval_low = HILL_CLIMBING_SAMPLE_INTERVAL_LOW; hc->sample_interval_high = HILL_CLIMBING_SAMPLE_INTERVAL_HIGH; hc->throughput_error_smoothing_factor = (gdouble) HILL_CLIMBING_ERROR_SMOOTHING_FACTOR; hc->gain_exponent = (gdouble) HILL_CLIMBING_GAIN_EXPONENT; hc->max_sample_error = (gdouble) HILL_CLIMBING_MAX_SAMPLE_ERROR_PERCENT; hc->current_control_setting = 0; hc->total_samples = 0; hc->last_thread_count = 0; hc->average_throughput_noise = 0; hc->elapsed_since_last_change = 0; hc->accumulated_completion_count = 0; hc->accumulated_sample_duration = 0; hc->samples = g_new0 (gdouble, hc->samples_to_measure); hc->thread_counts = g_new0 (gdouble, hc->samples_to_measure); hc->random_interval_generator = rand_create (); hc->current_sample_interval = rand_next (&hc->random_interval_generator, hc->sample_interval_low, hc->sample_interval_high); if (!(threads_per_cpu_env = g_getenv ("MONO_THREADS_PER_CPU"))) threads_per_cpu = 1; else threads_per_cpu = CLAMP (atoi (threads_per_cpu_env), 1, 50); threads_count = mono_cpu_count () * threads_per_cpu; threadpool->limit_worker_min = threadpool->limit_io_min = threads_count; threadpool->limit_worker_max = threadpool->limit_io_max = threads_count * 100; threadpool->counters._.max_working = threadpool->limit_worker_min; threadpool->cpu_usage_state = g_new0 (MonoCpuUsageState, 1); threadpool->suspended = FALSE; status = STATUS_INITIALIZED; }
void mono_gc_base_init (void) { MonoThreadInfoCallbacks cb; const char *env; int dummy; if (gc_initialized) return; /* * Handle the case when we are called from a thread different from the main thread, * confusing libgc. * FIXME: Move this to libgc where it belongs. * * we used to do this only when running on valgrind, * but it happens also in other setups. */ #if defined(HAVE_PTHREAD_GETATTR_NP) && defined(HAVE_PTHREAD_ATTR_GETSTACK) && !defined(__native_client__) { size_t size; void *sstart; pthread_attr_t attr; pthread_getattr_np (pthread_self (), &attr); pthread_attr_getstack (&attr, &sstart, &size); pthread_attr_destroy (&attr); /*g_print ("stackbottom pth is: %p\n", (char*)sstart + size);*/ #ifdef __ia64__ /* * The calculation above doesn't seem to work on ia64, also we need to set * GC_register_stackbottom as well, but don't know how. */ #else /* apparently with some linuxthreads implementations sstart can be NULL, * fallback to the more imprecise method (bug# 78096). */ if (sstart) { GC_stackbottom = (char*)sstart + size; } else { int dummy; gsize stack_bottom = (gsize)&dummy; stack_bottom += 4095; stack_bottom &= ~4095; GC_stackbottom = (char*)stack_bottom; } #endif } #elif defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP) GC_stackbottom = (char*)pthread_get_stackaddr_np (pthread_self ()); #elif defined(__OpenBSD__) # include <pthread_np.h> { stack_t ss; int rslt; rslt = pthread_stackseg_np(pthread_self(), &ss); g_assert (rslt == 0); GC_stackbottom = (char*)ss.ss_sp; } #elif defined(__native_client__) /* Do nothing, GC_stackbottom is set correctly in libgc */ #else { int dummy; gsize stack_bottom = (gsize)&dummy; stack_bottom += 4095; stack_bottom &= ~4095; /*g_print ("stackbottom is: %p\n", (char*)stack_bottom);*/ GC_stackbottom = (char*)stack_bottom; } #endif #if !defined(PLATFORM_ANDROID) /* If GC_no_dls is set to true, GC_find_limit is not called. This causes a seg fault on Android. */ GC_no_dls = TRUE; #endif GC_init (); GC_oom_fn = mono_gc_out_of_memory; GC_set_warn_proc (mono_gc_warning); GC_finalize_on_demand = 1; GC_finalizer_notifier = mono_gc_finalize_notify; #ifdef HAVE_GC_GCJ_MALLOC GC_init_gcj_malloc (5, NULL); #endif #ifdef HAVE_GC_ALLOW_REGISTER_THREADS GC_allow_register_threads(); #endif if ((env = g_getenv ("MONO_GC_PARAMS"))) { char **ptr, **opts = g_strsplit (env, ",", -1); for (ptr = opts; *ptr; ++ptr) { char *opt = *ptr; if (g_str_has_prefix (opt, "max-heap-size=")) { glong max_heap; opt = strchr (opt, '=') + 1; if (*opt && mono_gc_parse_environment_string_extract_number (opt, &max_heap)) { if (max_heap < MIN_BOEHM_MAX_HEAP_SIZE) { fprintf (stderr, "max-heap-size must be at least %dMb.\n", MIN_BOEHM_MAX_HEAP_SIZE_IN_MB); exit (1); } GC_set_max_heap_size (max_heap); } else { fprintf (stderr, "max-heap-size must be an integer.\n"); exit (1); } continue; } else if (g_str_has_prefix (opt, "toggleref-test")) { register_test_toggleref_callback (); continue; } else { /* Could be a parameter for sgen */ /* fprintf (stderr, "MONO_GC_PARAMS must be a comma-delimited list of one or more of the following:\n"); fprintf (stderr, " max-heap-size=N (where N is an integer, possibly with a k, m or a g suffix)\n"); exit (1); */ } } g_strfreev (opts); } memset (&cb, 0, sizeof (cb)); cb.thread_register = boehm_thread_register; cb.thread_unregister = boehm_thread_unregister; cb.mono_method_is_critical = (gpointer)mono_runtime_is_critical_method; #ifndef HOST_WIN32 cb.thread_exit = mono_gc_pthread_exit; cb.mono_gc_pthread_create = (gpointer)mono_gc_pthread_create; #endif mono_threads_init (&cb, sizeof (MonoThreadInfo)); mono_mutex_init (&mono_gc_lock); mono_thread_info_attach (&dummy); mono_gc_enable_events (); gc_initialized = TRUE; }
void mono_thread_pool_init (void) { gint threads_per_cpu = 1; gint thread_count; gint cpu_count = mono_cpu_count (); int result; if (tp_inited == 2) return; result = InterlockedCompareExchange (&tp_inited, 1, 0); if (result == 1) { while (1) { SleepEx (1, FALSE); if (tp_inited == 2) return; } } MONO_GC_REGISTER_ROOT_FIXED (socket_io_data.sock_to_state); mono_mutex_init_recursive (&socket_io_data.io_lock); if (g_getenv ("MONO_THREADS_PER_CPU") != NULL) { threads_per_cpu = atoi (g_getenv ("MONO_THREADS_PER_CPU")); if (threads_per_cpu < 1) threads_per_cpu = 1; } thread_count = MIN (cpu_count * threads_per_cpu, 100 * cpu_count); threadpool_init (&async_tp, thread_count, MAX (100 * cpu_count, thread_count), async_invoke_thread); threadpool_init (&async_io_tp, cpu_count * 2, cpu_count * 4, async_invoke_thread); async_io_tp.is_io = TRUE; async_call_klass = mono_class_from_name (mono_defaults.corlib, "System", "MonoAsyncCall"); g_assert (async_call_klass); mono_mutex_init (&threads_lock); threads = g_ptr_array_sized_new (thread_count); g_assert (threads); mono_mutex_init_recursive (&wsqs_lock); wsqs = g_ptr_array_sized_new (MAX (100 * cpu_count, thread_count)); #ifndef DISABLE_PERFCOUNTERS async_tp.pc_nitems = init_perf_counter ("Mono Threadpool", "Work Items Added"); g_assert (async_tp.pc_nitems); async_io_tp.pc_nitems = init_perf_counter ("Mono Threadpool", "IO Work Items Added"); g_assert (async_io_tp.pc_nitems); async_tp.pc_nthreads = init_perf_counter ("Mono Threadpool", "# of Threads"); g_assert (async_tp.pc_nthreads); async_io_tp.pc_nthreads = init_perf_counter ("Mono Threadpool", "# of IO Threads"); g_assert (async_io_tp.pc_nthreads); #endif tp_inited = 2; #ifdef DEBUG signal (SIGALRM, signal_handler); alarm (2); #endif MONO_SEM_INIT (&monitor_sem, 0); monitor_state = MONITOR_STATE_AWAKE; monitor_njobs = 0; }