Fwd: Re[3]: Boehm GC API update backport

Ivan Maidanski <[email protected]> Tue, 14 Jun 2016 22:00:18 +0300
Newsgroups gmane.comp.gcc.java.patches
Message-ID <[email protected]>
Hello,

Is there anything more preventing it to be merged to trunk?

The patches (rebased to recent trunk) are attached. (Actually only the first one is updated due to merge conflict in ChangeLog files.)

Thank you.

Regards,
Ivan

>Wed, 20 Jan 2016, 1:41 +03:00 from Ivan Maidanski < [email protected] >:
>
>Hello Matthias,
>
>I've checked objc tests - same as without the patches.
>Actually objc uses only GC_malloc/realloc and GC typed API - these are not affected.
>
>Regards,
>Ivan
>
>> Sun, 17 Jan 2016, 1:55 +01:00 from Matthias Klose < [email protected] >:
>> 
>> On 16.01.2016 13:19, Ivan Maidanski wrote:
>> > Hello,
>> >
>> > Proposed 4 commits are code refactoring of boehm-gc (and libjava/boehm.cc, accordingly) to match API of recent BDWGC master (  https://github.com/ivmai/bdwgc ). This should simplify optional replacement of internal boehm-gcc with the external one.
>> > All gcj tests pass.
>> >
>> > Some of the benefits of using mainline boehm gc:
>> > *  has no compiler warning
>> > *  more targets supported (e.g. arm64)
>> > *  no trouble with back-porting gc patches Similar thing was proposed for the Mono community -  https://github.com/mono/mono/pull/2247 (the patches were accepted recently)
>> >
>> > References:
>> > [1] The proposed patches in GCC unofficial git mirror fork -  https://github.com/ivmai/gcc/tree/match-bdwgc-api
>> 
>> for completeness, please check an ObjC enabled build configured with 
>> --enable-objc-gc
>> 
>> Matthias
>>
0001-Change-GC_set_free_space_divisor-prototy pe-in-boehm-.patch (application/x-patch, 3.7 KB)
From 50a20b00b55e7e116c60b479fa26dcf534b88941 Mon Sep 17 00:00:00 2001
From: Ivan Maidanski <[email protected]>
Date: Thu, 3 Dec 2015 01:48:30 +0300
Subject: [PATCH 1/4] Change GC_set_free_space_divisor prototype in boehm-gc
 (code refactoring to match BDWGC v7 API)

boehm-gc/
    * include/gc.h (GC_set_free_space_divisor): Change return type from
    word to void.
    (GC_get_free_space_divisor): New function.
    * misc.c (GC_set_free_space_divisor): Decouple to setter and getter.

libjava/
    * boehm.cc (_Jv_SetGCFreeSpaceDivisor): Use GC_get_free_space_divisor
    to get old_div (before GC_set_free_space_divisor call).
---
 boehm-gc/ChangeLog    |  7 +++++++
 boehm-gc/include/gc.h |  6 +++---
 boehm-gc/misc.c       | 11 +++++++----
 libjava/ChangeLog     |  5 +++++
 libjava/boehm.cc      |  4 +++-
 5 files changed, 25 insertions(+), 8 deletions(-)

diff --git a/boehm-gc/ChangeLog b/boehm-gc/ChangeLog
index 6896c67..532b889 100644
--- a/boehm-gc/ChangeLog
+++ b/boehm-gc/ChangeLog
@@ -1,3 +1,10 @@
+2015-12-03  Ivan Maidanski  <[email protected]>
+
+	* include/gc.h (GC_set_free_space_divisor): Change return type from
+	word to void.
+	(GC_get_free_space_divisor): New function.
+	* misc.c (GC_set_free_space_divisor): Decouple to setter and getter.
+
 2016-03-29  Samuel Thibault  <[email protected]>
 
 	* configure.host: Set gc_use_mmap on *-kfreebsd-gnu* and *-gnu*.
diff --git a/boehm-gc/include/gc.h b/boehm-gc/include/gc.h
index 6b38f2d..d02dab2 100644
--- a/boehm-gc/include/gc.h
+++ b/boehm-gc/include/gc.h
@@ -803,9 +803,9 @@ typedef void (*GC_warn_proc) GC_PROTO((char *msg, GC_word arg));
 GC_API GC_warn_proc GC_set_warn_proc GC_PROTO((GC_warn_proc p));
     /* Returns old warning procedure.	*/
 
-GC_API GC_word GC_set_free_space_divisor GC_PROTO((GC_word value));
-    /* Set free_space_divisor.  See above for definition.	*/
-    /* Returns old value.					*/
+GC_API void GC_set_free_space_divisor GC_PROTO((GC_word value));
+GC_API GC_word GC_get_free_space_divisor GC_PROTO((void));
+    /* Set and get free_space_divisor.  See above for the definition.	*/
 	
 /* The following is intended to be used by a higher level	*/
 /* (e.g. Java-like) finalization facility.  It is expected	*/
diff --git a/boehm-gc/misc.c b/boehm-gc/misc.c
index 069c7d5..c1faed0 100644
--- a/boehm-gc/misc.c
+++ b/boehm-gc/misc.c
@@ -1048,15 +1048,18 @@ GC_warn_proc GC_current_warn_proc = GC_default_warn_proc;
 }
 
 # if defined(__STDC__) || defined(__cplusplus)
-    GC_word GC_set_free_space_divisor (GC_word value)
+    void GC_set_free_space_divisor (GC_word value)
 # else
-    GC_word GC_set_free_space_divisor (value)
+    void GC_set_free_space_divisor (value)
     GC_word value;
 # endif
 {
-    GC_word old = GC_free_space_divisor;
     GC_free_space_divisor = value;
-    return old;
+}
+
+GC_word GC_get_free_space_divisor GC_PROTO((void))
+{
+    return GC_free_space_divisor;
 }
 
 #ifndef PCR
diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index a3bead2..e98fe56 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,3 +1,8 @@
+2015-12-03  Ivan Maidanski  <[email protected]>
+
+	* boehm.cc (_Jv_SetGCFreeSpaceDivisor): Use GC_get_free_space_divisor
+	to get old_div (before GC_set_free_space_divisor call).
+
 2016-06-01  Matthias Klose  <[email protected]>
 
 	* libtool-version: Bump soversion.
