generic-morestack.c: Include <string.h>.
authorIan Lance Taylor <iant@google.com>
Wed, 9 Nov 2011 20:06:31 +0000 (20:06 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Wed, 9 Nov 2011 20:06:31 +0000 (20:06 +0000)
libgcc/:
* generic-morestack.c: Include <string.h>.
(uintptr_type): Define.
(struct initial_sp): Add dont_block_signals field.  Reduce size of
extra array by 1.
(allocate_segment): Set prev field to NULL.  Don't set
__morestack_current_segment or __morestack_segments.
(__generic_morestack): Update current->prev and *pp after calling
allocate_segment.
(__morestack_block_signals): Don't do anything if
dont_block_signals is set.
(__morestack_unblock_signals): Likewise.
(__generic_findstack): Check for initial_sp == NULL.  Add casts to
uintptr_type.
(__splitstack_block_signals): New function.
(enum __splitstack_content_offsets): Define.
(__splitstack_getcontext, __splitstack_setcontext): New functions.
(__splitstack_makecontext): New function.
(__splitstack_block_signals_context): New function.
(__splitstack_find_context): New function.
* config/i386/morestack.S (__morestack_get_guard): New function.
(__morestack_set_guard, __morestack_make_guard): New functions.
* libgcc-std.ver.in: Add new functions to GCC_4.7.0.

gcc/testsuite/:
* lib/target-supports.exp (check_effective_target_ucontext_h): New
procedure.
* gcc.dg/split-5.c: New test.

From-SVN: r181234

gcc/testsuite/ChangeLog
gcc/testsuite/gcc.dg/split-5.c [new file with mode: 0644]
gcc/testsuite/lib/target-supports.exp
libgcc/ChangeLog
libgcc/config/i386/morestack.S
libgcc/generic-morestack.c
libgcc/libgcc-std.ver.in

index 4052135..ad7fbea 100644 (file)
@@ -1,3 +1,9 @@
+2011-11-09  Ian Lance Taylor  <iant@google.com>
+
+       * lib/target-supports.exp (check_effective_target_ucontext_h): New
+       procedure.
+       * gcc.dg/split-5.c: New test.
+
 2011-11-09  Patrick Marlier  <patrick.marlier@gmail.com>
 
        * gcc.dg/tm/memopt-1.c:  Adjust regexp. 
diff --git a/gcc/testsuite/gcc.dg/split-5.c b/gcc/testsuite/gcc.dg/split-5.c
new file mode 100644 (file)
index 0000000..601640f
--- /dev/null
@@ -0,0 +1,171 @@
+/* { dg-do run } */
+/* { dg-require-effective-target split_stack } */
+/* { dg-require-effective-target pthread_h } */
+/* { dg-require-effective-target ucontext_h } */
+/* { dg-options "-pthread -fsplit-stack" } */
+
+#include <stdlib.h>
+#include <pthread.h>
+#include <ucontext.h>
+
+extern void __splitstack_getcontext (void *context[10]);
+
+extern void __splitstack_setcontext (void *context[10]);
+
+extern void *__splitstack_makecontext (size_t, void *context[10], size_t *);
+
+extern void __splitstack_block_signals (int *, int *);
+
+extern void __splitstack_block_signals_context (void *context[10], int *,
+                                               int *);
+
+extern void *__splitstack_find (void *, void *, size_t *, void **, void **,
+                               void **);
+
+extern void *__splitstack_find_context (void *context[10], size_t *, void **,
+                                       void **, void **);
+
+static ucontext_t c1;
+static void *s1[10];
+
+static ucontext_t c2;
+static void *s2[10];
+
+static void swap (ucontext_t *, void *fs[10], ucontext_t *, void *ts[10])
+  __attribute__ ((no_split_stack));
+
+static void
+swap (ucontext_t *fu, void *fs[10], ucontext_t *tu, void *ts[10])
+{
+  __splitstack_getcontext (fs);
+  __splitstack_setcontext (ts);
+  swapcontext (fu, tu);
+  __splitstack_setcontext (fs);
+}
+
+/* Use a noinline function to ensure that the buffer is not removed
+   from the stack.  */
+static void use_buffer (char *buf) __attribute__ ((noinline));
+static void
+use_buffer (char *buf)
+{
+  buf[0] = '\0';
+}
+
+static void
+down (int i, const char *msg, ucontext_t *me, void *mes[10],
+      ucontext_t *other, void *others[10])
+{
+  char buf[10000];
+
+  if (i > 0)
+    {
+      use_buffer (buf);
+      swap (me, mes, other, others);
+      down (i - 1, msg, me, mes, other, others);
+    }
+  else
+    {
+      int c = 0;
+      void *stack;
+      size_t stack_size;
+      void *next_segment = NULL;
+      void *next_sp = NULL;
+      void *initial_sp = NULL;
+
+      stack = __splitstack_find_context (mes, &stack_size, &next_segment,
+                                       &next_sp, &initial_sp);
+      if (stack != NULL)
+       {
+         ++c;
+         while (__splitstack_find (next_segment, next_sp, &stack_size,
+                                   &next_segment, &next_sp, &initial_sp)
+                != NULL)
+           ++c;
+       }
+    }
+}
+
+static void
+go1 (void)
+{
+  down (1000, "go1", &c1, s1, &c2, s2);
+  pthread_exit (NULL);
+}
+
+static void
+go2 (void)
+{
+  down (1000, "go2", &c2, s2, &c1, s1);
+  pthread_exit (NULL);
+}
+
+struct thread_context
+{
+  ucontext_t *u;
+  void **s;
+};
+
+static void *start_thread (void *) __attribute__ ((no_split_stack));
+
+static void *
+start_thread (void *context)
+{
+  struct thread_context *tc = (struct thread_context *) context;
+  int block;
+
+  block = 0;
+  __splitstack_block_signals (&block, NULL);
+  __splitstack_setcontext (tc->s);
+  setcontext (tc->u);
+  abort ();
+}
+
+int
+main (int argc __attribute__ ((unused)), char **argv __attribute__ ((unused)))
+{
+  pthread_t tid;
+  int err;
+  size_t size;
+  struct thread_context tc;
+  int block;
+
+  if (getcontext (&c1) < 0)
+    abort ();
+
+  c2 = c1;
+
+  c1.uc_stack.ss_sp = __splitstack_makecontext (8192, &s1[0], &size);
+  if (c1.uc_stack.ss_sp == NULL)
+    abort ();
+  c1.uc_stack.ss_flags = 0;
+  c1.uc_stack.ss_size = size;
+  c1.uc_link = NULL;
+  block = 0;
+  __splitstack_block_signals_context (&s1[0], &block, NULL);
+  makecontext (&c1, go1, 0);
+
+  c2.uc_stack.ss_sp = __splitstack_makecontext (8192, &s2[0], &size);
+  if (c2.uc_stack.ss_sp == NULL)
+    abort ();
+  c2.uc_stack.ss_flags = 0;
+  c2.uc_stack.ss_size = size;
+  c2.uc_link = NULL;
+  __splitstack_block_signals_context (&s2[0], &block, NULL);
+  makecontext (&c2, go2, 0);
+
+  block = 0;
+  __splitstack_block_signals (&block, NULL);
+
+  tc.u = &c1;
+  tc.s = &s1[0];
+  err = pthread_create (&tid, NULL, start_thread, &tc);
+  if (err != 0)
+    abort ();
+
+  err = pthread_join (tid, NULL);
+  if (err != 0)
+    abort ();
+
+  return 0;
+}
index 944a668..9430910 100644 (file)
@@ -4401,3 +4401,11 @@ proc check_effective_target_non_strict_align {} {
        void foo(void) { z = (c *) y; }
     } "-Wcast-align"]
 }
