From a01207c473dcab88eb0ac769d2d9c68d7c9e0588 Mon Sep 17 00:00:00 2001
From: Ian Lance Taylor <iant@google.com>
Date: Mon, 28 Nov 2011 05:44:31 +0000
Subject: [PATCH] generic-morestack.c (__splitstack_find): Check for NULL old
 stack value.

	* generic-morestack.c (__splitstack_find): Check for NULL old
	stack value.
	(__splitstack_resetcontext): New function.
	(__splitstack_releasecontext): New function.
	* libgcc-std.ver.in: Add new functions to GCC_4.7.0.

From-SVN: r181771
---
 libgcc/ChangeLog           |  8 ++++
 libgcc/generic-morestack.c | 76 ++++++++++++++++++++++++++++++++++++--
 libgcc/libgcc-std.ver.in   |  2 +
 3 files changed, 83 insertions(+), 3 deletions(-)

diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog
index 4217f323cf7f..4b244f41022c 100644
--- a/libgcc/ChangeLog
+++ b/libgcc/ChangeLog
@@ -1,3 +1,11 @@
+2011-11-27  Ian Lance Taylor  <iant@google.com>
+
+	* generic-morestack.c (__splitstack_find): Check for NULL old
+	stack value.
+	(__splitstack_resetcontext): New function.
+	(__splitstack_releasecontext): New function.
+	* libgcc-std.ver.in: Add new functions to GCC_4.7.0.
+
 2011-11-27  Iain Sandoe  <iains@gcc.gnu.org>
 
 	* config/darwin-crt-tm.c: Correct comments, use correct licence.
diff --git a/libgcc/generic-morestack.c b/libgcc/generic-morestack.c
index 00a3b1c3bf06..4dbaa0e4cdc9 100644
--- a/libgcc/generic-morestack.c
+++ b/libgcc/generic-morestack.c
@@ -115,6 +115,14 @@ extern void *
 __splitstack_makecontext (size_t, void *context[10], size_t *)
   __attribute__ ((visibility ("default")));
 
+extern void *
+__splitstack_resetcontext (void *context[10], size_t *)
+  __attribute__ ((visibility ("default")));
+
+extern void
+__splitstack_releasecontext (void *context[10])
+  __attribute__ ((visibility ("default")));
+
 extern void
 __splitstack_block_signals_context (void *context[10], int *, int *)
   __attribute__ ((visibility ("default")));
@@ -911,15 +919,23 @@ __splitstack_find (void *segment_arg, void *sp, size_t *len,
 
   nsp = (char *) segment->old_stack;
 
+  if (nsp == NULL)
+    {
+      /* We've reached the top of the stack.  */
+      *next_segment = (void *) (uintptr_type) 2;
+    }
+  else
+    {
 #if defined (__x86_64__)
-  nsp -= 12 * sizeof (void *);
+      nsp -= 12 * sizeof (void *);
 #elif defined (__i386__)
-  nsp -= 6 * sizeof (void *);
+      nsp -= 6 * sizeof (void *);
 #else
 #error "unrecognized target"
 #endif
 
-  *next_sp = (void *) nsp;
+      *next_sp = (void *) nsp;
+    }
 
 #ifdef STACK_GROWS_DOWNWARD
   *len = (char *) (segment + 1) + segment->size - (char *) sp;
@@ -1037,6 +1053,60 @@ __splitstack_makecontext (size_t stack_size, void *context[NUMBER_OFFSETS],
   return (void *) (segment + 1);
 }
 
+/* Given an existing split stack context, reset it back to the start
+   of the stack.  Return the stack pointer and size, appropriate for
+   use with makecontext.  This may be used if a coroutine exits, in
+   order to reuse the stack segments for a new coroutine.  */
+
+void *
+__splitstack_resetcontext (void *context[10], size_t *size)
+{
+  struct stack_segment *segment;
+  void *initial_sp;
+  size_t initial_size;
+  void *ret;
+
+  /* Reset the context assuming that MORESTACK_SEGMENTS, INITIAL_SP
+     and INITIAL_SP_LEN are correct.  */
+
+  segment = context[MORESTACK_SEGMENTS];
+  context[CURRENT_SEGMENT] = segment;
+  context[CURRENT_STACK] = NULL;
+  if (segment == NULL)
+    {
+      initial_sp = context[INITIAL_SP];
+      initial_size = (uintptr_type) context[INITIAL_SP_LEN];
+      ret = initial_sp;
+#ifdef STACK_GROWS_DOWNWARD
+      ret = (void *) ((char *) ret - initial_size);
+#endif
+    }
+  else
+    {
+#ifdef STACK_GROWS_DOWNWARD
+      initial_sp = (void *) ((char *) (segment + 1) + segment->size);
+#else
+      initial_sp = (void *) (segment + 1);
+#endif
+      initial_size = segment->size;
+      ret = (void *) (segment + 1);
+    }
+  context[STACK_GUARD] = __morestack_make_guard (initial_sp, initial_size);
+  context[BLOCK_SIGNALS] = NULL;
+  *size = initial_size;
+  return ret;
+}
+
+/* Release all the memory associated with a splitstack context.  This
+   may be used if a coroutine exits and the associated stack should be
+   freed.  */
+
+void
+__splitstack_releasecontext (void *context[10])
+{
+  __morestack_release_segments (context[MORESTACK_SEGMENTS], 1);
+}
+
 /* Like __splitstack_block_signals, but operating on CONTEXT, rather
    than on the current state.  */
 
diff --git a/libgcc/libgcc-std.ver.in b/libgcc/libgcc-std.ver.in
index 2d66612d1c56..ec702952f9b9 100644
--- a/libgcc/libgcc-std.ver.in
+++ b/libgcc/libgcc-std.ver.in
@@ -1932,4 +1932,6 @@ GCC_4.7.0 {
   __splitstack_makecontext
   __splitstack_block_signals_context
   __splitstack_find_context
+  __splitstack_resetcontext
+  __splitstack_releasecontext
 }
-- 
GitLab