
Hello, I am checking out the fascinating work with Boost.Coroutine. Excellent! This is definitely paving the way for C++ threads. I have been looking for this kind of thing for quite some time now. I am mostly interested in adaptability, as I386 and the lot are mostly done. It's always the same game with the cooperative context switching. Time-after-time, you identify the clobbered registers after a cooperative yield, save them in a context structure and restore them after the yield. Then you deal with the stacks. OK, fine. But how can you approach the dream of generic context switching? So you know, here I am. I would want Boost.Context for numerous GCC targets: Atmel AVR, Renesas V850, Renesas RL78, Cortex-M3/4. And the list goes on, as I use numerous embedded processors. The compiler's calling convention is poorly documented at best. And various compiler vendors may or may not coordinate the calling convention among each other. Can the documentation of Boost.Coroutine aid in adaptation in any way? Or is this simply beyond the present scope of the proposed Boost.Coroutine? * Is there any documentation regarding the context switch? * Are you specifically targeting preemptive yields? * If so, is the compiler's calling convention taken into account? * Can the remarkable Boost.Coroutine be adapted to other CPUs? * How? * Is Coroutine meant to be compatible with std::this_thread::yield(), etc? * Can the user select the stack sizes? * How? Thank you. And keep up the great work! Best regards, Chris.

But how can you approach the dream of generic context switching? So you know, here I am. I would want Boost.Context for numerous GCC targets: Atmel AVR, Renesas V850, Renesas RL78, Cortex-M3/4. And the list goes on, as I use numerous embedded processors.
boost.coroutine uses boost.context for context switching and therefore you have to add support for the numerous architectures to boost.context in order to get boost.coroutine working on those CPUs.
* Is there any documentation regarding the context switch?
take a look in documentation of boost.context
* Are you specifically targeting preemptive yields?
no - it is cooperative
* If so, is the compiler's calling convention taken into account?
of course otherwise it would not work -> ABI
* Can the remarkable Boost.Coroutine be adapted to other CPUs? * How?
adapt boost.context for the specific architecture/ABI
* Is Coroutine meant to be compatible with std::this_thread::yield(),
no
* Can the user select the stack sizes? * How?
yes - one of ctor's argument regards, Oliver -- Empfehlen Sie GMX DSL Ihren Freunden und Bekannten und wir belohnen Sie mit bis zu 50,- Euro! https://freundschaftswerbung.gmx.de

But how can you approach the dream of generic context switching?
<snip>
boost.coroutine uses boost.context for context switching and therefore you have to add support for the numerous architectures to boost.context in order to get boost.coroutine working on those CPUs.
<snip>
* Can the remarkable Boost.Coroutine be adapted to other CPUs? * How?
adapt boost.context for the specific architecture/ABI regards, Oliver
Wow! This is really cool! I really appreciate what you are doing here! (Hut ab! Einfach Klasse!) It looks like you have really done your homework on this one. But I am still having difficulties identifying the context switch. In cooperative multitasking, the compiler *knows* which registers will be clobbered. Boost.Context has an abstraction of the clobbered registers, the stack pointer and the return address after subroutine call. And, yes, you do note in the doc that the cooperative task switch may be significantly more efficient than the preemptive one. Upon task yield, you need to store the coroutine's context in some kind of a task control block (the context). And you need to subsequently restore this context prior to rescheduling the task. In the past, I would always pass a pointer to an abstraction of the context to an assembly routine that was responsible for * context-save * task switch * context-restore and task re-scheduleWhere are these things in Boost.Coroutine? Where is the low-level assembly that does the *nuts-and-bolts* of the context switching? Or am I just totally confused here? Are you doing it in a high-level abstraction that I simply don't understand? Are you using proprocessor macros to do the context switch? Where is the assembler stuff? Thank you and best regards. Chris

