Hello,
Is there any mechanism to switch contexts in Genode threads? What I want to do is, whenever some condition is satisfied, to save the current thread context, create a new context (new stack, update sp and ip) to substitute the thread's old context, and restore the old context when another condition is satisfied.
I have looked into the implementation of the Thread class and, even though the thread context is public, the context allocation APIs seem to be private. Is there some other public API that I can use for this purpose? What would be the most reasonable way to tackle this?
Thanks.
Amadeo
Hello Amadeo,
is your question related to Daniel's posting earlier this month?
http://genode.org/community/viewml?thread_name=008f01cbddc7%248cdc9d90%24a69...
Is there any mechanism to switch contexts in Genode threads? What I want to do is, whenever some condition is satisfied, to save the current thread context, create a new context (new stack, update sp and ip) to substitute the thread’s old context, and restore the old context when another condition is satisfied.
In short, there is currently no way in asynchronously changing the context of a Genode thread via the Genode API.
Your question leaves open whether or not the original threads gets preempted (similar to receiving an interrupt) at any time during its execution, or if the thread explicitly yields control (e.g., by trying to get a lock, or by invoking a system call). The former case is similar to a VCPU execution model, which must be supported by the underlying kernel. Of Genode's current base platforms, only Fiasco.OC provides such a feature. Hence, Genode does not expose a VCPU-like abstraction at its API level. The latter case is much easier because your problem can be modelled with using multiple threads and locking, or by employing a user-level threading library (using setjmp/longjmp).
I have looked into the implementation of the Thread class and, even though the thread context is public, the context allocation APIs seem to be private. Is there some other public API that I can use for this purpose? What would be the most reasonable way to tackle this?
The 'Thread_base::Context' does not contain any CPU registers. It hosts only the meta data Genode needs to manage and use the thread. For example, the pointer to the Thread's UTCB, the thread name, and the top of the stack. Therefore, this API is private to Genode.
To provide you with a sensible approach, I'd appreciate more specific information about your actual problem. In particular, the above question (VCPU semantics or synchronous flow of control) is important.
Regards Norman
Norman, When we first tried this we used getcontext/makecontext/setcontext like implementations. Basically these APIs allow us to construct a stack and register state (context) to switch to. I thread is switched by loading the registers and changing the ip/sp. I think the main issue is that in our first attempt we did not copy the "additional context members" and "UTCB" to the new stack frame. The thread switching works until you try to access the utcb.
Do you see any issue in simply copying these extra bits?
Daniel
On 03/25/2011 01:51 AM, Norman Feske wrote:
Hello Amadeo,
is your question related to Daniel's posting earlier this month?
http://genode.org/community/viewml?thread_name=008f01cbddc7%248cdc9d90%24a69...
Is there any mechanism to switch contexts in Genode threads? What I want to do is, whenever some condition is satisfied, to save the current thread context, create a new context (new stack, update sp and ip) to substitute the thread’s old context, and restore the old context when another condition is satisfied.
In short, there is currently no way in asynchronously changing the context of a Genode thread via the Genode API.
Your question leaves open whether or not the original threads gets preempted (similar to receiving an interrupt) at any time during its execution, or if the thread explicitly yields control (e.g., by trying to get a lock, or by invoking a system call). The former case is similar to a VCPU execution model, which must be supported by the underlying kernel. Of Genode's current base platforms, only Fiasco.OC provides such a feature. Hence, Genode does not expose a VCPU-like abstraction at its API level. The latter case is much easier because your problem can be modelled with using multiple threads and locking, or by employing a user-level threading library (using setjmp/longjmp).
I have looked into the implementation of the Thread class and, even though the thread context is public, the context allocation APIs seem to be private. Is there some other public API that I can use for this purpose? What would be the most reasonable way to tackle this?
The 'Thread_base::Context' does not contain any CPU registers. It hosts only the meta data Genode needs to manage and use the thread. For example, the pointer to the Thread's UTCB, the thread name, and the top of the stack. Therefore, this API is private to Genode.
To provide you with a sensible approach, I'd appreciate more specific information about your actual problem. In particular, the above question (VCPU semantics or synchronous flow of control) is important.
Regards Norman
I'm thinking also that we'd have to change the kernel UTCB mappings?
Daniel
On 03/25/2011 01:51 AM, Norman Feske wrote:
Hello Amadeo,
is your question related to Daniel's posting earlier this month?
http://genode.org/community/viewml?thread_name=008f01cbddc7%248cdc9d90%24a69...
Is there any mechanism to switch contexts in Genode threads? What I want to do is, whenever some condition is satisfied, to save the current thread context, create a new context (new stack, update sp and ip) to substitute the thread’s old context, and restore the old context when another condition is satisfied.
In short, there is currently no way in asynchronously changing the context of a Genode thread via the Genode API.
Your question leaves open whether or not the original threads gets preempted (similar to receiving an interrupt) at any time during its execution, or if the thread explicitly yields control (e.g., by trying to get a lock, or by invoking a system call). The former case is similar to a VCPU execution model, which must be supported by the underlying kernel. Of Genode's current base platforms, only Fiasco.OC provides such a feature. Hence, Genode does not expose a VCPU-like abstraction at its API level. The latter case is much easier because your problem can be modelled with using multiple threads and locking, or by employing a user-level threading library (using setjmp/longjmp).
I have looked into the implementation of the Thread class and, even though the thread context is public, the context allocation APIs seem to be private. Is there some other public API that I can use for this purpose? What would be the most reasonable way to tackle this?
The 'Thread_base::Context' does not contain any CPU registers. It hosts only the meta data Genode needs to manage and use the thread. For example, the pointer to the Thread's UTCB, the thread name, and the top of the stack. Therefore, this API is private to Genode.
To provide you with a sensible approach, I'd appreciate more specific information about your actual problem. In particular, the above question (VCPU semantics or synchronous flow of control) is important.
Regards Norman
Hi Daniel,
On 03/25/2011 06:12 PM, Daniel Waddington wrote:
the registers and changing the ip/sp. I think the main issue is that in our first attempt we did not copy the "additional context members" and "UTCB" to the new stack frame. The thread switching works until you try to access the utcb.
I suspect that the culprit here is the 'Thread_base::myself()' function, which is used by the callee to determine it's 'Thread_base' object. This function uses the stack pointer as key to find the callee's 'Thread_base::Context'. The stack pointer is expected to reside within the so-called thread-context area. Each thread owns a slot within this virtual address range (currently a slot is 1MB - details can be found in 'base/include/base/thread.h'). Within each slot, there resides the thread's stack and the its 'Thread_base::Context' object.
Now, if you switch the stack pointer to an address allocated somewhere outside the thread-context area, the 'Thread_base::myself()' function will assume that the callee is the main thread (the main thread has no slot in the thread-context area, its stack is located within the BSS segment). Consequently, functionality that relies on the thread context (such as locking) is going to fail.
To overcome this problem, I see three possible solutions:
First, the 'Thread_base' class could be extended by a hook for considering additional stack ranges when 'Thread_base::myself()' is called. This hook would by able to tell 'Thread_base::myself()' about the physical thread context belonging to stack ranges allocated by a user-level threading library.
Alternatively, you might try placing the stack of the user-level thread within the same context-area slot as used by the physical thread so that 'Thread_base::myself()' will always return the correct physical 'Thread_base' object. To see how to directly interact with the thread-context area, please have a look at 'base/src/base/thread/thread.cc', in particular '_alloc_context()'.
As a third approach, you might consider adding support for user-level threads in a way that each user-level thread uses a real 'Thread_base' context but not a physical thread. Each thread context of a user-level thread would have a reference to the physical 'Thread_base' object used for its execution. This way, when 'Thread_base::myself()' is called, the 'myself()' function would first look whether the callee is a user-level thread. If so, it would return the referenced physical 'Thread_base' object. I think, this approach would be the most elegant one, mostly because it would allow the detection of stack overflows of user-level threads as each user-level thread would be subject to the overflow protection provided by the thread-context mechanism.
Best regards Norman