From 3268601daeb7bc61d17a80abc5ea958bc65e4028 Mon Sep 17 00:00:00 2001 From: Jinoh Kang Date: Sat, 18 Mar 2023 23:52:51 +0900 Subject: [PATCH] kernelbase: Implement activation context switching for fibers. --- dlls/kernel32/tests/fiber.c | 10 ++++---- dlls/kernelbase/thread.c | 47 +++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 5 deletions(-) diff --git a/dlls/kernel32/tests/fiber.c b/dlls/kernel32/tests/fiber.c index b0e50c791ad..46590075ffc 100644 --- a/dlls/kernel32/tests/fiber.c +++ b/dlls/kernel32/tests/fiber.c @@ -839,7 +839,7 @@ static void WINAPI fiber_actctx_func(void *actctx) HANDLE thread; BOOL ret; - check_current_actctx_is(NULL, TRUE); + check_current_actctx_is(NULL, FALSE); ret = ActivateActCtx(actctx, &cookie); ok(ret, "ActivateActCtx returned error %lu\n", GetLastError()); @@ -858,7 +858,7 @@ static void WINAPI fiber_actctx_func(void *actctx) ret = DeactivateActCtx(0, cookie); ok(ret, "DeactivateActCtx returned error %lu\n", GetLastError()); - check_current_actctx_is(NULL, TRUE); + check_current_actctx_is(NULL, FALSE); SwitchToFiber(fibers[0]); ok(0, "unreachable\n"); @@ -872,10 +872,10 @@ static void subtest_fiber_actctx_switch(HANDLE current_actctx, HANDLE child_actc check_current_actctx_is(current_actctx, FALSE); SwitchToFiber(fibers[1]); - check_current_actctx_is(current_actctx, TRUE); + check_current_actctx_is(current_actctx, FALSE); SwitchToFiber(fibers[1]); - check_current_actctx_is(current_actctx, TRUE); + check_current_actctx_is(current_actctx, FALSE); SwitchToFiber(fibers[2]); check_current_actctx_is(current_actctx, FALSE); @@ -910,7 +910,7 @@ static DWORD WINAPI thread_actctx_func_early_exit(void *actctx) /* exit thread, but keep current fiber */ SwitchToFiber(exit_thread_fiber); - check_current_actctx_is(actctx, TRUE); + check_current_actctx_is(actctx, FALSE); SwitchToFiber(fibers[0]); ok(0, "unreachable\n"); diff --git a/dlls/kernelbase/thread.c b/dlls/kernelbase/thread.c index 235624811f5..f6eb6b0e51e 100644 --- a/dlls/kernelbase/thread.c +++ b/dlls/kernelbase/thread.c @@ -768,6 +768,12 @@ BOOL WINAPI DECLSPEC_HOTPATCH TlsSetValue( DWORD index, LPVOID value ) ***********************************************************************/ +struct fiber_actctx +{ + ACTIVATION_CONTEXT_STACK stack_space; /* activation context stack space */ + ACTIVATION_CONTEXT_STACK *stack_ptr; /* last value of ActivationContextStackPointer */ +}; + struct fiber_data { LPVOID param; /* 00/00 fiber param */ @@ -779,6 +785,7 @@ struct fiber_data DWORD flags; /* fiber flags */ LPFIBER_START_ROUTINE start; /* start routine */ void *fls_slots; /* fiber storage slots */ + struct fiber_actctx actctx; /* activation context state */ }; extern void WINAPI switch_fiber( CONTEXT *old, CONTEXT *new ); @@ -931,6 +938,38 @@ static void init_fiber_context( struct fiber_data *fiber ) #endif } +static void move_list( LIST_ENTRY *dest, LIST_ENTRY *src ) +{ + LIST_ENTRY *head = src->Flink; + LIST_ENTRY *tail = src->Blink; + + if (src != head) + { + dest->Flink = head; + dest->Blink = tail; + head->Blink = dest; + tail->Flink = dest; + } + else InitializeListHead( dest ); +} + +static void relocate_thread_actctx_stack( ACTIVATION_CONTEXT_STACK *dest ) +{ + ACTIVATION_CONTEXT_STACK *src = NtCurrentTeb()->ActivationContextStackPointer; + + C_ASSERT(sizeof(*dest) == sizeof(dest->ActiveFrame) + sizeof(dest->FrameListCache) + + sizeof(dest->Flags) + sizeof(dest->NextCookieSequenceNumber) + + sizeof(dest->StackId)); + + dest->ActiveFrame = src->ActiveFrame; + move_list( &dest->FrameListCache, &src->FrameListCache ); + dest->Flags = src->Flags; + dest->NextCookieSequenceNumber = src->NextCookieSequenceNumber; + dest->StackId = src->StackId; + + NtCurrentTeb()->ActivationContextStackPointer = dest; +} + /*********************************************************************** * CreateFiber (kernelbase.@) @@ -969,6 +1008,8 @@ LPVOID WINAPI DECLSPEC_HOTPATCH CreateFiberEx( SIZE_T stack_commit, SIZE_T stack fiber->except = (void *)-1; fiber->start = start; fiber->flags = flags; + InitializeListHead( &fiber->actctx.stack_space.FrameListCache ); + fiber->actctx.stack_ptr = &fiber->actctx.stack_space; init_fiber_context( fiber ); return fiber; } @@ -983,6 +1024,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH ConvertFiberToThread(void) if (fiber) { + relocate_thread_actctx_stack( &NtCurrentTeb()->ActivationContextStack ); NtCurrentTeb()->Tib.u.FiberData = NULL; HeapFree( GetProcessHeap(), 0, fiber ); } @@ -1025,6 +1067,7 @@ LPVOID WINAPI DECLSPEC_HOTPATCH ConvertThreadToFiberEx( LPVOID param, DWORD flag fiber->start = NULL; fiber->flags = flags; fiber->fls_slots = NtCurrentTeb()->FlsSlots; + relocate_thread_actctx_stack( &fiber->actctx.stack_space ); NtCurrentTeb()->Tib.u.FiberData = fiber; return fiber; } @@ -1040,11 +1083,13 @@ void WINAPI DECLSPEC_HOTPATCH DeleteFiber( LPVOID fiber_ptr ) if (!fiber) return; if (fiber == NtCurrentTeb()->Tib.u.FiberData) { + relocate_thread_actctx_stack( &NtCurrentTeb()->ActivationContextStack ); HeapFree( GetProcessHeap(), 0, fiber ); RtlExitUserThread( 1 ); } RtlFreeUserStack( fiber->stack_allocation ); RtlProcessFlsData( fiber->fls_slots, 3 ); + RtlFreeActivationContextStack( &fiber->actctx.stack_space ); HeapFree( GetProcessHeap(), 0, fiber ); } @@ -1069,6 +1114,7 @@ void WINAPI DECLSPEC_HOTPATCH SwitchToFiber( LPVOID fiber ) current_fiber->except = NtCurrentTeb()->Tib.ExceptionList; current_fiber->stack_limit = NtCurrentTeb()->Tib.StackLimit; current_fiber->fls_slots = NtCurrentTeb()->FlsSlots; + current_fiber->actctx.stack_ptr = NtCurrentTeb()->ActivationContextStackPointer; /* stack_allocation and stack_base never change */ /* FIXME: should save floating point context if requested in fiber->flags */ @@ -1078,6 +1124,7 @@ void WINAPI DECLSPEC_HOTPATCH SwitchToFiber( LPVOID fiber ) NtCurrentTeb()->Tib.StackLimit = new_fiber->stack_limit; NtCurrentTeb()->DeallocationStack = new_fiber->stack_allocation; NtCurrentTeb()->FlsSlots = new_fiber->fls_slots; + NtCurrentTeb()->ActivationContextStackPointer = new_fiber->actctx.stack_ptr; switch_fiber( ¤t_fiber->context, &new_fiber->context ); }