From: Jinoh Kang jinoh.kang.kr@gmail.com
--- dlls/kernel32/tests/fiber.c | 222 ++++++++++++++++++++++++++++++++++++ 1 file changed, 222 insertions(+)
diff --git a/dlls/kernel32/tests/fiber.c b/dlls/kernel32/tests/fiber.c index 433883e5a26..5540305cd1a 100644 --- a/dlls/kernel32/tests/fiber.c +++ b/dlls/kernel32/tests/fiber.c @@ -24,6 +24,7 @@ #define WIN32_NO_STATUS #include <winternl.h> #include "wine/test.h" +#include <winuser.h>
static LPVOID (WINAPI *pCreateFiber)(SIZE_T,LPFIBER_START_ROUTINE,LPVOID); static LPVOID (WINAPI *pConvertThreadToFiber)(LPVOID); @@ -791,6 +792,226 @@ static void test_FiberLocalStorageWithFibers(PFLS_CALLBACK_FUNCTION cbfunc) test_ConvertFiberToThread(); }
+#define check_current_actctx_is(e,t) check_current_actctx_is_(__LINE__, e, t) +static void check_current_actctx_is_(int line, HANDLE expected_actctx, BOOL todo) +{ + HANDLE cur_actctx; + BOOL ret; + + cur_actctx = (void*)0xdeadbeef; + ret = GetCurrentActCtx(&cur_actctx); + ok_(__FILE__, line)(ret, "thread GetCurrentActCtx failed, %lu\n", GetLastError()); + + todo_wine_if(todo) + ok_(__FILE__, line)(cur_actctx == expected_actctx, "got %p, expected %p\n", cur_actctx, expected_actctx); + + ReleaseActCtx(cur_actctx); +} + +static DWORD WINAPI subthread_actctx_func(void *actctx) +{ + HANDLE fiber; + BOOL ret; + + check_current_actctx_is(actctx, FALSE); + + fiber = pConvertThreadToFiber(NULL); + ok(fiber != NULL, "ConvertThreadToFiber returned error %lu\n", GetLastError()); + check_current_actctx_is(actctx, FALSE); + fibers[2] = fiber; + + SwitchToFiber(fibers[0]); + check_current_actctx_is(actctx, FALSE); + + ok(fibers[2] == fiber, "fibers[2]: expected %p, got %p\n", fiber, fibers[2]); + fibers[2] = NULL; + ret = pConvertFiberToThread(); + ok(ret, "ConvertFiberToThread returned error %lu\n", GetLastError()); + check_current_actctx_is(actctx, FALSE); + + return 0; +} + +static void WINAPI fiber_actctx_func(void *actctx) +{ + ULONG_PTR cookie; + DWORD tid, wait; + HANDLE thread; + BOOL ret; + + check_current_actctx_is(NULL, TRUE); + + ret = ActivateActCtx(actctx, &cookie); + ok(ret, "ActivateActCtx returned error %lu\n", GetLastError()); + check_current_actctx_is(actctx, FALSE); + + SwitchToFiber(fibers[0]); + check_current_actctx_is(actctx, FALSE); + + thread = CreateThread(NULL, 0, subthread_actctx_func, actctx, 0, &tid); + ok(thread != NULL, "CreateThread returned error %lu\n", GetLastError()); + + wait = WaitForSingleObject(thread, INFINITE); + ok(wait == WAIT_OBJECT_0, "WaitForSingleObject returned %lu (last error: %lu)\n", + wait, GetLastError()); + CloseHandle(thread); + + ret = DeactivateActCtx(0, cookie); + ok(ret, "DeactivateActCtx returned error %lu\n", GetLastError()); + check_current_actctx_is(NULL, TRUE); + + SwitchToFiber(fibers[0]); + ok(0, "unreachable\n"); +} + +/* Test that activation context is switched on SwitchToFiber() call */ +static void subtest_fiber_actctx_switch(HANDLE current_actctx, HANDLE child_actctx) +{ + fibers[1] = pCreateFiber(0, fiber_actctx_func, child_actctx); + ok(fibers[1] != NULL, "CreateFiber returned error %lu\n", GetLastError()); + check_current_actctx_is(current_actctx, FALSE); + + SwitchToFiber(fibers[1]); + check_current_actctx_is(current_actctx, TRUE); + + SwitchToFiber(fibers[1]); + check_current_actctx_is(current_actctx, TRUE); + + SwitchToFiber(fibers[2]); + check_current_actctx_is(current_actctx, FALSE); + ok(fibers[2] == NULL, "expected fiber to be deleted (got %p)\n", fibers[2]); + + DeleteFiber(fibers[1]); + fibers[1] = NULL; +} + +static void WINAPI exit_thread_fiber_func(void *unused) +{ + BOOL ret; + + (void)unused; + ret = pConvertFiberToThread(); + ok(ret, "ConvertFiberToThread returned error %lu\n", GetLastError()); + + ExitThread(16); +} + +static DWORD WINAPI thread_actctx_func_early_exit(void *actctx) +{ + HANDLE exit_thread_fiber; + + check_current_actctx_is(actctx, FALSE); + + fibers[1] = pConvertThreadToFiber(NULL); + ok(fibers[1] != NULL, "ConvertThreadToFiber returned error %lu\n", GetLastError()); + check_current_actctx_is(actctx, FALSE); + + exit_thread_fiber = pCreateFiber(0, exit_thread_fiber_func, NULL); + ok(exit_thread_fiber != NULL, "CreateFiber returned error %lu\n", GetLastError()); + + /* exit thread, but keep current fiber */ + SwitchToFiber(exit_thread_fiber); + check_current_actctx_is(actctx, TRUE); + + SwitchToFiber(fibers[0]); + ok(0, "unreachable\n"); + return 17; +} + +/* Test that fiber activation context stack is preserved regardless of creator thread's lifetime */ +static void subtest_fiber_actctx_preservation(HANDLE current_actctx, HANDLE child_actctx) +{ + ULONG_PTR cookie; + DWORD tid, wait; + HANDLE thread; + BOOL ret; + + ret = ActivateActCtx(child_actctx, &cookie); + ok(ret, "ActivateActCtx returned error %lu\n", GetLastError()); + check_current_actctx_is(child_actctx, FALSE); + + thread = CreateThread(NULL, 0, thread_actctx_func_early_exit, child_actctx, 0, &tid); + ok(thread != NULL, "CreateThread returned error %lu\n", GetLastError()); + + ret = DeactivateActCtx(0, cookie); + ok(ret, "DeactivateActCtx returned error %lu\n", GetLastError()); + check_current_actctx_is(current_actctx, FALSE); + + wait = WaitForSingleObject(thread, INFINITE); + ok(wait == WAIT_OBJECT_0, "WaitForSingleObject returned %lu (last error: %lu)\n", + wait, GetLastError()); + CloseHandle(thread); + + /* The exited thread has been converted to a fiber */ + SwitchToFiber(fibers[1]); + check_current_actctx_is(current_actctx, FALSE); + + DeleteFiber(fibers[1]); + fibers[1] = NULL; +} + +static HANDLE create_actctx_from_module_manifest(void) +{ + ACTCTXW actctx; + + memset(&actctx, 0, sizeof(ACTCTXW)); + actctx.cbSize = sizeof(actctx); + actctx.dwFlags = ACTCTX_FLAG_HMODULE_VALID | ACTCTX_FLAG_RESOURCE_NAME_VALID; + actctx.lpResourceName = MAKEINTRESOURCEW(124); + actctx.hModule = GetModuleHandleW(NULL); + + return CreateActCtxW(&actctx); +} + +static void test_fiber_actctx(void) +{ + ULONG_PTR cookies[3]; + HANDLE actctxs[3]; + size_t i, j; + BOOL ret; + + for (i = 0; i < ARRAY_SIZE(actctxs); i++) + { + actctxs[i] = create_actctx_from_module_manifest(); + ok(actctxs[i] != INVALID_HANDLE_VALUE, "failed to create context, error %lu\n", GetLastError()); + for (j = 0; j < i; j++) + { + ok(actctxs[i] != actctxs[j], + "actctxs[%Iu] (%p) and actctxs[%Iu] (%p) should not alias\n", + i, actctxs[i], j, actctxs[j]); + } + } + + ret = ActivateActCtx(actctxs[0], &cookies[0]); + ok(ret, "ActivateActCtx returned error %lu\n", GetLastError()); + check_current_actctx_is(actctxs[0], FALSE); + + test_ConvertThreadToFiber(); + check_current_actctx_is(actctxs[0], FALSE); + + ret = ActivateActCtx(actctxs[1], &cookies[1]); + ok(ret, "ActivateActCtx returned error %lu\n", GetLastError()); + check_current_actctx_is(actctxs[1], FALSE); + + subtest_fiber_actctx_switch(actctxs[1], actctxs[2]); + subtest_fiber_actctx_preservation(actctxs[1], actctxs[2]); + + ret = DeactivateActCtx(0, cookies[1]); + ok(ret, "DeactivateActCtx returned error %lu\n", GetLastError()); + check_current_actctx_is(actctxs[0], FALSE); + + test_ConvertFiberToThread(); + check_current_actctx_is(actctxs[0], FALSE); + + ret = DeactivateActCtx(0, cookies[0]); + ok(ret, "DeactivateActCtx returned error %lu\n", GetLastError()); + check_current_actctx_is(NULL, FALSE); + + for (i = ARRAY_SIZE(actctxs); i > 0; ) + ReleaseActCtx(actctxs[--i]); +} + + static void WINAPI fls_exit_deadlock_callback(void *arg) { if (arg == (void *)1) @@ -873,5 +1094,6 @@ START_TEST(fiber) test_FiberLocalStorage(); test_FiberLocalStorageCallback(FiberLocalStorageProc); test_FiberLocalStorageWithFibers(FiberLocalStorageProc); + test_fiber_actctx(); test_fls_exit_deadlock(); }
From: Jinoh Kang jinoh.kang.kr@gmail.com
This refactoring makes it easier to change the algorithm of obtaining the current activation context stack.
Note that RtlAddRefActivationContext(NULL) is a no-op, and check_actctx(NULL) returns NULL without doing anything. --- dlls/ntdll/actctx.c | 36 ++++++++++++++++-------------------- 1 file changed, 16 insertions(+), 20 deletions(-)
diff --git a/dlls/ntdll/actctx.c b/dlls/ntdll/actctx.c index 721a2f339a5..34eb55cdea2 100644 --- a/dlls/ntdll/actctx.c +++ b/dlls/ntdll/actctx.c @@ -3383,6 +3383,14 @@ static NTSTATUS parse_depend_manifests(struct actctx_loader* acl) return status; }
+static HANDLE get_current_actctx_no_addref(void) +{ + if (NtCurrentTeb()->ActivationContextStack.ActiveFrame) + return NtCurrentTeb()->ActivationContextStack.ActiveFrame->ActivationContext; + + return NULL; +} + /* find the appropriate activation context for RtlQueryInformationActivationContext */ static NTSTATUS find_query_actctx( HANDLE *handle, DWORD flags, ULONG class ) { @@ -3392,8 +3400,7 @@ static NTSTATUS find_query_actctx( HANDLE *handle, DWORD flags, ULONG class ) { if (*handle) return STATUS_INVALID_PARAMETER;
- if (NtCurrentTeb()->ActivationContextStack.ActiveFrame) - *handle = NtCurrentTeb()->ActivationContextStack.ActiveFrame->ActivationContext; + *handle = get_current_actctx_no_addref(); } else if (flags & (QUERY_ACTCTX_FLAG_ACTCTX_IS_ADDRESS|QUERY_ACTCTX_FLAG_ACTCTX_IS_HMODULE)) { @@ -5461,14 +5468,7 @@ void WINAPI RtlFreeThreadActivationContextStack(void) */ NTSTATUS WINAPI RtlGetActiveActivationContext( HANDLE *handle ) { - if (NtCurrentTeb()->ActivationContextStack.ActiveFrame) - { - *handle = NtCurrentTeb()->ActivationContextStack.ActiveFrame->ActivationContext; - RtlAddRefActivationContext( *handle ); - } - else - *handle = 0; - + RtlAddRefActivationContext( *handle = get_current_actctx_no_addref() ); return STATUS_SUCCESS; }
@@ -5753,6 +5753,7 @@ NTSTATUS WINAPI RtlFindActivationContextSectionString( ULONG flags, const GUID * { PACTCTX_SECTION_KEYED_DATA data = ptr; NTSTATUS status = STATUS_SXS_KEY_NOT_FOUND; + ACTIVATION_CONTEXT *actctx;
TRACE("%08lx %s %lu %s %p\n", flags, debugstr_guid(guid), section_kind, debugstr_us(section_name), data); @@ -5774,11 +5775,8 @@ NTSTATUS WINAPI RtlFindActivationContextSectionString( ULONG flags, const GUID * return STATUS_INVALID_PARAMETER; }
- if (NtCurrentTeb()->ActivationContextStack.ActiveFrame) - { - ACTIVATION_CONTEXT *actctx = check_actctx(NtCurrentTeb()->ActivationContextStack.ActiveFrame->ActivationContext); - if (actctx) status = find_string( actctx, section_kind, section_name, flags, data ); - } + actctx = check_actctx( get_current_actctx_no_addref() ); + if (actctx) status = find_string( actctx, section_kind, section_name, flags, data );
if (status != STATUS_SUCCESS) status = find_string( process_actctx, section_kind, section_name, flags, data ); @@ -5797,6 +5795,7 @@ NTSTATUS WINAPI RtlFindActivationContextSectionGuid( ULONG flags, const GUID *ex { ACTCTX_SECTION_KEYED_DATA *data = ptr; NTSTATUS status = STATUS_SXS_KEY_NOT_FOUND; + ACTIVATION_CONTEXT *actctx;
TRACE("%08lx %s %lu %s %p\n", flags, debugstr_guid(extguid), section_kind, debugstr_guid(guid), data);
@@ -5815,11 +5814,8 @@ NTSTATUS WINAPI RtlFindActivationContextSectionGuid( ULONG flags, const GUID *ex if (!data || data->cbSize < FIELD_OFFSET(ACTCTX_SECTION_KEYED_DATA, ulAssemblyRosterIndex) || !guid) return STATUS_INVALID_PARAMETER;
- if (NtCurrentTeb()->ActivationContextStack.ActiveFrame) - { - ACTIVATION_CONTEXT *actctx = check_actctx(NtCurrentTeb()->ActivationContextStack.ActiveFrame->ActivationContext); - if (actctx) status = find_guid( actctx, section_kind, guid, flags, data ); - } + actctx = check_actctx( get_current_actctx_no_addref() ); + if (actctx) status = find_guid( actctx, section_kind, guid, flags, data );
if (status != STATUS_SUCCESS) status = find_guid( process_actctx, section_kind, guid, flags, data );
From: Jinoh Kang jinoh.kang.kr@gmail.com
This allows changing the location of activation context stack if it should be put somewhere else (e.g. inside the fiber structure). --- dlls/ntdll/actctx.c | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/dlls/ntdll/actctx.c b/dlls/ntdll/actctx.c index d92d51c0e8d..b66f2d2b895 100644 --- a/dlls/ntdll/actctx.c +++ b/dlls/ntdll/actctx.c @@ -3385,7 +3385,7 @@ static NTSTATUS parse_depend_manifests(struct actctx_loader* acl)
static HANDLE get_current_actctx_no_addref(void) { - ACTIVATION_CONTEXT_STACK *actctx_stack = &NtCurrentTeb()->ActivationContextStack; + ACTIVATION_CONTEXT_STACK *actctx_stack = NtCurrentTeb()->ActivationContextStackPointer;
if (actctx_stack->ActiveFrame) return actctx_stack->ActiveFrame->ActivationContext; @@ -5397,7 +5397,7 @@ NTSTATUS WINAPI RtlActivateActivationContext( ULONG unknown, HANDLE handle, PULO NTSTATUS WINAPI RtlActivateActivationContextEx( ULONG flags, TEB *teb, HANDLE handle, ULONG_PTR *cookie ) { RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame; - ACTIVATION_CONTEXT_STACK *actctx_stack = &teb->ActivationContextStack; + ACTIVATION_CONTEXT_STACK *actctx_stack = teb->ActivationContextStackPointer;
if (!(frame = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*frame) ))) return STATUS_NO_MEMORY; @@ -5419,7 +5419,7 @@ NTSTATUS WINAPI RtlActivateActivationContextEx( ULONG flags, TEB *teb, HANDLE ha */ void WINAPI RtlDeactivateActivationContext( ULONG flags, ULONG_PTR cookie ) { - ACTIVATION_CONTEXT_STACK *actctx_stack = &NtCurrentTeb()->ActivationContextStack; + ACTIVATION_CONTEXT_STACK *actctx_stack = NtCurrentTeb()->ActivationContextStackPointer; RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame, *top;
TRACE( "%lx cookie=%Ix\n", flags, cookie ); @@ -5453,7 +5453,7 @@ void WINAPI RtlDeactivateActivationContext( ULONG flags, ULONG_PTR cookie ) */ void WINAPI RtlFreeThreadActivationContextStack(void) { - ACTIVATION_CONTEXT_STACK *actctx_stack = &NtCurrentTeb()->ActivationContextStack; + ACTIVATION_CONTEXT_STACK *actctx_stack = NtCurrentTeb()->ActivationContextStackPointer; RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame;
frame = actctx_stack->ActiveFrame; @@ -5483,7 +5483,7 @@ NTSTATUS WINAPI RtlGetActiveActivationContext( HANDLE *handle ) */ BOOLEAN WINAPI RtlIsActivationContextActive( HANDLE handle ) { - ACTIVATION_CONTEXT_STACK *actctx_stack = &NtCurrentTeb()->ActivationContextStack; + ACTIVATION_CONTEXT_STACK *actctx_stack = NtCurrentTeb()->ActivationContextStackPointer; RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame;
for (frame = actctx_stack->ActiveFrame; frame; frame = frame->Previous)
From: Jinoh Kang jinoh.kang.kr@gmail.com
This refactoring makes it easier to change the algorithm of obtaining the current activation context stack. --- dlls/ntdll/actctx.c | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-)
diff --git a/dlls/ntdll/actctx.c b/dlls/ntdll/actctx.c index 34eb55cdea2..d92d51c0e8d 100644 --- a/dlls/ntdll/actctx.c +++ b/dlls/ntdll/actctx.c @@ -3385,8 +3385,10 @@ static NTSTATUS parse_depend_manifests(struct actctx_loader* acl)
static HANDLE get_current_actctx_no_addref(void) { - if (NtCurrentTeb()->ActivationContextStack.ActiveFrame) - return NtCurrentTeb()->ActivationContextStack.ActiveFrame->ActivationContext; + ACTIVATION_CONTEXT_STACK *actctx_stack = &NtCurrentTeb()->ActivationContextStack; + + if (actctx_stack->ActiveFrame) + return actctx_stack->ActiveFrame->ActivationContext;
return NULL; } @@ -5395,14 +5397,15 @@ NTSTATUS WINAPI RtlActivateActivationContext( ULONG unknown, HANDLE handle, PULO NTSTATUS WINAPI RtlActivateActivationContextEx( ULONG flags, TEB *teb, HANDLE handle, ULONG_PTR *cookie ) { RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame; + ACTIVATION_CONTEXT_STACK *actctx_stack = &teb->ActivationContextStack;
if (!(frame = RtlAllocateHeap( GetProcessHeap(), 0, sizeof(*frame) ))) return STATUS_NO_MEMORY;
- frame->Previous = teb->ActivationContextStack.ActiveFrame; + frame->Previous = actctx_stack->ActiveFrame; frame->ActivationContext = handle; frame->Flags = 0; - teb->ActivationContextStack.ActiveFrame = frame; + actctx_stack->ActiveFrame = frame; RtlAddRefActivationContext( handle );
*cookie = (ULONG_PTR)frame; @@ -5416,12 +5419,13 @@ NTSTATUS WINAPI RtlActivateActivationContextEx( ULONG flags, TEB *teb, HANDLE ha */ void WINAPI RtlDeactivateActivationContext( ULONG flags, ULONG_PTR cookie ) { + ACTIVATION_CONTEXT_STACK *actctx_stack = &NtCurrentTeb()->ActivationContextStack; RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame, *top;
TRACE( "%lx cookie=%Ix\n", flags, cookie );
/* find the right frame */ - top = NtCurrentTeb()->ActivationContextStack.ActiveFrame; + top = actctx_stack->ActiveFrame; for (frame = top; frame; frame = frame->Previous) if ((ULONG_PTR)frame == cookie) break;
@@ -5432,9 +5436,9 @@ void WINAPI RtlDeactivateActivationContext( ULONG flags, ULONG_PTR cookie ) RtlRaiseStatus( STATUS_SXS_EARLY_DEACTIVATION );
/* pop everything up to and including frame */ - NtCurrentTeb()->ActivationContextStack.ActiveFrame = frame->Previous; + actctx_stack->ActiveFrame = frame->Previous;
- while (top != NtCurrentTeb()->ActivationContextStack.ActiveFrame) + while (top != actctx_stack->ActiveFrame) { frame = top->Previous; RtlReleaseActivationContext( top->ActivationContext ); @@ -5449,9 +5453,10 @@ void WINAPI RtlDeactivateActivationContext( ULONG flags, ULONG_PTR cookie ) */ void WINAPI RtlFreeThreadActivationContextStack(void) { + ACTIVATION_CONTEXT_STACK *actctx_stack = &NtCurrentTeb()->ActivationContextStack; RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame;
- frame = NtCurrentTeb()->ActivationContextStack.ActiveFrame; + frame = actctx_stack->ActiveFrame; while (frame) { RTL_ACTIVATION_CONTEXT_STACK_FRAME *prev = frame->Previous; @@ -5459,7 +5464,7 @@ void WINAPI RtlFreeThreadActivationContextStack(void) RtlFreeHeap( GetProcessHeap(), 0, frame ); frame = prev; } - NtCurrentTeb()->ActivationContextStack.ActiveFrame = NULL; + actctx_stack->ActiveFrame = NULL; }
@@ -5478,9 +5483,10 @@ NTSTATUS WINAPI RtlGetActiveActivationContext( HANDLE *handle ) */ BOOLEAN WINAPI RtlIsActivationContextActive( HANDLE handle ) { + ACTIVATION_CONTEXT_STACK *actctx_stack = &NtCurrentTeb()->ActivationContextStack; RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame;
- for (frame = NtCurrentTeb()->ActivationContextStack.ActiveFrame; frame; frame = frame->Previous) + for (frame = actctx_stack->ActiveFrame; frame; frame = frame->Previous) if (frame->ActivationContext == handle) return TRUE; return FALSE; }
From: Jinoh Kang jinoh.kang.kr@gmail.com
--- dlls/ntdll/actctx.c | 10 +++++++++- dlls/ntdll/ntdll.spec | 1 + include/winternl.h | 1 + 3 files changed, 11 insertions(+), 1 deletion(-)
diff --git a/dlls/ntdll/actctx.c b/dlls/ntdll/actctx.c index b66f2d2b895..39058611232 100644 --- a/dlls/ntdll/actctx.c +++ b/dlls/ntdll/actctx.c @@ -5453,7 +5453,15 @@ void WINAPI RtlDeactivateActivationContext( ULONG flags, ULONG_PTR cookie ) */ void WINAPI RtlFreeThreadActivationContextStack(void) { - ACTIVATION_CONTEXT_STACK *actctx_stack = NtCurrentTeb()->ActivationContextStackPointer; + RtlFreeActivationContextStack( NtCurrentTeb()->ActivationContextStackPointer ); +} + + +/****************************************************************** + * RtlFreeActivationContextStack (NTDLL.@) + */ +void WINAPI RtlFreeActivationContextStack( ACTIVATION_CONTEXT_STACK *actctx_stack ) +{ RTL_ACTIVATION_CONTEXT_STACK_FRAME *frame;
frame = actctx_stack->ActiveFrame; diff --git a/dlls/ntdll/ntdll.spec b/dlls/ntdll/ntdll.spec index d5f6737e1aa..b7659ac8c49 100644 --- a/dlls/ntdll/ntdll.spec +++ b/dlls/ntdll/ntdll.spec @@ -700,6 +700,7 @@ @ stdcall RtlFormatCurrentUserKeyPath(ptr) @ stdcall RtlFormatMessage(ptr long long long long ptr ptr long ptr) @ stdcall RtlFormatMessageEx(ptr long long long long ptr ptr long ptr long) +@ stdcall RtlFreeActivationContextStack(ptr) @ stdcall RtlFreeAnsiString(ptr) @ stdcall RtlFreeHandle(ptr ptr) @ stdcall RtlFreeHeap(long long ptr) diff --git a/include/winternl.h b/include/winternl.h index 339d3d86f78..20516b32cfd 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -4420,6 +4420,7 @@ NTSYSAPI NTSTATUS WINAPI RtlFlsSetValue(ULONG,void *); NTSYSAPI NTSTATUS WINAPI RtlFormatCurrentUserKeyPath(PUNICODE_STRING); NTSYSAPI NTSTATUS WINAPI RtlFormatMessage(LPCWSTR,ULONG,BOOLEAN,BOOLEAN,BOOLEAN,__ms_va_list *,LPWSTR,ULONG,ULONG*); NTSYSAPI NTSTATUS WINAPI RtlFormatMessageEx(LPCWSTR,ULONG,BOOLEAN,BOOLEAN,BOOLEAN,__ms_va_list *,LPWSTR,ULONG,ULONG*,ULONG); +NTSYSAPI void WINAPI RtlFreeActivationContextStack(ACTIVATION_CONTEXT_STACK *); NTSYSAPI void WINAPI RtlFreeAnsiString(PANSI_STRING); NTSYSAPI BOOLEAN WINAPI RtlFreeHandle(RTL_HANDLE_TABLE *,RTL_HANDLE *); NTSYSAPI BOOLEAN WINAPI RtlFreeHeap(HANDLE,ULONG,PVOID);
From: Jinoh Kang jinoh.kang.kr@gmail.com
--- dlls/kernel32/tests/fiber.c | 10 ++++---- dlls/kernelbase/thread.c | 49 +++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 5 deletions(-)
diff --git a/dlls/kernel32/tests/fiber.c b/dlls/kernel32/tests/fiber.c index 5540305cd1a..a5b55c70af3 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); @@ -911,7 +911,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..c57f9f5e456 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,41 @@ 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; + + if (dest != src) + { + 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 +1011,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 +1027,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 +1070,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; } @@ -1045,6 +1091,7 @@ void WINAPI DECLSPEC_HOTPATCH DeleteFiber( LPVOID fiber_ptr ) } RtlFreeUserStack( fiber->stack_allocation ); RtlProcessFlsData( fiber->fls_slots, 3 ); + RtlFreeActivationContextStack( &fiber->actctx.stack_space ); HeapFree( GetProcessHeap(), 0, fiber ); }
@@ -1069,6 +1116,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 +1126,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 ); }
Hi,
It looks like your patch introduced the new failures shown below. Please investigate and fix them before resubmitting your patch. If they are not new, fixing them anyway would help a lot. Otherwise please ask for the known failures list to be updated.
The tests also ran into some preexisting test failures. If you know how to fix them that would be helpful. See the TestBot job for the details:
The full results can be found at: https://testbot.winehq.org/JobDetails.pl?Key=130803
Your paranoid android.
=== debian11 (32 bit report) ===
Report validation errors: kernel32:fiber has no test summary line (early exit of the main process?)
=== debian11 (32 bit ar:MA report) ===
Report validation errors: kernel32:fiber has no test summary line (early exit of the main process?)
=== debian11 (32 bit de report) ===
Report validation errors: kernel32:fiber has no test summary line (early exit of the main process?)
=== debian11 (32 bit fr report) ===
Report validation errors: kernel32:fiber has no test summary line (early exit of the main process?)
=== debian11 (32 bit he:IL report) ===
Report validation errors: kernel32:fiber has no test summary line (early exit of the main process?)
=== debian11 (32 bit hi:IN report) ===
Report validation errors: kernel32:fiber has no test summary line (early exit of the main process?)
=== debian11 (32 bit ja:JP report) ===
Report validation errors: kernel32:fiber has no test summary line (early exit of the main process?)
=== debian11 (32 bit zh:CN report) ===
Report validation errors: kernel32:fiber has no test summary line (early exit of the main process?)
=== debian11b (32 bit WoW report) ===
Report validation errors: kernel32:fiber has no test summary line (early exit of the main process?)
=== debian11b (64 bit WoW report) ===
Report validation errors: kernel32:fiber has no test summary line (early exit of the main process?)