From: hboehm Date: Thu, 24 May 2007 05:18:06 +0000 (+0000) Subject: 2007-05-23 Hans Boehm (Really mostly Romano Paolo Tenca) X-Git-Tag: gc7_0~17 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2fe9e9d55136f26d2ce005bb8c695ca22ba07c99;p=gc 2007-05-23 Hans Boehm (Really mostly Romano Paolo Tenca) * gc_dlopen.c, thread_local_alloc.c, threadlibs.c, win32_threads.c, tests/test.c: Accomodate GC_WIN32_PTHREADS. * include/gc.h: Don't include windows.h for GC_WIN32_PTHREADS. * include/gc_config_macros.h: Define both PTHREADS and GC_WIN32_THREADS. * include/private/gc_locks.h: Nonstandard definitions of NUMERIC_THREAD_ID for GC_WIN32_PTHREADS. * doc/README.win32, Makefile.direct: Include documentation for GC_WIN32_PTHREADS. * Makefile.direct: Remove some anachronisms in the documentation. --- diff --git a/ChangeLog b/ChangeLog index 09ca5d4d..e0ab5470 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +2007-05-23 Hans Boehm (Really mostly Romano Paolo Tenca) + + * gc_dlopen.c, thread_local_alloc.c, threadlibs.c, win32_threads.c, + tests/test.c: Accomodate GC_WIN32_PTHREADS. + * include/gc.h: Don't include windows.h for GC_WIN32_PTHREADS. + * include/gc_config_macros.h: Define both PTHREADS and + GC_WIN32_THREADS. + * include/private/gc_locks.h: Nonstandard definitions of + NUMERIC_THREAD_ID for GC_WIN32_PTHREADS. + * doc/README.win32, Makefile.direct: Include documentation + for GC_WIN32_PTHREADS. + * Makefile.direct: Remove some anachronisms in the documentation. + 2007-05-23 Hans Boehm * Makefile.am: Move includes to bottom. Add better library diff --git a/Makefile.direct b/Makefile.direct index da724480..e40e06ab 100644 --- a/Makefile.direct +++ b/Makefile.direct @@ -67,28 +67,37 @@ HOSTCFLAGS=$(CFLAGS) # This causes the collector to assume that all inaccessible # objects should have been explicitly deallocated, and reports exceptions. # Finalization and the test program are not usable in this mode. -# -DGC_SOLARIS_THREADS enables support for Solaris (thr_) threads. +# +# IMPORTANT: Any of the _THREADS options must normally also be defined in +# the client before including gc.h. This redefines thread primitives to +# invoke the GC_ versions instead. Alternatively, linker-based symbol +# interception can be used on a few platforms. +# -DGC_THREADS should set the appropriate one of the below macros, +# except -DGC_WIN32_PTHREADS, which must be set explicitly. +# -DGC_SOLARIS_PTHREADS enables support for Solaris pthreads. # (Clients should also define GC_SOLARIS_THREADS and then include # gc.h before performing thr_ or dl* or GC_ operations.) # Must also define -D_REENTRANT. -# -DGC_SOLARIS_PTHREADS enables support for Solaris pthreads. -# (Internally this define GC_SOLARIS_THREADS as well.) # -DGC_IRIX_THREADS enables support for Irix pthreads. See README.irix. # -DGC_HPUX_THREADS enables support for HP/UX 11 pthreads. # Also requires -D_REENTRANT or -D_POSIX_C_SOURCE=199506L. See README.hp. -# -DGC_LINUX_THREADS enables support for Xavier Leroy's Linux threads. -# see README.linux. -D_REENTRANT may also be required. +# -DGC_LINUX_THREADS enables support for Xavier Leroy's Linux threads +# or NPTL threads. See README.linux. -D_REENTRANT may also be required. # -DGC_OSF1_THREADS enables support for Tru64 pthreads. # -DGC_FREEBSD_THREADS enables support for FreeBSD pthreads. # Appeared to run into some underlying thread problems. # -DGC_DARWIN_THREADS enables support for Mac OS X pthreads. # -DGC_AIX_THREADS enables support for IBM AIX threads. # -DGC_DGUX386_THREADS enables support for DB/UX on I386 threads. -# See README.DGUX386. +# See README.DGUX386. (Probably has not been tested recently.) # -DGC_WIN32_THREADS enables support for win32 threads. That makes sense # for this Makefile only under Cygwin. -# -DGC_THREADS should set the appropriate one of the above macros. -# It assumes pthreads for Solaris. +# -DGC_WIN32_PTHREADS enables support for Ming32 pthreads. This cannot be +# enabled automatically by GC_THREADS, which would assume Win32 native +# threads. +# -DPTW32_STATIC_LIB causes the static version of the Mingw pthreads library +# to be used. Requires -DGC_WIN32_PTHREADS. +# # -DALL_INTERIOR_POINTERS allows all pointers to the interior # of objects to be recognized. (See gc_priv.h for consequences.) # Alternatively, GC_all_interior_pointers can be set at process diff --git a/doc/README.win32 b/doc/README.win32 index 218d903d..4e6f9d5b 100644 --- a/doc/README.win32 +++ b/doc/README.win32 @@ -196,6 +196,10 @@ Cygwin, use standard pthread calls instead.) As in the pthread case, including gc.h will redefine CreateThread, _beginthreadex, _endthreadex, and ExitThread to call the GC_ versions instead. +Note that, as usual, GC_CreateThread tends to introduce resource leaks +that are avoided by GC_beginthreadex. There is currently no equivalent of +_beginthread, and it should not be used. + GC_INIT should be called from the main executable before other GC calls. We strongly advise against using the TerminateThread() win32 API call, @@ -203,3 +207,9 @@ especially with the garbage collector. Any use is likely to provoke a crash in the GC, since it makes it impossible for the collector to correctly track threads. +To build the collector for Mingw32 Pthreads, use Makefile.direct and +explicitly set GC_WIN32_PTHREADS. Use -DPTW32_STATIC_LIB for the static +threads library. Note that the DEBUG_WIN32_PTHREADS support in +win32_threads.c is currently broken and looking for someone to debug it. +(This information and the port came from Romano Paolo Tenca). + diff --git a/gc_dlopen.c b/gc_dlopen.c index 79aaeb40..51659d1e 100644 --- a/gc_dlopen.c +++ b/gc_dlopen.c @@ -25,7 +25,7 @@ #include "private/gc_priv.h" -# if (defined(GC_PTHREADS) && !defined(GC_DARWIN_THREADS)) \ +# if (defined(GC_PTHREADS) && !defined(GC_DARWIN_THREADS)) && !defined(GC_WIN32_PTHREADS)\ || defined(GC_SOLARIS_THREADS) # if defined(dlopen) && !defined(GC_USE_LD_WRAP) diff --git a/include/gc.h b/include/gc.h index f3d17d1a..f3c7725b 100644 --- a/include/gc.h +++ b/include/gc.h @@ -1003,7 +1003,8 @@ GC_register_has_static_roots_callback (int (*callback)(const char *, void *, size_t)); -#if defined(GC_WIN32_THREADS) && !defined(__CYGWIN32__) && !defined(__CYGWIN__) +#if defined(GC_WIN32_THREADS) && !defined(__CYGWIN32__) && !defined(__CYGWIN__) \ + && !defined(GC_PTHREADS) # include /* diff --git a/include/gc_config_macros.h b/include/gc_config_macros.h index d73893f5..4b37b1c7 100644 --- a/include/gc_config_macros.h +++ b/include/gc_config_macros.h @@ -69,6 +69,11 @@ # define GC_PTHREADS # endif +#if defined(GC_WIN32_PTHREADS) +# define GC_WIN32_THREADS +# define GC_PTHREADS +#endif + #if defined(GC_THREADS) && !defined(GC_PTHREADS) # if defined(__linux__) # define GC_LINUX_THREADS diff --git a/include/private/gc_locks.h b/include/private/gc_locks.h index de9e578f..8e23d9f4 100644 --- a/include/private/gc_locks.h +++ b/include/private/gc_locks.h @@ -81,16 +81,23 @@ /* the mapping to integers does not need to result in different */ /* integers for each thread, though that should be true as much */ /* as possible. */ -# if 1 /* Refine to exclude platforms on which pthread_t is struct */ -# define NUMERIC_THREAD_ID(id) ((unsigned long)(id)) -# define THREAD_EQUAL(id1, id2) ((id1) == (id2)) -# define NUMERIC_THREAD_ID_UNIQUE + /* Refine to exclude platforms on which pthread_t is struct */ +# if !defined(GC_WIN32_PTHREADS) +# define NUMERIC_THREAD_ID(id) ((unsigned long)(id)) +# define THREAD_EQUAL(id1, id2) ((id1) == (id2)) +# define NUMERIC_THREAD_ID_UNIQUE # else - /* Generic definitions that always work, but will result in */ - /* poor performance and weak assertion checking. */ -# define NUMERIC_THREAD_ID(id) 1l -# define THREAD_EQUAL(id1, id2) pthread_equal(id1, id2) -# undef NUMERIC_THREAD_ID_UNIQUE +# if defined(GC_WIN32_PTHREADS) +# define NUMERIC_THREAD_ID(id) ((unsigned long)(id.p)) +# define THREAD_EQUAL(id1, id2) pthread_equal(id1, id2) +# undef NUMERIC_THREAD_ID_UNIQUE +# else + /* Generic definitions that always work, but will result in */ + /* poor performance and weak assertion checking. */ +# define NUMERIC_THREAD_ID(id) 1l +# define THREAD_EQUAL(id1, id2) pthread_equal(id1, id2) +# undef NUMERIC_THREAD_ID_UNIQUE +# endif # endif # define NO_THREAD (-1l) /* != NUMERIC_THREAD_ID(pthread_self()) for any thread */ diff --git a/tests/test.c b/tests/test.c index c3475b57..70bd7c5b 100644 --- a/tests/test.c +++ b/tests/test.c @@ -446,7 +446,7 @@ void check_marks_int_list(sexpr x) */ #ifdef THREADS -# if defined(GC_WIN32_THREADS) && !defined(CYGWIN32) +# if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS) DWORD __stdcall tiny_reverse_test(void * arg) # else void * tiny_reverse_test(void * arg) @@ -1385,7 +1385,7 @@ void SetMinimumStack(long minSize) } # endif -#if defined(GC_WIN32_THREADS) && !defined(CYGWIN32) +#if defined(GC_WIN32_THREADS) && !defined(GC_PTHREADS) DWORD __stdcall thr_run_one_test(void *arg) { @@ -1581,7 +1581,6 @@ int main() pthread_t th2; pthread_attr_t attr; int code; - # ifdef GC_IRIX_THREADS /* Force a larger stack to be preallocated */ /* Since the initial cant always grow later. */ @@ -1594,6 +1593,10 @@ int main() (void)GC_printf("pthread_default_stacksize_np failed.\n"); } # endif /* GC_HPUX_THREADS */ +# ifdef PTW32_STATIC_LIB + pthread_win32_process_attach_np (); + pthread_win32_thread_attach_np (); +# endif GC_INIT(); pthread_attr_init(&attr); @@ -1644,6 +1647,10 @@ int main() (void)fflush(stdout); pthread_attr_destroy(&attr); GC_printf("Completed %d collections\n", GC_gc_no); +# ifdef PTW32_STATIC_LIB + pthread_win32_thread_detach_np (); + pthread_win32_process_detach_np (); +# endif return(0); } #endif /* GC_PTHREADS */ diff --git a/thread_local_alloc.c b/thread_local_alloc.c index 6c2bff31..9acd3046 100644 --- a/thread_local_alloc.c +++ b/thread_local_alloc.c @@ -124,7 +124,8 @@ void GC_destroy_thread_local(GC_tlfs p) # endif } -#if defined(GC_ASSERTIONS) && defined(GC_PTHREADS) && !defined(CYGWIN32) +#if defined(GC_ASSERTIONS) && defined(GC_PTHREADS) && !defined(CYGWIN32) \ + && !defined(GC_WIN32_PTHREADS) # include extern char * GC_lookup_thread(pthread_t id); #endif diff --git a/threadlibs.c b/threadlibs.c index 50e962d1..f2ab5825 100644 --- a/threadlibs.c +++ b/threadlibs.c @@ -42,6 +42,14 @@ int main() # if defined(GC_WIN32_THREADS) && defined(CYGWIN32) printf("-lpthread\n"); # endif +# if defined(GC_WIN32_PTHREADS) +# ifdef PTW32_STATIC_LIB + /* assume suffix s for static version of the win32 pthread library */ + printf("-lpthreadGC2s -lws2_32\n"); +# else + printf("-lpthreadGC2\n"); +# endif +# endif # if defined(GC_OSF1_THREADS) printf("-pthread -lrt"); /* DOB: must be -pthread, not -lpthread */ # endif diff --git a/win32_threads.c b/win32_threads.c index 41e4968c..85bce0ca 100644 --- a/win32_threads.c +++ b/win32_threads.c @@ -29,7 +29,7 @@ unsigned long GC_lock_holder = NO_THREAD; #endif -#ifdef CYGWIN32 +#ifdef GC_PTHREADS # include /* GC_DLL should not normally be defined, especially since we often do turn on */ @@ -48,6 +48,7 @@ # undef dlopen # define DEBUG_CYGWIN_THREADS 0 +# define DEBUG_WIN32_PTHREADS 0 void * GC_pthread_start(void * arg); void GC_thread_exit_proc(void *arg); @@ -165,7 +166,7 @@ struct GC_Thread_Rep { /* !in_use ==> stack_base == 0 */ GC_bool suspended; -# ifdef CYGWIN32 +# ifdef GC_PTHREADS void *status; /* hold exit value until join in case it's a pointer */ pthread_t pthread_id; short flags; /* Protected by GC lock. */ @@ -255,7 +256,8 @@ GC_thread GC_new_thread(DWORD id) GC_ASSERT(!GC_win32_dll_threads); result = (struct GC_Thread_Rep *) GC_INTERNAL_MALLOC(sizeof(struct GC_Thread_Rep), NORMAL); -# ifdef CYGWIN32 +# ifdef GC_PTHREADS + /* result can be NULL -> segfault */ GC_ASSERT(result -> flags == 0); # endif } @@ -263,7 +265,7 @@ GC_thread GC_new_thread(DWORD id) /* result -> id = id; Done by caller. */ result -> next = GC_threads[hv]; GC_threads[hv] = result; -# ifdef CYGWIN32 +# ifdef GC_PTHREADS GC_ASSERT(result -> flags == 0 /* && result -> thread_blocked == 0 */); # endif return(result); @@ -345,9 +347,11 @@ static GC_thread GC_register_my_thread_inner(struct GC_stack_base *sb, GC_ASSERT(I_HOLD_LOCK()); me = GC_new_thread(thread_id); } -# ifdef CYGWIN32 - me -> pthread_id = pthread_self(); +# ifdef GC_PTHREADS + /* me can be NULL -> segfault */ + me -> pthread_id = pthread_self(); # endif + if (!DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), @@ -471,6 +475,9 @@ void GC_delete_gc_thread(GC_vthread gc_id) # ifdef CYGWIN32 gc_id -> pthread_id = 0; # endif /* CYGWIN32 */ +# ifdef GC_WIN32_PTHREADS + gc_id -> pthread_id.p = NULL; +# endif /* GC_WIN32_PTHREADS */ AO_store_release(&(gc_id->in_use), FALSE); } else { /* Cast away volatile qualifier, since we have lock. */ @@ -567,7 +574,7 @@ int GC_unregister_my_thread(void) } -#ifdef CYGWIN32 +#ifdef GC_PTHREADS /* A quick-and-dirty cache of the mapping between pthread_t */ /* and win32 thread id. */ @@ -595,7 +602,7 @@ static GC_thread GC_lookup_pthread(pthread_t id) for (i = 0; i <= my_max && (!AO_load_acquire(&(dll_thread_table[i].in_use)) - || dll_thread_table[i].pthread_id != id); + || THREAD_EQUAL(dll_thread_table[i].pthread_id, id)); /* Must still be in_use, since nobody else can store our thread_id. */ i++); if (i > my_max) return 0; @@ -625,7 +632,7 @@ static GC_thread GC_lookup_pthread(pthread_t id) } } -#endif /* CYGWIN32 */ +#endif /* GC_PTHREADS */ void GC_push_thread_structures(void) { @@ -634,7 +641,7 @@ void GC_push_thread_structures(void) /* Unlike the other threads implementations, the thread table here */ /* contains no pointers to the collectable heap. Thus we have */ /* no private structures we need to preserve. */ -# ifdef CYGWIN32 +# ifdef GC_PTHREADS { int i; /* pthreads may keep a pointer in the thread exit value */ LONG my_max = GC_get_max_thread_index(); @@ -671,7 +678,7 @@ void GC_suspend(GC_thread t) if (GetExitCodeThread(t -> handle, &exitCode) && exitCode != STILL_ACTIVE) { t -> stack_base = 0; /* prevent stack from being pushed */ -# ifndef CYGWIN32 +# ifndef GC_PTHREADS /* this breaks pthread_join on Cygwin, which is guaranteed to */ /* only see user pthreads */ AO_store(&(t -> in_use), FALSE); @@ -686,7 +693,7 @@ void GC_suspend(GC_thread t) } /* Defined in misc.c */ -#ifndef CYGWIN32 +#ifndef GC_PTHREADS extern CRITICAL_SECTION GC_write_cs; #endif @@ -699,7 +706,7 @@ void GC_stop_world(void) GC_ASSERT(I_HOLD_LOCK()); GC_please_stop = TRUE; -# ifndef CYGWIN32 +# ifndef GC_PTHREADS EnterCriticalSection(&GC_write_cs); # endif if (GC_win32_dll_threads) { @@ -728,7 +735,7 @@ void GC_stop_world(void) } } } -# ifndef CYGWIN32 +# ifndef GC_PTHREADS LeaveCriticalSection(&GC_write_cs); # endif } @@ -849,6 +856,10 @@ void GC_push_stack_for(GC_thread thread) # if DEBUG_CYGWIN_THREADS GC_printf("Pushing thread from %p to %p for %d from %d\n", sp, thread -> stack_base, thread -> id, me); +# endif +# if DEBUG_WIN32_PTHREADS + GC_printf("Pushing thread from %p to %p for 0x%x from 0x%x\n", + sp, thread -> stack_base, thread -> id, me); # endif GC_push_all_stack(sp, thread->stack_base); } else { @@ -938,7 +949,7 @@ void GC_get_next_stack(char *start, char **lo, char **hi) if (*lo < start) *lo = start; } -#if !defined(CYGWIN32) +#ifndef GC_PTHREADS /* We have no DllMain to take care of new threads. Thus we */ /* must properly intercept thread creation. */ @@ -1067,7 +1078,7 @@ void GC_endthreadex(unsigned retval) _endthreadex(retval); } -#endif /* !CYGWIN32 */ +#endif /* !GC_PTHREADS */ #ifdef MSWINCE @@ -1137,7 +1148,7 @@ void GC_thr_init(void) { GC_register_my_thread(&sb); } -#ifdef CYGWIN32 +#ifdef GC_PTHREADS struct start_info { void *(*start_routine)(void *); @@ -1154,6 +1165,10 @@ int GC_pthread_join(pthread_t pthread_id, void **retval) { GC_printf("thread 0x%x(0x%x) is joining thread 0x%x.\n", (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id); # endif +# if DEBUG_WIN32_PTHREADS + GC_printf("thread 0x%x(0x%x) is joining thread 0x%x.\n", + (pthread_self()).p, GetCurrentThreadId(), pthread_id.p); +# endif if (!parallel_initialized) GC_init_parallel(); /* Thread being joined might not have registered itself yet. */ @@ -1175,6 +1190,10 @@ int GC_pthread_join(pthread_t pthread_id, void **retval) { GC_printf("thread 0x%x(0x%x) completed join with thread 0x%x.\n", (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id); # endif +# if DEBUG_WIN32_PTHREADS + GC_printf("thread 0x%x(0x%x) completed join with thread 0x%x.\n", + (pthread_self()).p, GetCurrentThreadId(), pthread_id.p); +# endif return result; } @@ -1212,6 +1231,10 @@ GC_pthread_create(pthread_t *new_thread, # if DEBUG_CYGWIN_THREADS GC_printf("About to create a thread from 0x%x(0x%x)\n", (int)pthread_self(), GetCurrentThreadId); +# endif +# if DEBUG_WIN32_PTHREADS + GC_printf("About to create a thread from 0x%x(0x%x)\n", + (pthread_self()).p, GetCurrentThreadId()); # endif GC_need_to_lock = TRUE; result = pthread_create(new_thread, attr, GC_pthread_start, si); @@ -1239,6 +1262,10 @@ void * GC_pthread_start_inner(struct GC_stack_base *sb, void * arg) GC_printf("thread 0x%x(0x%x) starting...\n",(int)pthread_id, thread_id); # endif +# if DEBUG_WIN32_PTHREADS + GC_printf("thread 0x%x(0x%x) starting...\n",(int) pthread_id.p, + thread_id); +# endif GC_ASSERT(!GC_win32_dll_threads); /* If a GC occurs before the thread is registered, that GC will */ @@ -1268,6 +1295,10 @@ void * GC_pthread_start_inner(struct GC_stack_base *sb, void * arg) GC_printf("thread 0x%x(0x%x) returned from start routine.\n", (int)pthread_self(),GetCurrentThreadId()); # endif +# if DEBUG_WIN32_PTHREADS + GC_printf("thread 0x%x(0x%x) returned from start routine.\n", + (int)(pthread_self()).p, GetCurrentThreadId()); +# endif return(result); } @@ -1287,6 +1318,10 @@ void GC_thread_exit_proc(void *arg) GC_printf("thread 0x%x(0x%x) called pthread_exit().\n", (int)pthread_self(),GetCurrentThreadId()); # endif +# if DEBUG_WIN32_PTHREADS + GC_printf("thread 0x%x(0x%x) called pthread_exit().\n", + (int)(pthread_self()).p,GetCurrentThreadId()); +# endif LOCK(); # if defined(THREAD_LOCAL_ALLOC) @@ -1301,11 +1336,14 @@ void GC_thread_exit_proc(void *arg) UNLOCK(); } +#ifndef GC_WIN32_PTHREADS +/* win32 pthread does not support sigmask */ /* nothing required here... */ int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) { if (!parallel_initialized) GC_init_parallel(); return pthread_sigmask(how, set, oset); } +#endif int GC_pthread_detach(pthread_t thread) { @@ -1329,7 +1367,7 @@ int GC_pthread_detach(pthread_t thread) return result; } -#else /* !CYGWIN32 */ +#else /* !GC_PTHREADS */ /* * We avoid acquiring locks here, since this doesn't seem to be preemptable. @@ -1394,7 +1432,7 @@ GC_API BOOL WINAPI DllMain(HINSTANCE inst, ULONG reason, LPVOID reserved) return TRUE; } #endif /* GC_DLL */ -#endif /* !CYGWIN32 */ +#endif /* !GC_PTHREADS */ # endif /* !MSWINCE */