Tue May 13 16:41:49 CEST 2003 Paolo Molaro <lupus@ximian.com>
[mono.git] / mono / metadata / threads.c
index cb1cdb76a3c0c57283760d32c2f234dcef96406e..faa768f34e046894af69b80f5c4d9952c0444252 100644 (file)
@@ -3,6 +3,7 @@
  *
  * Author:
  *     Dick Porter (dick@ximian.com)
+ *     Paolo Molaro (lupus@ximian.com)
  *     Patrik Torstensson (patrik.torstensson@labs2.com)
  *
  * (C) 2001 Ximian, Inc.
 #include <mono/metadata/threads.h>
 #include <mono/metadata/threads-types.h>
 #include <mono/metadata/exception.h>
+#include <mono/metadata/environment.h>
+#include <mono/metadata/monitor.h>
 #include <mono/io-layer/io-layer.h>
 
 #include <mono/os/gc_wrapper.h>
 
 #undef THREAD_DEBUG
-#undef THREAD_LOCK_DEBUG
 #undef THREAD_WAIT_DEBUG
 
 struct StartInfo 
@@ -44,22 +46,14 @@ typedef union {
  */
 static MonoClassField *wait_handle_os_handle_field = NULL;
 
-/* Controls access to the 'threads' array */
+/* Controls access to the 'threads' hash table */
 static CRITICAL_SECTION threads_mutex;
 
-/* Controls access to the sync field in MonoObjects, to avoid race
- * conditions when adding sync data to an object for the first time.
- */
-static CRITICAL_SECTION monitor_mutex;
-
 /* The hash of existing threads (key is thread ID) that need joining
  * before exit
  */
 static MonoGHashTable *threads=NULL;
 
-/* The MonoObject associated with the main thread */
-static MonoThread *main_thread;
-
 /* The TLS key that holds the MonoObject assigned to each thread */
 static guint32 current_object_key;
 
@@ -67,11 +61,16 @@ static guint32 current_object_key;
 static MonoThreadStartCB mono_thread_start_cb = NULL;
 
 /* function called at thread attach */
-static MonoThreadStartCB mono_thread_attach_cb = NULL;
+static MonoThreadAttachCB mono_thread_attach_cb = NULL;
+
+/* function called when a new thread has been created */
+static MonoThreadCallbacks *mono_thread_callbacks = NULL;
 
 /* The TLS key that holds the LocalDataStoreSlot hash in each thread */
 static guint32 slothash_key;
 
+static void thread_adjust_static_data (MonoThread *thread);
+
 /* Spin lock for InterlockedXXX 64 bit functions */
 static CRITICAL_SECTION interlocked_mutex;
 
@@ -88,21 +87,13 @@ static void handle_store(MonoThread *thread)
 #endif
 
        if(threads==NULL) {
-               threads=mono_g_hash_table_new(g_int_hash, g_int_equal);
+               threads=mono_g_hash_table_new(g_direct_hash, g_direct_equal);
        }
 
-       /* GHashTable will remove a previous entry if a duplicate key
-        * is stored, which is exactly what we want: we store the
-        * thread both in the start_wrapper (in the subthread), and as
-        * soon as possible in the parent thread.  This is to minimise
-        * the window in which the thread exists but we haven't
-        * recorded it.
-        */
-       
        /* We don't need to duplicate thread->handle, because it is
         * only closed when the thread object is finalized by the GC.
         */
-       mono_g_hash_table_insert(threads, &thread->tid, thread);
+       mono_g_hash_table_insert(threads, GUINT_TO_POINTER(thread->tid), thread);
        LeaveCriticalSection(&threads_mutex);
 }
 
@@ -114,7 +105,7 @@ static void handle_remove(guint32 tid)
 
        EnterCriticalSection(&threads_mutex);
 
-       mono_g_hash_table_remove (threads, &tid);
+       mono_g_hash_table_remove (threads, GUINT_TO_POINTER(tid));
        
        LeaveCriticalSection(&threads_mutex);
 
@@ -133,10 +124,14 @@ static void handle_remove(guint32 tid)
         */
 }
 
-static void thread_cleanup (guint32 tid)
+static void thread_cleanup (MonoThread *thread)
 {
-       mono_profiler_thread_end (tid);
-       handle_remove (tid);
+       mono_monitor_try_enter ((MonoObject *)thread, INFINITE);
+       thread->state |= ThreadState_Stopped;
+       mono_monitor_exit ((MonoObject *)thread);
+       
+       mono_profiler_thread_end (thread->tid);
+       handle_remove (thread->tid);
 }
 
 static guint32 start_wrapper(void *data)
@@ -145,33 +140,60 @@ static guint32 start_wrapper(void *data)
        guint32 (*start_func)(void *);
        void *this;
        guint32 tid;
+       MonoThread *thread=start_info->obj;
        
 #ifdef THREAD_DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION ": Start wrapper");
+       g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Start wrapper",
+                 GetCurrentThreadId ());
 #endif
        
