GCC Bugzilla – Attachment 4888 Details for
Bug 10746
[3.3 regression] [win32] garbage collection crash in GCJ
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
Combined patch
1003gc.patch (text/plain), 39.80 KB, created by
Hans Boehm
on 2003-10-03 21:49:38 UTC
(
hide
)
Description:
Combined patch
Filename:
MIME Type:
Creator:
Hans Boehm
Created:
2003-10-03 21:49:38 UTC
Size:
39.80 KB
patch
obsolete
>Index: ChangeLog >=================================================================== >RCS file: /cvs/gcc/gcc/boehm-gc/ChangeLog,v >retrieving revision 1.161 >diff -u -r1.161 ChangeLog >--- ChangeLog 29 Sep 2003 20:01:55 -0000 1.161 >+++ ChangeLog 3 Oct 2003 18:39:38 -0000 >@@ -1,3 +1,12 @@ >+2003-10-03 Hans Boehm <Hans.Boehm@hp.com> >+ >+ * configure.in: Remove NO_GETENV definition for win32. >+ * mach_dep.c (GC_generic_push_regs): Prevent tail call optimization. >+ * misc.c (GC_init_inner): Call GC_thr_init for win32. >+ (GC_set_warn_proc): Add assertion. >+ * win32_threads.c: Import 6.3alpha2 version. >+ * include/private/gc_priv.h: Add support for EMPTY_GETENV_RESULTS. >+ > 2003-09-29 Rainer Orth <ro@TechFak.Uni-Bielefeld.DE> > > * configure.in: Remove wildcard from Solaris 8-9/Intel and Solaris >Index: configure.in >=================================================================== >RCS file: /cvs/gcc/gcc/boehm-gc/configure.in,v >retrieving revision 1.50 >diff -u -r1.50 configure.in >--- configure.in 29 Sep 2003 20:01:55 -0000 1.50 >+++ configure.in 3 Oct 2003 18:39:38 -0000 >@@ -137,8 +137,8 @@ > ;; > win32) > AC_DEFINE(GC_WIN32_THREADS) >- dnl Wine getenv may not return NULL for missing entry >- AC_DEFINE(NO_GETENV) >+ dnl Old wine getenv may not return NULL for missing entry. >+ dnl Define EMPTY_GETENV_RESULTS here to work around the bug. > ;; > dgux386) > THREADS=dgux386 >Index: mach_dep.c >=================================================================== >RCS file: /cvs/gcc/gcc/boehm-gc/mach_dep.c,v >retrieving revision 1.14 >diff -u -r1.14 mach_dep.c >--- mach_dep.c 28 Jul 2003 04:18:20 -0000 1.14 >+++ mach_dep.c 3 Oct 2003 18:39:38 -0000 >@@ -405,6 +405,8 @@ > ptr_t cold_gc_frame; > { > { >+ word dummy; >+ > # ifdef HAVE_BUILTIN_UNWIND_INIT > /* This was suggested by Richard Henderson as the way to */ > /* force callee-save registers and register windows onto */ >@@ -448,6 +450,10 @@ > } > # endif > GC_push_current_stack(cold_gc_frame); >+ /* Strongly discourage the compiler from treating the above */ >+ /* as a tail-call, since that would pop the register */ >+ /* contents before we get a chance to look at them. */ >+ GC_noop1((word)(&dummy)); > } > } > #endif /* USE_GENERIC_PUSH_REGS */ >Index: misc.c >=================================================================== >RCS file: /cvs/gcc/gcc/boehm-gc/misc.c,v >retrieving revision 1.27 >diff -u -r1.27 misc.c >--- misc.c 28 Jul 2003 04:18:20 -0000 1.27 >+++ misc.c 3 Oct 2003 18:39:38 -0000 >@@ -638,7 +638,8 @@ > # if (defined(NETBSD) || defined(OPENBSD)) && defined(__ELF__) > GC_init_netbsd_elf(); > # endif >-# if defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS) >+# if defined(GC_PTHREADS) || defined(GC_SOLARIS_THREADS) \ >+ || defined(GC_WIN32_THREADS) > GC_thr_init(); > # endif > # ifdef GC_SOLARIS_THREADS >@@ -1002,6 +1003,9 @@ > { > GC_warn_proc result; > >+# ifdef GC_WIN32_THREADS >+ GC_ASSERT(GC_is_initialized); >+# endif > LOCK(); > result = GC_current_warn_proc; > GC_current_warn_proc = p; >Index: win32_threads.c >=================================================================== >RCS file: /cvs/gcc/gcc/boehm-gc/win32_threads.c,v >retrieving revision 1.15 >diff -u -r1.15 win32_threads.c >--- win32_threads.c 31 Jul 2003 04:52:35 -0000 1.15 >+++ win32_threads.c 3 Oct 2003 18:39:38 -0000 >@@ -14,36 +14,205 @@ > > # define DEBUG_CYGWIN_THREADS 0 > >- GC_bool GC_thr_initialized = FALSE; > void * GC_start_routine(void * arg); > void GC_thread_exit_proc(void *arg); > > #endif > >+/* The type of the first argument to InterlockedExchange. */ >+/* Documented to be LONG volatile *, but at least gcc likes */ >+/* this better. */ >+typedef LONG * IE_t; >+ > #ifndef MAX_THREADS >-# define MAX_THREADS 64 >+# define MAX_THREADS 256 >+ /* FIXME: */ >+ /* Things may get quite slow for large numbers of threads, */ >+ /* since we look them up with sequential search. */ > #endif > >-struct thread_entry { >- LONG in_use; >+GC_bool GC_thr_initialized = FALSE; >+ >+DWORD GC_main_thread = 0; >+ >+struct GC_thread_Rep { >+ LONG in_use; /* Updated without lock. */ >+ /* We assert that unused */ >+ /* entries have invalid ids of */ >+ /* zero and zero stack fields. */ > DWORD id; > HANDLE handle; >- void *stack; /* The cold end of the stack. */ >+ ptr_t stack_base; /* The cold end of the stack. */ > /* 0 ==> entry not valid. */ >- /* !in_use ==> stack == 0 */ >- CONTEXT context; >+ /* !in_use ==> stack_base == 0 */ > GC_bool suspended; > > # ifdef CYGWIN32 > void *status; /* hold exit value until join in case it's a pointer */ > pthread_t pthread_id; >+ short flags; /* Protected by GC lock. */ >+# define FINISHED 1 /* Thread has exited. */ >+# define DETACHED 2 /* Thread is intended to be detached. */ > # endif >- > }; > >+typedef volatile struct GC_thread_Rep * GC_thread; >+ >+/* >+ * We generally assume that volatile ==> memory ordering, at least among >+ * volatiles. >+ */ >+ > volatile GC_bool GC_please_stop = FALSE; > >-volatile struct thread_entry thread_table[MAX_THREADS]; >+volatile struct GC_thread_Rep thread_table[MAX_THREADS]; >+ >+volatile LONG GC_max_thread_index = 0; /* Largest index in thread_table */ >+ /* that was ever used. */ >+ >+extern LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info); >+ >+/* >+ * This may be called from DllMain, and hence operates under unusual >+ * constraints. >+ */ >+static GC_thread GC_new_thread(void) { >+ int i; >+ /* It appears to be unsafe to acquire a lock here, since this */ >+ /* code is apparently not preeemptible on some systems. */ >+ /* (This is based on complaints, not on Microsoft's official */ >+ /* documentation, which says this should perform "only simple */ >+ /* initialization tasks".) */ >+ /* Hence we make do with nonblocking synchronization. */ >+ >+ /* The following should be a noop according to the win32 */ >+ /* documentation. There is empirical evidence that it */ >+ /* isn't. - HB */ >+# if defined(MPROTECT_VDB) >+ if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler); >+# endif >+ /* cast away volatile qualifier */ >+ for (i = 0; InterlockedExchange((IE_t)&thread_table[i].in_use,1) != 0; i++) { >+ /* Compare-and-swap would make this cleaner, but that's not */ >+ /* supported before Windows 98 and NT 4.0. In Windows 2000, */ >+ /* InterlockedExchange is supposed to be replaced by */ >+ /* InterlockedExchangePointer, but that's not really what I */ >+ /* want here. */ >+ if (i == MAX_THREADS - 1) >+ ABORT("too many threads"); >+ } >+ /* Update GC_max_thread_index if necessary. The following is safe, */ >+ /* and unlike CompareExchange-based solutions seems to work on all */ >+ /* Windows95 and later platforms. */ >+ /* Unfortunately, GC_max_thread_index may be temporarily out of */ >+ /* bounds, so readers have to compensate. */ >+ while (i > GC_max_thread_index) { >+ InterlockedIncrement((IE_t)&GC_max_thread_index); >+ } >+ if (GC_max_thread_index >= MAX_THREADS) { >+ /* We overshot due to simultaneous increments. */ >+ /* Setting it to MAX_THREADS-1 is always safe. */ >+ GC_max_thread_index = MAX_THREADS - 1; >+ } >+ >+# ifdef CYGWIN32 >+ thread_table[i].pthread_id = pthread_self(); >+# endif >+ if (!DuplicateHandle(GetCurrentProcess(), >+ GetCurrentThread(), >+ GetCurrentProcess(), >+ (HANDLE*)&thread_table[i].handle, >+ 0, >+ 0, >+ DUPLICATE_SAME_ACCESS)) { >+ DWORD last_error = GetLastError(); >+ GC_printf1("Last error code: %lx\n", last_error); >+ ABORT("DuplicateHandle failed"); >+ } >+ thread_table[i].stack_base = GC_get_stack_base(); >+ /* Up until this point, GC_psuh_all_stacks considers this thread */ >+ /* invalid. */ >+ if (thread_table[i].stack_base == NULL) >+ ABORT("Failed to find stack base in GC_new_thread"); >+ /* Up until this point, this entry is viewed as reserved but invalid */ >+ /* by GC_delete_thread. */ >+ thread_table[i].id = GetCurrentThreadId(); >+ /* If this thread is being created while we are trying to stop */ >+ /* the world, wait here. Hopefully this can't happen on any */ >+ /* systems that don't allow us to block here. */ >+ while (GC_please_stop) Sleep(20); >+ return thread_table + i; >+} >+ >+/* >+ * GC_max_thread_index may temporarily be larger than MAX_THREADS. >+ * To avoid subscript errors, we check on access. >+ */ >+#ifdef __GNUC__ >+__inline__ >+#endif >+LONG GC_get_max_thread_index() >+{ >+ LONG my_max = GC_max_thread_index; >+ >+ if (my_max >= MAX_THREADS) return MAX_THREADS-1; >+ return my_max; >+} >+ >+/* This is intended to be lock-free, though that */ >+/* assumes that the CloseHandle becomes visible before the */ >+/* in_use assignment. */ >+static void GC_delete_gc_thread(GC_thread thr) >+{ >+ CloseHandle(thr->handle); >+ /* cast away volatile qualifier */ >+ thr->stack_base = 0; >+ thr->id = 0; >+# ifdef CYGWIN32 >+ thr->pthread_id = 0; >+# endif /* CYGWIN32 */ >+ thr->in_use = FALSE; >+} >+ >+static void GC_delete_thread(DWORD thread_id) { >+ int i; >+ LONG my_max = GC_get_max_thread_index(); >+ >+ for (i = 0; >+ i <= my_max && >+ (!thread_table[i].in_use || thread_table[i].id != thread_id); >+ /* Must still be in_use, since nobody else can store our thread_id. */ >+ i++) {} >+ if (i > my_max) { >+ WARN("Removing nonexisiting thread %ld\n", (GC_word)thread_id); >+ } else { >+ GC_delete_gc_thread(thread_table+i); >+ } >+} >+ >+ >+#ifdef CYGWIN32 >+ >+/* Return a GC_thread corresponding to a given pthread_t. */ >+/* Returns 0 if it's not there. */ >+/* We assume that this is only called for pthread ids that */ >+/* have not yet terminated or are still joinable. */ >+static GC_thread GC_lookup_thread(pthread_t id) >+{ >+ int i; >+ LONG my_max = GC_get_max_thread_index(); >+ >+ for (i = 0; >+ i <= my_max && >+ (!thread_table[i].in_use || thread_table[i].pthread_id != id >+ || !thread_table[i].in_use); >+ /* Must still be in_use, since nobody else can store our thread_id. */ >+ i++); >+ if (i > my_max) return 0; >+ return thread_table + i; >+} >+ >+#endif /* CYGWIN32 */ > > void GC_push_thread_structures GC_PROTO((void)) > { >@@ -52,8 +221,12 @@ > /* no private structures we need to preserve. */ > # ifdef CYGWIN32 > { int i; /* pthreads may keep a pointer in the thread exit value */ >- for (i = 0; i < MAX_THREADS; i++) >- if (thread_table[i].in_use) GC_push_all((ptr_t)&(thread_table[i].status),(ptr_t)(&(thread_table[i].status)+1)); >+ LONG my_max = GC_get_max_thread_index(); >+ >+ for (i = 0; i <= my_max; i++) >+ if (thread_table[i].in_use) >+ GC_push_all((ptr_t)&(thread_table[i].status), >+ (ptr_t)(&(thread_table[i].status)+1)); > } > # endif > } >@@ -63,13 +236,11 @@ > DWORD thread_id = GetCurrentThreadId(); > int i; > >-#ifdef CYGWIN32 > if (!GC_thr_initialized) ABORT("GC_stop_world() called before GC_thr_init()"); >-#endif > > GC_please_stop = TRUE; >- for (i = 0; i < MAX_THREADS; i++) >- if (thread_table[i].stack != 0 >+ for (i = 0; i <= GC_get_max_thread_index(); i++) >+ if (thread_table[i].stack_base != 0 > && thread_table[i].id != thread_id) { > # ifdef MSWINCE > /* SuspendThread will fail if thread is running kernel code */ >@@ -84,13 +255,12 @@ > DWORD exitCode; > if (GetExitCodeThread(thread_table[i].handle,&exitCode) && > exitCode != STILL_ACTIVE) { >- thread_table[i].stack = 0; /* prevent stack from being pushed */ >+ thread_table[i].stack_base = 0; /* prevent stack from being pushed */ > # ifndef CYGWIN32 > /* this breaks pthread_join on Cygwin, which is guaranteed to */ > /* only see user pthreads */ > thread_table[i].in_use = FALSE; > CloseHandle(thread_table[i].handle); >- BZERO((void *)(&thread_table[i].context), sizeof(CONTEXT)); > # endif > continue; > } >@@ -105,8 +275,10 @@ > { > DWORD thread_id = GetCurrentThreadId(); > int i; >- for (i = 0; i < MAX_THREADS; i++) >- if (thread_table[i].stack != 0 && thread_table[i].suspended >+ LONG my_max = GC_get_max_thread_index(); >+ >+ for (i = 0; i <= my_max; i++) >+ if (thread_table[i].stack_base != 0 && thread_table[i].suspended > && thread_table[i].id != thread_id) { > if (ResumeThread(thread_table[i].handle) == (DWORD)-1) > ABORT("ResumeThread failed"); >@@ -122,9 +294,11 @@ > { > DWORD thread_id = GetCurrentThreadId(); > int i; >- for (i = 0; i < MAX_THREADS; i++) >- if (thread_table[i].stack && thread_table[i].id == thread_id) >- return thread_table[i].stack; >+ LONG my_max = GC_get_max_thread_index(); >+ >+ for (i = 0; i <= my_max; i++) >+ if (thread_table[i].stack_base && thread_table[i].id == thread_id) >+ return thread_table[i].stack_base; > ABORT("no thread table entry for current thread"); > } > # ifdef _MSC_VER >@@ -135,10 +309,10 @@ > /* The VirtualQuery calls below won't work properly on WinCE, but */ > /* since each stack is restricted to an aligned 64K region of */ > /* virtual memory we can just take the next lowest multiple of 64K. */ >-# define GC_get_lo_stack_addr(s) \ >+# define GC_get_stack_min(s) \ > ((ptr_t)(((DWORD)(s) - 1) & 0xFFFF0000)) > # else >- static ptr_t GC_get_lo_stack_addr(ptr_t s) >+ static ptr_t GC_get_stack_min(ptr_t s) > { > ptr_t bottom; > MEMORY_BASIC_INFORMATION info; >@@ -155,197 +329,76 @@ > void GC_push_all_stacks() > { > DWORD thread_id = GetCurrentThreadId(); >+ GC_bool found_me = FALSE; > int i; >- for (i = 0; i < MAX_THREADS; i++) >- if (thread_table[i].stack) { >- ptr_t bottom = GC_get_lo_stack_addr(thread_table[i].stack); >- if (thread_table[i].id == thread_id) >- GC_push_all_stack((ptr_t)&i, thread_table[i].stack); >- else { >- thread_table[i].context.ContextFlags >- = (CONTEXT_INTEGER|CONTEXT_CONTROL); >- if (!GetThreadContext(thread_table[i].handle, >- /* cast away volatile qualifier */ >- (LPCONTEXT)&thread_table[i].context)) >+ int dummy; >+ ptr_t sp, stack_min; >+ GC_thread thread; >+ LONG my_max = GC_get_max_thread_index(); >+ >+ for (i = 0; i <= my_max; i++) { >+ thread = thread_table + i; >+ if (thread -> in_use && thread -> stack_base) { >+ if (thread -> id == thread_id) { >+ sp = (ptr_t) &dummy; >+ found_me = TRUE; >+ } else { >+ CONTEXT context; >+ context.ContextFlags = CONTEXT_INTEGER|CONTEXT_CONTROL; >+ if (!GetThreadContext(thread_table[i].handle, &context)) > ABORT("GetThreadContext failed"); >-# ifdef I386 >- GC_push_one ((word) thread_table[i].context.Edi); >- GC_push_one ((word) thread_table[i].context.Esi); >- GC_push_one ((word) thread_table[i].context.Ebp); >- GC_push_one ((word) thread_table[i].context.Ebx); >- GC_push_one ((word) thread_table[i].context.Edx); >- GC_push_one ((word) thread_table[i].context.Ecx); >- GC_push_one ((word) thread_table[i].context.Eax); >- if (thread_table[i].context.Esp >= (DWORD)thread_table[i].stack >- || thread_table[i].context.Esp < (DWORD)bottom) { >- WARN("Thread stack pointer 0x%lx out of range, pushing everything", >- thread_table[i].context.Esp); >- GC_push_all_stack((char *) bottom, thread_table[i].stack); >- } else { >- GC_push_all_stack((char *) thread_table[i].context.Esp, >- thread_table[i].stack); >- } >-# else >-# ifdef ARM32 >- if (thread_table[i].context.Sp >= (DWORD)thread_table[i].stack >- || thread_table[i].context.Sp < (DWORD)bottom) >- ABORT("Thread stack pointer out of range"); >- GC_push_one ((word) thread_table[i].context.R0); >- GC_push_one ((word) thread_table[i].context.R1); >- GC_push_one ((word) thread_table[i].context.R2); >- GC_push_one ((word) thread_table[i].context.R3); >- GC_push_one ((word) thread_table[i].context.R4); >- GC_push_one ((word) thread_table[i].context.R5); >- GC_push_one ((word) thread_table[i].context.R6); >- GC_push_one ((word) thread_table[i].context.R7); >- GC_push_one ((word) thread_table[i].context.R8); >- GC_push_one ((word) thread_table[i].context.R9); >- GC_push_one ((word) thread_table[i].context.R10); >- GC_push_one ((word) thread_table[i].context.R11); >- GC_push_one ((word) thread_table[i].context.R12); >- GC_push_all_stack((char *) thread_table[i].context.Sp, >- thread_table[i].stack); >-# else >-# ifdef SHx >- if (thread_table[i].context.R15 >= (DWORD)thread_table[i].stack >- || thread_table[i].context.R15 < (DWORD)bottom) >- ABORT("Thread stack pointer out of range"); >- GC_push_one ((word) thread_table[i].context.R0); >- GC_push_one ((word) thread_table[i].context.R1); >- GC_push_one ((word) thread_table[i].context.R2); >- GC_push_one ((word) thread_table[i].context.R3); >- GC_push_one ((word) thread_table[i].context.R4); >- GC_push_one ((word) thread_table[i].context.R5); >- GC_push_one ((word) thread_table[i].context.R6); >- GC_push_one ((word) thread_table[i].context.R7); >- GC_push_one ((word) thread_table[i].context.R8); >- GC_push_one ((word) thread_table[i].context.R9); >- GC_push_one ((word) thread_table[i].context.R10); >- GC_push_one ((word) thread_table[i].context.R11); >- GC_push_one ((word) thread_table[i].context.R12); >- GC_push_one ((word) thread_table[i].context.R13); >- GC_push_one ((word) thread_table[i].context.R14); >- GC_push_all_stack((char *) thread_table[i].context.R15, >- thread_table[i].stack); >+ >+ /* Push all registers that might point into the heap. Frame */ >+ /* pointer registers are included in case client code was */ >+ /* compiled with the 'omit frame pointer' optimisation. */ >+# define PUSH1(reg) GC_push_one((word)context.reg) >+# define PUSH2(r1,r2) PUSH1(r1), PUSH1(r2) >+# define PUSH4(r1,r2,r3,r4) PUSH2(r1,r2), PUSH2(r3,r4) >+# if defined(I386) >+ PUSH4(Edi,Esi,Ebx,Edx), PUSH2(Ecx,Eax), PUSH1(Ebp); >+ sp = (ptr_t)context.Esp; >+# elif defined(ARM32) >+ PUSH4(R0,R1,R2,R3),PUSH4(R4,R5,R6,R7),PUSH4(R8,R9,R10,R11),PUSH1(R12); >+ sp = (ptr_t)context.Sp; >+# elif defined(SHx) >+ PUSH4(R0,R1,R2,R3), PUSH4(R4,R5,R6,R7), PUSH4(R8,R9,R10,R11); >+ PUSH2(R12,R13), PUSH1(R14); >+ sp = (ptr_t)context.R15; >+# elif defined(MIPS) >+ PUSH4(IntAt,IntV0,IntV1,IntA0), PUSH4(IntA1,IntA2,IntA3,IntT0); >+ PUSH4(IntT1,IntT2,IntT3,IntT4), PUSH4(IntT5,IntT6,IntT7,IntS0); >+ PUSH4(IntS1,IntS2,IntS3,IntS4), PUSH4(IntS5,IntS6,IntS7,IntT8); >+ PUSH4(IntT9,IntK0,IntK1,IntS8); >+ sp = (ptr_t)context.IntSp; >+# elif defined(PPC) >+ PUSH4(Gpr0, Gpr3, Gpr4, Gpr5), PUSH4(Gpr6, Gpr7, Gpr8, Gpr9); >+ PUSH4(Gpr10,Gpr11,Gpr12,Gpr14), PUSH4(Gpr15,Gpr16,Gpr17,Gpr18); >+ PUSH4(Gpr19,Gpr20,Gpr21,Gpr22), PUSH4(Gpr23,Gpr24,Gpr25,Gpr26); >+ PUSH4(Gpr27,Gpr28,Gpr29,Gpr30), PUSH1(Gpr31); >+ sp = (ptr_t)context.Gpr1; >+# elif defined(ALPHA) >+ PUSH4(IntV0,IntT0,IntT1,IntT2), PUSH4(IntT3,IntT4,IntT5,IntT6); >+ PUSH4(IntT7,IntS0,IntS1,IntS2), PUSH4(IntS3,IntS4,IntS5,IntFp); >+ PUSH4(IntA0,IntA1,IntA2,IntA3), PUSH4(IntA4,IntA5,IntT8,IntT9); >+ PUSH4(IntT10,IntT11,IntT12,IntAt); >+ sp = (ptr_t)context.IntSp; > # else >-# ifdef MIPS >- if (thread_table[i].context.IntSp >= (DWORD)thread_table[i].stack >- || thread_table[i].context.IntSp < (DWORD)bottom) >- ABORT("Thread stack pointer out of range"); >- GC_push_one ((word) thread_table[i].context.IntAt); >- GC_push_one ((word) thread_table[i].context.IntV0); >- GC_push_one ((word) thread_table[i].context.IntV1); >- GC_push_one ((word) thread_table[i].context.IntA0); >- GC_push_one ((word) thread_table[i].context.IntA1); >- GC_push_one ((word) thread_table[i].context.IntA2); >- GC_push_one ((word) thread_table[i].context.IntA3); >- GC_push_one ((word) thread_table[i].context.IntT0); >- GC_push_one ((word) thread_table[i].context.IntT1); >- GC_push_one ((word) thread_table[i].context.IntT2); >- GC_push_one ((word) thread_table[i].context.IntT3); >- GC_push_one ((word) thread_table[i].context.IntT4); >- GC_push_one ((word) thread_table[i].context.IntT5); >- GC_push_one ((word) thread_table[i].context.IntT6); >- GC_push_one ((word) thread_table[i].context.IntT7); >- GC_push_one ((word) thread_table[i].context.IntS0); >- GC_push_one ((word) thread_table[i].context.IntS1); >- GC_push_one ((word) thread_table[i].context.IntS2); >- GC_push_one ((word) thread_table[i].context.IntS3); >- GC_push_one ((word) thread_table[i].context.IntS4); >- GC_push_one ((word) thread_table[i].context.IntS5); >- GC_push_one ((word) thread_table[i].context.IntS6); >- GC_push_one ((word) thread_table[i].context.IntS7); >- GC_push_one ((word) thread_table[i].context.IntT8); >- GC_push_one ((word) thread_table[i].context.IntT9); >- GC_push_one ((word) thread_table[i].context.IntK0); >- GC_push_one ((word) thread_table[i].context.IntK1); >- GC_push_one ((word) thread_table[i].context.IntS8); >- GC_push_all_stack((char *) thread_table[i].context.IntSp, >- thread_table[i].stack); >-# else >-# ifdef PPC >- if (thread_table[i].context.Gpr1 >= (DWORD)thread_table[i].stack >- || thread_table[i].context.Gpr1 < (DWORD)bottom) >- ABORT("Thread stack pointer out of range"); >- GC_push_one ((word) thread_table[i].context.Gpr0); >- /* Gpr1 is stack pointer */ >- /* Gpr2 is global pointer */ >- GC_push_one ((word) thread_table[i].context.Gpr3); >- GC_push_one ((word) thread_table[i].context.Gpr4); >- GC_push_one ((word) thread_table[i].context.Gpr5); >- GC_push_one ((word) thread_table[i].context.Gpr6); >- GC_push_one ((word) thread_table[i].context.Gpr7); >- GC_push_one ((word) thread_table[i].context.Gpr8); >- GC_push_one ((word) thread_table[i].context.Gpr9); >- GC_push_one ((word) thread_table[i].context.Gpr10); >- GC_push_one ((word) thread_table[i].context.Gpr11); >- GC_push_one ((word) thread_table[i].context.Gpr12); >- /* Gpr13 is reserved for the kernel */ >- GC_push_one ((word) thread_table[i].context.Gpr14); >- GC_push_one ((word) thread_table[i].context.Gpr15); >- GC_push_one ((word) thread_table[i].context.Gpr16); >- GC_push_one ((word) thread_table[i].context.Gpr17); >- GC_push_one ((word) thread_table[i].context.Gpr18); >- GC_push_one ((word) thread_table[i].context.Gpr19); >- GC_push_one ((word) thread_table[i].context.Gpr20); >- GC_push_one ((word) thread_table[i].context.Gpr21); >- GC_push_one ((word) thread_table[i].context.Gpr22); >- GC_push_one ((word) thread_table[i].context.Gpr23); >- GC_push_one ((word) thread_table[i].context.Gpr24); >- GC_push_one ((word) thread_table[i].context.Gpr25); >- GC_push_one ((word) thread_table[i].context.Gpr26); >- GC_push_one ((word) thread_table[i].context.Gpr27); >- GC_push_one ((word) thread_table[i].context.Gpr28); >- GC_push_one ((word) thread_table[i].context.Gpr29); >- GC_push_one ((word) thread_table[i].context.Gpr30); >- GC_push_one ((word) thread_table[i].context.Gpr31); >- GC_push_all_stack((char *) thread_table[i].context.Gpr1, >- thread_table[i].stack); >-# else >-# ifdef ALPHA >- if (thread_table[i].context.IntSp >= (DWORD)thread_table[i].stack >- || thread_table[i].context.IntSp < (DWORD)bottom) >- ABORT("Thread stack pointer out of range"); >- GC_push_one ((word) thread_table[i].context.IntV0); >- GC_push_one ((word) thread_table[i].context.IntT0); >- GC_push_one ((word) thread_table[i].context.IntT1); >- GC_push_one ((word) thread_table[i].context.IntT2); >- GC_push_one ((word) thread_table[i].context.IntT3); >- GC_push_one ((word) thread_table[i].context.IntT4); >- GC_push_one ((word) thread_table[i].context.IntT5); >- GC_push_one ((word) thread_table[i].context.IntT6); >- GC_push_one ((word) thread_table[i].context.IntT7); >- GC_push_one ((word) thread_table[i].context.IntS0); >- GC_push_one ((word) thread_table[i].context.IntS1); >- GC_push_one ((word) thread_table[i].context.IntS2); >- GC_push_one ((word) thread_table[i].context.IntS3); >- GC_push_one ((word) thread_table[i].context.IntS4); >- GC_push_one ((word) thread_table[i].context.IntS5); >- GC_push_one ((word) thread_table[i].context.IntFp); >- GC_push_one ((word) thread_table[i].context.IntA0); >- GC_push_one ((word) thread_table[i].context.IntA1); >- GC_push_one ((word) thread_table[i].context.IntA2); >- GC_push_one ((word) thread_table[i].context.IntA3); >- GC_push_one ((word) thread_table[i].context.IntA4); >- GC_push_one ((word) thread_table[i].context.IntA5); >- GC_push_one ((word) thread_table[i].context.IntT8); >- GC_push_one ((word) thread_table[i].context.IntT9); >- GC_push_one ((word) thread_table[i].context.IntT10); >- GC_push_one ((word) thread_table[i].context.IntT11); >- GC_push_one ((word) thread_table[i].context.IntT12); >- GC_push_one ((word) thread_table[i].context.IntAt); >- GC_push_all_stack((char *) thread_table[i].context.IntSp, >- thread_table[i].stack); >-# else >- --> architecture not supported >-# endif /* !ALPHA */ >-# endif /* !PPC */ >-# endif /* !MIPS */ >-# endif /* !SHx */ >-# endif /* !ARM32 */ >-# endif /* !I386 */ >+# error "architecture is not supported" >+# endif >+ } >+ >+ stack_min = GC_get_stack_min(thread->stack_base); >+ >+ if (sp >= stack_min && sp < thread->stack_base) >+ GC_push_all_stack(sp, thread->stack_base); >+ else { >+ WARN("Thread stack pointer 0x%lx out of range, pushing everything\n", >+ (unsigned long)sp); >+ GC_push_all_stack(stack_min, thread->stack_base); > } > } >+ } >+ if (!found_me) ABORT("Collecting from unknown thread."); > } > > void GC_get_next_stack(char *start, char **lo, char **hi) >@@ -353,9 +406,10 @@ > int i; > # define ADDR_LIMIT (char *)(-1L) > char * current_min = ADDR_LIMIT; >- >- for (i = 0; i < MAX_THREADS; i++) { >- char * s = (char *)thread_table[i].stack; >+ LONG my_max = GC_get_max_thread_index(); >+ >+ for (i = 0; i <= my_max; i++) { >+ char * s = (char *)thread_table[i].stack_base; > > if (0 != s && s > start && s < current_min) { > current_min = s; >@@ -366,7 +420,7 @@ > *lo = ADDR_LIMIT; > return; > } >- *lo = GC_get_lo_stack_addr(current_min); >+ *lo = GC_get_stack_min(current_min); > if (*lo < start) *lo = start; > } > >@@ -391,8 +445,6 @@ > /* must properly intercept thread creation. */ > > typedef struct { >- HANDLE child_ready_h, parent_ready_h; >- volatile struct thread_entry * entry; > LPTHREAD_START_ROUTINE start; > LPVOID param; > } thread_args; >@@ -405,80 +457,27 @@ > LPVOID lpParameter, DWORD dwCreationFlags, LPDWORD lpThreadId ) > { > HANDLE thread_h = NULL; >- HANDLE child_ready_h, parent_ready_h; > >- int i; >- thread_args args; >+ thread_args *args; > >- /* allocate thread slot */ >- LOCK(); >- for (i = 0; i != MAX_THREADS && thread_table[i].in_use; i++) >- ; >- if (i != MAX_THREADS) { >- thread_table[i].in_use = TRUE; >+ if (!GC_is_initialized) GC_init(); >+ /* make sure GC is initialized (i.e. main thread is attached) */ >+ >+ args = GC_malloc_uncollectable(sizeof(thread_args)); >+ /* Handed off to and deallocated by child thread. */ >+ if (0 == args) { >+ SetLastError(ERROR_NOT_ENOUGH_MEMORY); >+ return NULL; > } >- UNLOCK(); >- >- if (i != MAX_THREADS) { >- >- /* create unnamed unsignalled events */ >- if (child_ready_h = CreateEvent(NULL, FALSE, FALSE, NULL)) { >- if (parent_ready_h = CreateEvent(NULL, FALSE, FALSE, NULL)) { >- >- /* set up thread arguments */ >- args.child_ready_h = child_ready_h; >- args.parent_ready_h = parent_ready_h; >- args.entry = &thread_table[i]; >- args.start = lpStartAddress; >- args.param = lpParameter; >- >- thread_h = CreateThread(lpThreadAttributes, >- dwStackSize, thread_start, >- &args, >- dwCreationFlags & ~CREATE_SUSPENDED, >- lpThreadId); >- >- if (thread_h) { >- >- /* fill in ID and handle; tell child this is done */ >- thread_table[i].id = *lpThreadId; >- if (!DuplicateHandle(GetCurrentProcess(), >- thread_h, >- GetCurrentProcess(), >- (PHANDLE) &thread_table[i].handle, >- 0, >- 0, >- DUPLICATE_SAME_ACCESS)) { >- DWORD last_error = GetLastError(); >- GC_printf1("Last error code: %lx\n", last_error); >- ABORT("DuplicateHandle failed"); >- } >- SetEvent (parent_ready_h); >- >- /* wait for child to fill in stack and copy args */ >- WaitForSingleObject (child_ready_h, INFINITE); >- >- /* suspend the child if requested */ >- if (dwCreationFlags & CREATE_SUSPENDED) >- SuspendThread (thread_h); >- >- /* let child call given function now (or when resumed) */ >- SetEvent (parent_ready_h); >- >- } else { >- CloseHandle (parent_ready_h); >- } >- } >- } >- >- CloseHandle (child_ready_h); > >- if (thread_h == NULL) >- thread_table[i].in_use = FALSE; >- >- } else { /* no thread slot found */ >- SetLastError (ERROR_TOO_MANY_TCBS); >- } >+ /* set up thread arguments */ >+ args -> start = lpStartAddress; >+ args -> param = lpParameter; >+ >+ thread_h = CreateThread(lpThreadAttributes, >+ dwStackSize, thread_start, >+ args, dwCreationFlags, >+ lpThreadId); > > return thread_h; > } >@@ -486,19 +485,9 @@ > static DWORD WINAPI thread_start(LPVOID arg) > { > DWORD ret = 0; >- thread_args args = *(thread_args *)arg; >+ thread_args *args = (thread_args *)arg; > >- /* wait for parent to fill in ID and handle */ >- WaitForSingleObject (args.parent_ready_h, INFINITE); >- ResetEvent (args.parent_ready_h); >- >- /* fill in stack; tell parent this is done */ >- args.entry->stack = GC_get_stack_base(); >- SetEvent (args.child_ready_h); >- >- /* wait for parent to tell us to go (in case it needs to suspend us) */ >- WaitForSingleObject (args.parent_ready_h, INFINITE); >- CloseHandle (args.parent_ready_h); >+ GC_new_thread(); > > /* Clear the thread entry even if we exit with an exception. */ > /* This is probably pointless, since an uncaught exception is */ >@@ -506,16 +495,12 @@ > #ifndef __GNUC__ > __try { > #endif /* __GNUC__ */ >- ret = args.start (args.param); >+ ret = args->start (args->param); > #ifndef __GNUC__ > } __finally { > #endif /* __GNUC__ */ >- LOCK(); >- args.entry->stack = 0; >- args.entry->in_use = FALSE; >- /* cast away volatile qualifier */ >- BZERO((void *) &args.entry->context, sizeof(CONTEXT)); >- UNLOCK(); >+ GC_free(args); >+ GC_delete_thread(GetCurrentThreadId()); > #ifndef __GNUC__ > } > #endif /* __GNUC__ */ >@@ -549,7 +534,6 @@ > DWORD thread_id; > > /* initialize everything */ >- InitializeCriticalSection(&GC_allocate_ml); > GC_init(); > > /* start the main thread */ >@@ -579,126 +563,44 @@ > > # else /* !MSWINCE */ > >-LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info); >- >-/* threadAttach/threadDetach routines used by both CYGWIN and DLL >- * implementation, since both recieve explicit notification on thread >- * creation/destruction. >- */ >-static void threadAttach() { >- int i; >- /* It appears to be unsafe to acquire a lock here, since this */ >- /* code is apparently not preeemptible on some systems. */ >- /* (This is based on complaints, not on Microsoft's official */ >- /* documentation, which says this should perform "only simple */ >- /* inititalization tasks".) */ >- /* Hence we make do with nonblocking synchronization. */ >- >- /* The following should be a noop according to the win32 */ >- /* documentation. There is empirical evidence that it */ >- /* isn't. - HB */ >-# if defined(MPROTECT_VDB) >- if (GC_incremental) SetUnhandledExceptionFilter(GC_write_fault_handler); >-# endif >- /* cast away volatile qualifier */ >- for (i = 0; InterlockedExchange((LONG*)&thread_table[i].in_use,1) != 0; i++) { >- /* Compare-and-swap would make this cleaner, but that's not */ >- /* supported before Windows 98 and NT 4.0. In Windows 2000, */ >- /* InterlockedExchange is supposed to be replaced by */ >- /* InterlockedExchangePointer, but that's not really what I */ >- /* want here. */ >- if (i == MAX_THREADS - 1) >- ABORT("too many threads"); >- } >- thread_table[i].id = GetCurrentThreadId(); >-# ifdef CYGWIN32 >- thread_table[i].pthread_id = pthread_self(); >-# endif >- if (!DuplicateHandle(GetCurrentProcess(), >- GetCurrentThread(), >- GetCurrentProcess(), >- (HANDLE*)&thread_table[i].handle, >- 0, >- 0, >- DUPLICATE_SAME_ACCESS)) { >- DWORD last_error = GetLastError(); >- GC_printf1("Last error code: %lx\n", last_error); >- ABORT("DuplicateHandle failed"); >- } >- thread_table[i].stack = GC_get_stack_base(); >- if (thread_table[i].stack == NULL) >- ABORT("Failed to find stack base in threadAttach"); >- /* If this thread is being created while we are trying to stop */ >- /* the world, wait here. Hopefully this can't happen on any */ >- /* systems that don't allow us to block here. */ >- while (GC_please_stop) Sleep(20); >-} >- >-static void threadDetach(DWORD thread_id) { >- int i; >- >- LOCK(); >- for (i = 0; >- i < MAX_THREADS && >- (!thread_table[i].in_use || thread_table[i].id != thread_id); >- i++) {} >- if (i >= MAX_THREADS ) { >- WARN("thread %ld not found on detach", (GC_word)thread_id); >- } else { >- thread_table[i].stack = 0; >- thread_table[i].in_use = FALSE; >- CloseHandle(thread_table[i].handle); >- /* cast away volatile qualifier */ >- BZERO((void *)&thread_table[i].context, sizeof(CONTEXT)); >- } >- UNLOCK(); >-} >- >-#ifdef CYGWIN32 >- > /* Called by GC_init() - we hold the allocation lock. */ > void GC_thr_init() { > if (GC_thr_initialized) return; >+ GC_main_thread = GetCurrentThreadId(); > GC_thr_initialized = TRUE; > >-#if 0 >- /* this might already be handled in GC_init... */ >- InitializeCriticalSection(&GC_allocate_ml); >-#endif >- > /* Add the initial thread, so we can stop it. */ >- threadAttach(); >+ GC_new_thread(); > } > >+#ifdef CYGWIN32 >+ > struct start_info { > void *(*start_routine)(void *); > void *arg; >+ GC_bool detached; > }; > > int GC_pthread_join(pthread_t pthread_id, void **retval) { > int result; > int i; >+ GC_thread me; > > # if DEBUG_CYGWIN_THREADS >- GC_printf3("thread 0x%x(0x%x) is joining thread 0x%x.\n",(int)pthread_self(), >- GetCurrentThreadId(), (int)pthread_id); >+ GC_printf3("thread 0x%x(0x%x) is joining thread 0x%x.\n", >+ (int)pthread_self(), GetCurrentThreadId(), (int)pthread_id); > # endif > >- /* Can't do any table lookups here, because thread being joined >- might not have registered itself yet */ >+ /* Thread being joined might not have registered itself yet. */ >+ /* After the join,thread id may have been recycled. */ >+ /* FIXME: It would be better if this worked more like */ >+ /* pthread_support.c. */ >+ >+ while ((me = GC_lookup_thread(pthread_id)) == 0) Sleep(10); > > result = pthread_join(pthread_id, retval); > >- LOCK(); >- for (i = 0; !thread_table[i].in_use || thread_table[i].pthread_id != pthread_id; >- i++) { >- if (i == MAX_THREADS - 1) { >- GC_printf1("Failed to find thread 0x%x in pthread_join()\n", pthread_id); >- ABORT("thread not found on detach"); >- } >- } >- UNLOCK(); >- threadDetach(thread_table[i].id); >+ GC_delete_gc_thread(me); > > # if DEBUG_CYGWIN_THREADS > GC_printf3("thread 0x%x(0x%x) completed join with thread 0x%x.\n", >@@ -729,10 +631,15 @@ > > si -> start_routine = start_routine; > si -> arg = arg; >+ if (attr != 0 && >+ pthread_attr_getdetachstate(attr, &si->detached) >+ == PTHREAD_CREATE_DETACHED) { >+ si->detached = TRUE; >+ } > > # if DEBUG_CYGWIN_THREADS >- GC_printf2("About to create a thread from 0x%x(0x%x)\n",(int)pthread_self(), >- GetCurrentThreadId); >+ GC_printf2("About to create a thread from 0x%x(0x%x)\n", >+ (int)pthread_self(), GetCurrentThreadId); > # endif > result = pthread_create(new_thread, attr, GC_start_routine, si); > >@@ -750,6 +657,8 @@ > void *(*start)(void *); > void *start_arg; > pthread_t pthread_id; >+ GC_thread me; >+ GC_bool detached; > int i; > > # if DEBUG_CYGWIN_THREADS >@@ -764,17 +673,19 @@ > LOCK(); > /* We register the thread here instead of in the parent, so that */ > /* we don't need to hold the allocation lock during pthread_create. */ >- threadAttach(); >+ me = GC_new_thread(); > UNLOCK(); > > start = si -> start_routine; > start_arg = si -> arg; >- pthread_id = pthread_self(); >+ if (si-> detached) me -> flags |= DETACHED; >+ me -> pthread_id = pthread_id = pthread_self(); > > GC_free(si); /* was allocated uncollectable */ > >- pthread_cleanup_push(GC_thread_exit_proc, pthread_id); >+ pthread_cleanup_push(GC_thread_exit_proc, (void *)me); > result = (*start)(start_arg); >+ me -> status = result; > pthread_cleanup_pop(0); > > # if DEBUG_CYGWIN_THREADS >@@ -782,20 +693,12 @@ > (int)pthread_self(),GetCurrentThreadId()); > # endif > >- LOCK(); >- for (i = 0; thread_table[i].pthread_id != pthread_id; i++) { >- if (i == MAX_THREADS - 1) >- ABORT("thread not found on exit"); >- } >- thread_table[i].status = result; >- UNLOCK(); >- > return(result); > } > > void GC_thread_exit_proc(void *arg) > { >- pthread_t pthread_id = (pthread_t)arg; >+ GC_thread me = (GC_thread)arg; > int i; > > # if DEBUG_CYGWIN_THREADS >@@ -804,25 +707,41 @@ > # endif > > LOCK(); >- for (i = 0; thread_table[i].pthread_id != pthread_id; i++) { >- if (i == MAX_THREADS - 1) >- ABORT("thread not found on exit"); >+ if (me -> flags & DETACHED) { >+ GC_delete_thread(GetCurrentThreadId()); >+ } else { >+ /* deallocate it as part of join */ >+ me -> flags |= FINISHED; > } > UNLOCK(); >- >-#if 0 >- /* TODO: we need a way to get the exit value after a pthread_exit so we can stash it safely away */ >- thread_table[i].status = ??? >-#endif > } > > /* nothing required here... */ > int GC_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) { > return pthread_sigmask(how, set, oset); > } >-int GC_pthread_detach(pthread_t thread) { >- return pthread_detach(thread); >+ >+int GC_pthread_detach(pthread_t thread) >+{ >+ int result; >+ GC_thread thread_gc_id; >+ >+ LOCK(); >+ thread_gc_id = GC_lookup_thread(thread); >+ UNLOCK(); >+ result = pthread_detach(thread); >+ if (result == 0) { >+ LOCK(); >+ thread_gc_id -> flags |= DETACHED; >+ /* Here the pthread thread id may have been recycled. */ >+ if (thread_gc_id -> flags & FINISHED) { >+ GC_delete_gc_thread(thread_gc_id); >+ } >+ UNLOCK(); >+ } >+ return result; > } >+ > #else /* !CYGWIN32 */ > > /* >@@ -834,15 +753,17 @@ > { > switch (reason) { > case DLL_PROCESS_ATTACH: >- InitializeCriticalSection(&GC_allocate_ml); > GC_init(); /* Force initialization before thread attach. */ > /* fall through */ > case DLL_THREAD_ATTACH: >- threadAttach(); >+ GC_ASSERT(GC_thr_initialized); >+ if (GC_main_thread != GetCurrentThreadId()) { >+ GC_new_thread(); >+ } /* o.w. we already did it during GC_thr_init(), called by GC_init() */ > break; > > case DLL_THREAD_DETACH: >- threadDetach(GetCurrentThreadId()); >+ GC_delete_thread(GetCurrentThreadId()); > break; > > case DLL_PROCESS_DETACH: >@@ -850,15 +771,10 @@ > int i; > > LOCK(); >- for (i = 0; i < MAX_THREADS; ++i) >+ for (i = 0; i <= GC_get_max_thread_index(); ++i) > { > if (thread_table[i].in_use) >- { >- thread_table[i].stack = 0; >- thread_table[i].in_use = FALSE; >- CloseHandle(thread_table[i].handle); >- BZERO((void *) &thread_table[i].context, sizeof(CONTEXT)); >- } >+ GC_delete_gc_thread(thread_table + i); > } > UNLOCK(); > >Index: include/private/gc_priv.h >=================================================================== >RCS file: /cvs/gcc/gcc/boehm-gc/include/private/gc_priv.h,v >retrieving revision 1.12 >diff -u -r1.12 gc_priv.h >--- include/private/gc_priv.h 28 Jul 2003 04:18:23 -0000 1.12 >+++ include/private/gc_priv.h 3 Oct 2003 18:39:38 -0000 >@@ -448,7 +448,19 @@ > > /* Get environment entry */ > #if !defined(NO_GETENV) >-# define GETENV(name) getenv(name) >+# if defined(EMPTY_GETENV_RESULTS) >+ /* Workaround for a reputed Wine bug. */ >+ static inline char * fixed_getenv(const char *name) >+ { >+ char * tmp = getenv(name); >+ if (tmp == 0 || strlen(tmp) == 0) >+ return 0; >+ return tmp; >+ } >+# define GETENV(name) fixed_getenv(name) >+# else >+# define GETENV(name) getenv(name) >+# endif > #else > # define GETENV(name) 0 > #endif
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 10746
:
4528
|
4716
|
4732
|
4733
|
4764
|
4765
|
4783
| 4888