mirror of
https://gcc.gnu.org/git/gcc.git
synced 2024-11-27 05:44:15 +08:00
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
This commit is contained in:
parent
8ee9fac21e
commit
e14304eff5
@ -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.
|
||||
|
171
gcc/testsuite/gcc.dg/split-5.c
Normal file
171
gcc/testsuite/gcc.dg/split-5.c
Normal file
@ -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;
|
||||
}
|
@ -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>
|
||||
}]
|
||||
}
|
||||
|
@ -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 ...
|
||||
|
@ -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.
|
||||
|
@ -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) */
|
||||
|
@ -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
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user