diff --git a/libjava/boehm.cc b/libjava/boehm.cc
index 043fd00..34a6ead 100644
--- a/libjava/boehm.cc
+++ b/libjava/boehm.cc
@@ -468,7 +468,9 @@ _Jv_GCSetMaximumHeapSize (size_t size)
 int
 _Jv_SetGCFreeSpaceDivisor (int div)
 {
-  return (int)GC_set_free_space_divisor ((GC_word)div);
+  int old_div = (int)GC_get_free_space_divisor ();
+  GC_set_free_space_divisor ((GC_word)div);
+  return old_div;
 }
 
 void
-- 
2.8.2
0002-Move-extern-C-from-boehm.cc-to-boehm-gc- header-files.patch (application/x-patch, 8.3 KB)
From 6c3c544918a3d6c0e10ac84df937be7c82849f11 Mon Sep 17 00:00:00 2001
From: Ivan Maidanski <[email protected]>
Date: Sat, 5 Dec 2015 19:28:20 +0300
Subject: [PATCH 2/4] Move 'extern C' from boehm.cc to boehm-gc header files;
 avoid explicit include gc_local_alloc.h from boehm.cc; remove
 GC_enable/disable duplicate prototyping (code refactoring to match BDWGC v7
 API)

boehm-gc/
    * include/gc.h (GC_suspend_thread, GC_resume_thread,
    GC_is_thread_suspended): Move inside 'extern "C"' block.
    [GC_REDIRECT_TO_LOCAL]: Include gc_local_alloc.h outside 'extern "C"'
    block; do not include gc_local_alloc.h if gc.h is included from
    gc_gcj.h (so that GC_[LOCAL_]GCJ_MALLOC to be defined after other GCJ
    symbols).
    * include/gc_gcj.h [__cplusplus]: Wrap all declarations into
    'extern "C"' block.
    * include/gc_local_alloc.h [__cplusplus]: Likewise.
    * include/javaxfc.h [__cplusplus]: Likewise.
    * include/gc_gcj.h [GC_REDIRECT_TO_LOCAL]: Include gc_local_alloc.h.

libjava/
    * boehm.cc (GC_enable, GC_disable): Remove prototype (as declared in
    boehm-gc/include/gc.h).
    [THREAD_LOCAL_ALLOC] (GC_REDIRECT_TO_LOCAL): Define before include
    gc_gcj.h file.
    * boehm.cc: Remove 'extern "C"' for included boehm-gc/include header
    files (they are properly decorated inside now); remove include
    "gc_local_alloc.h" (as it is implicitly included now by
    boehm-gc/include/gc_gcj.h); include "gc_gcj.h" before any other
    boehm-gc header file (to let GC_GCJ_MALLOC be properly redefined to
    a thread-local allocator in boehm-gc/include/gc_local_alloc.h).
---
 boehm-gc/ChangeLog                | 14 ++++++++++++++
 boehm-gc/include/gc.h             | 22 ++++++++++++++--------
 boehm-gc/include/gc_gcj.h         | 12 ++++++++++++
 boehm-gc/include/gc_local_alloc.h |  8 ++++++++
 boehm-gc/include/gc_mark.h        |  9 ++++++++-
 boehm-gc/include/javaxfc.h        |  8 +++++++-
 libjava/ChangeLog                 | 13 +++++++++++++
 libjava/boehm.cc                  | 14 +++-----------
 8 files changed, 79 insertions(+), 21 deletions(-)

diff --git a/boehm-gc/ChangeLog b/boehm-gc/ChangeLog
index 532b889..8a4b8d6 100644
--- a/boehm-gc/ChangeLog
+++ b/boehm-gc/ChangeLog
@@ -1,3 +1,17 @@
+2015-12-05  Ivan Maidanski  <[email protected]>
+
+	* include/gc.h (GC_suspend_thread, GC_resume_thread,
+	GC_is_thread_suspended): Move inside 'extern "C"' block.
+	[GC_REDIRECT_TO_LOCAL]: Include gc_local_alloc.h outside 'extern "C"'
+	block; do not include gc_local_alloc.h if gc.h is included from
+	gc_gcj.h (so that GC_[LOCAL_]GCJ_MALLOC to be defined after other GCJ
+	symbols).
+	* include/gc_gcj.h [__cplusplus]: Wrap all declarations into
+	'extern "C"' block.
+	* include/gc_local_alloc.h [__cplusplus]: Likewise.
+	* include/javaxfc.h [__cplusplus]: Likewise.
+	* include/gc_gcj.h [GC_REDIRECT_TO_LOCAL]: Include gc_local_alloc.h.
+
 2015-12-03  Ivan Maidanski  <[email protected]>
 
 	* include/gc.h (GC_set_free_space_divisor): Change return type from
diff --git a/boehm-gc/include/gc.h b/boehm-gc/include/gc.h
index d02dab2..f193065 100644
--- a/boehm-gc/include/gc.h
+++ b/boehm-gc/include/gc.h
@@ -1061,14 +1061,6 @@ GC_API void GC_register_has_static_roots_callback
 # include "gc_amiga_redirects.h"
 #endif
 
-#if defined(GC_REDIRECT_TO_LOCAL) && !defined(GC_LOCAL_ALLOC_H)
-#  include  "gc_local_alloc.h"
-#endif
-
-#ifdef __cplusplus
-    }  /* end of extern "C" */
-#endif
-
 /* External thread suspension support. These functions do not implement
  * suspension counts or any other higher-level abstraction. Threads which
  * have been suspended numerous times will resume with the very first call
@@ -1080,4 +1072,18 @@ GC_API void GC_suspend_thread GC_PROTO((pthread_t));
 GC_API void GC_resume_thread GC_PROTO((pthread_t));
 GC_API int GC_is_thread_suspended GC_PROTO((pthread_t));
 #endif
+
+#ifdef __cplusplus
+    } /* end of extern "C" */
+#endif
+
+#if defined(GC_REDIRECT_TO_LOCAL) && !defined(GC_LOCAL_ALLOC_H) \
+    && !defined(GC_GCJ_H)
+  /* In case of gc.h is included from gc_gcj.h file, gc_local_alloc.h	*/
+  /* should be included at the end of gc_gcj.h instead of gc.h to have	*/
+  /* all GCJ symbols defined before some of them are redefined to	*/
+  /* their thread-local counterparts.					*/
+# include "gc_local_alloc.h"
+#endif
+
 #endif /* _GC_H */
diff --git a/boehm-gc/include/gc_gcj.h b/boehm-gc/include/gc_gcj.h
index 5e79e27..b771734 100644
--- a/boehm-gc/include/gc_gcj.h
+++ b/boehm-gc/include/gc_gcj.h
@@ -44,6 +44,10 @@
 #   include "gc.h"
 #endif
 
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
 /* The following allocators signal an out of memory condition with	*/
 /* return GC_oom_fn(bytes);						*/
 
