/* Force it to be attached to avoid racing during shutdown. */
thread = mono_thread_attach_full (mono_get_root_domain (), TRUE, &error);
mono_error_raise_exception (&error); /* FIXME don't raise here */
- mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Domain unloader"), TRUE);
+ mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Domain unloader"), TRUE, &error);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
/*
* FIXME: Abort our parent thread last, so we can return a failure
static guint32 WINAPI
receiver_thread (void *arg)
{
+ MonoError error;
int res, content_len;
guint8 buffer [256];
guint8 *p, *p_end;
printf ("attach: Connected.\n");
MonoThread *thread = mono_thread_attach (mono_get_root_domain ());
- mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Attach receiver"), TRUE);
+ mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "Attach receiver"), TRUE, &error);
+ mono_error_assert_ok (&error);
/* Ask the runtime to not abort this thread */
//mono_thread_current ()->flags |= MONO_THREAD_FLAG_DONT_MANAGE;
/* Ask the runtime to not wait for this thread */
{
char *trace;
MonoString *res;
- if (!exc)
- mono_raise_exception (mono_get_exception_argument_null ("exception"));
+ if (!exc) {
+ mono_set_pending_exception (mono_get_exception_argument_null ("exception"));
+ return NULL;
+ }
trace = mono_exception_get_native_backtrace (exc);
res = mono_string_new (mono_domain_get (), trace);
static guint32
finalizer_thread (gpointer unused)
{
- mono_thread_set_name_internal (mono_thread_internal_current (), mono_string_new (mono_get_root_domain (), "Finalizer"), FALSE);
+ MonoError error;
+ mono_thread_set_name_internal (mono_thread_internal_current (), mono_string_new (mono_get_root_domain (), "Finalizer"), FALSE, &error);
+ mono_error_assert_ok (&error);
gboolean wait = TRUE;
thread = mono_thread_internal_current ();
g_assert (thread);
- mono_thread_set_name_internal (thread, mono_string_new (mono_get_root_domain (), "Threadpool worker"), FALSE);
+ mono_thread_set_name_internal (thread, mono_string_new (mono_get_root_domain (), "Threadpool worker"), FALSE, &error);
+ mono_error_assert_ok (&error);
mono_coop_mutex_lock (&threadpool->active_threads_lock);
g_ptr_array_add (threadpool->working_threads, thread);
MonoException* mono_thread_get_and_clear_pending_exception (void);
-void mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed);
+void mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed, MonoError *error);
void mono_runtime_set_has_tls_get (gboolean val);
gboolean mono_runtime_has_tls_get (void);
return thread;
}
-static void
-init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate)
+static gboolean
+init_root_domain_thread (MonoInternalThread *thread, MonoThread *candidate, MonoError *error)
{
- MonoError error;
MonoDomain *domain = mono_get_root_domain ();
+ mono_error_init (error);
if (!candidate || candidate->obj.vtable->domain != domain) {
- candidate = new_thread_with_internal (domain, thread, &error);
- mono_error_raise_exception (&error); /* FIXME don't raise here */
+ candidate = new_thread_with_internal (domain, thread, error);
+ return_val_if_nok (error, FALSE);
}
set_current_thread_for_domain (domain, thread, candidate);
g_assert (!thread->root_domain_thread);
MONO_OBJECT_SETREF (thread, root_domain_thread, candidate);
+ return TRUE;
}
static guint32 WINAPI start_wrapper_internal(void *data)
{
+ MonoError error;
MonoThreadInfo *info;
StartInfo *start_info = (StartInfo *)data;
guint32 (*start_func)(void *);
/* We have to do this here because mono_thread_new_init()
requires that root_domain_thread is set up. */
thread_adjust_static_data (internal);
- init_root_domain_thread (internal, start_info->obj);
+ init_root_domain_thread (internal, start_info->obj, &error);
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
/* This MUST be called before any managed code can be
* executed, as it calls the callback function that (for the
*/
static gboolean
create_thread (MonoThread *thread, MonoInternalThread *internal, StartInfo *start_info, gboolean threadpool_thread, guint32 stack_size,
- gboolean throw_on_failure)
+ MonoError *error)
{
HANDLE thread_handle;
MonoNativeThreadId tid;
*/
mono_threads_join_threads ();
+ mono_error_init (error);
+
mono_threads_lock ();
if (shutting_down) {
g_free (start_info);
stack_size, create_flags, &tid);
if (thread_handle == NULL) {
- /* The thread couldn't be created, so throw an exception */
+ /* The thread couldn't be created, so set an exception */
mono_threads_lock ();
mono_g_hash_table_remove (threads_starting_up, thread);
mono_threads_unlock ();
g_free (start_info);
- if (throw_on_failure)
- mono_raise_exception (mono_get_exception_execution_engine ("Couldn't create thread"));
- else
- g_warning ("%s: CreateThread error 0x%x", __func__, GetLastError ());
+ mono_error_set_execution_engine (error, "Couldn't create thread. Error 0x%x", GetLastError());
return FALSE;
}
THREAD_DEBUG (g_message ("%s: Started thread ID %"G_GSIZE_FORMAT" (handle %p)", __func__, tid, thread_handle));
start_info->obj = thread;
start_info->start_arg = arg;
- res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, TRUE);
- if (!res)
+ res = create_thread (thread, internal, start_info, threadpool_thread, stack_size, &error);
+ if (!res) {
+ mono_error_raise_exception (&error); /* FIXME don't raise here */
return NULL;
+ }
/* Check that the managed and unmanaged layout of MonoInternalThread matches */
#ifndef MONO_CROSS_COMPILE
thread_adjust_static_data (thread);
- init_root_domain_thread (thread, current_thread);
+ init_root_domain_thread (thread, current_thread, error);
+ return_val_if_nok (error, NULL);
+
if (domain != mono_get_root_domain ())
set_current_thread_for_domain (domain, thread, current_thread);
ves_icall_System_Threading_Thread_Thread_internal (MonoThread *this_obj,
MonoObject *start)
{
+ MonoError error;
StartInfo *start_info;
MonoInternalThread *internal;
gboolean res;
start_info->obj = this_obj;
g_assert (this_obj->obj.vtable->domain == mono_domain_get ());
- res = create_thread (this_obj, internal, start_info, FALSE, 0, FALSE);
+ res = create_thread (this_obj, internal, start_info, FALSE, 0, &error);
if (!res) {
+ mono_error_cleanup (&error);
UNLOCK_THREAD (internal);
return NULL;
}
}
void
-mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed)
+mono_thread_set_name_internal (MonoInternalThread *this_obj, MonoString *name, gboolean managed, MonoError *error)
{
LOCK_THREAD (this_obj);
+ mono_error_init (error);
+
if ((this_obj->flags & MONO_THREAD_FLAG_NAME_SET) && !this_obj->threadpool_thread) {
UNLOCK_THREAD (this_obj);
- mono_raise_exception (mono_get_exception_invalid_operation ("Thread.Name can only be set once."));
+ mono_error_set_invalid_operation (error, "Thread.Name can only be set once.");
return;
}
if (this_obj->name) {
void
ves_icall_System_Threading_Thread_SetName_internal (MonoInternalThread *this_obj, MonoString *name)
{
- mono_thread_set_name_internal (this_obj, name, TRUE);
+ MonoError error;
+ mono_thread_set_name_internal (this_obj, name, TRUE, &error);
+ mono_error_set_pending_exception (&error);
}
/*
GPtrArray *methods = (GPtrArray *)user_data [2];
int i;
+ MonoError error;
MonoThread *thread = mono_thread_attach (domain);
- mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "AOT compiler"), TRUE);
+ mono_thread_set_name_internal (thread->internal_thread, mono_string_new (mono_get_root_domain (), "AOT compiler"), TRUE, &error);
+ mono_error_assert_ok (&error);
for (i = 0; i < methods->len; ++i)
compile_method (acfg, (MonoMethod *)g_ptr_array_index (methods, i));
static guint32 WINAPI
debugger_thread (void *arg)
{
+ MonoError error;
int res, len, id, flags, command = 0;
CommandSet command_set = (CommandSet)0;
guint8 header [HEADER_LENGTH];
attach_cookie = mono_jit_thread_attach (mono_get_root_domain (), &attach_dummy);
MonoInternalThread *thread = mono_thread_internal_current ();
- mono_thread_set_name_internal (thread, mono_string_new (mono_get_root_domain (), "Debugger agent"), TRUE);
+ mono_thread_set_name_internal (thread, mono_string_new (mono_get_root_domain (), "Debugger agent"), TRUE, &error);
+ mono_error_assert_ok (&error);
thread->flags |= MONO_THREAD_FLAG_DONT_MANAGE;
#endif
-#if defined(TARGET_APPLETVOS)
+#if defined(TARGET_APPLETVOS) || defined(TARGET_IOS)
#define MONO_ARCH_HAVE_UNWIND_BACKTRACE 1
#endif
#endif
volatile gint32 run_writer_thread;
MonoLockFreeQueue writer_queue;
+ MonoSemType writer_queue_sem;
MonoConcurrentHashTable *method_table;
mono_mutex_t method_table_mutex;
BinaryObject *binary_objects;
entry->methods = methods;
entry->buffer = buffer;
mono_lock_free_queue_enqueue (&prof->writer_queue, &entry->node);
+ mono_os_sem_post (&prof->writer_queue_sem);
}
static void
TLS_SET (tlsmethodlist, NULL);
InterlockedWrite (&prof->run_writer_thread, 0);
+ mono_os_sem_post (&prof->writer_queue_sem);
pthread_join (prof->writer_thread, &res);
+ mono_os_sem_destroy (&prof->writer_queue_sem);
+
#if defined (HAVE_SYS_ZLIB)
if (prof->gzfile)
gzclose (prof->gzfile);
}
#endif
-static void *
-writer_thread (void *arg)
+static gboolean
+handle_writer_queue_entry (MonoProfiler *prof)
{
- MonoProfiler *prof = (MonoProfiler *)arg;
+ WriterQueueEntry *entry;
- mono_threads_attach_tools_thread ();
- mono_thread_info_set_name (mono_native_thread_id_get (), "Profiler writer");
+ if ((entry = (WriterQueueEntry *) mono_lock_free_queue_dequeue (&prof->writer_queue))) {
+ LogBuffer *method_buffer = NULL;
+ gboolean new_methods = FALSE;
- dump_header (prof);
+ if (entry->methods->len)
+ method_buffer = create_buffer ();
- while (InterlockedRead (&prof->run_writer_thread)) {
- WriterQueueEntry *entry;
+ /*
+ * Encode the method events in a temporary log buffer that we
+ * flush to disk before the main buffer, ensuring that all
+ * methods have metadata emitted before they're referenced.
+ */
+ for (guint i = 0; i < entry->methods->len; i++) {
+ MethodInfo *info = (MethodInfo *)g_ptr_array_index (entry->methods, i);
- while ((entry = (WriterQueueEntry *) mono_lock_free_queue_dequeue (&prof->writer_queue))) {
- LogBuffer *method_buffer = NULL;
- gboolean new_methods = FALSE;
+ if (mono_conc_hashtable_lookup (prof->method_table, info->method))
+ continue;
- if (entry->methods->len)
- method_buffer = create_buffer ();
+ new_methods = TRUE;
/*
- * Encode the method events in a temporary log buffer that we
- * flush to disk before the main buffer, ensuring that all
- * methods have metadata emitted before they're referenced.
+ * Other threads use this hash table to get a general
+ * idea of whether a method has already been emitted to
+ * the stream. Due to the way we add to this table, it
+ * can easily happen that multiple threads queue up the
+ * same methods, but that's OK since eventually all
+ * methods will be in this table and the thread-local
+ * method lists will just be empty for the rest of the
+ * app's lifetime.
*/
- for (guint i = 0; i < entry->methods->len; i++) {
- MethodInfo *info = (MethodInfo *)g_ptr_array_index (entry->methods, i);
+ mono_os_mutex_lock (&prof->method_table_mutex);
+ mono_conc_hashtable_insert (prof->method_table, info->method, info->method);
+ mono_os_mutex_unlock (&prof->method_table_mutex);
+
+ char *name = mono_method_full_name (info->method, 1);
+ int nlen = strlen (name) + 1;
+ void *cstart = info->ji ? mono_jit_info_get_code_start (info->ji) : NULL;
+ int csize = info->ji ? mono_jit_info_get_code_size (info->ji) : 0;
+
+ method_buffer = ensure_logbuf_inner (method_buffer,
+ EVENT_SIZE /* event */ +
+ LEB128_SIZE /* time */ +
+ LEB128_SIZE /* method */ +
+ LEB128_SIZE /* start */ +
+ LEB128_SIZE /* size */ +
+ nlen /* name */
+ );
+
+ emit_byte (method_buffer, TYPE_JIT | TYPE_METHOD);
+ emit_time (method_buffer, info->time);
+ emit_method_inner (method_buffer, info->method);
+ emit_ptr (method_buffer, cstart);
+ emit_value (method_buffer, csize);
+
+ memcpy (method_buffer->cursor, name, nlen);
+ method_buffer->cursor += nlen;
+
+ mono_free (name);
+ free (info);
+ }
- if (mono_conc_hashtable_lookup (prof->method_table, info->method))
- continue;
+ g_ptr_array_free (entry->methods, TRUE);
- new_methods = TRUE;
-
- /*
- * Other threads use this hash table to get a general
- * idea of whether a method has already been emitted to
- * the stream. Due to the way we add to this table, it
- * can easily happen that multiple threads queue up the
- * same methods, but that's OK since eventually all
- * methods will be in this table and the thread-local
- * method lists will just be empty for the rest of the
- * app's lifetime.
- */
- mono_os_mutex_lock (&prof->method_table_mutex);
- mono_conc_hashtable_insert (prof->method_table, info->method, info->method);
- mono_os_mutex_unlock (&prof->method_table_mutex);
-
- char *name = mono_method_full_name (info->method, 1);
- int nlen = strlen (name) + 1;
- void *cstart = info->ji ? mono_jit_info_get_code_start (info->ji) : NULL;
- int csize = info->ji ? mono_jit_info_get_code_size (info->ji) : 0;
-
- method_buffer = ensure_logbuf_inner (method_buffer,
- EVENT_SIZE /* event */ +
- LEB128_SIZE /* time */ +
- LEB128_SIZE /* method */ +
- LEB128_SIZE /* start */ +
- LEB128_SIZE /* size */ +
- nlen /* name */
- );
-
- emit_byte (method_buffer, TYPE_JIT | TYPE_METHOD);
- emit_time (method_buffer, info->time);
- emit_method_inner (method_buffer, info->method);
- emit_ptr (method_buffer, cstart);
- emit_value (method_buffer, csize);
-
- memcpy (method_buffer->cursor, name, nlen);
- method_buffer->cursor += nlen;
-
- mono_free (name);
- free (info);
- }
+ if (new_methods) {
+ for (LogBuffer *iter = method_buffer; iter; iter = iter->next)
+ iter->thread_id = 0;
+
+ dump_buffer (prof, method_buffer);
+ } else if (method_buffer)
+ free_buffer (method_buffer, method_buffer->size);
- g_ptr_array_free (entry->methods, TRUE);
+ dump_buffer (prof, entry->buffer);
- if (new_methods) {
- for (LogBuffer *iter = method_buffer; iter; iter = iter->next)
- iter->thread_id = 0;
+ free (entry);
- dump_buffer (prof, method_buffer);
- } else if (method_buffer)
- free_buffer (method_buffer, method_buffer->size);
+ return TRUE;
+ }
- dump_buffer (prof, entry->buffer);
+ return FALSE;
+}
- free (entry);
- }
+static void *
+writer_thread (void *arg)
+{
+ MonoProfiler *prof = (MonoProfiler *)arg;
+ WriterQueueEntry *entry;
+
+ mono_threads_attach_tools_thread ();
+ mono_thread_info_set_name (mono_native_thread_id_get (), "Profiler writer");
+
+ dump_header (prof);
+
+ while (InterlockedRead (&prof->run_writer_thread)) {
+ mono_os_sem_wait (&prof->writer_queue_sem, MONO_SEM_FLAGS_NONE);
+ handle_writer_queue_entry (prof);
}
+ /* Drain any remaining entries on shutdown. */
+ while (handle_writer_queue_entry (prof));
+
mono_thread_info_detach ();
return NULL;
#endif
mono_lock_free_queue_init (&prof->writer_queue);
+ mono_os_sem_init (&prof->writer_queue_sem, 1);
+
mono_os_mutex_init (&prof->method_table_mutex);
prof->method_table = mono_conc_hashtable_new (NULL, NULL);
void
mono_error_set_not_supported (MonoError *error, const char *msg_format, ...);
+void
+mono_error_set_invalid_operation (MonoError *error, const char *msg_format, ...);
+
void
mono_error_set_exception_instance (MonoError *error, MonoException *exc);
}
/**
- * mono_error_set_execution_engine:
+ * mono_error_set_not_supported:
*
* System.NotSupportedException
*/
va_end (args);
}
+/**
+ * mono_error_set_invalid_operation:
+ *
+ * System.InvalidOperationException
+ */
+void
+mono_error_set_invalid_operation (MonoError *oerror, const char *msg_format, ...)
+{
+ va_list args;
+ va_start (args, msg_format);
+ mono_error_set_generic_errorv (oerror, "System", "InvalidOperationException", msg_format, args);
+ va_end (args);
+}
+
void
mono_error_set_exception_instance (MonoError *oerror, MonoException *exc)
{