[xbuild] Update man page with info about FrameworkList.xml
[mono.git] / libgc / pthread_support.c
index ecb07ffd4e2d92f16c4fd62f936993c9f39fc6ee..3e588ace211abdcd0ed62b104f94f2a57d8b336b 100644 (file)
@@ -67,8 +67,9 @@
 # endif
 
 # if (defined(GC_DGUX386_THREADS) || defined(GC_OSF1_THREADS) || \
-      defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)) \
-      && !defined(USE_PTHREAD_SPECIFIC)
+      defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)) || \
+      defined(GC_NETBSD_THREADS) && !defined(USE_PTHREAD_SPECIFIC) || \
+      defined(GC_OPENBSD_THREADS)
 #   define USE_PTHREAD_SPECIFIC
 # endif
 
       typedef pthread_key_t GC_key_t;
 #   endif
 #   if defined(USE_COMPILER_TLS)
+/* Note sles9 gcc on powerpc gets confused by the define to set GC_thread_tls and pthread_setspecific
+ * so we actually use a static inline function decalred below that is equivalent to:
+ *   define GC_setspecific(key, v) (GC_thread_tls = (v), pthread_setspecific ((key), (v)))
+ */
 #     define GC_getspecific(x) (GC_thread_tls)
-#     define GC_setspecific(key, v) (GC_thread_tls = (v), pthread_setspecific ((key), (v)))
 #     define GC_key_create pthread_key_create
       typedef pthread_key_t GC_key_t;
 #   endif
 # include <sys/sysctl.h>
 #endif /* GC_DARWIN_THREADS */
 
+#if defined(GC_NETBSD_THREADS) || defined(GC_OPENBSD_THREADS)
+# include <sys/param.h>
+# include <sys/sysctl.h>
+#endif
+
 
 
 #if defined(GC_DGUX386_THREADS)
 #   endif
 #   undef pthread_join
 #   undef pthread_detach
+#   if defined(NACL)
+#     undef pthread_exit
+#   endif
 #   if defined(GC_OSF1_THREADS) && defined(_PTHREAD_USE_MANGLED_NAMES_) \
        && !defined(_PTHREAD_USE_PTDNAM_)
 /* Restore the original mangled names on Tru64 UNIX.  */
@@ -186,7 +198,19 @@ static
 GC_key_t GC_thread_key;
 
 #ifdef USE_COMPILER_TLS
-static __thread MONO_TLS_FAST void* GC_thread_tls;
+__thread MONO_TLS_FAST void* GC_thread_tls;
+
+/*
+ * gcc errors out with /tmp/ccdPMFuq.s:2994: Error: symbol `.LTLS4' is already defined
+ * if the inline is added on powerpc
+ */
+#if !defined(__ppc__) && !defined(__powerpc__)
+inline
+#endif
+static int GC_setspecific (GC_key_t key, void *value) {
+       GC_thread_tls = value;
+       return pthread_setspecific (key, value);
+}
 #endif
 
 static GC_bool keys_initialized;
@@ -655,6 +679,52 @@ void GC_mark_thread_local_free_lists(void)
 
 static struct GC_Thread_Rep first_thread;
 
+#ifdef NACL
+extern int nacl_thread_parked[MAX_NACL_GC_THREADS];
+extern int nacl_thread_used[MAX_NACL_GC_THREADS];
+extern int nacl_thread_parking_inited;
+extern int nacl_num_gc_threads;
+extern pthread_mutex_t nacl_thread_alloc_lock;
+extern __thread int nacl_thread_idx;
+extern __thread GC_thread nacl_gc_thread_self;
+
+void nacl_initialize_gc_thread()
+{
+    int i;
+    pthread_mutex_lock(&nacl_thread_alloc_lock);
+    if (!nacl_thread_parking_inited)
+    {
+        for (i = 0; i < MAX_NACL_GC_THREADS; i++) {
+            nacl_thread_used[i] = 0;
+            nacl_thread_parked[i] = 0;
+        }
+        nacl_thread_parking_inited = 1;
+    }
+    GC_ASSERT(nacl_num_gc_threads <= MAX_NACL_GC_THREADS);
+    for (i = 0; i < MAX_NACL_GC_THREADS; i++) {
+        if (nacl_thread_used[i] == 0) {
+            nacl_thread_used[i] = 1;
+            nacl_thread_idx = i;
+            nacl_num_gc_threads++;
+            break;
+        }
+    }
+    pthread_mutex_unlock(&nacl_thread_alloc_lock);
+}
+
+void nacl_shutdown_gc_thread()
+{
+    pthread_mutex_lock(&nacl_thread_alloc_lock);
+    GC_ASSERT(nacl_thread_idx >= 0 && nacl_thread_idx < MAX_NACL_GC_THREADS);
+    GC_ASSERT(nacl_thread_used[nacl_thread_idx] != 0);
+    nacl_thread_used[nacl_thread_idx] = 0;
+    nacl_thread_idx = -1;
+    nacl_num_gc_threads--;
+    pthread_mutex_unlock(&nacl_thread_alloc_lock);
+}
+
+#endif /* NACL */
+
 /* Add a thread to GC_threads.  We assume it wasn't already there.     */
 /* Caller holds allocation lock.                                       */
 GC_thread GC_new_thread(pthread_t id)
