*
* Copyright 2001-2003 Ximian, Inc (http://www.ximian.com)
* Copyright 2004-2009 Novell, Inc (http://www.novell.com)
+ * Copyright 2011 Xamarin, Inc (http://www.xamarin.com)
*/
#include <config.h>
#include <mono/utils/mono-time.h>
#include <mono/utils/mono-threads.h>
#include <mono/utils/hazard-pointer.h>
+#include <mono/utils/mono-tls.h>
#include <mono/metadata/gc-internal.h>
static MonoGHashTable *thread_start_args = NULL;
/* The TLS key that holds the MonoObject assigned to each thread */
-static guint32 current_object_key = -1;
+static MonoNativeTlsKey current_object_key;
#ifdef MONO_HAVE_FAST_TLS
/* we need to use both the Tls* functions and __thread because
MONO_FAST_TLS_DECLARE(tls_current_object);
#define SET_CURRENT_OBJECT(x) do { \
MONO_FAST_TLS_SET (tls_current_object, x); \
- TlsSetValue (current_object_key, x); \
+ mono_native_tls_set_value (current_object_key, x); \
} while (FALSE)
#define GET_CURRENT_OBJECT() ((MonoInternalThread*) MONO_FAST_TLS_GET (tls_current_object))
#else
-#define SET_CURRENT_OBJECT(x) TlsSetValue (current_object_key, x)
-#define GET_CURRENT_OBJECT() (MonoInternalThread*) TlsGetValue (current_object_key)
+#define SET_CURRENT_OBJECT(x) mono_native_tls_set_value (current_object_key, x)
+#define GET_CURRENT_OBJECT() (MonoInternalThread*) mono_native_tls_get_value (current_object_key)
#endif
/* function called at thread start */
return InterlockedIncrement (&managed_thread_id_counter);
}
-guint32
+MonoNativeTlsKey
mono_thread_get_tls_key (void)
{
return current_object_key;
}
mono_release_type_locks (thread);
+ ensure_synch_cs_set (thread);
+
EnterCriticalSection (thread->synch_cs);
thread->state |= ThreadState_Stopped;
#ifdef HOST_WIN32
DWORD real_tid;
- res = CreateThread (security, stacksize, start, param, create, &real_tid);
+ res = mono_threads_CreateThread (security, stacksize, start, param, create, &real_tid);
if (tid)
*tid = real_tid;
#else
#if defined(HAVE_PTHREAD_GET_STACKSIZE_NP) && defined(HAVE_PTHREAD_GET_STACKADDR_NP)
*staddr = (guint8*)pthread_get_stackaddr_np (pthread_self ());
*stsize = pthread_get_stacksize_np (pthread_self ());
+
+ /* staddr points to the start of the stack, not the end */
+ *staddr -= *stsize;
*staddr = (guint8*)((gssize)*staddr & ~(mono_pagesize () - 1));
return;
/* FIXME: simplify the mess below */
void ves_icall_System_Threading_Thread_Interrupt_internal (MonoInternalThread *this)
{
- gboolean throw = FALSE;
-
+ MonoInternalThread *current;
+ gboolean throw;
+
ensure_synch_cs_set (this);
- if (this == mono_thread_internal_current ())
- return;
-
- EnterCriticalSection (this->synch_cs);
-
- this->thread_interrupt_requested = TRUE;
-
- if (this->state & ThreadState_WaitSleepJoin) {
- throw = TRUE;
- }
-
+ current = mono_thread_internal_current ();
+
+ EnterCriticalSection (this->synch_cs);
+
+ this->thread_interrupt_requested = TRUE;
+ throw = current != this && (this->state & ThreadState_WaitSleepJoin);
+
LeaveCriticalSection (this->synch_cs);
if (throw) {
return (void *) *((volatile void **) ptr);
}
+double
+ves_icall_System_Threading_Thread_VolatileReadDouble (void *ptr)
+{
+ return *((volatile double *) (ptr));
+}
+
+float
+ves_icall_System_Threading_Thread_VolatileReadFloat (void *ptr)
+{
+ return *((volatile float *) (ptr));
+}
+
void
ves_icall_System_Threading_Thread_VolatileWrite1 (void *ptr, gint8 value)
{
mono_gc_wbarrier_generic_store (ptr, value);
}
+void
+ves_icall_System_Threading_Thread_VolatileWriteDouble (void *ptr, double value)
+{
+ *((volatile double *) ptr) = value;
+}
+
+void
+ves_icall_System_Threading_Thread_VolatileWriteFloat (void *ptr, float value)
+{
+ *((volatile float *) ptr) = value;
+}
+
void mono_thread_init (MonoThreadStartCB start_cb,
MonoThreadAttachCB attach_cb)
{
mono_init_static_data_info (&context_static_info);
MONO_FAST_TLS_INIT (tls_current_object);
- current_object_key=TlsAlloc();
+ mono_native_tls_alloc (¤t_object_key, NULL);
THREAD_DEBUG (g_message ("%s: Allocated current_object_key %d", __func__, current_object_key));
mono_thread_start_cb = start_cb;
CloseHandle (background_change_event);
#endif
- TlsFree (current_object_key);
+ mono_native_tls_free (current_object_key);
}
void
return ret;
}
-static MonoClassField *execution_context_field;
+//static MonoClassField *execution_context_field;
static MonoObject**
get_execution_context_addr (void)
{
MonoDomain *domain = mono_domain_get ();
- guint32 offset;
+ guint32 offset = domain->execution_context_field_offset;
- if (!execution_context_field) {
- execution_context_field = mono_class_get_field_from_name (mono_defaults.thread_class,
- "_ec");
- g_assert (execution_context_field);
- }
+ if (!offset) {
+ MonoClassField *field = mono_class_get_field_from_name (mono_defaults.thread_class, "_ec");
+ g_assert (field);
- g_assert (mono_class_try_get_vtable (domain, mono_defaults.appdomain_class));
+ g_assert (mono_class_try_get_vtable (domain, mono_defaults.appdomain_class));
- mono_domain_lock (domain);
- offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, execution_context_field));
- mono_domain_unlock (domain);
- g_assert (offset);
+ mono_domain_lock (domain);
+ offset = GPOINTER_TO_UINT (g_hash_table_lookup (domain->special_static_fields, field));
+ mono_domain_unlock (domain);
+ g_assert (offset);
+
+ domain->execution_context_field_offset = offset;
+ }
return (MonoObject**) mono_get_special_static_data (offset);
}
mono_thread_info_setup_async_call (info, self_interrupt_thread, NULL);
mono_thread_info_resume (mono_thread_info_get_tid (info));
} else {
+ gpointer interrupt_handle;
/*
* This will cause waits to be broken.
* It will also prevent the thread from entering a wait, so if the thread returns
* make it return.
*/
InterlockedIncrement (&thread_interruption_requested);
+#ifndef HOST_WIN32
+ interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
+#endif
mono_thread_info_resume (mono_thread_info_get_tid (info));
#ifndef HOST_WIN32
- wapi_interrupt_thread (thread->handle);
+ wapi_finish_interrupt_thread (interrupt_handle);
#endif
}
/*FIXME we need to wait for interruption to complete -- figure out how much into interruption we should wait for here*/
if (running_managed && !protected_wrapper) {
transition_to_suspended (thread);
} else {
+ gpointer interrupt_handle;
+
if (InterlockedCompareExchange (&thread->interruption_requested, 1, 0) == 0)
InterlockedIncrement (&thread_interruption_requested);
#ifndef HOST_WIN32
if (interrupt)
- wapi_interrupt_thread (thread->handle);
+ interrupt_handle = wapi_prepare_interrupt_thread (thread->handle);
#endif
mono_thread_info_resume (mono_thread_info_get_tid (info));
+#ifndef HOST_WIN32
+ if (interrupt)
+ wapi_finish_interrupt_thread (interrupt_handle);
+#endif
LeaveCriticalSection (thread->synch_cs);
}
}