-       start_func = start_info->func;
+       /* We can be sure start_info->obj->tid and
+        * start_info->obj->handle have been set, because the thread
+        * was created suspended, and these values were set before the
+        * thread resumed
+        */
+
+       tid=thread->tid;
+       
        mono_domain_set (start_info->domain);
+
+       start_func = start_info->func;
        this = start_info->this;
 
-       tid=GetCurrentThreadId ();
-       /* Set the thread ID here as well as in the parent thread,
-        * because we don't know whether the thread object will
-        * already have its ID set before we get to it.  This isn't a
-        * race condition, because if we're not guaranteed to get the
-        * same number in both the parent and child threads, then
-        * something else is seriously broken.
+       /* This MUST be called before any managed code can be
+        * executed, as it calls the callback function that (for the
+        * jit) sets the lmf marker.
         */
-       start_info->obj->tid=tid;
-       
-       handle_store(start_info->obj);
+       mono_thread_new_init (tid, &tid, start_func);
+       thread->stack_ptr = &tid;
 
-       mono_profiler_thread_start (tid);
+#ifdef LIBGC_DEBUG
+       g_message (G_GNUC_PRETTY_FUNCTION
+                  ": (%d,%d) Setting thread stack to %p",
+                  GetCurrentThreadId (), getpid (), thread->stack_ptr);
+#endif
+
+#ifdef THREAD_DEBUG
+       g_message (G_GNUC_PRETTY_FUNCTION
+                  ": (%d) Setting current_object_key to %p",
+                  GetCurrentThreadId (), thread);
+#endif
+
+       TlsSetValue (current_object_key, thread);
 
-       mono_new_thread_init (start_info->obj, &tid);
+       mono_profiler_thread_start (tid);
 
+       if(thread->start_notify!=NULL) {
+               /* Let the thread that called Start() know we're
+                * ready
+                */
+               ReleaseSemaphore (thread->start_notify, 1, NULL);
+       }
+       
        g_free (start_info);
 
+       thread_adjust_static_data (thread);
+
        start_func (this);
 
        /* If the thread calls ExitThread at all, this remaining code
@@ -180,39 +202,34 @@ static guint32 start_wrapper(void *data)
         */
 
 #ifdef THREAD_DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION ": Start wrapper terminating");
+       g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Start wrapper terminating",
+                 GetCurrentThreadId ());
 #endif
        
-       thread_cleanup (tid);
+       thread_cleanup (thread);
        
        return(0);
 }
 
-void mono_new_thread_init (MonoThread *thread_object, gpointer stack_start)
+void mono_thread_new_init (guint32 tid, gpointer stack_start, gpointer func)
 {
-       /* FIXME: GC problem here with recorded object
-        * pointer!
-        *
-        * This is recorded so CurrentThread can return the
-        * Thread object.
-        */
-       TlsSetValue (current_object_key, thread_object);
-
        if (mono_thread_start_cb) {
-               mono_thread_start_cb (stack_start);
+               mono_thread_start_cb (tid, stack_start, func);
        }
+
+       if (mono_thread_callbacks)
+               (* mono_thread_callbacks->thread_created) (tid, stack_start, func);
 }
 