+
+# Return 1 if the target has <ucontext.h>.
+
+proc check_effective_target_ucontext_h { } {
+    return [check_no_compiler_messages ucontext_h assembly {
+       #include <ucontext.h>
+    }]
+}
index 0e99994..bfaa1a0 100644 (file)
@@ -1,3 +1,28 @@
+2011-11-09  Ian Lance Taylor  <iant@google.com>
+
+       * generic-morestack.c: Include <string.h>.
+       (uintptr_type): Define.
+       (struct initial_sp): Add dont_block_signals field.  Reduce size of
+       extra array by 1.
+       (allocate_segment): Set prev field to NULL.  Don't set
+       __morestack_current_segment or __morestack_segments.
+       (__generic_morestack): Update current->prev and *pp after calling
+       allocate_segment.
+       (__morestack_block_signals): Don't do anything if
+       dont_block_signals is set.
+       (__morestack_unblock_signals): Likewise.
+       (__generic_findstack): Check for initial_sp == NULL.  Add casts to
+       uintptr_type.
+       (__splitstack_block_signals): New function.
+       (enum __splitstack_content_offsets): Define.
+       (__splitstack_getcontext, __splitstack_setcontext): New functions.
+       (__splitstack_makecontext): New function.
+       (__splitstack_block_signals_context): New function.
+       (__splitstack_find_context): New function.
+       * config/i386/morestack.S (__morestack_get_guard): New function.
+       (__morestack_set_guard, __morestack_make_guard): New functions.
+       * libgcc-std.ver.in: Add new functions to GCC_4.7.0.
+
 2011-11-09  Rainer Orth  <ro@CeBiTec.Uni-Bielefeld.DE>
 
        * config.host (i[34567]86-*-cygwin*): Move i386/t-mingw-pthread ...
