review request for boost.context

Hello John, hello Ronald, could you add boost.context to the review queue please. boost.context allows to switch between execution contexts. The state of the context which will be left is saved and maybe resumed later. It is a kind of POSIX ucontext (fallback on POSIX platforms for boost.context) but provides assembler for some platforms (faster and some platforms doesn't implement POSIX ucontext because it is deprecaded -> ARM). thanks an best regards, Oliver

downloadable from boost vault: http://www.boostpro.com/vault/index.php?action=downloadfile&filename=boost.context-0.1.0.zip&directory=Concurrent%20Programming& boost.context implements the POSIX ucontext functionality (makecontext()/swapcontext()) and WIN32 Fiber stuff. For performance reasons it provides assembler - 8x-10x faster than POSIX swapcontext() (because no sys call is involved). Please note that POSIX ucontext is now marked as deprecated by the new POSIX standard and may not be implemented for newer platforms (for instance on ARM makecontext()/swapcontext() is not provided by glibc). boost.context is the basis of boost.fiber. Phil Endecott requested to move this code from boost.fiber into a new lib in order to be reused by libs implementing some kind of cooperative scheduling (for instance boost.coroutine/boost.fiber). Oliver Am 28.07.2010 09:17, schrieb Robert Ramey:

On Windows I'd suggest to fall back to CreateFiber/SwitchToFiber/etc. These functions are not kernel calls, but merely do the context creation/switching. In my experience, it is almost impossible to convince the MSVC C++ runtime libraries to behave properly if you use your own context switching assembly code. OTOH, the measurements we performed shows SwitchToContext being to almost as fast as the hand written assembly code we were using in the beginning. Regards Hartmut --------------- Meet me at BoostCon www.boostcon.com

Am 28.07.2010 16:34, schrieb Hartmut Kaiser:
I find the Win32 Fiber interface ugly - at least the need to call ConvertThreadToFiber() and ConvertFiberToThread(). Until VISTA you had no Function which tells you if you already running in a fiber or not. You could fall back only to some heuristics. The TIB is not changed (only the pointers pointing to the limit and base of the stack). Ofcourse a new SEH chain has to be created and installed for each new context. So I'd like to know which problems did you encounter with own context switching code and MSVC C++ runtime libs. AFAIK migrating Win32 Fibers between threads is not possible and cloning also not - but maybe I'm wrong in this point. Oliver

Right, but it's known how to figure that out anyways.
You could fall back only to some heuristics.
Sure, but those are proven to work :-P
The TIB is not changed (only the pointers pointing to the limit and base of the stack).
That will result in problems, I'm sure - at least as soon as you start moving context's between threads.
Yeah, mostly SEH related things. All I could find still is a reference to: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?Feedbac kID=100319, otherwise I just don't concretely remember anymore, sorry. The fiber API works just fine for us, so we stopped looking into the assembly related problems.
AFAIK migrating Win32 Fibers between threads is not possible and cloning also not - but maybe I'm wrong in this point.
Moving Windows fibers between threads is definitely possible. Regards Hartmut --------------- Meet me at BoostCon www.boostcon.com

Am 28.07.2010 19:21, schrieb Hartmut Kaiser:
Hmm - boost.fiber uses boost.context and has some tests moving the boost fibers between boost threads. I didn't get errors until now =:o Could you describe a scenario which will trigger an error, please?
Isn't the TIB accessible over fs register? At least SEH handler is accessed via fs:[0] and the structure of TIB can be accessed from fs:[0]. Wouldn't be the content of fs:[0] another if I move a Win32 fiber to another thread (pointing to another TIB -> see stakc base and limit in TIB)? Or do I have to use a special function form the Win32 API? thx, Oliver

I'm not much of an expert of Windows internals. So it might be that our assembly context switch implementation was flawed.
Could you describe a scenario which will trigger an error, please?
We had problems during initialization of the runtime libraries under Win64, debug mode. That's all what I remember.
That's what SwitchFiber is taking care of, I guess. AFAIR it manipulates the content of fs:[0] as well. FWIW, we have a quite complex system running which definitely moves Win32 fibers between threads. And it works without problems. Regards Hartmut --------------- Meet me at BoostCon www.boostcon.com

Hello Oliver, This is very useful work. I'd very much like (see someone else) implementing CSP like channel/light-weight-process on top of it. My recent experience with google's Go language give quite positive impression of that model. Have you had a look of Russ Cox's libtask (http://swtch.com/libtask/)? which also provide a context wrapper (on *nix platforms). For the windows platform, now we have user-mode-scheduling (UMS) feature in Windows7 and WindowsServer2008R2, which kind of fixed many issues of fibers. Could it be a fallback for your interface? Regards Yigong

Am 29.07.2010 06:55, schrieb Yigong Liu:
I'd very much like (see someone else) implementing CSP like channel/light-weight-process on top of it.
I've implemented boost.fiber on top of boost.context - it aims to be a light-weight-process (with scheduling etc.). boost.fiber provides some channels too which can be used to exchange data between fibers even if they are running in different threads (fiber blocks/yields if it is waiting on a channel and gets resumed -> special mutex and condition vairables). I don't know if the channels of boost.fiber conform to CSP.
My recent experience with google's Go language give quite positive impression of that model.
I try to provide similiar functionality to C++.
Have you had a look of Russ Cox's libtask (http://swtch.com/libtask/)? which also provide a context wrapper (on *nix platforms).
I didn't knew libtask - seams similiar implementation is C (despite the fact of differences in assembler).
Unfortunately XP is still my developing platform (have no access to Windows7 etc.). Maybe it could be a fallback. Oliver

Oliver Kowalke <k-oli@gmx.de> writes:
Anything that uses thread-local variables or fiber-local variables will fail if you just run it on another thread or fiber. This can include C runtime functions --- errno is typically thread-local, for example.
Or do I have to use a special function form the Win32 API?
You need 3 fibers to move a fiber between threads: Thread A is running Fiber 1. It switches to Fiber 2. Thread B is running Fiber 3. It switches to Fiber 1. Hey presto, fiber 1 has switched threads. All is now well, provided code on Fiber 1 doesn't use thread-local variables. Recent versions of the MSVC runtime use fiber-local variables instead of thread-local ones, so standard C and C++ functions should be OK, but e.g. boost::thread uses thread-local variables for things like the thread ID, thread_specific_ptr variables and at_thread_exit handlers. Anthony -- Author of C++ Concurrency in Action http://www.stdthread.co.uk/book/ just::thread C++0x thread library http://www.stdthread.co.uk Just Software Solutions Ltd http://www.justsoftwaresolutions.co.uk 15 Carrallack Mews, St Just, Cornwall, TR19 7UL, UK. Company No. 5478976

Am 29.07.2010 10:36, schrieb Anthony Williams:
OK - it's up to the user anyway. Using thread-local-storage in different threads is always false and boost.context hasn't take special care.
So SwitchToFiber() takes care of TIB (setting the members accordingly). AFAIK only SEH frame, top of stack, current bottom of stack - thats's what boost.context does.
Hmm - maybe boost.context should take care of fiber data (fs:[0x10]) and arbitary data slot (fs:[0x14])?! Oliver

I must admit I haven't been following all of this thread but I'm quite a bit concerned by this approach. I worked on VC's CRT for over two years and I can tell you that these things are much more involved (and from haunting a shutdown bug I'm fairly certain there's another pointer fairly high up in the TIB to the FLS data and/or rundown list). Unless there's documentation that clearly states you can rely on binary layout and semantics of structure members, you shouldn't. Besides execution context is not something considered stable within the operating system itself as there are architectural advancements (AVX register state is a recent example that was up for a change in Windows 7 and again in W7 SP1 -- and VC10 does generate instructions accessing YMM registers even without intrinsics in user code). Again, I haven't looked at code (yet?) and I'm no longer with MSFT and can't just look up the bits, but trying to outsmart the OS facilities is almost certainly a bad idea. -hg

Although this is correct, I would like to emphasize that sometimes it does make sense to use thread local storage even with fibers. This requires careful design, but allows to attach data to the OS threads driving the whole thing. I gues what I want to say is that it's not a good idea to fully replace TLS with FLS, but both need to complement each other. Regards Hartmut --------------- Meet me at BoostCon www.boostcon.com

On Wed, Jul 28, 2010 at 7:08 AM, Oliver Kowalke <k-oli@gmx.de> wrote:
Wouldn't it be nicer if the framework catches exceptions from the functions and then propagates them to the caller from jump_to() or a special function exception_ptr get_error()? Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

Am 28.07.2010 20:28, schrieb Emil Dotchevski:
No, because boost.context behaves like POSIX ucontext. The app exits if the function executed by the context ends. You could 'link' to another context which will be executed after finishing up the function. What you suggest should be part of higher levels - you could find such exception passing in boost.fiber which uses a future object for this purpose. Oliver

On Wed, Jul 28, 2010 at 11:41 AM, Oliver Kowalke <k-oli@gmx.de> wrote:
I'm not familiar with ucontext, what is the rationale for that behavior? How do I go about creating a system where contexts are created and destroyed dynamically? Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

Am 28.07.2010 20:46, schrieb Emil Dotchevski:
If one context ends what should be the standard behaviour? When the main-context (main function ends) - the app exits. If you which to jump to the originating context (for instance it may be main()) you can link against it and the originating context will continue its execution.
How do I go about creating a system where contexts are created and destroyed dynamically?
look into boost.fiber or boost.task boost.fiber uses boost.context to implement cooperative scheduling and boost.task uses boost.fiber to distribute several tasks on a limited set of threads. Oliver

On 07/28/10 01:42, Oliver Kowalke wrote:
downloadable from boost vault: http://www.boostpro.com/vault/index.php?action=downloadfile&filename=boost.context-0.1.0.zip&directory=Concurrent%20Programming&
[snip] Thanks Oliver. The html file: boost.context-0.1.0/libs/context/doc/html/context/overview.html contains: -{--cut here-- * Boost.Context can be build using assembler (fcontext_t) for context switching o call bjam toolset=<compiler> architecture=<arch> instruction-set=<set> --with-context install in order to build and install the library o bjam toolset=gcc architectue=x86 instruction-set=i686 --with-context install o bjam toolset=gcc architectue=x86 instruction-set=yorksfield --with-context install o bjam toolset=gcc architectue=arm --with-context install * the library uses ucontext_t on POSIX-platforms when build without properties architecture and instruction-set -}--cut here-- However, there's no explanation of or links from fcontext_t or ucontext_t. Could you provide them on this page? TIA. -regards, Larry

On 07/28/10 01:42, Oliver Kowalke wrote:
downloadable from boost vault: http://www.boostpro.com/vault/index.php?action=downloadfile&filename=boost.context-0.1.0.zip&directory=Concurrent%20Programming&
[snip] The html file: boost.context-0.1.0/libs/context/doc/html/context/context_management/context/jump_to.html contains: -{--cut here-- If *this refers to a context, the function saves the state of *this and executes the context of other. -}--cut here-- What's the saved state used for? I'm guessing that maybe it's used to resume execution of the original context after the other context finishes executing. Is that right? -regards, Larry

Am 28.07.2010 13:01, schrieb Larry Evans:
Right! It saves the register of the cpu (like stack pointer instruction pointer etc.). The context must not necessarily finish its execution it can decide to suspend itself - its state is saved and may be resumed later (e.g. it continues its work if resumed). Oliver

On Tue, Jul 27, 2010 at 10:52 PM, Oliver Kowalke <k-oli@gmx.de> wrote:
Hello John, hello Ronald,
could you add boost.context to the review queue please.
Looks good, I'll just add that it would be nice to support boost::function too, possibly as a separate namespace-scope interface. Emil Dotchevski Reverge Studios, Inc. http://www.revergestudios.com/reblog/index.php?n=ReCode

Am 28.07.2010 20:34, schrieb Emil Dotchevski:
boost.context was an implementation detail of boost.fiber. Phil Endecott requested to move this code in a separate library. boost::function is supported by boost.fiber (which uses boost.context as basis). boost.coroutine which uses POSIX ucontext could use it too (AFAIK boost.coroutine has assembler for i386). Oliver
participants (10)
-
Anthony Williams
-
ecyrbe
-
Emil Dotchevski
-
Hartmut Kaiser
-
Holger Grund
-
Larry Evans
-
Oliver Kowalke
-
Robert Ramey
-
Ronald Garcia
-
Yigong Liu