@@ -667,12 +737,20 @@ GC_thread GC_new_thread(pthread_t id)
        result = &first_thread;
        first_thread_used = TRUE;
     } else {
-       result = calloc (1, sizeof (struct GC_Thread_Rep));
+        result = (struct GC_Thread_Rep *)
+                GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL);
     }
     if (result == 0) return(0);
     result -> id = id;
+#ifdef PLATFORM_ANDROID
+    result -> kernel_id = gettid();
+#endif
     result -> next = GC_threads[hv];
     GC_threads[hv] = result;
+#ifdef NACL
+    nacl_gc_thread_self = result;
+    nacl_initialize_gc_thread();
+#endif
     GC_ASSERT(result -> flags == 0 && result -> thread_blocked == 0);
     return(result);
 }
@@ -686,6 +764,11 @@ void GC_delete_thread(pthread_t id)
     register GC_thread p = GC_threads[hv];
     register GC_thread prev = 0;
     
+#ifdef NACL
+    nacl_shutdown_gc_thread();
+    nacl_gc_thread_self = NULL;
+#endif
+
     while (!pthread_equal(p -> id, id)) {
         prev = p;
         p = p -> next;
@@ -699,7 +782,12 @@ void GC_delete_thread(pthread_t id)
     if (gc_thread_vtable && gc_thread_vtable->thread_exited)
        gc_thread_vtable->thread_exited (id, &p->stop_info.stack_ptr);
 #endif
-    free(p);
+       
+#ifdef GC_DARWIN_THREADS
+       mach_port_deallocate(mach_task_self(), p->stop_info.mach_thread);
+#endif
+       
+    GC_INTERNAL_FREE(p);
 }
 
 /* If a thread has been joined, but we have not yet            */
@@ -721,7 +809,12 @@ void GC_delete_gc_thread(pthread_t id, GC_thread gc_id)
     } else {
         prev -> next = p -> next;
     }
-    free(p);
+       
+#ifdef GC_DARWIN_THREADS
+       mach_port_deallocate(mach_task_self(), p->stop_info.mach_thread);
+#endif
+       
+    GC_INTERNAL_FREE(p);
 }
 
 /* Return a GC_thread corresponding to a given pthread_t.      */
@@ -774,11 +867,12 @@ void GC_remove_all_threads_but_me(void)
              GC_destroy_thread_local(p);
            }
 #        endif /* THREAD_LOCAL_ALLOC */
-           if (p != &first_thread) free(p);
+           if (p != &first_thread) GC_INTERNAL_FREE(p);
        }
       }
       GC_threads[hv] = me;
     }
+    GC_INTERNAL_FREE(p);
 }
 #endif /* HANDLE_FORK */
 
@@ -978,7 +1072,11 @@ void GC_thr_init()
       t -> flags = DETACHED | MAIN_THREAD;
 #ifdef MONO_DEBUGGER_SUPPORTED
       if (gc_thread_vtable && gc_thread_vtable->thread_created)
-        gc_thread_vtable->thread_created (pthread_self (), &t->stop_info.stack_ptr);
+#     ifdef GC_DARWIN_THREADS
+        gc_thread_vtable->thread_created (mach_thread_self (), &t->stop_info.stack_ptr);
+#     else
+         gc_thread_vtable->thread_created (pthread_self (), &t->stop_info.stack_ptr);
+#     endif
 #endif
 
     GC_stop_init();
@@ -1001,7 +1099,7 @@ void GC_thr_init()
          GC_nprocs = sysconf(_SC_NPROC_ONLN);
          if (GC_nprocs <= 0) GC_nprocs = 1;
 #       endif
