aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@google.com>2011-11-09 20:06:31 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2011-11-09 20:06:31 +0000
commite14304eff546e4ef3dc33e6439d793f999e81c91 (patch)
treeb16db4d1e1ec9a11ee2ee00a183a6daa8b383c59
parent8ee9fac21ec877d5e0bbcd3460eb584bbeccf836 (diff)
downloadgcc-e14304eff546e4ef3dc33e6439d793f999e81c91.zip
gcc-e14304eff546e4ef3dc33e6439d793f999e81c91.tar.gz
gcc-e14304eff546e4ef3dc33e6439d793f999e81c91.tar.bz2
generic-morestack.c: Include <string.h>.
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
-rw-r--r--gcc/testsuite/ChangeLog6
-rw-r--r--gcc/testsuite/gcc.dg/split-5.c171
-rw-r--r--gcc/testsuite/lib/target-supports.exp8
-rw-r--r--libgcc/ChangeLog25
-rw-r--r--libgcc/config/i386/morestack.S78
-rw-r--r--libgcc/generic-morestack.c252
-rw-r--r--libgcc/libgcc-std.ver.in8
7 files changed, 527 insertions, 21 deletions
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 4052135..ad7fbea 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -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
index 0000000..601640f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/split-5.c
@@ -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;
+}
diff --git a/gcc/testsuite/lib/target-supports.exp b/gcc/testsuite/lib/target-supports.exp
index 944a668..9430910 100644
--- a/gcc/testsuite/lib/target-supports.exp
+++ b/gcc/testsuite/lib/target-supports.exp
@@ -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>
+ }]
+}
diff --git a/libgcc/ChangeLog b/libgcc/ChangeLog
index 0e99994..bfaa1a0 100644
--- a/libgcc/ChangeLog
+++ b/libgcc/ChangeLog
@@ -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 ...
diff --git a/libgcc/config/i386/morestack.S b/libgcc/config/i386/morestack.S
index 85c20ed..0667590 100644
--- a/libgcc/config/i386/morestack.S
+++ b/libgcc/config/i386/morestack.S
@@ -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.
diff --git a/libgcc/generic-morestack.c b/libgcc/generic-morestack.c
index 07bc2a6..00a3b1c 100644
--- a/libgcc/generic-morestack.c
+++ b/libgcc/generic-morestack.c
@@ -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) */
diff --git a/libgcc/libgcc-std.ver.in b/libgcc/libgcc-std.ver.in
index 2946468..2d66612 100644
--- a/libgcc/libgcc-std.ver.in
+++ b/libgcc/libgcc-std.ver.in
@@ -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
}