index 85c20ed..0667590 100644 (file)
@@ -1,5 +1,5 @@
 # x86/x86_64 support for -fsplit-stack.
-# Copyright (C) 2009, 2010 Free Software Foundation, Inc.
+# Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc.
 # Contributed by Ian Lance Taylor <iant@google.com>.
 
 # This file is part of GCC.
@@ -620,6 +620,82 @@ __stack_split_initialize:
        .size   __stack_split_initialize, . - __stack_split_initialize
 #endif
 
+# Routines to get and set the guard, for __splitstack_getcontext,
+# __splitstack_setcontext, and __splitstack_makecontext.
+
+# void *__morestack_get_guard (void) returns the current stack guard.
+       .text
+       .global __morestack_get_guard
+       .hidden __morestack_get_guard
+
+#ifdef __ELF__
+       .type   __morestack_get_guard,@function
+#endif
+
+__morestack_get_guard:
+
+#ifndef __x86_64__
+       movl    %gs:0x30,%eax
+#else
+#ifdef __LP64__
+       movq    %fs:0x70,%rax
+#else
+       movl    %fs:0x40,%eax
+#endif
+#endif
+       ret
+
+#ifdef __ELF__
+       .size   __morestack_get_guard, . - __morestack_get_guard
+#endif
+
+# void __morestack_set_guard (void *) sets the stack guard.
+       .global __morestack_set_guard
+       .hidden __morestack_set_guard
+
+#ifdef __ELF__
+       .type   __morestack_set_guard,@function
+#endif
+
+__morestack_set_guard:
+
+#ifndef __x86_64__
+       movl    4(%esp),%eax
+       movl    %eax,%gs:0x30
+#else
+       X86_64_SAVE_NEW_STACK_BOUNDARY (di)
+#endif
+       ret
+
+#ifdef __ELF__
+       .size   __morestack_set_guard, . - __morestack_set_guard
+#endif
+
+# void *__morestack_make_guard (void *, size_t) returns the stack
+# guard value for a stack.
+       .global __morestack_make_guard
+       .hidden __morestack_make_guard
+
+#ifdef __ELF__
+       .type   __morestack_make_guard,@function
+#endif
+
+__morestack_make_guard:
+
+#ifndef __x86_64__
+       movl    4(%esp),%eax
+       subl    8(%esp),%eax
+       addl    $BACKOFF,%eax
+#else
+       subq    %rsi,%rdi
+       addq    $BACKOFF,%rdi
+       movq    %rdi,%rax
+#endif
+       ret
+
+#ifdef __ELF__
+       .size   __morestack_make_guard, . - __morestack_make_guard
+#endif
 
 # Make __stack_split_initialize a high priority constructor.  FIXME:
 # This is ELF specific.
index 07bc2a6..00a3b1c 100644 (file)
@@ -41,12 +41,15 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #include <errno.h>
 #include <signal.h>
 #include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 #include <sys/mman.h>
 #include <sys/uio.h>
 
 #include "generic-morestack.h"
 
+typedef unsigned uintptr_type __attribute__ ((mode (pointer)));
+
 /* This file contains subroutines that are used by code compiled with
    -fsplit-stack.  */
 
@@ -88,14 +91,50 @@ extern void *
 __morestack_allocate_stack_space (size_t size)
   __attribute__ ((visibility ("hidden")));
 
-/* This is a function which -fsplit-stack code can call to get a list
-   of the stacks.  Since it is not called only by the compiler, it is
-   not hidden.  */
+/* These are functions which -fsplit-stack code can call.  These are
+   not called by the compiler, and are not hidden.  FIXME: These
+   should be in some header file somewhere, somehow.  */
 
 extern void *
 __splitstack_find (void *, void *, size_t *, void **, void **, void **)
   __attribute__ ((visibility ("default")));
 
