Thread context switch
norman.feske at ...1...
Sat Mar 26 14:27:51 CET 2011
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.
Dr.-Ing. Norman Feske
http://www.genode-labs.com · http://genode.org
Genode Labs GmbH · Amtsgericht Dresden · HRB 28424 · Sitz Dresden
Geschäftsführer: Dr.-Ing. Norman Feske, Christian Helmuth
More information about the users