-MonoThread *mono_thread_create (MonoDomain *domain, gpointer func,
-                               gpointer arg)
+void mono_thread_create (MonoDomain *domain, gpointer func, gpointer arg)
 {
        MonoThread *thread;
        HANDLE thread_handle;
        struct StartInfo *start_info;
        guint32 tid;
        
-       thread = (MonoThread *)mono_object_new (domain,
-                                               mono_defaults.thread_class);
+       thread=(MonoThread *)mono_object_new (domain,
+                                             mono_defaults.thread_class);
 
        start_info=g_new0 (struct StartInfo, 1);
        start_info->func = func;
@@ -220,7 +237,11 @@ MonoThread *mono_thread_create (MonoDomain *domain, gpointer func,
        start_info->domain = domain;
        start_info->this = arg;
                
-       thread_handle = CreateThread(NULL, 0, start_wrapper, start_info, 0, &tid);
+       /* Create suspended, so we can do some housekeeping before the thread
+        * starts
+        */
+       thread_handle = CreateThread(NULL, 0, start_wrapper, start_info,
+                                    CREATE_SUSPENDED, &tid);
 #ifdef THREAD_DEBUG
        g_message(G_GNUC_PRETTY_FUNCTION ": Started thread ID %d (handle %p)",
                  tid, thread_handle);
@@ -232,7 +253,7 @@ MonoThread *mono_thread_create (MonoDomain *domain, gpointer func,
 
        handle_store(thread);
 
-       return thread;
+       ResumeThread (thread_handle);
 }
 
 MonoThread *
@@ -245,7 +266,7 @@ mono_thread_attach (MonoDomain *domain)
        if ((thread = mono_thread_current ())) {
                g_warning ("mono_thread_attach called for an already attached thread");
                if (mono_thread_attach_cb) {
-                       mono_thread_attach_cb (&tid);
+                       mono_thread_attach_cb (tid, &tid);
                }
                return thread;
        }
@@ -268,11 +289,19 @@ mono_thread_attach (MonoDomain *domain)
 
        handle_store(thread);
 
+#ifdef THREAD_DEBUG
+       g_message (G_GNUC_PRETTY_FUNCTION
+                  ": (%d) Setting current_object_key to %p",
+                  GetCurrentThreadId (), thread);
+#endif
+
        TlsSetValue (current_object_key, thread);
        mono_domain_set (domain);
 
+       thread_adjust_static_data (thread);
+
        if (mono_thread_attach_cb) {
-               mono_thread_attach_cb (&tid);
+               mono_thread_attach_cb (tid, &tid);
        }
 
        return(thread);
@@ -297,7 +326,10 @@ HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this,
 #endif
        
        im = mono_get_delegate_invoke (start->vtable->klass);
-       start_func = mono_compile_method (im);
+       if (mono_thread_callbacks)
+               start_func = (* mono_thread_callbacks->thread_start_compile_func) (im);
+       else
+               start_func = mono_compile_method (im);
 
        if(start_func==NULL) {
                g_warning(G_GNUC_PRETTY_FUNCTION
@@ -311,6 +343,12 @@ HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this,
                start_info->obj = this;
                start_info->domain = mono_domain_get ();
 
+               this->start_notify=CreateSemaphore (NULL, 0, 0x7fffffff, NULL);
+               if(this->start_notify==NULL) {
+                       g_warning (G_GNUC_PRETTY_FUNCTION ": CreateSemaphore error 0x%x", GetLastError ());
+                       return(NULL);
+               }
+
                thread=CreateThread(NULL, 0, start_wrapper, start_info,
                                    CREATE_SUSPENDED, &tid);
                if(thread==NULL) {
@@ -318,7 +356,7 @@ HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this,
                                  ": CreateThread error 0x%x", GetLastError());
                        return(NULL);
                }
-
+               
                this->handle=thread;
                this->tid=tid;
 
@@ -332,7 +370,7 @@ HANDLE ves_icall_System_Threading_Thread_Thread_internal(MonoThread *this,
                g_message(G_GNUC_PRETTY_FUNCTION
                          ": Started thread ID %d (handle %p)", tid, thread);
 #endif
-               
+
                return(thread);
        }
 }
@@ -356,7 +394,8 @@ void ves_icall_System_Threading_Thread_Start_internal(MonoThread *this,
        MONO_ARCH_SAVE_REGS;
 
 #ifdef THREAD_DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION ": Launching thread %p", this);
+       g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Launching thread %p (%d)",
+                 GetCurrentThreadId (), this, this->tid);
 #endif
 
        /* Only store the handle when the thread is about to be
@@ -365,7 +404,37 @@ void ves_icall_System_Threading_Thread_Start_internal(MonoThread *this,
         */
        handle_store(this);
 
+       if (mono_thread_callbacks)
+               (* mono_thread_callbacks->start_resume) (this->tid);
+
        ResumeThread(thread);
+
+       if (mono_thread_callbacks)
+               (* mono_thread_callbacks->end_resume) (this->tid);
+
+       if(this->start_notify!=NULL) {
+               /* Wait for the thread to set up its TLS data etc, so
+                * theres no potential race condition if someone tries
+                * to look up the data believing the thread has
+                * started
+                */
+
+#ifdef THREAD_DEBUG
+               g_message(G_GNUC_PRETTY_FUNCTION
+                         ": (%d) waiting for thread %p (%d) to start",
+                         GetCurrentThreadId (), this, this->tid);
+#endif
+
+               WaitForSingleObject (this->start_notify, INFINITE);
+               CloseHandle (this->start_notify);
+               this->start_notify=NULL;
+       }
+
+#ifdef THREAD_DEBUG
+       g_message(G_GNUC_PRETTY_FUNCTION
+                 ": (%d) Done launching thread %p (%d)",
+                 GetCurrentThreadId (), this, this->tid);
+#endif
 }
 
 void ves_icall_System_Threading_Thread_Sleep_internal(gint32 ms)
@@ -462,398 +531,6 @@ MonoObject *ves_icall_System_Threading_Thread_SlotHash_lookup(void)
        return(data);
 }
 