Hi Chris,
In the past, I would always pass a pointer to an abstraction of the context to an assembly routine that was responsible for
* context-save * task switch * context-restore and task re-schedule
Where are these things in Boost.Coroutine? Where is the low-level assembly that does the *nuts-and-bolts* of the context switching?
boost.context contains struct fcontext_t storing the architecture+ABI specific stuff (registers) and functions make_fcontext() and jump_fcontext(). The first function is used to set up a fcontext_t and the second one is used to jump from one context to another one. Both functions are written in assembler. Template coroutine aggregates two fcontext's. One to store the relevant registers form the calling context and the second struct contains the register stuff of the to called context (coroutines context, coroutine's funtion).
Or am I just totally confused here? Are you doing it in a high-level abstraction that I simply don't understand? Are you using proprocessor macros to do the context switch?
it's assembler code (no inline assembler).
Where is the assembler stuff?
libs/context/src/asm/... so long, Oliver -- NEU: FreePhone 3-fach-Flat mit kostenlosem Smartphone! Jetzt informieren: http://mobile.1und1.de/?ac=OM.PW.PW003K20328T7073a

Where is the low-level assembly that does the *nuts-and-bolts* of the context switching?
boost.context contains struct fcontext_t storing the architecture+ABI specific stuff (registers) and functions make_fcontext() and jump_fcontext(). The first function is used to set up a fcontext_t and the second one is used to jump from one context to another one. Both functions are written in assembler.
OK. Thanks Oliver. I *really* appreciate what you are doing with context and coroutine. I haven't fully comprehended the depths of your fascinating development, but I sort of get it. I know it's wayyy too late in the game for any top-level requirements. But I would recommend inserting a potentially user-customizable functional element between the context-save and the context-restore. Maybe you already have it and I'm a dummy who can't see it. Do you know why I suggest this? Because we could specialize the functional element to implement a simple (nearly portable) time-slicing cooperative multitasking scheduler simply using a container filled with (coroutine + timer) objects. You already have a yield() function. And I do see some evidence of events and waiting. With a scheduling element and a potential sleep_for() function we could essentially get a robust cooperative multitasking scheduler *right off the rack* from boost. And this is the kind of thing that I, personally, would definitely want to adapt to other architectures. Back in the day, I spent about 5 years, off-and-on writing multitasking schedulers. I eventually ended up at your design---but with scheduling and sleep_for(), but not in the cool boost-way that you have. And these schedulers are still running and being produced in tens of millions of products to this very day.
Template coroutine aggregates two fcontext's. One to store the relevant registers form the calling context and the second struct contains the register stuff of the to called context (coroutines context, coroutine's funtion).
Or am I just totally confused here? Are you doing it in a high-level abstraction that I simply don't understand? Are you using proprocessor macros to do the context switch?
it's assembler code (no inline assembler). Yeah. It's the only way to do it.
Where is the assembler stuff? libs/context/src/asm/...
OK. I Got it. Thanks so much for the clarifications. Well, I need to get back to my other math projects and the pesky day job. I am looking forward to any progress with Boost.Coroutine. Thanks again for this contribution. Best regards, Chris.

I know it's wayyy too late in the game for any top-level requirements. But I would recommend inserting a potentially user-customizable functional element between the context-save and the context-restore.
Maybe you already have it and I'm a dummy who can't see it.
Do you know why I suggest this?
Because we could specialize the functional element to implement a simple (nearly portable) time-slicing cooperative multitasking scheduler simply using a container filled with (coroutine + timer) objects. You already have a yield() function. And I do see some evidence of events and waiting. With a scheduling element and a potential sleep_for() function we could essentially get a robust cooperative multitasking scheduler *right off the rack* from boost.
I'm currently working on a library for cooperative multitasking (containing a scheduler etc.) - boost.stratified. It provides some kind of user-land threads together with mutexs, condition- and event variables ... Maybe we can talk about it in a private conversation. regards, Oliver
participants (3)
-
Christopher Kormanyos
-
Oliver Kowalke
-
Steven Watanabe