From 9b2906f9ff440d9b7c31479f9c9629b5aa47cc5a Mon Sep 17 00:00:00 2001 From: Rain Mark Date: Thu, 27 Jan 2022 04:32:38 -0500 Subject: [PATCH] add split stack --- build.sh | 4 +++ coroutine.cpp | 6 ++++ coroutine.h | 54 +++++++++++++++++++++++++++++++ gcc-split-stack-extra-space.patch | 26 +++++++++++++++ splitstack.cpp | 14 ++++++++ 5 files changed, 104 insertions(+) create mode 100644 gcc-split-stack-extra-space.patch create mode 100644 splitstack.cpp diff --git a/build.sh b/build.sh index 29949bb..ace1117 100755 --- a/build.sh +++ b/build.sh @@ -12,3 +12,7 @@ $CXX $FLAGS future_test.cpp -o bin/future_test $CXX $FLAGS -O0 loop_test.cpp coroutine.cpp *.S -o bin/loop_test $CXX $FLAGS -O0 httpd/httpd.cpp coroutine.cpp *.S -o bin/httpd + +$CXX $FLAGS -fsplit-stack -O0 splitstack.cpp -o bin/splitstack + +$CXX $FLAGS -fsplit-stack -DSPLIT_STACK loop_test.cpp coroutine.cpp *.S -o bin/loop_split_stack_test diff --git a/coroutine.cpp b/coroutine.cpp index 06ff4c2..e0e2e1e 100644 --- a/coroutine.cpp +++ b/coroutine.cpp @@ -15,6 +15,9 @@ void main(coro_t* coro, context from) { void coro_t::switch_out() { current = next_; +#ifdef SPLIT_STACK + switch_split_stack_context(stack_.ss_ctx_, stack_.next_); +#endif context from = switch_context(next_, next_->ctx_); next_ = static_cast(from); next_->ctx_ = from; @@ -23,6 +26,9 @@ void coro_t::switch_out() { void coro_t::switch_in() { next_ = current; current = this; +#ifdef SPLIT_STACK + switch_split_stack_context(stack_.next_, stack_.ss_ctx_); +#endif ctx_ = switch_context(this, ctx_); } diff --git a/coroutine.h b/coroutine.h index 5cff059..fdd8555 100644 --- a/coroutine.h +++ b/coroutine.h @@ -6,6 +6,36 @@ #include +#ifdef SPLIT_STACK + +/////////////////////////// +// forward declaration for splitstack-functions defined in libgcc +// https://github.com/gcc-mirror/gcc/blob/master/libgcc/generic-morestack.c +// https://github.com/gcc-mirror/gcc/blob/master/libgcc/config/i386/morestack.S + +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 +}; + +extern "C" { + void *__splitstack_makecontext(std::size_t, void* [NUMBER_OFFSETS], std::size_t*); + void __splitstack_setcontext(void* [NUMBER_OFFSETS]); + void __splitstack_getcontext(void* [NUMBER_OFFSETS]); + void __splitstack_releasecontext(void* [NUMBER_OFFSETS]); + void __splitstack_resetcontext(void* [NUMBER_OFFSETS]); + void __splitstack_block_signals_context(void* [NUMBER_OFFSETS], int* new_value, int* old_value); +} + +#endif + namespace cops { class coro_t; class event_loop_t; @@ -23,10 +53,20 @@ namespace cops { class stack_t { public: stack_t(size_t size = 64 * 1024) : size_(size) { +#ifdef SPLIT_STACK + sp_ = static_cast(__splitstack_makecontext(size_, ss_ctx_, &size_)); + static int off = 0; + __splitstack_block_signals_context(ss_ctx_, &off, 0); +#else sp_ = new char[size_]; +#endif } ~stack_t() { +#ifdef SPLIT_STACK + __splitstack_releasecontext(ss_ctx_); +#else delete[] sp_; +#endif } void* sp() { @@ -36,8 +76,22 @@ public: private: char* sp_; size_t size_; +#ifdef SPLIT_STACK +public: + using split_stack_context = void* [NUMBER_OFFSETS]; + split_stack_context ss_ctx_{0}; + split_stack_context next_{0}; +#endif }; +#ifdef SPLIT_STACK +inline void switch_split_stack_context(stack_t::split_stack_context from, + stack_t::split_stack_context to) { + __splitstack_getcontext(from); + __splitstack_setcontext(to); +} +#endif + class coro_t { public: using Fn = std::function; diff --git a/gcc-split-stack-extra-space.patch b/gcc-split-stack-extra-space.patch new file mode 100644 index 0000000..123155f --- /dev/null +++ b/gcc-split-stack-extra-space.patch @@ -0,0 +1,26 @@ +diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c +index 59101d8..4cbad01 100644 +--- a/gcc/config/i386/i386.c ++++ b/gcc/config/i386/i386.c +@@ -9488,7 +9488,7 @@ ix86_expand_split_stack_prologue (void) + + ix86_finalize_stack_frame_flags (); + struct ix86_frame &frame = cfun->machine->frame; +- allocate = frame.stack_pointer_offset - INCOMING_FRAME_SP_OFFSET; ++ allocate = frame.stack_pointer_offset - INCOMING_FRAME_SP_OFFSET + 64 * 1024; + + /* This is the label we will branch to if we have enough stack + space. We expect the basic block reordering pass to reverse this +diff --git a/libgcc/config/i386/morestack.S b/libgcc/config/i386/morestack.S +index 519bbbc..0f0a79e 100644 +--- a/libgcc/config/i386/morestack.S ++++ b/libgcc/config/i386/morestack.S +@@ -84,7 +84,7 @@ + + + # The amount of space we ask for when calling non-split-stack code. +-#define NON_SPLIT_STACK 0x100000 ++#define NON_SPLIT_STACK 0x8000 + + # This entry point is for split-stack code which calls non-split-stack + # code. When the linker sees this case, it converts the call to diff --git a/splitstack.cpp b/splitstack.cpp new file mode 100644 index 0000000..bd09163 --- /dev/null +++ b/splitstack.cpp @@ -0,0 +1,14 @@ +#include + +int foo(int x1) { + printf("%d\n", x1); + return 0; +} + +int bar(int x2) { + return foo(x2); +} + +int main() { + return bar(0); +}