@@ -110,4 +114,12 @@ extern int GC_gcj_debug_kind;
 	GC_gcj_malloc_ignore_off_page(s,d)
 # endif
 
+#ifdef __cplusplus
+  } /* end of extern "C" */
+#endif
+
+#if defined(GC_REDIRECT_TO_LOCAL)
+# include "gc_local_alloc.h"
+#endif
+
 #endif /* GC_GCJ_H */
diff --git a/boehm-gc/include/gc_local_alloc.h b/boehm-gc/include/gc_local_alloc.h
index 1874c7b..e4fe205 100644
--- a/boehm-gc/include/gc_local_alloc.h
+++ b/boehm-gc/include/gc_local_alloc.h
@@ -49,6 +49,10 @@
 #   include "gc_gcj.h"
 #endif
 
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
 /* We assume ANSI C for this interface.	*/
 
 GC_PTR GC_local_malloc(size_t bytes);
@@ -86,4 +90,8 @@ GC_PTR GC_local_malloc_atomic(size_t bytes);
 #   endif
 # endif
 
+#ifdef __cplusplus
+  } /* end of extern "C" */
+#endif
+
 #endif /* GC_LOCAL_ALLOC_H */
diff --git a/boehm-gc/include/gc_mark.h b/boehm-gc/include/gc_mark.h
index 953bb74..7c92946 100644
--- a/boehm-gc/include/gc_mark.h
+++ b/boehm-gc/include/gc_mark.h
@@ -29,6 +29,10 @@
 #   include "gc.h"
 # endif
 
+# ifdef __cplusplus
+    extern "C" {
+# endif
+
 /* A client supplied mark procedure.  Returns new mark stack pointer.	*/
 /* Primary effect should be to push new entries on the mark stack.	*/
 /* Mark stack pointer values are passed and returned explicitly.	*/
@@ -199,5 +203,8 @@ void GC_register_describe_type_fn GC_PROTO((int kind, GC_describe_type_fn knd));
 				/* to be used when printing objects	*/
 				/* of a particular kind.		*/
 
-#endif  /* GC_MARK_H */
+# ifdef __cplusplus
+    } /* end of extern "C" */
+# endif
 
+#endif  /* GC_MARK_H */
diff --git a/boehm-gc/include/javaxfc.h b/boehm-gc/include/javaxfc.h
index 23e0100..669ba64 100644
--- a/boehm-gc/include/javaxfc.h
+++ b/boehm-gc/include/javaxfc.h
@@ -2,6 +2,10 @@
 #   include "gc.h"
 # endif
 
+#ifdef __cplusplus
+  extern "C" {
+#endif
+
 /*
  * Invoke all remaining finalizers that haven't yet been run.
  * This is needed for strict compliance with the Java standard, 
@@ -18,4 +22,6 @@
  */
 void GC_finalize_all();
 
-
+#ifdef __cplusplus
+  } /* end of extern "C" */
+#endif
diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index e98fe56..28adfaf 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,3 +1,16 @@
+2015-12-05  Ivan Maidanski  <[email protected]>
+
+	* boehm.cc (GC_enable, GC_disable): Remove prototype (as declared in
+	boehm-gc/include/gc.h).
+	[THREAD_LOCAL_ALLOC] (GC_REDIRECT_TO_LOCAL): Define before include
+	gc_gcj.h file.
+	* boehm.cc: Remove 'extern "C"' for included boehm-gc/include header
+	files (they are properly decorated inside now); remove include
+	"gc_local_alloc.h" (as it is implicitly included now by
+	boehm-gc/include/gc_gcj.h); include "gc_gcj.h" before any other
+	boehm-gc header file (to let GC_GCJ_MALLOC be properly redefined to
+	a thread-local allocator in boehm-gc/include/gc_local_alloc.h).
+
 2015-12-03  Ivan Maidanski  <[email protected]>
 
 	* boehm.cc (_Jv_SetGCFreeSpaceDivisor): Use GC_get_free_space_divisor
diff --git a/libjava/boehm.cc b/libjava/boehm.cc
index 34a6ead..39563f0 100644
--- a/libjava/boehm.cc
+++ b/libjava/boehm.cc
@@ -38,8 +38,6 @@ details.  */
 #include <dlfcn.h>
 #endif
 
-extern "C"
-{
 #include <gc_config.h>
 
 // Set GC_DEBUG before including gc.h!
@@ -47,19 +45,13 @@ extern "C"
 # define GC_DEBUG
 #endif
 
-#include <gc_mark.h>
-#include <gc_gcj.h>
-#include <javaxfc.h>  // GC_finalize_all declaration.  
-
 #ifdef THREAD_LOCAL_ALLOC
 # define GC_REDIRECT_TO_LOCAL
-# include <gc_local_alloc.h>
 #endif
+#include <gc_gcj.h> // includes gc.h and gc_local_alloc.h
 
-  // From boehm's misc.c 
-  void GC_enable();
-  void GC_disable();
-};
+#include <gc_mark.h>
+#include <javaxfc.h>  // GC_finalize_all declaration.
 
 #define MAYBE_MARK(Obj, Top, Limit, Source)  \
 	Top=GC_MARK_AND_PUSH((GC_PTR) Obj, Top, Limit, (GC_PTR *) Source)
-- 
2.8.2
0004-Change-GC_-un-register_my_thread-prototy pes-in-boehm.patch (application/x-patch, 9.2 KB)
From 270c3e2c4c2f314b9ee083350f4670cbac167424 Mon Sep 17 00:00:00 2001
From: Ivan Maidanski <[email protected]>
Date: Thu, 17 Dec 2015 00:51:21 +0300
Subject: [PATCH 4/4] Change GC_[un]register_my_thread prototypes in boehm-gc
 (code refactoring to match BDWGC v7 API)

boehm-gc/
    * include/gc.h (GC_DUPLICATE): New public macro.
    (GC_register_my_thread): Change prototype (accept GC_stack_base*).
    (GC_register_my_thread, GC_unregister_my_thread): Change prototype
    (return operation completion status); update comment.
    * pthread_support.c (GC_register_my_thread): Change prototype; change
    "sb" type to pointer; do not call GC_get_stack_base (it is called by
    GC_register_my_thread caller now); return GC_DUPLICATE or GC_SUCCESS.
    (GC_unregister_my_thread): Change prototype; return GC_SUCCESS.
    * win32_threads.c (GC_register_my_thread, GC_unregister_my_thread):
    New function (stub returning GC_DUPLICATE if threads are registered
    implicitly otherwise GC_UNIMPLEMENTED).

