* Form.cs: If the child form has no menu the default main menu is
[mono.git] / libgc / pthread_support.c
index 8b47b4d3db8666db8a7a2b47b3c3e9bf6e8ef9f9..9def3e117cb6c954660de365d52b014ba1c35b55 100644 (file)
@@ -168,9 +168,17 @@ void GC_init_parallel();
 
 /* We don't really support thread-local allocation with DBG_HDRS_ALL */
 
+/* work around a dlopen issue (bug #75390), undefs to avoid warnings with redefinitions */
+#undef PACKAGE_BUGREPORT
+#undef PACKAGE_NAME
+#undef PACKAGE_STRING
+#undef PACKAGE_TARNAME
+#undef PACKAGE_VERSION
+#include "mono/utils/mono-compiler.h"
+
 static
 #ifdef USE_COMPILER_TLS
-  __thread
+  __thread MONO_TLS_FAST
 #endif
 GC_key_t GC_thread_key;
 
@@ -213,6 +221,20 @@ static void return_freelists(ptr_t *fl, ptr_t *gfl)
 /* we arrange for those to fault asap.)                                        */
 static ptr_t size_zero_object = (ptr_t)(&size_zero_object);
 
+void GC_delete_thread(pthread_t id);
+
+void GC_thread_deregister_foreign (void *data)
+{
+    GC_thread me = (GC_thread)data;
+ /*   GC_fprintf1( "\n\n\n\n --- Deregister %x ---\n\n\n\n\n", me->flags ); */
+    if (me -> flags & FOREIGN_THREAD) {
+       LOCK();
+ /*    GC_fprintf0( "\n\n\n\n --- FOO ---\n\n\n\n\n" ); */
+       GC_delete_thread(me->id);
+       UNLOCK();
+    }
+}
+
 /* Each thread structure must be initialized.  */
 /* This call must be made from the new thread. */
 /* Caller holds allocation lock.               */
@@ -221,7 +243,7 @@ void GC_init_thread_local(GC_thread p)
     int i;
 
     if (!keys_initialized) {
-       if (0 != GC_key_create(&GC_thread_key, 0)) {
+       if (0 != GC_key_create(&GC_thread_key, GC_thread_deregister_foreign)) {
            ABORT("Failed to create key for local allocator");
         }
        keys_initialized = TRUE;
@@ -556,6 +578,27 @@ GC_bool GC_thr_initialized = FALSE;
 
 volatile GC_thread GC_threads[THREAD_TABLE_SZ];
 
+/* 
+ * gcc-3.3.6 miscompiles the &GC_thread_key+sizeof(&GC_thread_key) expression so
+ * put it into a separate function.
+ */
+#   if defined(__GNUC__) && defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
+static __attribute__((noinline)) unsigned char* get_gc_thread_key_addr GC_PROTO((void))
+{
+       return (unsigned char*)&GC_thread_key;
+}
+
+void GC_push_thread_structures GC_PROTO((void))
+{
+    GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
+#   if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
+      GC_push_all((ptr_t)get_gc_thread_key_addr(),
+         (ptr_t)(get_gc_thread_key_addr())+sizeof(&GC_thread_key));
+#   endif
+}
+
+#else
+
 void GC_push_thread_structures GC_PROTO((void))
 {
     GC_push_all((ptr_t)(GC_threads), (ptr_t)(GC_threads)+sizeof(GC_threads));
@@ -565,6 +608,8 @@ void GC_push_thread_structures GC_PROTO((void))
 #   endif
 }
 
+#endif
+
 #ifdef THREAD_LOCAL_ALLOC
 /* We must explicitly mark ptrfree and gcj free lists, since the free  */
 /* list links wouldn't otherwise be found.  We also set them in the    */
@@ -1170,15 +1215,14 @@ WRAP_FUNC(pthread_detach)(pthread_t thread)
 
 GC_bool GC_in_thread_creation = FALSE;
 
-void * GC_start_routine(void * arg)
+typedef void *(*ThreadStartFn)(void *);
+void * GC_start_routine_head(void * arg, void *base_addr,
+                            ThreadStartFn *start, void **start_arg )
 {
-    int dummy;
     struct start_info * si = arg;
     void * result;
     GC_thread me;
     pthread_t my_pthread;
-    void *(*start)(void *);
-    void *start_arg;
 
     my_pthread = pthread_self();
 #   ifdef DEBUG_THREADS
@@ -1201,7 +1245,7 @@ void * GC_start_routine(void * arg)
     /* one for the main thread.  There is a strong argument that that's        */
     /* a kernel bug, but a pervasive one.                              */
 #   ifdef STACK_GROWS_DOWN
-      me -> stack_end = (ptr_t)(((word)(&dummy) + (GC_page_size - 1))
+      me -> stack_end = (ptr_t)(((word)(base_addr) + (GC_page_size - 1))
                                & ~(GC_page_size - 1));
 #        ifndef GC_DARWIN_THREADS
         me -> stop_info.stack_ptr = me -> stack_end - 0x10;
@@ -1209,7 +1253,7 @@ void * GC_start_routine(void * arg)
        /* Needs to be plausible, since an asynchronous stack mark      */
        /* should not crash.                                            */
 #   else
-      me -> stack_end = (ptr_t)((word)(&dummy) & ~(GC_page_size - 1));
+      me -> stack_end = (ptr_t)((word)(base_addr) & ~(GC_page_size - 1));
       me -> stop_info.stack_ptr = me -> stack_end + 0x10;
 #   endif
     /* This is dubious, since we may be more than a page into the stack, */
@@ -1221,19 +1265,56 @@ void * GC_start_routine(void * arg)
       /* from /proc, but the hook to do so isn't there yet.            */
 #   endif /* IA64 */
     UNLOCK();
-    start = si -> start_routine;
-#   ifdef DEBUG_THREADS
-       GC_printf1("start_routine = 0x%lx\n", start);
-#   endif
-    start_arg = si -> arg;
+
+    if (start) *start = si -> start_routine;
+    if (start_arg) *start_arg = si -> arg;
+
     sem_post(&(si -> registered));     /* Last action on si.   */
                                        /* OK to deallocate.    */
-    pthread_cleanup_push(GC_thread_exit_proc, 0);
 #   if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
        LOCK();
         GC_init_thread_local(me);
        UNLOCK();
 #   endif
+
+    return me;
+}
+
+int GC_thread_register_foreign (void *base_addr)
+{
+    struct start_info si = { 0, }; /* stacked for legibility & locking */
+    GC_thread me;
+
+    GC_printf1( "GC_thread_register_foreign %p\n", &si );
+
+    si.flags = FOREIGN_THREAD;
+
+    if (!parallel_initialized) GC_init_parallel();
+    LOCK();
+    if (!GC_thr_initialized) GC_thr_init();
+
+    UNLOCK();
+
+    me = GC_start_routine_head(&si, base_addr, NULL, NULL);
+
+    return me != NULL;
+}
+
+void * GC_start_routine(void * arg)
+{
+    int dummy;
+    struct start_info * si = arg;
+    void * result;
+    GC_thread me;
+    ThreadStartFn start;
+    void *start_arg;
+
+    me = GC_start_routine_head (arg, &dummy, &start, &start_arg);
+
+    pthread_cleanup_push(GC_thread_exit_proc, 0);
+#   ifdef DEBUG_THREADS
+       GC_printf1("start_routine = 0x%lx\n", start);
+#   endif
     result = (*start)(start_arg);
 #if DEBUG_THREADS
         GC_printf1("Finishing thread 0x%x\n", pthread_self());