-static void mon_finalize (void *o, void *unused)
-{
-       MonoThreadsSync *mon=(MonoThreadsSync *)o;
-       
-#ifdef THREAD_LOCK_DEBUG
-       g_message (G_GNUC_PRETTY_FUNCTION ": Finalizing sync");
-#endif
-       
-       CloseHandle (mon->monitor);
-       CloseHandle (mon->sema);
-       CloseHandle (mon->waiters_done);
-       DeleteCriticalSection (&mon->waiters_count_lock);
-}
-
-static MonoThreadsSync *mon_new(void)
-{
-       MonoThreadsSync *new;
-       
-#if HAVE_BOEHM_GC
-       new=(MonoThreadsSync *)GC_MALLOC (sizeof(MonoThreadsSync));
-       GC_REGISTER_FINALIZER (new, mon_finalize, NULL, NULL, NULL);
-#else
-       /* This should be freed when the object that owns it is
-        * deleted
-        */
-       new=(MonoThreadsSync *)g_new0 (MonoThreadsSync, 1);
-#endif
-       
-       new->monitor=CreateMutex(NULL, FALSE, NULL);
-       if(new->monitor==NULL) {
-               /* Throw some sort of system exception? (ditto for the
-                * sem and event handles below)
-                */
-       }
-
-       new->waiters_count=0;
-       new->was_broadcast=FALSE;
-       InitializeCriticalSection(&new->waiters_count_lock);
-       new->sema=CreateSemaphore(NULL, 0, 0x7fffffff, NULL);
-       new->waiters_done=CreateEvent(NULL, FALSE, FALSE, NULL);
-       
-#ifdef THREAD_LOCK_DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION ": (%d) ThreadsSync %p mutex created: %p, sem: %p, event: %p", GetCurrentThreadId (), new, new->monitor, new->sema, new->waiters_done);
-#endif
-       
-       return(new);
-}
-
-gboolean ves_icall_System_Threading_Monitor_Monitor_try_enter(MonoObject *obj,
-                                                             int ms)
-{
-       MonoThreadsSync *mon;
-       guint32 ret;
-       
-       MONO_ARCH_SAVE_REGS;
-
-#ifdef THREAD_LOCK_DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION
-                 ": (%d) Trying to lock object %p", GetCurrentThreadId(),
-                 obj);
-#endif
-
-       EnterCriticalSection(&monitor_mutex);
-
-       mon=obj->synchronisation;
-       if(mon==NULL) {
-               mon=mon_new();
-               obj->synchronisation=mon;
-       }
-       
-       /* Don't hold the monitor lock while waiting to acquire the
-        * object lock
-        */
-       LeaveCriticalSection(&monitor_mutex);
-       
-       /* Acquire the mutex */
-#ifdef THREAD_LOCK_DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Acquiring monitor mutex %p",
-                 GetCurrentThreadId (), mon->monitor);
-#endif
-       ret=WaitForSingleObject(mon->monitor, ms);
-       if(ret==WAIT_OBJECT_0) {
-               mon->count++;
-               mon->tid=GetCurrentThreadId();
-       
-#ifdef THREAD_LOCK_DEBUG
-               g_message(G_GNUC_PRETTY_FUNCTION
-                         ": (%d) object %p now locked %d times",
-                         GetCurrentThreadId (), obj, mon->count);
-#endif
-
-               return(TRUE);
-       }
-
-       return(FALSE);
-}
-
-void ves_icall_System_Threading_Monitor_Monitor_exit(MonoObject *obj)
-{
-       MonoThreadsSync *mon;
-       
-       MONO_ARCH_SAVE_REGS;
-
-#ifdef THREAD_LOCK_DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Unlocking %p",
-                 GetCurrentThreadId (), obj);
-#endif
-
-       /* No need to lock monitor_mutex here because we only adjust
-        * the monitor state if this thread already owns the lock
-        */
-       mon=obj->synchronisation;
-
-       if(mon==NULL) {
-               return;
-       }
-
-       if(mon->tid!=GetCurrentThreadId()) {
-               return;
-       }
-       
-       mon->count--;
-       
-#ifdef THREAD_LOCK_DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION ": (%d) %p now locked %d times",
-                 GetCurrentThreadId (), obj, mon->count);
-#endif
-
-       if(mon->count==0) {
-               mon->tid=0;     /* FIXME: check that 0 isnt a valid id */
-       }
-       
-#ifdef THREAD_LOCK_DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Releasing mutex %p",
-                 GetCurrentThreadId (), mon->monitor);
-#endif
-
-       ReleaseMutex(mon->monitor);
-}
-
-gboolean ves_icall_System_Threading_Monitor_Monitor_test_owner(MonoObject *obj)
-{
-       MonoThreadsSync *mon;
-       gboolean ret=FALSE;
-       
-       MONO_ARCH_SAVE_REGS;
-
-#ifdef THREAD_LOCK_DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION
-                 ": Testing if %p is owned by thread %d", obj,
-                 GetCurrentThreadId());
-#endif
-
-       EnterCriticalSection(&monitor_mutex);
-       
-       mon=obj->synchronisation;
-       if(mon==NULL) {
-               goto finished;
-       }
-
-       if(mon->tid!=GetCurrentThreadId()) {
-#ifdef THREAD_LOCK_DEBUG
-               g_message (G_GNUC_PRETTY_FUNCTION
-                          ": (%d) object %p is owned by thread %d",
-                          GetCurrentThreadId (), obj, mon->tid);
-#endif
-
-               goto finished;
-       }
-       
-       ret=TRUE;
-       
-finished:
-       LeaveCriticalSection(&monitor_mutex);
-
-       return(ret);
-}
-
-gboolean ves_icall_System_Threading_Monitor_Monitor_test_synchronised(MonoObject *obj)
-{
-       MonoThreadsSync *mon;
-       gboolean ret=FALSE;
-       
-       MONO_ARCH_SAVE_REGS;
-
-#ifdef THREAD_LOCK_DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION
-                 ": (%d) Testing if %p is owned by any thread",
-                 GetCurrentThreadId (), obj);
-#endif
-
-       EnterCriticalSection(&monitor_mutex);
-       
-       mon=obj->synchronisation;
-       if(mon==NULL) {
-               goto finished;
-       }
-
-       if(mon->tid==0) {
-               goto finished;
-       }
-       
-       g_assert(mon->count);
-       
-       ret=TRUE;
-       
-finished:
-       LeaveCriticalSection(&monitor_mutex);
-
-       return(ret);
-}
-
-       
-void ves_icall_System_Threading_Monitor_Monitor_pulse(MonoObject *obj)
-{
-       gboolean have_waiters;
-       MonoThreadsSync *mon;
-       
-       MONO_ARCH_SAVE_REGS;
-
-#ifdef THREAD_LOCK_DEBUG
-       g_message("(%d) Pulsing %p", GetCurrentThreadId (), obj);
-#endif
-
-       EnterCriticalSection(&monitor_mutex);
-       
-       mon=obj->synchronisation;
-       if(mon==NULL) {
-               LeaveCriticalSection(&monitor_mutex);
-               return;
-       }
-
-       if(mon->tid!=GetCurrentThreadId()) {
-               LeaveCriticalSection(&monitor_mutex);
-               return;
-       }
-       LeaveCriticalSection(&monitor_mutex);
-       
-       EnterCriticalSection(&mon->waiters_count_lock);
-       have_waiters=(mon->waiters_count>0);
-       LeaveCriticalSection(&mon->waiters_count_lock);
-       
-       if(have_waiters==TRUE) {
-               ReleaseSemaphore(mon->sema, 1, 0);
-       }
-}
-
-void ves_icall_System_Threading_Monitor_Monitor_pulse_all(MonoObject *obj)
-{
-       gboolean have_waiters=FALSE;
-       MonoThreadsSync *mon;
-       
-       MONO_ARCH_SAVE_REGS;
-
-#ifdef THREAD_LOCK_DEBUG
-       g_message("(%d) Pulsing all %p", GetCurrentThreadId (), obj);
-#endif
-
-       EnterCriticalSection(&monitor_mutex);
-       
-       mon=obj->synchronisation;
-       if(mon==NULL) {
-               LeaveCriticalSection(&monitor_mutex);
-               return;
-       }
-
-       if(mon->tid!=GetCurrentThreadId()) {
-               LeaveCriticalSection(&monitor_mutex);
-               return;
-       }
-       LeaveCriticalSection(&monitor_mutex);
-       
-       EnterCriticalSection(&mon->waiters_count_lock);
-       if(mon->waiters_count>0) {
-               mon->was_broadcast=TRUE;
-               have_waiters=TRUE;
-       }
-       
-       if(have_waiters==TRUE) {
-               ReleaseSemaphore(mon->sema, mon->waiters_count, 0);
-               
-               LeaveCriticalSection(&mon->waiters_count_lock);
-               
-               WaitForSingleObject(mon->waiters_done, INFINITE);
-               mon->was_broadcast=FALSE;
-       } else {
-               LeaveCriticalSection(&mon->waiters_count_lock);
-       }
-}
-
-gboolean ves_icall_System_Threading_Monitor_Monitor_wait(MonoObject *obj,
-                                                        int ms)
-{
-       gboolean last_waiter;
-       MonoThreadsSync *mon;
-       guint32 save_count;
-       
-       MONO_ARCH_SAVE_REGS;
-
-#ifdef THREAD_LOCK_DEBUG
-       g_message("(%d) Trying to wait for %p with timeout %dms",
-                 GetCurrentThreadId (), obj, ms);
-#endif
-
-       EnterCriticalSection(&monitor_mutex);
-       
-       mon=obj->synchronisation;
-       if(mon==NULL) {
-               LeaveCriticalSection(&monitor_mutex);
-               return(FALSE);
-       }
-
-       if(mon->tid!=GetCurrentThreadId()) {
-               LeaveCriticalSection(&monitor_mutex);
-               return(FALSE);
-       }
-       LeaveCriticalSection(&monitor_mutex);
-       
-       EnterCriticalSection(&mon->waiters_count_lock);
-       mon->waiters_count++;
-       LeaveCriticalSection(&mon->waiters_count_lock);
-       
-#ifdef THREAD_LOCK_DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION ": (%d) %p locked %d times",
-                 GetCurrentThreadId (), obj, mon->count);
-#endif
-
-       /* We need to put the lock count back afterwards */
-       save_count=mon->count;
-       
-       while(mon->count>1) {
-#ifdef THREAD_LOCK_DEBUG
-               g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Releasing mutex %p",
-                         GetCurrentThreadId (), mon->monitor);
-#endif
-
-               ReleaseMutex(mon->monitor);
-               mon->count--;
-       }
-       
-       /* We're releasing this mutex */
-       mon->count=0;
-       mon->tid=0;
-#ifdef THREAD_LOCK_DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Signalling monitor mutex %p",
-                 GetCurrentThreadId (), mon->monitor);
-#endif
-
-       SignalObjectAndWait(mon->monitor, mon->sema, INFINITE, FALSE);
-       
-       EnterCriticalSection(&mon->waiters_count_lock);
-       mon->waiters_count++;
-       last_waiter=mon->was_broadcast && mon->waiters_count==0;
-       LeaveCriticalSection(&mon->waiters_count_lock);
-       
-       if(last_waiter) {
-#ifdef THREAD_LOCK_DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Waiting for monitor mutex %p",
-                 GetCurrentThreadId (), mon->monitor);
-#endif
-               SignalObjectAndWait(mon->waiters_done, mon->monitor, INFINITE, FALSE);
-       } else {
-#ifdef THREAD_LOCK_DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION ": (%d) Waiting for monitor mutex %p",
-                 GetCurrentThreadId (), mon->monitor);
-#endif
-               WaitForSingleObject(mon->monitor, INFINITE);
-       }
-
-       /* We've reclaimed this mutex */
-       mon->count=save_count;
-       mon->tid=GetCurrentThreadId();
-
-       /* Lock the mutex the required number of times */
-       while(save_count>1) {
-#ifdef THREAD_LOCK_DEBUG
-               g_message(G_GNUC_PRETTY_FUNCTION
-                         ": (%d) Waiting for monitor mutex %p",
-                         GetCurrentThreadId (), mon->monitor);
-#endif
-               WaitForSingleObject(mon->monitor, INFINITE);
-               save_count--;
-       }
-       
-#ifdef THREAD_LOCK_DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION ": (%d) %p still locked %d times",
-                 GetCurrentThreadId (), obj, mon->count);
-#endif
-       
-       return(TRUE);
-}
-
 /* FIXME: exitContext isnt documented */
 gboolean ves_icall_System_Threading_WaitHandle_WaitAll_internal(MonoArray *mono_handles, gint32 ms, gboolean exitContext)
 {
@@ -1153,6 +830,12 @@ ves_icall_System_Threading_Thread_Abort (MonoThread *thread, MonoObject *state)
        thread->abort_state = state;
        thread->abort_exc = mono_get_exception_thread_abort ();
 
+#ifdef THREAD_DEBUG
+       g_message (G_GNUC_PRETTY_FUNCTION
+                  ": (%d) Abort requested for %p (%d)", GetCurrentThreadId (),
+                  thread, thread->tid);
+#endif
+       
 #ifdef __MINGW32__
        g_assert_not_reached ();
 #else
@@ -1181,32 +864,10 @@ ves_icall_System_Threading_Thread_ResetAbort (void)
        }
 }
 