+extern void
+__splitstack_block_signals (int *, int *)
+  __attribute__ ((visibility ("default")));
+
+extern void
+__splitstack_getcontext (void *context[10])
+  __attribute__ ((no_split_stack, visibility ("default")));
+
+extern void
+__splitstack_setcontext (void *context[10])
+  __attribute__ ((no_split_stack, visibility ("default")));
+
+extern void *
+__splitstack_makecontext (size_t, void *context[10], size_t *)
+  __attribute__ ((visibility ("default")));
+
+extern void
+__splitstack_block_signals_context (void *context[10], int *, int *)
+  __attribute__ ((visibility ("default")));
+
+extern void *
+__splitstack_find_context (void *context[10], size_t *, void **, void **,
+                          void **)
+  __attribute__ ((visibility ("default")));
+
+/* These functions must be defined by the processor specific code.  */
+
+extern void *__morestack_get_guard (void)
+  __attribute__ ((no_split_stack, visibility ("hidden")));
+
+extern void __morestack_set_guard (void *)
+  __attribute__ ((no_split_stack, visibility ("hidden")));
+
+extern void *__morestack_make_guard (void *, size_t)
+  __attribute__ ((no_split_stack, visibility ("hidden")));
+
 /* When we allocate a stack segment we put this header at the
    start.  */
 
@@ -138,8 +177,13 @@ struct initial_sp
   /* A signal mask, put here so that the thread can use it without
      needing stack space.  */
   sigset_t mask;
+  /* Non-zero if we should not block signals.  This is a reversed flag
+     so that the default zero value is the safe value.  The type is
+     uintptr_type because it replaced one of the void * pointers in
+     extra.  */
+  uintptr_type dont_block_signals;
   /* Some extra space for later extensibility.  */
-  void *extra[5];
+  void *extra[4];
 };
 
 /* A list of memory blocks allocated by dynamic stack allocation.
@@ -339,18 +383,13 @@ allocate_segment (size_t frame_size)
 
   pss = (struct stack_segment *) space;
 
-  pss->prev = __morestack_current_segment;
+  pss->prev = NULL;
   pss->next = NULL;
   pss->size = allocate - overhead;
   pss->dynamic_allocation = NULL;
   pss->free_dynamic_allocation = NULL;
   pss->extra = NULL;
 
-  if (__morestack_current_segment != NULL)
-    __morestack_current_segment->next = pss;
-  else
-    __morestack_segments = pss;
-
   return pss;
 }
 
@@ -513,7 +552,11 @@ __generic_morestack (size_t *pframe_size, void *old_stack, size_t param_size)
   current = *pp;
 
   if (current == NULL)
-    current = allocate_segment (frame_size + param_size);
+    {
+      current = allocate_segment (frame_size + param_size);
+      current->prev = __morestack_current_segment;
+      *pp = current;
+    }
 
   current->old_stack = old_stack;
 
@@ -614,7 +657,9 @@ extern int pthread_sigmask (int, const sigset_t *, sigset_t *)
 void
 __morestack_block_signals (void)
 {
-  if (pthread_sigmask)
+  if (__morestack_initial_sp.dont_block_signals)
+    ;
+  else if (pthread_sigmask)
     pthread_sigmask (SIG_BLOCK, &__morestack_fullmask,
                     &__morestack_initial_sp.mask);
   else
@@ -627,7 +672,9 @@ __morestack_block_signals (void)
 void
 __morestack_unblock_signals (void)
 {
-  if (pthread_sigmask)
+  if (__morestack_initial_sp.dont_block_signals)
+    ;
+  else if (pthread_sigmask)
     pthread_sigmask (SIG_SETMASK, &__morestack_initial_sp.mask, NULL);
   else
     sigprocmask (SIG_SETMASK, &__morestack_initial_sp.mask, NULL);
@@ -727,6 +774,10 @@ __generic_findstack (void *stack)
     }
 
   /* We have popped back to the original stack.  */
+
+  if (__morestack_initial_sp.sp == NULL)
+    return 0;
+
 #ifdef STACK_GROWS_DOWNWARD
   if ((char *) stack >= (char *) __morestack_initial_sp.sp)
     used = 0;
