X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=libgc%2Fpthread_support.c;h=58a662e773be9cd2bc16c2075e925f3a9dc1f4fb;hb=bd78760dffe1a99944b21194d18c10291ba33b02;hp=8b47b4d3db8666db8a7a2b47b3c3e9bf6e8ef9f9;hpb=234225d112c4b018b8d1796f4c06a15812137500;p=mono.git diff --git a/libgc/pthread_support.c b/libgc/pthread_support.c index 8b47b4d3db8..58a662e773b 100644 --- a/libgc/pthread_support.c +++ b/libgc/pthread_support.c @@ -2,7 +2,7 @@ * Copyright (c) 1994 by Xerox Corporation. All rights reserved. * Copyright (c) 1996 by Silicon Graphics. All rights reserved. * Copyright (c) 1998 by Fergus Henderson. All rights reserved. - * Copyright (c) 2000-2001 by Hewlett-Packard Company. All rights reserved. + * Copyright (c) 2000-2004 by Hewlett-Packard Company. All rights reserved. * * THIS MATERIAL IS PROVIDED AS IS, WITH ABSOLUTELY NO WARRANTY EXPRESSED * OR IMPLIED. ANY USE IS AT YOUR OWN RISK. @@ -50,8 +50,7 @@ # include "private/pthread_support.h" # if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \ - && !defined(GC_IRIX_THREADS) && !defined(GC_WIN32_THREADS) \ - && !defined(GC_AIX_THREADS) + && !defined(GC_WIN32_THREADS) # if defined(GC_HPUX_THREADS) && !defined(USE_PTHREAD_SPECIFIC) \ && !defined(USE_COMPILER_TLS) @@ -68,7 +67,8 @@ # endif # if (defined(GC_DGUX386_THREADS) || defined(GC_OSF1_THREADS) || \ - defined(GC_DARWIN_THREADS)) && !defined(USE_PTHREAD_SPECIFIC) + defined(GC_DARWIN_THREADS) || defined(GC_AIX_THREADS)) \ + && !defined(USE_PTHREAD_SPECIFIC) # define USE_PTHREAD_SPECIFIC # endif @@ -84,6 +84,12 @@ # if !defined(USE_PTHREAD_SPECIFIC) && !defined(USE_COMPILER_TLS) # include "private/specific.h" # endif + +/* Note that these macros should be used only to get/set the GC_thread pointer. + * We need to use both tls and pthread because we use the pthread_create function hook to + * free the data for foreign threads. When that doesn't happen, libgc could have old + * pthread_t that get reused... + */ # if defined(USE_PTHREAD_SPECIFIC) # define GC_getspecific pthread_getspecific # define GC_setspecific pthread_setspecific @@ -91,10 +97,10 @@ typedef pthread_key_t GC_key_t; # endif # if defined(USE_COMPILER_TLS) -# define GC_getspecific(x) (x) -# define GC_setspecific(key, v) ((key) = (v), 0) -# define GC_key_create(key, d) 0 - typedef void * GC_key_t; +# 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 # endif # include @@ -116,7 +122,7 @@ # include #endif /* !GC_DARWIN_THREADS */ -#if defined(GC_DARWIN_THREADS) +#if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS) # include #endif /* GC_DARWIN_THREADS */ @@ -168,11 +174,20 @@ 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 +GC_key_t GC_thread_key; + #ifdef USE_COMPILER_TLS - __thread +static __thread MONO_TLS_FAST void* GC_thread_tls; #endif -GC_key_t GC_thread_key; static GC_bool keys_initialized; @@ -213,6 +228,24 @@ 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_gc_thread(pthread_t id, GC_thread gct); +void GC_destroy_thread_local(GC_thread p); + +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" ); */ +#if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL) + GC_destroy_thread_local (me); +#endif + GC_delete_gc_thread(me->id, me); + UNLOCK(); + } +} + /* Each thread structure must be initialized. */ /* This call must be made from the new thread. */ /* Caller holds allocation lock. */ @@ -221,7 +254,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 +589,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 +619,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 */ @@ -892,9 +948,9 @@ int GC_get_nprocs() /* We hold the allocation lock. */ void GC_thr_init() { -# ifndef GC_DARWIN_THREADS - int dummy; -# endif +# ifndef GC_DARWIN_THREADS + int dummy; +# endif GC_thread t; if (GC_thr_initialized) return; @@ -926,14 +982,15 @@ void GC_thr_init() # if defined(GC_HPUX_THREADS) GC_nprocs = pthread_num_processors_np(); # endif -# if defined(GC_OSF1_THREADS) +# if defined(GC_OSF1_THREADS) || defined(GC_AIX_THREADS) GC_nprocs = sysconf(_SC_NPROCESSORS_ONLN); if (GC_nprocs <= 0) GC_nprocs = 1; # endif -# if defined(GC_FREEBSD_THREADS) - GC_nprocs = 1; +# if defined(GC_IRIX_THREADS) + GC_nprocs = sysconf(_SC_NPROC_ONLN); + if (GC_nprocs <= 0) GC_nprocs = 1; # endif -# if defined(GC_DARWIN_THREADS) +# if defined(GC_DARWIN_THREADS) || defined(GC_FREEBSD_THREADS) int ncpus = 1; size_t len = sizeof(ncpus); sysctl((int[2]) {CTL_HW, HW_NCPU}, 2, &ncpus, &len, NULL, 0); @@ -980,6 +1037,8 @@ void GC_thr_init() /* Disable true incremental collection, but generational is OK. */ GC_time_limit = GC_TIME_UNLIMITED; } + /* If we are using a parallel marker, actually start helper threads. */ + if (GC_parallel) start_mark_threads(); # endif } @@ -996,10 +1055,6 @@ void GC_init_parallel() /* GC_init() calls us back, so set flag first. */ if (!GC_is_initialized) GC_init(); - /* If we are using a parallel marker, start the helper threads. */ -# ifdef PARALLEL_MARK - if (GC_parallel) start_mark_threads(); -# endif /* Initialize thread local free lists if used. */ # if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL) LOCK(); @@ -1170,15 +1225,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 +1255,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 +1263,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 +1275,58 @@ 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; + +# ifdef DEBUG_THREADS + GC_printf1( "GC_thread_register_foreign %p\n", &si ); +# endif + + 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()); @@ -1275,7 +1368,7 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread, if (!GC_thr_initialized) GC_thr_init(); # ifdef GC_ASSERTIONS { - int stack_size; + size_t stack_size; if (NULL == attr) { pthread_attr_t my_attr; pthread_attr_init(&my_attr); @@ -1283,7 +1376,13 @@ WRAP_FUNC(pthread_create)(pthread_t *new_thread, } else { pthread_attr_getstacksize(attr, &stack_size); } - GC_ASSERT(stack_size >= (8*HBLKSIZE*sizeof(word))); +# ifdef PARALLEL_MARK + GC_ASSERT(stack_size >= (8*HBLKSIZE*sizeof(word))); +# else + /* FreeBSD-5.3/Alpha: default pthread stack is 64K, */ + /* HBLKSIZE=8192, sizeof(word)=8 */ + GC_ASSERT(stack_size >= 65536); +# endif /* Our threads may need to do some work for the GC. */ /* Ridiculously small threads won't work, and they */ /* probably wouldn't work anyway. */