-void mono_thread_init (MonoDomain *domain, MonoThreadStartCB start_cb,
-                      MonoThreadStartCB attach_cb)
+void mono_thread_init (MonoThreadStartCB start_cb,
+                      MonoThreadAttachCB attach_cb)
 {
-       /* Build a System.Threading.Thread object instance to return
-        * for the main line's Thread.CurrentThread property.
-        */
-       
-       /* I wonder what happens if someone tries to destroy this
-        * object? In theory, I guess the whole program should act as
-        * though exit() were called :-)
-        */
-#ifdef THREAD_DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION
-                 ": Starting to build main Thread object");
-#endif
-       main_thread = (MonoThread *)mono_object_new (domain, mono_defaults.thread_class);
-
-       main_thread->handle = GetCurrentThread ();
-
-#ifdef THREAD_DEBUG
-       g_message(G_GNUC_PRETTY_FUNCTION
-                 ": Finished building main Thread object: %p", main_thread);
-#endif
-
        InitializeCriticalSection(&threads_mutex);
-       InitializeCriticalSection(&monitor_mutex);
        InitializeCriticalSection(&interlocked_mutex);
        
        current_object_key=TlsAlloc();
@@ -1215,8 +876,6 @@ void mono_thread_init (MonoDomain *domain, MonoThreadStartCB start_cb,
                   current_object_key);
 #endif
 
