Guys, I'm playing around with Boost.Coroutine experimental package[1] and it looks like it's corrupting the stack. I can't say for sure if it's a stack corruption, however, my application produces a seg.fault when running acceptance tests and gdb can't fully show the core dump backtrace saying "Backtrace stopped: previous frame inner to this frame (corrupt stack?)". If there are any coroutine users around, could you please give any tips on proper usage of this package, its limitations, etc? I had really high hopes for this package and really don't want to go back to the ugly non-coroutine logic. Thanks P.S. I'm using gcc-4.3.3 on linux x86(_64) [1] http://www.crystalclearsoftware.com/soc/coroutine/index.html -- Best regards, Pavel
On Tue, Aug 04, 2009 at 04:15:35PM +0400, Pavel Shevaev wrote:
Guys, I'm playing around with Boost.Coroutine experimental package[1] and it looks like it's corrupting the stack.
I can't say for sure if it's a stack corruption, however, my application produces a seg.fault when running acceptance tests and gdb can't fully show the core dump backtrace saying "Backtrace stopped: previous frame inner to this frame (corrupt stack?)".
If there are any coroutine users around, could you please give any tips on proper usage of this package, its limitations, etc? I had really high hopes for this package and really don't want to go back to the ugly non-coroutine logic.
In C and C++, each coroutine (and thread for that matter) must have a single, contiguous stack which, in addition, cannot grow. Because of this, you should 1) avoid large local variables (e.g., arrays), 2) avoid recursion of any kind, 3) avoid calling any other functions that use a lot of stack (see 1) and 2)), 4) have enough stack space for signal handling [actually, the best thing to do is to install an alternate signal stack by using sigaltstack()]. If you're running in 64-bit mode, try setting the stack size of each coroutine to something like 1MB; the system's demand-paging logic will actually allocate as much physical memory as the program needs. But the fundamental limitations listed above remain.
In C and C++, each coroutine (and thread for that matter) must have a single, contiguous stack which, in addition, cannot grow. Because of this, you should 1) avoid large local variables (e.g., arrays), 2) avoid recursion of any kind, 3) avoid calling any other functions that use a lot of stack (see 1) and 2)), 4) have enough stack space for signal handling [actually, the best thing to do is to install an alternate signal stack by using sigaltstack()].
Thanks a lot for these tips!
If you're running in 64-bit mode, try setting the stack size of each coroutine to something like 1MB; the system's demand-paging logic will actually allocate as much physical memory as the program needs. But the fundamental limitations listed above remain.
I migrated to boost.fibers for now and increased the size of the default stack to 64kb and corruption was gone. I tried to increase the amount of stack size for boost.coroutine as well but for some reason it didn't work. I'm going to find out what was wrong with boost.coroutine since it's faster than boost.fibers thanks to lighter implementation of stack switching. -- Best regards, Pavel
On Thu, Aug 06, 2009 at 09:25:56AM +0400, Pavel Shevaev wrote:
I migrated to boost.fibers for now and increased the size of the default stack to 64kb and corruption was gone. I tried to increase the amount of stack size for boost.coroutine as well but for some reason it didn't work. I'm going to find out what was wrong with boost.coroutine since it's faster than boost.fibers thanks to lighter implementation of stack switching.
I would advise against using hand-coded context switch under windows, unless you have *really* good knowledge of the internals of Windows' process model. Windows' process model is more complex than POSIX and proper context switch, as performed by the Fiber API, does few more things than just swapping the values of few registers. Using the Fibers API is safe(r) and CPU-independent. Anyway, if you're using visual studio, be sure to tell optimizer that you're using fibers (there's an option somewhere in project properties that forces the optimizer to use only fiber-safe optimizations).
I would advise against using hand-coded context switch under windows, unless you have *really* good knowledge of the internals of Windows' process model. Windows' process model is more complex than POSIX and proper context switch, as performed by the Fiber API, does few more things than just swapping the values of few registers. Using the Fibers API is safe(r) and CPU-independent.
Oh, don't let the name boost.fibers confuse you :) Internally it uses POSIX context switching under linux As for boost.coroutine being faster than boost.fibers, I wanted to say boost.coroutine uses very fast assembler snippet instead of heavy POSIX calls. -- Best regards, Pavel
participants (2)
-
Pavel Shevaev
-
Zeljko Vrba