#define CULTURES_START_IDX 0
#define UICULTURES_START_IDX NUM_CACHED_CULTURES
-/*
- * The "os_handle" field of the WaitHandle class.
- */
-static MonoClassField *wait_handle_os_handle_field = NULL;
-
/* Controls access to the 'threads' hash table */
#define mono_threads_lock() EnterCriticalSection (&threads_mutex)
#define mono_threads_unlock() LeaveCriticalSection (&threads_mutex)
static guint32 mono_alloc_static_data_slot (StaticDataInfo *static_data, guint32 size, guint32 align);
static gboolean mono_thread_resume (MonoThread* thread);
static void mono_thread_start (MonoThread *thread);
+static void signal_thread_state_change (MonoThread *thread);
/* Spin lock for InterlockedXXX 64 bit functions */
#define mono_interlocked_lock() EnterCriticalSection (&interlocked_mutex)
tid=thread->tid;
SET_CURRENT_OBJECT (thread);
+
+ /* Every thread references the appdomain which created it */
+ mono_thread_push_appdomain_ref (start_info->domain);
if (!mono_domain_set (start_info->domain, FALSE)) {
/* No point in raising an appdomain_unloaded exception here */
/* FIXME: Cleanup here */
+ mono_thread_pop_appdomain_ref ();
return 0;
}
g_free (start_info);
- /* Every thread references the appdomain which created it */
- mono_thread_push_appdomain_ref (mono_domain_get ());
-
thread_adjust_static_data (thread);
#ifdef DEBUG
g_message ("%s: start_wrapper for %"G_GSIZE_FORMAT, __func__,
ResumeThread (thread_handle);
}
+/*
+ * mono_thread_get_stack_bounds:
+ *
+ * Return the address and size of the current threads stack. Return NULL as the stack
+ * address if the stack address cannot be determined.
+ */
+static void
+mono_thread_get_stack_bounds (guint8 **staddr, size_t *stsize)
+{
+#ifndef PLATFORM_WIN32
+ pthread_attr_t attr;
+ guint8 *current = (guint8*)&attr;
+
+ pthread_attr_init (&attr);
+#ifdef HAVE_PTHREAD_GETATTR_NP
+ pthread_getattr_np (pthread_self(), &attr);
+#else
+#ifdef HAVE_PTHREAD_ATTR_GET_NP
+ pthread_attr_get_np (pthread_self(), &attr);
+#elif defined(sun)
+ *staddr = NULL;
+ pthread_attr_getstacksize (&attr, &stsize);
+#else
+ *staddr = NULL;
+ *stsize = 0;
+ return;
+#endif
+#endif
+
+#ifndef sun
+ pthread_attr_getstack (&attr, (void**)staddr, stsize);
+ if (*staddr)
+ g_assert ((current > *staddr) && (current < *staddr + *stsize));
+#endif
+#endif
+}
+
MonoThread *
mono_thread_attach (MonoDomain *domain)
{
thread_adjust_static_data (thread);
if (mono_thread_attach_cb) {
- mono_thread_attach_cb (tid, &tid);
+ guint8 *staddr;
+ size_t stsize;
+
+ mono_thread_get_stack_bounds (&staddr, &stsize);
+
+ if (staddr == NULL)
+ mono_thread_attach_cb (tid, &tid);
+ else
+ mono_thread_attach_cb (tid, staddr + stsize);
}
return(thread);
THREAD_DEBUG (g_message ("%s: Sleeping for %d ms", __func__, ms));
+ mono_thread_current_check_pending_interrupt ();
+
mono_monitor_enter (thread->synch_lock);
thread->state |= ThreadState_WaitSleepJoin;
mono_monitor_exit (thread->synch_lock);
mono_monitor_exit (thread->synch_lock);
}
+void ves_icall_System_Threading_Thread_SpinWait_internal (gint32 iterations)
+{
+ gint32 i;
+
+ for(i = 0; i < iterations; i++) {
+ /* We're busy waiting, but at least we can tell the
+ * scheduler to let someone else have a go...
+ */
+ Sleep (0);
+ }
+}
+
gint32
ves_icall_System_Threading_Thread_GetDomainID (void)
{
return FALSE;
}
+ mono_thread_current_check_pending_interrupt ();
+
this->state |= ThreadState_WaitSleepJoin;
mono_monitor_exit (this->synch_lock);
guint32 ret;
guint32 i;
MonoObject *waitHandle;
- MonoClass *klass;
MonoThread *thread = mono_thread_current ();
MONO_ARCH_SAVE_REGS;
+ /* Do this WaitSleepJoin check before creating objects */
+ mono_thread_current_check_pending_interrupt ();
+
numhandles = mono_array_length(mono_handles);
handles = g_new0(HANDLE, numhandles);
- if (wait_handle_os_handle_field == 0) {
- /* Get the field os_handle which will contain the actual handle */
- klass = mono_class_from_name(mono_defaults.corlib, "System.Threading", "WaitHandle");
- wait_handle_os_handle_field = mono_class_get_field_from_name(klass, "os_handle");
- }
-
for(i = 0; i < numhandles; i++) {
- waitHandle = mono_array_get(mono_handles, MonoObject*, i);
- mono_field_get_value(waitHandle, wait_handle_os_handle_field, &handles[i]);
+ waitHandle = mono_array_get(mono_handles, MonoObject*, i);
+ handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
}
if(ms== -1) {
guint32 ret;
guint32 i;
MonoObject *waitHandle;
- MonoClass *klass;
MonoThread *thread = mono_thread_current ();
MONO_ARCH_SAVE_REGS;
+ /* Do this WaitSleepJoin check before creating objects */
+ mono_thread_current_check_pending_interrupt ();
+
numhandles = mono_array_length(mono_handles);
handles = g_new0(HANDLE, numhandles);
- if (wait_handle_os_handle_field == 0) {
- /* Get the field os_handle which will contain the actual handle */
- klass = mono_class_from_name(mono_defaults.corlib, "System.Threading", "WaitHandle");
- wait_handle_os_handle_field = mono_class_get_field_from_name(klass, "os_handle");
- }
-
for(i = 0; i < numhandles; i++) {
- waitHandle = mono_array_get(mono_handles, MonoObject*, i);
- mono_field_get_value(waitHandle, wait_handle_os_handle_field, &handles[i]);
+ waitHandle = mono_array_get(mono_handles, MonoObject*, i);
+ handles [i] = mono_wait_handle_get_handle ((MonoWaitHandle *) waitHandle);
}
if(ms== -1) {
ms=INFINITE;
}
+ mono_thread_current_check_pending_interrupt ();
+
mono_monitor_enter (thread->synch_lock);
thread->state |= ThreadState_WaitSleepJoin;
mono_monitor_exit (thread->synch_lock);
return(mutex);
}
-void ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
+MonoBoolean ves_icall_System_Threading_Mutex_ReleaseMutex_internal (HANDLE handle ) {
MONO_ARCH_SAVE_REGS;
- ReleaseMutex(handle);
+ return(ReleaseMutex (handle));
}
HANDLE ves_icall_System_Threading_Mutex_OpenMutex_internal (MonoString *name,
void
ves_icall_System_Threading_Thread_MemoryBarrier (void)
{
- /* Should be implemented as a JIT intrinsic */
- mono_raise_exception (mono_get_exception_not_implemented (NULL));
+ mono_threads_lock ();
+ mono_threads_unlock ();
}
void
return state;
}
+void ves_icall_System_Threading_Thread_Interrupt_internal (MonoThread *this)
+{
+ gboolean throw = FALSE;
+
+ mono_monitor_enter (this->synch_lock);
+
+ /* Clear out any previous request */
+ this->thread_interrupt_requested = FALSE;
+
+ if (this->state & ThreadState_WaitSleepJoin) {
+ throw = TRUE;
+ } else {
+ this->thread_interrupt_requested = TRUE;
+ }
+
+ mono_monitor_exit (this->synch_lock);
+
+ if (throw) {
+ signal_thread_state_change (this);
+ }
+}
+
+void mono_thread_current_check_pending_interrupt ()
+{
+ MonoThread *thread = mono_thread_current ();
+ gboolean throw = FALSE;
+
+ mono_monitor_enter (thread->synch_lock);
+
+ if (thread->thread_interrupt_requested) {
+ throw = TRUE;
+ thread->thread_interrupt_requested = FALSE;
+ }
+
+ mono_monitor_exit (thread->synch_lock);
+
+ if (throw) {
+ mono_raise_exception (mono_get_exception_thread_interrupted ());
+ }
+}
+
int
mono_thread_get_abort_signal (void)
{
-#if defined (__MINGW32__) || defined (_MSC_VER)
+#ifdef PLATFORM_WIN32
return -1;
#else
#ifndef SIGRTMIN
/* fallback to the old way */
return SIGRTMIN;
#endif
-#endif /*defined (__MINGW32__) || defined (_MSC_VER) */
+#endif /* PLATFORM_WIN32 */
}
-#if defined (__MINGW32__) || defined (_MSC_VER)
+#ifdef PLATFORM_WIN32
static void CALLBACK interruption_request_apc (ULONG_PTR param)
{
MonoException* exc = mono_thread_request_interruption (FALSE);
if (exc) mono_raise_exception (exc);
}
-#endif /* defined (__MINGW32__) || defined (_MSC_VER) */
+#endif /* PLATFORM_WIN32 */
/*
* signal_thread_state_change
mono_raise_exception (exc);
}
-#if defined (__MINGW32__) || defined (_MSC_VER)
+#ifdef PLATFORM_WIN32
QueueUserAPC ((PAPCFUNC)interruption_request_apc, thread->handle, NULL);
#else
/* fixme: store the state somewhere */
#else
pthread_kill (thread->tid, mono_thread_get_abort_signal ());
#endif
-#endif /* defined (__MINGW32__) || defined (__MSC_VER) */
+#endif /* PLATFORM_WIN32 */
}
void
}
thread->resume_event = CreateEvent (NULL, TRUE, FALSE, NULL);
+ if (thread->resume_event == NULL) {
+ mono_monitor_exit (thread->synch_lock);
+ return(FALSE);
+ }
/* Awake the thread */
SetEvent (thread->suspend_event);
InitializeCriticalSection(&interlocked_mutex);
InitializeCriticalSection(&contexts_mutex);
background_change_event = CreateEvent (NULL, TRUE, FALSE, NULL);
+ g_assert(background_change_event != NULL);
mono_init_static_data_info (&thread_static_info);
mono_init_static_data_info (&context_static_info);
MonoThread *thread=(MonoThread *)value;
/* Ignore background threads, we abort them later */
- mono_monitor_enter (thread->synch_lock);
+ /* Do not lock here since it is not needed and the caller holds threads_lock */
if (thread->state & ThreadState_Background) {
THREAD_DEBUG (g_message ("%s: ignoring background thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
- mono_monitor_exit (thread->synch_lock);
return; /* just leave, ignore */
}
- mono_monitor_exit (thread->synch_lock);
if (mono_gc_is_finalizer_thread (thread)) {
THREAD_DEBUG (g_message ("%s: ignoring finalizer thread %"G_GSIZE_FORMAT, __func__, (gsize)thread->tid));
thread->state |= ThreadState_SuspendRequested;
- if (thread->suspended_event == NULL)
+ if (thread->suspended_event == NULL) {
thread->suspended_event = CreateEvent (NULL, TRUE, FALSE, NULL);
+ if (thread->suspended_event == NULL) {
+ /* Forget this one and go on to the next */
+ mono_monitor_exit (thread->synch_lock);
+ continue;
+ }
+ }
events [eventidx++] = thread->suspended_event;
mono_monitor_exit (thread->synch_lock);
MonoDomain *domain = data->domain;
if (mono_thread_has_appdomain_ref (thread, domain)) {
- HANDLE handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
- if (handle == NULL)
- return;
-
/* printf ("ABORTING THREAD %p BECAUSE IT REFERENCES DOMAIN %s.\n", thread->tid, domain->friendly_name); */
ves_icall_System_Threading_Thread_Abort (thread, NULL);
if(data->wait.num<MAXIMUM_WAIT_OBJECTS) {
+ HANDLE handle = OpenThread (THREAD_ALL_ACCESS, TRUE, thread->tid);
+ if (handle == NULL)
+ return;
data->wait.handles [data->wait.num] = handle;
data->wait.threads [data->wait.num] = thread;
data->wait.num++;
}
}
-#ifdef __MINGW32__
-static CALLBACK void dummy_apc (ULONG_PTR param)
+#ifdef PLATFORM_WIN32
+static void CALLBACK dummy_apc (ULONG_PTR param)
{
}
#else
thread->state &= ~ThreadState_SuspendRequested;
thread->state |= ThreadState_Suspended;
thread->suspend_event = CreateEvent (NULL, TRUE, FALSE, NULL);
+ if (thread->suspend_event == NULL) {
+ mono_monitor_exit (thread->synch_lock);
+ return(NULL);
+ }
if (thread->suspended_event)
SetEvent (thread->suspended_event);
mono_monitor_exit (thread->synch_lock);
mono_monitor_exit (thread->synch_lock);
mono_thread_exit ();
return NULL;
+ } else if (thread->thread_interrupt_requested) {
+ mono_monitor_exit (thread->synch_lock);
+ return(mono_get_exception_thread_interrupted ());
}
mono_monitor_exit (thread->synch_lock);