void mono_gc_base_init (void) { MonoThreadInfoCallbacks cb; int dummy; if (gc_initialized) return; mono_counters_init (); corgc_init (); memset (&cb, 0, sizeof (cb)); cb.thread_register = corgc_thread_register; cb.thread_unregister = corgc_thread_unregister; cb.mono_method_is_critical = (gboolean(*)(void*))mono_runtime_is_critical_method; #ifndef HOST_WIN32 cb.thread_exit = mono_gc_pthread_exit; cb.mono_gc_pthread_create = mono_gc_pthread_create; #endif mono_threads_init (&cb, sizeof (CorgcThreadInfo)); mono_thread_info_attach (&dummy); mono_gc_enable_events (); gc_initialized = TRUE; }
int main (void) { MonoThreadInfoCallbacks cb = { NULL }; MonoThreadInfoRuntimeCallbacks ticallbacks; int res = 0; CHECKED_MONO_INIT (); mono_threads_init (&cb, sizeof (MonoThreadInfo)); memset (&ticallbacks, 0, sizeof (ticallbacks)); ticallbacks.thread_state_init = thread_state_init; mono_threads_runtime_init (&ticallbacks); mono_thread_info_attach ((gpointer)&cb); // benchmark_conc (); // benchmark_glib (); res += single_writer_single_reader (); res += parallel_writer_single_reader (); res += single_writer_parallel_reader (); res += parallel_writer_parallel_reader (); return res; }
int main (void) { MonoThreadInfoRuntimeCallbacks ticallbacks; int res = 0; CHECKED_MONO_INIT (); mono_thread_info_init (sizeof (MonoThreadInfo)); memset (&ticallbacks, 0, sizeof (ticallbacks)); ticallbacks.thread_state_init = thread_state_init; mono_thread_info_runtime_init (&ticallbacks); #ifndef HOST_WIN32 mono_w32handle_init (); #endif mono_thread_info_attach (); // benchmark_conc (); // benchmark_glib (); res += single_writer_single_reader (); res += parallel_writer_single_reader (); res += single_writer_parallel_reader (); res += parallel_writer_parallel_reader (); return res; }
static DWORD WINAPI inner_start_thread (LPVOID arg) { ThreadStartInfo *start_info = arg; void *t_arg = start_info->arg; int post_result; LPTHREAD_START_ROUTINE start_func = start_info->start_routine; DWORD result; gboolean suspend = start_info->suspend; HANDLE suspend_event = start_info->suspend_event; MonoThreadInfo *info; info = mono_thread_info_attach (&result); info->runtime_thread = TRUE; info->create_suspended = suspend; post_result = MONO_SEM_POST (&(start_info->registered)); g_assert (!post_result); if (suspend) { WaitForSingleObject (suspend_event, INFINITE); /* caller will suspend the thread before setting the event. */ CloseHandle (suspend_event); } result = start_func (t_arg); mono_thread_info_detach (); return result; }
static gsize WINAPI inner_start_thread (gpointer data) { CreateThreadData *thread_data; MonoThreadInfo *info; MonoThreadStart start_routine; gpointer start_routine_arg; gsize start_routine_res; gsize dummy; thread_data = (CreateThreadData*) data; g_assert (thread_data); start_routine = thread_data->start_routine; start_routine_arg = thread_data->start_routine_arg; info = mono_thread_info_attach (&dummy); info->runtime_thread = TRUE; thread_data->handle = mono_threads_open_thread_handle (info->handle); mono_coop_sem_post (&thread_data->registered); mono_refcount_dec (thread_data); /* thread_data is not valid anymore */ thread_data = NULL; /* Run the actual main function of the thread */ start_routine_res = start_routine (start_routine_arg); mono_thread_info_exit (start_routine_res); g_assert_not_reached (); }
static void* pw_sr_thread (void *arg) { int i, idx = 1000 * GPOINTER_TO_INT (arg); mono_thread_info_attach (); for (i = 0; i < 1000; ++i) { mono_os_mutex_lock (&global_mutex); mono_conc_hashtable_insert (hash, GINT_TO_POINTER (i + idx), GINT_TO_POINTER (i + 1)); mono_os_mutex_unlock (&global_mutex); } return NULL; }
static void* inner_start_thread (void *arg) { StartInfo *start_info = (StartInfo *) arg; void *t_arg = start_info->arg; int res; void *(*start_func)(void*) = start_info->start_routine; guint32 flags = start_info->flags; void *result; HANDLE handle; MonoThreadInfo *info; /* Register the thread with the io-layer */ handle = wapi_create_thread_handle (); if (!handle) { res = MONO_SEM_POST (&(start_info->registered)); g_assert (!res); return NULL; } start_info->handle = handle; info = mono_thread_info_attach (&result); MONO_PREPARE_BLOCKING info->runtime_thread = TRUE; info->handle = handle; if (flags & CREATE_SUSPENDED) { info->create_suspended = TRUE; MONO_SEM_INIT (&info->create_suspended_sem, 0); } /* start_info is not valid after this */ res = MONO_SEM_POST (&(start_info->registered)); g_assert (!res); start_info = NULL; if (flags & CREATE_SUSPENDED) { while (MONO_SEM_WAIT (&info->create_suspended_sem) != 0 && errno == EINTR); MONO_SEM_DESTROY (&info->create_suspended_sem); } MONO_FINISH_BLOCKING /* Run the actual main function of the thread */ result = start_func (t_arg); mono_threads_core_exit (GPOINTER_TO_UINT (result)); g_assert_not_reached (); }
/** * mono_threads_attach_tools_thread * * Attach the current thread as a tool thread. DON'T USE THIS FUNCTION WITHOUT READING ALL DISCLAIMERS. * * A tools thread is a very special kind of thread that needs access to core runtime facilities but should * not be counted as a regular thread for high order facilities such as executing managed code or accessing * the managed heap. * * This is intended only to tools such as a profiler than needs to be able to use our lock-free support when * doing things like resolving backtraces in their background processing thread. */ void mono_threads_attach_tools_thread (void) { int dummy = 0; MonoThreadInfo *info; /* Must only be called once */ g_assert (!mono_native_tls_get_value (thread_info_key)); info = mono_thread_info_attach (&dummy); g_assert (info); info->tools_thread = TRUE; }
static void* pw_pr_w_del_thread (void *arg) { int i, idx = 1000 * GPOINTER_TO_INT (arg); mono_thread_info_attach (); for (i = idx; i < idx + 1000; i++) { mono_os_mutex_lock (&global_mutex); mono_conc_hashtable_remove (hash, GINT_TO_POINTER (i + 1)); mono_os_mutex_unlock (&global_mutex); } return NULL; }
static void* pr_sw_thread (void *arg) { int i = 0, idx = 100 * GPOINTER_TO_INT (arg); mono_thread_info_attach (); while (i < 100) { gpointer res = mono_conc_hashtable_lookup (hash, GINT_TO_POINTER (i + idx + 1)); if (!res) continue; if (res != GINT_TO_POINTER ((i + idx) * 2 + 1)) return GINT_TO_POINTER (i); ++i; } return NULL; }
void mono_gc_base_init (void) { MonoThreadInfoCallbacks cb; int dummy; mono_counters_init (); memset (&cb, 0, sizeof (cb)); /* TODO: This casts away an incompatible pointer type warning in the same manner that boehm-gc does it. This is probably worth investigating more carefully. */ cb.mono_method_is_critical = (gpointer)mono_runtime_is_critical_method; mono_threads_init (&cb, sizeof (MonoThreadInfo)); mono_thread_info_attach (&dummy); }
static gsize WINAPI inner_start_thread (gpointer data) { CreateThreadData *thread_data; MonoThreadInfo *info; MonoThreadStart start_routine; gpointer start_routine_arg; guint32 start_routine_res; gint32 priority; gsize dummy; thread_data = (CreateThreadData*) data; g_assert (thread_data); start_routine = thread_data->start_routine; start_routine_arg = thread_data->start_routine_arg; priority = thread_data->priority; info = mono_thread_info_attach (&dummy); info->runtime_thread = TRUE; mono_threads_platform_set_priority (info, priority); thread_data->handle = mono_thread_info_duplicate_handle (info); mono_coop_sem_post (&thread_data->registered); if (InterlockedDecrement (&thread_data->ref) == 0) { mono_coop_sem_destroy (&thread_data->registered); g_free (thread_data); } /* thread_data is not valid anymore */ thread_data = NULL; /* Run the actual main function of the thread */ start_routine_res = start_routine (start_routine_arg); mono_threads_platform_exit (start_routine_res); g_assert_not_reached (); }
static void* inner_start_thread (void *arg) { ThreadStartInfo *start_info = arg; void *t_arg = start_info->arg; int post_result; void *(*start_func)(void*) = start_info->start_routine; void *result; mono_thread_info_attach (&result); post_result = MONO_SEM_POST (&(start_info->registered)); g_assert (!post_result); result = start_func (t_arg); g_assert (!mono_domain_get ()); return result; }
static void* pw_pr_r_thread (void *arg) { int key, val, i; mono_thread_info_attach (); /* i will not be incremented as long as running is set to 1, this guarantee that we loop over all the keys at least once after the writer threads have finished */ for (i = 0; i < 2; i += 1 - running) { for (key = 1; key < 3 * 1000 + 1; key++) { val = GPOINTER_TO_INT (mono_conc_hashtable_lookup (hash, GINT_TO_POINTER (key))); if (!val) continue; if (key != val) return GINT_TO_POINTER (key); } } return NULL; }
static void* inner_start_thread (void *arg) { StartInfo *start_info = arg; void *t_arg = start_info->arg; int res; void *(*start_func)(void*) = start_info->start_routine; guint32 flags = start_info->flags; void *result; HANDLE handle; MonoThreadInfo *info; /* Register the thread with the io-layer */ handle = wapi_create_thread_handle (); if (!handle) { res = MONO_SEM_POST (&(start_info->registered)); g_assert (!res); return NULL; } start_info->handle = handle; info = mono_thread_info_attach (&result); info->runtime_thread = TRUE; info->handle = handle; if (flags & CREATE_SUSPENDED) { info->create_suspended = TRUE; MONO_SEM_INIT (&info->create_suspended_sem, 0); } /* start_info is not valid after this */ res = MONO_SEM_POST (&(start_info->registered)); g_assert (!res); start_info = NULL; if (flags & CREATE_SUSPENDED) { while (MONO_SEM_WAIT (&info->create_suspended_sem) != 0 && errno == EINTR); MONO_SEM_DESTROY (&info->create_suspended_sem); } /* Run the actual main function of the thread */ result = start_func (t_arg); /* mono_thread_info_detach (); */ #if defined(__native_client__) nacl_shutdown_gc_thread(); #endif wapi_thread_handle_set_exited (handle, GPOINTER_TO_UINT (result)); /* This is needed by mono_threads_core_unregister () which is called later */ info->handle = NULL; g_assert (mono_threads_get_callbacks ()->thread_exit); mono_threads_get_callbacks ()->thread_exit (NULL); g_assert_not_reached (); return result; }
gboolean mono_gc_register_thread (void *baseptr) { return mono_thread_info_attach (baseptr) != NULL; }
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; }