From 8bc263a68ac3d99c2ce80acc4bdfb9b37d2ecfd5 Mon Sep 17 00:00:00 2001
From: Ivan Maidanski <ivmai@mail.ru>
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 9988605..35bd442 100644
--- a/boehm-gc/ChangeLog
+++ b/boehm-gc/ChangeLog
@@ -1,3 +1,35 @@
+2015-12-10  Ivan Maidanski  <ivmai@mail.ru>
+
+	* 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  <ivmai@mail.ru>
 
 	* 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.1.4

