Tech Off Post

Single Post Permalink

View Thread: IL to C++ compiler - Need advice on implementing context switching
  • User profile image
    Dexter

    So instead, I need to have an additional void* in each thread whose address will be passed in to the SwitchContext call, correct?

    Yes, this value contains the current stack pointer for the thread. When you switch away from a thread its current stack pointer gets saved and the stack pointer of the new thread is loaded.

    The question is, if this is the very first context switch, what should be stored at the pNewStack value

    That's the role of InitializeContext, it sets up the initial stack so it looks similar to the one expected by SwitchContext. That's why the start address gets pushed on the stack, when SwitchContext willreturn to what's stored on the stack, your start address. This might sound strange, the start function is notcalled but returned too, but it works fine as long as the stack is setup correctly. That's also the reason for those 4 push eax, they compensate the fact that SwitchContext pops edi, esi, ebp, ebx.

    I assume this should be at some negative offset into that thread's NativeStack

    The InitializeContext already computes the correct value but it looks like it doesn't store it correctly. Let's fix things a bit:

    void NativePlatform::InitializeThreadContext(RuntimeThread* pThread, VirtualObject** pData) {
        void* stack = pThread->NativeStack;
        void* startAddress = (void*)pThread->GetStartAddress();

        __asm {
            // Save current stack
            mov ecx, esp

            // Switch to pThread's stack
            mov esp, stack

            // Push arguments for the start function
            // It looks like your start function expects pThread and pData so:
            mov eax, pData
            push eax      
            mov eax, pThread
            push eax

            // Push the start function address, SwitchContext will return to this address
            mov eax, startAddress
            push eax

            // Push 4 values to compensate for pop edi, esi, ebx, ebp in SwitchContext
            xor eax, eax
            push eax
            push eax
            push eax
            push eax

            // At this point the stack is similar to what SwitchContext expects, save the stack pointer
            mov stack, esp

            // Switch back to this thread's stack
            mov esp, ecx
        }
        // save the thread's current stack pointer
        pThread->CurrentStackPointer = stack;
    }

    I added some comments to make it more clear and also added arguments for your start function (my previous example didn't pass any arguments to the start function).

    After InitializeContext runs you should be able to switch to the new thread by doing SwitchContext(&currentThread->CurrentStackPointer, &newThread->CurrentStackPointer).

    Now there's another fun thing to solve. What happens when the thread exits? Big Smile