@@ -796,11 +847,14 @@ __splitstack_find (void *segment_arg, void *sp, size_t *len,
   void *ret;
   char *nsp;
 
-  if (segment_arg == (void *) 1)
+  if (segment_arg == (void *) (uintptr_type) 1)
     {
       char *isp = (char *) *initial_sp;
 
-      *next_segment = (void *) 2;
+      if (isp == NULL)
+       return NULL;
+
+      *next_segment = (void *) (uintptr_type) 2;
       *next_sp = NULL;
 #ifdef STACK_GROWS_DOWNWARD
       if ((char *) sp >= isp)
@@ -814,7 +868,7 @@ __splitstack_find (void *segment_arg, void *sp, size_t *len,
       return (void *) isp;
 #endif
     }
-  else if (segment_arg == (void *) 2)
+  else if (segment_arg == (void *) (uintptr_type) 2)
     return NULL;
   else if (segment_arg != NULL)
     segment = (struct stack_segment *) segment_arg;
@@ -826,8 +880,8 @@ __splitstack_find (void *segment_arg, void *sp, size_t *len,
       while (1)
        {
          if (segment == NULL)
-           return __splitstack_find ((void *) 1, sp, len, next_segment,
-                                     next_sp, initial_sp);
+           return __splitstack_find ((void *) (uintptr_type) 1, sp, len,
+                                     next_segment, next_sp, initial_sp);
          if ((char *) sp >= (char *) (segment + 1)
              && (char *) sp <= (char *) (segment + 1) + segment->size)
            break;
@@ -836,7 +890,7 @@ __splitstack_find (void *segment_arg, void *sp, size_t *len,
     }
 
   if (segment->prev == NULL)
-    *next_segment = (void *) 1;
+    *next_segment = (void *) (uintptr_type) 1;
   else
     *next_segment = segment->prev;
 
@@ -878,4 +932,164 @@ __splitstack_find (void *segment_arg, void *sp, size_t *len,
   return ret;
 }
 
+/* Tell the split stack code whether it has to block signals while
+   manipulating the stack.  This is for programs in which some threads
+   block all signals.  If a thread already blocks signals, there is no
+   need for the split stack code to block them as well.  If NEW is not
+   NULL, then if *NEW is non-zero signals will be blocked while
+   splitting the stack, otherwise they will not.  If OLD is not NULL,
+   *OLD will be set to the old value.  */
+
+void
+__splitstack_block_signals (int *new, int *old)
+{
+  if (old != NULL)
+    *old = __morestack_initial_sp.dont_block_signals ? 0 : 1;
+  if (new != NULL)
+    __morestack_initial_sp.dont_block_signals = *new ? 0 : 1;
+}
+
+/* The offsets into the arrays used by __splitstack_getcontext and
+   __splitstack_setcontext.  */
+
+enum __splitstack_context_offsets
+{
+  MORESTACK_SEGMENTS = 0,
+  CURRENT_SEGMENT = 1,
+  CURRENT_STACK = 2,
+  STACK_GUARD = 3,
+  INITIAL_SP = 4,
+  INITIAL_SP_LEN = 5,
+  BLOCK_SIGNALS = 6,
+
+  NUMBER_OFFSETS = 10
+};
+
+/* Get the current split stack context.  This may be used for
+   coroutine switching, similar to getcontext.  The argument should
+   have at least 10 void *pointers for extensibility, although we
+   don't currently use all of them.  This would normally be called
+   immediately before a call to getcontext or swapcontext or
+   setjmp.  */
+
+void
+__splitstack_getcontext (void *context[NUMBER_OFFSETS])
+{
+  memset (context, 0, NUMBER_OFFSETS * sizeof (void *));
+  context[MORESTACK_SEGMENTS] = (void *) __morestack_segments;
+  context[CURRENT_SEGMENT] = (void *) __morestack_current_segment;
+  context[CURRENT_STACK] = (void *) &context;
+  context[STACK_GUARD] = __morestack_get_guard ();
+  context[INITIAL_SP] = (void *) __morestack_initial_sp.sp;
+  context[INITIAL_SP_LEN] = (void *) (uintptr_type) __morestack_initial_sp.len;
+  context[BLOCK_SIGNALS] = (void *) __morestack_initial_sp.dont_block_signals;
+}
+
+/* Set the current split stack context.  The argument should be a
+   context previously passed to __splitstack_getcontext.  This would
+   normally be called immediately after a call to getcontext or
+   swapcontext or setjmp if something jumped to it.  */
+
+void
+__splitstack_setcontext (void *context[NUMBER_OFFSETS])
+{
+  __morestack_segments = (struct stack_segment *) context[MORESTACK_SEGMENTS];
+  __morestack_current_segment =
+    (struct stack_segment *) context[CURRENT_SEGMENT];
+  __morestack_set_guard (context[STACK_GUARD]);
+  __morestack_initial_sp.sp = context[INITIAL_SP];
+  __morestack_initial_sp.len = (size_t) context[INITIAL_SP_LEN];
+  __morestack_initial_sp.dont_block_signals =
+    (uintptr_type) context[BLOCK_SIGNALS];
+}
+
+/* Create a new split stack context.  This will allocate a new stack
+   segment which may be used by a coroutine.  STACK_SIZE is the
+   minimum size of the new stack.  The caller is responsible for
+   actually setting the stack pointer.  This would normally be called
+   before a call to makecontext, and the returned stack pointer and
+   size would be used to set the uc_stack field.  A function called
+   via makecontext on a stack created by __splitstack_makecontext may
+   not return.  Note that the returned pointer points to the lowest
+   address in the stack space, and thus may not be the value to which
+   to set the stack pointer.  */
+
+void *
+__splitstack_makecontext (size_t stack_size, void *context[NUMBER_OFFSETS],
+                         size_t *size)
+{
+  struct stack_segment *segment;
+  void *initial_sp;
+
+  memset (context, 0, NUMBER_OFFSETS * sizeof (void *));
+  segment = allocate_segment (stack_size);
+  context[MORESTACK_SEGMENTS] = segment;
+  context[CURRENT_SEGMENT] = segment;
+#ifdef STACK_GROWS_DOWNWARD
+  initial_sp = (void *) ((char *) (segment + 1) + segment->size);
+#else
+  initial_sp = (void *) (segment + 1);
+#endif
+  context[STACK_GUARD] = __morestack_make_guard (initial_sp, segment->size);
+  context[INITIAL_SP] = NULL;
+  context[INITIAL_SP_LEN] = 0;
+  *size = segment->size;
+  return (void *) (segment + 1);
+}
+
+/* Like __splitstack_block_signals, but operating on CONTEXT, rather
+   than on the current state.  */
+
+void
+__splitstack_block_signals_context (void *context[NUMBER_OFFSETS], int *new,
+                                   int *old)
+{
+  if (old != NULL)
+    *old = ((uintptr_type) context[BLOCK_SIGNALS]) != 0 ? 0 : 1;
+  if (new != NULL)
+    context[BLOCK_SIGNALS] = (void *) (uintptr_type) (*new ? 0 : 1);
+}
+
+/* Find the stack segments associated with a split stack context.
+   This will return the address of the first stack segment and set
+   *STACK_SIZE to its size.  It will set next_segment, next_sp, and
+   initial_sp which may be passed to __splitstack_find to find the
+   remaining segments.  */
+
+void *
+__splitstack_find_context (void *context[NUMBER_OFFSETS], size_t *stack_size,
+                          void **next_segment, void **next_sp,
+                          void **initial_sp)
+{
+  void *sp;
+  struct stack_segment *segment;
+
+  *initial_sp = context[INITIAL_SP];
+
+  sp = context[CURRENT_STACK];
+  if (sp == NULL)
+    {
+      /* Most likely this context was created but was never used.  The
+        value 2 is a code used by __splitstack_find to mean that we
+        have reached the end of the list of stacks.  */
+      *next_segment = (void *) (uintptr_type) 2;
+      *next_sp = NULL;
+      *initial_sp = NULL;
+      return NULL;
+    }
+
+  segment = context[CURRENT_SEGMENT];
+  if (segment == NULL)
+    {
+      /* Most likely this context was saved by a thread which was not
+        created using __splistack_makecontext and which has never
+        split the stack.  The value 1 is a code used by
+        __splitstack_find to look at the initial stack.  */
+      segment = (struct stack_segment *) (uintptr_type) 1;
+    }
+
+  return __splitstack_find (segment, sp, stack_size, next_segment, next_sp,
+                           initial_sp);
+}
+
 #endif /* !defined (inhibit_libc) */
index 2946468..2d66612 100644 (file)
@@ -1,5 +1,5 @@
 # Copyright (C) 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007,
-# 2008, 2010 Free Software Foundation, Inc.
+# 2008, 2010, 2011 Free Software Foundation, Inc.
 #
 # This file is part of GCC.
 #
@@ -1926,4 +1926,10 @@ GCC_4.7.0 {
   __PFX__clrsbsi2
   __PFX__clrsbdi2
   __PFX__clrsbti2
+  __splitstack_block_signals
+  __splitstack_getcontext
+  __splitstack_setcontext
+  __splitstack_makecontext
+  __splitstack_block_signals_context
+  __splitstack_find_context
 }