-       TlsSetValue(current_object_key, main_thread);
-
        mono_thread_start_cb = start_cb;
        mono_thread_attach_cb = attach_cb;
 
@@ -1230,10 +889,15 @@ void mono_thread_init (MonoDomain *domain, MonoThreadStartCB start_cb,
        GetCurrentProcess ();
 }
 
+void mono_install_thread_callbacks (MonoThreadCallbacks *callbacks)
+{
+       mono_thread_callbacks = callbacks;
+}
+
 #ifdef THREAD_DEBUG
 static void print_tids (gpointer key, gpointer value, gpointer user)
 {
-       g_message ("Waiting for: %d", *(guint32 *)key);
+       g_message ("Waiting for: %d", GPOINTER_TO_UINT(key));
 }
 #endif
 
@@ -1266,7 +930,7 @@ static void wait_for_tids (struct wait_data *wait)
        for(i=0; i<wait->num; i++) {
                guint32 tid=wait->threads[i]->tid;
                
-               if(mono_g_hash_table_lookup (threads, &tid)!=NULL) {
+               if(mono_g_hash_table_lookup (threads, GUINT_TO_POINTER(tid))!=NULL) {
                        /* This thread must have been killed, because
                         * it hasn't cleaned itself up. (It's just
                         * possible that the thread exited before the
@@ -1282,7 +946,7 @@ static void wait_for_tids (struct wait_data *wait)
                        g_message (G_GNUC_PRETTY_FUNCTION
                                   ": cleaning up after thread %d", tid);
 #endif
-                       thread_cleanup (tid);
+                       thread_cleanup (wait->threads[i]);
                }
        }
 }
@@ -1293,14 +957,12 @@ static void build_wait_tids (gpointer key, gpointer value, gpointer user)
 
        if(wait->num<MAXIMUM_WAIT_OBJECTS) {
                MonoThread *thread=(MonoThread *)value;
+
+               /* BUG: For now we just ignore background threads, we should abort them
+               */
+               if (thread->state & ThreadState_Background)
+                       return; /* just leave, ignore */
                
-               /* Theres a theoretical chance that thread->handle
-                * might be NULL if the child thread has called
-                * handle_store() but the parent thread hasn't set the
-                * handle pointer yet.  WaitForMultipleObjects will
-                * fail, and we'll just go round the loop again.  By
-                * that time the handle should be stored properly.
-                */
                wait->handles[wait->num]=thread->handle;
                wait->threads[wait->num]=thread;
                wait->num++;
@@ -1311,7 +973,7 @@ static void build_wait_tids (gpointer key, gpointer value, gpointer user)
        }
 }
 
-void mono_thread_cleanup(void)
+void mono_thread_manage (void)
 {
        struct wait_data *wait=g_new0 (struct wait_data, 1);
        
@@ -1351,3 +1013,243 @@ void mono_thread_cleanup(void)
        mono_g_hash_table_destroy(threads);
        threads=NULL;
 }
+
+static void terminate_thread (gpointer key, gpointer value, gpointer user)
+{
+       MonoThread *thread=(MonoThread *)value;
+       guint32 self=GPOINTER_TO_UINT (user);
+       
+       if(thread->tid!=self) {
+               /*TerminateThread (thread->handle, -1);*/
+       }
+}
+
+void mono_thread_abort_all_other_threads (void)
+{
+       guint32 self=GetCurrentThreadId ();
+
+       EnterCriticalSection (&threads_mutex);
+#ifdef THREAD_DEBUG
+       g_message(G_GNUC_PRETTY_FUNCTION ":There are %d threads to abort",
+                 mono_g_hash_table_size (threads));
+       mono_g_hash_table_foreach (threads, print_tids, NULL);
+#endif
+
+       mono_g_hash_table_foreach (threads, terminate_thread,
+                                  GUINT_TO_POINTER (self));
+       
+       LeaveCriticalSection (&threads_mutex);
+}
+
+static int static_data_idx = 0;
+static int static_data_offset = 0;
+#define NUM_STATIC_DATA_IDX 8
+static const int static_data_size [NUM_STATIC_DATA_IDX] = {
+       1024, 4096, 16384, 65536, 262144, 1048576, 4194304, 16777216
+};
+
+static void 
+thread_alloc_static_data (MonoThread *thread, guint32 offset)
+{
+       guint idx = (offset >> 24) - 1;
+       int i;
+
+       if (!thread->static_data) {
+               thread->static_data = GC_MALLOC (static_data_size [0]);
+               thread->static_data [0] = thread->static_data;
+       }
+       for (i = 1; i < idx; ++i) {
+               if (thread->static_data [i])
+                       continue;
+               thread->static_data [i] = GC_MALLOC (static_data_size [i]);
+       }
+       
+}
+
+/* 
+ * ensure thread static fields already allocated are valid for thread
+ * This function is called when a thread is created or on thread attach.
+ */
+static void
+thread_adjust_static_data (MonoThread *thread)
+{
+       guint32 offset;
+
+       EnterCriticalSection (&threads_mutex);
+       if (static_data_offset || static_data_idx > 0) {
+               /* get the current allocated size */
+               offset = static_data_offset | ((static_data_idx + 1) << 24);
+               thread_alloc_static_data (thread, offset);
+       }
+       LeaveCriticalSection (&threads_mutex);
+}
+
+static void 
+alloc_thread_static_data_helper (gpointer key, gpointer value, gpointer user)
+{
+       MonoThread *thread = value;
+       guint32 offset = GPOINTER_TO_UINT (user);
+       
+       thread_alloc_static_data (thread, offset);
+}
+
+/*
+ * The offset for a thread static variable is composed of two parts:
+ * an index in the array of chunks of memory for the thread (thread->static_data)
+ * and an offset in that chunk of mem. This allows allocating less memory in the 
+ * common case.
+ */
+guint32
+mono_threads_alloc_static_data (guint32 size, guint32 align)
+{
+       guint32 offset;
+       
+       EnterCriticalSection (&threads_mutex);
+
+       if (!static_data_idx && !static_data_offset) {
+               /* 
+                * we use the first chunk of the first allocation also as
+                * an array for the rest of the data 
+                */
+               static_data_offset = sizeof (gpointer) * NUM_STATIC_DATA_IDX;
+       }
+       static_data_offset += align - 1;
+       static_data_offset &= ~(align - 1);
+       if (static_data_offset + size >= static_data_size [static_data_idx]) {
+               static_data_idx ++;
+               g_assert (size <= static_data_size [static_data_idx]);
+               /* 
+                * massive unloading and reloading of domains with thread-static
+                * data may eventually exceed the allocated storage...
+                * Need to check what the MS runtime does in that case.
+                * Note that for each appdomain, we need to allocate a separate
+                * thread data slot for security reasons. We could keep track
+                * of the slots per-domain and when the domain is unloaded
+                * out the slots on a sort of free list.
+                */
+               g_assert (static_data_idx < NUM_STATIC_DATA_IDX);
+               static_data_offset = 0;
+       }
+       offset = static_data_offset | ((static_data_idx + 1) << 24);
+       static_data_offset += size;
+       
+       mono_g_hash_table_foreach (threads, alloc_thread_static_data_helper, GUINT_TO_POINTER (offset));
+
+       LeaveCriticalSection (&threads_mutex);
+       return offset;
+}
+
+gpointer
+mono_threads_get_static_data (guint32 offset)
+{
+       MonoThread *thread = mono_thread_current ();
+       int idx = offset >> 24;
+       
+       return ((char*) thread->static_data [idx - 1]) + (offset & 0xffffff);
+}
+
+#ifdef WITH_INCLUDED_LIBGC
+
+static void gc_stop_world (gpointer key, gpointer value, gpointer user)
+{
+       MonoThread *thread=(MonoThread *)value;
+       guint32 self=GPOINTER_TO_UINT (user);
+
+#ifdef LIBGC_DEBUG
+       g_message (G_GNUC_PRETTY_FUNCTION ": %d - %d", self, thread->tid);
+#endif
+       
+       if(thread->tid==self)
+               return;
+
+       SuspendThread (thread->handle);
+}
+
+void mono_gc_stop_world (void)
+{
+       guint32 self=GetCurrentThreadId ();
+
+#ifdef LIBGC_DEBUG
+       g_message (G_GNUC_PRETTY_FUNCTION ": %d - %p", self, threads);
+#endif
+
+       EnterCriticalSection (&threads_mutex);
+
+       if (threads != NULL)
+               mono_g_hash_table_foreach (threads, gc_stop_world, GUINT_TO_POINTER (self));
+       
+       LeaveCriticalSection (&threads_mutex);
+}
+
+static void gc_start_world (gpointer key, gpointer value, gpointer user)
+{
+       MonoThread *thread=(MonoThread *)value;
+       guint32 self=GPOINTER_TO_UINT (user);
+       
+#ifdef LIBGC_DEBUG
+       g_message (G_GNUC_PRETTY_FUNCTION ": %d - %d", self, thread->tid);
+#endif
+       
+       if(thread->tid==self)
+               return;
+
+       ResumeThread (thread->handle);
+}
+
+void mono_gc_start_world (void)
+{
+       guint32 self=GetCurrentThreadId ();
+
+#ifdef LIBGC_DEBUG
+       g_message (G_GNUC_PRETTY_FUNCTION ": %d - %p", self, threads);
+#endif
+
+       EnterCriticalSection (&threads_mutex);
+
+       if (threads != NULL)
+               mono_g_hash_table_foreach (threads, gc_start_world, GUINT_TO_POINTER (self));
+       
+       LeaveCriticalSection (&threads_mutex);
+}
+
+static void gc_push_all_stacks (gpointer key, gpointer value, gpointer user)
+{
+       MonoThread *thread=(MonoThread *)value;
+       guint32 *selfp=(guint32 *)user, self = *selfp;
+
+#ifdef LIBGC_DEBUG
+       g_message (G_GNUC_PRETTY_FUNCTION ": %d - %d - %p", self, thread->tid, thread->stack_ptr);
+#endif
+       
+       if(thread->tid==self) {
+#ifdef LIBGC_DEBUG
+               g_message (G_GNUC_PRETTY_FUNCTION ": %p - %p", selfp, thread->stack_ptr);
+#endif
+               GC_push_all_stack (selfp, thread->stack_ptr);
+               return;
+       }
+
+#ifdef PLATFORM_WIN32
+       GC_win32_push_thread_stack (thread->handle, thread->stack_ptr);
+#else
+       mono_wapi_push_thread_stack (thread->handle, thread->stack_ptr);
+#endif
+}
+
+void mono_gc_push_all_stacks (void)
+{
+       guint32 self=GetCurrentThreadId ();
+
+#ifdef LIBGC_DEBUG
+       g_message (G_GNUC_PRETTY_FUNCTION ": %d - %p", self, threads);
+#endif
+
+       EnterCriticalSection (&threads_mutex);
+
+       if (threads != NULL)
+               mono_g_hash_table_foreach (threads, gc_push_all_stacks, &self);
+       
+       LeaveCriticalSection (&threads_mutex);
+}
+
+#endif /* WITH_INCLUDED_LIBGC */