libjava/
    * boehm.cc (_Jv_GCAttachThread, _Jv_GCDetachThread): Do not test
    HAVE_PTHREAD_GETATTR_NP and GC_SOLARIS_THREADS macros, test
    GC_PTHREADS macro instead (i.e., invoke GC thread register/unregister
    for all multi-threaded targets); remove the relevant comment.
    (_Jv_GCAttachThread): Declare "sb" local variable; invoke
    GC_get_stack_base (pass obtained stack base to GC_register_my_thread);
    call JvFail with the appropriate message in case of GC_get_stack_base
    or GC_register_my_thread failure (but handle properly the case when
    GC_get_stack_base returns GC_UNIMPLEMENTED but the thread is already
    registered implicitly).
---
 boehm-gc/ChangeLog         | 14 ++++++++++++++
 boehm-gc/include/gc.h      | 15 +++++++--------
 boehm-gc/pthread_support.c | 17 +++++++----------
 boehm-gc/win32_threads.c   | 17 +++++++++++++++++
 libjava/ChangeLog          | 13 +++++++++++++
 libjava/boehm.cc           | 22 ++++++++++++++--------
 6 files changed, 72 insertions(+), 26 deletions(-)

diff --git a/boehm-gc/ChangeLog b/boehm-gc/ChangeLog
index af44b3e..4e0483a 100644
--- a/boehm-gc/ChangeLog
+++ b/boehm-gc/ChangeLog
@@ -1,3 +1,17 @@
+2015-12-17  Ivan Maidanski  <[email protected]>
+
+	* include/gc.h (GC_DUPLICATE): New public macro.
+	(GC_register_my_thread): Change prototype (accept GC_stack_base*).
+	(GC_register_my_thread, GC_unregister_my_thread): Change prototype
+	(return operation completion status); update comment.
+	* pthread_support.c (GC_register_my_thread): Change prototype; change
+	"sb" type to pointer; do not call GC_get_stack_base (it is called by
+	GC_register_my_thread caller now); return GC_DUPLICATE or GC_SUCCESS.
+	(GC_unregister_my_thread): Change prototype; return GC_SUCCESS.
+	* win32_threads.c (GC_register_my_thread, GC_unregister_my_thread):
+	New function (stub returning GC_DUPLICATE if threads are registered
+	implicitly otherwise GC_UNIMPLEMENTED).
+
 2015-12-10  Ivan Maidanski  <[email protected]>
 
 	* AmigaOS.c (GC_get_stack_base): Rename to GC_get_main_stack_base.
diff --git a/boehm-gc/include/gc.h b/boehm-gc/include/gc.h
index 6ba20e6..99adedd 100644
--- a/boehm-gc/include/gc.h
+++ b/boehm-gc/include/gc.h
@@ -935,6 +935,7 @@ struct GC_stack_base {
 };
 
 #define GC_SUCCESS 0
+#define GC_DUPLICATE 1		/* Was already registered.		*/
 #define GC_UNIMPLEMENTED 3	/* Not yet implemented on the platform.	*/
 
 /* Attempt to fill in the GC_stack_base structure with the stack base	*/
@@ -954,15 +955,13 @@ GC_API int GC_get_stack_base GC_PROTO((struct GC_stack_base *));
 /* a thread can allocate garbage collected memory, or assign pointers	*/
 /* to the garbage collected heap.  Once registered, a thread will be	*/
 /* stopped during garbage collections.					*/
-GC_API void GC_register_my_thread GC_PROTO((void));
+/* Returns GC_SUCCESS on success, GC_DUPLICATE if already done. 	*/
+/* On some platforms it returns GC_UNIMPLEMENTED.			*/
+GC_API int GC_register_my_thread GC_PROTO((struct GC_stack_base *));
 
-/* Register the current thread, with the indicated stack base, as	*/
-/* a new thread whose stack(s) should be traced by the GC.  If a 	*/
-/* platform does not implicitly do so, this must be called before a	*/
-/* thread can allocate garbage collected memory, or assign pointers	*/
-/* to the garbage collected heap.  Once registered, a thread will be	*/
-/* stopped during garbage collections.					*/
-GC_API void GC_unregister_my_thread GC_PROTO((void));
+/* Unregister the current thread.					*/
+/* Returns GC_SUCCESS or GC_UNIMPLEMENTED.				*/
+GC_API int GC_unregister_my_thread GC_PROTO((void));
 
 /* This returns a list of objects, linked through their first		*/
 /* word.  Its use can greatly reduce lock contention problems, since	*/
diff --git a/boehm-gc/pthread_support.c b/boehm-gc/pthread_support.c
index e077abb..acb1a55 100644
--- a/boehm-gc/pthread_support.c
+++ b/boehm-gc/pthread_support.c
@@ -1170,15 +1170,10 @@ int GC_get_stack_base(struct GC_stack_base *sb)
 # endif
 }
 
-void GC_register_my_thread()
+int GC_register_my_thread(struct GC_stack_base *sb)
 {
   GC_thread me;
   pthread_t my_pthread;
-# if !defined(GC_DARWIN_THREADS) || defined(IA64)
-    struct GC_stack_base sb;
-    if (GC_get_stack_base(&sb) == GC_UNIMPLEMENTED)
-      ABORT("Can not determine stack base for attached thread");
-# endif
 
   my_pthread = pthread_self();
 #   ifdef DEBUG_THREADS
@@ -1195,7 +1190,7 @@ void GC_register_my_thread()
 #   ifdef DEBUG_THREADS
       GC_printf1("Attempt to re-attach known thread 0x%lx\n", my_pthread);
 #   endif
-      return;
+      return GC_DUPLICATE;
     }
 
   LOCK();
@@ -1208,7 +1203,7 @@ void GC_register_my_thread()
 #ifdef GC_DARWIN_THREADS
     me -> stop_info.mach_thread = mach_thread_self();
 #else
-    me -> stack_end = sb.mem_base;
+    me -> stack_end = sb -> mem_base;
     
 #   ifdef STACK_GROWS_DOWN
       me -> stop_info.stack_ptr = me -> stack_end - 0x10;
@@ -1218,16 +1213,17 @@ void GC_register_my_thread()
 #endif
 
 #   ifdef IA64