-#       if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS)
+#       if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS) || defined(GC_NETBSD_THREADS) || defined(GC_OPENBSD_THREADS)
          int ncpus = 1;
          size_t len = sizeof(ncpus);
          sysctl((int[2]) {CTL_HW, HW_NCPU}, 2, &ncpus, &len, NULL, 0);
@@ -1025,6 +1123,8 @@ void GC_thr_init()
              GC_markers = atoi(markers_string);
            } else {
              GC_markers = GC_nprocs;
+                 if (GC_markers > MAX_MARKERS)
+                         GC_markers = MAX_MARKERS;
            }
           }
 #      endif
@@ -1075,7 +1175,8 @@ void GC_init_parallel()
 }
 
 
-#if !defined(GC_DARWIN_THREADS)
+#if !defined(GC_DARWIN_THREADS) && !defined(GC_OPENBSD_THREADS)
+#ifndef NACL
 int WRAP_FUNC(pthread_sigmask)(int how, const sigset_t *set, sigset_t *oset)
 {
     sigset_t fudged_set;
@@ -1087,6 +1188,7 @@ int WRAP_FUNC(pthread_sigmask)(int how, const sigset_t *set, sigset_t *oset)
     }
     return(REAL_FUNC(pthread_sigmask)(how, set, oset));
 }
+#endif
 #endif /* !GC_DARWIN_THREADS */
 
 /* Wrappers for functions that are likely to block for an appreciable  */
@@ -1168,6 +1270,11 @@ void GC_thread_exit_proc(void *arg)
     me = GC_lookup_thread(pthread_self());
     GC_destroy_thread_local(me);
     if (me -> flags & DETACHED) {
+# ifdef THREAD_LOCAL_ALLOC
+               /* NULL out the tls key to prevent the dtor function from being called */
+               if (0 != GC_setspecific(GC_thread_key, NULL))
+                       ABORT("Failed to set thread specific allocation pointers");
+#endif
        GC_delete_thread(pthread_self());
     } else {
        me -> flags |= FINISHED;
@@ -1212,6 +1319,17 @@ int WRAP_FUNC(pthread_join)(pthread_t thread, void **retval)
     return result;
 }
 
+#ifdef NACL
+/* Native Client doesn't support pthread cleanup functions, */
+/* so wrap pthread_exit and manually cleanup the thread.    */
+void
+WRAP_FUNC(pthread_exit)(void *status)
+{
+    GC_thread_exit_proc(0); 
+    REAL_FUNC(pthread_exit)(status);
+}
+#endif
+
 int
 WRAP_FUNC(pthread_detach)(pthread_t thread)
 {
@@ -1287,14 +1405,19 @@ void * GC_start_routine_head(void * arg, void *base_addr,
 #   endif /* IA64 */
 #ifdef MONO_DEBUGGER_SUPPORTED
     if (gc_thread_vtable && gc_thread_vtable->thread_created)
-       gc_thread_vtable->thread_created (my_pthread, &me->stop_info.stack_ptr);
+#      ifdef GC_DARWIN_THREADS
+       gc_thread_vtable->thread_created (mach_thread_self(), &me->stop_info.stack_ptr);
+#      else
+       gc_thread_vtable->thread_created (my_pthread, &me->stop_info.stack_ptr);
+#      endif
 #endif
     UNLOCK();
 
     if (start) *start = si -> start_routine;
     if (start_arg) *start_arg = si -> arg;
 
-    sem_post(&(si -> registered));     /* Last action on si.   */
+       if (!(si->flags & FOREIGN_THREAD))
+               sem_post(&(si -> registered));  /* Last action on si.   */
                                        /* OK to deallocate.    */
 #   if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
        LOCK();
@@ -1371,7 +1494,8 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread,
     /* responsibility.                                                 */
 
     LOCK();
-    si = calloc (1, sizeof (struct start_info));
+    si = (struct start_info *)GC_INTERNAL_MALLOC(sizeof(struct start_info),
+                                                NORMAL);
     UNLOCK();
     if (!parallel_initialized) GC_init_parallel();
     if (0 == si) return(ENOMEM);
@@ -1431,7 +1555,7 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread,
     }
     sem_destroy(&(si -> registered));
     LOCK();
-    free(si);
+    GC_INTERNAL_FREE(si);
     UNLOCK();
 
     return(result);