-      me -> backing_store_end = sb.reg_base;
+      me -> backing_store_end = sb -> reg_base;
 #   endif /* IA64 */
 
 #   if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
         GC_init_thread_local(me);
 #   endif
   UNLOCK();
+  return GC_SUCCESS;
 }
 
-void GC_unregister_my_thread()
+int GC_unregister_my_thread GC_PROTO((void))
 {
   pthread_t my_pthread;
 
@@ -1238,6 +1234,7 @@ void GC_unregister_my_thread()
 #   endif
 
   GC_thread_exit_proc (0);
+  return GC_SUCCESS;
 }
 
 void * GC_start_routine(void * arg)
diff --git a/boehm-gc/win32_threads.c b/boehm-gc/win32_threads.c
index 354e5a7..a32bf8d 100644
--- a/boehm-gc/win32_threads.c
+++ b/boehm-gc/win32_threads.c
@@ -527,6 +527,23 @@ static DWORD WINAPI thread_start(LPVOID arg)
 
 #endif /* !CYGWIN32 */
 
+int GC_register_my_thread(struct GC_stack_base *sb)
+{
+#   if defined(GC_DLL) && !defined(CYGWIN32) && !defined(MSWINCE)
+	/* Registered by DllMain. */
+	return GC_DUPLICATE;
+#   else
+	/* TODO: Implement. */
+	return GC_UNIMPLEMENTED;
+#   endif
+}
+
+int GC_unregister_my_thread GC_PROTO((void))
+{
+    /* TODO: Implement. */
+    return GC_UNIMPLEMENTED;
+}
+
 #ifdef MSWINCE
 
 typedef struct {
diff --git a/libjava/ChangeLog b/libjava/ChangeLog
index 28adfaf..7f52a3f 100644
--- a/libjava/ChangeLog
+++ b/libjava/ChangeLog
@@ -1,3 +1,16 @@
+2015-12-17  Ivan Maidanski  <[email protected]>
+
+	* boehm.cc (_Jv_GCAttachThread, _Jv_GCDetachThread): Do not test
+	HAVE_PTHREAD_GETATTR_NP and GC_SOLARIS_THREADS macros, test
+	GC_PTHREADS macro instead (i.e., invoke GC thread register/unregister
+	for all multi-threaded targets); remove the relevant comment.
+	(_Jv_GCAttachThread): Declare "sb" local variable; invoke
+	GC_get_stack_base (pass obtained stack base to GC_register_my_thread);
+	call JvFail with the appropriate message in case of GC_get_stack_base
+	or GC_register_my_thread failure (but handle properly the case when
+	GC_get_stack_base returns GC_UNIMPLEMENTED but the thread is already
+	registered implicitly).
+
 2015-12-05  Ivan Maidanski  <[email protected]>
 
 	* boehm.cc (GC_enable, GC_disable): Remove prototype (as declared in
diff --git a/libjava/boehm.cc b/libjava/boehm.cc
index 39563f0..4ec91af 100644
--- a/libjava/boehm.cc
+++ b/libjava/boehm.cc
@@ -738,20 +738,26 @@ _Jv_IsThreadSuspended (_Jv_Thread_t *thread)
 void
 _Jv_GCAttachThread ()
 {
-  // The registration interface is only defined on posixy systems and
-  // only actually works if pthread_getattr_np is defined.
-  // FIXME: until gc7 it is simpler to disable this on solaris.
-#if defined(HAVE_PTHREAD_GETATTR_NP) && !defined(GC_SOLARIS_THREADS) \
-    && !defined(GC_WIN32_THREADS)
-  GC_register_my_thread ();
+#if defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
+  struct GC_stack_base sb;
+
+  if (GC_get_stack_base (&sb) == GC_UNIMPLEMENTED)
+    {
+      // Do not fail in case of implicitly registered threads.
+      sb.mem_base = &sb;
+      if (GC_register_my_thread (&sb) != GC_DUPLICATE)
+        JvFail ("Cannot determine stack base for attached thread");
+      return;
+    }
+  if (GC_register_my_thread (&sb) == GC_UNIMPLEMENTED)
+    JvFail ("Cannot attach thread");
 #endif
 }
 
 void
 _Jv_GCDetachThread ()
 {
-#if defined(HAVE_PTHREAD_GETATTR_NP) && !defined(GC_SOLARIS_THREADS) \
-    && !defined(GC_WIN32_THREADS)
+#if defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
   GC_unregister_my_thread ();
 #endif
 }
-- 
2.8.2
0003-Change-GC_get_-thread-main_-stack_base-p rototypes.patch (application/x-patch, 16 KB)
From 5109009195e8d53597edce62778ed4466e811fc1 Mon Sep 17 00:00:00 2001
From: Ivan Maidanski <[email protected]>
Date: Thu, 10 Dec 2015 21:46:54 +0300
Subject: [PATCH 3/4] Change GC_get_[thread/main_]stack_base prototypes (code
 refactoring to match BDWGC v7 API)

GC_get_stack_base renamed to GC_get_main_stack_base;
ptr_t GC_get_thread_stack_base() public prototype changed to
int GC_get_stack_base(struct GC_stack_base*);
GC_get_stack_base now defined for all targets (but returns
GC_UNIMPLEMENTED if no implementation for the target).

boehm-gc/
    * AmigaOS.c (GC_get_stack_base): Rename to GC_get_main_stack_base.
    * include/private/gc_priv.h (GC_get_stack_base): Likewise.
    * include/gc.h (struct GC_stack_base): New public type.
    (GC_SUCCESS, GC_UNIMPLEMENTED): New public macro.
    (GC_get_thread_stack_base): Replace with
    int GC_get_stack_base(struct GC_stack_base*); declare even in
    a single-threaded case; refine comment.
    * misc.c (GC_init_inner): Rename GC_get_stack_base to
    GC_get_main_stack_base.
    (GC_init_inner): Replace GC_get_thread_stack_base to
    GC_get_stack_base.
    * win32_threads.c [CYGWIN32] (GC_get_thread_stack_base): Likewise.
    * os_dep.c [MSWIN32 || MSWINCE || BEOS || OS2] (GC_get_stack_base):
    Accommodate to GC_get_stack_base prototype change.
    * win32_threads.c (GC_new_thread): Likewise.
    * os_dep.c (HAVE_GET_STACK_BASE): Define in every case when
    target-specific GC_get_stack_base is defined (including for cases
    when GC_get_stack_base is pthread_support.c or win32_threads.c).
    (GC_get_stack_base): Rename to GC_get_main_stack_base (except for
    Win32, WinCE, BeOS and OS/2).
    (GET_MAIN_STACKBASE_SPECIAL): Define in every case when
    target-specific GC_get_main_stack_base is defined.
    [!HAVE_GET_STACK_BASE] (GC_get_stack_base): Define with the default
    implementation.
    [!GET_MAIN_STACKBASE_SPECIAL] (GC_get_main_stack_base): Likewise.
    * pthread_support.c (GC_get_thread_stack_base): Replace to
    GC_get_stack_base; set reg_base for IA64.
    [!GC_DARWIN_THREADS] (GC_register_my_thread): Call GC_get_stack_base
    instead of GC_get_thread_stack_base and GC_save_regs_in_stack.
---
 boehm-gc/AmigaOS.c                 |  4 +--
 boehm-gc/ChangeLog                 | 32 +++++++++++++++++++
 boehm-gc/include/gc.h              | 20 ++++++++++--
 boehm-gc/include/private/gc_priv.h |  2 +-
 boehm-gc/misc.c                    |  8 +++--
 boehm-gc/os_dep.c                  | 63 ++++++++++++++++++++++++++++++++------
 boehm-gc/pthread_support.c         | 30 ++++++++++--------
 boehm-gc/win32_threads.c           | 14 +++++----
 8 files changed, 139 insertions(+), 34 deletions(-)

diff --git a/boehm-gc/AmigaOS.c b/boehm-gc/AmigaOS.c
index f4024a7..b76f446 100644
--- a/boehm-gc/AmigaOS.c
+++ b/boehm-gc/AmigaOS.c
@@ -40,7 +40,7 @@
    Find the base of the stack.
 ******************************************************************/
 
-ptr_t GC_get_stack_base()
+ptr_t GC_get_main_stack_base()
 {
     struct Process *proc = (struct Process*)SysBase->ThisTask;
  
@@ -58,7 +58,7 @@ ptr_t GC_get_stack_base()
 }
 
 #if 0 /* old version */
-ptr_t GC_get_stack_base()
+ptr_t GC_get_main_stack_base()
 {
     extern struct WBStartup *_WBenchMsg;
     extern long __base;
diff --git a/boehm-gc/ChangeLog b/boehm-gc/ChangeLog
index 8a4b8d6..af44b3e 100644
--- a/boehm-gc/ChangeLog
+++ b/boehm-gc/ChangeLog
@@ -1,3 +1,35 @@
+2015-12-10  Ivan Maidanski  <[email protected]>
+
+	* AmigaOS.c (GC_get_stack_base): Rename to GC_get_main_stack_base.
+	* include/private/gc_priv.h (GC_get_stack_base): Likewise.
+	* include/gc.h (struct GC_stack_base): New public type.
+	(GC_SUCCESS, GC_UNIMPLEMENTED): New public macro.
+	(GC_get_thread_stack_base): Replace with
+	int GC_get_stack_base(struct GC_stack_base*); declare even in
+	a single-threaded case; refine comment.
+	* misc.c (GC_init_inner): Rename GC_get_stack_base to
+	GC_get_main_stack_base.
+	(GC_init_inner): Replace GC_get_thread_stack_base to
+	GC_get_stack_base.
+	* win32_threads.c [CYGWIN32] (GC_get_thread_stack_base): Likewise.
+	* os_dep.c [MSWIN32 || MSWINCE || BEOS || OS2] (GC_get_stack_base):
+	Accommodate to GC_get_stack_base prototype change.
+	* win32_threads.c (GC_new_thread): Likewise.
+	* os_dep.c (HAVE_GET_STACK_BASE): Define in every case when
+	target-specific GC_get_stack_base is defined (including for cases
+	when GC_get_stack_base is pthread_support.c or win32_threads.c).
+	(GC_get_stack_base): Rename to GC_get_main_stack_base (except for
+	Win32, WinCE, BeOS and OS/2).
+	(GET_MAIN_STACKBASE_SPECIAL): Define in every case when
+	target-specific GC_get_main_stack_base is defined.
+	[!HAVE_GET_STACK_BASE] (GC_get_stack_base): Define with the default
+	implementation.
+	[!GET_MAIN_STACKBASE_SPECIAL] (GC_get_main_stack_base): Likewise.
+	* pthread_support.c (GC_get_thread_stack_base): Replace to
+	GC_get_stack_base; set reg_base for IA64.
+	[!GC_DARWIN_THREADS] (GC_register_my_thread): Call GC_get_stack_base
+	instead of GC_get_thread_stack_base and GC_save_regs_in_stack.
+
 2015-12-05  Ivan Maidanski  <[email protected]>
 
 	* include/gc.h (GC_suspend_thread, GC_resume_thread,
diff --git a/boehm-gc/include/gc.h b/boehm-gc/include/gc.h
index f193065..6ba20e6 100644
--- a/boehm-gc/include/gc.h
+++ b/boehm-gc/include/gc.h
@@ -926,6 +926,24 @@ GC_API void (*GC_is_visible_print_proc)
 # include "gc_pthread_redirects.h"
 #endif
 
+/* Structure representing the base of a thread stack.			*/
+struct GC_stack_base {
+    void * mem_base; /* Base of memory stack. */
+#   if defined(__ia64) || defined(__ia64__) || defined(_M_IA64)
+	void * reg_base; /* Base of separate register stack. */
+#   endif
+};
+
+#define GC_SUCCESS 0
+#define GC_UNIMPLEMENTED 3	/* Not yet implemented on the platform.	*/
+
+/* Attempt to fill in the GC_stack_base structure with the stack base	*/
+/* for this thread.  This appears to be required to implement anything	*/
+/* like the JNI AttachCurrentThread in an environment in which new	*/
+/* threads are not automatically registered with the collector. 	*/
+/* Returns GC_SUCCESS or GC_UNIMPLEMENTED.				*/
+GC_API int GC_get_stack_base GC_PROTO((struct GC_stack_base *));
+
 # if defined(PCR) || defined(GC_SOLARIS_THREADS) || \
      defined(GC_PTHREADS) || defined(GC_WIN32_THREADS)
    	/* Any flavor of threads except SRC_M3.	*/
@@ -946,8 +964,6 @@ GC_API void GC_register_my_thread GC_PROTO((void));
 /* stopped during garbage collections.					*/
 GC_API void GC_unregister_my_thread GC_PROTO((void));
 
-GC_API GC_PTR GC_get_thread_stack_base GC_PROTO((void));
-
 /* This returns a list of objects, linked through their first		*/
 /* word.  Its use can greatly reduce lock contention problems, since	*/
 /* the allocation lock can be acquired and released many fewer times.	*/
diff --git a/boehm-gc/include/private/gc_priv.h b/boehm-gc/include/private/gc_priv.h
index 4dbfa7d..a6fda46 100644
--- a/boehm-gc/include/private/gc_priv.h
+++ b/boehm-gc/include/private/gc_priv.h
@@ -1493,7 +1493,7 @@ GC_bool GC_register_main_static_data GC_PROTO((void));
 		/* dynamic library registration.			*/
   
 /* Machine dependent startup routines */
-ptr_t GC_get_stack_base GC_PROTO((void));	/* Cold end of stack */
+ptr_t GC_get_main_stack_base GC_PROTO((void));	/* Cold end of stack */
 #ifdef IA64
   ptr_t GC_get_register_stack_base GC_PROTO((void));
   					/* Cold end of register stack.	*/
diff --git a/boehm-gc/misc.c b/boehm-gc/misc.c
index c1faed0..0f4edff 100644
--- a/boehm-gc/misc.c
+++ b/boehm-gc/misc.c
@@ -677,10 +677,14 @@ void GC_init_inner()
         # if defined(GC_PTHREADS) && ! defined(GC_SOLARIS_THREADS)
 	/* Use thread_stack_base if available, as GC could be initialized from
 	   a thread that is not the "main" thread.  */
-	GC_stackbottom = GC_get_thread_stack_base();
+	  struct GC_stack_base sb;
+	  sb.mem_base = NULL;
+	  (void)GC_get_stack_base(&sb);
+		/* In case of failure, mem_base remains NULL.		*/
+	  GC_stackbottom = sb.mem_base;
 	# endif
 	if (GC_stackbottom == 0)
-	  GC_stackbottom = GC_get_stack_base();
+	  GC_stackbottom = GC_get_main_stack_base();
 #       if (defined(LINUX) || defined(HPUX)) && defined(IA64)
 	  GC_register_stackbottom = GC_get_register_stack_base();
 #       endif
diff --git a/boehm-gc/os_dep.c b/boehm-gc/os_dep.c
index 60cbc2b..f8da082 100644
--- a/boehm-gc/os_dep.c
+++ b/boehm-gc/os_dep.c
@@ -639,42 +639,53 @@ word GC_get_writable_length(ptr_t p, ptr_t *base)
     return(buf.RegionSize);
 }
 
-ptr_t GC_get_stack_base()
+int GC_get_stack_base(struct GC_stack_base *sb)
 {
     int dummy;
     ptr_t sp = (ptr_t)(&dummy);
     ptr_t trunc_sp = (ptr_t)((word)sp & ~(GC_page_size - 1));
     word size = GC_get_writable_length(trunc_sp, 0);
    
-    return(trunc_sp + size);
+    sb -> mem_base = trunc_sp + size;
+    return GC_SUCCESS;
 }
+#   define HAVE_GET_STACK_BASE
 
+# elif defined(CYGWIN32) && defined(GC_WIN32_THREADS)
+
+    /* GC_get_stack_base() is defined in win32_threads.c.	*/
+#   define HAVE_GET_STACK_BASE
 
 # endif /* MS Windows */
 
 # ifdef BEOS
 # include <kernel/OS.h>
-ptr_t GC_get_stack_base(){
+int GC_get_stack_base(struct GC_stack_base *sb)
+{
 	thread_info th;
 	get_thread_info(find_thread(NULL),&th);
-	return th.stack_end;
+	sb -> mem_base = th.stack_end;
+	return GC_SUCCESS;
 }
+#   define HAVE_GET_STACK_BASE
 # endif /* BEOS */
 
 
 # ifdef OS2
 
-ptr_t GC_get_stack_base()
+int GC_get_stack_base(struct GC_stack_base *sb)
 {
     PTIB ptib;
     PPIB ppib;
     
     if (DosGetInfoBlocks(&ptib, &ppib) != NO_ERROR) {
     	GC_err_printf0("DosGetInfoBlocks failed\n");
-    	ABORT("DosGetInfoBlocks failed\n");
+	return GC_UNIMPLEMENTED;
     }
-    return((ptr_t)(ptib -> tib_pstacklimit));
+    sb -> mem_base = (void *)(ptib -> tib_pstacklimit);
+    return GC_SUCCESS;
 }
+#   define HAVE_GET_STACK_BASE
 
 # endif /* OS2 */
 
@@ -682,6 +693,7 @@ ptr_t GC_get_stack_base()
 #   define GC_AMIGA_SB
 #   include "AmigaOS.c"
 #   undef GC_AMIGA_SB
+#   define GET_MAIN_STACKBASE_SPECIAL
 # endif /* AMIGA */
 
 # if defined(NEED_FIND_LIMIT) || defined(UNIX_LIKE)
@@ -819,10 +831,11 @@ ptr_t GC_get_stack_base()
 # endif
 
 #if defined(ECOS) || defined(NOSYS)
-  ptr_t GC_get_stack_base()
+  ptr_t GC_get_main_stack_base GC_PROTO((void))
   {
     return STACKBOTTOM;
   }
+# define GET_MAIN_STACKBASE_SPECIAL
 #endif
 
 #ifdef HPUX_STACKBOTTOM
@@ -1059,7 +1072,7 @@ ptr_t GC_get_stack_base()
 #if !defined(BEOS) && !defined(AMIGA) && !defined(MSWIN32) \
     && !defined(MSWINCE) && !defined(OS2) && !defined(NOSYS) && !defined(ECOS)
 
-ptr_t GC_get_stack_base()
+ptr_t GC_get_main_stack_base GC_PROTO((void))
 {
 #   if defined(HEURISTIC1) || defined(HEURISTIC2) || \
        defined(LINUX_STACKBOTTOM) || defined(FREEBSD_STACKBOTTOM) || \
@@ -1118,9 +1131,41 @@ ptr_t GC_get_stack_base()
     	return(result);
 #   endif /* STACKBOTTOM */
 }
+#   define GET_MAIN_STACKBASE_SPECIAL
 
 # endif /* ! AMIGA, !OS 2, ! MS Windows, !BEOS, !NOSYS, !ECOS */
 
+#if defined(GC_PTHREADS) && !defined(GC_SOLARIS_THREADS) \
+    && !defined(GC_WIN32_THREADS)
+    /* GC_get_stack_base() is defined in pthread_support.c.	*/
+#   define HAVE_GET_STACK_BASE
+#endif
+
+#ifndef HAVE_GET_STACK_BASE
+    int GC_get_stack_base(struct GC_stack_base *sb)
+    {
+#     if defined(GET_MAIN_STACKBASE_SPECIAL) && !defined(THREADS) \
+	 && !defined(IA64)
+	sb->mem_base = GC_get_main_stack_base();
+	return GC_SUCCESS;
+#     else
+	return GC_UNIMPLEMENTED;
+#     endif
+    }
+#endif /* !HAVE_GET_STACK_BASE */
+
+#ifndef GET_MAIN_STACKBASE_SPECIAL
+  /* This is always called from the main thread.  Default implementation. */
+  ptr_t GC_get_main_stack_base GC_PROTO((void))
+  {
+    struct GC_stack_base sb;
+
+    if (GC_get_stack_base(&sb) != GC_SUCCESS)
+      ABORT("GC_get_stack_base failed");
+    return (ptr_t)sb.mem_base;
+  }
+#endif /* !GET_MAIN_STACKBASE_SPECIAL */
+
 /*
  * Register static data segment(s) as roots.
  * If more data segments are added later then they need to be registered
diff --git a/boehm-gc/pthread_support.c b/boehm-gc/pthread_support.c
index 6d8f020..e077abb 100644
--- a/boehm-gc/pthread_support.c
+++ b/boehm-gc/pthread_support.c
@@ -1127,7 +1127,7 @@ WRAP_FUNC(pthread_detach)(pthread_t thread)
 
 GC_bool GC_in_thread_creation = FALSE;
 
-GC_PTR GC_get_thread_stack_base()
+int GC_get_stack_base(struct GC_stack_base *sb)
 {  
 # ifdef HAVE_PTHREAD_GETATTR_NP
   pthread_t my_pthread;
@@ -1141,7 +1141,7 @@ GC_PTR GC_get_thread_stack_base()
 #   ifdef DEBUG_THREADS
       GC_printf0("Can not determine stack base for attached thread");
 #   endif
-      return 0;
+      return GC_UNIMPLEMENTED;
     }
   pthread_attr_getstack (&attr, (void **) &stack_addr, &stack_size);
   pthread_attr_destroy (&attr);
@@ -1151,16 +1151,22 @@ GC_PTR GC_get_thread_stack_base()
 #   endif
 
 #   ifdef STACK_GROWS_DOWN
-      return stack_addr + stack_size;
+      sb -> mem_base = stack_addr + stack_size;
 #   else
-      return stack_addr;
+      sb -> mem_base = stack_addr;
 #   endif
+#   ifdef IA64
+      sb -> reg_base = (void*)(GC_save_regs_in_stack() & ~(GC_page_size - 1));
+	/* This is not 100% convincing.  We should also read this	*/
+	/* from /proc, but the hook to do so isn't there yet.		*/
+#   endif
+    return GC_SUCCESS;
 
 # else
 #   ifdef DEBUG_THREADS
 	GC_printf0("Can not determine stack base for attached thread");
 #   endif
-  return 0;
+    return GC_UNIMPLEMENTED;
 # endif
 }
 
@@ -1168,6 +1174,11 @@ void GC_register_my_thread()
 {
   GC_thread me;
   pthread_t my_pthread;
+# if !defined(GC_DARWIN_THREADS) || defined(IA64)
+    struct GC_stack_base sb;
+    if (GC_get_stack_base(&sb) == GC_UNIMPLEMENTED)
+      ABORT("Can not determine stack base for attached thread");
+# endif
 
   my_pthread = pthread_self();
 #   ifdef DEBUG_THREADS
@@ -1197,9 +1208,7 @@ void GC_register_my_thread()
 #ifdef GC_DARWIN_THREADS
     me -> stop_info.mach_thread = mach_thread_self();
 #else
-    me -> stack_end = GC_get_thread_stack_base();    
-    if (me -> stack_end == 0)
-      GC_abort("Can not determine stack base for attached thread");
+    me -> stack_end = sb.mem_base;
     
 #   ifdef STACK_GROWS_DOWN
       me -> stop_info.stack_ptr = me -> stack_end - 0x10;
@@ -1209,10 +1218,7 @@ void GC_register_my_thread()
 #endif
 
 #   ifdef IA64
-      me -> backing_store_end = (ptr_t)
-			(GC_save_regs_in_stack() & ~(GC_page_size - 1));
-      /* This is also < 100% convincing.  We should also read this 	*/
-      /* from /proc, but the hook to do so isn't there yet.		*/
+      me -> backing_store_end = sb.reg_base;
 #   endif /* IA64 */
 
 #   if defined(THREAD_LOCAL_ALLOC) && !defined(DBG_HDRS_ALL)
diff --git a/boehm-gc/win32_threads.c b/boehm-gc/win32_threads.c
index 2de1c69..354e5a7 100644
--- a/boehm-gc/win32_threads.c
+++ b/boehm-gc/win32_threads.c
@@ -80,6 +80,7 @@ extern LONG WINAPI GC_write_fault_handler(struct _EXCEPTION_POINTERS *exc_info);
  */
 static GC_thread GC_new_thread(void) {
   int i;
+  struct GC_stack_base sb;
   /* 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	*/
@@ -131,11 +132,11 @@ static GC_thread GC_new_thread(void) {
 	GC_printf1("Last error code: %lx\n", last_error);
 	ABORT("DuplicateHandle failed");
   }
-  thread_table[i].stack_base = GC_get_stack_base();
+  if (GC_get_stack_base(&sb) == GC_UNIMPLEMENTED)
+    ABORT("Failed to find stack base in GC_new_thread");
+  thread_table[i].stack_base = sb.mem_base;
   /* Up until this point, GC_push_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();
@@ -757,14 +758,15 @@ int GC_pthread_detach(pthread_t thread)
     return result;
 }
 
-GC_PTR GC_get_thread_stack_base()
+int GC_get_stack_base(struct GC_stack_base *sb)
 {
 #ifdef __x86_64__
-  return ((NT_TIB*)NtCurrentTeb())->StackBase;
+  sb -> mem_base = ((NT_TIB*)NtCurrentTeb())->StackBase;
 #else
   extern GC_PTR _tlsbase __asm__ ("%fs:4");
-  return _tlsbase;
+  sb -> mem_base = _tlsbase;
 #endif
+  return GC_SUCCESS;
 }
 
 #else /* !CYGWIN32 */
-- 
2.8.2