From e7fa615f4cb41fae006c197bf7694e4b69d939ad Mon Sep 17 00:00:00 2001 From: William Horvath Date: Wed, 8 Jan 2025 13:35:07 -0800 Subject: [PATCH] 10.0-rc4-5 patchset - rebase - add fix/workaround for osu! floating point bug (finally) - shared memory optimizations - faster memcpy/memmove/memset patches - update wrapper "wine-osu(-wow64)" to be usable with winetricks - e.g. WINE=wine-osu winetricks -q deletemyhomefolder - compilation fixes and improvements - prebuilt binary/generic release requires AVX now - random tree-wide fixes - make it go faster --- ...w-FindExecutables-to-find-unix-files.patch | 42 - ...elper-to-compute-the-terminated-flag.patch | 119 --- ...d-helper-to-compute-the-alerted-flag.patch | 49 -- ...r-to-compute-the-unknown-status-flag.patch | 76 -- ...ver-Introduce-a-new-async-state-enum.patch | 298 ------- ...unconditionally-in-async-set-result-.patch | 32 - ...irect-result-field-from-struct-async.patch | 112 --- ...ove-signaled-field-from-struct-async.patch | 97 -- ...e-terminated-field-from-struct-async.patch | 91 -- ...move-alerted-field-from-struct-async.patch | 75 -- ...known-status-field-from-struct-async.patch | 93 -- ...async-unknown-status-helper-function.patch | 72 -- ...minate-async-alerted-helper-function.patch | 60 -- ...dHandler-handlers-on-an-IAsyncAction.patch | 196 +++++ ...-Implement-GetResults-for-IAsyncInfo.patch | 299 +++++++ ...rrorCode-Cancel-Close-for-IAsyncInfo.patch | 190 ++++ ...d-and-get-Completed-for-IAsyncAction.patch | 183 ++++ ...ation-using-Windows-System-Threading.patch | 762 ++++++++++++++++ ...in-the-64-bit-segv-handler-on-WoW64.patch} | 46 +- ...Improve-GetWindowStateUpdates-traces.patch | 34 - ...dates-again-after-applying-new-state.patch | 37 - ...-returned-from-CanConvert-consistent.patch | 288 ++++++ ...er-get-metadata-blocks-using-realloc.patch | 67 ++ ...g-for-OCSP-basic-response-extensions.patch | 64 ++ ...-for-OCSP-single-response-extensions.patch | 25 + ...OCSP-request-with-POST-if-GET-failed.patch | 143 +++ ...IFY-CACHE-ONLY-BASED-REVOCATION-flag.patch | 34 + ...p-flags-when-syncing-window-position.patch | 67 ++ ...cpy-instead-of-preventing-optimisati.patch | 157 ++++ ...dd-AVX-memcpy-memmove-implementation.patch | 831 ++++++++++++++++++ ...ore-optimized-string-functions-from-.patch | 732 +++++++++++++++ ...ilation-with-llvm-mingw-UCRT-if-fgnu.patch | 44 + ...t-frame-pointers-on-x86_64-leaf-fram.patch | 42 + ...000-configure.ac-Omit-frame-pointers.patch | 46 - ...isable-debug-features-if-NDEBUG-is-d.patch | 80 +- ...-more-__GNUC__-to-__GNUC__-__clang__.patch | 135 +++ ...figure-ntdll-Use-gettid-if-available.patch | 38 + ...se-__builtin_expect-for-debug-macros.patch | 2 +- ...ject-operation-to-grab-the-esync-fil.patch | 135 +-- ...ject-operation-to-grab-the-fsync-shm.patch | 20 + ...fsync-Always-inline-spinwait-helpers.patch | 47 + ...an-in-process-synchronization-object.patch | 18 +- ...-synchronization-objects-for-threads.patch | 12 +- ...thread-suspension-in-NtSuspendThread.patch | 118 --- ...ject-when-waiting-in-NtSuspendThread.patch | 26 - ...-ntdll-Increase-cache-entries-to-256.patch | 40 + .../0012-makedep-nasm-silent-rule.patch | 12 + ...drawable-outside-of-the-win_data-mut.patch | 46 - ...4-revert-broken-staging-focus-active.patch | 254 ++++++ .../0018-winex11-child-window-styles.patch | 2 +- ...e-a-race-condition-in-wglSwapBuffers.patch | 33 + ...on-t-reallocate-a-buffer-for-every-r.patch | 68 -- ...on-t-reallocate-reply-when-size-chan.patch | 92 -- ...rver-Always-send-replies-with-writev.patch | 63 -- ...se-a-pool-for-small-most-thread_wait.patch | 90 -- ...Optimize-namespace-element-iteration.patch | 4 +- ...rver-Allow-cancelling-alerted-asyncs.patch | 61 ++ ...-Make-server_select-a-memory-barrier.patch | 26 - ...-Make-server_select-a-memory-barrier.patch | 22 + ...PWB-in-contended-NtWaitForAlertByThr.patch | 31 + ...o-send-asyncs-to-threads-in-APC-wait.patch | 90 ++ ...pport-hardcode-with-old-kernel-check.patch | 4 +- ..._gettime-for-set_current_time-if-ava.patch | 2 +- ...icated-thread-for-user_shared_data-t.patch | 193 ++++ ...ll-Remove-CLOCK_REALTIME_COARSE-path.patch | 40 + .../0010-use_clock_monotonic.patch | 151 +--- ...try-barely-yielding-see-what-happens.patch | 126 +++ ...lback-to-RTKIT-for-thread-priorities.patch | 4 +- ...-setting-the-cursor-position-if-the-.patch | 40 + ...rv-Use-input-shared-memory-for-NtUse.patch | 92 ++ ...desktop-shared-memory-for-some-curso.patch | 78 ++ ...rn-async-keyboard-state-in-NtUserGet.patch | 39 + ...tart-iteration-with-1-to-avoid-buffe.patch | 89 -- ...62-dwrite-Avoid-heap-buffer-overflow.patch | 109 --- ...turn-immediately-with-negative-count.patch | 46 - ...4-uiautomationcore-Avoid-double-free.patch | 98 --- ...-Avoid-merging-of-memcpy-and-memmove.patch | 92 -- ...ditionally-save-restore-x87-FPU-cont.patch | 56 ++ ...a-magic-trick-to-allow-osu-to-work-w.patch | 26 - ...ffers-directly-to-opengl32.wglSwapBu.patch | 58 ++ ...lbase-Add-AppPolicyGetClrCompat-stub.patch | 77 ++ 9000-misc-additions/roapi-stubs.patch | 240 +++++ ...sable-CHACHA20-POLY1305-ciphersuites.patch | 12 + ...ex11-Custom-frame-limiter-for-OpenGL.patch | 14 +- ...tFPWB-in-contended-NtWaitForAlertByT.patch | 33 - staging-commit | 2 +- wine-commit | 2 +- 87 files changed, 6169 insertions(+), 2622 deletions(-) delete mode 100644 0003-pending-mrs-and-backports/6285-shell32-Allow-FindExecutables-to-find-unix-files/0001-shell32-Allow-FindExecutables-to-find-unix-files.patch delete mode 100644 0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0001-server-Introduce-async-terminated-helper-to-compute-the-terminated-flag.patch delete mode 100644 0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0002-server-Introduce-async-alerted-helper-to-compute-the-alerted-flag.patch delete mode 100644 0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0003-server-Introduce-async-unknown-status-helper-to-compute-the-unknown-status-flag.patch delete mode 100644 0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0004-server-Introduce-a-new-async-state-enum.patch delete mode 100644 0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0005-server-Signal-async-unconditionally-in-async-set-result-.patch delete mode 100644 0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0006-server-Remove-direct-result-field-from-struct-async.patch delete mode 100644 0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0007-server-Remove-signaled-field-from-struct-async.patch delete mode 100644 0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0008-server-Remove-terminated-field-from-struct-async.patch delete mode 100644 0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0009-server-Remove-alerted-field-from-struct-async.patch delete mode 100644 0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0010-server-Remove-unknown-status-field-from-struct-async.patch delete mode 100644 0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0011-server-Eliminate-async-unknown-status-helper-function.patch delete mode 100644 0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0012-server-Eliminate-async-alerted-helper-function.patch create mode 100644 0003-pending-mrs-and-backports/6889-Draft-threadpoolwinrt-Implement-IAsyncAction-and-IAsyncInfo/0001-threadpoolwinrt-tests-Add-conformance-tests-for-setting-IAsyncActionCompletedHandler-handlers-on-an-IAsyncAction.patch create mode 100644 0003-pending-mrs-and-backports/6889-Draft-threadpoolwinrt-Implement-IAsyncAction-and-IAsyncInfo/0002-threadpoolwinrt-Implement-GetResults-for-IAsyncInfo.patch create mode 100644 0003-pending-mrs-and-backports/6889-Draft-threadpoolwinrt-Implement-IAsyncAction-and-IAsyncInfo/0003-threadpoolwinrt-Implement-get-Id-get-Status-get-ErrorCode-Cancel-Close-for-IAsyncInfo.patch create mode 100644 0003-pending-mrs-and-backports/6889-Draft-threadpoolwinrt-Implement-IAsyncAction-and-IAsyncInfo/0004-threadpoolwinrt-Implement-put-Completed-and-get-Completed-for-IAsyncAction.patch create mode 100644 0003-pending-mrs-and-backports/6889-Draft-threadpoolwinrt-Implement-IAsyncAction-and-IAsyncInfo/0005-cryptowinrt-Rewrite-IAsyncOperation-using-Windows-System-Threading.patch rename 0003-pending-mrs-and-backports/{7064-Draft-ntdll-Check-for-invalid-GS-base-in-the-64-bit-segv-handler/0001-ntdll-Check-for-invalid-gs-value-in-32-bit-code-on-WoW64.patch => 7064-ntdll-Check-for-invalid-GS-base-in-the-64-bit-segv-handler/0001-ntdll-Check-for-invalid-GS-base-in-the-64-bit-segv-handler-on-WoW64.patch} (73%) delete mode 100644 0003-pending-mrs-and-backports/7072-win32u-Check-window-state-updates-again-after-applying-new-state/0001-winex11-Improve-GetWindowStateUpdates-traces.patch delete mode 100644 0003-pending-mrs-and-backports/7072-win32u-Check-window-state-updates-again-after-applying-new-state/0002-win32u-Check-window-state-updates-again-after-applying-new-state.patch create mode 100644 0003-pending-mrs-and-backports/7091-windowscodecs-Make-values-returned-from-CanConvert-consistent/0001-windowscodecs-Make-values-returned-from-CanConvert-consistent.patch create mode 100644 0003-pending-mrs-and-backports/7099-windowscodecs-Simplify-png-decoder-get-metadata-blocks-using-realloc/0001-windowscodecs-Simplify-png-decoder-get-metadata-blocks-using-realloc.patch create mode 100644 0003-pending-mrs-and-backports/7112-crypt32-cryptnet-OCSP-revocation-check-improvements/0001-crypt32-Use-correct-tag-for-OCSP-basic-response-extensions.patch create mode 100644 0003-pending-mrs-and-backports/7112-crypt32-cryptnet-OCSP-revocation-check-improvements/0002-crypt32-Use-correct-tag-for-OCSP-single-response-extensions.patch create mode 100644 0003-pending-mrs-and-backports/7112-crypt32-cryptnet-OCSP-revocation-check-improvements/0003-cryptnet-Retry-OCSP-request-with-POST-if-GET-failed.patch create mode 100644 0003-pending-mrs-and-backports/7112-crypt32-cryptnet-OCSP-revocation-check-improvements/0004-cryptnet-Do-not-perform-OCSP-requests-with-CERT-VERIFY-CACHE-ONLY-BASED-REVOCATION-flag.patch create mode 100644 0003-pending-mrs-and-backports/7116-winex11-Respect-swp-flags-when-syncing-window-position/0001-winex11-Respect-swp-flags-when-syncing-window-position.patch create mode 100644 0004-build-fix-undebug-optimize/0001-ntdll-Unroll-memcpy-instead-of-preventing-optimisati.patch create mode 100644 0004-build-fix-undebug-optimize/0004-WIP-msvcrt-Add-AVX-memcpy-memmove-implementation.patch create mode 100644 0004-build-fix-undebug-optimize/0005-ntdll-Sync-the-more-optimized-string-functions-from-.patch create mode 100644 0004-build-fix-undebug-optimize/0006-headers-Fix-compilation-with-llvm-mingw-UCRT-if-fgnu.patch create mode 100644 0004-build-fix-undebug-optimize/2000-configure.ac-Omit-frame-pointers-on-x86_64-leaf-fram.patch delete mode 100644 0004-build-fix-undebug-optimize/2000-configure.ac-Omit-frame-pointers.patch create mode 100644 0004-build-fix-undebug-optimize/8500-headers-change-more-__GNUC__-to-__GNUC__-__clang__.patch create mode 100644 0004-build-fix-undebug-optimize/8600-configure-ntdll-Use-gettid-if-available.patch create mode 100644 0006-proton-esync-fsync/0263-fsync-Always-inline-spinwait-helpers.patch delete mode 100644 0007-ntsync/0032-ntdll-Wait-for-thread-suspension-in-NtSuspendThread.patch delete mode 100644 0007-ntsync/0033-ntdll-Use-server_wait_for_object-when-waiting-in-NtSuspendThread.patch create mode 100644 0007-ntsync/0035-ntdll-Increase-cache-entries-to-256.patch create mode 100644 0008-jpeg-SIMD/0012-makedep-nasm-silent-rule.patch delete mode 100644 0009-windowing-system-integration/0001-misc/0000-Revert-winex11-Sync-gl-drawable-outside-of-the-win_data-mut.patch create mode 100644 0009-windowing-system-integration/0001-misc/0004-revert-broken-staging-focus-active.patch create mode 100644 0009-windowing-system-integration/0001-misc/0060-winex11-Introduce-a-race-condition-in-wglSwapBuffers.patch delete mode 100644 0013-server-optimization/0001-misc/ps0033-p0001-server-Don-t-reallocate-a-buffer-for-every-r.patch delete mode 100644 0013-server-optimization/0001-misc/ps0033-p0002-server-Don-t-reallocate-reply-when-size-chan.patch delete mode 100644 0013-server-optimization/0001-misc/ps0033-p0003-server-Always-send-replies-with-writev.patch delete mode 100644 0013-server-optimization/0001-misc/ps0033-p0004-server-Use-a-pool-for-small-most-thread_wait.patch create mode 100644 0013-server-optimization/0001-misc/ps0471-server-Allow-cancelling-alerted-asyncs.patch delete mode 100644 0013-server-optimization/0001-misc/ps0741-ntdll-Make-server_select-a-memory-barrier.patch create mode 100644 0013-server-optimization/0001-misc/ps0741EXT-ntdll-Make-server_select-a-memory-barrier.patch create mode 100644 0013-server-optimization/0001-misc/ps0741EXT-ntdll-try-FPWB-in-contended-NtWaitForAlertByThr.patch create mode 100644 0013-server-optimization/0001-misc/ps5091-server-Try-to-send-asyncs-to-threads-in-APC-wait.patch create mode 100644 0013-server-optimization/0004-time-wait/0007-server-Use-a-dedicated-thread-for-user_shared_data-t.patch create mode 100644 0013-server-optimization/0004-time-wait/0008-ntdll-Remove-CLOCK_REALTIME_COARSE-path.patch create mode 100644 0013-server-optimization/0004-time-wait/0015-various-try-barely-yielding-see-what-happens.patch create mode 100644 0013-server-optimization/0008-shm-opts/ps2002-HACK-win32u-Skip-setting-the-cursor-position-if-the-.patch create mode 100644 0013-server-optimization/0008-shm-opts/ps2005-win32u-winex11.drv-Use-input-shared-memory-for-NtUse.patch create mode 100644 0013-server-optimization/0008-shm-opts/ps2006-HACK-win32u-Use-desktop-shared-memory-for-some-curso.patch create mode 100644 0013-server-optimization/0008-shm-opts/ps3002-HACK-win32u-Return-async-keyboard-state-in-NtUserGet.patch delete mode 100644 0015-bernhard-asan/0057-d3dx9_36-tests-Start-iteration-with-1-to-avoid-buffe.patch delete mode 100644 0015-bernhard-asan/0062-dwrite-Avoid-heap-buffer-overflow.patch delete mode 100644 0015-bernhard-asan/0065-gdi32-Return-immediately-with-negative-count.patch delete mode 100644 0015-bernhard-asan/0074-uiautomationcore-Avoid-double-free.patch delete mode 100644 0015-bernhard-asan/0085-ntdll-Avoid-merging-of-memcpy-and-memmove.patch create mode 100644 9000-misc-additions/HACK-ntdll-Unconditionally-save-restore-x87-FPU-cont.patch delete mode 100644 9000-misc-additions/combase-Perform-a-magic-trick-to-allow-osu-to-work-w.patch create mode 100644 9000-misc-additions/gdi32-Map-SwapBuffers-directly-to-opengl32.wglSwapBu.patch create mode 100644 9000-misc-additions/kernelbase-Add-AppPolicyGetClrCompat-stub.patch create mode 100644 9000-misc-additions/roapi-stubs.patch delete mode 100644 9500-testing/0001-ntdll-TEST-try-NtFPWB-in-contended-NtWaitForAlertByT.patch diff --git a/0003-pending-mrs-and-backports/6285-shell32-Allow-FindExecutables-to-find-unix-files/0001-shell32-Allow-FindExecutables-to-find-unix-files.patch b/0003-pending-mrs-and-backports/6285-shell32-Allow-FindExecutables-to-find-unix-files/0001-shell32-Allow-FindExecutables-to-find-unix-files.patch deleted file mode 100644 index d87eb24..0000000 --- a/0003-pending-mrs-and-backports/6285-shell32-Allow-FindExecutables-to-find-unix-files/0001-shell32-Allow-FindExecutables-to-find-unix-files.patch +++ /dev/null @@ -1,42 +0,0 @@ -From 2b4faa78340a546e709e881a2b291997a2b0df83 Mon Sep 17 00:00:00 2001 -From: Alistair Leslie-Hughes -Date: Thu, 15 Aug 2024 10:33:02 +1000 -Subject: [PATCH] shell32: Allow FindExecutables to find unix files. - ---- - dlls/shell32/shlexec.c | 12 +++++++++++- - 1 file changed, 11 insertions(+), 1 deletion(-) - -diff --git a/dlls/shell32/shlexec.c b/dlls/shell32/shlexec.c -index 828c7168a34..607aca3a450 100644 ---- a/dlls/shell32/shlexec.c -+++ b/dlls/shell32/shlexec.c -@@ -677,7 +677,15 @@ static UINT SHELL_FindExecutable(LPCWSTR lpPath, LPCWSTR lpFile, LPCWSTR lpVerb, - /* The file was found in lpPath or one of the directories in the system-wide search path */ - } - else -- xlpFile[0] = '\0'; -+ { -+ /* Checking for an unix application */ -+ if( (xlpFile[0] == '/') || PathFindOnPathW(xlpFile, search_paths)) -+ { -+ lstrcpyW(lpResult, xlpFile); -+ } -+ else -+ xlpFile[0] = '\0'; -+ } - } - - attribs = GetFileAttributesW(lpFile); -@@ -1939,6 +1947,8 @@ static BOOL SHELL_execute( LPSHELLEXECUTEINFOW sei, SHELL_ExecuteW32 execfunc ) - - end: - TRACE("retval %Iu\n", retval); -+ if (retval == SE_ERR_NOASSOC) -+ SetLastError(ERROR_FILE_NOT_FOUND); - - free(wszApplicationName); - if (wszParameters != parametersBuffer) --- -GitLab - diff --git a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0001-server-Introduce-async-terminated-helper-to-compute-the-terminated-flag.patch b/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0001-server-Introduce-async-terminated-helper-to-compute-the-terminated-flag.patch deleted file mode 100644 index 9a40143..0000000 --- a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0001-server-Introduce-async-terminated-helper-to-compute-the-terminated-flag.patch +++ /dev/null @@ -1,119 +0,0 @@ -From 2247381180a72ffa6b8033d5add4fa401bf90601 Mon Sep 17 00:00:00 2001 -From: Jinoh Kang -Date: Sat, 24 Aug 2024 10:50:46 +0900 -Subject: [PATCH] server: Introduce async_terminated() helper to compute the - 'terminated' flag. - -This helper will later be rewritten to compute the flag from a state -enum. ---- - server/async.c | 25 +++++++++++++++---------- - 1 file changed, 15 insertions(+), 10 deletions(-) - -diff --git a/server/async.c b/server/async.c -index 749c547af4f..9c7218a2e54 100644 ---- a/server/async.c -+++ b/server/async.c -@@ -161,12 +161,17 @@ static void async_destroy( struct object *obj ) - release_object( async->thread ); - } - -+static int async_terminated( const struct async *async ) -+{ -+ return async->terminated; -+} -+ - /* notifies client thread of new status of its async request */ - void async_terminate( struct async *async, unsigned int status ) - { - struct iosb *iosb = async->iosb; - -- if (async->terminated) return; -+ if (async_terminated( async )) return; - - async->terminated = 1; - if (async->iosb && async->iosb->status == STATUS_PENDING) async->iosb->status = status; -@@ -491,7 +496,7 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota - - if (obj->ops != &async_ops) return; /* in case the client messed up the APC results */ - -- assert( async->terminated ); /* it must have been woken up if we get a result */ -+ assert( async_terminated( async ) ); /* it must have been woken up if we get a result */ - - if (async->unknown_status) async_set_initial_status( async, status ); - -@@ -571,7 +576,7 @@ int async_waiting( struct async_queue *queue ) - - if (!(ptr = list_head( &queue->queue ))) return 0; - async = LIST_ENTRY( ptr, struct async, queue_entry ); -- return !async->terminated; -+ return !async_terminated( async ); - } - - static int cancel_async( struct process *process, struct object *obj, struct thread *thread, client_ptr_t iosb ) -@@ -586,7 +591,7 @@ static int cancel_async( struct process *process, struct object *obj, struct thr - restart: - LIST_FOR_EACH_ENTRY( async, &process->asyncs, struct async, process_entry ) - { -- if (async->terminated || async->canceled || async->is_system) continue; -+ if (async_terminated( async ) || async->canceled || async->is_system) continue; - if ((!obj || (get_fd_user( async->fd ) == obj)) && - (!thread || async->thread == thread) && - (!iosb || async->data.iosb == iosb)) -@@ -608,7 +613,7 @@ static int cancel_blocking( struct process *process, struct thread *thread, clie - restart: - LIST_FOR_EACH_ENTRY( async, &process->asyncs, struct async, process_entry ) - { -- if (async->terminated || async->canceled) continue; -+ if (async_terminated( async ) || async->canceled) continue; - if (async->blocking && async->thread == thread && - (!iosb || async->data.iosb == iosb)) - { -@@ -628,7 +633,7 @@ void cancel_process_asyncs( struct process *process ) - restart: - LIST_FOR_EACH_ENTRY( async, &process->asyncs, struct async, process_entry ) - { -- if (async->terminated || async->canceled) continue; -+ if (async_terminated( async ) || async->canceled) continue; - async->canceled = 1; - fd_cancel_async( async->fd, async ); - goto restart; -@@ -647,7 +652,7 @@ int async_close_obj_handle( struct object *obj, struct process *process, obj_han - restart: - LIST_FOR_EACH_ENTRY( async, &process->asyncs, struct async, process_entry ) - { -- if (async->terminated || async->canceled || get_fd_user( async->fd ) != obj) continue; -+ if (async_terminated( async ) || async->canceled || get_fd_user( async->fd ) != obj) continue; - if (!async->completion || !async->data.apc_context || async->event) continue; - - async->canceled = 1; -@@ -664,7 +669,7 @@ void cancel_terminating_thread_asyncs( struct thread *thread ) - restart: - LIST_FOR_EACH_ENTRY( async, &thread->process->asyncs, struct async, process_entry ) - { -- if (async->thread != thread || async->terminated || async->canceled) continue; -+ if (async->thread != thread || async_terminated( async ) || async->canceled) continue; - if (async->completion && async->data.apc_context && !async->event) continue; - if (async->is_system) continue; - -@@ -793,7 +798,7 @@ struct async *find_pending_async( struct async_queue *queue ) - { - struct async *async; - LIST_FOR_EACH_ENTRY( async, &queue->queue, struct async, queue_entry ) -- if (!async->terminated) return (struct async *)grab_object( async ); -+ if (!async_terminated( async )) return (struct async *)grab_object( async ); - return NULL; - } - -@@ -863,7 +868,7 @@ DECL_HANDLER(set_async_direct_result) - - if (!async) return; - -- if (!async->unknown_status || !async->terminated || !async->alerted) -+ if (!async->unknown_status || !async_terminated( async ) || !async->alerted) - { - set_error( STATUS_INVALID_PARAMETER ); - release_object( &async->obj ); --- -GitLab - diff --git a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0002-server-Introduce-async-alerted-helper-to-compute-the-alerted-flag.patch b/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0002-server-Introduce-async-alerted-helper-to-compute-the-alerted-flag.patch deleted file mode 100644 index 821348f..0000000 --- a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0002-server-Introduce-async-alerted-helper-to-compute-the-alerted-flag.patch +++ /dev/null @@ -1,49 +0,0 @@ -From a47510678ea8e7de317bed16a305d1b576734629 Mon Sep 17 00:00:00 2001 -From: Jinoh Kang -Date: Sat, 24 Aug 2024 10:52:53 +0900 -Subject: [PATCH] server: Introduce async_alerted() helper to compute the - 'alerted' flag. - -This helper will later be rewritten to compute the flag from a state -enum. ---- - server/async.c | 9 +++++++-- - 1 file changed, 7 insertions(+), 2 deletions(-) - -diff --git a/server/async.c b/server/async.c -index 9c7218a2e54..4754d9f2a86 100644 ---- a/server/async.c -+++ b/server/async.c -@@ -166,6 +166,11 @@ static int async_terminated( const struct async *async ) - return async->terminated; - } - -+static int async_alerted( const struct async *async ) -+{ -+ return async->alerted; -+} -+ - /* notifies client thread of new status of its async request */ - void async_terminate( struct async *async, unsigned int status ) - { -@@ -500,7 +505,7 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota - - if (async->unknown_status) async_set_initial_status( async, status ); - -- if (async->alerted && status == STATUS_PENDING) /* restart it */ -+ if (async_alerted( async ) && status == STATUS_PENDING) /* restart it */ - { - async->terminated = 0; - async->alerted = 0; -@@ -868,7 +873,7 @@ DECL_HANDLER(set_async_direct_result) - - if (!async) return; - -- if (!async->unknown_status || !async_terminated( async ) || !async->alerted) -+ if (!async->unknown_status || !async_terminated( async ) || !async_alerted( async )) - { - set_error( STATUS_INVALID_PARAMETER ); - release_object( &async->obj ); --- -GitLab - diff --git a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0003-server-Introduce-async-unknown-status-helper-to-compute-the-unknown-status-flag.patch b/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0003-server-Introduce-async-unknown-status-helper-to-compute-the-unknown-status-flag.patch deleted file mode 100644 index d48b360..0000000 --- a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0003-server-Introduce-async-unknown-status-helper-to-compute-the-unknown-status-flag.patch +++ /dev/null @@ -1,76 +0,0 @@ -From 953e68eeaf08887d141a5d0751f19aca7e309efd Mon Sep 17 00:00:00 2001 -From: Jinoh Kang -Date: Sat, 24 Aug 2024 10:58:42 +0900 -Subject: [PATCH] server: Introduce async_unknown_status() helper to compute - the 'unknown_status' flag. - -This helper will later be rewritten to compute the flag from a state -enum. ---- - server/async.c | 15 ++++++++++----- - 1 file changed, 10 insertions(+), 5 deletions(-) - -diff --git a/server/async.c b/server/async.c -index 4754d9f2a86..a664b6bc93c 100644 ---- a/server/async.c -+++ b/server/async.c -@@ -171,6 +171,11 @@ static int async_alerted( const struct async *async ) - return async->alerted; - } - -+static int async_unknown_status( const struct async *async ) -+{ -+ return async->unknown_status; -+} -+ - /* notifies client thread of new status of its async request */ - void async_terminate( struct async *async, unsigned int status ) - { -@@ -326,7 +331,7 @@ void set_async_pending( struct async *async ) - - void async_wake_obj( struct async *async ) - { -- assert( !async->unknown_status ); -+ assert( !async_unknown_status( async ) ); - if (!async->blocking) - { - async->signaled = 1; -@@ -346,7 +351,7 @@ obj_handle_t async_handoff( struct async *async, data_size_t *result, int force_ - { - async->blocking = force_blocking || async->blocking; - -- if (async->unknown_status) -+ if (async_unknown_status( async )) - { - /* even the initial status is not known yet */ - set_error( STATUS_PENDING ); -@@ -503,7 +508,7 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota - - assert( async_terminated( async ) ); /* it must have been woken up if we get a result */ - -- if (async->unknown_status) async_set_initial_status( async, status ); -+ if (async_unknown_status( async )) async_set_initial_status( async, status ); - - if (async_alerted( async ) && status == STATUS_PENDING) /* restart it */ - { -@@ -568,7 +573,7 @@ int async_queue_has_waiting_asyncs( struct async_queue *queue ) - struct async *async; - - LIST_FOR_EACH_ENTRY( async, &queue->queue, struct async, queue_entry ) -- if (!async->unknown_status) return 1; -+ if (!async_unknown_status( async )) return 1; - - return 0; - } -@@ -873,7 +878,7 @@ DECL_HANDLER(set_async_direct_result) - - if (!async) return; - -- if (!async->unknown_status || !async_terminated( async ) || !async_alerted( async )) -+ if (!async_unknown_status( async ) || !async_terminated( async ) || !async_alerted( async )) - { - set_error( STATUS_INVALID_PARAMETER ); - release_object( &async->obj ); --- -GitLab - diff --git a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0004-server-Introduce-a-new-async-state-enum.patch b/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0004-server-Introduce-a-new-async-state-enum.patch deleted file mode 100644 index cec8103..0000000 --- a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0004-server-Introduce-a-new-async-state-enum.patch +++ /dev/null @@ -1,298 +0,0 @@ -From 2a61bb98dc219a6a4e5c04b3a95a98b694d07036 Mon Sep 17 00:00:00 2001 -From: Jinoh Kang -Date: Mon, 26 Aug 2024 23:05:15 +0900 -Subject: [PATCH] server: Introduce a new async state enum. - ---- - server/async.c | 159 +++++++++++++++++++++++++++++++++++++++++++++++++ - 1 file changed, 159 insertions(+) - -diff --git a/server/async.c b/server/async.c -index a664b6bc93c..68c248728d0 100644 ---- a/server/async.c -+++ b/server/async.c -@@ -34,6 +34,48 @@ - #include "process.h" - #include "handle.h" - -+enum async_state -+{ -+ /* The I/O operation has just initiated, or initial status is known. */ -+ ASYNC_INITIAL, -+ -+ /* The I/O operation has just initiated via create_request_async(). */ -+ ASYNC_INITIAL_DIRECT_RESULT, -+ -+ /* The initial status is not known yet. It will be determined by the client or winedevice.exe. */ -+ ASYNC_UNKNOWN_STATUS, -+ -+ /* The I/O operation is being processed by the wineserver or winedevice.eze. */ -+ ASYNC_IN_PROGRESS, -+ -+ /* The I/O operation is being processed by the client. */ -+ ASYNC_ALERTED, -+ -+ /* The I/O operation has finished synchronously (APC result) but not been -+ * acknowledged by the client. -+ * -+ * The completion is being delivered to the client indirectly via -+ * APC_ASYNC_IO. The client had no chance to fill the IOSB synchronously, -+ * due to unknwon initial status (e.g., processed by winedevice.exe). -+ */ -+ ASYNC_FINALIZING_SYNC_APC_RESULT, -+ -+ /* The I/O operation has finished synchronously (direct result) but not -+ * been acknowledged by the client. -+ * -+ * The completion is being delivered to the client directly via server -+ * request return. The client may proceed to fill the IOSB synchronously, -+ * and notify the server that it has done so. -+ */ -+ ASYNC_FINALIZING_SYNC_DIRECT_RESULT, -+ -+ /* The I/O operation has finished asynchronously but not been acknowledged by the client. */ -+ ASYNC_FINALIZING_ASYNC, -+ -+ /* The I/O operation has finished and the result has been acknowledged by the client. */ -+ ASYNC_COMPLETED -+}; -+ - struct async - { - struct object obj; /* object header */ -@@ -49,6 +91,7 @@ struct async - struct iosb *iosb; /* I/O status block */ - obj_handle_t wait_handle; /* pre-allocated wait handle */ - unsigned int initial_status; /* status returned from initial request */ -+ enum async_state state; - unsigned int signaled :1; - unsigned int pending :1; /* request successfully queued, but pending */ - unsigned int direct_result :1;/* a flag if we're passing result directly from request instead of APC */ -@@ -110,6 +153,32 @@ static int async_signaled( struct object *obj, struct wait_queue_entry *entry ) - { - struct async *async = (struct async *)obj; - assert( obj->ops == &async_ops ); -+ switch (async->state) -+ { -+ case ASYNC_INITIAL: -+ case ASYNC_INITIAL_DIRECT_RESULT: -+ case ASYNC_UNKNOWN_STATUS: -+ case ASYNC_FINALIZING_SYNC_APC_RESULT: -+ assert( async->signaled == 0 ); -+ break; -+ case ASYNC_FINALIZING_SYNC_DIRECT_RESULT: -+ /* The client will "wait" on the async to signal completion. */ -+ assert( async->signaled == 1 ); -+ break; -+ case ASYNC_IN_PROGRESS: -+ case ASYNC_ALERTED: -+ case ASYNC_FINALIZING_ASYNC: -+ /* If nonblocking, the client will "wait" on the async to close it. */ -+ assert( async->signaled == (!async->blocking) ); -+ break; -+ case ASYNC_COMPLETED: -+ /* If there is an open async handle, notify the waiter of completion. */ -+ assert( async->signaled == 1 ); -+ break; -+ default: -+ assert( 0 ); -+ break; -+ } - return async->signaled; - } - -@@ -121,6 +190,7 @@ static void async_satisfied( struct object *obj, struct wait_queue_entry *entry - /* we only return an async handle for asyncs created via create_request_async() */ - assert( async->iosb ); - -+ assert( async->direct_result == (async->state == ASYNC_FINALIZING_SYNC_DIRECT_RESULT) ); - if (async->direct_result) - { - async_set_result( &async->obj, async->iosb->status, async->iosb->result ); -@@ -163,16 +233,58 @@ static void async_destroy( struct object *obj ) - - static int async_terminated( const struct async *async ) - { -+ switch (async->state) -+ { -+ case ASYNC_INITIAL: -+ case ASYNC_INITIAL_DIRECT_RESULT: -+ case ASYNC_IN_PROGRESS: -+ assert( async->terminated == 0 ); -+ break; -+ case ASYNC_UNKNOWN_STATUS: -+ case ASYNC_ALERTED: -+ case ASYNC_FINALIZING_SYNC_APC_RESULT: -+ case ASYNC_FINALIZING_SYNC_DIRECT_RESULT: -+ case ASYNC_FINALIZING_ASYNC: -+ case ASYNC_COMPLETED: -+ assert( async->terminated == 1 ); -+ break; -+ default: -+ assert( 0 ); -+ break; -+ } - return async->terminated; - } - - static int async_alerted( const struct async *async ) - { -+ switch (async->state) -+ { -+ case ASYNC_INITIAL_DIRECT_RESULT: -+ case ASYNC_IN_PROGRESS: -+ case ASYNC_FINALIZING_SYNC_APC_RESULT: -+ case ASYNC_FINALIZING_SYNC_DIRECT_RESULT: -+ case ASYNC_FINALIZING_ASYNC: -+ case ASYNC_COMPLETED: -+ assert( async->alerted == 0 ); -+ break; -+ case ASYNC_INITIAL: -+ /* initial status set from set_async_direct_result */ -+ assert( async->alerted == 1 ); -+ break; -+ case ASYNC_UNKNOWN_STATUS: -+ case ASYNC_ALERTED: -+ assert( async->alerted == 1 ); -+ break; -+ default: -+ assert( 0 ); -+ break; -+ } - return async->alerted; - } - - static int async_unknown_status( const struct async *async ) - { -+ assert( async->unknown_status == (async->state == ASYNC_UNKNOWN_STATUS) ); - return async->unknown_status; - } - -@@ -182,17 +294,50 @@ void async_terminate( struct async *async, unsigned int status ) - struct iosb *iosb = async->iosb; - - if (async_terminated( async )) return; -+ assert( async->state == ASYNC_INITIAL || async->state == ASYNC_INITIAL_DIRECT_RESULT || async->state == ASYNC_IN_PROGRESS ); -+ -+ if (status == STATUS_ALERTED) -+ { -+ assert( async->direct_result == (async->state == ASYNC_INITIAL_DIRECT_RESULT) ); -+ if (async->direct_result) -+ { -+ assert( async->unknown_status ); -+ async->state = ASYNC_UNKNOWN_STATUS; -+ } -+ else -+ { -+ assert( !async->unknown_status ); -+ async->state = ASYNC_ALERTED; -+ } -+ } -+ else -+ { -+ if (async->state == ASYNC_INITIAL) -+ async->state = ASYNC_FINALIZING_SYNC_APC_RESULT; -+ else if (async->state == ASYNC_INITIAL_DIRECT_RESULT) -+ async->state = ASYNC_FINALIZING_SYNC_DIRECT_RESULT; -+ else -+ async->state = ASYNC_FINALIZING_ASYNC; -+ } - - async->terminated = 1; - if (async->iosb && async->iosb->status == STATUS_PENDING) async->iosb->status = status; - if (status == STATUS_ALERTED) - async->alerted = 1; - -+ if (async->state == ASYNC_FINALIZING_SYNC_DIRECT_RESULT || -+ (async->state == ASYNC_ALERTED || async->state == ASYNC_FINALIZING_ASYNC) && !async->blocking) -+ { -+ async->signaled = 1; -+ wake_up( &async->obj, 0 ); -+ } -+ - /* if no APC could be queued (e.g. the process is terminated), - * thread_queue_apc() may trigger async_set_result(), which may drop the - * last reference to the async, so grab a temporary reference here */ - grab_object( async ); - -+ assert( (!async->direct_result) == (async->state != ASYNC_FINALIZING_SYNC_DIRECT_RESULT && async->state != ASYNC_UNKNOWN_STATUS) ); - if (!async->direct_result) - { - apc_call_t data; -@@ -284,6 +429,7 @@ struct async *create_async( struct fd *fd, struct thread *thread, const async_da - async->queue = NULL; - async->fd = (struct fd *)grab_object( fd ); - async->initial_status = STATUS_PENDING; -+ async->state = ASYNC_INITIAL; - async->signaled = 0; - async->pending = 1; - async->wait_handle = 0; -@@ -321,10 +467,13 @@ void async_set_initial_status( struct async *async, unsigned int status ) - { - async->initial_status = status; - async->unknown_status = 0; -+ if (async->state == ASYNC_UNKNOWN_STATUS) -+ async->state = ASYNC_INITIAL; - } - - void set_async_pending( struct async *async ) - { -+ assert( (!async->terminated) == (async->state == ASYNC_INITIAL_DIRECT_RESULT || async->state == ASYNC_UNKNOWN_STATUS) ); - if (!async->terminated) - async->pending = 1; - } -@@ -332,6 +481,8 @@ void set_async_pending( struct async *async ) - void async_wake_obj( struct async *async ) - { - assert( !async_unknown_status( async ) ); -+ assert( async->state == ASYNC_INITIAL ); -+ async->state = ASYNC_IN_PROGRESS; - if (!async->blocking) - { - async->signaled = 1; -@@ -417,6 +568,8 @@ obj_handle_t async_handoff( struct async *async, data_size_t *result, int force_ - } - else - { -+ assert( async->state == ASYNC_INITIAL_DIRECT_RESULT ); -+ async->state = ASYNC_IN_PROGRESS; - async->direct_result = 0; - async->pending = 1; - if (!async->blocking) -@@ -472,6 +625,8 @@ void async_request_complete_alloc( struct async *async, unsigned int status, dat - /* mark an async as having unknown initial status */ - void async_set_unknown_status( struct async *async ) - { -+ assert( async->state == ASYNC_INITIAL_DIRECT_RESULT ); -+ async->state = ASYNC_UNKNOWN_STATUS; - async->unknown_status = 1; - async->direct_result = 0; - } -@@ -512,6 +667,8 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota - - if (async_alerted( async ) && status == STATUS_PENDING) /* restart it */ - { -+ assert( async->state == ASYNC_INITIAL || async->state == ASYNC_ALERTED ); -+ async->state = ASYNC_IN_PROGRESS; - async->terminated = 0; - async->alerted = 0; - async_reselect( async ); -@@ -549,6 +706,7 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota - else if (async->fd && !async->is_system) set_fd_signaled( async->fd, 1 ); - } - -+ async->state = ASYNC_COMPLETED; - if (!async->signaled) - { - async->signaled = 1; -@@ -786,6 +944,7 @@ struct async *create_request_async( struct fd *fd, unsigned int comp_flags, cons - return NULL; - } - async->pending = 0; -+ async->state = ASYNC_INITIAL_DIRECT_RESULT; - async->direct_result = 1; - async->is_system = !!is_system; - async->comp_flags = comp_flags; --- -GitLab - diff --git a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0005-server-Signal-async-unconditionally-in-async-set-result-.patch b/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0005-server-Signal-async-unconditionally-in-async-set-result-.patch deleted file mode 100644 index 389e3a3..0000000 --- a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0005-server-Signal-async-unconditionally-in-async-set-result-.patch +++ /dev/null @@ -1,32 +0,0 @@ -From 83b6353324e1eeda1422c5654ac60135c471d72e Mon Sep 17 00:00:00 2001 -From: Jinoh Kang -Date: Sat, 24 Aug 2024 11:56:08 +0900 -Subject: [PATCH] server: Signal async unconditionally in async_set_result(). - -This helps simplify further refactoring that gets rid of 'signaled' flag -entirely. ---- - server/async.c | 7 ++----- - 1 file changed, 2 insertions(+), 5 deletions(-) - -diff --git a/server/async.c b/server/async.c -index 68c248728d0..336bf10ac1a 100644 ---- a/server/async.c -+++ b/server/async.c -@@ -707,11 +707,8 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota - } - - async->state = ASYNC_COMPLETED; -- if (!async->signaled) -- { -- async->signaled = 1; -- wake_up( &async->obj, 0 ); -- } -+ async->signaled = 1; -+ wake_up( &async->obj, 0 ); - - async_call_completion_callback( async ); - --- -GitLab - diff --git a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0006-server-Remove-direct-result-field-from-struct-async.patch b/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0006-server-Remove-direct-result-field-from-struct-async.patch deleted file mode 100644 index f334385..0000000 --- a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0006-server-Remove-direct-result-field-from-struct-async.patch +++ /dev/null @@ -1,112 +0,0 @@ -From 772c8ca0a658e12e582c0e821bd465953832dda2 Mon Sep 17 00:00:00 2001 -From: Jinoh Kang -Date: Sat, 21 Sep 2024 23:01:03 +0900 -Subject: [PATCH] server: Remove "direct_result" field from struct async. - ---- - server/async.c | 24 +++++++----------------- - 1 file changed, 7 insertions(+), 17 deletions(-) - -diff --git a/server/async.c b/server/async.c -index 336bf10ac1a..3a37c105a2b 100644 ---- a/server/async.c -+++ b/server/async.c -@@ -94,7 +94,6 @@ struct async - enum async_state state; - unsigned int signaled :1; - unsigned int pending :1; /* request successfully queued, but pending */ -- unsigned int direct_result :1;/* a flag if we're passing result directly from request instead of APC */ - unsigned int alerted :1; /* fd is signaled, but we are waiting for client-side I/O */ - unsigned int terminated :1; /* async has been terminated */ - unsigned int canceled :1; /* have we already queued cancellation for this async? */ -@@ -190,11 +189,9 @@ static void async_satisfied( struct object *obj, struct wait_queue_entry *entry - /* we only return an async handle for asyncs created via create_request_async() */ - assert( async->iosb ); - -- assert( async->direct_result == (async->state == ASYNC_FINALIZING_SYNC_DIRECT_RESULT) ); -- if (async->direct_result) -+ if (async->state == ASYNC_FINALIZING_SYNC_DIRECT_RESULT) - { - async_set_result( &async->obj, async->iosb->status, async->iosb->result ); -- async->direct_result = 0; - } - - if (async->initial_status == STATUS_PENDING && async->blocking) -@@ -298,8 +295,7 @@ void async_terminate( struct async *async, unsigned int status ) - - if (status == STATUS_ALERTED) - { -- assert( async->direct_result == (async->state == ASYNC_INITIAL_DIRECT_RESULT) ); -- if (async->direct_result) -+ if (async->state == ASYNC_INITIAL_DIRECT_RESULT) - { - assert( async->unknown_status ); - async->state = ASYNC_UNKNOWN_STATUS; -@@ -337,8 +333,7 @@ void async_terminate( struct async *async, unsigned int status ) - * last reference to the async, so grab a temporary reference here */ - grab_object( async ); - -- assert( (!async->direct_result) == (async->state != ASYNC_FINALIZING_SYNC_DIRECT_RESULT && async->state != ASYNC_UNKNOWN_STATUS) ); -- if (!async->direct_result) -+ if (async->state != ASYNC_FINALIZING_SYNC_DIRECT_RESULT && async->state != ASYNC_UNKNOWN_STATUS) - { - apc_call_t data; - -@@ -433,7 +428,6 @@ struct async *create_async( struct fd *fd, struct thread *thread, const async_da - async->signaled = 0; - async->pending = 1; - async->wait_handle = 0; -- async->direct_result = 0; - async->alerted = 0; - async->terminated = 0; - async->canceled = 0; -@@ -524,10 +518,10 @@ obj_handle_t async_handoff( struct async *async, data_size_t *result, int force_ - * the one responsible for performing the I/O is not the device driver, - * but instead the client that requested the I/O in the first place. - * -- * also, async_set_unknown_status() would set direct_result to zero -- * forcing APC_ASYNC_IO to fire in async_terminate(), which is not -- * useful due to subtle semantic differences between synchronous and -- * asynchronous completion. -+ * also, async_set_unknown_status() would eventually force APC_ASYNC_IO -+ * to fire in async_terminate(), which is not useful due to subtle -+ * semantic differences between synchronous and asynchronous -+ * completion. - */ - async->unknown_status = 1; - async_terminate( async, STATUS_ALERTED ); -@@ -570,7 +564,6 @@ obj_handle_t async_handoff( struct async *async, data_size_t *result, int force_ - { - assert( async->state == ASYNC_INITIAL_DIRECT_RESULT ); - async->state = ASYNC_IN_PROGRESS; -- async->direct_result = 0; - async->pending = 1; - if (!async->blocking) - { -@@ -628,7 +621,6 @@ void async_set_unknown_status( struct async *async ) - assert( async->state == ASYNC_INITIAL_DIRECT_RESULT ); - async->state = ASYNC_UNKNOWN_STATUS; - async->unknown_status = 1; -- async->direct_result = 0; - } - - /* set the timeout of an async operation */ -@@ -942,7 +934,6 @@ struct async *create_request_async( struct fd *fd, unsigned int comp_flags, cons - } - async->pending = 0; - async->state = ASYNC_INITIAL_DIRECT_RESULT; -- async->direct_result = 1; - async->is_system = !!is_system; - async->comp_flags = comp_flags; - } -@@ -1043,7 +1034,6 @@ DECL_HANDLER(set_async_direct_result) - - if (status == STATUS_PENDING) - { -- async->direct_result = 0; - async->pending = 1; - } - else if (req->mark_pending) --- -GitLab - diff --git a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0007-server-Remove-signaled-field-from-struct-async.patch b/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0007-server-Remove-signaled-field-from-struct-async.patch deleted file mode 100644 index c97e36b..0000000 --- a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0007-server-Remove-signaled-field-from-struct-async.patch +++ /dev/null @@ -1,97 +0,0 @@ -From b0845af16e2a08d0e8ad21cda8cca217b3656b02 Mon Sep 17 00:00:00 2001 -From: Jinoh Kang -Date: Tue, 27 Aug 2024 21:54:15 +0900 -Subject: [PATCH] server: Remove "signaled" field from struct async. - ---- - server/async.c | 21 +++++---------------- - 1 file changed, 5 insertions(+), 16 deletions(-) - -diff --git a/server/async.c b/server/async.c -index 3a37c105a2b..7f0970a7db9 100644 ---- a/server/async.c -+++ b/server/async.c -@@ -92,7 +92,6 @@ struct async - obj_handle_t wait_handle; /* pre-allocated wait handle */ - unsigned int initial_status; /* status returned from initial request */ - enum async_state state; -- unsigned int signaled :1; - unsigned int pending :1; /* request successfully queued, but pending */ - unsigned int alerted :1; /* fd is signaled, but we are waiting for client-side I/O */ - unsigned int terminated :1; /* async has been terminated */ -@@ -158,27 +157,22 @@ static int async_signaled( struct object *obj, struct wait_queue_entry *entry ) - case ASYNC_INITIAL_DIRECT_RESULT: - case ASYNC_UNKNOWN_STATUS: - case ASYNC_FINALIZING_SYNC_APC_RESULT: -- assert( async->signaled == 0 ); -- break; -+ return 0; - case ASYNC_FINALIZING_SYNC_DIRECT_RESULT: - /* The client will "wait" on the async to signal completion. */ -- assert( async->signaled == 1 ); -- break; -+ return 1; - case ASYNC_IN_PROGRESS: - case ASYNC_ALERTED: - case ASYNC_FINALIZING_ASYNC: - /* If nonblocking, the client will "wait" on the async to close it. */ -- assert( async->signaled == (!async->blocking) ); -- break; -+ return !async->blocking; - case ASYNC_COMPLETED: - /* If there is an open async handle, notify the waiter of completion. */ -- assert( async->signaled == 1 ); -- break; -+ return 1; - default: - assert( 0 ); -- break; -+ return 0; - } -- return async->signaled; - } - - static void async_satisfied( struct object *obj, struct wait_queue_entry *entry ) -@@ -324,7 +318,6 @@ void async_terminate( struct async *async, unsigned int status ) - if (async->state == ASYNC_FINALIZING_SYNC_DIRECT_RESULT || - (async->state == ASYNC_ALERTED || async->state == ASYNC_FINALIZING_ASYNC) && !async->blocking) - { -- async->signaled = 1; - wake_up( &async->obj, 0 ); - } - -@@ -425,7 +418,6 @@ struct async *create_async( struct fd *fd, struct thread *thread, const async_da - async->fd = (struct fd *)grab_object( fd ); - async->initial_status = STATUS_PENDING; - async->state = ASYNC_INITIAL; -- async->signaled = 0; - async->pending = 1; - async->wait_handle = 0; - async->alerted = 0; -@@ -479,7 +471,6 @@ void async_wake_obj( struct async *async ) - async->state = ASYNC_IN_PROGRESS; - if (!async->blocking) - { -- async->signaled = 1; - wake_up( &async->obj, 0 ); - } - } -@@ -558,7 +549,6 @@ obj_handle_t async_handoff( struct async *async, data_size_t *result, int force_ - if (async->iosb->status != STATUS_PENDING) - { - if (result) *result = async->iosb->result; -- async->signaled = 1; - } - else - { -@@ -699,7 +689,6 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota - } - - async->state = ASYNC_COMPLETED; -- async->signaled = 1; - wake_up( &async->obj, 0 ); - - async_call_completion_callback( async ); --- -GitLab - diff --git a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0008-server-Remove-terminated-field-from-struct-async.patch b/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0008-server-Remove-terminated-field-from-struct-async.patch deleted file mode 100644 index ccd48a7..0000000 --- a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0008-server-Remove-terminated-field-from-struct-async.patch +++ /dev/null @@ -1,91 +0,0 @@ -From 996ef3f02db6b006712f4a3483a5d1ce40a4190f Mon Sep 17 00:00:00 2001 -From: Jinoh Kang -Date: Tue, 27 Aug 2024 21:56:36 +0900 -Subject: [PATCH] server: Remove "terminated" field from struct async. - ---- - server/async.c | 17 ++++------------- - 1 file changed, 4 insertions(+), 13 deletions(-) - -diff --git a/server/async.c b/server/async.c -index 7f0970a7db9..e515629dcda 100644 ---- a/server/async.c -+++ b/server/async.c -@@ -94,7 +94,6 @@ struct async - enum async_state state; - unsigned int pending :1; /* request successfully queued, but pending */ - unsigned int alerted :1; /* fd is signaled, but we are waiting for client-side I/O */ -- unsigned int terminated :1; /* async has been terminated */ - unsigned int canceled :1; /* have we already queued cancellation for this async? */ - unsigned int unknown_status :1; /* initial status is not known yet */ - unsigned int blocking :1; /* async is blocking */ -@@ -229,21 +228,18 @@ static int async_terminated( const struct async *async ) - case ASYNC_INITIAL: - case ASYNC_INITIAL_DIRECT_RESULT: - case ASYNC_IN_PROGRESS: -- assert( async->terminated == 0 ); -- break; -+ return 0; - case ASYNC_UNKNOWN_STATUS: - case ASYNC_ALERTED: - case ASYNC_FINALIZING_SYNC_APC_RESULT: - case ASYNC_FINALIZING_SYNC_DIRECT_RESULT: - case ASYNC_FINALIZING_ASYNC: - case ASYNC_COMPLETED: -- assert( async->terminated == 1 ); -- break; -+ return 1; - default: - assert( 0 ); -- break; -+ return 0; - } -- return async->terminated; - } - - static int async_alerted( const struct async *async ) -@@ -310,7 +306,6 @@ void async_terminate( struct async *async, unsigned int status ) - async->state = ASYNC_FINALIZING_ASYNC; - } - -- async->terminated = 1; - if (async->iosb && async->iosb->status == STATUS_PENDING) async->iosb->status = status; - if (status == STATUS_ALERTED) - async->alerted = 1; -@@ -421,7 +416,6 @@ struct async *create_async( struct fd *fd, struct thread *thread, const async_da - async->pending = 1; - async->wait_handle = 0; - async->alerted = 0; -- async->terminated = 0; - async->canceled = 0; - async->unknown_status = 0; - async->blocking = !is_fd_overlapped( fd ); -@@ -459,8 +453,7 @@ void async_set_initial_status( struct async *async, unsigned int status ) - - void set_async_pending( struct async *async ) - { -- assert( (!async->terminated) == (async->state == ASYNC_INITIAL_DIRECT_RESULT || async->state == ASYNC_UNKNOWN_STATUS) ); -- if (!async->terminated) -+ if (async->state == ASYNC_INITIAL_DIRECT_RESULT || async->state == ASYNC_UNKNOWN_STATUS) - async->pending = 1; - } - -@@ -651,7 +644,6 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota - { - assert( async->state == ASYNC_INITIAL || async->state == ASYNC_ALERTED ); - async->state = ASYNC_IN_PROGRESS; -- async->terminated = 0; - async->alerted = 0; - async_reselect( async ); - } -@@ -659,7 +651,6 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota - { - if (async->timeout) remove_timeout_user( async->timeout ); - async->timeout = NULL; -- async->terminated = 1; - if (async->iosb) async->iosb->status = status; - - /* don't signal completion if the async failed synchronously --- -GitLab - diff --git a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0009-server-Remove-alerted-field-from-struct-async.patch b/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0009-server-Remove-alerted-field-from-struct-async.patch deleted file mode 100644 index 44b90c5..0000000 --- a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0009-server-Remove-alerted-field-from-struct-async.patch +++ /dev/null @@ -1,75 +0,0 @@ -From c7f22bdaf626d962e24fd50f90cb8ad1cb134354 Mon Sep 17 00:00:00 2001 -From: Jinoh Kang -Date: Tue, 27 Aug 2024 21:58:35 +0900 -Subject: [PATCH] server: Remove "alerted" field from struct async. - ---- - server/async.c | 17 ++++------------- - 1 file changed, 4 insertions(+), 13 deletions(-) - -diff --git a/server/async.c b/server/async.c -index e515629dcda..23bc257a7a5 100644 ---- a/server/async.c -+++ b/server/async.c -@@ -93,7 +93,6 @@ struct async - unsigned int initial_status; /* status returned from initial request */ - enum async_state state; - unsigned int pending :1; /* request successfully queued, but pending */ -- unsigned int alerted :1; /* fd is signaled, but we are waiting for client-side I/O */ - unsigned int canceled :1; /* have we already queued cancellation for this async? */ - unsigned int unknown_status :1; /* initial status is not known yet */ - unsigned int blocking :1; /* async is blocking */ -@@ -252,21 +251,17 @@ static int async_alerted( const struct async *async ) - case ASYNC_FINALIZING_SYNC_DIRECT_RESULT: - case ASYNC_FINALIZING_ASYNC: - case ASYNC_COMPLETED: -- assert( async->alerted == 0 ); -- break; -+ return 0; - case ASYNC_INITIAL: - /* initial status set from set_async_direct_result */ -- assert( async->alerted == 1 ); -- break; -+ return 1; - case ASYNC_UNKNOWN_STATUS: - case ASYNC_ALERTED: -- assert( async->alerted == 1 ); -- break; -+ return 1; - default: - assert( 0 ); -- break; -+ return 0; - } -- return async->alerted; - } - - static int async_unknown_status( const struct async *async ) -@@ -307,8 +302,6 @@ void async_terminate( struct async *async, unsigned int status ) - } - - if (async->iosb && async->iosb->status == STATUS_PENDING) async->iosb->status = status; -- if (status == STATUS_ALERTED) -- async->alerted = 1; - - if (async->state == ASYNC_FINALIZING_SYNC_DIRECT_RESULT || - (async->state == ASYNC_ALERTED || async->state == ASYNC_FINALIZING_ASYNC) && !async->blocking) -@@ -415,7 +408,6 @@ struct async *create_async( struct fd *fd, struct thread *thread, const async_da - async->state = ASYNC_INITIAL; - async->pending = 1; - async->wait_handle = 0; -- async->alerted = 0; - async->canceled = 0; - async->unknown_status = 0; - async->blocking = !is_fd_overlapped( fd ); -@@ -644,7 +636,6 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota - { - assert( async->state == ASYNC_INITIAL || async->state == ASYNC_ALERTED ); - async->state = ASYNC_IN_PROGRESS; -- async->alerted = 0; - async_reselect( async ); - } - else --- -GitLab - diff --git a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0010-server-Remove-unknown-status-field-from-struct-async.patch b/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0010-server-Remove-unknown-status-field-from-struct-async.patch deleted file mode 100644 index 946b388..0000000 --- a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0010-server-Remove-unknown-status-field-from-struct-async.patch +++ /dev/null @@ -1,93 +0,0 @@ -From 373569c436d17bd4a64b1693adb6330d0efe9ec7 Mon Sep 17 00:00:00 2001 -From: Jinoh Kang -Date: Tue, 27 Aug 2024 22:00:08 +0900 -Subject: [PATCH] server: Remove "unknown_status" field from struct async. - ---- - server/async.c | 18 +++++------------- - 1 file changed, 5 insertions(+), 13 deletions(-) - -diff --git a/server/async.c b/server/async.c -index 23bc257a7a5..cbc4607327c 100644 ---- a/server/async.c -+++ b/server/async.c -@@ -94,7 +94,6 @@ struct async - enum async_state state; - unsigned int pending :1; /* request successfully queued, but pending */ - unsigned int canceled :1; /* have we already queued cancellation for this async? */ -- unsigned int unknown_status :1; /* initial status is not known yet */ - unsigned int blocking :1; /* async is blocking */ - unsigned int is_system :1; /* background system operation not affecting userspace visible state. */ - struct completion *completion; /* completion associated with fd */ -@@ -266,8 +265,7 @@ static int async_alerted( const struct async *async ) - - static int async_unknown_status( const struct async *async ) - { -- assert( async->unknown_status == (async->state == ASYNC_UNKNOWN_STATUS) ); -- return async->unknown_status; -+ return async->state == ASYNC_UNKNOWN_STATUS; - } - - /* notifies client thread of new status of its async request */ -@@ -282,12 +280,10 @@ void async_terminate( struct async *async, unsigned int status ) - { - if (async->state == ASYNC_INITIAL_DIRECT_RESULT) - { -- assert( async->unknown_status ); - async->state = ASYNC_UNKNOWN_STATUS; - } - else - { -- assert( !async->unknown_status ); - async->state = ASYNC_ALERTED; - } - } -@@ -409,7 +405,6 @@ struct async *create_async( struct fd *fd, struct thread *thread, const async_da - async->pending = 1; - async->wait_handle = 0; - async->canceled = 0; -- async->unknown_status = 0; - async->blocking = !is_fd_overlapped( fd ); - async->is_system = 0; - async->completion = fd_get_completion( fd, &async->comp_key ); -@@ -438,7 +433,6 @@ struct async *create_async( struct fd *fd, struct thread *thread, const async_da - void async_set_initial_status( struct async *async, unsigned int status ) - { - async->initial_status = status; -- async->unknown_status = 0; - if (async->state == ASYNC_UNKNOWN_STATUS) - async->state = ASYNC_INITIAL; - } -@@ -489,17 +483,16 @@ obj_handle_t async_handoff( struct async *async, data_size_t *result, int force_ - * instead. - * - * since we're deferring the initial I/O (to the client), we mark the -- * async as having unknown initial status (unknown_status = 1). note -- * that we don't reuse async_set_unknown_status() here. this is because -- * the one responsible for performing the I/O is not the device driver, -- * but instead the client that requested the I/O in the first place. -+ * async as having unknown initial status. note that we don't reuse -+ * async_set_unknown_status() here. this is because the one -+ * responsible for performing the I/O is not the device driver, but -+ * instead the client that requested the I/O in the first place. - * - * also, async_set_unknown_status() would eventually force APC_ASYNC_IO - * to fire in async_terminate(), which is not useful due to subtle - * semantic differences between synchronous and asynchronous - * completion. - */ -- async->unknown_status = 1; - async_terminate( async, STATUS_ALERTED ); - return async->wait_handle; - } -@@ -595,7 +588,6 @@ void async_set_unknown_status( struct async *async ) - { - assert( async->state == ASYNC_INITIAL_DIRECT_RESULT ); - async->state = ASYNC_UNKNOWN_STATUS; -- async->unknown_status = 1; - } - - /* set the timeout of an async operation */ --- -GitLab - diff --git a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0011-server-Eliminate-async-unknown-status-helper-function.patch b/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0011-server-Eliminate-async-unknown-status-helper-function.patch deleted file mode 100644 index c9575e0..0000000 --- a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0011-server-Eliminate-async-unknown-status-helper-function.patch +++ /dev/null @@ -1,72 +0,0 @@ -From ca62d6e0e5c6df2ba4f314f7e556fae9bbe66c1d Mon Sep 17 00:00:00 2001 -From: Jinoh Kang -Date: Tue, 27 Aug 2024 22:02:22 +0900 -Subject: [PATCH] server: Eliminate async_unknown_status() helper function. - ---- - server/async.c | 14 ++++---------- - 1 file changed, 4 insertions(+), 10 deletions(-) - -diff --git a/server/async.c b/server/async.c -index cbc4607327c..87fbb9d2ae2 100644 ---- a/server/async.c -+++ b/server/async.c -@@ -263,11 +263,6 @@ static int async_alerted( const struct async *async ) - } - } - --static int async_unknown_status( const struct async *async ) --{ -- return async->state == ASYNC_UNKNOWN_STATUS; --} -- - /* notifies client thread of new status of its async request */ - void async_terminate( struct async *async, unsigned int status ) - { -@@ -445,7 +440,6 @@ void set_async_pending( struct async *async ) - - void async_wake_obj( struct async *async ) - { -- assert( !async_unknown_status( async ) ); - assert( async->state == ASYNC_INITIAL ); - async->state = ASYNC_IN_PROGRESS; - if (!async->blocking) -@@ -466,7 +460,7 @@ obj_handle_t async_handoff( struct async *async, data_size_t *result, int force_ - { - async->blocking = force_blocking || async->blocking; - -- if (async_unknown_status( async )) -+ if (async->state == ASYNC_UNKNOWN_STATUS) - { - /* even the initial status is not known yet */ - set_error( STATUS_PENDING ); -@@ -622,7 +616,7 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota - - assert( async_terminated( async ) ); /* it must have been woken up if we get a result */ - -- if (async_unknown_status( async )) async_set_initial_status( async, status ); -+ if (async->state == ASYNC_UNKNOWN_STATUS) async_set_initial_status( async, status ); - - if (async_alerted( async ) && status == STATUS_PENDING) /* restart it */ - { -@@ -683,7 +677,7 @@ int async_queue_has_waiting_asyncs( struct async_queue *queue ) - struct async *async; - - LIST_FOR_EACH_ENTRY( async, &queue->queue, struct async, queue_entry ) -- if (!async_unknown_status( async )) return 1; -+ if (async->state != ASYNC_UNKNOWN_STATUS) return 1; - - return 0; - } -@@ -988,7 +982,7 @@ DECL_HANDLER(set_async_direct_result) - - if (!async) return; - -- if (!async_unknown_status( async ) || !async_terminated( async ) || !async_alerted( async )) -+ if (async->state != ASYNC_UNKNOWN_STATUS) - { - set_error( STATUS_INVALID_PARAMETER ); - release_object( &async->obj ); --- -GitLab - diff --git a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0012-server-Eliminate-async-alerted-helper-function.patch b/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0012-server-Eliminate-async-alerted-helper-function.patch deleted file mode 100644 index 4c421aa..0000000 --- a/0003-pending-mrs-and-backports/6369-Draft-Refactor-the-async-state-flags/0012-server-Eliminate-async-alerted-helper-function.patch +++ /dev/null @@ -1,60 +0,0 @@ -From 33e5f4acdfdfd2554c56774630c36cc8972b611a Mon Sep 17 00:00:00 2001 -From: Jinoh Kang -Date: Tue, 27 Aug 2024 22:05:43 +0900 -Subject: [PATCH] server: Eliminate async_alerted() helper function. - ---- - server/async.c | 28 +++------------------------- - 1 file changed, 3 insertions(+), 25 deletions(-) - -diff --git a/server/async.c b/server/async.c -index 87fbb9d2ae2..74dca104628 100644 ---- a/server/async.c -+++ b/server/async.c -@@ -240,29 +240,6 @@ static int async_terminated( const struct async *async ) - } - } - --static int async_alerted( const struct async *async ) --{ -- switch (async->state) -- { -- case ASYNC_INITIAL_DIRECT_RESULT: -- case ASYNC_IN_PROGRESS: -- case ASYNC_FINALIZING_SYNC_APC_RESULT: -- case ASYNC_FINALIZING_SYNC_DIRECT_RESULT: -- case ASYNC_FINALIZING_ASYNC: -- case ASYNC_COMPLETED: -- return 0; -- case ASYNC_INITIAL: -- /* initial status set from set_async_direct_result */ -- return 1; -- case ASYNC_UNKNOWN_STATUS: -- case ASYNC_ALERTED: -- return 1; -- default: -- assert( 0 ); -- return 0; -- } --} -- - /* notifies client thread of new status of its async request */ - void async_terminate( struct async *async, unsigned int status ) - { -@@ -617,10 +594,11 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota - assert( async_terminated( async ) ); /* it must have been woken up if we get a result */ - - if (async->state == ASYNC_UNKNOWN_STATUS) async_set_initial_status( async, status ); -+ assert( async->state != ASYNC_UNKNOWN_STATUS ); - -- if (async_alerted( async ) && status == STATUS_PENDING) /* restart it */ -+ if ((async->state == ASYNC_INITIAL || async->state == ASYNC_ALERTED) && -+ status == STATUS_PENDING) /* restart it */ - { -- assert( async->state == ASYNC_INITIAL || async->state == ASYNC_ALERTED ); - async->state = ASYNC_IN_PROGRESS; - async_reselect( async ); - } --- -GitLab - diff --git a/0003-pending-mrs-and-backports/6889-Draft-threadpoolwinrt-Implement-IAsyncAction-and-IAsyncInfo/0001-threadpoolwinrt-tests-Add-conformance-tests-for-setting-IAsyncActionCompletedHandler-handlers-on-an-IAsyncAction.patch b/0003-pending-mrs-and-backports/6889-Draft-threadpoolwinrt-Implement-IAsyncAction-and-IAsyncInfo/0001-threadpoolwinrt-tests-Add-conformance-tests-for-setting-IAsyncActionCompletedHandler-handlers-on-an-IAsyncAction.patch new file mode 100644 index 0000000..97de1af --- /dev/null +++ b/0003-pending-mrs-and-backports/6889-Draft-threadpoolwinrt-Implement-IAsyncAction-and-IAsyncInfo/0001-threadpoolwinrt-tests-Add-conformance-tests-for-setting-IAsyncActionCompletedHandler-handlers-on-an-IAsyncAction.patch @@ -0,0 +1,196 @@ +From e22b5a9c6837e5640fe358a4cbc3710fe80c94f9 Mon Sep 17 00:00:00 2001 +From: Vibhav Pant +Date: Fri, 22 Nov 2024 15:32:06 +0530 +Subject: [PATCH] threadpoolwinrt/tests: Add conformance tests for setting + IAsyncActionCompletedHandler handlers on an IAsyncAction. + +--- + dlls/threadpoolwinrt/tests/threadpool.c | 138 ++++++++++++++++++++++-- + 1 file changed, 130 insertions(+), 8 deletions(-) + +diff --git a/dlls/threadpoolwinrt/tests/threadpool.c b/dlls/threadpoolwinrt/tests/threadpool.c +index 715180818e1..c86e6af8483 100644 +--- a/dlls/threadpoolwinrt/tests/threadpool.c ++++ b/dlls/threadpoolwinrt/tests/threadpool.c +@@ -138,7 +138,6 @@ static ULONG STDMETHODCALLTYPE work_item_Release(IWorkItemHandler *iface) + static HRESULT STDMETHODCALLTYPE work_item_Invoke(IWorkItemHandler *iface, IAsyncAction *action) + { + struct work_item *item = impl_from_IWorkItemHandler(iface); +- IAsyncActionCompletedHandler *handler; + IAsyncInfo *async_info; + AsyncStatus status; + HRESULT hr; +@@ -160,13 +159,6 @@ static HRESULT STDMETHODCALLTYPE work_item_Invoke(IWorkItemHandler *iface, IAsyn + todo_wine + ok(hr == E_ILLEGAL_METHOD_CALL, "Unexpected hr %#lx.\n", hr); + +- handler = (void *)0xdeadbeef; +- hr = IAsyncAction_get_Completed(action, &handler); +- todo_wine +- ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); +- todo_wine +- ok(!handler, "Unexpected pointer %p.\n", handler); +- + hr = IAsyncAction_put_Completed(action, NULL); + todo_wine + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); +@@ -202,10 +194,107 @@ static HRESULT create_work_item(IWorkItemHandler **item) + return S_OK; + } + ++struct completed_handler ++{ ++ IAsyncActionCompletedHandler IAsyncActionCompletedHandler_iface; ++ HANDLE invoked_event; ++ BOOL invoked; ++ LONG refcount; ++}; ++ ++static inline struct completed_handler * ++impl_from_IAsyncActionCompletedHandler(IAsyncActionCompletedHandler *iface) ++{ ++ return CONTAINING_RECORD(iface, struct completed_handler, IAsyncActionCompletedHandler_iface); ++} ++ ++static HRESULT STDMETHODCALLTYPE handler_QueryInterface(IAsyncActionCompletedHandler *iface, REFIID riid, void **out) ++{ ++ if (IsEqualGUID(&IID_IUnknown, riid) || ++ IsEqualGUID(&IID_IAsyncActionCompletedHandler, riid)) ++ { ++ *out = iface; ++ IUnknown_AddRef((IUnknown *)*out); ++ return S_OK; ++ } ++ ++ return E_NOINTERFACE; ++} ++ ++static ULONG STDMETHODCALLTYPE handler_AddRef(IAsyncActionCompletedHandler *iface) ++{ ++ struct completed_handler *handler = impl_from_IAsyncActionCompletedHandler(iface); ++ return InterlockedIncrement(&handler->refcount); ++} ++ ++static ULONG STDMETHODCALLTYPE handler_Release(IAsyncActionCompletedHandler *iface) ++{ ++ struct completed_handler *handler = impl_from_IAsyncActionCompletedHandler(iface); ++ ULONG ref = InterlockedDecrement(&handler->refcount); ++ if (!ref) ++ { ++ CloseHandle(handler->invoked_event); ++ free(handler); ++ } ++ ++ return ref; ++} ++ ++static HRESULT STDMETHODCALLTYPE handler_Invoke(IAsyncActionCompletedHandler *iface, IAsyncAction *action, ++ AsyncStatus status) ++{ ++ struct completed_handler *handler = impl_from_IAsyncActionCompletedHandler(iface); ++ ++ ok(!handler->invoked, "Handler should only be invoked once.\n"); ++ ok(!!action, "Execpted non-null IAsyncAction value.\n"); ++ handler->invoked = TRUE; ++ SetEvent(handler->invoked_event); ++ return S_OK; ++} ++ ++static const IAsyncActionCompletedHandlerVtbl completed_handler_vtbl = { ++ handler_QueryInterface, ++ handler_AddRef, ++ handler_Release, ++ handler_Invoke, ++}; ++ ++static HRESULT create_completed_handler(IAsyncActionCompletedHandler **handler) ++{ ++ struct completed_handler *object; ++ ++ *handler = NULL; ++ ++ object = calloc(1, sizeof(*object)); ++ if (!object) ++ return E_OUTOFMEMORY; ++ ++ object->IAsyncActionCompletedHandler_iface.lpVtbl = &completed_handler_vtbl; ++ object->refcount = 1; ++ object->invoked_event = CreateEventW(NULL, FALSE, FALSE, NULL); ++ ++ *handler = &object->IAsyncActionCompletedHandler_iface; ++ ++ return S_OK; ++} ++ ++#define test_IAsyncActionCompletedHandler(h) test_IAsyncActionCompletedHandler_(__LINE__, (h)) ++static void test_IAsyncActionCompletedHandler_(int line, IAsyncActionCompletedHandler *handler) ++{ ++ struct completed_handler *impl = impl_from_IAsyncActionCompletedHandler(handler); ++ DWORD ret; ++ ++ ret = WaitForSingleObject(impl->invoked_event, 1000); ++ ok(!ret, "Unexpected wait result %lu.\n", ret); ++ ++ ok_(__FILE__, line)(impl->invoked, "Expected invoked to be non-zero.\n"); ++} ++ + static void test_RunAsync(void) + { + IActivationFactory *factory = NULL; + IThreadPoolStatics *threadpool_statics; ++ IAsyncActionCompletedHandler *handler = NULL; + IWorkItemHandler *item_iface; + struct work_item *item; + IAsyncAction *action; +@@ -250,15 +339,48 @@ static void test_RunAsync(void) + + hr = IThreadPoolStatics_RunWithPriorityAsync(threadpool_statics, item_iface, WorkItemPriority_Normal, &action); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ++ if (hr == S_OK) ++ { ++ hr = create_completed_handler(&handler); ++ ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ++ ++ if (hr == S_OK) ++ { ++ hr = IAsyncAction_put_Completed(action, handler); ++ todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ++ } ++ } + ret = WaitForSingleObject(item->event, 1000); + ok(!ret, "Unexpected wait result %lu.\n", ret); ++ if (handler) ++ { ++ todo_wine test_IAsyncActionCompletedHandler(handler); ++ IAsyncActionCompletedHandler_Release(handler); ++ } + IAsyncAction_Release(action); + ++ handler = NULL; + hr = IThreadPoolStatics_RunWithPriorityAndOptionsAsync(threadpool_statics, item_iface, WorkItemPriority_Normal, + WorkItemOptions_TimeSliced, &action); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + ret = WaitForSingleObject(item->event, 1000); + ok(!ret, "Unexpected wait result %lu.\n", ret); ++ /* Try setting a Completed handler after the work item has likely run. */ ++ if (hr == S_OK) ++ { ++ hr = create_completed_handler(&handler); ++ ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ++ ++ if (hr == S_OK) ++ { ++ hr = IAsyncAction_put_Completed(action, handler); ++ todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ++ hr = IAsyncAction_put_Completed(action, handler); ++ todo_wine ok(hr == E_ILLEGAL_DELEGATE_ASSIGNMENT, "%#lx != %#lx\n", hr, E_ILLEGAL_DELEGATE_ASSIGNMENT); ++ todo_wine test_IAsyncActionCompletedHandler(handler); ++ IAsyncActionCompletedHandler_Release(handler); ++ } ++ } + IAsyncAction_Release(action); + + hr = IThreadPoolStatics_RunWithPriorityAndOptionsAsync(threadpool_statics, item_iface, WorkItemPriority_Low, +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/6889-Draft-threadpoolwinrt-Implement-IAsyncAction-and-IAsyncInfo/0002-threadpoolwinrt-Implement-GetResults-for-IAsyncInfo.patch b/0003-pending-mrs-and-backports/6889-Draft-threadpoolwinrt-Implement-IAsyncAction-and-IAsyncInfo/0002-threadpoolwinrt-Implement-GetResults-for-IAsyncInfo.patch new file mode 100644 index 0000000..687db85 --- /dev/null +++ b/0003-pending-mrs-and-backports/6889-Draft-threadpoolwinrt-Implement-IAsyncAction-and-IAsyncInfo/0002-threadpoolwinrt-Implement-GetResults-for-IAsyncInfo.patch @@ -0,0 +1,299 @@ +From ee8a374a96d35c57f0b2bb38e2afdadbf20d639e Mon Sep 17 00:00:00 2001 +From: Vibhav Pant +Date: Fri, 22 Nov 2024 18:46:44 +0530 +Subject: [PATCH] threadpoolwinrt: Implement GetResults() for IAsyncInfo. + +--- + dlls/threadpoolwinrt/main.c | 199 +++++++++++------------- + dlls/threadpoolwinrt/tests/threadpool.c | 1 - + 2 files changed, 89 insertions(+), 111 deletions(-) + +diff --git a/dlls/threadpoolwinrt/main.c b/dlls/threadpoolwinrt/main.c +index d047d3ce9fb..66910c5e01a 100644 +--- a/dlls/threadpoolwinrt/main.c ++++ b/dlls/threadpoolwinrt/main.c +@@ -48,6 +48,12 @@ struct async_action + { + IAsyncAction IAsyncAction_iface; + IAsyncInfo IAsyncInfo_iface; ++ ++ TP_WORK *work; ++ IWorkItemHandler *work_item_handler; ++ ++ CRITICAL_SECTION cs; ++ AsyncStatus status; + LONG refcount; + }; + +@@ -116,7 +122,12 @@ static ULONG STDMETHODCALLTYPE async_action_Release(IAsyncAction *iface) + TRACE("iface %p, refcount %lu.\n", iface, refcount); + + if (!refcount) ++ { ++ IWorkItemHandler_Release(action->work_item_handler); ++ action->cs.DebugInfo->Spare[0] = 0; ++ DeleteCriticalSection(&action->cs); + free(action); ++ } + + return refcount; + } +@@ -161,9 +172,18 @@ static HRESULT STDMETHODCALLTYPE async_action_get_Completed(IAsyncAction *iface, + + static HRESULT STDMETHODCALLTYPE async_action_GetResults(IAsyncAction *iface) + { +- FIXME("iface %p stub!\n", iface); ++ struct async_action *action; ++ HRESULT hr = E_ILLEGAL_METHOD_CALL; + +- return E_NOTIMPL; ++ TRACE("iface %p\n", iface); ++ ++ action = impl_from_IAsyncAction(iface); ++ EnterCriticalSection(&action->cs); ++ if (action->status == Completed || action->status == Error) ++ hr = S_OK; ++ LeaveCriticalSection(&action->cs); ++ ++ return hr; + } + + static const IAsyncActionVtbl async_action_vtbl = +@@ -265,73 +285,87 @@ static const IAsyncInfoVtbl async_info_vtbl = + async_info_Close, + }; + +-static HRESULT async_action_create(IAsyncAction **ret) +-{ +- struct async_action *object; +- +- *ret = NULL; +- +- if (!(object = calloc(1, sizeof(*object)))) +- return E_OUTOFMEMORY; + +- object->IAsyncAction_iface.lpVtbl = &async_action_vtbl; +- object->IAsyncInfo_iface.lpVtbl = &async_info_vtbl; +- object->refcount = 1; ++static void async_action_invoke_and_release(IAsyncAction *action_iface) ++{ ++ struct async_action *action = impl_from_IAsyncAction(action_iface); ++ HRESULT hr; + +- *ret = &object->IAsyncAction_iface; ++ hr = IWorkItemHandler_Invoke(action->work_item_handler, action_iface); + +- return S_OK; ++ EnterCriticalSection(&action->cs); ++ action->status = FAILED(hr) ? Error : Completed; ++ LeaveCriticalSection(&action->cs); ++ IAsyncAction_Release(action_iface); + } + +-struct work_item ++static void CALLBACK async_action_tp_callback(TP_CALLBACK_INSTANCE *inst, void *action_iface, TP_WORK *work) + { +- IWorkItemHandler *handler; +- IAsyncAction *action; +-}; ++ async_action_invoke_and_release(action_iface); ++} + +-static void release_work_item(struct work_item *item) ++static DWORD CALLBACK async_action_sliced_proc(void *action_iface) + { +- IWorkItemHandler_Release(item->handler); +- IAsyncAction_Release(item->action); +- free(item); ++ async_action_invoke_and_release(action_iface); ++ return 0; + } + +-static HRESULT alloc_work_item(IWorkItemHandler *handler, struct work_item **ret) ++static HRESULT async_action_create_and_start(TP_CALLBACK_ENVIRON *environment, WorkItemPriority priority, ++ IWorkItemHandler *work_item, IAsyncAction **ret) + { +- struct work_item *object; +- HRESULT hr; ++ struct async_action *object; ++ HANDLE thread = NULL; + + *ret = NULL; + + if (!(object = calloc(1, sizeof(*object)))) + return E_OUTOFMEMORY; + +- if (FAILED(hr = async_action_create(&object->action))) ++ object->IAsyncAction_iface.lpVtbl = &async_action_vtbl; ++ object->IAsyncInfo_iface.lpVtbl = &async_info_vtbl; ++ if (environment) + { +- free(object); +- return hr; ++ object->work = CreateThreadpoolWork(async_action_tp_callback, &object->IAsyncAction_iface, environment); ++ if (!object->work) ++ { ++ ERR("Failed to create a thread pool work item: %lu.\n", GetLastError()); ++ free(object); ++ return HRESULT_FROM_WIN32(GetLastError()); ++ } + } +- +- IWorkItemHandler_AddRef((object->handler = handler)); +- +- *ret = object; ++ else ++ { ++ thread = CreateThread(NULL, 0, async_action_sliced_proc, &object->IAsyncAction_iface, CREATE_SUSPENDED, ++ NULL); ++ if (!thread) ++ { ++ ERR("Failed to create a thread: %lu\n", GetLastError()); ++ free(object); ++ return HRESULT_FROM_WIN32(GetLastError()); ++ } ++ if (priority != WorkItemPriority_Normal) ++ SetThreadPriority(thread, priority == WorkItemPriority_High ? THREAD_PRIORITY_HIGHEST ++ : THREAD_PRIORITY_LOWEST); ++ } ++ object->work_item_handler = work_item; ++ IWorkItemHandler_AddRef(work_item); ++ object->status = Started; ++ InitializeCriticalSectionEx(&object->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); ++ object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__": async_action.cs"); ++ object->refcount = 2; ++ ++ if (object->work) ++ SubmitThreadpoolWork(object->work); ++ else ++ { ++ ResumeThread(thread); ++ CloseHandle(thread); ++ } ++ *ret = &object->IAsyncAction_iface; + + return S_OK; + } + +-static void work_item_invoke_release(struct work_item *item) +-{ +- IWorkItemHandler_Invoke(item->handler, item->action); +- release_work_item(item); +-} +- +-static DWORD WINAPI sliced_thread_proc(void *arg) +-{ +- struct work_item *item = arg; +- work_item_invoke_release(item); +- return 0; +-} +- + struct thread_pool + { + INIT_ONCE init_once; +@@ -354,62 +388,10 @@ static BOOL CALLBACK pool_init_once(INIT_ONCE *init_once, void *param, void **co + return TRUE; + } + +-static void CALLBACK pool_work_callback(TP_CALLBACK_INSTANCE *instance, void *context, TP_WORK *work) +-{ +- struct work_item *item = context; +- work_item_invoke_release(item); +-} +- +-static HRESULT submit_threadpool_work(struct work_item *item, WorkItemPriority priority, IAsyncAction **action) +-{ +- struct thread_pool *pool; +- TP_WORK *work; +- +- assert(priority == WorkItemPriority_Low +- || priority == WorkItemPriority_Normal +- || priority == WorkItemPriority_High); +- +- pool = &pools[priority + 1]; +- +- if (!InitOnceExecuteOnce(&pool->init_once, pool_init_once, pool, NULL)) +- return E_FAIL; +- +- if (!(work = CreateThreadpoolWork(pool_work_callback, item, &pool->environment))) +- return E_FAIL; +- +- IAsyncAction_AddRef((*action = item->action)); +- SubmitThreadpoolWork(work); +- +- return S_OK; +-} +- +-static HRESULT submit_standalone_thread_work(struct work_item *item, WorkItemPriority priority, IAsyncAction **action) +-{ +- HANDLE thread; +- +- if (!(thread = CreateThread(NULL, 0, sliced_thread_proc, item, priority == WorkItemPriority_Normal ? +- 0 : CREATE_SUSPENDED, NULL))) +- { +- WARN("Failed to create a thread, error %ld.\n", GetLastError()); +- return HRESULT_FROM_WIN32(GetLastError()); +- } +- +- IAsyncAction_AddRef((*action = item->action)); +- if (priority != WorkItemPriority_Normal) +- { +- SetThreadPriority(thread, priority == WorkItemPriority_High ? THREAD_PRIORITY_HIGHEST : THREAD_PRIORITY_LOWEST); +- ResumeThread(thread); +- } +- CloseHandle(thread); +- +- return S_OK; +-} +- + static HRESULT run_async(IWorkItemHandler *handler, WorkItemPriority priority, WorkItemOptions options, + IAsyncAction **action) + { +- struct work_item *item; +- HRESULT hr; ++ TP_CALLBACK_ENVIRON *environment = NULL; + + *action = NULL; + +@@ -419,18 +401,15 @@ static HRESULT run_async(IWorkItemHandler *handler, WorkItemPriority priority, W + if (priority < WorkItemPriority_Low || priority > WorkItemPriority_High) + return E_INVALIDARG; + +- if (FAILED(hr = alloc_work_item(handler, &item))) +- return hr; +- +- if (options == WorkItemOptions_TimeSliced) +- hr = submit_standalone_thread_work(item, priority, action); +- else +- hr = submit_threadpool_work(item, priority, action); +- +- if (FAILED(hr)) +- release_work_item(item); ++ if (options != WorkItemOptions_TimeSliced) ++ { ++ struct thread_pool *pool = &pools[priority + 1]; ++ if (!InitOnceExecuteOnce(&pool->init_once, pool_init_once, pool, NULL)) ++ return E_FAIL; ++ environment = &pools[priority + 1].environment; ++ } + +- return hr; ++ return async_action_create_and_start(environment, priority, handler, action); + } + + static HRESULT STDMETHODCALLTYPE threadpool_factory_QueryInterface( +diff --git a/dlls/threadpoolwinrt/tests/threadpool.c b/dlls/threadpoolwinrt/tests/threadpool.c +index c86e6af8483..73a91358c64 100644 +--- a/dlls/threadpoolwinrt/tests/threadpool.c ++++ b/dlls/threadpoolwinrt/tests/threadpool.c +@@ -156,7 +156,6 @@ static HRESULT STDMETHODCALLTYPE work_item_Invoke(IWorkItemHandler *iface, IAsyn + IAsyncInfo_Release(async_info); + + hr = IAsyncAction_GetResults(action); +- todo_wine + ok(hr == E_ILLEGAL_METHOD_CALL, "Unexpected hr %#lx.\n", hr); + + hr = IAsyncAction_put_Completed(action, NULL); +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/6889-Draft-threadpoolwinrt-Implement-IAsyncAction-and-IAsyncInfo/0003-threadpoolwinrt-Implement-get-Id-get-Status-get-ErrorCode-Cancel-Close-for-IAsyncInfo.patch b/0003-pending-mrs-and-backports/6889-Draft-threadpoolwinrt-Implement-IAsyncAction-and-IAsyncInfo/0003-threadpoolwinrt-Implement-get-Id-get-Status-get-ErrorCode-Cancel-Close-for-IAsyncInfo.patch new file mode 100644 index 0000000..94b1d7c --- /dev/null +++ b/0003-pending-mrs-and-backports/6889-Draft-threadpoolwinrt-Implement-IAsyncAction-and-IAsyncInfo/0003-threadpoolwinrt-Implement-get-Id-get-Status-get-ErrorCode-Cancel-Close-for-IAsyncInfo.patch @@ -0,0 +1,190 @@ +From eb927692b443cd08ac7d57fe05c0bc5e3ac1c5d3 Mon Sep 17 00:00:00 2001 +From: Vibhav Pant +Date: Fri, 22 Nov 2024 19:02:19 +0530 +Subject: [PATCH] threadpoolwinrt: Implement get_Id, get_Status, get_ErrorCode, + Cancel, Close for IAsyncInfo. + +--- + dlls/threadpoolwinrt/main.c | 85 +++++++++++++++++++++---- + dlls/threadpoolwinrt/tests/threadpool.c | 2 - + 2 files changed, 74 insertions(+), 13 deletions(-) + +diff --git a/dlls/threadpoolwinrt/main.c b/dlls/threadpoolwinrt/main.c +index 66910c5e01a..8a85cdb1612 100644 +--- a/dlls/threadpoolwinrt/main.c ++++ b/dlls/threadpoolwinrt/main.c +@@ -37,6 +37,8 @@ + + WINE_DEFAULT_DEBUG_CHANNEL(threadpool); + ++#define Closed 4 ++ + struct threadpool_factory + { + IActivationFactory IActivationFactory_iface; +@@ -49,6 +51,8 @@ struct async_action + IAsyncAction IAsyncAction_iface; + IAsyncInfo IAsyncInfo_iface; + ++ UINT32 id; ++ HRESULT hr; + TP_WORK *work; + IWorkItemHandler *work_item_handler; + +@@ -123,6 +127,7 @@ static ULONG STDMETHODCALLTYPE async_action_Release(IAsyncAction *iface) + + if (!refcount) + { ++ IAsyncInfo_Close(&action->IAsyncInfo_iface); + IWorkItemHandler_Release(action->work_item_handler); + action->cs.DebugInfo->Spare[0] = 0; + DeleteCriticalSection(&action->cs); +@@ -237,37 +242,91 @@ static HRESULT STDMETHODCALLTYPE async_info_GetTrustLevel(IAsyncInfo *iface, Tru + + static HRESULT STDMETHODCALLTYPE async_info_get_Id(IAsyncInfo *iface, UINT32 *id) + { +- FIXME("iface %p, id %p stub!\n", iface, id); ++ struct async_action *action = impl_from_IAsyncInfo(iface); ++ HRESULT hr = S_OK; + +- return E_NOTIMPL; ++ TRACE("iface %p, id %p\n", iface, id); ++ ++ EnterCriticalSection(&action->cs); ++ if (action->status == Closed) ++ hr = E_ILLEGAL_METHOD_CALL; ++ else ++ *id = action->id; ++ LeaveCriticalSection(&action->cs); ++ ++ return hr; + } + + static HRESULT STDMETHODCALLTYPE async_info_get_Status(IAsyncInfo *iface, AsyncStatus *status) + { +- FIXME("iface %p, status %p stub!\n", iface, status); ++ struct async_action *action = impl_from_IAsyncInfo(iface); ++ HRESULT hr = S_OK; + +- return E_NOTIMPL; ++ TRACE("iface %p, status %p\n", iface, status); ++ ++ EnterCriticalSection(&action->cs); ++ if (action->status == Closed) ++ hr = E_ILLEGAL_METHOD_CALL; ++ *status = action->status; ++ LeaveCriticalSection(&action->cs); ++ ++ return hr; + } + + static HRESULT STDMETHODCALLTYPE async_info_get_ErrorCode(IAsyncInfo *iface, HRESULT *error_code) + { +- FIXME("iface %p, error_code %p stub!\n", iface, error_code); ++ struct async_action *action = impl_from_IAsyncInfo(iface); ++ HRESULT hr = S_OK; + +- return E_NOTIMPL; ++ TRACE("iface %p, error_code %p\n", iface, error_code); ++ ++ EnterCriticalSection(&action->cs); ++ if (action->status == Closed) ++ *error_code = hr = E_ILLEGAL_METHOD_CALL; ++ else ++ *error_code = action->hr; ++ LeaveCriticalSection(&action->cs); ++ ++ return hr; + } + + static HRESULT STDMETHODCALLTYPE async_info_Cancel(IAsyncInfo *iface) + { +- FIXME("iface %p stub!\n", iface); ++ struct async_action *action = impl_from_IAsyncInfo(iface); ++ HRESULT hr = S_OK; + +- return E_NOTIMPL; ++ TRACE("iface %p\n", iface); ++ ++ EnterCriticalSection(&action->cs); ++ if (action->status == Closed) ++ hr = E_ILLEGAL_METHOD_CALL; ++ else if (action->status == Started) ++ action->status = Canceled; ++ LeaveCriticalSection(&action->cs); ++ ++ return hr; + } + + static HRESULT STDMETHODCALLTYPE async_info_Close(IAsyncInfo *iface) + { +- FIXME("iface %p stub!\n", iface); ++ struct async_action *action = impl_from_IAsyncInfo( iface ); ++ HRESULT hr = S_OK; + +- return E_NOTIMPL; ++ TRACE("iface %p\n", iface); ++ ++ EnterCriticalSection(&action->cs); ++ if (action->status == Started) ++ hr = E_ILLEGAL_STATE_CHANGE; ++ else if (action->status != Closed) ++ { ++ if (action->work) ++ CloseThreadpoolWork( action->work ); ++ action->work = NULL; ++ action->status = Closed; ++ } ++ LeaveCriticalSection(&action->cs); ++ ++ return hr; + } + + static const IAsyncInfoVtbl async_info_vtbl = +@@ -294,7 +353,9 @@ static void async_action_invoke_and_release(IAsyncAction *action_iface) + hr = IWorkItemHandler_Invoke(action->work_item_handler, action_iface); + + EnterCriticalSection(&action->cs); +- action->status = FAILED(hr) ? Error : Completed; ++ action->hr = hr; ++ if (action->status != Closed) ++ action->status = FAILED(hr) ? Error : Completed; + LeaveCriticalSection(&action->cs); + IAsyncAction_Release(action_iface); + } +@@ -314,6 +375,7 @@ static HRESULT async_action_create_and_start(TP_CALLBACK_ENVIRON *environment, W + IWorkItemHandler *work_item, IAsyncAction **ret) + { + struct async_action *object; ++ static LONG async_action_id = 0; + HANDLE thread = NULL; + + *ret = NULL; +@@ -347,6 +409,7 @@ static HRESULT async_action_create_and_start(TP_CALLBACK_ENVIRON *environment, W + SetThreadPriority(thread, priority == WorkItemPriority_High ? THREAD_PRIORITY_HIGHEST + : THREAD_PRIORITY_LOWEST); + } ++ object->id = InterlockedIncrement(&async_action_id); + object->work_item_handler = work_item; + IWorkItemHandler_AddRef(work_item); + object->status = Started; +diff --git a/dlls/threadpoolwinrt/tests/threadpool.c b/dlls/threadpoolwinrt/tests/threadpool.c +index 73a91358c64..6048a868234 100644 +--- a/dlls/threadpoolwinrt/tests/threadpool.c ++++ b/dlls/threadpoolwinrt/tests/threadpool.c +@@ -145,12 +145,10 @@ static HRESULT STDMETHODCALLTYPE work_item_Invoke(IWorkItemHandler *iface, IAsyn + hr = IAsyncAction_QueryInterface(action, &IID_IAsyncInfo, (void **)&async_info); + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IAsyncInfo_get_Status(async_info, &status); +- todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + if (SUCCEEDED(hr)) ok(status == Started, "Unexpected status %d.\n", status); + + hr = IAsyncInfo_Cancel(async_info); +- todo_wine + ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + + IAsyncInfo_Release(async_info); +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/6889-Draft-threadpoolwinrt-Implement-IAsyncAction-and-IAsyncInfo/0004-threadpoolwinrt-Implement-put-Completed-and-get-Completed-for-IAsyncAction.patch b/0003-pending-mrs-and-backports/6889-Draft-threadpoolwinrt-Implement-IAsyncAction-and-IAsyncInfo/0004-threadpoolwinrt-Implement-put-Completed-and-get-Completed-for-IAsyncAction.patch new file mode 100644 index 0000000..9ca856d --- /dev/null +++ b/0003-pending-mrs-and-backports/6889-Draft-threadpoolwinrt-Implement-IAsyncAction-and-IAsyncInfo/0004-threadpoolwinrt-Implement-put-Completed-and-get-Completed-for-IAsyncAction.patch @@ -0,0 +1,183 @@ +From fcd66519e82207532d9fe72a2389d47fb5ea2fb1 Mon Sep 17 00:00:00 2001 +From: Vibhav Pant +Date: Fri, 22 Nov 2024 18:49:28 +0530 +Subject: [PATCH] threadpoolwinrt: Implement put_Completed and get_Completed + for IAsyncAction. + +--- + dlls/threadpoolwinrt/main.c | 72 +++++++++++++++++++++++-- + dlls/threadpoolwinrt/tests/threadpool.c | 11 ++-- + 2 files changed, 72 insertions(+), 11 deletions(-) + +diff --git a/dlls/threadpoolwinrt/main.c b/dlls/threadpoolwinrt/main.c +index 8a85cdb1612..87643836513 100644 +--- a/dlls/threadpoolwinrt/main.c ++++ b/dlls/threadpoolwinrt/main.c +@@ -37,6 +37,7 @@ + + WINE_DEFAULT_DEBUG_CHANNEL(threadpool); + ++#define HANDLER_NOT_SET ((void *)~(ULONG_PTR)0) + #define Closed 4 + + struct threadpool_factory +@@ -57,6 +58,7 @@ struct async_action + IWorkItemHandler *work_item_handler; + + CRITICAL_SECTION cs; ++ IAsyncActionCompletedHandler *completed_handler; + AsyncStatus status; + LONG refcount; + }; +@@ -127,6 +129,8 @@ static ULONG STDMETHODCALLTYPE async_action_Release(IAsyncAction *iface) + + if (!refcount) + { ++ if (action->completed_handler && action->completed_handler != HANDLER_NOT_SET) ++ IAsyncActionCompletedHandler_Release( action->completed_handler ); + IAsyncInfo_Close(&action->IAsyncInfo_iface); + IWorkItemHandler_Release(action->work_item_handler); + action->cs.DebugInfo->Spare[0] = 0; +@@ -163,16 +167,61 @@ static HRESULT STDMETHODCALLTYPE async_action_GetTrustLevel( + + static HRESULT STDMETHODCALLTYPE async_action_put_Completed(IAsyncAction *iface, IAsyncActionCompletedHandler *handler) + { +- FIXME("iface %p, handler %p stub!\n", iface, handler); ++ struct async_action *action; ++ HRESULT hr = S_OK; + +- return E_NOTIMPL; ++ TRACE("iface %p, handler %p\n", iface, handler); ++ ++ if (!handler) ++ return E_POINTER; ++ ++ action = impl_from_IAsyncAction(iface); ++ EnterCriticalSection(&action->cs); ++ if (action->status == Closed) ++ hr = E_ILLEGAL_METHOD_CALL; ++ else if (action->completed_handler != HANDLER_NOT_SET) ++ hr = E_ILLEGAL_DELEGATE_ASSIGNMENT; ++ else if (handler) ++ { ++ action->completed_handler = handler; ++ IAsyncActionCompletedHandler_AddRef(action->completed_handler); ++ if (action->status > Started) ++ { ++ AsyncStatus status = action->status; ++ action->completed_handler = NULL; ++ LeaveCriticalSection(&action->cs); ++ ++ IAsyncActionCompletedHandler_Invoke(handler, iface, status); ++ IAsyncActionCompletedHandler_Release(handler); ++ return S_OK; ++ } ++ } ++ LeaveCriticalSection(&action->cs); ++ ++ return hr; + } + + static HRESULT STDMETHODCALLTYPE async_action_get_Completed(IAsyncAction *iface, IAsyncActionCompletedHandler **handler) + { +- FIXME("iface %p, handler %p stub!\n", iface, handler); ++ struct async_action *action; ++ HRESULT hr = S_OK; + +- return E_NOTIMPL; ++ TRACE("iface %p, handler %p\n", iface, handler); ++ ++ action = impl_from_IAsyncAction(iface); ++ EnterCriticalSection(&action->cs); ++ if (action->status == Closed) ++ hr = E_ILLEGAL_METHOD_CALL; ++ if (!action->completed_handler || action->completed_handler == HANDLER_NOT_SET) ++ *handler = NULL; ++ else ++ { ++ *handler = action->completed_handler; ++ IAsyncActionCompletedHandler_AddRef(*handler); ++ } ++ LeaveCriticalSection(&action->cs); ++ ++ return hr; + } + + static HRESULT STDMETHODCALLTYPE async_action_GetResults(IAsyncAction *iface) +@@ -354,9 +403,21 @@ static void async_action_invoke_and_release(IAsyncAction *action_iface) + + EnterCriticalSection(&action->cs); + action->hr = hr; ++ + if (action->status != Closed) + action->status = FAILED(hr) ? Error : Completed; +- LeaveCriticalSection(&action->cs); ++ if (action->completed_handler && action->completed_handler != HANDLER_NOT_SET) ++ { ++ AsyncStatus status = action->status; ++ IAsyncActionCompletedHandler *handler = action->completed_handler; ++ action->completed_handler = NULL; ++ LeaveCriticalSection(&action->cs); ++ ++ IAsyncActionCompletedHandler_Invoke(handler, &action->IAsyncAction_iface, status); ++ IAsyncActionCompletedHandler_Release(handler); ++ } ++ else ++ LeaveCriticalSection(&action->cs); + IAsyncAction_Release(action_iface); + } + +@@ -412,6 +473,7 @@ static HRESULT async_action_create_and_start(TP_CALLBACK_ENVIRON *environment, W + object->id = InterlockedIncrement(&async_action_id); + object->work_item_handler = work_item; + IWorkItemHandler_AddRef(work_item); ++ object->completed_handler = HANDLER_NOT_SET; + object->status = Started; + InitializeCriticalSectionEx(&object->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO); + object->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__": async_action.cs"); +diff --git a/dlls/threadpoolwinrt/tests/threadpool.c b/dlls/threadpoolwinrt/tests/threadpool.c +index 6048a868234..94e7cf48bf5 100644 +--- a/dlls/threadpoolwinrt/tests/threadpool.c ++++ b/dlls/threadpoolwinrt/tests/threadpool.c +@@ -157,7 +157,6 @@ static HRESULT STDMETHODCALLTYPE work_item_Invoke(IWorkItemHandler *iface, IAsyn + ok(hr == E_ILLEGAL_METHOD_CALL, "Unexpected hr %#lx.\n", hr); + + hr = IAsyncAction_put_Completed(action, NULL); +- todo_wine + ok(hr == E_POINTER, "Unexpected hr %#lx.\n", hr); + + SetEvent(item->event); +@@ -344,14 +343,14 @@ static void test_RunAsync(void) + if (hr == S_OK) + { + hr = IAsyncAction_put_Completed(action, handler); +- todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ++ ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + } + } + ret = WaitForSingleObject(item->event, 1000); + ok(!ret, "Unexpected wait result %lu.\n", ret); + if (handler) + { +- todo_wine test_IAsyncActionCompletedHandler(handler); ++ test_IAsyncActionCompletedHandler(handler); + IAsyncActionCompletedHandler_Release(handler); + } + IAsyncAction_Release(action); +@@ -371,10 +370,10 @@ static void test_RunAsync(void) + if (hr == S_OK) + { + hr = IAsyncAction_put_Completed(action, handler); +- todo_wine ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); ++ ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); + hr = IAsyncAction_put_Completed(action, handler); +- todo_wine ok(hr == E_ILLEGAL_DELEGATE_ASSIGNMENT, "%#lx != %#lx\n", hr, E_ILLEGAL_DELEGATE_ASSIGNMENT); +- todo_wine test_IAsyncActionCompletedHandler(handler); ++ ok(hr == E_ILLEGAL_DELEGATE_ASSIGNMENT, "%#lx != %#lx\n", hr, E_ILLEGAL_DELEGATE_ASSIGNMENT); ++ test_IAsyncActionCompletedHandler(handler); + IAsyncActionCompletedHandler_Release(handler); + } + } +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/6889-Draft-threadpoolwinrt-Implement-IAsyncAction-and-IAsyncInfo/0005-cryptowinrt-Rewrite-IAsyncOperation-using-Windows-System-Threading.patch b/0003-pending-mrs-and-backports/6889-Draft-threadpoolwinrt-Implement-IAsyncAction-and-IAsyncInfo/0005-cryptowinrt-Rewrite-IAsyncOperation-using-Windows-System-Threading.patch new file mode 100644 index 0000000..54482eb --- /dev/null +++ b/0003-pending-mrs-and-backports/6889-Draft-threadpoolwinrt-Implement-IAsyncAction-and-IAsyncInfo/0005-cryptowinrt-Rewrite-IAsyncOperation-using-Windows-System-Threading.patch @@ -0,0 +1,762 @@ +From 421a3ca62375fec19f643b7f2e53eb78a9a2afe4 Mon Sep 17 00:00:00 2001 +From: Vibhav Pant +Date: Fri, 22 Nov 2024 22:33:37 +0530 +Subject: [PATCH] cryptowinrt: Rewrite IAsyncOperation using + Windows.System.Threading. + +--- + dlls/cryptowinrt/Makefile.in | 1 - + dlls/cryptowinrt/async.c | 479 +++++++++++++++------------------- + dlls/cryptowinrt/private.h | 3 +- + dlls/cryptowinrt/provider.idl | 47 ---- + 4 files changed, 216 insertions(+), 314 deletions(-) + delete mode 100644 dlls/cryptowinrt/provider.idl + +diff --git a/dlls/cryptowinrt/Makefile.in b/dlls/cryptowinrt/Makefile.in +index 8d9d23a6cc2..9517170b1d3 100644 +--- a/dlls/cryptowinrt/Makefile.in ++++ b/dlls/cryptowinrt/Makefile.in +@@ -6,4 +6,3 @@ SOURCES = \ + classes.idl \ + credentials.c \ + main.c \ +- provider.idl +diff --git a/dlls/cryptowinrt/async.c b/dlls/cryptowinrt/async.c +index 5c3d718ae2d..bb6c76fec5e 100644 +--- a/dlls/cryptowinrt/async.c ++++ b/dlls/cryptowinrt/async.c +@@ -2,6 +2,7 @@ + * + * Copyright 2022 Bernhard Kölbl for CodeWeavers + * Copyright 2022 Rémi Bernon for CodeWeavers ++ * Copyright 2024 Vibhav Pant + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public +@@ -20,353 +21,268 @@ + + #include "private.h" + ++#include "roapi.h" + #include "wine/debug.h" + + WINE_DEFAULT_DEBUG_CHANNEL(crypto); + +-#define Closed 4 +-#define HANDLER_NOT_SET ((void *)~(ULONG_PTR)0) ++typedef HRESULT (WINAPI *async_completed_invoke_callback)(IInspectable *handler, IInspectable *info, AsyncStatus status); + +-struct async_info ++struct async_completed + { +- IWineAsyncInfoImpl IWineAsyncInfoImpl_iface; +- IAsyncInfo IAsyncInfo_iface; +- IInspectable *IInspectable_outer; ++ IAsyncActionCompletedHandler IAsyncActionCompletedHandler_iface; ++ IInspectable *outer_handler; ++ IInspectable *outer_operation; ++ async_completed_invoke_callback cb; + LONG ref; +- +- async_operation_callback callback; +- TP_WORK *async_run_work; +- IUnknown *invoker; +- IUnknown *param; +- +- CRITICAL_SECTION cs; +- IWineAsyncOperationCompletedHandler *handler; +- PROPVARIANT result; +- AsyncStatus status; +- HRESULT hr; + }; + +-static inline struct async_info *impl_from_IWineAsyncInfoImpl( IWineAsyncInfoImpl *iface ) ++#define DEFINE_ASYNC_COMPLETED_HANDLER_CALLBACK( type ) \ ++ static HRESULT WINAPI async_completed_handler_cb_##type( IInspectable *handler, IInspectable *operation, \ ++ AsyncStatus status ) \ ++ { \ ++ return IAsyncOperationCompletedHandler_##type##_Invoke( \ ++ (IAsyncOperationCompletedHandler_##type *)handler, (IAsyncOperation_##type *)operation, status ); \ ++ } ++ ++static inline struct async_completed *impl_from_IAsyncActionCompletedHandler( IAsyncActionCompletedHandler *iface ) + { +- return CONTAINING_RECORD( iface, struct async_info, IWineAsyncInfoImpl_iface ); ++ return CONTAINING_RECORD( iface, struct async_completed, IAsyncActionCompletedHandler_iface ); + } + +-static HRESULT WINAPI async_impl_QueryInterface( IWineAsyncInfoImpl *iface, REFIID iid, void **out ) ++static HRESULT WINAPI async_completed_QueryInterface( IAsyncActionCompletedHandler *iface, REFIID iid, void **out ) + { +- struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); ++ struct async_completed *impl = impl_from_IAsyncActionCompletedHandler( iface ); + + TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + + if (IsEqualGUID( iid, &IID_IUnknown ) || + IsEqualGUID( iid, &IID_IInspectable ) || +- IsEqualGUID( iid, &IID_IAgileObject ) || +- IsEqualGUID( iid, &IID_IWineAsyncInfoImpl )) +- { +- IInspectable_AddRef( (*out = &impl->IWineAsyncInfoImpl_iface) ); +- return S_OK; +- } +- +- if (IsEqualGUID( iid, &IID_IAsyncInfo )) ++ IsEqualGUID( iid, &IID_IAsyncActionCompletedHandler )) + { +- IInspectable_AddRef( (*out = &impl->IAsyncInfo_iface) ); ++ *out = iface; ++ IUnknown_AddRef((IUnknown *)*out); + return S_OK; + } + +- FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); +- *out = NULL; +- return E_NOINTERFACE; ++ return IInspectable_QueryInterface( impl->outer_handler, iid, out ); + } + +-static ULONG WINAPI async_impl_AddRef( IWineAsyncInfoImpl *iface ) ++static ULONG WINAPI async_completed_AddRef( IAsyncActionCompletedHandler *iface ) + { +- struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); ++ struct async_completed *impl = impl_from_IAsyncActionCompletedHandler( iface ); + ULONG ref = InterlockedIncrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + return ref; + } + +-static ULONG WINAPI async_impl_Release( IWineAsyncInfoImpl *iface ) ++static ULONG WINAPI async_completed_Release( IAsyncActionCompletedHandler *iface ) + { +- struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); ++ struct async_completed *impl = impl_from_IAsyncActionCompletedHandler( iface ); + ULONG ref = InterlockedDecrement( &impl->ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + + if (!ref) + { +- if (impl->handler && impl->handler != HANDLER_NOT_SET) IWineAsyncOperationCompletedHandler_Release( impl->handler ); +- IAsyncInfo_Close( &impl->IAsyncInfo_iface ); +- if (impl->param) IUnknown_Release( impl->param ); +- if (impl->invoker) IUnknown_Release( impl->invoker ); +- impl->cs.DebugInfo->Spare[0] = 0; +- DeleteCriticalSection( &impl->cs ); ++ IInspectable_Release( impl->outer_handler ); ++ IInspectable_Release( impl->outer_operation ); + free( impl ); + } + + return ref; + } + +-static HRESULT WINAPI async_impl_put_Completed( IWineAsyncInfoImpl *iface, IWineAsyncOperationCompletedHandler *handler ) ++static HRESULT WINAPI async_completed_Invoke( IAsyncActionCompletedHandler *iface, IAsyncAction *info, ++ AsyncStatus status ) + { +- struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); +- HRESULT hr = S_OK; +- +- TRACE( "iface %p, handler %p.\n", iface, handler ); +- +- EnterCriticalSection( &impl->cs ); +- if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; +- else if (impl->handler != HANDLER_NOT_SET) hr = E_ILLEGAL_DELEGATE_ASSIGNMENT; +- else if ((impl->handler = handler)) +- { +- IWineAsyncOperationCompletedHandler_AddRef( impl->handler ); +- +- if (impl->status > Started) +- { +- IInspectable *operation = impl->IInspectable_outer; +- AsyncStatus status = impl->status; +- impl->handler = NULL; /* Prevent concurrent invoke. */ +- LeaveCriticalSection( &impl->cs ); +- +- IWineAsyncOperationCompletedHandler_Invoke( handler, operation, status ); +- IWineAsyncOperationCompletedHandler_Release( handler ); +- +- return S_OK; +- } +- } +- LeaveCriticalSection( &impl->cs ); +- +- return hr; +-} +- +-static HRESULT WINAPI async_impl_get_Completed( IWineAsyncInfoImpl *iface, IWineAsyncOperationCompletedHandler **handler ) +-{ +- struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); +- HRESULT hr = S_OK; +- +- TRACE( "iface %p, handler %p.\n", iface, handler ); +- +- EnterCriticalSection( &impl->cs ); +- if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; +- if (impl->handler == NULL || impl->handler == HANDLER_NOT_SET) *handler = NULL; +- else IWineAsyncOperationCompletedHandler_AddRef( (*handler = impl->handler) ); +- LeaveCriticalSection( &impl->cs ); +- +- return hr; ++ struct async_completed *impl = impl_from_IAsyncActionCompletedHandler( iface ); ++ return impl->cb( (IInspectable *)impl->outer_handler, (IInspectable *)impl->outer_operation, status); + } + +-static HRESULT WINAPI async_impl_get_Result( IWineAsyncInfoImpl *iface, PROPVARIANT *result ) ++static const IAsyncActionCompletedHandlerVtbl async_completed_vtbl = + { +- struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); +- HRESULT hr = E_ILLEGAL_METHOD_CALL; +- +- TRACE( "iface %p, result %p.\n", iface, result ); +- +- EnterCriticalSection( &impl->cs ); +- if (impl->status == Completed || impl->status == Error) +- { +- PropVariantCopy( result, &impl->result ); +- hr = impl->hr; +- } +- LeaveCriticalSection( &impl->cs ); +- +- return hr; +-} ++ async_completed_QueryInterface, ++ async_completed_AddRef, ++ async_completed_Release, ++ async_completed_Invoke, ++}; + +-static HRESULT WINAPI async_impl_Start( IWineAsyncInfoImpl *iface ) ++static HRESULT async_completed_create( IInspectable *outer_operation, IInspectable *outer_handler, ++ async_completed_invoke_callback cb, IAsyncActionCompletedHandler **handler ) + { +- struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); +- +- TRACE( "iface %p.\n", iface ); +- +- /* keep the async alive in the callback */ +- IInspectable_AddRef( impl->IInspectable_outer ); +- SubmitThreadpoolWork( impl->async_run_work ); ++ struct async_completed *impl; ++ ++ impl = calloc( 1, sizeof( *impl ) ); ++ if (!impl) ++ return E_NOINTERFACE; ++ ++ impl->IAsyncActionCompletedHandler_iface.lpVtbl = &async_completed_vtbl; ++ impl->outer_operation = outer_operation; ++ impl->outer_handler = outer_handler; ++ IInspectable_AddRef( impl->outer_operation ); ++ IInspectable_AddRef( impl->outer_handler ); ++ impl->cb = cb; ++ impl->ref = 1; + ++ *handler = &impl->IAsyncActionCompletedHandler_iface; + return S_OK; + } + +-static const struct IWineAsyncInfoImplVtbl async_impl_vtbl = ++struct async_operation_base + { +- /* IUnknown methods */ +- async_impl_QueryInterface, +- async_impl_AddRef, +- async_impl_Release, +- /* IWineAsyncInfoImpl */ +- async_impl_put_Completed, +- async_impl_get_Completed, +- async_impl_get_Result, +- async_impl_Start, ++ IWorkItemHandler *work_item; ++ IAsyncAction *inner_action; ++ PROPVARIANT *result; ++ LONG ref; + }; + +-DEFINE_IINSPECTABLE_OUTER( async_info, IAsyncInfo, struct async_info, IInspectable_outer ) +- +-static HRESULT WINAPI async_info_get_Id( IAsyncInfo *iface, UINT32 *id ) ++/* operation should be an IAsyncOperation, while handler should be an IAsyncOperationCompletedHandler. */ ++static HRESULT async_operation_put_Completed( struct async_operation_base *base, IInspectable *operation, ++ IInspectable *handler, async_completed_invoke_callback cb ) + { +- struct async_info *impl = impl_from_IAsyncInfo( iface ); +- HRESULT hr = S_OK; +- +- TRACE( "iface %p, id %p.\n", iface, id ); +- +- EnterCriticalSection( &impl->cs ); +- if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; +- *id = 1; +- LeaveCriticalSection( &impl->cs ); ++ IAsyncActionCompletedHandler *wrapper; ++ HRESULT hr; + ++ hr = async_completed_create( (IInspectable *)operation, (IInspectable *)handler, cb, &wrapper ); ++ if (FAILED( hr )) ++ return hr; ++ hr = IAsyncAction_put_Completed( base->inner_action, wrapper ); ++ IAsyncActionCompletedHandler_Release( wrapper ); + return hr; + } + +-static HRESULT WINAPI async_info_get_Status( IAsyncInfo *iface, AsyncStatus *status ) ++static HRESULT async_operation_get_Completed( struct async_operation_base *base, REFIID iid, void **handler ) + { +- struct async_info *impl = impl_from_IAsyncInfo( iface ); +- HRESULT hr = S_OK; +- +- TRACE( "iface %p, status %p.\n", iface, status ); ++ IAsyncActionCompletedHandler *wrapper; ++ HRESULT hr; + +- EnterCriticalSection( &impl->cs ); +- if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; +- *status = impl->status; +- LeaveCriticalSection( &impl->cs ); ++ *handler = NULL; ++ hr = IAsyncAction_get_Completed( base->inner_action, &wrapper ); ++ if (FAILED( hr ) || !wrapper) ++ return hr; + ++ hr = IAsyncActionCompletedHandler_QueryInterface( wrapper, iid, (void **)handler ); ++ IAsyncActionCompletedHandler_Release( wrapper ); + return hr; + } + +-static HRESULT WINAPI async_info_get_ErrorCode( IAsyncInfo *iface, HRESULT *error_code ) ++struct work_item + { +- struct async_info *impl = impl_from_IAsyncInfo( iface ); +- HRESULT hr = S_OK; +- +- TRACE( "iface %p, error_code %p.\n", iface, error_code ); ++ IWorkItemHandler IWorkItemHandler_iface; ++ async_operation_callback callback; ++ PROPVARIANT result; + +- EnterCriticalSection( &impl->cs ); +- if (impl->status == Closed) *error_code = hr = E_ILLEGAL_METHOD_CALL; +- else *error_code = impl->hr; +- LeaveCriticalSection( &impl->cs ); ++ IUnknown *invoker; ++ IUnknown *param; ++ LONG ref; ++}; + +- return hr; ++static inline struct work_item *impl_from_IWorkItemHandler( IWorkItemHandler *iface ) ++{ ++ return CONTAINING_RECORD( iface, struct work_item, IWorkItemHandler_iface ); + } + +-static HRESULT WINAPI async_info_Cancel( IAsyncInfo *iface ) ++static HRESULT WINAPI work_item_QueryInterface( IWorkItemHandler *iface, REFIID iid, void **out ) + { +- struct async_info *impl = impl_from_IAsyncInfo( iface ); +- HRESULT hr = S_OK; +- +- TRACE( "iface %p.\n", iface ); ++ TRACE( "iface %p, iid %s, out %p.\n", iface, debugstr_guid( iid ), out ); + +- EnterCriticalSection( &impl->cs ); +- if (impl->status == Closed) hr = E_ILLEGAL_METHOD_CALL; +- else if (impl->status == Started) impl->status = Canceled; +- LeaveCriticalSection( &impl->cs ); ++ if (IsEqualGUID( iid, &IID_IUnknown ) || ++ IsEqualGUID( iid, &IID_IInspectable ) || ++ IsEqualGUID( iid, &IID_IWorkItemHandler )) ++ { ++ *out = iface; ++ IUnknown_AddRef( (IUnknown *)*out ); ++ return S_OK; ++ } + +- return hr; ++ *out = NULL; ++ FIXME( "%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid( iid ) ); ++ return E_NOINTERFACE; + } + +-static HRESULT WINAPI async_info_Close( IAsyncInfo *iface ) ++static ULONG WINAPI work_item_AddRef( IWorkItemHandler *iface ) + { +- struct async_info *impl = impl_from_IAsyncInfo( iface ); +- HRESULT hr = S_OK; ++ struct work_item *impl = impl_from_IWorkItemHandler( iface ); ++ ULONG ref = InterlockedIncrement( &impl->ref ); ++ TRACE( "iface %p, ref %lu.\n", iface, ref ); ++ return ref; ++} + +- TRACE( "iface %p.\n", iface ); ++static ULONG WINAPI work_item_Release( IWorkItemHandler *iface ) ++{ ++ struct work_item *impl = impl_from_IWorkItemHandler( iface ); ++ ULONG ref = InterlockedDecrement( &impl->ref ); ++ TRACE( "iface %p, ref %lu.\n", iface, ref ); + +- EnterCriticalSection( &impl->cs ); +- if (impl->status == Started) +- hr = E_ILLEGAL_STATE_CHANGE; +- else if (impl->status != Closed) ++ if (!ref) + { +- CloseThreadpoolWork( impl->async_run_work ); +- impl->async_run_work = NULL; +- impl->status = Closed; ++ if (impl->invoker) ++ IUnknown_Release( impl->invoker ); ++ if (impl->param) ++ IUnknown_Release( impl->param ); ++ free( impl ); + } +- LeaveCriticalSection( &impl->cs ); +- +- return hr; ++ return ref; + } + +-static const struct IAsyncInfoVtbl async_info_vtbl = ++static HRESULT WINAPI work_item_Invoke( IWorkItemHandler *iface, IAsyncAction *action ) + { +- /* IUnknown methods */ +- async_info_QueryInterface, +- async_info_AddRef, +- async_info_Release, +- /* IInspectable methods */ +- async_info_GetIids, +- async_info_GetRuntimeClassName, +- async_info_GetTrustLevel, +- /* IAsyncInfo */ +- async_info_get_Id, +- async_info_get_Status, +- async_info_get_ErrorCode, +- async_info_Cancel, +- async_info_Close, +-}; +- +-static void CALLBACK async_info_callback( TP_CALLBACK_INSTANCE *instance, void *iface, TP_WORK *work ) +-{ +- struct async_info *impl = impl_from_IWineAsyncInfoImpl( iface ); +- IInspectable *operation = impl->IInspectable_outer; +- PROPVARIANT result; ++ struct work_item *impl = impl_from_IWorkItemHandler( iface ); ++ IAsyncInfo *info; ++ AsyncStatus status; + HRESULT hr; + +- hr = impl->callback( impl->invoker, impl->param, &result ); ++ TRACE( "iface %p, action %p.\n", iface, action ); + +- EnterCriticalSection( &impl->cs ); +- if (impl->status != Closed) impl->status = FAILED(hr) ? Error : Completed; +- PropVariantCopy( &impl->result, &result ); +- impl->hr = hr; +- +- if (impl->handler != NULL && impl->handler != HANDLER_NOT_SET) +- { +- IWineAsyncOperationCompletedHandler *handler = impl->handler; +- AsyncStatus status = impl->status; +- impl->handler = NULL; /* Prevent concurrent invoke. */ +- LeaveCriticalSection( &impl->cs ); +- +- IWineAsyncOperationCompletedHandler_Invoke( handler, operation, status ); +- IWineAsyncOperationCompletedHandler_Release( handler ); +- } +- else LeaveCriticalSection( &impl->cs ); ++ hr = IAsyncAction_QueryInterface( action, &IID_IAsyncInfo, (void **)&info ); ++ if (FAILED( hr )) ++ return hr; + +- /* release refcount acquired in Start */ +- IInspectable_Release( operation ); ++ hr = IAsyncInfo_get_Status( info, &status ); ++ IAsyncInfo_Release( info ); ++ if (FAILED( hr )) ++ return hr; + +- PropVariantClear( &result ); ++ return status != Canceled ? impl->callback( impl->invoker, impl->param, &impl->result ) : S_OK; + } + +-static HRESULT async_info_create( IUnknown *invoker, IUnknown *param, async_operation_callback callback, +- IInspectable *outer, IWineAsyncInfoImpl **out ) ++static const IWorkItemHandlerVtbl work_item_vtbl = + { +- struct async_info *impl; +- HRESULT hr; +- +- if (!(impl = calloc( 1, sizeof(struct async_info) ))) return E_OUTOFMEMORY; +- impl->IWineAsyncInfoImpl_iface.lpVtbl = &async_impl_vtbl; +- impl->IAsyncInfo_iface.lpVtbl = &async_info_vtbl; +- impl->IInspectable_outer = outer; +- impl->ref = 1; ++ work_item_QueryInterface, ++ work_item_AddRef, ++ work_item_Release, ++ work_item_Invoke, ++}; + +- impl->callback = callback; +- impl->handler = HANDLER_NOT_SET; +- impl->status = Started; +- if (!(impl->async_run_work = CreateThreadpoolWork( async_info_callback, &impl->IWineAsyncInfoImpl_iface, NULL ))) +- { +- hr = HRESULT_FROM_WIN32( GetLastError() ); +- free( impl ); +- return hr; +- } ++static HRESULT work_item_create( IUnknown *invoker, IUnknown *param, async_operation_callback callback, ++ PROPVARIANT **result, IWorkItemHandler **handler ) ++{ ++ struct work_item *impl; + +- if ((impl->invoker = invoker)) IUnknown_AddRef( impl->invoker ); +- if ((impl->param = param)) IUnknown_AddRef( impl->param ); ++ impl = calloc( 1, sizeof( *impl ) ); ++ if (!impl) ++ return E_OUTOFMEMORY; + +- InitializeCriticalSectionEx( &impl->cs, 0, RTL_CRITICAL_SECTION_FLAG_FORCE_DEBUG_INFO ); +- impl->cs.DebugInfo->Spare[0] = (DWORD_PTR)( __FILE__ ": async_info.cs" ); ++ impl->IWorkItemHandler_iface.lpVtbl = &work_item_vtbl; ++ impl->callback = callback; ++ impl->invoker = invoker; ++ impl->param = param; ++ if (invoker) ++ IUnknown_AddRef(invoker); ++ if (param) ++ IUnknown_AddRef(param); ++ impl->ref = 1; + +- *out = &impl->IWineAsyncInfoImpl_iface; ++ *result = &impl->result; ++ *handler = &impl->IWorkItemHandler_iface; + return S_OK; + } + + struct async_bool + { + IAsyncOperation_boolean IAsyncOperation_boolean_iface; +- IWineAsyncInfoImpl *IWineAsyncInfoImpl_inner; +- LONG ref; ++ ++ struct async_operation_base base; + }; + + static inline struct async_bool *impl_from_IAsyncOperation_boolean( IAsyncOperation_boolean *iface ) +@@ -389,13 +305,13 @@ static HRESULT WINAPI async_bool_QueryInterface( IAsyncOperation_boolean *iface, + return S_OK; + } + +- return IWineAsyncInfoImpl_QueryInterface( impl->IWineAsyncInfoImpl_inner, iid, out ); ++ return IAsyncAction_QueryInterface( impl->base.inner_action, iid, out ); + } + + static ULONG WINAPI async_bool_AddRef( IAsyncOperation_boolean *iface ) + { + struct async_bool *impl = impl_from_IAsyncOperation_boolean( iface ); +- ULONG ref = InterlockedIncrement( &impl->ref ); ++ ULONG ref = InterlockedIncrement( &impl->base.ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + return ref; + } +@@ -403,14 +319,13 @@ static ULONG WINAPI async_bool_AddRef( IAsyncOperation_boolean *iface ) + static ULONG WINAPI async_bool_Release( IAsyncOperation_boolean *iface ) + { + struct async_bool *impl = impl_from_IAsyncOperation_boolean( iface ); +- ULONG ref = InterlockedDecrement( &impl->ref ); ++ ULONG ref = InterlockedDecrement( &impl->base.ref ); + TRACE( "iface %p, ref %lu.\n", iface, ref ); + + if (!ref) + { +- /* guard against re-entry if inner releases an outer iface */ +- InterlockedIncrement( &impl->ref ); +- IWineAsyncInfoImpl_Release( impl->IWineAsyncInfoImpl_inner ); ++ IWorkItemHandler_Release(impl->base.work_item); ++ IAsyncAction_Release( impl->base.inner_action ); + free( impl ); + } + +@@ -436,34 +351,41 @@ static HRESULT WINAPI async_bool_GetTrustLevel( IAsyncOperation_boolean *iface, + return E_NOTIMPL; + } + ++DEFINE_ASYNC_COMPLETED_HANDLER_CALLBACK( boolean ); ++ + static HRESULT WINAPI async_bool_put_Completed( IAsyncOperation_boolean *iface, IAsyncOperationCompletedHandler_boolean *bool_handler ) + { +- IWineAsyncOperationCompletedHandler *handler = (IWineAsyncOperationCompletedHandler *)bool_handler; + struct async_bool *impl = impl_from_IAsyncOperation_boolean( iface ); +- TRACE( "iface %p, handler %p.\n", iface, handler ); +- return IWineAsyncInfoImpl_put_Completed( impl->IWineAsyncInfoImpl_inner, (IWineAsyncOperationCompletedHandler *)handler ); ++ ++ TRACE( "iface %p, handler %p.\n", iface, bool_handler ); ++ ++ return async_operation_put_Completed( &impl->base, (IInspectable *)iface, (IInspectable *)bool_handler, ++ async_completed_handler_cb_boolean ); + } + + static HRESULT WINAPI async_bool_get_Completed( IAsyncOperation_boolean *iface, IAsyncOperationCompletedHandler_boolean **bool_handler ) + { +- IWineAsyncOperationCompletedHandler **handler = (IWineAsyncOperationCompletedHandler **)bool_handler; + struct async_bool *impl = impl_from_IAsyncOperation_boolean( iface ); +- TRACE( "iface %p, handler %p.\n", iface, handler ); +- return IWineAsyncInfoImpl_get_Completed( impl->IWineAsyncInfoImpl_inner, (IWineAsyncOperationCompletedHandler **)handler ); ++ ++ TRACE( "iface %p, handler %p.\n", iface, bool_handler ); ++ ++ return async_operation_get_Completed( &impl->base, &IID_IAsyncOperationCompletedHandler_boolean, (void **)bool_handler ); + } + + static HRESULT WINAPI async_bool_GetResults( IAsyncOperation_boolean *iface, BOOLEAN *results ) + { + struct async_bool *impl = impl_from_IAsyncOperation_boolean( iface ); +- PROPVARIANT result = {.vt = VT_BOOL}; + HRESULT hr; + + TRACE( "iface %p, results %p.\n", iface, results ); + +- hr = IWineAsyncInfoImpl_get_Result( impl->IWineAsyncInfoImpl_inner, &result ); ++ hr = IAsyncAction_GetResults( impl->base.inner_action ); ++ if (hr == S_OK) ++ { ++ *results = impl->base.result->boolVal; ++ PropVariantClear( impl->base.result ); ++ } + +- *results = result.boolVal; +- PropVariantClear( &result ); + return hr; + } + +@@ -483,6 +405,24 @@ static const struct IAsyncOperation_booleanVtbl async_bool_vtbl = + async_bool_GetResults, + }; + ++static IThreadPoolStatics *threadpool_statics; ++static INIT_ONCE threadpool_statics_init = INIT_ONCE_STATIC_INIT; ++ ++static BOOL CALLBACK init_threadpool_statics( INIT_ONCE *once, void *param, void **ctx ) ++{ ++ HSTRING str; ++ HRESULT hr; ++ ++ hr = WindowsCreateString( RuntimeClass_Windows_System_Threading_ThreadPool, ++ wcslen( RuntimeClass_Windows_System_Threading_ThreadPool ), &str ); ++ if (FAILED( hr )) ++ return FALSE; ++ ++ hr = RoGetActivationFactory( str, &IID_IThreadPoolStatics, (void **)&threadpool_statics ); ++ WindowsDeleteString( str ); ++ return SUCCEEDED( hr ); ++} ++ + HRESULT async_operation_boolean_create( IUnknown *invoker, IUnknown *param, async_operation_callback callback, + IAsyncOperation_boolean **out ) + { +@@ -490,18 +430,27 @@ HRESULT async_operation_boolean_create( IUnknown *invoker, IUnknown *param, asyn + HRESULT hr; + + *out = NULL; ++ if (!InitOnceExecuteOnce( &threadpool_statics_init, init_threadpool_statics, NULL, NULL )) ++ return E_FAIL; ++ + if (!(impl = calloc( 1, sizeof(*impl) ))) return E_OUTOFMEMORY; + impl->IAsyncOperation_boolean_iface.lpVtbl = &async_bool_vtbl; +- impl->ref = 1; + +- if (FAILED(hr = async_info_create( invoker, param, callback, (IInspectable *)&impl->IAsyncOperation_boolean_iface, &impl->IWineAsyncInfoImpl_inner )) || +- FAILED(hr = IWineAsyncInfoImpl_Start( impl->IWineAsyncInfoImpl_inner ))) ++ hr = work_item_create( invoker, param, callback, &impl->base.result, &impl->base.work_item ); ++ if (FAILED( hr )) + { +- if (impl->IWineAsyncInfoImpl_inner) IWineAsyncInfoImpl_Release( impl->IWineAsyncInfoImpl_inner ); + free( impl ); + return hr; + } ++ impl->base.ref = 1; + ++ hr = IThreadPoolStatics_RunAsync( threadpool_statics, impl->base.work_item, &impl->base.inner_action ); ++ if (FAILED( hr )) ++ { ++ IWorkItemHandler_Release( impl->base.work_item ); ++ free( impl ); ++ return hr; ++ } + *out = &impl->IAsyncOperation_boolean_iface; + TRACE( "created IAsyncOperation_boolean %p\n", *out ); + return S_OK; +diff --git a/dlls/cryptowinrt/private.h b/dlls/cryptowinrt/private.h +index 3ce3620118c..8a4595eb9ae 100644 +--- a/dlls/cryptowinrt/private.h ++++ b/dlls/cryptowinrt/private.h +@@ -37,7 +37,8 @@ + #define WIDL_using_Windows_Security_Credentials + #include "windows.security.credentials.h" + +-#include "provider.h" ++#define WIDL_using_Windows_System_Threading ++#include "windows.system.threading.h" + + extern IActivationFactory *credentials_activation_factory; + +diff --git a/dlls/cryptowinrt/provider.idl b/dlls/cryptowinrt/provider.idl +deleted file mode 100644 +index 7196119dba0..00000000000 +--- a/dlls/cryptowinrt/provider.idl ++++ /dev/null +@@ -1,47 +0,0 @@ +-/* +- * Copyright 2022 Mohamad Al-Jaf +- * Copyright 2022 Rémi Bernon for CodeWeavers +- * +- * This library is free software; you can redistribute it and/or +- * modify it under the terms of the GNU Lesser General Public +- * License as published by the Free Software Foundation; either +- * version 2.1 of the License, or (at your option) any later version. +- * +- * This library is distributed in the hope that it will be useful, +- * but WITHOUT ANY WARRANTY; without even the implied warranty of +- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +- * Lesser General Public License for more details. +- * +- * You should have received a copy of the GNU Lesser General Public +- * License along with this library; if not, write to the Free Software +- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA +- */ +- +-#pragma makedep header +- +-#ifdef __WIDL__ +-#pragma winrt ns_prefix +-#endif +- +-import "propidl.idl"; +-import "inspectable.idl"; +-import "asyncinfo.idl"; +-import "eventtoken.idl"; +-import "windowscontracts.idl"; +-import "windows.foundation.idl"; +- +-namespace Windows.Security.Credentials { +- /* type-pruning version of AsyncOperationCompletedHandler */ +- delegate HRESULT WineAsyncOperationCompletedHandler([in] IInspectable *async, [in] AsyncStatus status); +- +- [ +- uuid(83f377ee-c799-11ec-9d64-0242ac120002) +- ] +- interface IWineAsyncInfoImpl : IUnknown +- { +- [propput] HRESULT Completed([in] WineAsyncOperationCompletedHandler *handler); +- [propget] HRESULT Completed([out, retval] WineAsyncOperationCompletedHandler **handler); +- [propget] HRESULT Result([out, retval] PROPVARIANT *result); +- HRESULT Start(); +- } +-} +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/7064-Draft-ntdll-Check-for-invalid-GS-base-in-the-64-bit-segv-handler/0001-ntdll-Check-for-invalid-gs-value-in-32-bit-code-on-WoW64.patch b/0003-pending-mrs-and-backports/7064-ntdll-Check-for-invalid-GS-base-in-the-64-bit-segv-handler/0001-ntdll-Check-for-invalid-GS-base-in-the-64-bit-segv-handler-on-WoW64.patch similarity index 73% rename from 0003-pending-mrs-and-backports/7064-Draft-ntdll-Check-for-invalid-GS-base-in-the-64-bit-segv-handler/0001-ntdll-Check-for-invalid-gs-value-in-32-bit-code-on-WoW64.patch rename to 0003-pending-mrs-and-backports/7064-ntdll-Check-for-invalid-GS-base-in-the-64-bit-segv-handler/0001-ntdll-Check-for-invalid-GS-base-in-the-64-bit-segv-handler-on-WoW64.patch index 3b79d56..a01467e 100644 --- a/0003-pending-mrs-and-backports/7064-Draft-ntdll-Check-for-invalid-GS-base-in-the-64-bit-segv-handler/0001-ntdll-Check-for-invalid-gs-value-in-32-bit-code-on-WoW64.patch +++ b/0003-pending-mrs-and-backports/7064-ntdll-Check-for-invalid-GS-base-in-the-64-bit-segv-handler/0001-ntdll-Check-for-invalid-GS-base-in-the-64-bit-segv-handler-on-WoW64.patch @@ -1,30 +1,27 @@ -From c1b0461f3fdd6281742e7c8880b8ac85ccf6cd0b Mon Sep 17 00:00:00 2001 +From bfbe01336d02f9b0a56b4aab9017a7cec50e8366 Mon Sep 17 00:00:00 2001 From: William Horvath Date: Sun, 22 Dec 2024 04:22:32 -0800 -Subject: [PATCH] ntdll: Check for invalid %gs value in 32-bit code on WoW64. +Subject: [PATCH] ntdll: Check for invalid GS base in the 64-bit segv_handler + on WoW64. -Adapted from check_invalid_gs in signal_i386.c. This prevents -crashing when the %gs register is manipulated. An example of this -can be seen in the game "Exertus: Darkness Approaches", which crashes -in 32-bit code when using "new-style" WoW64. +Adapted from check_invalid_gs in signal_i386.c. PE-side code can +manipulate %gs and cause wine_syscall_dispatcher to immediately fault, +as the syscall_frame is relative to it. Catch this early, and fix up +up the thread's GS base register with one that matches NtCurrentTeb(). -The SYSCALL_HAVE_WRFSGSBASE fast-path for getting/setting the segment -registers on Linux is already checked in signal_init_process, and -the other platforms' implementations follow existing conventions. - -Also note that we check in the TRAP_x86_PAGEFLT case because -the error occurs when the invalid %gs value is actually used. +Alice: Madness Returns (2011) is one example of game that does this, +among a few others currently known. Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57444 --- - dlls/ntdll/unix/signal_x86_64.c | 108 ++++++++++++++++++++++++++++++++ - 1 file changed, 108 insertions(+) + dlls/ntdll/unix/signal_x86_64.c | 101 ++++++++++++++++++++++++++++++++ + 1 file changed, 101 insertions(+) diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c -index caa85249896..5a39e4a0fa6 100644 +index caa85249896..fa2e1f8ba8e 100644 --- a/dlls/ntdll/unix/signal_x86_64.c +++ b/dlls/ntdll/unix/signal_x86_64.c -@@ -1967,6 +1967,109 @@ static BOOL handle_syscall_trap( ucontext_t *sigcontext, siginfo_t *siginfo ) +@@ -1967,6 +1967,102 @@ static BOOL handle_syscall_trap( ucontext_t *sigcontext, siginfo_t *siginfo ) } @@ -32,19 +29,13 @@ index caa85249896..5a39e4a0fa6 100644 + * check_invalid_gsbase + * + * Check for fault caused by invalid %gs value (some copy protection schemes mess with it). -+ * + */ +static inline BOOL check_invalid_gsbase( ucontext_t *sigcontext, CONTEXT *context ) +{ + unsigned int prefix_count = 0; + const BYTE *instr = (const BYTE *)context->Rip; ++ TEB *teb = NtCurrentTeb(); + ULONG_PTR cur_gsbase = 0; -+ TEB *teb; -+ -+ if (CS_sig(sigcontext) != cs64_sel) return FALSE; -+ /* FIXME: breaks on linux 64-bit code and macOS 32- or 64-bit code -+ if (virtual_is_valid_code_address( instr, 1 )) return FALSE; -+ */ + +#ifdef __linux__ + if (syscall_flags & SYSCALL_HAVE_WRFSGSBASE) @@ -56,12 +47,11 @@ index caa85249896..5a39e4a0fa6 100644 +#elif defined(__NetBSD__) + sysarch( X86_64_GET_GSBASE, &cur_gsbase ); +#elif defined(__APPLE__) -+ /* FIXME */ ++ cur_gsbase = (ULONG_PTR)teb->ThreadLocalStoragePointer; +#else +# error Please define getting %gs for your architecture +#endif + -+ teb = NtCurrentTeb(); + if (cur_gsbase == (ULONG_PTR)teb) return FALSE; + + for (;;) @@ -107,7 +97,7 @@ index caa85249896..5a39e4a0fa6 100644 + break; /* %gs: */ + } + -+ TRACE( "%016lx/%p at %p, fixing up\n", cur_gsbase, teb, instr ); ++ TRACE( "gsbase %016lx teb %p at instr %p, fixing up\n", cur_gsbase, teb, instr ); + +#ifdef __linux__ + if (syscall_flags & SYSCALL_HAVE_WRFSGSBASE) @@ -134,11 +124,11 @@ index caa85249896..5a39e4a0fa6 100644 /********************************************************************** * segv_handler * -@@ -2025,6 +2128,11 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) +@@ -2025,6 +2121,11 @@ static void segv_handler( int signal, siginfo_t *siginfo, void *sigcontext ) /* send EXCEPTION_EXECUTE_FAULT only if data execution prevention is enabled */ if (!(flags & MEM_EXECUTE_OPTION_DISABLE)) rec.ExceptionInformation[0] = EXCEPTION_READ_FAULT; } -+ if (check_invalid_gsbase( ucontext, &context.c )) ++ if (is_wow64() && CS_sig(ucontext) == cs64_sel && check_invalid_gsbase( ucontext, &context.c )) + { + leave_handler( ucontext ); + return; diff --git a/0003-pending-mrs-and-backports/7072-win32u-Check-window-state-updates-again-after-applying-new-state/0001-winex11-Improve-GetWindowStateUpdates-traces.patch b/0003-pending-mrs-and-backports/7072-win32u-Check-window-state-updates-again-after-applying-new-state/0001-winex11-Improve-GetWindowStateUpdates-traces.patch deleted file mode 100644 index c9c6345..0000000 --- a/0003-pending-mrs-and-backports/7072-win32u-Check-window-state-updates-again-after-applying-new-state/0001-winex11-Improve-GetWindowStateUpdates-traces.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 1550256217df46166321ded756f3043655dbd639 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 24 Dec 2024 12:58:40 +0100 -Subject: [PATCH] winex11: Improve GetWindowStateUpdates traces. - ---- - dlls/winex11.drv/window.c | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index bf415f19cb9..1d43c4edbdb 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -1622,8 +1622,6 @@ BOOL X11DRV_GetWindowStateUpdates( HWND hwnd, UINT *state_cmd, UINT *config_cmd, - { - struct x11drv_win_data *data; - -- TRACE( "hwnd %p, state_cmd %p, config_cmd %p, rect %p\n", hwnd, state_cmd, config_cmd, rect ); -- - if (!(data = get_win_data( hwnd ))) return FALSE; - - *state_cmd = window_update_client_state( data ); -@@ -1632,7 +1630,7 @@ BOOL X11DRV_GetWindowStateUpdates( HWND hwnd, UINT *state_cmd, UINT *config_cmd, - - release_win_data( data ); - -- TRACE( "returning state_cmd %#x, config_cmd %#x, rect %s\n", *state_cmd, *config_cmd, wine_dbgstr_rect(rect) ); -+ TRACE( "hwnd %p, returning state_cmd %#x, config_cmd %#x, rect %s\n", hwnd, *state_cmd, *config_cmd, wine_dbgstr_rect(rect) ); - return *state_cmd || *config_cmd; - } - --- -GitLab - diff --git a/0003-pending-mrs-and-backports/7072-win32u-Check-window-state-updates-again-after-applying-new-state/0002-win32u-Check-window-state-updates-again-after-applying-new-state.patch b/0003-pending-mrs-and-backports/7072-win32u-Check-window-state-updates-again-after-applying-new-state/0002-win32u-Check-window-state-updates-again-after-applying-new-state.patch deleted file mode 100644 index 67ce4ef..0000000 --- a/0003-pending-mrs-and-backports/7072-win32u-Check-window-state-updates-again-after-applying-new-state/0002-win32u-Check-window-state-updates-again-after-applying-new-state.patch +++ /dev/null @@ -1,37 +0,0 @@ -From 38e78439da525d1cd51e6c94aa424eb2c87c45ff Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Tue, 24 Dec 2024 12:58:54 +0100 -Subject: [PATCH] win32u: Check window state updates again after applying new - state. - -The state change might have applied the new config already, or might -have triggered some new requests which would override the new config. - -It's also necessary to call again to compute the visible rect from the -window rect after taking the new state into account. Minimized windows -have a different window / visible rect offset than normal windows for -instance. - -Wine-Bug: https://bugs.winehq.org/show_bug.cgi?id=57577 ---- - dlls/win32u/message.c | 4 ++++ - 1 file changed, 4 insertions(+) - -diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c -index d8da5a0f48f..2f1e14c82c8 100644 ---- a/dlls/win32u/message.c -+++ b/dlls/win32u/message.c -@@ -2136,6 +2136,10 @@ static LRESULT handle_internal_message( HWND hwnd, UINT msg, WPARAM wparam, LPAR - { - if (LOWORD(state_cmd) == SC_RESTORE && HIWORD(state_cmd)) NtUserSetActiveWindow( hwnd ); - send_message( hwnd, WM_SYSCOMMAND, LOWORD(state_cmd), 0 ); -+ -+ /* state change might have changed the window config already, check again */ -+ user_driver->pGetWindowStateUpdates( hwnd, &state_cmd, &config_cmd, &window_rect ); -+ if (state_cmd) WARN( "window %p state needs another update, ignoring\n", hwnd ); - } - if (config_cmd) - { --- -GitLab - diff --git a/0003-pending-mrs-and-backports/7091-windowscodecs-Make-values-returned-from-CanConvert-consistent/0001-windowscodecs-Make-values-returned-from-CanConvert-consistent.patch b/0003-pending-mrs-and-backports/7091-windowscodecs-Make-values-returned-from-CanConvert-consistent/0001-windowscodecs-Make-values-returned-from-CanConvert-consistent.patch new file mode 100644 index 0000000..e0692c9 --- /dev/null +++ b/0003-pending-mrs-and-backports/7091-windowscodecs-Make-values-returned-from-CanConvert-consistent/0001-windowscodecs-Make-values-returned-from-CanConvert-consistent.patch @@ -0,0 +1,288 @@ +From fd00152502bd9e30ef56e9aa95202bc0c8d3e371 Mon Sep 17 00:00:00 2001 +From: Jeff Smith +Date: Tue, 31 Dec 2024 21:22:53 -0600 +Subject: [PATCH] windowscodecs: Make values returned from CanConvert + consistent + +Any time CanConvert returns FALSE for the output parameter, +also return an appropriate failing result code. + +This also adds tests for CanConvert. +--- + dlls/windowscodecs/converter.c | 40 +++++-- + dlls/windowscodecs/tests/converter.c | 167 ++++++++++++++++++++++++++- + 2 files changed, 199 insertions(+), 8 deletions(-) + +diff --git a/dlls/windowscodecs/converter.c b/dlls/windowscodecs/converter.c +index 39fcce61dd8..b5e253c98ea 100644 +--- a/dlls/windowscodecs/converter.c ++++ b/dlls/windowscodecs/converter.c +@@ -59,6 +59,18 @@ enum pixelformat { + format_48bppRGB, + format_64bppRGBA, + format_32bppCMYK, ++ format_8bppAlpha, ++ format_48bppBGR, ++ format_64bppRGB, ++ format_64bppBGRA, ++ format_64bppPRGBA, ++ format_64bppPBGRA, ++ format_32bppBGR101010, ++ format_96bppRGBFloat, ++ format_128bppRGBAFloat, ++ format_128bppPRGBAFloat, ++ format_128bppRGBFloat, ++ format_32bppR10G10B10A2, + }; + + typedef HRESULT (*copyfunc)(struct FormatConverter *This, const WICRect *prc, +@@ -1640,6 +1652,18 @@ static const struct pixelformatinfo supported_formats[] = { + {format_48bppRGB, &GUID_WICPixelFormat48bppRGB, NULL}, + {format_64bppRGBA, &GUID_WICPixelFormat64bppRGBA, copypixels_to_64bppRGBA}, + {format_32bppCMYK, &GUID_WICPixelFormat32bppCMYK, NULL}, ++ {format_8bppAlpha, &GUID_WICPixelFormat8bppAlpha, NULL}, ++ {format_48bppBGR, &GUID_WICPixelFormat48bppBGR, NULL}, ++ {format_64bppRGB, &GUID_WICPixelFormat64bppRGB, NULL}, ++ {format_64bppBGRA, &GUID_WICPixelFormat64bppBGRA, NULL}, ++ {format_64bppPRGBA, &GUID_WICPixelFormat64bppPRGBA, NULL}, ++ {format_64bppPBGRA, &GUID_WICPixelFormat64bppPBGRA, NULL}, ++ {format_32bppBGR101010, &GUID_WICPixelFormat32bppBGR101010, NULL}, ++ {format_96bppRGBFloat, &GUID_WICPixelFormat96bppRGBFloat, NULL}, ++ {format_128bppRGBAFloat, &GUID_WICPixelFormat128bppRGBAFloat, NULL}, ++ {format_128bppPRGBAFloat, &GUID_WICPixelFormat128bppPRGBAFloat, NULL}, ++ {format_128bppRGBFloat, &GUID_WICPixelFormat128bppRGBFloat, NULL}, ++ {format_32bppR10G10B10A2, &GUID_WICPixelFormat32bppR10G10B10A2, NULL}, + {0} + }; + +@@ -1914,26 +1938,28 @@ static HRESULT WINAPI FormatConverter_CanConvert(IWICFormatConverter *iface, + srcinfo = get_formatinfo(srcPixelFormat); + if (!srcinfo) + { +- FIXME("Unsupported source format %s\n", debugstr_guid(srcPixelFormat)); ++ *pfCanConvert = FALSE; + return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; + } + + dstinfo = get_formatinfo(dstPixelFormat); + if (!dstinfo) + { +- FIXME("Unsupported destination format %s\n", debugstr_guid(dstPixelFormat)); ++ *pfCanConvert = FALSE; + return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; + } + +- if (dstinfo->copy_function && +- SUCCEEDED(dstinfo->copy_function(This, NULL, 0, 0, NULL, dstinfo->format))) +- *pfCanConvert = TRUE; +- else ++ if (!dstinfo->copy_function || ++ FAILED(dstinfo->copy_function(This, NULL, 0, 0, NULL, srcinfo->format))) + { +- FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(srcPixelFormat), debugstr_guid(dstPixelFormat)); ++ if (dstinfo->format != format_32bppR10G10B10A2 && ++ srcinfo->format != format_32bppCMYK && dstinfo->format != format_32bppCMYK) ++ FIXME("Unsupported conversion %s -> %s\n", debugstr_guid(srcPixelFormat), debugstr_guid(dstPixelFormat)); + *pfCanConvert = FALSE; ++ return WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; + } + ++ *pfCanConvert = TRUE; + return S_OK; + } + +diff --git a/dlls/windowscodecs/tests/converter.c b/dlls/windowscodecs/tests/converter.c +index f6cef841d56..82bfee47161 100644 +--- a/dlls/windowscodecs/tests/converter.c ++++ b/dlls/windowscodecs/tests/converter.c +@@ -707,6 +707,170 @@ static void test_default_converter(void) + DeleteTestBitmap(src_obj); + } + ++static void test_can_convert(void) ++{ ++#define WIC_PIXEL_FORMAT(fmt) #fmt, &GUID_WICPixelFormat ## fmt ++ static const struct test_data ++ { ++ const char *name; ++ const WICPixelFormatGUID *format; ++ BOOL src_valid; ++ BOOL dst_valid; ++ BOOL src_todo; ++ BOOL dst_todo; ++ BOOL src_broken; ++ } ++ td[] = ++ { ++ {WIC_PIXEL_FORMAT(Undefined)}, ++ {WIC_PIXEL_FORMAT(1bppIndexed), TRUE, TRUE, FALSE, TRUE}, ++ {WIC_PIXEL_FORMAT(2bppIndexed), TRUE, TRUE, FALSE, TRUE}, ++ {WIC_PIXEL_FORMAT(4bppIndexed), TRUE, TRUE, FALSE, TRUE}, ++ {WIC_PIXEL_FORMAT(8bppIndexed), TRUE, TRUE}, ++ {WIC_PIXEL_FORMAT(BlackWhite), TRUE, TRUE, FALSE, TRUE}, ++ {WIC_PIXEL_FORMAT(2bppGray), TRUE, TRUE, FALSE, TRUE}, ++ {WIC_PIXEL_FORMAT(4bppGray), TRUE, TRUE, FALSE, TRUE}, ++ {WIC_PIXEL_FORMAT(8bppGray), TRUE, TRUE}, ++ {WIC_PIXEL_FORMAT(16bppGray), TRUE, TRUE, FALSE, TRUE}, ++ ++ {WIC_PIXEL_FORMAT(8bppAlpha), TRUE, TRUE, TRUE, TRUE}, ++ ++ {WIC_PIXEL_FORMAT(16bppBGR555), TRUE, TRUE, FALSE, TRUE}, ++ {WIC_PIXEL_FORMAT(16bppBGR565), TRUE, TRUE, FALSE, TRUE}, ++ {WIC_PIXEL_FORMAT(16bppBGRA5551), TRUE, TRUE}, ++ {WIC_PIXEL_FORMAT(24bppBGR), TRUE, TRUE}, ++ {WIC_PIXEL_FORMAT(24bppRGB), TRUE, TRUE}, ++ {WIC_PIXEL_FORMAT(32bppBGR), TRUE, TRUE}, ++ {WIC_PIXEL_FORMAT(32bppBGRA), TRUE, TRUE}, ++ {WIC_PIXEL_FORMAT(32bppPBGRA), TRUE, TRUE}, ++ {WIC_PIXEL_FORMAT(32bppRGB), TRUE, TRUE}, ++ {WIC_PIXEL_FORMAT(32bppRGBA), TRUE, TRUE}, ++ {WIC_PIXEL_FORMAT(32bppPRGBA), TRUE, TRUE}, ++ {WIC_PIXEL_FORMAT(32bppGrayFloat), TRUE, TRUE}, ++ ++ {WIC_PIXEL_FORMAT(48bppRGB), TRUE, TRUE, FALSE, TRUE}, ++ {WIC_PIXEL_FORMAT(48bppBGR), TRUE, TRUE, TRUE, TRUE}, ++ {WIC_PIXEL_FORMAT(64bppRGB), TRUE, TRUE, TRUE, TRUE}, ++ {WIC_PIXEL_FORMAT(64bppRGBA), TRUE, TRUE}, ++ {WIC_PIXEL_FORMAT(64bppBGRA), TRUE, TRUE, TRUE, TRUE}, ++ {WIC_PIXEL_FORMAT(64bppPRGBA), TRUE, TRUE, TRUE, TRUE}, ++ {WIC_PIXEL_FORMAT(64bppPBGRA), TRUE, TRUE, TRUE, TRUE}, ++ ++ {WIC_PIXEL_FORMAT(16bppGrayFixedPoint)}, ++ {WIC_PIXEL_FORMAT(32bppBGR101010), TRUE, TRUE, TRUE, TRUE}, ++ {WIC_PIXEL_FORMAT(48bppRGBFixedPoint)}, ++ {WIC_PIXEL_FORMAT(48bppBGRFixedPoint)}, ++ {WIC_PIXEL_FORMAT(96bppRGBFixedPoint)}, ++ {WIC_PIXEL_FORMAT(96bppRGBFloat), TRUE, TRUE, TRUE, TRUE}, ++ {WIC_PIXEL_FORMAT(128bppRGBAFloat), TRUE, TRUE, TRUE, TRUE}, ++ {WIC_PIXEL_FORMAT(128bppPRGBAFloat), TRUE, TRUE, TRUE, TRUE}, ++ {WIC_PIXEL_FORMAT(128bppRGBFloat), TRUE, TRUE, TRUE, TRUE}, ++ ++ /* Not actually TODO, but it succeeds where Windows fails */ ++ {WIC_PIXEL_FORMAT(32bppCMYK), FALSE, FALSE, TRUE}, ++ ++ {WIC_PIXEL_FORMAT(64bppRGBAFixedPoint)}, ++ {WIC_PIXEL_FORMAT(64bppBGRAFixedPoint)}, ++ {WIC_PIXEL_FORMAT(64bppRGBFixedPoint)}, ++ {WIC_PIXEL_FORMAT(128bppRGBAFixedPoint)}, ++ {WIC_PIXEL_FORMAT(128bppRGBFixedPoint)}, ++ ++ {WIC_PIXEL_FORMAT(64bppRGBAHalf)}, ++ {WIC_PIXEL_FORMAT(64bppPRGBAHalf)}, ++ {WIC_PIXEL_FORMAT(64bppRGBHalf)}, ++ {WIC_PIXEL_FORMAT(48bppRGBHalf)}, ++ ++ {WIC_PIXEL_FORMAT(32bppRGBE)}, ++ ++ {WIC_PIXEL_FORMAT(16bppGrayHalf)}, ++ {WIC_PIXEL_FORMAT(32bppGrayFixedPoint)}, ++ ++ {WIC_PIXEL_FORMAT(32bppRGBA1010102)}, ++ {WIC_PIXEL_FORMAT(32bppRGBA1010102XR)}, ++ ++ /* Starting with Windows 10 v1809, this works as a source format */ ++ {WIC_PIXEL_FORMAT(32bppR10G10B10A2), TRUE, FALSE, TRUE, FALSE, TRUE}, ++ ++ {WIC_PIXEL_FORMAT(32bppR10G10B10A2HDR10)}, ++ ++ {WIC_PIXEL_FORMAT(64bppCMYK)}, ++ ++ {WIC_PIXEL_FORMAT(24bpp3Channels)}, ++ {WIC_PIXEL_FORMAT(32bpp4Channels)}, ++ {WIC_PIXEL_FORMAT(40bpp5Channels)}, ++ {WIC_PIXEL_FORMAT(48bpp6Channels)}, ++ {WIC_PIXEL_FORMAT(56bpp7Channels)}, ++ {WIC_PIXEL_FORMAT(64bpp8Channels)}, ++ ++ {WIC_PIXEL_FORMAT(48bpp3Channels)}, ++ {WIC_PIXEL_FORMAT(64bpp4Channels)}, ++ {WIC_PIXEL_FORMAT(80bpp5Channels)}, ++ {WIC_PIXEL_FORMAT(96bpp6Channels)}, ++ {WIC_PIXEL_FORMAT(112bpp7Channels)}, ++ {WIC_PIXEL_FORMAT(128bpp8Channels)}, ++ ++ {WIC_PIXEL_FORMAT(40bppCMYKAlpha)}, ++ {WIC_PIXEL_FORMAT(80bppCMYKAlpha)}, ++ ++ {WIC_PIXEL_FORMAT(32bpp3ChannelsAlpha)}, ++ {WIC_PIXEL_FORMAT(40bpp4ChannelsAlpha)}, ++ {WIC_PIXEL_FORMAT(48bpp5ChannelsAlpha)}, ++ {WIC_PIXEL_FORMAT(56bpp6ChannelsAlpha)}, ++ {WIC_PIXEL_FORMAT(64bpp7ChannelsAlpha)}, ++ {WIC_PIXEL_FORMAT(72bpp8ChannelsAlpha)}, ++ ++ {WIC_PIXEL_FORMAT(64bpp3ChannelsAlpha)}, ++ {WIC_PIXEL_FORMAT(80bpp4ChannelsAlpha)}, ++ {WIC_PIXEL_FORMAT(96bpp5ChannelsAlpha)}, ++ {WIC_PIXEL_FORMAT(112bpp6ChannelsAlpha)}, ++ {WIC_PIXEL_FORMAT(128bpp7ChannelsAlpha)}, ++ {WIC_PIXEL_FORMAT(144bpp8ChannelsAlpha)}, ++ ++ {WIC_PIXEL_FORMAT(8bppY)}, ++ {WIC_PIXEL_FORMAT(8bppCb)}, ++ {WIC_PIXEL_FORMAT(8bppCr)}, ++ {WIC_PIXEL_FORMAT(16bppCbCr)}, ++ ++ {WIC_PIXEL_FORMAT(16bppYQuantizedDctCoefficients)}, ++ {WIC_PIXEL_FORMAT(16bppCbQuantizedDctCoefficients)}, ++ {WIC_PIXEL_FORMAT(16bppCrQuantizedDctCoefficients)}, ++ }; ++#undef WIC_PIXEL_FORMAT ++ BOOL can_convert, can_native, can_broken, can_wine; ++ HRESULT hr, expect_hr, broken_hr; ++ IWICFormatConverter *converter; ++ UINT i, j; ++ ++ hr = CoCreateInstance(&CLSID_WICDefaultFormatConverter, NULL, CLSCTX_INPROC_SERVER, ++ &IID_IWICFormatConverter, (void**)&converter); ++ ok(SUCCEEDED(hr), "CoCreateInstance failed, hr=%lx\n", hr); ++ if (FAILED(hr)) ++ return; ++ ++ for (i = 0; i < ARRAY_SIZE(td); i++) ++ { ++ for (j = 0; j < ARRAY_SIZE(td); j++) ++ { ++ can_native = td[i].src_valid && td[j].dst_valid; ++ can_broken = (td[i].src_valid ^ td[i].src_broken) && td[j].dst_valid; ++ can_wine = (td[i].src_valid ^ td[i].src_todo) && (td[j].dst_valid ^ td[j].dst_todo); ++ expect_hr = can_native ? S_OK : WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; ++ broken_hr = can_broken ? S_OK : WINCODEC_ERR_UNSUPPORTEDPIXELFORMAT; ++ ++ can_convert = -1; ++ hr = IWICFormatConverter_CanConvert(converter, td[i].format, td[j].format, &can_convert); ++ todo_wine_if (can_native != can_wine) { ++ ok(hr == expect_hr || broken(hr == broken_hr), ++ "CanConvert (%s -> %s) returned %lx\n", td[i].name, td[j].name, hr); ++ ok(can_convert == can_native || broken(can_convert == can_broken), ++ "expected %i, got %i \n", can_native, can_convert); ++ } ++ } ++ } ++ ++ IWICFormatConverter_Release(converter); ++} ++ + static void test_converter_4bppGray(void) + { + BitmapTestSrc *src_obj; +@@ -723,7 +887,7 @@ static void test_converter_4bppGray(void) + { + hr = IWICFormatConverter_CanConvert(converter, &GUID_WICPixelFormat32bppBGRA, + &GUID_WICPixelFormat4bppGray, &can_convert); +- ok(SUCCEEDED(hr), "CanConvert returned %lx\n", hr); ++ todo_wine ok(SUCCEEDED(hr), "CanConvert returned %lx\n", hr); + todo_wine ok(can_convert, "expected TRUE, got %i\n", can_convert); + + hr = IWICFormatConverter_Initialize(converter, &src_obj->IWICBitmapSource_iface, +@@ -2088,6 +2252,7 @@ START_TEST(converter) + + test_invalid_conversion(); + test_default_converter(); ++ test_can_convert(); + test_converter_4bppGray(); + test_converter_8bppGray(); + test_converter_8bppIndexed(); +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/7099-windowscodecs-Simplify-png-decoder-get-metadata-blocks-using-realloc/0001-windowscodecs-Simplify-png-decoder-get-metadata-blocks-using-realloc.patch b/0003-pending-mrs-and-backports/7099-windowscodecs-Simplify-png-decoder-get-metadata-blocks-using-realloc/0001-windowscodecs-Simplify-png-decoder-get-metadata-blocks-using-realloc.patch new file mode 100644 index 0000000..b968b3d --- /dev/null +++ b/0003-pending-mrs-and-backports/7099-windowscodecs-Simplify-png-decoder-get-metadata-blocks-using-realloc/0001-windowscodecs-Simplify-png-decoder-get-metadata-blocks-using-realloc.patch @@ -0,0 +1,67 @@ +From f1f7397552feb30acaf138f460e768ec3b7998e0 Mon Sep 17 00:00:00 2001 +From: Jeff Smith +Date: Wed, 9 Aug 2023 21:45:44 -0500 +Subject: [PATCH] windowscodecs: Simplify png_decoder_get_metadata_blocks using + realloc. + +--- + dlls/windowscodecs/libpng.c | 19 +++++++------------ + 1 file changed, 7 insertions(+), 12 deletions(-) + +diff --git a/dlls/windowscodecs/libpng.c b/dlls/windowscodecs/libpng.c +index 137a8e15e33..2c660b83e72 100644 +--- a/dlls/windowscodecs/libpng.c ++++ b/dlls/windowscodecs/libpng.c +@@ -377,10 +377,12 @@ static HRESULT CDECL png_decoder_get_metadata_blocks(struct decoder* iface, + do + { + hr = stream_seek(This->stream, seek, STREAM_SEEK_SET, &chunk_start); +- if (FAILED(hr)) goto end; ++ if (FAILED(hr)) ++ break; + + hr = read_png_chunk(This->stream, chunk_type, NULL, &chunk_size); +- if (FAILED(hr)) goto end; ++ if (FAILED(hr)) ++ break; + + if (chunk_type[0] >= 'a' && chunk_type[0] <= 'z' && + memcmp(chunk_type, "tRNS", 4) && memcmp(chunk_type, "pHYs", 4)) +@@ -389,23 +391,17 @@ static HRESULT CDECL png_decoder_get_metadata_blocks(struct decoder* iface, + if (*count == metadata_blocks_size) + { + struct decoder_block *new_metadata_blocks; +- ULONG new_metadata_blocks_size; + +- new_metadata_blocks_size = 4 + metadata_blocks_size * 2; +- new_metadata_blocks = malloc(new_metadata_blocks_size * sizeof(*new_metadata_blocks)); ++ metadata_blocks_size = 4 + metadata_blocks_size * 2; ++ new_metadata_blocks = realloc(result, metadata_blocks_size * sizeof(*new_metadata_blocks)); + + if (!new_metadata_blocks) + { + hr = E_OUTOFMEMORY; +- goto end; ++ break; + } + +- memcpy(new_metadata_blocks, result, +- *count * sizeof(*new_metadata_blocks)); +- +- free(result); + result = new_metadata_blocks; +- metadata_blocks_size = new_metadata_blocks_size; + } + + result[*count].offset = chunk_start; +@@ -417,7 +413,6 @@ static HRESULT CDECL png_decoder_get_metadata_blocks(struct decoder* iface, + seek = chunk_start + chunk_size + 12; /* skip data and CRC */ + } while (memcmp(chunk_type, "IEND", 4)); + +-end: + if (SUCCEEDED(hr)) + { + *blocks = result; +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/7112-crypt32-cryptnet-OCSP-revocation-check-improvements/0001-crypt32-Use-correct-tag-for-OCSP-basic-response-extensions.patch b/0003-pending-mrs-and-backports/7112-crypt32-cryptnet-OCSP-revocation-check-improvements/0001-crypt32-Use-correct-tag-for-OCSP-basic-response-extensions.patch new file mode 100644 index 0000000..3f7967e --- /dev/null +++ b/0003-pending-mrs-and-backports/7112-crypt32-cryptnet-OCSP-revocation-check-improvements/0001-crypt32-Use-correct-tag-for-OCSP-basic-response-extensions.patch @@ -0,0 +1,64 @@ +From 76fc1c734223f65d7415d75beda6e9ef4b5c6fbe Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Tue, 7 Jan 2025 16:56:55 -0600 +Subject: [PATCH] crypt32: Use correct tag for OCSP basic response extensions. + +--- + dlls/crypt32/decode.c | 2 +- + dlls/crypt32/tests/encode.c | 14 ++++++++++++++ + 2 files changed, 15 insertions(+), 1 deletion(-) + +diff --git a/dlls/crypt32/decode.c b/dlls/crypt32/decode.c +index cfdeef5380a..44877a6e9d6 100644 +--- a/dlls/crypt32/decode.c ++++ b/dlls/crypt32/decode.c +@@ -6722,7 +6722,7 @@ static BOOL WINAPI CRYPT_AsnDecodeOCSPBasicResponse(DWORD dwCertEncodingType, + { ASN_SEQUENCEOF, offsetof(OCSP_BASIC_RESPONSE_INFO, cResponseEntry), + CRYPT_AsnDecodeOCSPBasicResponseEntriesArray, MEMBERSIZE(OCSP_BASIC_RESPONSE_INFO, cResponseEntry, cExtension), + TRUE, TRUE, offsetof(OCSP_BASIC_RESPONSE_INFO, rgResponseEntry) }, +- { ASN_CONTEXT | ASN_CONSTRUCTOR, offsetof(OCSP_BASIC_RESPONSE_INFO, cExtension), ++ { ASN_CONTEXT | ASN_CONSTRUCTOR | 1, offsetof(OCSP_BASIC_RESPONSE_INFO, cExtension), + CRYPT_AsnDecodeCertExtensions, FINALMEMBERSIZE(OCSP_BASIC_RESPONSE_INFO, cExtension), + TRUE, TRUE, offsetof(OCSP_BASIC_RESPONSE_INFO, rgExtension), 0 }, + }; +diff --git a/dlls/crypt32/tests/encode.c b/dlls/crypt32/tests/encode.c +index b5db9cf7d0d..c6c461999e6 100644 +--- a/dlls/crypt32/tests/encode.c ++++ b/dlls/crypt32/tests/encode.c +@@ -8847,6 +8847,7 @@ static const BYTE ocsp_basic_signed_response_with_cert[] = + static void test_decodeOCSPBasicSignedResponseInfo(DWORD dwEncoding) + { + OCSP_BASIC_SIGNED_RESPONSE_INFO *info; ++ OCSP_BASIC_RESPONSE_INFO *b; + DWORD size; + BOOL ret; + +@@ -8875,12 +8876,25 @@ static void test_decodeOCSPBasicSignedResponseInfo(DWORD dwEncoding) + + ok(!info->SignatureInfo.cCertEncoded, "got %lu\n", info->SignatureInfo.cCertEncoded); + ok(!info->SignatureInfo.rgCertEncoded, "got %p\n", info->SignatureInfo.rgCertEncoded); ++ ++ ++ ret = CryptDecodeObjectEx(dwEncoding, OCSP_BASIC_RESPONSE, info->ToBeSigned.pbData, info->ToBeSigned.cbData, ++ CRYPT_DECODE_ALLOC_FLAG, NULL, &b, &size); ++ ok(ret, "got %08lx\n", GetLastError()); ++ ok(!b->cExtension, "got %lu.\n", b->cExtension); ++ LocalFree(b); + LocalFree(info); + + size = 0; + ret = CryptDecodeObjectEx(dwEncoding, OCSP_BASIC_SIGNED_RESPONSE, ocsp_basic_signed_response_with_cert, + sizeof(ocsp_basic_signed_response_with_cert), CRYPT_DECODE_ALLOC_FLAG, NULL, &info, &size); + ok(ret, "got %08lx\n", GetLastError()); ++ ++ ret = CryptDecodeObjectEx(dwEncoding, OCSP_BASIC_RESPONSE, info->ToBeSigned.pbData, info->ToBeSigned.cbData, ++ CRYPT_DECODE_ALLOC_FLAG, NULL, &b, &size); ++ ok(ret, "got %08lx\n", GetLastError()); ++ ok(b->cExtension == 1, "got %lu.\n", b->cExtension); ++ LocalFree(b); + LocalFree(info); + } + +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/7112-crypt32-cryptnet-OCSP-revocation-check-improvements/0002-crypt32-Use-correct-tag-for-OCSP-single-response-extensions.patch b/0003-pending-mrs-and-backports/7112-crypt32-cryptnet-OCSP-revocation-check-improvements/0002-crypt32-Use-correct-tag-for-OCSP-single-response-extensions.patch new file mode 100644 index 0000000..56d7bd8 --- /dev/null +++ b/0003-pending-mrs-and-backports/7112-crypt32-cryptnet-OCSP-revocation-check-improvements/0002-crypt32-Use-correct-tag-for-OCSP-single-response-extensions.patch @@ -0,0 +1,25 @@ +From 2016e7afd1d1f4bc20cd735fa475d8576c239495 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Tue, 7 Jan 2025 15:54:00 -0600 +Subject: [PATCH] crypt32: Use correct tag for OCSP single response extensions. + +--- + dlls/crypt32/decode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/dlls/crypt32/decode.c b/dlls/crypt32/decode.c +index 44877a6e9d6..2deacc1cb15 100644 +--- a/dlls/crypt32/decode.c ++++ b/dlls/crypt32/decode.c +@@ -6507,7 +6507,7 @@ static BOOL CRYPT_AsnDecodeOCSPBasicResponseEntry(const BYTE *pbEncoded, DWORD c + { ASN_CONTEXT | ASN_CONSTRUCTOR, offsetof(OCSP_BASIC_RESPONSE_ENTRY, NextUpdate), + CRYPT_AsnDecodeOCSPNextUpdate, sizeof(FILETIME), TRUE, FALSE, + 0, 0 }, +- { ASN_CONTEXT | ASN_CONSTRUCTOR /* FIXME */, offsetof(OCSP_BASIC_RESPONSE_ENTRY, cExtension), ++ { ASN_CONTEXT | ASN_CONSTRUCTOR | 1 /* FIXME */, offsetof(OCSP_BASIC_RESPONSE_ENTRY, cExtension), + CRYPT_AsnDecodeCertExtensions, FINALMEMBERSIZE(OCSP_BASIC_RESPONSE_ENTRY, cExtension), + TRUE, TRUE, offsetof(OCSP_BASIC_RESPONSE_ENTRY, rgExtension), 0 }, + }; +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/7112-crypt32-cryptnet-OCSP-revocation-check-improvements/0003-cryptnet-Retry-OCSP-request-with-POST-if-GET-failed.patch b/0003-pending-mrs-and-backports/7112-crypt32-cryptnet-OCSP-revocation-check-improvements/0003-cryptnet-Retry-OCSP-request-with-POST-if-GET-failed.patch new file mode 100644 index 0000000..bf16fb9 --- /dev/null +++ b/0003-pending-mrs-and-backports/7112-crypt32-cryptnet-OCSP-revocation-check-improvements/0003-cryptnet-Retry-OCSP-request-with-POST-if-GET-failed.patch @@ -0,0 +1,143 @@ +From a3ff2a352ad955cd9aea6b8c683fd5fe1b1beb7b Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Tue, 7 Jan 2025 15:58:07 -0600 +Subject: [PATCH] cryptnet: Retry OCSP request with POST if GET failed. + +--- + dlls/cryptnet/cryptnet_main.c | 72 ++++++++++++++++++++++++++--------- + 1 file changed, 53 insertions(+), 19 deletions(-) + +diff --git a/dlls/cryptnet/cryptnet_main.c b/dlls/cryptnet/cryptnet_main.c +index 1068dd26868..ed4add512e6 100644 +--- a/dlls/cryptnet/cryptnet_main.c ++++ b/dlls/cryptnet/cryptnet_main.c +@@ -2028,11 +2028,12 @@ static DWORD handle_ocsp_response(const CERT_INFO *cert, const CERT_INFO *issuer + static DWORD verify_cert_revocation_with_ocsp(const CERT_CONTEXT *cert, const WCHAR *base_url, + const CERT_REVOCATION_PARA *revpara, FILETIME *next_update) + { +- HINTERNET ses, con, req = NULL; ++ HINTERNET ses = NULL, con = NULL, req = NULL; + BYTE *request_data = NULL, *response_data = NULL; +- DWORD size, flags, status, request_len, response_len, count, ret = CRYPT_E_REVOCATION_OFFLINE; ++ DWORD size, status, request_len, response_len, count, ret = CRYPT_E_REVOCATION_OFFLINE; ++ DWORD flags = INTERNET_FLAG_KEEP_CONNECTION; + URL_COMPONENTSW comp; +- WCHAR *url; ++ WCHAR *url = NULL; + + if (!revpara || !revpara->pIssuerCert) + { +@@ -2043,8 +2044,11 @@ static DWORD verify_cert_revocation_with_ocsp(const CERT_CONTEXT *cert, const WC + return CRYPT_E_REVOCATION_OFFLINE; + + url = build_request_url(base_url, request_data, request_len); +- LocalFree(request_data); +- if (!url) return CRYPT_E_REVOCATION_OFFLINE; ++ if (!url) ++ { ++ ret = CRYPT_E_REVOCATION_OFFLINE; ++ goto done; ++ } + + memset(&comp, 0, sizeof(comp)); + comp.dwStructSize = sizeof(comp); +@@ -2052,31 +2056,33 @@ static DWORD verify_cert_revocation_with_ocsp(const CERT_CONTEXT *cert, const WC + comp.dwUrlPathLength = ~0u; + if (!InternetCrackUrlW(url, 0, 0, &comp)) + { +- free(url); +- return CRYPT_E_REVOCATION_OFFLINE; ++ ret = CRYPT_E_REVOCATION_OFFLINE; ++ goto done; + } + + switch (comp.nScheme) + { + case INTERNET_SCHEME_HTTP: +- flags = 0; + break; + case INTERNET_SCHEME_HTTPS: +- flags = INTERNET_FLAG_SECURE; ++ flags |= INTERNET_FLAG_SECURE; + break; + default: + FIXME("scheme %u not supported\n", comp.nScheme); +- free(url); +- return ERROR_NOT_SUPPORTED; ++ ret = ERROR_NOT_SUPPORTED; ++ goto done; + } + +- if (!(ses = InternetOpenW(L"CryptoAPI", 0, NULL, NULL, 0))) return GetLastError(); ++ if (!(ses = InternetOpenW(L"CryptoAPI", 0, NULL, NULL, 0))) ++ { ++ ret = GetLastError(); ++ goto done; ++ } + comp.lpszHostName[comp.dwHostNameLength] = 0; + if (!(con = InternetConnectW(ses, comp.lpszHostName, comp.nPort, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0))) + { +- free(url); +- InternetCloseHandle(ses); +- return GetLastError(); ++ ret = GetLastError(); ++ goto done; + } + comp.lpszHostName[comp.dwHostNameLength] = '/'; + if (!(req = HttpOpenRequestW(con, NULL, comp.lpszUrlPath, NULL, NULL, NULL, flags, 0)) || +@@ -2084,13 +2090,40 @@ static DWORD verify_cert_revocation_with_ocsp(const CERT_CONTEXT *cert, const WC + + size = sizeof(status); + if (!HttpQueryInfoW(req, HTTP_QUERY_STATUS_CODE | HTTP_QUERY_FLAG_NUMBER, &status, &size, NULL)) goto done; +- if (status != HTTP_STATUS_OK) ++ if (status == HTTP_STATUS_OK) + { +- WARN("request status %lu\n", status); +- goto done; ++ size = sizeof(response_len); ++ if (!HttpQueryInfoW(req, HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_CONTENT_LENGTH, &response_len, &size, 0) || ++ !response_len || !(response_data = malloc(response_len)) || ++ !InternetReadFile(req, response_data, response_len, &count) || count != response_len) goto done; ++ ++ ret = handle_ocsp_response(cert->pCertInfo, revpara->pIssuerCert->pCertInfo, response_data, response_len, ++ next_update); + } ++ if (ret == ERROR_SUCCESS || ret == CRYPT_E_REVOKED) goto done; + +- size = sizeof(response_len); ++ WARN("GET OCSP request failed, status %lu, ret %#lx, retrying with POST.\n", status, ret); ++ InternetCloseHandle(req); ++ req = NULL; ++ free(response_data); ++ response_data = NULL; ++ memset(&comp, 0, sizeof(comp)); ++ comp.dwStructSize = sizeof(comp); ++ comp.dwHostNameLength = ~0u; ++ comp.dwUrlPathLength = ~0u; ++ if (!InternetCrackUrlW(base_url, 0, 0, &comp)) ++ { ++ ret = CRYPT_E_REVOCATION_OFFLINE; ++ goto done; ++ } ++ flags &= ~INTERNET_FLAG_KEEP_CONNECTION; ++ if (!(req = HttpOpenRequestW(con, L"POST", comp.lpszUrlPath, NULL, NULL, NULL, flags, 0)) || ++ !HttpSendRequestW(req, L"Content-Type: application/ocsp-request\0", -1, request_data, request_len)) goto done; ++ if (status != HTTP_STATUS_OK) ++ { ++ WARN("request status %lu.\n", status); ++ goto done; ++ } + if (!HttpQueryInfoW(req, HTTP_QUERY_FLAG_NUMBER | HTTP_QUERY_CONTENT_LENGTH, &response_len, &size, 0) || + !response_len || !(response_data = malloc(response_len)) || + !InternetReadFile(req, response_data, response_len, &count) || count != response_len) goto done; +@@ -2099,6 +2132,7 @@ static DWORD verify_cert_revocation_with_ocsp(const CERT_CONTEXT *cert, const WC + next_update); + + done: ++ LocalFree(request_data); + free(url); + free(response_data); + InternetCloseHandle(req); +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/7112-crypt32-cryptnet-OCSP-revocation-check-improvements/0004-cryptnet-Do-not-perform-OCSP-requests-with-CERT-VERIFY-CACHE-ONLY-BASED-REVOCATION-flag.patch b/0003-pending-mrs-and-backports/7112-crypt32-cryptnet-OCSP-revocation-check-improvements/0004-cryptnet-Do-not-perform-OCSP-requests-with-CERT-VERIFY-CACHE-ONLY-BASED-REVOCATION-flag.patch new file mode 100644 index 0000000..bce25e4 --- /dev/null +++ b/0003-pending-mrs-and-backports/7112-crypt32-cryptnet-OCSP-revocation-check-improvements/0004-cryptnet-Do-not-perform-OCSP-requests-with-CERT-VERIFY-CACHE-ONLY-BASED-REVOCATION-flag.patch @@ -0,0 +1,34 @@ +From d72150150c50dd76064a395dfa8f5bf6342f6179 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Mon, 6 Jan 2025 15:28:02 -0600 +Subject: [PATCH] cryptnet: Do not perform OCSP requests with + CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION flag. + +--- + dlls/cryptnet/cryptnet_main.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/dlls/cryptnet/cryptnet_main.c b/dlls/cryptnet/cryptnet_main.c +index ed4add512e6..1200416af58 100644 +--- a/dlls/cryptnet/cryptnet_main.c ++++ b/dlls/cryptnet/cryptnet_main.c +@@ -2161,7 +2161,15 @@ static DWORD verify_cert_revocation_from_aia_ext(const CRYPT_DATA_BLOB *value, c + { + const WCHAR *url = aia->rgAccDescr[i].AccessLocation.pwszURL; + TRACE("OCSP URL = %s\n", debugstr_w(url)); +- error = verify_cert_revocation_with_ocsp(cert, url, pRevPara, next_update); ++ if (dwFlags & CERT_VERIFY_CACHE_ONLY_BASED_REVOCATION) ++ { ++ TRACE("Cache only revocation, returning CRYPT_E_REVOCATION_OFFLINE.\n"); ++ error = CRYPT_E_REVOCATION_OFFLINE; ++ } ++ else ++ { ++ error = verify_cert_revocation_with_ocsp(cert, url, pRevPara, next_update); ++ } + } + else + { +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/7116-winex11-Respect-swp-flags-when-syncing-window-position/0001-winex11-Respect-swp-flags-when-syncing-window-position.patch b/0003-pending-mrs-and-backports/7116-winex11-Respect-swp-flags-when-syncing-window-position/0001-winex11-Respect-swp-flags-when-syncing-window-position.patch new file mode 100644 index 0000000..397a59d --- /dev/null +++ b/0003-pending-mrs-and-backports/7116-winex11-Respect-swp-flags-when-syncing-window-position/0001-winex11-Respect-swp-flags-when-syncing-window-position.patch @@ -0,0 +1,67 @@ +From 480fc3a39a989580c33da00f51c6eddc67cf9c79 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Gabriel=20Iv=C4=83ncescu?= +Date: Wed, 8 Jan 2025 22:52:21 +0200 +Subject: [PATCH] winex11: Respect swp_flags when syncing window position. +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since 895ca2eda64f506b936999cdd8f14e224eef6a7f, we're not telling Win32 +side of the fact the window moved offscreen. This means any SetWindowPos +sent afterwards has potential to resync the Window and "put it on screen +again", even if such operation has SWP_NOMOVE or SWP_NOSIZE. This causes +some fullscreen apps to follow the workspace/desktop instead of remaining +offscreen. + +Fixes a regression introduced by 895ca2eda64f506b936999cdd8f14e224eef6a7f. + +Signed-off-by: Gabriel Ivăncescu +--- + dlls/winex11.drv/window.c | 23 ++++++++++++++++++++++- + 1 file changed, 22 insertions(+), 1 deletion(-) + +diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c +index 1d43c4edbdb..d1518875c23 100644 +--- a/dlls/winex11.drv/window.c ++++ b/dlls/winex11.drv/window.c +@@ -1777,7 +1777,9 @@ static void sync_window_position( struct x11drv_win_data *data, UINT swp_flags ) + { + DWORD style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ); + DWORD ex_style = NtUserGetWindowLongW( data->hwnd, GWL_EXSTYLE ); ++ LONG new_width, new_height; + BOOL above = FALSE; ++ RECT new_rect; + + if (data->managed && data->desired_state.wm_state == IconicState) return; + +@@ -1795,7 +1797,26 @@ static void sync_window_position( struct x11drv_win_data *data, UINT swp_flags ) + set_size_hints( data, style ); + set_mwm_hints( data, style, ex_style ); + update_net_wm_states( data ); +- window_set_config( data, &data->rects.visible, above ); ++ ++ new_rect = data->rects.visible; ++ if (swp_flags & SWP_NOSIZE) ++ { ++ new_width = data->pending_state.rect.right - data->pending_state.rect.left; ++ new_height = data->pending_state.rect.bottom - data->pending_state.rect.top; ++ } ++ else ++ { ++ new_width = new_rect.right - new_rect.left; ++ new_height = new_rect.bottom - new_rect.top; ++ } ++ if (swp_flags & SWP_NOMOVE) ++ { ++ new_rect.left = data->pending_state.rect.left; ++ new_rect.top = data->pending_state.rect.top; ++ } ++ new_rect.right = new_rect.left + new_width; ++ new_rect.bottom = new_rect.top + new_height; ++ window_set_config( data, &new_rect, above ); + } + + +-- +GitLab + diff --git a/0004-build-fix-undebug-optimize/0001-ntdll-Unroll-memcpy-instead-of-preventing-optimisati.patch b/0004-build-fix-undebug-optimize/0001-ntdll-Unroll-memcpy-instead-of-preventing-optimisati.patch new file mode 100644 index 0000000..d7f655c --- /dev/null +++ b/0004-build-fix-undebug-optimize/0001-ntdll-Unroll-memcpy-instead-of-preventing-optimisati.patch @@ -0,0 +1,157 @@ +From 9d81d53f8f3460314c8b26cf800cab0433dd1a94 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Mon, 24 May 2021 19:21:13 +0200 +Subject: [PATCH 1/4] ntdll: Unroll memcpy instead of preventing optimisations. + +--- + dlls/ntdll/string.c | 115 +++++++++++++++++++++++++++++++++----------- + 1 file changed, 87 insertions(+), 28 deletions(-) + +diff --git a/dlls/ntdll/string.c b/dlls/ntdll/string.c +index a48496b65c6..39762015262 100644 +--- a/dlls/ntdll/string.c ++++ b/dlls/ntdll/string.c +@@ -95,53 +95,112 @@ int __cdecl memcmp( const void *ptr1, const void *ptr2, size_t n ) + } + + +-/********************************************************************* +- * memcpy (NTDLL.@) +- * +- * NOTES +- * Behaves like memmove. +- */ +-void * __cdecl memcpy( void *dst, const void *src, size_t n ) ++static FORCEINLINE void memmove_unaligned_24( char *d, const char *s, size_t n ) + { +- volatile unsigned char *d = dst; /* avoid gcc optimizations */ +- const unsigned char *s = src; ++ typedef uint64_t DECLSPEC_ALIGN(1) unaligned_ui64; ++ typedef uint32_t DECLSPEC_ALIGN(1) unaligned_ui32; ++ typedef uint16_t DECLSPEC_ALIGN(1) unaligned_ui16; ++ uint64_t tmp0, tmp1, tmpn; + +- if ((size_t)dst - (size_t)src >= n) ++ if (n >= 16) + { +- while (n--) *d++ = *s++; ++ tmp0 = *(unaligned_ui64 *)s; ++ tmp1 = *(unaligned_ui64 *)(s + 8); ++ tmpn = *(unaligned_ui64 *)(s + n - 8); ++ *(unaligned_ui64 *)d = tmp0; ++ *(unaligned_ui64 *)(d + 8) = tmp1; ++ *(unaligned_ui64 *)(d + n - 8) = tmpn; + } +- else ++ else if (n >= 8) + { +- d += n - 1; +- s += n - 1; +- while (n--) *d-- = *s--; ++ tmp0 = *(unaligned_ui64 *)s; ++ tmpn = *(unaligned_ui64 *)(s + n - 8); ++ *(unaligned_ui64 *)d = tmp0; ++ *(unaligned_ui64 *)(d + n - 8) = tmpn; ++ } ++ else if (n >= 4) ++ { ++ tmp0 = *(unaligned_ui32 *)s; ++ tmpn = *(unaligned_ui32 *)(s + n - 4); ++ *(unaligned_ui32 *)d = tmp0; ++ *(unaligned_ui32 *)(d + n - 4) = tmpn; ++ } ++ else if (n >= 2) ++ { ++ tmp0 = *(unaligned_ui16 *)s; ++ tmpn = *(unaligned_ui16 *)(s + n - 2); ++ *(unaligned_ui16 *)d = tmp0; ++ *(unaligned_ui16 *)(d + n - 2) = tmpn; ++ } ++ else if (n >= 1) ++ { ++ *(uint8_t *)d = *(uint8_t *)s; + } +- return dst; + } + +- +-/********************************************************************* +- * memmove (NTDLL.@) +- */ +-void * __cdecl memmove( void *dst, const void *src, size_t n ) ++static FORCEINLINE void *memmove_unrolled( char *dst, const char *src, size_t n ) + { +- volatile unsigned char *d = dst; /* avoid gcc optimizations */ +- const unsigned char *s = src; ++ typedef uint64_t DECLSPEC_ALIGN(1) unaligned_ui64; ++ uint64_t tmp0, tmp1, tmp2; ++ char *end; + +- if ((size_t)dst - (size_t)src >= n) ++ if (n <= 24) memmove_unaligned_24( dst, src, n ); ++ else if ((size_t)dst - (size_t)src >= n) + { +- while (n--) *d++ = *s++; ++ end = dst + n; src += n; ++ do ++ { ++ tmp0 = *(unaligned_ui64 *)(src - n + 0); ++ tmp1 = *(unaligned_ui64 *)(src - n + 8); ++ tmp2 = *(unaligned_ui64 *)(src - n + 16); ++ *(unaligned_ui64*)(end - n + 0) = tmp0; ++ *(unaligned_ui64*)(end - n + 8) = tmp1; ++ *(unaligned_ui64*)(end - n + 16) = tmp2; ++ n -= 24; ++ } ++ while (n >= 24); ++ memmove_unaligned_24( end - n, src - n, n ); + } + else + { +- d += n - 1; +- s += n - 1; +- while (n--) *d-- = *s--; ++ do ++ { ++ tmp0 = *(unaligned_ui64 *)(src + n - 8); ++ tmp1 = *(unaligned_ui64 *)(src + n - 16); ++ tmp2 = *(unaligned_ui64 *)(src + n - 24); ++ *(unaligned_ui64*)(dst + n - 8) = tmp0; ++ *(unaligned_ui64*)(dst + n - 16) = tmp1; ++ *(unaligned_ui64*)(dst + n - 24) = tmp2; ++ n -= 24; ++ } ++ while (n >= 24); ++ memmove_unaligned_24( dst, src, n ); + } + return dst; + } + + ++/********************************************************************* ++ * memcpy (NTDLL.@) ++ * ++ * NOTES ++ * Behaves like memmove. ++ */ ++void * __cdecl memcpy( void *dst, const void *src, size_t n ) ++{ ++ return memmove_unrolled( dst, src, n ); ++} ++ ++ ++/********************************************************************* ++ * memmove (NTDLL.@) ++ */ ++void * __cdecl memmove( void *dst, const void *src, size_t n ) ++{ ++ return memmove_unrolled( dst, src, n ); ++} ++ ++ + /********************************************************************* + * memcpy_s (MSVCRT.@) + */ +-- +2.45.0 + diff --git a/0004-build-fix-undebug-optimize/0004-WIP-msvcrt-Add-AVX-memcpy-memmove-implementation.patch b/0004-build-fix-undebug-optimize/0004-WIP-msvcrt-Add-AVX-memcpy-memmove-implementation.patch new file mode 100644 index 0000000..536cc68 --- /dev/null +++ b/0004-build-fix-undebug-optimize/0004-WIP-msvcrt-Add-AVX-memcpy-memmove-implementation.patch @@ -0,0 +1,831 @@ +From 960dd289a9c7c2b71eb3a4f05d648bef1a3a29d0 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Sat, 7 May 2022 00:44:27 +0200 +Subject: [PATCH 4/4] WIP: msvcrt: Add AVX memcpy/memmove implementation. + +--- + dlls/msvcrt/math.c | 24 ++ + dlls/msvcrt/string.c | 715 +++++++++++++++++++++---------------------- + 2 files changed, 377 insertions(+), 362 deletions(-) + +diff --git a/dlls/msvcrt/math.c b/dlls/msvcrt/math.c +index ce6e9ccfb4f..de39baae2f7 100644 +--- a/dlls/msvcrt/math.c ++++ b/dlls/msvcrt/math.c +@@ -51,6 +51,8 @@ + #include "wine/asm.h" + #include "wine/debug.h" + ++#include "msvcrt/intrin.h" ++ + WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); + + #undef div +@@ -67,8 +69,18 @@ static MSVCRT_matherr_func MSVCRT_default_matherr_func = NULL; + + BOOL erms_supported; + BOOL sse2_supported; ++BOOL avx_supported; + static BOOL sse2_enabled; + ++#ifndef __AVX__ ++#ifdef __clang__ ++#pragma clang attribute push (__attribute__((target("avx"))), apply_to=function) ++#else ++#pragma GCC push_options ++#pragma GCC target("avx") ++#endif ++#define __DISABLE_AVX__ ++#endif /* __AVX__ */ + void msvcrt_init_math( void *module ) + { + #if defined(__i386__) || defined(__x86_64__) +@@ -80,6 +92,10 @@ void msvcrt_init_math( void *module ) + __cpuidex(regs, 7, 0); + erms_supported = ((regs[1] >> 9) & 1); + } ++ ++ __cpuid(regs, 1); ++ if (IsProcessorFeaturePresent( PF_XSAVE_ENABLED ) && (regs[2] & (1 << 28))) ++ avx_supported = (_xgetbv(0) & 0x6) == 0x6; + #endif + + sse2_supported = IsProcessorFeaturePresent( PF_XMMI64_INSTRUCTIONS_AVAILABLE ); +@@ -89,6 +105,14 @@ void msvcrt_init_math( void *module ) + sse2_enabled = sse2_supported; + #endif + } ++#ifdef __DISABLE_AVX__ ++#undef __DISABLE_AVX__ ++#ifdef __clang__ ++#pragma clang attribute pop ++#else ++#pragma GCC pop_options ++#endif ++#endif /* __DISABLE_AVX__ */ + + /* Copied from musl: src/internal/libm.h */ + static inline float fp_barrierf(float x) +diff --git a/dlls/msvcrt/string.c b/dlls/msvcrt/string.c +index a4e05bd4e7e..3d18e3c77c9 100644 +--- a/dlls/msvcrt/string.c ++++ b/dlls/msvcrt/string.c +@@ -34,6 +34,8 @@ + #include "wine/asm.h" + #include "wine/debug.h" + ++#include ++ + WINE_DEFAULT_DEBUG_CHANNEL(msvcrt); + + /********************************************************************* +@@ -2785,388 +2787,372 @@ int __cdecl memcmp(const void *ptr1, const void *ptr2, size_t n) + return memcmp_blocks(p1, p2, n); + } + +-#if defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__)) ++extern BOOL sse2_supported; ++extern BOOL avx_supported; ++ ++#define likely(x) __builtin_expect(x, 1) ++#define unlikely(x) __builtin_expect(x, 0) ++ ++#define MEMMOVEV_UNALIGNED_DECLARE(name, type, size, loadu, storeu) \ ++static FORCEINLINE void memmove_ ## name ## _unaligned(char *d, const char *s, size_t n) \ ++{ \ ++ type tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; \ ++ if (unlikely(n > 4 * size)) \ ++ { \ ++ tmp0 = loadu((type *)(s + 0 * size)); \ ++ tmp1 = loadu((type *)(s + 1 * size)); \ ++ tmp2 = loadu((type *)(s + 2 * size)); \ ++ tmp3 = loadu((type *)(s + n - 3 * size)); \ ++ tmp4 = loadu((type *)(s + n - 2 * size)); \ ++ tmp5 = loadu((type *)(s + n - 1 * size)); \ ++ storeu((type *)(d + 0 * size), tmp0); \ ++ storeu((type *)(d + 1 * size), tmp1); \ ++ storeu((type *)(d + 2 * size), tmp2); \ ++ storeu((type *)(d + n - 3 * size), tmp3); \ ++ storeu((type *)(d + n - 2 * size), tmp4); \ ++ storeu((type *)(d + n - 1 * size), tmp5); \ ++ } \ ++ else if (unlikely(n > size * 2)) \ ++ { \ ++ tmp0 = loadu((type *)(s + 0 * size)); \ ++ tmp1 = loadu((type *)(s + 1 * size)); \ ++ tmp2 = loadu((type *)(s + n - 2 * size)); \ ++ tmp3 = loadu((type *)(s + n - 1 * size)); \ ++ storeu((type *)(d + 0 * size), tmp0); \ ++ storeu((type *)(d + 1 * size), tmp1); \ ++ storeu((type *)(d + n - 2 * size), tmp2); \ ++ storeu((type *)(d + n - 1 * size), tmp3); \ ++ } \ ++ else if (unlikely(n > size)) \ ++ { \ ++ tmp0 = loadu((type *)(s + 0 * size)); \ ++ tmp1 = loadu((type *)(s + n - 1 * size)); \ ++ storeu((type *)(d + 0 * size), tmp0); \ ++ storeu((type *)(d + n - 1 * size), tmp1); \ ++ } \ ++ else memmove_c_unaligned_32(d, s, n); \ ++} ++ ++#define MEMMOVEV_DECLARE(name, type, size, loadu, storeu, store) \ ++static void *__cdecl memmove_ ## name(char *d, const char *s, size_t n) \ ++{ \ ++ if (likely(n <= 6 * size)) memmove_ ## name ## _unaligned(d, s, n); \ ++ else if (d <= s) \ ++ { \ ++ type tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; \ ++ size_t k = (size - ((uintptr_t)d & (size - 1))); \ ++ tmp0 = loadu((type *)s); \ ++ tmp1 = loadu((type *)(s + k + 0 * size)); \ ++ tmp2 = loadu((type *)(s + k + 1 * size)); \ ++ tmp3 = loadu((type *)(s + k + 2 * size)); \ ++ tmp4 = loadu((type *)(s + k + 3 * size)); \ ++ tmp5 = loadu((type *)(s + k + 4 * size)); \ ++ storeu((type *)d, tmp0); \ ++ store((type *)(d + k + 0 * size), tmp1); \ ++ store((type *)(d + k + 1 * size), tmp2); \ ++ store((type *)(d + k + 2 * size), tmp3); \ ++ store((type *)(d + k + 3 * size), tmp4); \ ++ store((type *)(d + k + 4 * size), tmp5); \ ++ k += 5 * size; d += k; s += k; n -= k; \ ++ while (unlikely(n >= 12 * size)) \ ++ { \ ++ tmp0 = loadu((type *)(s + 0 * size)); \ ++ tmp1 = loadu((type *)(s + 1 * size)); \ ++ tmp2 = loadu((type *)(s + 2 * size)); \ ++ tmp3 = loadu((type *)(s + 3 * size)); \ ++ tmp4 = loadu((type *)(s + 4 * size)); \ ++ tmp5 = loadu((type *)(s + 5 * size)); \ ++ store((type *)(d + 0 * size), tmp0); \ ++ store((type *)(d + 1 * size), tmp1); \ ++ store((type *)(d + 2 * size), tmp2); \ ++ store((type *)(d + 3 * size), tmp3); \ ++ store((type *)(d + 4 * size), tmp4); \ ++ store((type *)(d + 5 * size), tmp5); \ ++ tmp0 = loadu((type *)(s + 6 * size)); \ ++ tmp1 = loadu((type *)(s + 7 * size)); \ ++ tmp2 = loadu((type *)(s + 8 * size)); \ ++ tmp3 = loadu((type *)(s + 9 * size)); \ ++ tmp4 = loadu((type *)(s + 10 * size)); \ ++ tmp5 = loadu((type *)(s + 11 * size)); \ ++ store((type *)(d + 6 * size), tmp0); \ ++ store((type *)(d + 7 * size), tmp1); \ ++ store((type *)(d + 8 * size), tmp2); \ ++ store((type *)(d + 9 * size), tmp3); \ ++ store((type *)(d + 10 * size), tmp4); \ ++ store((type *)(d + 11 * size), tmp5); \ ++ d += 12 * size; s += 12 * size; n -= 12 * size; k += 12 * size; \ ++ } \ ++ while (unlikely(n >= 6 * size)) \ ++ { \ ++ tmp0 = loadu((type *)(s + 0 * size)); \ ++ tmp1 = loadu((type *)(s + 1 * size)); \ ++ tmp2 = loadu((type *)(s + 2 * size)); \ ++ tmp3 = loadu((type *)(s + 3 * size)); \ ++ tmp4 = loadu((type *)(s + 4 * size)); \ ++ tmp5 = loadu((type *)(s + 5 * size)); \ ++ store((type *)(d + 0 * size), tmp0); \ ++ store((type *)(d + 1 * size), tmp1); \ ++ store((type *)(d + 2 * size), tmp2); \ ++ store((type *)(d + 3 * size), tmp3); \ ++ store((type *)(d + 4 * size), tmp4); \ ++ store((type *)(d + 5 * size), tmp5); \ ++ d += 6 * size; s += 6 * size; n -= 6 * size; k += 6 * size; \ ++ } \ ++ memmove_ ## name ## _unaligned(d, s, n); \ ++ return d - k; \ ++ } \ ++ else \ ++ { \ ++ type tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; \ ++ size_t k = n - ((uintptr_t)(d + n) & (size - 1)); \ ++ tmp0 = loadu((type *)(s + n - 1 * size)); \ ++ tmp1 = loadu((type *)(s + k - 1 * size)); \ ++ tmp2 = loadu((type *)(s + k - 2 * size)); \ ++ tmp3 = loadu((type *)(s + k - 3 * size)); \ ++ tmp4 = loadu((type *)(s + k - 4 * size)); \ ++ tmp5 = loadu((type *)(s + k - 5 * size)); \ ++ storeu((type *)(d + n - 1 * size), tmp0); \ ++ store((type *)(d + k - 1 * size), tmp1); \ ++ store((type *)(d + k - 2 * size), tmp2); \ ++ store((type *)(d + k - 3 * size), tmp3); \ ++ store((type *)(d + k - 4 * size), tmp4); \ ++ store((type *)(d + k - 5 * size), tmp5); \ ++ k -= 5 * size; \ ++ while (unlikely(k >= 12 * size)) \ ++ { \ ++ tmp0 = loadu((type *)(s + k - 1 * size)); \ ++ tmp1 = loadu((type *)(s + k - 2 * size)); \ ++ tmp2 = loadu((type *)(s + k - 3 * size)); \ ++ tmp3 = loadu((type *)(s + k - 4 * size)); \ ++ tmp4 = loadu((type *)(s + k - 5 * size)); \ ++ tmp5 = loadu((type *)(s + k - 6 * size)); \ ++ store((type *)(d + k - 1 * size), tmp0); \ ++ store((type *)(d + k - 2 * size), tmp1); \ ++ store((type *)(d + k - 3 * size), tmp2); \ ++ store((type *)(d + k - 4 * size), tmp3); \ ++ store((type *)(d + k - 5 * size), tmp4); \ ++ store((type *)(d + k - 6 * size), tmp5); \ ++ tmp0 = loadu((type *)(s + k - 7 * size)); \ ++ tmp1 = loadu((type *)(s + k - 8 * size)); \ ++ tmp2 = loadu((type *)(s + k - 9 * size)); \ ++ tmp3 = loadu((type *)(s + k - 10 * size)); \ ++ tmp4 = loadu((type *)(s + k - 11 * size)); \ ++ tmp5 = loadu((type *)(s + k - 12 * size)); \ ++ store((type *)(d + k - 7 * size), tmp0); \ ++ store((type *)(d + k - 8 * size), tmp1); \ ++ store((type *)(d + k - 9 * size), tmp2); \ ++ store((type *)(d + k - 10 * size), tmp3); \ ++ store((type *)(d + k - 11 * size), tmp4); \ ++ store((type *)(d + k - 12 * size), tmp5); \ ++ k -= 12 * size; \ ++ } \ ++ while (unlikely(k >= 6 * size)) \ ++ { \ ++ tmp0 = loadu((type *)(s + k - 1 * size)); \ ++ tmp1 = loadu((type *)(s + k - 2 * size)); \ ++ tmp2 = loadu((type *)(s + k - 3 * size)); \ ++ tmp3 = loadu((type *)(s + k - 4 * size)); \ ++ tmp4 = loadu((type *)(s + k - 5 * size)); \ ++ tmp5 = loadu((type *)(s + k - 6 * size)); \ ++ store((type *)(d + k - 1 * size), tmp0); \ ++ store((type *)(d + k - 2 * size), tmp1); \ ++ store((type *)(d + k - 3 * size), tmp2); \ ++ store((type *)(d + k - 4 * size), tmp3); \ ++ store((type *)(d + k - 5 * size), tmp4); \ ++ store((type *)(d + k - 6 * size), tmp5); \ ++ k -= 6 * size; \ ++ } \ ++ memmove_ ## name ## _unaligned(d, s, k); \ ++ } \ ++ return d; \ ++} ++ ++static FORCEINLINE void __cdecl memmove_c_unaligned_32(char *d, const char *s, size_t n) ++{ ++ uint64_t tmp0, tmp1, tmp2, tmpn; ++ ++ if (unlikely(n >= 24)) ++ { ++ tmp0 = *(uint64_t *)s; ++ tmp1 = *(uint64_t *)(s + 8); ++ tmp2 = *(uint64_t *)(s + 16); ++ tmpn = *(uint64_t *)(s + n - 8); ++ *(uint64_t *)d = tmp0; ++ *(uint64_t *)(d + 8) = tmp1; ++ *(uint64_t *)(d + 16) = tmp2; ++ *(uint64_t *)(d + n - 8) = tmpn; ++ } ++ else if (unlikely(n >= 16)) ++ { ++ tmp0 = *(uint64_t *)s; ++ tmp1 = *(uint64_t *)(s + 8); ++ tmpn = *(uint64_t *)(s + n - 8); ++ *(uint64_t *)d = tmp0; ++ *(uint64_t *)(d + 8) = tmp1; ++ *(uint64_t *)(d + n - 8) = tmpn; ++ } ++ else if (unlikely(n >= 8)) ++ { ++ tmp0 = *(uint64_t *)s; ++ tmpn = *(uint64_t *)(s + n - 8); ++ *(uint64_t *)d = tmp0; ++ *(uint64_t *)(d + n - 8) = tmpn; ++ } ++ else if (unlikely(n >= 4)) ++ { ++ tmp0 = *(uint32_t *)s; ++ tmpn = *(uint32_t *)(s + n - 4); ++ *(uint32_t *)d = tmp0; ++ *(uint32_t *)(d + n - 4) = tmpn; ++ } ++ else if (unlikely(n >= 2)) ++ { ++ tmp0 = *(uint16_t *)s; ++ tmpn = *(uint16_t *)(s + n - 2); ++ *(uint16_t *)d = tmp0; ++ *(uint16_t *)(d + n - 2) = tmpn; ++ } ++ else if (likely(n >= 1)) ++ { ++ *(uint8_t *)d = *(uint8_t *)s; ++ } ++} ++ ++static void *__cdecl memmove_c(char *d, const char *s, size_t n) ++{ ++ if (likely(n <= 32)) memmove_c_unaligned_32(d, s, n); ++ else if (d <= s) ++ { ++ uint64_t tmp0, tmp1, tmp2; ++ size_t k = 0; ++ while (unlikely(n >= 48)) ++ { ++ tmp0 = *(uint64_t *)(s + 0); ++ tmp1 = *(uint64_t *)(s + 8); ++ tmp2 = *(uint64_t *)(s + 16); ++ *(uint64_t*)(d + 0) = tmp0; ++ *(uint64_t*)(d + 8) = tmp1; ++ *(uint64_t*)(d + 16) = tmp2; ++ tmp0 = *(uint64_t *)(s + 24); ++ tmp1 = *(uint64_t *)(s + 32); ++ tmp2 = *(uint64_t *)(s + 40); ++ *(uint64_t*)(d + 24) = tmp0; ++ *(uint64_t*)(d + 32) = tmp1; ++ *(uint64_t*)(d + 40) = tmp2; ++ d += 48; s += 48; n -= 48; k += 48; ++ } ++ while (unlikely(n >= 24)) ++ { ++ tmp0 = *(uint64_t *)(s + 0); ++ tmp1 = *(uint64_t *)(s + 8); ++ tmp2 = *(uint64_t *)(s + 16); ++ *(uint64_t*)(d + 0) = tmp0; ++ *(uint64_t*)(d + 8) = tmp1; ++ *(uint64_t*)(d + 16) = tmp2; ++ d += 24; s += 24; n -= 24; k += 24; ++ } ++ memmove_c_unaligned_32(d, s, n); ++ return d - k; ++ } ++ else ++ { ++ uint64_t tmp0, tmp1, tmp2; ++ size_t k = n; ++ while (unlikely(k >= 48)) ++ { ++ tmp0 = *(uint64_t *)(s + k - 8); ++ tmp1 = *(uint64_t *)(s + k - 16); ++ tmp2 = *(uint64_t *)(s + k - 24); ++ *(uint64_t*)(d + k - 8) = tmp0; ++ *(uint64_t*)(d + k - 16) = tmp1; ++ *(uint64_t*)(d + k - 24) = tmp2; ++ tmp0 = *(uint64_t *)(s + k - 32); ++ tmp1 = *(uint64_t *)(s + k - 40); ++ tmp2 = *(uint64_t *)(s + k - 48); ++ *(uint64_t*)(d + k - 32) = tmp0; ++ *(uint64_t*)(d + k - 40) = tmp1; ++ *(uint64_t*)(d + k - 48) = tmp2; ++ k -= 48; ++ } ++ while (unlikely(k >= 24)) ++ { ++ tmp0 = *(uint64_t *)(s + k - 8); ++ tmp1 = *(uint64_t *)(s + k - 16); ++ tmp2 = *(uint64_t *)(s + k - 24); ++ *(uint64_t*)(d + k - 8) = tmp0; ++ *(uint64_t*)(d + k - 16) = tmp1; ++ *(uint64_t*)(d + k - 24) = tmp2; ++ k -= 24; ++ } ++ memmove_c_unaligned_32(d, s, k); ++ } ++ return d; ++} + +-#ifdef __i386__ ++#ifndef __SSE2__ ++#ifdef __clang__ ++#pragma clang attribute push (__attribute__((target("sse2"))), apply_to=function) ++#else ++#pragma GCC push_options ++#pragma GCC target("sse2") ++#endif ++#define __DISABLE_SSE2__ ++#endif /* __SSE2__ */ + +-#define DEST_REG "%edi" +-#define SRC_REG "%esi" +-#define LEN_REG "%ecx" +-#define TMP_REG "%edx" +- +-#define MEMMOVE_INIT \ +- "pushl " SRC_REG "\n\t" \ +- __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") \ +- "pushl " DEST_REG "\n\t" \ +- __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") \ +- "movl 12(%esp), " DEST_REG "\n\t" \ +- "movl 16(%esp), " SRC_REG "\n\t" \ +- "movl 20(%esp), " LEN_REG "\n\t" +- +-#define MEMMOVE_CLEANUP \ +- "movl 12(%esp), %eax\n\t" \ +- "popl " DEST_REG "\n\t" \ +- __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t") \ +- "popl " SRC_REG "\n\t" \ +- __ASM_CFI(".cfi_adjust_cfa_offset -4\n\t") ++MEMMOVEV_UNALIGNED_DECLARE(sse2, __m128i, 16, _mm_loadu_si128, _mm_storeu_si128) ++MEMMOVEV_DECLARE(sse2, __m128i, 16, _mm_loadu_si128, _mm_storeu_si128, _mm_store_si128) + ++#ifdef __DISABLE_SSE2__ ++#ifdef __clang__ ++#pragma clang attribute pop + #else +- +-#define DEST_REG "%rdi" +-#define SRC_REG "%rsi" +-#define LEN_REG "%r8" +-#define TMP_REG "%r9" +- +-#define MEMMOVE_INIT \ +- "pushq " SRC_REG "\n\t" \ +- __ASM_SEH(".seh_pushreg " SRC_REG "\n\t") \ +- __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t") \ +- "pushq " DEST_REG "\n\t" \ +- __ASM_SEH(".seh_pushreg " DEST_REG "\n\t") \ +- __ASM_SEH(".seh_endprologue\n\t") \ +- __ASM_CFI(".cfi_adjust_cfa_offset 8\n\t") \ +- "movq %rcx, " DEST_REG "\n\t" \ +- "movq %rdx, " SRC_REG "\n\t" +- +-#define MEMMOVE_CLEANUP \ +- "movq %rcx, %rax\n\t" \ +- "popq " DEST_REG "\n\t" \ +- __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t") \ +- "popq " SRC_REG "\n\t" \ +- __ASM_CFI(".cfi_adjust_cfa_offset -8\n\t") ++#pragma GCC pop_options + #endif ++#undef __DISABLE_SSE2__ ++#endif /* __DISABLE_SSE2__ */ + +-void * __cdecl sse2_memmove(void *dst, const void *src, size_t n); +-__ASM_GLOBAL_FUNC( sse2_memmove, +- MEMMOVE_INIT +- "mov " DEST_REG ", " TMP_REG "\n\t" /* check copying direction */ +- "sub " SRC_REG ", " TMP_REG "\n\t" +- "cmp " LEN_REG ", " TMP_REG "\n\t" +- "jb copy_bwd\n\t" +- /* copy forwards */ +- "cmp $4, " LEN_REG "\n\t" /* 4-bytes align */ +- "jb copy_fwd3\n\t" +- "mov " DEST_REG ", " TMP_REG "\n\t" +- "shr $1, " TMP_REG "\n\t" +- "jnc 1f\n\t" +- "movsb\n\t" +- "dec " LEN_REG "\n\t" +- "inc " TMP_REG "\n\t" +- "1:\n\t" +- "shr $1, " TMP_REG "\n\t" +- "jnc 1f\n\t" +- "movsw\n\t" +- "sub $2, " LEN_REG "\n\t" +- "inc " TMP_REG "\n\t" +- "1:\n\t" /* 16-bytes align */ +- "cmp $16, " LEN_REG "\n\t" +- "jb copy_fwd15\n\t" +- "shr $1, " TMP_REG "\n\t" +- "jnc 1f\n\t" +- "movsl\n\t" +- "sub $4, " LEN_REG "\n\t" +- "inc " TMP_REG "\n\t" +- "1:\n\t" +- "shr $1, " TMP_REG "\n\t" +- "jnc 1f\n\t" +- "movsl\n\t" +- "movsl\n\t" +- "sub $8, " LEN_REG "\n\t" +- "1:\n\t" +- "cmp $64, " LEN_REG "\n\t" +- "jb copy_fwd63\n\t" +- "1:\n\t" /* copy 64-bytes blocks in loop, dest 16-bytes aligned */ +- "movdqu 0x00(" SRC_REG "), %xmm0\n\t" +- "movdqu 0x10(" SRC_REG "), %xmm1\n\t" +- "movdqu 0x20(" SRC_REG "), %xmm2\n\t" +- "movdqu 0x30(" SRC_REG "), %xmm3\n\t" +- "movdqa %xmm0, 0x00(" DEST_REG ")\n\t" +- "movdqa %xmm1, 0x10(" DEST_REG ")\n\t" +- "movdqa %xmm2, 0x20(" DEST_REG ")\n\t" +- "movdqa %xmm3, 0x30(" DEST_REG ")\n\t" +- "add $64, " SRC_REG "\n\t" +- "add $64, " DEST_REG "\n\t" +- "sub $64, " LEN_REG "\n\t" +- "cmp $64, " LEN_REG "\n\t" +- "jae 1b\n\t" +- "copy_fwd63:\n\t" /* copy last 63 bytes, dest 16-bytes aligned */ +- "mov " LEN_REG ", " TMP_REG "\n\t" +- "and $15, " LEN_REG "\n\t" +- "shr $5, " TMP_REG "\n\t" +- "jnc 1f\n\t" +- "movdqu 0(" SRC_REG "), %xmm0\n\t" +- "movdqa %xmm0, 0(" DEST_REG ")\n\t" +- "add $16, " SRC_REG "\n\t" +- "add $16, " DEST_REG "\n\t" +- "1:\n\t" +- "shr $1, " TMP_REG "\n\t" +- "jnc copy_fwd15\n\t" +- "movdqu 0x00(" SRC_REG "), %xmm0\n\t" +- "movdqu 0x10(" SRC_REG "), %xmm1\n\t" +- "movdqa %xmm0, 0x00(" DEST_REG ")\n\t" +- "movdqa %xmm1, 0x10(" DEST_REG ")\n\t" +- "add $32, " SRC_REG "\n\t" +- "add $32, " DEST_REG "\n\t" +- "copy_fwd15:\n\t" /* copy last 15 bytes, dest 4-bytes aligned */ +- "mov " LEN_REG ", " TMP_REG "\n\t" +- "and $3, " LEN_REG "\n\t" +- "shr $3, " TMP_REG "\n\t" +- "jnc 1f\n\t" +- "movsl\n\t" +- "1:\n\t" +- "shr $1, " TMP_REG "\n\t" +- "jnc copy_fwd3\n\t" +- "movsl\n\t" +- "movsl\n\t" +- "copy_fwd3:\n\t" /* copy last 3 bytes */ +- "shr $1, " LEN_REG "\n\t" +- "jnc 1f\n\t" +- "movsb\n\t" +- "1:\n\t" +- "shr $1, " LEN_REG "\n\t" +- "jnc 1f\n\t" +- "movsw\n\t" +- "1:\n\t" +- MEMMOVE_CLEANUP +- "ret\n\t" +- "copy_bwd:\n\t" +- "lea (" DEST_REG ", " LEN_REG "), " DEST_REG "\n\t" +- "lea (" SRC_REG ", " LEN_REG "), " SRC_REG "\n\t" +- "cmp $4, " LEN_REG "\n\t" /* 4-bytes align */ +- "jb copy_bwd3\n\t" +- "mov " DEST_REG ", " TMP_REG "\n\t" +- "shr $1, " TMP_REG "\n\t" +- "jnc 1f\n\t" +- "dec " SRC_REG "\n\t" +- "dec " DEST_REG "\n\t" +- "movb (" SRC_REG "), %al\n\t" +- "movb %al, (" DEST_REG ")\n\t" +- "dec " LEN_REG "\n\t" +- "1:\n\t" +- "shr $1, " TMP_REG "\n\t" +- "jnc 1f\n\t" +- "sub $2, " SRC_REG "\n\t" +- "sub $2, " DEST_REG "\n\t" +- "movw (" SRC_REG "), %ax\n\t" +- "movw %ax, (" DEST_REG ")\n\t" +- "sub $2, " LEN_REG "\n\t" +- "1:\n\t" /* 16-bytes align */ +- "cmp $16, " LEN_REG "\n\t" +- "jb copy_bwd15\n\t" +- "shr $1, " TMP_REG "\n\t" +- "jnc 1f\n\t" +- "sub $4, " SRC_REG "\n\t" +- "sub $4, " DEST_REG "\n\t" +- "movl (" SRC_REG "), %eax\n\t" +- "movl %eax, (" DEST_REG ")\n\t" +- "sub $4, " LEN_REG "\n\t" +- "1:\n\t" +- "shr $1, " TMP_REG "\n\t" +- "jnc 1f\n\t" +- "sub $8, " SRC_REG "\n\t" +- "sub $8, " DEST_REG "\n\t" +- "movl 4(" SRC_REG "), %eax\n\t" +- "movl %eax, 4(" DEST_REG ")\n\t" +- "movl (" SRC_REG "), %eax\n\t" +- "movl %eax, (" DEST_REG ")\n\t" +- "sub $8, " LEN_REG "\n\t" +- "1:\n\t" +- "cmp $64, " LEN_REG "\n\t" +- "jb copy_bwd63\n\t" +- "1:\n\t" /* copy 64-bytes blocks in loop, dest 16-bytes aligned */ +- "sub $64, " SRC_REG "\n\t" +- "sub $64, " DEST_REG "\n\t" +- "movdqu 0x00(" SRC_REG "), %xmm0\n\t" +- "movdqu 0x10(" SRC_REG "), %xmm1\n\t" +- "movdqu 0x20(" SRC_REG "), %xmm2\n\t" +- "movdqu 0x30(" SRC_REG "), %xmm3\n\t" +- "movdqa %xmm0, 0x00(" DEST_REG ")\n\t" +- "movdqa %xmm1, 0x10(" DEST_REG ")\n\t" +- "movdqa %xmm2, 0x20(" DEST_REG ")\n\t" +- "movdqa %xmm3, 0x30(" DEST_REG ")\n\t" +- "sub $64, " LEN_REG "\n\t" +- "cmp $64, " LEN_REG "\n\t" +- "jae 1b\n\t" +- "copy_bwd63:\n\t" /* copy last 63 bytes, dest 16-bytes aligned */ +- "mov " LEN_REG ", " TMP_REG "\n\t" +- "and $15, " LEN_REG "\n\t" +- "shr $5, " TMP_REG "\n\t" +- "jnc 1f\n\t" +- "sub $16, " SRC_REG "\n\t" +- "sub $16, " DEST_REG "\n\t" +- "movdqu (" SRC_REG "), %xmm0\n\t" +- "movdqa %xmm0, (" DEST_REG ")\n\t" +- "1:\n\t" +- "shr $1, " TMP_REG "\n\t" +- "jnc copy_bwd15\n\t" +- "sub $32, " SRC_REG "\n\t" +- "sub $32, " DEST_REG "\n\t" +- "movdqu 0x00(" SRC_REG "), %xmm0\n\t" +- "movdqu 0x10(" SRC_REG "), %xmm1\n\t" +- "movdqa %xmm0, 0x00(" DEST_REG ")\n\t" +- "movdqa %xmm1, 0x10(" DEST_REG ")\n\t" +- "copy_bwd15:\n\t" /* copy last 15 bytes, dest 4-bytes aligned */ +- "mov " LEN_REG ", " TMP_REG "\n\t" +- "and $3, " LEN_REG "\n\t" +- "shr $3, " TMP_REG "\n\t" +- "jnc 1f\n\t" +- "sub $4, " SRC_REG "\n\t" +- "sub $4, " DEST_REG "\n\t" +- "movl (" SRC_REG "), %eax\n\t" +- "movl %eax, (" DEST_REG ")\n\t" +- "1:\n\t" +- "shr $1, " TMP_REG "\n\t" +- "jnc copy_bwd3\n\t" +- "sub $8, " SRC_REG "\n\t" +- "sub $8, " DEST_REG "\n\t" +- "movl 4(" SRC_REG "), %eax\n\t" +- "movl %eax, 4(" DEST_REG ")\n\t" +- "movl (" SRC_REG "), %eax\n\t" +- "movl %eax, (" DEST_REG ")\n\t" +- "copy_bwd3:\n\t" /* copy last 3 bytes */ +- "shr $1, " LEN_REG "\n\t" +- "jnc 1f\n\t" +- "dec " SRC_REG "\n\t" +- "dec " DEST_REG "\n\t" +- "movb (" SRC_REG "), %al\n\t" +- "movb %al, (" DEST_REG ")\n\t" +- "1:\n\t" +- "shr $1, " LEN_REG "\n\t" +- "jnc 1f\n\t" +- "movw -2(" SRC_REG "), %ax\n\t" +- "movw %ax, -2(" DEST_REG ")\n\t" +- "1:\n\t" +- MEMMOVE_CLEANUP +- "ret" ) ++#ifndef __AVX__ ++#ifdef __clang__ ++#pragma clang attribute push (__attribute__((target("avx"))), apply_to=function) ++#else ++#pragma GCC push_options ++#pragma GCC target("avx") ++#endif ++#define __DISABLE_AVX__ ++#endif /* __AVX__ */ + +-#undef MEMMOVE_INIT +-#undef MEMMOVE_CLEANUP +-#undef DEST_REG +-#undef SRC_REG +-#undef LEN_REG +-#undef TMP_REG ++MEMMOVEV_UNALIGNED_DECLARE(avx, __m256i, 32, _mm256_loadu_si256, _mm256_storeu_si256) ++MEMMOVEV_DECLARE(avx, __m256i, 32, _mm256_loadu_si256, _mm256_storeu_si256, _mm256_store_si256) + ++#ifdef __DISABLE_AVX__ ++#undef __DISABLE_AVX__ ++#ifdef __clang__ ++#pragma clang attribute pop ++#else ++#pragma GCC pop_options + #endif ++#endif /* __DISABLE_AVX__ */ + + /********************************************************************* + * memmove (MSVCRT.@) + */ +-#ifdef WORDS_BIGENDIAN +-# define MERGE(w1, sh1, w2, sh2) ((w1 << sh1) | (w2 >> sh2)) +-#else +-# define MERGE(w1, sh1, w2, sh2) ((w1 >> sh1) | (w2 << sh2)) +-#endif +-void * __cdecl memmove(void *dst, const void *src, size_t n) ++void *__cdecl memmove(void *dst, const void *src, size_t n) + { +-#if defined(__x86_64__) && !defined(__arm64ec__) +- return sse2_memmove(dst, src, n); +-#else +- unsigned char *d = dst; +- const unsigned char *s = src; +- int sh1; +- +-#ifdef __i386__ +- if (sse2_supported) +- return sse2_memmove(dst, src, n); +-#endif +- +- if (!n) return dst; +- +- if ((size_t)dst - (size_t)src >= n) +- { +- for (; (size_t)d % sizeof(size_t) && n; n--) *d++ = *s++; +- +- sh1 = 8 * ((size_t)s % sizeof(size_t)); +- if (!sh1) +- { +- while (n >= sizeof(size_t)) +- { +- *(size_t*)d = *(size_t*)s; +- s += sizeof(size_t); +- d += sizeof(size_t); +- n -= sizeof(size_t); +- } +- } +- else if (n >= 2 * sizeof(size_t)) +- { +- int sh2 = 8 * sizeof(size_t) - sh1; +- size_t x, y; +- +- s -= sh1 / 8; +- x = *(size_t*)s; +- do +- { +- s += sizeof(size_t); +- y = *(size_t*)s; +- *(size_t*)d = MERGE(x, sh1, y, sh2); +- d += sizeof(size_t); +- +- s += sizeof(size_t); +- x = *(size_t*)s; +- *(size_t*)d = MERGE(y, sh1, x, sh2); +- d += sizeof(size_t); +- +- n -= 2 * sizeof(size_t); +- } while (n >= 2 * sizeof(size_t)); +- s += sh1 / 8; +- } +- while (n--) *d++ = *s++; +- return dst; +- } +- else +- { +- d += n; +- s += n; +- +- for (; (size_t)d % sizeof(size_t) && n; n--) *--d = *--s; +- +- sh1 = 8 * ((size_t)s % sizeof(size_t)); +- if (!sh1) +- { +- while (n >= sizeof(size_t)) +- { +- s -= sizeof(size_t); +- d -= sizeof(size_t); +- *(size_t*)d = *(size_t*)s; +- n -= sizeof(size_t); +- } +- } +- else if (n >= 2 * sizeof(size_t)) +- { +- int sh2 = 8 * sizeof(size_t) - sh1; +- size_t x, y; +- +- s -= sh1 / 8; +- x = *(size_t*)s; +- do +- { +- s -= sizeof(size_t); +- y = *(size_t*)s; +- d -= sizeof(size_t); +- *(size_t*)d = MERGE(y, sh1, x, sh2); +- +- s -= sizeof(size_t); +- x = *(size_t*)s; +- d -= sizeof(size_t); +- *(size_t*)d = MERGE(x, sh1, y, sh2); +- +- n -= 2 * sizeof(size_t); +- } while (n >= 2 * sizeof(size_t)); +- s += sh1 / 8; +- } +- while (n--) *--d = *--s; +- } +- return dst; +-#endif ++ if (unlikely(n < 32)) { memmove_c_unaligned_32(dst, src, n); return dst; } ++ if (likely(avx_supported)) return memmove_avx(dst, src, n); ++ if (likely(sse2_supported)) return memmove_sse2(dst, src, n); ++ return memmove_c(dst, src, n); + } +-#undef MERGE + + /********************************************************************* + * memcpy (MSVCRT.@) + */ +-void * __cdecl memcpy(void *dst, const void *src, size_t n) ++void *__cdecl memcpy(void *dst, const void *src, size_t n) + { +- return memmove(dst, src, n); ++ if (unlikely(n < 32)) { memmove_c_unaligned_32(dst, src, n); return dst; } ++ if (likely(avx_supported)) return memmove_avx(dst, src, n); ++ if (likely(sse2_supported)) return memmove_sse2(dst, src, n); ++ return memmove_c(dst, src, n); + } + + /********************************************************************* +@@ -3343,6 +3329,11 @@ void *__cdecl memset(void *dst, int c, size_t n) + return dst; + } + ++#undef MEMMOVEV_DECLARE ++#undef MEMMOVEV_UNALIGNED_DECLARE ++#undef likely ++#undef unlikely ++ + /********************************************************************* + * strchr (MSVCRT.@) + */ +-- +2.45.0 + diff --git a/0004-build-fix-undebug-optimize/0005-ntdll-Sync-the-more-optimized-string-functions-from-.patch b/0004-build-fix-undebug-optimize/0005-ntdll-Sync-the-more-optimized-string-functions-from-.patch new file mode 100644 index 0000000..71f3492 --- /dev/null +++ b/0004-build-fix-undebug-optimize/0005-ntdll-Sync-the-more-optimized-string-functions-from-.patch @@ -0,0 +1,732 @@ +From a55deb30503f7f9a3ee3cadf2749b8755ec5a541 Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Thu, 2 Jan 2025 11:42:57 -0800 +Subject: [PATCH] ntdll: Sync the more optimized string functions from msvcrt. + +--- + dlls/ntdll/string.c | 630 ++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 551 insertions(+), 79 deletions(-) + +diff --git a/dlls/ntdll/string.c b/dlls/ntdll/string.c +index d334c169332..28f14cc9afe 100644 +--- a/dlls/ntdll/string.c ++++ b/dlls/ntdll/string.c +@@ -32,8 +32,11 @@ + #include "winbase.h" + #include "winnls.h" + #include "winternl.h" ++#include "wine/asm.h" ++#include "ddk/wdm.h" + #include "ntdll_misc.h" + ++#include + + /* same as wctypes except for TAB, which doesn't have C1_BLANK for some reason... */ + static const unsigned short ctypes[257] = +@@ -79,128 +82,500 @@ void * __cdecl memchr( const void *ptr, int c, size_t n ) + } + + +-/********************************************************************* +- * memcmp (NTDLL.@) +- */ +-int __cdecl memcmp( const void *ptr1, const void *ptr2, size_t n ) ++static inline int memcmp_bytes(const void *ptr1, const void *ptr2, size_t n) + { + const unsigned char *p1, *p2; + + for (p1 = ptr1, p2 = ptr2; n; n--, p1++, p2++) + { +- if (*p1 < *p2) return -1; +- if (*p1 > *p2) return 1; ++ if (*p1 != *p2) ++ return *p1 > *p2 ? 1 : -1; + } + return 0; + } + +- +-static FORCEINLINE void memmove_unaligned_24( char *d, const char *s, size_t n ) ++static inline int memcmp_blocks(const void *ptr1, const void *ptr2, size_t size) + { + typedef uint64_t DECLSPEC_ALIGN(1) unaligned_ui64; +- typedef uint32_t DECLSPEC_ALIGN(1) unaligned_ui32; +- typedef uint16_t DECLSPEC_ALIGN(1) unaligned_ui16; +- uint64_t tmp0, tmp1, tmpn; + +- if (n >= 16) ++ const uint64_t *p1 = ptr1; ++ const unaligned_ui64 *p2 = ptr2; ++ size_t remainder = size & (sizeof(uint64_t) - 1); ++ size_t block_count = size / sizeof(uint64_t); ++ ++ while (block_count) ++ { ++ if (*p1 != *p2) ++ return memcmp_bytes(p1, p2, sizeof(uint64_t)); ++ ++ p1++; ++ p2++; ++ block_count--; ++ } ++ ++ return memcmp_bytes(p1, p2, remainder); ++} ++ ++/********************************************************************* ++ * memcmp (NTDLL.@) ++ */ ++int __cdecl memcmp(const void *ptr1, const void *ptr2, size_t n) ++{ ++ const unsigned char *p1 = ptr1, *p2 = ptr2; ++ size_t align; ++ int result; ++ ++ if (n < sizeof(uint64_t)) ++ return memcmp_bytes(p1, p2, n); ++ ++ align = -(size_t)p1 & (sizeof(uint64_t) - 1); ++ ++ if ((result = memcmp_bytes(p1, p2, align))) ++ return result; ++ ++ p1 += align; ++ p2 += align; ++ n -= align; ++ ++ return memcmp_blocks(p1, p2, n); ++} ++ ++#if defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__)) ++ ++#if __has_builtin(__cpuidex) || (defined(_MSC_VER) && !defined(__clang__)) ++void __cpuidex(int info[4], int ax, int cx); ++#pragma intrinsic(__cpuidex) ++#else ++static FORCEINLINE void __cpuidex(int info[4], int ax, int cx) ++{ ++ __asm__ ("cpuid" : "=a"(info[0]), "=b" (info[1]), "=c"(info[2]), "=d"(info[3]) : "a"(ax), "c"(cx)); ++} ++#endif ++ ++#if __has_builtin(__cpuid) || (defined(_MSC_VER) && !defined(__clang__)) ++void __cpuid(int info[4], int ax); ++#pragma intrinsic(__cpuid) ++#else ++static FORCEINLINE void __cpuid(int info[4], int ax) ++{ ++ return __cpuidex(info, ax, 0); ++} ++#endif ++ ++static FORCEINLINE BOOL erms_supported( void ) ++{ ++ static BOOL supported; ++ if (!supported) ++ { ++ int regs[4]; ++ __cpuid(regs, 0); ++ if ((regs[1] >> 9) & 1) ++ supported = 1; ++ else ++ supported = -1; ++ } ++ return supported > 0; ++} ++ ++static FORCEINLINE BOOL avx_supported( void ) ++{ ++ static BOOL supported; ++ if (!supported) + { +- tmp0 = *(unaligned_ui64 *)s; +- tmp1 = *(unaligned_ui64 *)(s + 8); +- tmpn = *(unaligned_ui64 *)(s + n - 8); +- *(unaligned_ui64 *)d = tmp0; +- *(unaligned_ui64 *)(d + 8) = tmp1; +- *(unaligned_ui64 *)(d + n - 8) = tmpn; ++ int regs[4]; ++ __cpuid(regs, 1); ++ if (user_shared_data->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE] && (regs[2] & (1 << 28)) && ((_xgetbv(0) & 0x6) == 0x6)) ++ supported = 1; ++ else ++ supported = -1; ++ } ++ return supported > 0; ++} ++ ++static FORCEINLINE BOOL sse2_supported( void ) ++{ ++ static BOOL supported; ++ if (!supported) ++ { ++ if (user_shared_data->ProcessorFeatures[PF_XMMI64_INSTRUCTIONS_AVAILABLE]) ++ supported = 1; ++ else ++ supported = -1; + } +- else if (n >= 8) ++ return supported > 0; ++} ++ ++#else ++#define erms_supported() 0 ++#define sse2_supported() 0 ++#define avx_supported() 0 ++#endif ++ ++#define likely(x) __builtin_expect(x, 1) ++#define unlikely(x) __builtin_expect(x, 0) ++ ++#define MEMMOVEV_UNALIGNED_DECLARE(name, type, size, loadu, storeu) \ ++static FORCEINLINE void memmove_ ## name ## _unaligned(char *d, const char *s, size_t n) \ ++{ \ ++ type tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; \ ++ if (unlikely(n > 4 * size)) \ ++ { \ ++ tmp0 = loadu((type *)(s + 0 * size)); \ ++ tmp1 = loadu((type *)(s + 1 * size)); \ ++ tmp2 = loadu((type *)(s + 2 * size)); \ ++ tmp3 = loadu((type *)(s + n - 3 * size)); \ ++ tmp4 = loadu((type *)(s + n - 2 * size)); \ ++ tmp5 = loadu((type *)(s + n - 1 * size)); \ ++ storeu((type *)(d + 0 * size), tmp0); \ ++ storeu((type *)(d + 1 * size), tmp1); \ ++ storeu((type *)(d + 2 * size), tmp2); \ ++ storeu((type *)(d + n - 3 * size), tmp3); \ ++ storeu((type *)(d + n - 2 * size), tmp4); \ ++ storeu((type *)(d + n - 1 * size), tmp5); \ ++ } \ ++ else if (unlikely(n > size * 2)) \ ++ { \ ++ tmp0 = loadu((type *)(s + 0 * size)); \ ++ tmp1 = loadu((type *)(s + 1 * size)); \ ++ tmp2 = loadu((type *)(s + n - 2 * size)); \ ++ tmp3 = loadu((type *)(s + n - 1 * size)); \ ++ storeu((type *)(d + 0 * size), tmp0); \ ++ storeu((type *)(d + 1 * size), tmp1); \ ++ storeu((type *)(d + n - 2 * size), tmp2); \ ++ storeu((type *)(d + n - 1 * size), tmp3); \ ++ } \ ++ else if (unlikely(n > size)) \ ++ { \ ++ tmp0 = loadu((type *)(s + 0 * size)); \ ++ tmp1 = loadu((type *)(s + n - 1 * size)); \ ++ storeu((type *)(d + 0 * size), tmp0); \ ++ storeu((type *)(d + n - 1 * size), tmp1); \ ++ } \ ++ else memmove_c_unaligned_32(d, s, n); \ ++} ++ ++#define MEMMOVEV_DECLARE(name, type, size, loadu, storeu, store) \ ++static void *__cdecl memmove_ ## name(char *d, const char *s, size_t n) \ ++{ \ ++ if (likely(n <= 6 * size)) memmove_ ## name ## _unaligned(d, s, n); \ ++ else if (d <= s) \ ++ { \ ++ type tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; \ ++ size_t k = (size - ((uintptr_t)d & (size - 1))); \ ++ tmp0 = loadu((type *)s); \ ++ tmp1 = loadu((type *)(s + k + 0 * size)); \ ++ tmp2 = loadu((type *)(s + k + 1 * size)); \ ++ tmp3 = loadu((type *)(s + k + 2 * size)); \ ++ tmp4 = loadu((type *)(s + k + 3 * size)); \ ++ tmp5 = loadu((type *)(s + k + 4 * size)); \ ++ storeu((type *)d, tmp0); \ ++ store((type *)(d + k + 0 * size), tmp1); \ ++ store((type *)(d + k + 1 * size), tmp2); \ ++ store((type *)(d + k + 2 * size), tmp3); \ ++ store((type *)(d + k + 3 * size), tmp4); \ ++ store((type *)(d + k + 4 * size), tmp5); \ ++ k += 5 * size; d += k; s += k; n -= k; \ ++ while (unlikely(n >= 12 * size)) \ ++ { \ ++ tmp0 = loadu((type *)(s + 0 * size)); \ ++ tmp1 = loadu((type *)(s + 1 * size)); \ ++ tmp2 = loadu((type *)(s + 2 * size)); \ ++ tmp3 = loadu((type *)(s + 3 * size)); \ ++ tmp4 = loadu((type *)(s + 4 * size)); \ ++ tmp5 = loadu((type *)(s + 5 * size)); \ ++ store((type *)(d + 0 * size), tmp0); \ ++ store((type *)(d + 1 * size), tmp1); \ ++ store((type *)(d + 2 * size), tmp2); \ ++ store((type *)(d + 3 * size), tmp3); \ ++ store((type *)(d + 4 * size), tmp4); \ ++ store((type *)(d + 5 * size), tmp5); \ ++ tmp0 = loadu((type *)(s + 6 * size)); \ ++ tmp1 = loadu((type *)(s + 7 * size)); \ ++ tmp2 = loadu((type *)(s + 8 * size)); \ ++ tmp3 = loadu((type *)(s + 9 * size)); \ ++ tmp4 = loadu((type *)(s + 10 * size)); \ ++ tmp5 = loadu((type *)(s + 11 * size)); \ ++ store((type *)(d + 6 * size), tmp0); \ ++ store((type *)(d + 7 * size), tmp1); \ ++ store((type *)(d + 8 * size), tmp2); \ ++ store((type *)(d + 9 * size), tmp3); \ ++ store((type *)(d + 10 * size), tmp4); \ ++ store((type *)(d + 11 * size), tmp5); \ ++ d += 12 * size; s += 12 * size; n -= 12 * size; k += 12 * size; \ ++ } \ ++ while (unlikely(n >= 6 * size)) \ ++ { \ ++ tmp0 = loadu((type *)(s + 0 * size)); \ ++ tmp1 = loadu((type *)(s + 1 * size)); \ ++ tmp2 = loadu((type *)(s + 2 * size)); \ ++ tmp3 = loadu((type *)(s + 3 * size)); \ ++ tmp4 = loadu((type *)(s + 4 * size)); \ ++ tmp5 = loadu((type *)(s + 5 * size)); \ ++ store((type *)(d + 0 * size), tmp0); \ ++ store((type *)(d + 1 * size), tmp1); \ ++ store((type *)(d + 2 * size), tmp2); \ ++ store((type *)(d + 3 * size), tmp3); \ ++ store((type *)(d + 4 * size), tmp4); \ ++ store((type *)(d + 5 * size), tmp5); \ ++ d += 6 * size; s += 6 * size; n -= 6 * size; k += 6 * size; \ ++ } \ ++ memmove_ ## name ## _unaligned(d, s, n); \ ++ return d - k; \ ++ } \ ++ else \ ++ { \ ++ type tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; \ ++ size_t k = n - ((uintptr_t)(d + n) & (size - 1)); \ ++ tmp0 = loadu((type *)(s + n - 1 * size)); \ ++ tmp1 = loadu((type *)(s + k - 1 * size)); \ ++ tmp2 = loadu((type *)(s + k - 2 * size)); \ ++ tmp3 = loadu((type *)(s + k - 3 * size)); \ ++ tmp4 = loadu((type *)(s + k - 4 * size)); \ ++ tmp5 = loadu((type *)(s + k - 5 * size)); \ ++ storeu((type *)(d + n - 1 * size), tmp0); \ ++ store((type *)(d + k - 1 * size), tmp1); \ ++ store((type *)(d + k - 2 * size), tmp2); \ ++ store((type *)(d + k - 3 * size), tmp3); \ ++ store((type *)(d + k - 4 * size), tmp4); \ ++ store((type *)(d + k - 5 * size), tmp5); \ ++ k -= 5 * size; \ ++ while (unlikely(k >= 12 * size)) \ ++ { \ ++ tmp0 = loadu((type *)(s + k - 1 * size)); \ ++ tmp1 = loadu((type *)(s + k - 2 * size)); \ ++ tmp2 = loadu((type *)(s + k - 3 * size)); \ ++ tmp3 = loadu((type *)(s + k - 4 * size)); \ ++ tmp4 = loadu((type *)(s + k - 5 * size)); \ ++ tmp5 = loadu((type *)(s + k - 6 * size)); \ ++ store((type *)(d + k - 1 * size), tmp0); \ ++ store((type *)(d + k - 2 * size), tmp1); \ ++ store((type *)(d + k - 3 * size), tmp2); \ ++ store((type *)(d + k - 4 * size), tmp3); \ ++ store((type *)(d + k - 5 * size), tmp4); \ ++ store((type *)(d + k - 6 * size), tmp5); \ ++ tmp0 = loadu((type *)(s + k - 7 * size)); \ ++ tmp1 = loadu((type *)(s + k - 8 * size)); \ ++ tmp2 = loadu((type *)(s + k - 9 * size)); \ ++ tmp3 = loadu((type *)(s + k - 10 * size)); \ ++ tmp4 = loadu((type *)(s + k - 11 * size)); \ ++ tmp5 = loadu((type *)(s + k - 12 * size)); \ ++ store((type *)(d + k - 7 * size), tmp0); \ ++ store((type *)(d + k - 8 * size), tmp1); \ ++ store((type *)(d + k - 9 * size), tmp2); \ ++ store((type *)(d + k - 10 * size), tmp3); \ ++ store((type *)(d + k - 11 * size), tmp4); \ ++ store((type *)(d + k - 12 * size), tmp5); \ ++ k -= 12 * size; \ ++ } \ ++ while (unlikely(k >= 6 * size)) \ ++ { \ ++ tmp0 = loadu((type *)(s + k - 1 * size)); \ ++ tmp1 = loadu((type *)(s + k - 2 * size)); \ ++ tmp2 = loadu((type *)(s + k - 3 * size)); \ ++ tmp3 = loadu((type *)(s + k - 4 * size)); \ ++ tmp4 = loadu((type *)(s + k - 5 * size)); \ ++ tmp5 = loadu((type *)(s + k - 6 * size)); \ ++ store((type *)(d + k - 1 * size), tmp0); \ ++ store((type *)(d + k - 2 * size), tmp1); \ ++ store((type *)(d + k - 3 * size), tmp2); \ ++ store((type *)(d + k - 4 * size), tmp3); \ ++ store((type *)(d + k - 5 * size), tmp4); \ ++ store((type *)(d + k - 6 * size), tmp5); \ ++ k -= 6 * size; \ ++ } \ ++ memmove_ ## name ## _unaligned(d, s, k); \ ++ } \ ++ return d; \ ++} ++ ++static FORCEINLINE void __cdecl memmove_c_unaligned_32(char *d, const char *s, size_t n) ++{ ++ uint64_t tmp0, tmp1, tmp2, tmpn; ++ ++ if (unlikely(n >= 24)) + { +- tmp0 = *(unaligned_ui64 *)s; +- tmpn = *(unaligned_ui64 *)(s + n - 8); +- *(unaligned_ui64 *)d = tmp0; +- *(unaligned_ui64 *)(d + n - 8) = tmpn; ++ tmp0 = *(uint64_t *)s; ++ tmp1 = *(uint64_t *)(s + 8); ++ tmp2 = *(uint64_t *)(s + 16); ++ tmpn = *(uint64_t *)(s + n - 8); ++ *(uint64_t *)d = tmp0; ++ *(uint64_t *)(d + 8) = tmp1; ++ *(uint64_t *)(d + 16) = tmp2; ++ *(uint64_t *)(d + n - 8) = tmpn; + } +- else if (n >= 4) ++ else if (unlikely(n >= 16)) + { +- tmp0 = *(unaligned_ui32 *)s; +- tmpn = *(unaligned_ui32 *)(s + n - 4); +- *(unaligned_ui32 *)d = tmp0; +- *(unaligned_ui32 *)(d + n - 4) = tmpn; ++ tmp0 = *(uint64_t *)s; ++ tmp1 = *(uint64_t *)(s + 8); ++ tmpn = *(uint64_t *)(s + n - 8); ++ *(uint64_t *)d = tmp0; ++ *(uint64_t *)(d + 8) = tmp1; ++ *(uint64_t *)(d + n - 8) = tmpn; + } +- else if (n >= 2) ++ else if (unlikely(n >= 8)) + { +- tmp0 = *(unaligned_ui16 *)s; +- tmpn = *(unaligned_ui16 *)(s + n - 2); +- *(unaligned_ui16 *)d = tmp0; +- *(unaligned_ui16 *)(d + n - 2) = tmpn; ++ tmp0 = *(uint64_t *)s; ++ tmpn = *(uint64_t *)(s + n - 8); ++ *(uint64_t *)d = tmp0; ++ *(uint64_t *)(d + n - 8) = tmpn; + } +- else if (n >= 1) ++ else if (unlikely(n >= 4)) ++ { ++ tmp0 = *(uint32_t *)s; ++ tmpn = *(uint32_t *)(s + n - 4); ++ *(uint32_t *)d = tmp0; ++ *(uint32_t *)(d + n - 4) = tmpn; ++ } ++ else if (unlikely(n >= 2)) ++ { ++ tmp0 = *(uint16_t *)s; ++ tmpn = *(uint16_t *)(s + n - 2); ++ *(uint16_t *)d = tmp0; ++ *(uint16_t *)(d + n - 2) = tmpn; ++ } ++ else if (likely(n >= 1)) + { + *(uint8_t *)d = *(uint8_t *)s; + } + } + +-static FORCEINLINE void *memmove_unrolled( char *dst, const char *src, size_t n ) ++static void *__cdecl memmove_c(char *d, const char *s, size_t n) + { +- typedef uint64_t DECLSPEC_ALIGN(1) unaligned_ui64; +- uint64_t tmp0, tmp1, tmp2; +- char *end; +- +- if (n <= 24) memmove_unaligned_24( dst, src, n ); +- else if ((size_t)dst - (size_t)src >= n) ++ if (likely(n <= 32)) memmove_c_unaligned_32(d, s, n); ++ else if (d <= s) + { +- end = dst + n; src += n; +- do ++ uint64_t tmp0, tmp1, tmp2; ++ size_t k = 0; ++ while (unlikely(n >= 48)) ++ { ++ tmp0 = *(uint64_t *)(s + 0); ++ tmp1 = *(uint64_t *)(s + 8); ++ tmp2 = *(uint64_t *)(s + 16); ++ *(uint64_t*)(d + 0) = tmp0; ++ *(uint64_t*)(d + 8) = tmp1; ++ *(uint64_t*)(d + 16) = tmp2; ++ tmp0 = *(uint64_t *)(s + 24); ++ tmp1 = *(uint64_t *)(s + 32); ++ tmp2 = *(uint64_t *)(s + 40); ++ *(uint64_t*)(d + 24) = tmp0; ++ *(uint64_t*)(d + 32) = tmp1; ++ *(uint64_t*)(d + 40) = tmp2; ++ d += 48; s += 48; n -= 48; k += 48; ++ } ++ while (unlikely(n >= 24)) + { +- tmp0 = *(unaligned_ui64 *)(src - n + 0); +- tmp1 = *(unaligned_ui64 *)(src - n + 8); +- tmp2 = *(unaligned_ui64 *)(src - n + 16); +- *(unaligned_ui64*)(end - n + 0) = tmp0; +- *(unaligned_ui64*)(end - n + 8) = tmp1; +- *(unaligned_ui64*)(end - n + 16) = tmp2; +- n -= 24; ++ tmp0 = *(uint64_t *)(s + 0); ++ tmp1 = *(uint64_t *)(s + 8); ++ tmp2 = *(uint64_t *)(s + 16); ++ *(uint64_t*)(d + 0) = tmp0; ++ *(uint64_t*)(d + 8) = tmp1; ++ *(uint64_t*)(d + 16) = tmp2; ++ d += 24; s += 24; n -= 24; k += 24; + } +- while (n >= 24); +- memmove_unaligned_24( end - n, src - n, n ); ++ memmove_c_unaligned_32(d, s, n); ++ return d - k; + } + else + { +- do ++ uint64_t tmp0, tmp1, tmp2; ++ size_t k = n; ++ while (unlikely(k >= 48)) + { +- tmp0 = *(unaligned_ui64 *)(src + n - 8); +- tmp1 = *(unaligned_ui64 *)(src + n - 16); +- tmp2 = *(unaligned_ui64 *)(src + n - 24); +- *(unaligned_ui64*)(dst + n - 8) = tmp0; +- *(unaligned_ui64*)(dst + n - 16) = tmp1; +- *(unaligned_ui64*)(dst + n - 24) = tmp2; +- n -= 24; ++ tmp0 = *(uint64_t *)(s + k - 8); ++ tmp1 = *(uint64_t *)(s + k - 16); ++ tmp2 = *(uint64_t *)(s + k - 24); ++ *(uint64_t*)(d + k - 8) = tmp0; ++ *(uint64_t*)(d + k - 16) = tmp1; ++ *(uint64_t*)(d + k - 24) = tmp2; ++ tmp0 = *(uint64_t *)(s + k - 32); ++ tmp1 = *(uint64_t *)(s + k - 40); ++ tmp2 = *(uint64_t *)(s + k - 48); ++ *(uint64_t*)(d + k - 32) = tmp0; ++ *(uint64_t*)(d + k - 40) = tmp1; ++ *(uint64_t*)(d + k - 48) = tmp2; ++ k -= 48; + } +- while (n >= 24); +- memmove_unaligned_24( dst, src, n ); ++ while (unlikely(k >= 24)) ++ { ++ tmp0 = *(uint64_t *)(s + k - 8); ++ tmp1 = *(uint64_t *)(s + k - 16); ++ tmp2 = *(uint64_t *)(s + k - 24); ++ *(uint64_t*)(d + k - 8) = tmp0; ++ *(uint64_t*)(d + k - 16) = tmp1; ++ *(uint64_t*)(d + k - 24) = tmp2; ++ k -= 24; ++ } ++ memmove_c_unaligned_32(d, s, k); + } +- return dst; ++ return d; + } + ++#ifndef __SSE2__ ++#ifdef __clang__ ++#pragma clang attribute push (__attribute__((target("sse2"))), apply_to=function) ++#else ++#pragma GCC push_options ++#pragma GCC target("sse2") ++#endif ++#define __DISABLE_SSE2__ ++#endif /* __SSE2__ */ ++ ++MEMMOVEV_UNALIGNED_DECLARE(sse2, __m128i, 16, _mm_loadu_si128, _mm_storeu_si128) ++MEMMOVEV_DECLARE(sse2, __m128i, 16, _mm_loadu_si128, _mm_storeu_si128, _mm_store_si128) ++ ++#ifdef __DISABLE_SSE2__ ++#ifdef __clang__ ++#pragma clang attribute pop ++#else ++#pragma GCC pop_options ++#endif ++#undef __DISABLE_SSE2__ ++#endif /* __DISABLE_SSE2__ */ ++ ++#ifndef __AVX__ ++#ifdef __clang__ ++#pragma clang attribute push (__attribute__((target("avx"))), apply_to=function) ++#else ++#pragma GCC push_options ++#pragma GCC target("avx") ++#endif ++#define __DISABLE_AVX__ ++#endif /* __AVX__ */ ++ ++MEMMOVEV_UNALIGNED_DECLARE(avx, __m256i, 32, _mm256_loadu_si256, _mm256_storeu_si256) ++MEMMOVEV_DECLARE(avx, __m256i, 32, _mm256_loadu_si256, _mm256_storeu_si256, _mm256_store_si256) ++ ++#ifdef __DISABLE_AVX__ ++#undef __DISABLE_AVX__ ++#ifdef __clang__ ++#pragma clang attribute pop ++#else ++#pragma GCC pop_options ++#endif ++#endif /* __DISABLE_AVX__ */ + + /********************************************************************* +- * memcpy (NTDLL.@) +- * +- * NOTES +- * Behaves like memmove. ++ * memmove (NTDLL.@) + */ +-void * __cdecl memcpy( void *dst, const void *src, size_t n ) ++void *__cdecl memmove(void *dst, const void *src, size_t n) + { +- return memmove_unrolled( dst, src, n ); ++ if (unlikely(n < 32)) { memmove_c_unaligned_32(dst, src, n); return dst; } ++ if (likely(avx_supported())) return memmove_avx(dst, src, n); ++ if (likely(sse2_supported())) return memmove_sse2(dst, src, n); ++ return memmove_c(dst, src, n); + } + +- + /********************************************************************* +- * memmove (NTDLL.@) ++ * memcpy (NTDLL.@) + */ +-void * __cdecl memmove( void *dst, const void *src, size_t n ) ++void *__cdecl memcpy(void *dst, const void *src, size_t n) + { +- return memmove_unrolled( dst, src, n ); ++ if (unlikely(n < 32)) { memmove_c_unaligned_32(dst, src, n); return dst; } ++ if (likely(avx_supported())) return memmove_avx(dst, src, n); ++ if (likely(sse2_supported())) return memmove_sse2(dst, src, n); ++ return memmove_c(dst, src, n); + } + +- + /********************************************************************* + * memcpy_s (MSVCRT.@) + */ +@@ -250,10 +625,83 @@ static inline void memset_aligned_32( unsigned char *d, uint64_t v, size_t n ) + } + } + +-/********************************************************************* +- * memset (NTDLL.@) +- */ +-void *__cdecl memset( void *dst, int c, size_t n ) ++#if defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__)) ++ ++#ifdef __i386__ ++#define DEST_REG "%edi" ++#define LEN_REG "%ecx" ++#define VAL_REG "%eax" ++ ++#define MEMSET_INIT \ ++ "movl " DEST_REG ", %edx\n\t" \ ++ "movl 4(%esp), " DEST_REG "\n\t" \ ++ "movl 8(%esp), " VAL_REG "\n\t" \ ++ "movl 12(%esp), " LEN_REG "\n\t" ++ ++#define MEMSET_RET \ ++ "movl %edx, " DEST_REG "\n\t" \ ++ "ret" ++ ++#else ++ ++#define DEST_REG "%rdi" ++#define LEN_REG "%rcx" ++#define VAL_REG "%eax" ++ ++#define MEMSET_INIT \ ++ "movq " DEST_REG ", %r9\n\t" \ ++ "movq %rcx, " DEST_REG "\n\t" \ ++ "movl %edx, " VAL_REG "\n\t" \ ++ "movq %r8, " LEN_REG "\n\t" ++ ++#define MEMSET_RET \ ++ "movq %r9, " DEST_REG "\n\t" \ ++ "ret" ++ ++#endif ++ ++void __cdecl erms_memset_aligned_32(unsigned char *d, unsigned int c, size_t n); ++__ASM_GLOBAL_FUNC( erms_memset_aligned_32, ++ MEMSET_INIT ++ "rep\n\t" ++ "stosb\n\t" ++ MEMSET_RET ) ++ ++void __cdecl sse2_memset_aligned_32(unsigned char *d, unsigned int c, size_t n); ++__ASM_GLOBAL_FUNC( sse2_memset_aligned_32, ++ MEMSET_INIT ++ "movd " VAL_REG ", %xmm0\n\t" ++ "pshufd $0, %xmm0, %xmm0\n\t" ++ "test $0x20, " LEN_REG "\n\t" ++ "je 1f\n\t" ++ "add $0x20, " DEST_REG "\n\t" ++ "sub $0x20, " LEN_REG "\n\t" ++ "movdqa %xmm0, -0x20(" DEST_REG ")\n\t" ++ "movdqa %xmm0, -0x10(" DEST_REG ")\n\t" ++ "je 2f\n\t" ++ "1:\n\t" ++ "add $0x40, " DEST_REG "\n\t" ++ "sub $0x40, " LEN_REG "\n\t" ++ "movdqa %xmm0, -0x40(" DEST_REG ")\n\t" ++ "movdqa %xmm0, -0x30(" DEST_REG ")\n\t" ++ "movdqa %xmm0, -0x20(" DEST_REG ")\n\t" ++ "movdqa %xmm0, -0x10(" DEST_REG ")\n\t" ++ "ja 1b\n\t" ++ "2:\n\t" ++ MEMSET_RET ) ++ ++#undef MEMSET_INIT ++#undef MEMSET_RET ++#undef DEST_REG ++#undef LEN_REG ++#undef VAL_REG ++ ++#endif ++ ++/********************************************************************* ++ * memset (NTDLL.@) ++ */ ++void *__cdecl memset(void *dst, int c, size_t n) + { + typedef uint64_t DECLSPEC_ALIGN(1) unaligned_ui64; + typedef uint32_t DECLSPEC_ALIGN(1) unaligned_ui32; +@@ -277,8 +725,27 @@ void *__cdecl memset( void *dst, int c, size_t n ) + if (n <= 64) return dst; + + n = (n - a) & ~0x1f; +- memset_aligned_32( d + a, v, n ); ++#if defined(__i386__) || defined(__x86_64__) ++ if (n >= 2048 && erms_supported) ++ { ++ erms_memset_aligned_32(d + a, v, n); ++ return dst; ++ } ++#ifdef __x86_64__ ++ sse2_memset_aligned_32(d + a, v, n); + return dst; ++#else ++ if (sse2_supported()) ++ { ++ sse2_memset_aligned_32(d + a, v, n); ++ return dst; ++ } ++#endif ++#endif ++#ifndef __x86_64__ ++ memset_aligned_32(d + a, v, n); ++ return dst; ++#endif + } + if (n >= 8) + { +@@ -306,6 +773,11 @@ void *__cdecl memset( void *dst, int c, size_t n ) + return dst; + } + ++#undef MEMMOVEV_DECLARE ++#undef MEMMOVEV_UNALIGNED_DECLARE ++#undef likely ++#undef unlikely ++ + + /****************************************************************************** + * RtlCopyMemory (NTDLL.@) +-- +2.47.1 + diff --git a/0004-build-fix-undebug-optimize/0006-headers-Fix-compilation-with-llvm-mingw-UCRT-if-fgnu.patch b/0004-build-fix-undebug-optimize/0006-headers-Fix-compilation-with-llvm-mingw-UCRT-if-fgnu.patch new file mode 100644 index 0000000..42ad249 --- /dev/null +++ b/0004-build-fix-undebug-optimize/0006-headers-Fix-compilation-with-llvm-mingw-UCRT-if-fgnu.patch @@ -0,0 +1,44 @@ +From e2be60158032e164952311200154ad54cafa280e Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Tue, 31 Dec 2024 14:35:39 -0800 +Subject: [PATCH] headers: Fix compilation with llvm-mingw UCRT if + -fgnuc-version>=5. + +--- + include/msvcrt/intrin.h | 4 ++++ + libs/faudio/src/FAudio_internal_simd.c | 4 ++++ + 2 files changed, 8 insertions(+) + +diff --git a/include/msvcrt/intrin.h b/include/msvcrt/intrin.h +index ba825b7b09e..de523ec5e89 100644 +--- a/include/msvcrt/intrin.h ++++ b/include/msvcrt/intrin.h +@@ -8,6 +8,10 @@ + #define _INC_INTRIN + + #if defined(__i386__) || (defined(__x86_64__) && !defined(__arm64ec__)) ++#if defined(__clang__) && (defined(__MINGW64__) || defined(__MINGW32__)) ++#define __mingw_aligned_malloc _aligned_malloc ++#define __mingw_aligned_free _aligned_free ++#endif + # include + #endif + +diff --git a/libs/faudio/src/FAudio_internal_simd.c b/libs/faudio/src/FAudio_internal_simd.c +index 7b7997b2ad0..6c830d9a239 100644 +--- a/libs/faudio/src/FAudio_internal_simd.c ++++ b/libs/faudio/src/FAudio_internal_simd.c +@@ -69,6 +69,10 @@ + + + #ifdef __SSE2__ ++#if defined(__clang__) && (defined(__MINGW64__) || defined(__MINGW32__)) ++#define __mingw_aligned_malloc _aligned_malloc ++#define __mingw_aligned_free _aligned_free ++#endif + #include + #define HAVE_SSE2_INTRINSICS 1 + #endif +-- +2.47.1 + diff --git a/0004-build-fix-undebug-optimize/2000-configure.ac-Omit-frame-pointers-on-x86_64-leaf-fram.patch b/0004-build-fix-undebug-optimize/2000-configure.ac-Omit-frame-pointers-on-x86_64-leaf-fram.patch new file mode 100644 index 0000000..124c6d3 --- /dev/null +++ b/0004-build-fix-undebug-optimize/2000-configure.ac-Omit-frame-pointers-on-x86_64-leaf-fram.patch @@ -0,0 +1,42 @@ +From 046670cd17d81661e58ac65ad75730df9dcfd957 Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Mon, 30 Dec 2024 02:31:59 -0800 +Subject: [PATCH] configure.ac: Omit frame pointers on x86_64, leaf frame + pointers on i386. + +--- + configure.ac | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/configure.ac b/configure.ac +index 2648ea2f834..f86ddd3dd60 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -987,10 +987,12 @@ This is an error since --enable-archs=$wine_arch was requested.])]) + + case $wine_arch in + i386) WINE_TRY_PE_CFLAGS([-fno-omit-frame-pointer]) ++ WINE_TRY_PE_CFLAGS([-momit-leaf-frame-pointer]) + WINE_TRY_PE_CFLAGS([-mpreferred-stack-boundary=2]) + WINE_TRY_PE_CFLAGS([-Wl,--disable-stdcall-fixup], + [AS_VAR_APPEND([${wine_arch}_LDFLAGS],[" -Wl,--disable-stdcall-fixup"])]) ;; +- x86_64) WINE_TRY_PE_CFLAGS([-Wformat-overflow]) ++ x86_64) WINE_TRY_PE_CFLAGS([-fomit-frame-pointer]) ++ WINE_TRY_PE_CFLAGS([-Wformat-overflow]) + WINE_TRY_PE_CFLAGS([-Wnonnull]) + WINE_TRY_PE_CFLAGS([-mcx16]) + WINE_TRY_PE_CFLAGS([-mcmodel=small]) ;; +@@ -1984,8 +1986,9 @@ then + + case $HOST_ARCH in + dnl gcc-4.6+ omits frame pointers by default, breaking some copy protections +- i386) WINE_TRY_CFLAGS([-fno-omit-frame-pointer],[MSVCRTFLAGS="$MSVCRTFLAGS -fno-omit-frame-pointer"]) ;; ++ i386) WINE_TRY_CFLAGS([-fno-omit-frame-pointer -momit-leaf-frame-pointer],[MSVCRTFLAGS="$MSVCRTFLAGS -fno-omit-frame-pointer -momit-leaf-frame-pointer"]) ;; + x86_64) ++ WINE_TRY_CFLAGS([-fomit-frame-pointer],[MSVCRTFLAGS="$MSVCRTFLAGS -fomit-frame-pointer"]) + case $host_os in + dnl Mingw uses Windows 64-bit types, not Unix ones + cygwin*|mingw32*) WINE_TRY_CFLAGS([-Wno-format]) ;; +-- +2.47.1 + diff --git a/0004-build-fix-undebug-optimize/2000-configure.ac-Omit-frame-pointers.patch b/0004-build-fix-undebug-optimize/2000-configure.ac-Omit-frame-pointers.patch deleted file mode 100644 index 8abab0a..0000000 --- a/0004-build-fix-undebug-optimize/2000-configure.ac-Omit-frame-pointers.patch +++ /dev/null @@ -1,46 +0,0 @@ -From: William Horvath -Date: Sat, 5 Oct 2024 06:34:55 -0700 -Subject: [PATCH] configure.ac: Omit frame pointers. - ---- -diff --git a/configure.ac b/configure.ac -index 11111111111..11111111111 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -963,6 +963,7 @@ This is an error since --enable-archs=$wine_arch was requested.])]) - WINE_TRY_PE_CFLAGS([-Wabsolute-value]) - WINE_TRY_PE_CFLAGS([-Wenum-enum-conversion],[:],WINE_TRY_PE_CFLAGS([-Wenum-conversion])) - WINE_TRY_PE_CFLAGS([-ffunction-sections]) -+ WINE_TRY_PE_CFLAGS([-fomit-frame-pointer]) - - dnl clang had broken -fms-hotpatch support before version 18 (https://github.com/llvm/llvm-project/pull/77245) - WINE_TRY_PE_CFLAGS([-fms-hotpatch -DMIN_CLANG_VERSION=18], -@@ -973,8 +974,7 @@ This is an error since --enable-archs=$wine_arch was requested.])]) - WINE_TRY_PE_CFLAGS([-flarge-source-files -Wmisleading-indentation],[AS_VAR_APPEND(${wine_arch}_EXTRACFLAGS,[" -Wno-misleading-indentation"])]) - - case $wine_arch in -- i386) WINE_TRY_PE_CFLAGS([-fno-omit-frame-pointer]) -- WINE_TRY_PE_CFLAGS([-mpreferred-stack-boundary=2]) -+ i386) WINE_TRY_PE_CFLAGS([-mpreferred-stack-boundary=2]) - WINE_TRY_PE_CFLAGS([-Wl,--disable-stdcall-fixup], - [AS_VAR_APPEND([${wine_arch}_LDFLAGS],[" -Wl,--disable-stdcall-fixup"])]) ;; - x86_64) WINE_TRY_PE_CFLAGS([-Wformat-overflow]) -@@ -1968,7 +1968,6 @@ then - - case $HOST_ARCH in - dnl gcc-4.6+ omits frame pointers by default, breaking some copy protections -- i386) WINE_TRY_CFLAGS([-fno-omit-frame-pointer],[MSVCRTFLAGS="$MSVCRTFLAGS -fno-omit-frame-pointer"]) ;; - x86_64) - case $host_os in - dnl Mingw uses Windows 64-bit types, not Unix ones -@@ -1987,6 +1986,7 @@ int a(int b, ...) { __builtin_ms_va_list list; __builtin_ms_va_start(list,b); }] - esac ;; - arm) - WINE_TRY_CFLAGS([-Wincompatible-function-pointer-types],[EXTRACFLAGS="$EXTRACFLAGS -Wno-error=incompatible-function-pointer-types"]) ;; -+ *) WINE_TRY_CFLAGS([-fomit-frame-pointer],[MSVCRTFLAGS="$MSVCRTFLAGS -fomit-frame-pointer"]) ;; - esac - - CFLAGS=$saved_CFLAGS --- -0.0.0 - diff --git a/0004-build-fix-undebug-optimize/6000-server-Disable-debug-features-if-NDEBUG-is-d.patch b/0004-build-fix-undebug-optimize/6000-server-Disable-debug-features-if-NDEBUG-is-d.patch index cbb1f27..65b36f7 100644 --- a/0004-build-fix-undebug-optimize/6000-server-Disable-debug-features-if-NDEBUG-is-d.patch +++ b/0004-build-fix-undebug-optimize/6000-server-Disable-debug-features-if-NDEBUG-is-d.patch @@ -1,15 +1,74 @@ -From b4f3bbfe08ce92cc78b21543a149e8f876c7235e Mon Sep 17 00:00:00 2001 +From 62d6666c6316fc8b449d6b3f8c215ae500495835 Mon Sep 17 00:00:00 2001 From: William Horvath -Date: Thu, 5 Dec 2024 17:50:13 -0800 +Date: Mon, 30 Dec 2024 02:14:28 -0800 Subject: [PATCH] server: Disable debug features if NDEBUG is defined. Co-authored-by: Torge Matthies --- - server/object.h | 2 ++ - 1 file changed, 2 insertions(+) + server/mapping.c | 4 ++++ + server/object.c | 11 ++++++++--- + server/object.h | 4 ++++ + 3 files changed, 16 insertions(+), 3 deletions(-) +diff --git a/server/mapping.c b/server/mapping.c +index 177c7bab7d0..2a49e61f6fb 100644 +--- a/server/mapping.c ++++ b/server/mapping.c +@@ -1397,7 +1397,9 @@ const volatile void *alloc_shared_object(void) + SHARED_WRITE_BEGIN( &object->obj.shm, object_shm_t ) + { + /* mark the object data as uninitialized */ ++#ifndef NDEBUG + mark_block_uninitialized( (void *)shared, sizeof(*shared) ); ++#endif + CONTAINING_RECORD( shared, shared_object_t, shm )->id = ++session.last_object_id; + } + SHARED_WRITE_END; +@@ -1411,7 +1413,9 @@ void free_shared_object( const volatile void *object_shm ) + + SHARED_WRITE_BEGIN( &object->obj.shm, object_shm_t ) + { ++#ifndef NDEBUG + mark_block_noaccess( (void *)shared, sizeof(*shared) ); ++#endif + CONTAINING_RECORD( shared, shared_object_t, shm )->id = 0; + } + SHARED_WRITE_END; +diff --git a/server/object.c b/server/object.c +index 529296c3674..69746b66ff4 100644 +--- a/server/object.c ++++ b/server/object.c +@@ -190,8 +190,6 @@ void close_objects(void) + dump_objects(); /* dump any remaining objects */ + } + +-#endif /* DEBUG_OBJECTS */ +- + /*****************************************************************/ + + /* mark a block of memory as not accessible for debugging purposes */ +@@ -221,11 +219,18 @@ void mark_block_uninitialized( void *ptr, size_t size ) + #endif + } + ++#endif /* DEBUG_OBJECTS */ ++ + /* malloc replacement */ + void *mem_alloc( size_t size ) + { + void *ptr = malloc( size ); +- if (ptr) mark_block_uninitialized( ptr, size ); ++ if (ptr) ++#ifndef NDEBUG ++ mark_block_uninitialized( ptr, size ); ++#else ++0; ++#endif + else set_error( STATUS_NO_MEMORY ); + return ptr; + } diff --git a/server/object.h b/server/object.h -index 20d242f3079..c27407e8375 100644 +index 1a09c1f2548..6c0b83a4326 100644 --- a/server/object.h +++ b/server/object.h @@ -26,7 +26,9 @@ @@ -22,6 +81,17 @@ index 20d242f3079..c27407e8375 100644 /* kernel objects */ +@@ -152,8 +154,10 @@ struct namespace_iterator + void *entry; + }; + ++#ifndef NDEBUG + extern void mark_block_noaccess( void *ptr, size_t size ); + extern void mark_block_uninitialized( void *ptr, size_t size ); ++#endif + extern void *mem_alloc( size_t size ) __WINE_ALLOC_SIZE(1) __WINE_DEALLOC(free) __WINE_MALLOC; + extern void *memdup( const void *data, size_t len ) __WINE_ALLOC_SIZE(2) __WINE_DEALLOC(free); + extern void *alloc_object( const struct object_ops *ops ); -- 2.47.1 diff --git a/0004-build-fix-undebug-optimize/8500-headers-change-more-__GNUC__-to-__GNUC__-__clang__.patch b/0004-build-fix-undebug-optimize/8500-headers-change-more-__GNUC__-to-__GNUC__-__clang__.patch new file mode 100644 index 0000000..b874ccd --- /dev/null +++ b/0004-build-fix-undebug-optimize/8500-headers-change-more-__GNUC__-to-__GNUC__-__clang__.patch @@ -0,0 +1,135 @@ +From 766cb869a815329985698856847062f4186c04f9 Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Sat, 28 Dec 2024 04:33:48 -0800 +Subject: [PATCH] headers: change more __GNUC__ to (__GNUC__ || __clang__) + +--- + dlls/ntdll/signal_i386.c | 4 ++-- + dlls/oleaut32/vartype.c | 2 +- + dlls/rsaenh/tomcrypt.h | 2 +- + dlls/vcomp/main.c | 2 +- + dlls/win32u/dibdrv/primitives.c | 4 ++-- + include/msvcrt/stdlib.h | 2 +- + include/winnt.h | 3 ++- + 7 files changed, 10 insertions(+), 9 deletions(-) + +diff --git a/dlls/ntdll/signal_i386.c b/dlls/ntdll/signal_i386.c +index dd7c33933ba..9bf742899a8 100644 +--- a/dlls/ntdll/signal_i386.c ++++ b/dlls/ntdll/signal_i386.c +@@ -232,7 +232,7 @@ void WINAPI KiUserCallbackDispatcher( ULONG id, void *args, ULONG len ) + */ + static inline void save_fpu( CONTEXT *context ) + { +-#ifdef __GNUC__ ++#if defined(__GNUC__) || defined(__clang__) + struct + { + DWORD ControlWord; +@@ -264,7 +264,7 @@ static inline void save_fpu( CONTEXT *context ) + */ + static inline void save_fpux( CONTEXT *context ) + { +-#ifdef __GNUC__ ++#if defined(__GNUC__) || defined(__clang__) + /* we have to enforce alignment by hand */ + char buffer[sizeof(XSAVE_FORMAT) + 16]; + XSAVE_FORMAT *state = (XSAVE_FORMAT *)(((ULONG_PTR)buffer + 15) & ~15); +diff --git a/dlls/oleaut32/vartype.c b/dlls/oleaut32/vartype.c +index 747705f94e2..86a3f8b5950 100644 +--- a/dlls/oleaut32/vartype.c ++++ b/dlls/oleaut32/vartype.c +@@ -3496,7 +3496,7 @@ HRESULT WINAPI VarCyFromR4(FLOAT fltIn, CY* pCyOut) + */ + HRESULT WINAPI VarCyFromR8(double dblIn, CY* pCyOut) + { +-#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) ++#if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) + /* This code gives identical results to Win32 on Intel. + * Here we use fp exceptions to catch overflows when storing the value. + */ +diff --git a/dlls/rsaenh/tomcrypt.h b/dlls/rsaenh/tomcrypt.h +index 3e1db9aa01a..27dcd891d31 100644 +--- a/dlls/rsaenh/tomcrypt.h ++++ b/dlls/rsaenh/tomcrypt.h +@@ -94,7 +94,7 @@ typedef ULONG32 ulong32; + ((unsigned long)((y)[2] & 255)<<8) | \ + ((unsigned long)((y)[3] & 255)); } + +-#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) && !defined(INTEL_CC) ++#if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) && !defined(INTEL_CC) + + static inline unsigned ROR(unsigned word, int i) + { +diff --git a/dlls/vcomp/main.c b/dlls/vcomp/main.c +index e3be001d302..01721215e1b 100644 +--- a/dlls/vcomp/main.c ++++ b/dlls/vcomp/main.c +@@ -135,7 +135,7 @@ static void copy_va_list_data(void **args, va_list valist, int args_count) + args[i] = va_arg(valist, void *); + } + +-#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) ++#if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) + + static inline char interlocked_cmpxchg8(char *dest, char xchg, char compare) + { +diff --git a/dlls/win32u/dibdrv/primitives.c b/dlls/win32u/dibdrv/primitives.c +index 3633c687e78..b0d611db9e7 100644 +--- a/dlls/win32u/dibdrv/primitives.c ++++ b/dlls/win32u/dibdrv/primitives.c +@@ -246,7 +246,7 @@ static inline void do_rop_codes_line_rev_4(BYTE *dst, int dst_x, const BYTE *src + + static inline void memset_32( DWORD *start, DWORD val, DWORD size ) + { +-#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) ++#if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) + DWORD dummy; + __asm__ __volatile__( "cld; rep; stosl" + : "=c" (dummy), "=D" (dummy) +@@ -258,7 +258,7 @@ static inline void memset_32( DWORD *start, DWORD val, DWORD size ) + + static inline void memset_16( WORD *start, WORD val, DWORD size ) + { +-#if defined(__GNUC__) && (defined(__i386__) || defined(__x86_64__)) ++#if (defined(__GNUC__) || defined(__clang__)) && (defined(__i386__) || defined(__x86_64__)) + DWORD dummy; + __asm__ __volatile__( "cld; rep; stosw" + : "=c" (dummy), "=D" (dummy) +diff --git a/include/msvcrt/stdlib.h b/include/msvcrt/stdlib.h +index 9cb8ccb110a..7ce9b1068f9 100644 +--- a/include/msvcrt/stdlib.h ++++ b/include/msvcrt/stdlib.h +@@ -231,7 +231,7 @@ _ACRTIMP float __cdecl strtof(const char*,char**); + _ACRTIMP float __cdecl _strtof_l(const char*,char**,_locale_t); + _ACRTIMP double __cdecl strtod(const char*,char**); + _ACRTIMP double __cdecl _strtod_l(const char*,char**,_locale_t); +-#if defined(__GNUC__) || _MSVCR_VER < 120 ++#if (defined(__GNUC__) || defined(__clang__)) || _MSVCR_VER < 120 + static inline long double strtold(const char *string, char **endptr) { return strtod(string, endptr); } + static inline long double _strtold_l(const char *string, char **endptr, _locale_t locale) { return _strtod_l(string, endptr, locale); } + #else +diff --git a/include/winnt.h b/include/winnt.h +index c6ed535c8d8..5e4a5694e18 100644 +--- a/include/winnt.h ++++ b/include/winnt.h +@@ -34,6 +34,7 @@ + + + #if defined(_MSC_VER) && (defined(__arm__) || defined(__aarch64__) || defined(__arm64ec__)) ++#include + #include + #endif + +@@ -221,7 +222,7 @@ extern "C" { + #define __WINE_DEALLOC(...) + #endif + +-#if defined(__GNUC__) && (__GNUC__ > 2) ++#if (defined(__GNUC__) && (__GNUC__ > 2)) || defined(__clang__) + #define __WINE_MALLOC __attribute__((malloc)) + #else + #define __WINE_MALLOC +-- +2.47.1 + diff --git a/0004-build-fix-undebug-optimize/8600-configure-ntdll-Use-gettid-if-available.patch b/0004-build-fix-undebug-optimize/8600-configure-ntdll-Use-gettid-if-available.patch new file mode 100644 index 0000000..8c0003a --- /dev/null +++ b/0004-build-fix-undebug-optimize/8600-configure-ntdll-Use-gettid-if-available.patch @@ -0,0 +1,38 @@ +From d43631c794412029bfd804349a081be9395ab313 Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Sun, 29 Dec 2024 23:23:41 -0800 +Subject: [PATCH] configure, ntdll: Use gettid() if available. + +--- + configure.ac | 1 + + dlls/ntdll/unix/server.c | 2 ++ + 2 files changed, 3 insertions(+) + +diff --git a/configure.ac b/configure.ac +index 10f78f7af86..6d0562d50b9 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -2089,6 +2089,7 @@ AC_CHECK_FUNCS(\ + getauxval \ + getifaddrs \ + getrandom \ ++ gettid \ + kqueue \ + pipe2 \ + port_create \ +diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c +index 5862cd1666f..d9452e168ab 100644 +--- a/dlls/ntdll/unix/server.c ++++ b/dlls/ntdll/unix/server.c +@@ -1549,6 +1549,8 @@ static int get_unix_tid(void) + int ret = -1; + #ifdef HAVE_PTHREAD_GETTHREADID_NP + ret = pthread_getthreadid_np(); ++#elif defined(HAVE_GETTID) ++ ret = gettid(); + #elif defined(linux) + ret = syscall( __NR_gettid ); + #elif defined(__sun) +-- +2.47.1 + diff --git a/0004-build-fix-undebug-optimize/ps0388-include-Use-__builtin_expect-for-debug-macros.patch b/0004-build-fix-undebug-optimize/ps0388-include-Use-__builtin_expect-for-debug-macros.patch index f9a4587..936f062 100644 --- a/0004-build-fix-undebug-optimize/ps0388-include-Use-__builtin_expect-for-debug-macros.patch +++ b/0004-build-fix-undebug-optimize/ps0388-include-Use-__builtin_expect-for-debug-macros.patch @@ -15,7 +15,7 @@ index 11111111111..11111111111 100644 char name[15]; }; -+#ifdef __GNUC__ ++#if defined(__GNUC__) || defined(__clang__) +# define __WINE_GET_DEBUGGING_UNLIKELY(x) (__builtin_expect(!!(x), 0)) +# define __WINE_GET_DEBUGGING_LIKELY(x) (__builtin_expect(!!(x), 1)) +#else diff --git a/0006-proton-esync-fsync/0117-server-Add-an-object-operation-to-grab-the-esync-fil.patch b/0006-proton-esync-fsync/0117-server-Add-an-object-operation-to-grab-the-esync-fil.patch index d7fb16d..da718c2 100644 --- a/0006-proton-esync-fsync/0117-server-Add-an-object-operation-to-grab-the-esync-fil.patch +++ b/0006-proton-esync-fsync/0117-server-Add-an-object-operation-to-grab-the-esync-fil.patch @@ -1,12 +1,10 @@ -From 37eb12f03153dfad7554e7fee4a621ec501167f7 Mon Sep 17 00:00:00 2001 +From 914fe97f7dc20348ec3e1a2e18bcefa9b7cab463 Mon Sep 17 00:00:00 2001 From: Zebediah Figura Date: Fri, 8 Jun 2018 18:51:40 -0500 -Subject: [PATCH 0438/2346] server: Add an object operation to grab the esync - file descriptor. +Subject: [PATCH] server: Add an object operation to grab the esync file + descriptor. Split off to decrease patch size. - -Wine-Staging: eventfd_synchronization --- server/async.c | 2 ++ server/atom.c | 1 + @@ -27,6 +25,7 @@ Wine-Staging: eventfd_synchronization server/mapping.c | 3 +++ server/mutex.c | 1 + server/named_pipe.c | 5 +++++ + server/object.c | 2 ++ server/object.h | 2 ++ server/process.c | 3 +++ server/queue.c | 2 ++ @@ -42,13 +41,13 @@ Wine-Staging: eventfd_synchronization server/token.c | 1 + server/window.c | 1 + server/winstation.c | 2 ++ - 34 files changed, 68 insertions(+) + 35 files changed, 70 insertions(+) diff --git a/server/async.c b/server/async.c -index 9cb251df5ce..337bba8631b 100644 +index 749c547af4f..2377c737e98 100644 --- a/server/async.c +++ b/server/async.c -@@ -77,6 +77,7 @@ static const struct object_ops async_ops = +@@ -78,6 +78,7 @@ static const struct object_ops async_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ async_signaled, /* signaled */ @@ -56,7 +55,7 @@ index 9cb251df5ce..337bba8631b 100644 async_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ -@@ -676,6 +677,7 @@ static const struct object_ops iosb_ops = +@@ -698,6 +699,7 @@ static const struct object_ops iosb_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ @@ -77,7 +76,7 @@ index ff0799f5880..d9824de8eac 100644 no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/change.c b/server/change.c -index 843e495411c..5f1cf9b880b 100644 +index f42ce066340..d0a90a99261 100644 --- a/server/change.c +++ b/server/change.c @@ -112,6 +112,7 @@ static const struct object_ops dir_ops = @@ -89,7 +88,7 @@ index 843e495411c..5f1cf9b880b 100644 no_signal, /* signal */ dir_get_fd, /* get_fd */ diff --git a/server/clipboard.c b/server/clipboard.c -index 8118a467dd8..8b265f2dcea 100644 +index 91f159bc7c9..0df7fd2f18e 100644 --- a/server/clipboard.c +++ b/server/clipboard.c @@ -76,6 +76,7 @@ static const struct object_ops clipboard_ops = @@ -101,10 +100,10 @@ index 8118a467dd8..8b265f2dcea 100644 no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/completion.c b/server/completion.c -index 6933195e72d..3d4be86a212 100644 +index f9e68c523f1..9093132efac 100644 --- a/server/completion.c +++ b/server/completion.c -@@ -75,6 +75,7 @@ static const struct object_ops completion_ops = +@@ -166,6 +167,7 @@ static const struct object_ops completion_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ completion_signaled, /* signaled */ @@ -173,7 +172,7 @@ index b64283baf4a..1cc9eea6a50 100644 no_signal, /* signal */ console_connection_get_fd, /* get_fd */ diff --git a/server/debugger.c b/server/debugger.c -index 48adb244b09..d85a2000684 100644 +index c59a0abea77..ca04d4c71ce 100644 --- a/server/debugger.c +++ b/server/debugger.c @@ -86,6 +86,7 @@ static const struct object_ops debug_event_ops = @@ -229,10 +228,10 @@ index 436dac6bfe9..f730fa81afa 100644 no_signal, /* signal */ device_file_get_fd, /* get_fd */ diff --git a/server/directory.c b/server/directory.c -index e169cc2d011..dc3f0cf3cf8 100644 +index b37ec969a9e..a6c0e292071 100644 --- a/server/directory.c +++ b/server/directory.c -@@ -70,6 +70,7 @@ static const struct object_ops object_type_ops = +@@ -69,6 +69,7 @@ static const struct object_ops object_type_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ @@ -240,7 +239,7 @@ index e169cc2d011..dc3f0cf3cf8 100644 NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ -@@ -120,6 +121,7 @@ static const struct object_ops directory_ops = +@@ -119,6 +120,7 @@ static const struct object_ops directory_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ @@ -281,10 +280,10 @@ index f1b79b1b35e..c727bfdd1ba 100644 no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/fd.c b/server/fd.c -index 8576882aaa9..f9f747016b3 100644 +index 16328063df6..4ce78db5b33 100644 --- a/server/fd.c +++ b/server/fd.c -@@ -169,6 +169,7 @@ static const struct object_ops fd_ops = +@@ -172,6 +172,7 @@ static const struct object_ops fd_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ @@ -292,7 +291,7 @@ index 8576882aaa9..f9f747016b3 100644 NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ -@@ -210,6 +211,7 @@ static const struct object_ops device_ops = +@@ -213,6 +214,7 @@ static const struct object_ops device_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ @@ -300,7 +299,7 @@ index 8576882aaa9..f9f747016b3 100644 NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ -@@ -250,6 +252,7 @@ static const struct object_ops inode_ops = +@@ -253,6 +255,7 @@ static const struct object_ops inode_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ @@ -308,7 +307,7 @@ index 8576882aaa9..f9f747016b3 100644 NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ -@@ -292,6 +295,7 @@ static const struct object_ops file_lock_ops = +@@ -295,6 +298,7 @@ static const struct object_ops file_lock_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ file_lock_signaled, /* signaled */ @@ -317,7 +316,7 @@ index 8576882aaa9..f9f747016b3 100644 no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/file.c b/server/file.c -index 76c687833c9..26c62809d33 100644 +index 2a839968c25..cbef0c63383 100644 --- a/server/file.c +++ b/server/file.c @@ -94,6 +94,7 @@ static const struct object_ops file_ops = @@ -329,7 +328,7 @@ index 76c687833c9..26c62809d33 100644 no_signal, /* signal */ file_get_fd, /* get_fd */ diff --git a/server/handle.c b/server/handle.c -index 0595fdb403b..d41c7e86454 100644 +index e65831b3b22..e6c5707556f 100644 --- a/server/handle.c +++ b/server/handle.c @@ -126,6 +126,7 @@ static const struct object_ops handle_table_ops = @@ -341,10 +340,10 @@ index 0595fdb403b..d41c7e86454 100644 no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/hook.c b/server/hook.c -index dd3657c2eac..95a588c843b 100644 +index c2d2823cd61..ab4d0e9dd31 100644 --- a/server/hook.c +++ b/server/hook.c -@@ -80,6 +80,7 @@ static const struct object_ops hook_table_ops = +@@ -81,6 +81,7 @@ static const struct object_ops hook_table_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ @@ -353,10 +352,10 @@ index dd3657c2eac..95a588c843b 100644 no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/mailslot.c b/server/mailslot.c -index 2d8697ec9bd..4cf9b73f784 100644 +index 61eceec94e2..92fe938d3b9 100644 --- a/server/mailslot.c +++ b/server/mailslot.c -@@ -74,6 +74,7 @@ static const struct object_ops mailslot_ops = +@@ -81,6 +81,7 @@ static const struct object_ops mailslot_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ @@ -364,7 +363,7 @@ index 2d8697ec9bd..4cf9b73f784 100644 no_satisfied, /* satisfied */ no_signal, /* signal */ mailslot_get_fd, /* get_fd */ -@@ -133,6 +134,7 @@ static const struct object_ops mail_writer_ops = +@@ -142,6 +143,7 @@ static const struct object_ops mail_writer_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ @@ -372,7 +371,7 @@ index 2d8697ec9bd..4cf9b73f784 100644 NULL, /* satisfied */ no_signal, /* signal */ mail_writer_get_fd, /* get_fd */ -@@ -196,6 +198,7 @@ static const struct object_ops mailslot_device_ops = +@@ -207,6 +209,7 @@ static const struct object_ops mailslot_device_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ @@ -380,7 +379,7 @@ index 2d8697ec9bd..4cf9b73f784 100644 no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ -@@ -226,6 +229,7 @@ static const struct object_ops mailslot_device_file_ops = +@@ -237,6 +240,7 @@ static const struct object_ops mailslot_device_file_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ @@ -389,10 +388,10 @@ index 2d8697ec9bd..4cf9b73f784 100644 no_signal, /* signal */ mailslot_device_file_get_fd, /* get_fd */ diff --git a/server/mapping.c b/server/mapping.c -index 7a07575bca2..bc971fa91c4 100644 +index 2bf45780375..b84bb08a77b 100644 --- a/server/mapping.c +++ b/server/mapping.c -@@ -72,6 +72,7 @@ static const struct object_ops ranges_ops = +@@ -67,6 +67,7 @@ static const struct object_ops ranges_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ @@ -400,7 +399,7 @@ index 7a07575bca2..bc971fa91c4 100644 NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ -@@ -108,6 +109,7 @@ static const struct object_ops shared_map_ops = +@@ -103,6 +104,7 @@ static const struct object_ops shared_map_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ @@ -408,7 +407,7 @@ index 7a07575bca2..bc971fa91c4 100644 NULL, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ -@@ -182,6 +184,7 @@ static const struct object_ops mapping_ops = +@@ -176,6 +178,7 @@ static const struct object_ops mapping_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ @@ -429,7 +428,7 @@ index af0efe72132..4785a830e92 100644 mutex_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/named_pipe.c b/server/named_pipe.c -index f3404a33c3b..f28cb14cb45 100644 +index dd8c14b30a9..5880b601d3a 100644 --- a/server/named_pipe.c +++ b/server/named_pipe.c @@ -119,6 +119,7 @@ static const struct object_ops named_pipe_ops = @@ -472,8 +471,28 @@ index f3404a33c3b..f28cb14cb45 100644 no_satisfied, /* satisfied */ no_signal, /* signal */ named_pipe_device_file_get_fd, /* get_fd */ +diff --git a/server/object.c b/server/object.c +index b1665fb5372..0a4d1bede06 100644 +--- a/server/object.c ++++ b/server/object.c +@@ -108,6 +108,7 @@ static const struct object_ops apc_reserve_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -132,6 +133,7 @@ static const struct object_ops completion_reserve_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ diff --git a/server/object.h b/server/object.h -index 66012fbc4af..51ee819415a 100644 +index 6222e3352ed..0a65d0e3892 100644 --- a/server/object.h +++ b/server/object.h @@ -78,6 +78,8 @@ struct object_ops @@ -486,7 +505,7 @@ index 66012fbc4af..51ee819415a 100644 void (*satisfied)(struct object *,struct wait_queue_entry *); /* signal an object */ diff --git a/server/process.c b/server/process.c -index a0d5ea64d97..777bf7c2fe2 100644 +index 49f5c75005f..dc83a089655 100644 --- a/server/process.c +++ b/server/process.c @@ -105,6 +105,7 @@ static const struct object_ops process_ops = @@ -514,10 +533,10 @@ index a0d5ea64d97..777bf7c2fe2 100644 no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/queue.c b/server/queue.c -index 7a4d45659ba..e709f0348f8 100644 +index 984d466b66e..8a95055db40 100644 --- a/server/queue.c +++ b/server/queue.c -@@ -166,6 +166,7 @@ static const struct object_ops msg_queue_ops = +@@ -165,6 +165,7 @@ static const struct object_ops msg_queue_ops = msg_queue_add_queue, /* add_queue */ msg_queue_remove_queue, /* remove_queue */ msg_queue_signaled, /* signaled */ @@ -525,7 +544,7 @@ index 7a4d45659ba..e709f0348f8 100644 msg_queue_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ -@@ -203,6 +204,7 @@ static const struct object_ops thread_input_ops = +@@ -202,6 +203,7 @@ static const struct object_ops thread_input_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ @@ -534,7 +553,7 @@ index 7a4d45659ba..e709f0348f8 100644 no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/registry.c b/server/registry.c -index 0128b8be9d8..c071f42532b 100644 +index cc9a33fff1d..c19e92c9750 100644 --- a/server/registry.c +++ b/server/registry.c @@ -180,6 +180,7 @@ static const struct object_ops key_ops = @@ -546,7 +565,7 @@ index 0128b8be9d8..c071f42532b 100644 no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/request.c b/server/request.c -index 7021741c765..ca83fdbd2af 100644 +index dabcea68309..832a33917b4 100644 --- a/server/request.c +++ b/server/request.c @@ -90,6 +90,7 @@ static const struct object_ops master_socket_ops = @@ -570,10 +589,10 @@ index 53b42a886df..e3889f24601 100644 semaphore_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/serial.c b/server/serial.c -index d665eb7fa35..11e204e4419 100644 +index 209f2e9174e..0d49a996c2a 100644 --- a/server/serial.c +++ b/server/serial.c -@@ -85,6 +85,7 @@ static const struct object_ops serial_ops = +@@ -91,6 +91,7 @@ static const struct object_ops serial_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ @@ -594,10 +613,10 @@ index 19b76d44c16..55cd6aa037e 100644 no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/sock.c b/server/sock.c -index 84c0d4a4931..177e7e6dded 100644 +index d2ec882554f..44a4e3b7b15 100644 --- a/server/sock.c +++ b/server/sock.c -@@ -453,6 +453,7 @@ static const struct object_ops sock_ops = +@@ -471,6 +471,7 @@ static const struct object_ops sock_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ default_fd_signaled, /* signaled */ @@ -605,7 +624,7 @@ index 84c0d4a4931..177e7e6dded 100644 no_satisfied, /* satisfied */ no_signal, /* signal */ sock_get_fd, /* get_fd */ -@@ -3554,6 +3555,7 @@ static const struct object_ops ifchange_ops = +@@ -3599,6 +3600,7 @@ static const struct object_ops ifchange_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ @@ -613,7 +632,7 @@ index 84c0d4a4931..177e7e6dded 100644 no_satisfied, /* satisfied */ no_signal, /* signal */ ifchange_get_fd, /* get_fd */ -@@ -3775,6 +3777,7 @@ static const struct object_ops socket_device_ops = +@@ -3820,6 +3822,7 @@ static const struct object_ops socket_device_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ @@ -634,10 +653,10 @@ index dd28efd3a75..c7f34412317 100644 no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/thread.c b/server/thread.c -index 08742786b03..f579ffddad8 100644 +index 506adfc0a6f..339cdfec1fa 100644 --- a/server/thread.c +++ b/server/thread.c -@@ -100,6 +100,7 @@ static const struct object_ops thread_apc_ops = +@@ -96,6 +96,7 @@ static const struct object_ops thread_apc_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ thread_apc_signaled, /* signaled */ @@ -645,7 +664,7 @@ index 08742786b03..f579ffddad8 100644 no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ -@@ -142,6 +143,7 @@ static const struct object_ops context_ops = +@@ -138,6 +139,7 @@ static const struct object_ops context_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ context_signaled, /* signaled */ @@ -653,7 +672,7 @@ index 08742786b03..f579ffddad8 100644 no_satisfied, /* satisfied */ no_signal, /* signal */ no_get_fd, /* get_fd */ -@@ -191,6 +193,7 @@ static const struct object_ops thread_ops = +@@ -187,6 +189,7 @@ static const struct object_ops thread_ops = add_queue, /* add_queue */ remove_queue, /* remove_queue */ thread_signaled, /* signaled */ @@ -674,10 +693,10 @@ index 96dc9d00ca1..f59902d5607 100644 no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/token.c b/server/token.c -index 4df8d2e0c6e..8b4d2f0c1b1 100644 +index 48ee1eca8fe..479596bdbfa 100644 --- a/server/token.c +++ b/server/token.c -@@ -143,6 +143,7 @@ static const struct object_ops token_ops = +@@ -145,6 +145,7 @@ static const struct object_ops token_ops = no_add_queue, /* add_queue */ NULL, /* remove_queue */ NULL, /* signaled */ @@ -686,7 +705,7 @@ index 4df8d2e0c6e..8b4d2f0c1b1 100644 no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/window.c b/server/window.c -index bd11d0d32de..f6b9a25baa4 100644 +index 412592fbc71..94a70ce890f 100644 --- a/server/window.c +++ b/server/window.c @@ -107,6 +107,7 @@ static const struct object_ops window_ops = @@ -698,7 +717,7 @@ index bd11d0d32de..f6b9a25baa4 100644 no_signal, /* signal */ no_get_fd, /* get_fd */ diff --git a/server/winstation.c b/server/winstation.c -index a0c41ea21a2..ae1123c1d38 100644 +index e5f4bfec357..50fe34aa9ce 100644 --- a/server/winstation.c +++ b/server/winstation.c @@ -76,6 +76,7 @@ static const struct object_ops winstation_ops = @@ -718,5 +737,5 @@ index a0c41ea21a2..ae1123c1d38 100644 no_signal, /* signal */ no_get_fd, /* get_fd */ -- -2.47.0 +2.45.2 diff --git a/0006-proton-esync-fsync/0168-server-Add-an-object-operation-to-grab-the-fsync-shm.patch b/0006-proton-esync-fsync/0168-server-Add-an-object-operation-to-grab-the-fsync-shm.patch index e7a45e8..0084c0a 100644 --- a/0006-proton-esync-fsync/0168-server-Add-an-object-operation-to-grab-the-fsync-shm.patch +++ b/0006-proton-esync-fsync/0168-server-Add-an-object-operation-to-grab-the-fsync-shm.patch @@ -482,6 +482,26 @@ index a90ec606226..1a168f0b395 100644 no_satisfied, /* satisfied */ no_signal, /* signal */ named_pipe_device_file_get_fd, /* get_fd */ +diff --git a/server/object.c b/server/object.c +index b1665fb5372..0a4d1bede06 100644 +--- a/server/object.c ++++ b/server/object.c +@@ -108,6 +108,7 @@ static const struct object_ops apc_reserve_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -132,6 +133,7 @@ static const struct object_ops completion_reserve_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ diff --git a/server/object.h b/server/object.h index 51ee819415a..632b20a548c 100644 --- a/server/object.h diff --git a/0006-proton-esync-fsync/0263-fsync-Always-inline-spinwait-helpers.patch b/0006-proton-esync-fsync/0263-fsync-Always-inline-spinwait-helpers.patch new file mode 100644 index 0000000..390c4e3 --- /dev/null +++ b/0006-proton-esync-fsync/0263-fsync-Always-inline-spinwait-helpers.patch @@ -0,0 +1,47 @@ +From a69b32e12931a3bcf13b7a59d18b8e5ddd0ef565 Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Mon, 6 Jan 2025 09:50:04 -0800 +Subject: [PATCH] fsync: Always inline spinwait helpers. + +--- + dlls/ntdll/unix/fsync.c | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 6db3f6cf7f2..0a9e3c00a41 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -821,8 +821,8 @@ static inline int mwaitx_supported( void ) + * observed_val - If non-NULL, receives the last observed value + * mon_timeout - Max cycles to wait in mwaitx before falling back to spin + */ +-static inline NTSTATUS try_wait_value( volatile int *addr, int expected_val, +- int *observed_val, const unsigned int mon_timeout ) ++static FORCEINLINE NTSTATUS try_wait_value( volatile int *addr, int expected_val, ++ int *observed_val, const unsigned int mon_timeout ) + { + unsigned int attempts = 0; + +@@ -872,8 +872,8 @@ static inline NTSTATUS try_wait_value( volatile int *addr, int expected_val, + return STATUS_UNSUCCESSFUL; + } + +-static inline BOOL try_reacquire_mutex( struct mutex *mutex, int current_tid, +- int *observed_tid, BOOL zero_timeout ) ++static FORCEINLINE BOOL try_reacquire_mutex( struct mutex *mutex, int current_tid, ++ int *observed_tid, BOOL zero_timeout ) + { + int tid = *observed_tid; + +@@ -901,7 +901,7 @@ static inline BOOL try_reacquire_mutex( struct mutex *mutex, int current_tid, + return FALSE; /* fall back to futex */ + } + +-static inline BOOL try_acquire_semaphore( struct semaphore *semaphore, BOOL zero_timeout ) ++static FORCEINLINE BOOL try_acquire_semaphore( struct semaphore *semaphore, BOOL zero_timeout ) + { + int count, new_count; + +-- +2.47.1 + diff --git a/0007-ntsync/0003-server-Add-an-object-operation-to-retrieve-an-in-process-synchronization-object.patch b/0007-ntsync/0003-server-Add-an-object-operation-to-retrieve-an-in-process-synchronization-object.patch index a9135d5..ba7b0bf 100644 --- a/0007-ntsync/0003-server-Add-an-object-operation-to-retrieve-an-in-process-synchronization-object.patch +++ b/0007-ntsync/0003-server-Add-an-object-operation-to-retrieve-an-in-process-synchronization-object.patch @@ -504,7 +504,23 @@ diff --git a/server/object.c b/server/object.c index 29f1ea96129..1af3df77467 100644 --- a/server/object.c +++ b/server/object.c -@@ -538,6 +538,12 @@ struct fd *no_get_fd( struct object *obj ) +@@ -120,6 +120,7 @@ static const struct object_ops apc_reserve_ops = + default_unlink_name, /* unlink_name */ + no_open_file, /* open_file */ + no_kernel_obj_list, /* get_kernel_obj_list */ ++ no_get_inproc_sync, /* get_inproc_sync */ + no_close_handle, /* close_handle */ + no_destroy /* destroy */ + }; +@@ -144,6 +145,7 @@ static const struct object_ops completion_reserve_ops = + default_unlink_name, /* unlink_name */ + no_open_file, /* open_file */ + no_kernel_obj_list, /* get_kernel_obj_list */ ++ no_get_inproc_sync, /* get_inproc_sync */ + no_close_handle, /* close_handle */ + no_destroy /* destroy */ + }; +@@ -639,6 +641,12 @@ struct fd *no_get_fd( struct object *obj ) return NULL; } diff --git a/0007-ntsync/0016-server-Create-in-process-synchronization-objects-for-threads.patch b/0007-ntsync/0016-server-Create-in-process-synchronization-objects-for-threads.patch index 82bd93e..abaab03 100644 --- a/0007-ntsync/0016-server-Create-in-process-synchronization-objects-for-threads.patch +++ b/0007-ntsync/0016-server-Create-in-process-synchronization-objects-for-threads.patch @@ -64,13 +64,13 @@ index 30caeba7622..ea57e7303c0 100644 /* dump a thread on stdout for debugging purposes */ @@ -1394,6 +1407,7 @@ void kill_thread( struct thread *thread, int violent_death ) - fsync_abandon_mutexes( thread ); - if (do_esync()) - esync_abandon_mutexes( thread ); + check_terminated( thread ); + } + else wake_up( &thread->obj, 0 ); + set_inproc_event( thread->inproc_sync ); - if (violent_death) - { - send_thread_signal( thread, SIGQUIT ); + cleanup_thread( thread ); + remove_process_thread( thread->process, thread ); + release_object( thread ); diff --git a/server/thread.h b/server/thread.h index 416b01db318..b5afb565ef4 100644 --- a/server/thread.h diff --git a/0007-ntsync/0032-ntdll-Wait-for-thread-suspension-in-NtSuspendThread.patch b/0007-ntsync/0032-ntdll-Wait-for-thread-suspension-in-NtSuspendThread.patch deleted file mode 100644 index e8b5599..0000000 --- a/0007-ntsync/0032-ntdll-Wait-for-thread-suspension-in-NtSuspendThread.patch +++ /dev/null @@ -1,118 +0,0 @@ -From bfebb2efea2c6059bb9c6323cd01615c6d7246b5 Mon Sep 17 00:00:00 2001 -From: Paul Gofman -Date: Wed, 13 Mar 2024 18:44:31 -0600 -Subject: [PATCH] ntdll: Wait for thread suspension in NtSuspendThread(). - ---- - dlls/ntdll/unix/thread.c | 25 +++++++++++++++++++++---- - server/protocol.def | 6 ++++-- - server/thread.c | 28 ++++++++++++++++++++++++---- - 3 files changed, 49 insertions(+), 10 deletions(-) - -diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c -index 60c833b0320..19ce0fb28a3 100644 ---- a/dlls/ntdll/unix/thread.c -+++ b/dlls/ntdll/unix/thread.c -@@ -1611,19 +1611,36 @@ NTSTATUS WINAPI NtOpenThread( HANDLE *handle, ACCESS_MASK access, - /****************************************************************************** - * NtSuspendThread (NTDLL.@) - */ --NTSTATUS WINAPI NtSuspendThread( HANDLE handle, ULONG *count ) -+NTSTATUS WINAPI NtSuspendThread( HANDLE handle, ULONG *ret_count ) - { -- unsigned int ret; -+ unsigned int ret, count = 0; -+ HANDLE wait_handle = NULL; - - SERVER_START_REQ( suspend_thread ) - { - req->handle = wine_server_obj_handle( handle ); -- if (!(ret = wine_server_call( req ))) -+ if (!(ret = wine_server_call( req )) || ret == STATUS_PENDING) - { -- if (count) *count = reply->count; -+ count = reply->count; -+ wait_handle = wine_server_ptr_handle( reply->wait_handle ); - } - } - SERVER_END_REQ; -+ -+ if (ret == STATUS_PENDING && wait_handle) -+ { -+ NtWaitForSingleObject( wait_handle, FALSE, NULL ); -+ -+ SERVER_START_REQ( suspend_thread ) -+ { -+ req->handle = wine_server_obj_handle( handle ); -+ req->waited_handle = wine_server_obj_handle( wait_handle ); -+ ret = wine_server_call( req ); -+ } -+ SERVER_END_REQ; -+ } -+ -+ if (!ret && ret_count) *ret_count = count; - return ret; - } - -diff --git a/server/protocol.def b/server/protocol.def -index 13aea96e796..b26dbc79962 100644 ---- a/server/protocol.def -+++ b/server/protocol.def -@@ -1107,9 +1107,11 @@ typedef struct - - /* Suspend a thread */ - @REQ(suspend_thread) -- obj_handle_t handle; /* thread handle */ -+ obj_handle_t handle; /* thread handle */ -+ obj_handle_t waited_handle; /* handle waited on */ - @REPLY -- int count; /* new suspend count */ -+ int count; /* new suspend count */ -+ obj_handle_t wait_handle; /* handle to wait on */ - @END - - -diff --git a/server/thread.c b/server/thread.c -index 56f57cefd8f..c41fd0a02dc 100644 ---- a/server/thread.c -+++ b/server/thread.c -@@ -1550,12 +1550,32 @@ DECL_HANDLER(suspend_thread) - { - struct thread *thread; - -- if ((thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME ))) -+ if (req->waited_handle) - { -- if (thread->state == TERMINATED) set_error( STATUS_ACCESS_DENIED ); -- else reply->count = suspend_thread( thread ); -- release_object( thread ); -+ struct context *context; -+ -+ if (!(context = (struct context *)get_handle_obj( current->process, req->waited_handle, -+ 0, &context_ops ))) -+ return; -+ close_handle( current->process, req->waited_handle ); /* avoid extra server call */ -+ set_error( context->status ); -+ release_object( context ); -+ return; - } -+ -+ if (!(thread = get_thread_from_handle( req->handle, THREAD_SUSPEND_RESUME ))) return; -+ -+ if (thread->state != RUNNING) set_error( STATUS_ACCESS_DENIED ); -+ else -+ { -+ reply->count = suspend_thread( thread ); -+ if (!get_error() && thread != current && thread->context && thread->context->status == STATUS_PENDING) -+ { -+ set_error( STATUS_PENDING ); -+ reply->wait_handle = alloc_handle( current->process, thread->context, SYNCHRONIZE, 0 ); -+ } -+ } -+ release_object( thread ); - } - - /* resume a thread */ --- -GitLab - diff --git a/0007-ntsync/0033-ntdll-Use-server_wait_for_object-when-waiting-in-NtSuspendThread.patch b/0007-ntsync/0033-ntdll-Use-server_wait_for_object-when-waiting-in-NtSuspendThread.patch deleted file mode 100644 index 73484a6..0000000 --- a/0007-ntsync/0033-ntdll-Use-server_wait_for_object-when-waiting-in-NtSuspendThread.patch +++ /dev/null @@ -1,26 +0,0 @@ -From dc76375244b13b65297f46e5a0d315fe0e9df642 Mon Sep 17 00:00:00 2001 -From: Stelios Tsampas -Date: Sun, 22 Dec 2024 14:03:35 +0200 -Subject: [PATCH 32/32] ntdll: Use server_wait_for_object() when waiting in - NtSuspendThread - ---- - dlls/ntdll/unix/thread.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c -index 8314d8800b0..e6ffb586015 100644 ---- a/dlls/ntdll/unix/thread.c -+++ b/dlls/ntdll/unix/thread.c -@@ -1644,7 +1644,7 @@ NTSTATUS WINAPI NtSuspendThread( HANDLE handle, ULONG *ret_count ) - - if (ret == STATUS_PENDING && wait_handle) - { -- NtWaitForSingleObject( wait_handle, FALSE, NULL ); -+ server_wait_for_object( wait_handle, FALSE, NULL ); - - SERVER_START_REQ( suspend_thread ) - { --- -2.47.1 - diff --git a/0007-ntsync/0035-ntdll-Increase-cache-entries-to-256.patch b/0007-ntsync/0035-ntdll-Increase-cache-entries-to-256.patch new file mode 100644 index 0000000..cc78517 --- /dev/null +++ b/0007-ntsync/0035-ntdll-Increase-cache-entries-to-256.patch @@ -0,0 +1,40 @@ +From 9d4307cd0ca1a8216cc71ded627106439425eb7a Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Thu, 26 Dec 2024 07:00:02 -0800 +Subject: [PATCH] ntdll: Increase cache entries to 256. + +Match esync/fsync size to reduce 'too many allocated handles, not caching'. +--- + dlls/ntdll/unix/server.c | 2 +- + dlls/ntdll/unix/sync.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c +index 04feea53b3d..295d98b29b9 100644 +--- a/dlls/ntdll/unix/server.c ++++ b/dlls/ntdll/unix/server.c +@@ -1043,7 +1043,7 @@ union fd_cache_entry + C_ASSERT( sizeof(union fd_cache_entry) == sizeof(LONG64) ); + + #define FD_CACHE_BLOCK_SIZE (65536 / sizeof(union fd_cache_entry)) +-#define FD_CACHE_ENTRIES 128 ++#define FD_CACHE_ENTRIES 256 + + static union fd_cache_entry *fd_cache[FD_CACHE_ENTRIES]; + static union fd_cache_entry fd_cache_initial_block[FD_CACHE_BLOCK_SIZE]; +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index b89430f3edc..b06fb6eb378 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -474,7 +474,7 @@ static void release_inproc_sync_obj( struct inproc_sync_cache_entry *cache ) + + + #define INPROC_SYNC_CACHE_BLOCK_SIZE (65536 / sizeof(struct inproc_sync_cache_entry)) +-#define INPROC_SYNC_CACHE_ENTRIES 128 ++#define INPROC_SYNC_CACHE_ENTRIES 256 + + static struct inproc_sync_cache_entry *inproc_sync_cache[INPROC_SYNC_CACHE_ENTRIES]; + static struct inproc_sync_cache_entry inproc_sync_cache_initial_block[INPROC_SYNC_CACHE_BLOCK_SIZE]; +-- +2.47.1 + diff --git a/0008-jpeg-SIMD/0012-makedep-nasm-silent-rule.patch b/0008-jpeg-SIMD/0012-makedep-nasm-silent-rule.patch new file mode 100644 index 0000000..1978e82 --- /dev/null +++ b/0008-jpeg-SIMD/0012-makedep-nasm-silent-rule.patch @@ -0,0 +1,12 @@ +diff --git a/tools/makedep.c b/tools/makedep.c +index e8e5512f5f8..ed5731383fc 100644 +--- a/tools/makedep.c ++++ b/tools/makedep.c +@@ -4427,6 +4427,7 @@ static void output_silent_rules(void) + "GEN", + "LN", + "MSG", ++ "NASM", + "SAST", + "SED", + "TEST", diff --git a/0009-windowing-system-integration/0001-misc/0000-Revert-winex11-Sync-gl-drawable-outside-of-the-win_data-mut.patch b/0009-windowing-system-integration/0001-misc/0000-Revert-winex11-Sync-gl-drawable-outside-of-the-win_data-mut.patch deleted file mode 100644 index 06652b5..0000000 --- a/0009-windowing-system-integration/0001-misc/0000-Revert-winex11-Sync-gl-drawable-outside-of-the-win_data-mut.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 54d82ed4d5483f7569871219acc485b3cb5a224e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Sat, 14 Dec 2024 13:15:42 +0100 -Subject: [PATCH] winex11: Sync gl drawable outside of the win_data mutex. - -Some thread might be destroying a window, calling destroy_client_window -from release_gl_drawable, holding the GL context mutex and trying to -enter the win_data mutex. - -At the same time, another thread might be moving its window, calling -sync_gl_drawable from X11DRV_WindowPosChanged, holding the win_data -mutex and trying to enter the GL context mutex. - -The deadlock was present before already, although less frequently -triggered as sync_gl_drawable was done conditionally if the client -window has been moved. - -This triggers now more frequently in the dxgi:dxgi tests. ---- - dlls/winex11.drv/window.c | 3 +-- - 1 file changed, 1 insertion(+), 2 deletions(-) - -diff --git b/dlls/winex11.drv/window.c a/dlls/winex11.drv/window.c -index bf415f19cb9..d109d6a744e 100644 ---- b/dlls/winex11.drv/window.c -+++ a/dlls/winex11.drv/window.c -@@ -2932,8 +2932,6 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UIN - struct window_rects old_rects; - BOOL was_fullscreen; - -- sync_gl_drawable( hwnd, FALSE ); -- - if (!(data = get_win_data( hwnd ))) return; - - old_style = new_style & ~(WS_VISIBLE | WS_MINIMIZE | WS_MAXIMIZE); -@@ -2952,6 +2950,7 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, HWND owner_hint, UIN - XFlush( gdi_display ); /* make sure painting is done before we move the window */ - - sync_client_position( data, &old_rects ); -+ sync_gl_drawable( hwnd, FALSE ); - - if (!data->whole_window) - { --- -2.47.1 - diff --git a/0009-windowing-system-integration/0001-misc/0004-revert-broken-staging-focus-active.patch b/0009-windowing-system-integration/0001-misc/0004-revert-broken-staging-focus-active.patch new file mode 100644 index 0000000..7537d5d --- /dev/null +++ b/0009-windowing-system-integration/0001-misc/0004-revert-broken-staging-focus-active.patch @@ -0,0 +1,254 @@ +--- b/dlls/winex11.drv/event.c ++++ a/dlls/winex11.drv/event.c +@@ -604,27 +604,16 @@ + */ + static void set_focus( Display *display, HWND hwnd, Time time ) + { ++ HWND focus; +- HWND focus, old_active; + Window win; + GUITHREADINFO threadinfo; + +- old_active = NtUserGetForegroundWindow(); +- + /* prevent recursion */ + x11drv_thread_data()->active_window = hwnd; + + TRACE( "setting foreground window to %p\n", hwnd ); + NtUserSetForegroundWindow( hwnd ); + +- /* Some applications expect that a being deactivated topmost window +- * receives the WM_WINDOWPOSCHANGING/WM_WINDOWPOSCHANGED messages, +- * and perform some specific actions. Chessmaster is one of such apps. +- * Window Manager keeps a topmost window on top in z-oder, so there is +- * no need to actually do anything, just send the messages. +- */ +- if (old_active && (NtUserGetWindowLongW( old_active, GWL_EXSTYLE ) & WS_EX_TOPMOST)) +- NtUserSetWindowPos( old_active, hwnd, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOOWNERZORDER ); +- + threadinfo.cbSize = sizeof(threadinfo); + NtUserGetGUIThreadInfo( 0, &threadinfo ); + focus = threadinfo.hwndFocus; +--- b/dlls/win32u/input.c ++++ a/dlls/win32u/input.c +@@ -1375,9 +1375,6 @@ + send_message( hwnd, WM_ACTIVATE, + MAKEWPARAM( mouse ? WA_CLICKACTIVE : WA_ACTIVE, is_iconic(hwnd) ), + (LPARAM)previous ); +- +- send_message( hwnd, WM_NCPOINTERUP, 0, 0); +- + if (NtUserGetAncestor( hwnd, GA_PARENT ) == get_desktop_window()) + NtUserPostMessage( get_desktop_window(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd ); + +--- b/dlls/win32u/input.c ++++ a/dlls/win32u/input.c +@@ -1633,10 +1633,6 @@ + (LPARAM)previous ); + if (NtUserGetAncestor( hwnd, GA_PARENT ) == get_desktop_window()) + NtUserPostMessage( get_desktop_window(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd ); +- +- if (hwnd == NtUserGetForegroundWindow() && !is_iconic( hwnd )) +- NtUserSetActiveWindow( hwnd ); +- + } + + user_driver->pSetActiveWindow( hwnd ); +--- b/dlls/win32u/driver.c ++++ a/dlls/win32u/driver.c +@@ -838,10 +838,6 @@ + hdc, rect.left - dx, rect.top - dy, SRCCOPY, 0, 0 ); + } + +-static void nulldrv_SetActiveWindow( HWND hwnd ) +-{ +-} +- + static void nulldrv_SetCapture( HWND hwnd, UINT flags ) + { + } +@@ -1245,7 +1241,6 @@ + nulldrv_ProcessEvents, + nulldrv_ReleaseDC, + nulldrv_ScrollDC, +- nulldrv_SetActiveWindow, + nulldrv_SetCapture, + loaderdrv_SetDesktopWindow, + nulldrv_SetFocus, +@@ -1325,7 +1320,6 @@ + SET_USER_FUNC(ProcessEvents); + SET_USER_FUNC(ReleaseDC); + SET_USER_FUNC(ScrollDC); +- SET_USER_FUNC(SetActiveWindow); + SET_USER_FUNC(SetCapture); + SET_USER_FUNC(SetDesktopWindow); + SET_USER_FUNC(SetFocus); +--- b/dlls/win32u/input.c ++++ a/dlls/win32u/input.c +@@ -1887,8 +1887,6 @@ + NtUserPostMessage( get_desktop_window(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd ); + } + +- user_driver->pSetActiveWindow( hwnd ); +- + /* now change focus if necessary */ + if (focus) + { +--- b/dlls/winex11.drv/event.c ++++ a/dlls/winex11.drv/event.c +@@ -576,9 +576,6 @@ + Window win; + GUITHREADINFO threadinfo; + +- /* prevent recursion */ +- x11drv_thread_data()->active_window = hwnd; +- + TRACE( "setting foreground window to %p\n", hwnd ); + NtUserSetForegroundWindow( hwnd ); + +@@ -836,8 +833,6 @@ + + if (!focus_win) + { +- x11drv_thread_data()->active_window = 0; +- + /* Abey : 6-Oct-99. Check again if the focus out window is the + Foreground window, because in most cases the messages sent + above must have already changed the foreground window, in which +--- b/dlls/winex11.drv/init.c ++++ a/dlls/winex11.drv/init.c +@@ -421,7 +421,6 @@ + .pProcessEvents = X11DRV_ProcessEvents, + .pReleaseDC = X11DRV_ReleaseDC, + .pScrollDC = X11DRV_ScrollDC, +- .pSetActiveWindow = X11DRV_SetActiveWindow, + .pSetCapture = X11DRV_SetCapture, + .pSetDesktopWindow = X11DRV_SetDesktopWindow, + .pSetFocus = X11DRV_SetFocus, +--- a/dlls/winex11.drv/window.c ++++ b/dlls/winex11.drv/window.c +@@ -2969,55 +2969,6 @@ BOOL X11DRV_ScrollDC( HDC hdc, INT dx, INT dy, HRGN update ) + return ret; + } + +- +-/*********************************************************************** +- * SetActiveWindow (X11DRV.@) +- */ +-void X11DRV_SetActiveWindow( HWND hwnd ) +-{ +- struct x11drv_thread_data *thread_data = x11drv_init_thread_data(); +- struct x11drv_win_data *data; +- +- TRACE("%p\n", hwnd); +- +- if (thread_data->active_window == hwnd) +- { +- TRACE("ignoring activation for already active window %p\n", hwnd); +- return; +- } +- +- if (!(data = get_win_data( hwnd ))) return; +- +- if (data->managed) +- { +- XEvent xev; +- struct x11drv_win_data *active = get_win_data( thread_data->active_window ); +- DWORD timestamp = NtUserGetThreadInfo()->message_time - EVENT_x11_time_to_win32_time( 0 ); +- +- TRACE("setting _NET_ACTIVE_WINDOW to %p/%lx, current active %p/%lx\n", +- data->hwnd, data->whole_window, active ? active->hwnd : NULL, active ? active->whole_window : 0 ); +- +- xev.xclient.type = ClientMessage; +- xev.xclient.window = data->whole_window; +- xev.xclient.message_type = x11drv_atom(_NET_ACTIVE_WINDOW); +- xev.xclient.serial = 0; +- xev.xclient.display = data->display; +- xev.xclient.send_event = True; +- xev.xclient.format = 32; +- +- xev.xclient.data.l[0] = 1; /* source: application */ +- xev.xclient.data.l[1] = timestamp; +- xev.xclient.data.l[2] = active ? active->whole_window : 0; +- xev.xclient.data.l[3] = 0; +- xev.xclient.data.l[4] = 0; +- XSendEvent( data->display, root_window, False, SubstructureRedirectMask | SubstructureNotifyMask, &xev ); +- +- if (active) release_win_data( active ); +- } +- +- release_win_data( data ); +-} +- + /*********************************************************************** + * SetCapture (X11DRV.@) + */ +--- b/dlls/winex11.drv/x11drv.h ++++ a/dlls/winex11.drv/x11drv.h +@@ -231,7 +231,6 @@ + const RECT *top_rect, DWORD flags ); + extern void X11DRV_ReleaseDC( HWND hwnd, HDC hdc ); + extern BOOL X11DRV_ScrollDC( HDC hdc, INT dx, INT dy, HRGN update ); +-extern void X11DRV_SetActiveWindow( HWND hwnd ); + extern void X11DRV_SetCapture( HWND hwnd, UINT flags ); + extern void X11DRV_SetDesktopWindow( HWND hwnd ); + extern void X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, +@@ -383,7 +382,6 @@ + Display *display; + XEvent *current_event; /* event currently being processed */ + HWND grab_hwnd; /* window that currently grabs the mouse */ +- HWND active_window; /* active window */ + HWND last_focus; /* last window that had focus */ + XIM xim; /* input method */ + HWND last_xic_hwnd; /* last xic window */ +@@ -490,7 +488,6 @@ + XATOM__ICC_PROFILE, + XATOM__KDE_NET_WM_STATE_SKIP_SWITCHER, + XATOM__MOTIF_WM_HINTS, +- XATOM__NET_ACTIVE_WINDOW, + XATOM__NET_STARTUP_INFO_BEGIN, + XATOM__NET_STARTUP_INFO, + XATOM__NET_SUPPORTED, +--- b/dlls/winex11.drv/x11drv_main.c ++++ a/dlls/winex11.drv/x11drv_main.c +@@ -154,7 +154,6 @@ + "_ICC_PROFILE", + "_KDE_NET_WM_STATE_SKIP_SWITCHER", + "_MOTIF_WM_HINTS", +- "_NET_ACTIVE_WINDOW", + "_NET_STARTUP_INFO_BEGIN", + "_NET_STARTUP_INFO", + "_NET_SUPPORTED", +--- b/include/wine/gdi_driver.h ++++ a/include/wine/gdi_driver.h +@@ -316,7 +316,6 @@ + BOOL (*pProcessEvents)(DWORD); + void (*pReleaseDC)(HWND,HDC); + BOOL (*pScrollDC)(HDC,INT,INT,HRGN); +- void (*pSetActiveWindow)(HWND); + void (*pSetCapture)(HWND,UINT); + void (*pSetDesktopWindow)(HWND); + void (*pSetFocus)(HWND); +--- b/dlls/winex11.drv/window.c ++++ a/dlls/winex11.drv/window.c +@@ -278,6 +278,9 @@ + if (style & WS_MINIMIZEBOX) ret |= MWM_DECOR_MINIMIZE; + if (style & WS_MAXIMIZEBOX) ret |= MWM_DECOR_MAXIMIZE; + } ++ if (ex_style & WS_EX_DLGMODALFRAME) ret |= MWM_DECOR_BORDER; ++ else if (style & WS_THICKFRAME) ret |= MWM_DECOR_BORDER; ++ else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) ret |= MWM_DECOR_BORDER; + return ret; + } + +--- b/dlls/winex11.drv/window.c ++++ a/dlls/winex11.drv/window.c +@@ -279,7 +279,7 @@ + if (style & WS_MAXIMIZEBOX) ret |= MWM_DECOR_MAXIMIZE; + } + if (ex_style & WS_EX_DLGMODALFRAME) ret |= MWM_DECOR_BORDER; ++ else if (style & WS_THICKFRAME) ret |= MWM_DECOR_BORDER | MWM_DECOR_RESIZEH; +- else if (style & WS_THICKFRAME) ret |= MWM_DECOR_BORDER; + else if ((style & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME) ret |= MWM_DECOR_BORDER; + return ret; + } diff --git a/0009-windowing-system-integration/0001-misc/0018-winex11-child-window-styles.patch b/0009-windowing-system-integration/0001-misc/0018-winex11-child-window-styles.patch index 448780e..4a393cd 100644 --- a/0009-windowing-system-integration/0001-misc/0018-winex11-child-window-styles.patch +++ b/0009-windowing-system-integration/0001-misc/0018-winex11-child-window-styles.patch @@ -11,7 +11,7 @@ index 8385595563c..b8aed3af540 100644 if (ex_style & WS_EX_TOOLWINDOW) return 0; - if ((ex_style & (WS_EX_LAYERED | WS_EX_COMPOSITED)) == WS_EX_LAYERED) return 0; -+ if (!(style & WS_CAPTION) && (ex_style & (WS_EX_LAYERED | WS_EX_COMPOSITED)) == WS_EX_LAYERED) return 0; ++ if (!((style & WS_CAPTION) == WS_CAPTION) && (ex_style & (WS_EX_LAYERED | WS_EX_COMPOSITED)) == WS_EX_LAYERED) return 0; if ((style & WS_CAPTION) == WS_CAPTION) { diff --git a/0009-windowing-system-integration/0001-misc/0060-winex11-Introduce-a-race-condition-in-wglSwapBuffers.patch b/0009-windowing-system-integration/0001-misc/0060-winex11-Introduce-a-race-condition-in-wglSwapBuffers.patch new file mode 100644 index 0000000..4dab816 --- /dev/null +++ b/0009-windowing-system-integration/0001-misc/0060-winex11-Introduce-a-race-condition-in-wglSwapBuffers.patch @@ -0,0 +1,33 @@ +From 70a3f2cd499350da73220177a8163c50d268bab4 Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Mon, 6 Jan 2025 12:32:24 -0800 +Subject: [PATCH] winex11: Introduce a race condition in wglSwapBuffers. + +Racing is faster. +--- + dlls/winex11.drv/opengl.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/dlls/winex11.drv/opengl.c b/dlls/winex11.drv/opengl.c +index 857c2a878f0..f5ad0a61b9b 100644 +--- a/dlls/winex11.drv/opengl.c ++++ b/dlls/winex11.drv/opengl.c +@@ -2880,13 +2880,13 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) + return FALSE; + } + +- pthread_mutex_lock( &context_mutex ); + if (gl->refresh_swap_interval) + { ++ pthread_mutex_lock( &context_mutex ); + set_swap_interval(gl->drawable, gl->swap_interval); + gl->refresh_swap_interval = FALSE; ++ pthread_mutex_unlock( &context_mutex ); + } +- pthread_mutex_unlock( &context_mutex ); + + switch (gl->type) + { +-- +2.47.1 + diff --git a/0013-server-optimization/0001-misc/ps0033-p0001-server-Don-t-reallocate-a-buffer-for-every-r.patch b/0013-server-optimization/0001-misc/ps0033-p0001-server-Don-t-reallocate-a-buffer-for-every-r.patch deleted file mode 100644 index a382c5c..0000000 --- a/0013-server-optimization/0001-misc/ps0033-p0001-server-Don-t-reallocate-a-buffer-for-every-r.patch +++ /dev/null @@ -1,68 +0,0 @@ -From 02453537d5b801ea62870b745e90cebcfc75a50f Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 13 Mar 2020 16:00:56 +0100 -Subject: [PATCH 1/4] server: Don't reallocate a buffer for every request. - ---- - server/request.c | 14 ++++++++------ - server/thread.c | 1 + - server/thread.h | 1 + - 3 files changed, 10 insertions(+), 6 deletions(-) - -diff --git a/server/request.c b/server/request.c -index 11111111111..11111111111 100644 ---- a/server/request.c -+++ b/server/request.c -@@ -342,11 +342,15 @@ void read_request( struct thread *thread ) - call_req_handler( thread ); - return; - } -- if (!(thread->req_data = malloc( thread->req_toread ))) -+ if (thread->req_data_size < thread->req_toread) - { -- fatal_protocol_error( thread, "no memory for %u bytes request %d\n", -- thread->req_toread, thread->req.request_header.req ); -- return; -+ thread->req_data_size = thread->req_toread; -+ if (!(thread->req_data = realloc( thread->req_data, thread->req_data_size ))) -+ { -+ fatal_protocol_error( thread, "no memory for %u bytes request %d\n", -+ thread->req_toread, thread->req.request_header.req ); -+ return; -+ } - } - } - -@@ -361,8 +365,6 @@ void read_request( struct thread *thread ) - if (!(thread->req_toread -= ret)) - { - call_req_handler( thread ); -- free( thread->req_data ); -- thread->req_data = NULL; - return; - } - } -diff --git a/server/thread.c b/server/thread.c -index 11111111111..11111111111 100644 ---- a/server/thread.c -+++ b/server/thread.c -@@ -326,6 +326,7 @@ static inline void init_thread_structure( struct thread *thread ) - thread->wait = NULL; - thread->error = 0; - thread->req_data = NULL; -+ thread->req_data_size = 0; - thread->req_toread = 0; - thread->reply_data = NULL; - thread->reply_towrite = 0; -diff --git a/server/thread.h b/server/thread.h -index 11111111111..11111111111 100644 ---- a/server/thread.h -+++ b/server/thread.h -@@ -67,6 +67,7 @@ struct thread - unsigned int error; /* current error code */ - union generic_request req; /* current request */ - void *req_data; /* variable-size data for request */ -+ unsigned int req_data_size; - unsigned int req_toread; /* amount of data still to read in request */ - void *reply_data; /* variable-size data for reply */ - unsigned int reply_size; /* size of reply data */ diff --git a/0013-server-optimization/0001-misc/ps0033-p0002-server-Don-t-reallocate-reply-when-size-chan.patch b/0013-server-optimization/0001-misc/ps0033-p0002-server-Don-t-reallocate-reply-when-size-chan.patch deleted file mode 100644 index a4bd80a..0000000 --- a/0013-server-optimization/0001-misc/ps0033-p0002-server-Don-t-reallocate-reply-when-size-chan.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 8c9be738edf2a5ea207a4f3174ce92f4b658391b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 13 Mar 2020 16:32:56 +0100 -Subject: [PATCH 2/4] server: Don't reallocate reply when size changes. - ---- - server/request.c | 12 +++++++++--- - server/thread.c | 6 +++++- - server/thread.h | 2 ++ - 3 files changed, 16 insertions(+), 4 deletions(-) - -diff --git a/server/request.c b/server/request.c -index 11111111111..11111111111 100644 ---- a/server/request.c -+++ b/server/request.c -@@ -160,7 +160,13 @@ void fatal_error( const char *err, ... ) - void *set_reply_data_size( data_size_t size ) - { - assert( size <= get_reply_max_size() ); -- if (size && !(current->reply_data = mem_alloc( size ))) size = 0; -+ if (size > current->rep_data_size) -+ { -+ if (current->rep_data) free(current->rep_data); -+ if (!(current->rep_data = mem_alloc( size ))) size = 0; -+ current->rep_data_size = size; -+ } -+ current->reply_data = current->rep_data; - current->reply_size = size; - return current->reply_data; - } -@@ -235,7 +241,7 @@ void write_reply( struct thread *thread ) - { - if (!(thread->reply_towrite -= ret)) - { -- free( thread->reply_data ); -+ if (thread->reply_data != thread->rep_data) free( thread->reply_data ); - thread->reply_data = NULL; - /* sent everything, can go back to waiting for requests */ - set_fd_events( thread->request_fd, POLLIN ); -@@ -278,7 +284,7 @@ static void send_reply( union generic_reply *reply ) - return; - } - } -- free( current->reply_data ); -+ if (current->reply_data != current->rep_data) free( current->reply_data ); - current->reply_data = NULL; - return; - -diff --git a/server/thread.c b/server/thread.c -index 11111111111..11111111111 100644 ---- a/server/thread.c -+++ b/server/thread.c -@@ -328,6 +328,8 @@ static inline void init_thread_structure( struct thread *thread ) - thread->req_data = NULL; - thread->req_data_size = 0; - thread->req_toread = 0; -+ thread->rep_data = NULL; -+ thread->rep_data_size = 0; - thread->reply_data = NULL; - thread->reply_towrite = 0; - thread->request_fd = NULL; -@@ -600,7 +602,8 @@ static void cleanup_thread( struct thread *thread ) - clear_apc_queue( &thread->system_apc ); - clear_apc_queue( &thread->user_apc ); - free( thread->req_data ); -- free( thread->reply_data ); -+ free( thread->rep_data ); -+ if (thread->reply_data != thread->rep_data) free( thread->reply_data ); - if (thread->request_fd) release_object( thread->request_fd ); - if (thread->reply_fd) release_object( thread->reply_fd ); - if (thread->wait_fd) release_object( thread->wait_fd ); -@@ -622,6 +625,7 @@ static void cleanup_thread( struct thread *thread ) - if (thread->input_shared_mapping) release_object( thread->input_shared_mapping ); - thread->input_shared_mapping = NULL; - thread->req_data = NULL; -+ thread->rep_data = NULL; - thread->reply_data = NULL; - thread->request_fd = NULL; - thread->reply_fd = NULL; -diff --git a/server/thread.h b/server/thread.h -index 11111111111..11111111111 100644 ---- a/server/thread.h -+++ b/server/thread.h -@@ -69,6 +69,8 @@ struct thread - void *req_data; /* variable-size data for request */ - unsigned int req_data_size; - unsigned int req_toread; /* amount of data still to read in request */ -+ void *rep_data; /* variable-size data for reply */ -+ unsigned int rep_data_size; /* size of reply data */ - void *reply_data; /* variable-size data for reply */ - unsigned int reply_size; /* size of reply data */ - unsigned int reply_towrite; /* amount of data still to write in reply */ diff --git a/0013-server-optimization/0001-misc/ps0033-p0003-server-Always-send-replies-with-writev.patch b/0013-server-optimization/0001-misc/ps0033-p0003-server-Always-send-replies-with-writev.patch deleted file mode 100644 index 6ce5b96..0000000 --- a/0013-server-optimization/0001-misc/ps0033-p0003-server-Always-send-replies-with-writev.patch +++ /dev/null @@ -1,63 +0,0 @@ -From eaa41f8fcf0b31d0b08993d70a5ce11f0e5dc11c Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 19 Mar 2020 12:08:33 +0100 -Subject: [PATCH 3/4] server: Always send replies with writev. - ---- - server/request.c | 37 +++++++++++++++---------------------- - 1 file changed, 15 insertions(+), 22 deletions(-) - -diff --git a/server/request.c b/server/request.c -index 11111111111..11111111111 100644 ---- a/server/request.c -+++ b/server/request.c -@@ -256,34 +256,27 @@ void write_reply( struct thread *thread ) - } - - /* send a reply to the current thread */ --static void send_reply( union generic_reply *reply ) -+void send_reply( union generic_reply *reply ) - { - int ret; - -- if (!current->reply_size) -+ struct iovec vec[2]; -+ -+ vec[0].iov_base = (void *)reply; -+ vec[0].iov_len = sizeof(*reply); -+ vec[1].iov_base = current->reply_data; -+ vec[1].iov_len = current->reply_size; -+ -+ if ((ret = writev( get_unix_fd( current->reply_fd ), vec, 2 )) < sizeof(*reply)) goto error; -+ -+ if ((current->reply_towrite = current->reply_size - (ret - sizeof(*reply)))) - { -- if ((ret = write( get_unix_fd( current->reply_fd ), -- reply, sizeof(*reply) )) != sizeof(*reply)) goto error; -+ /* couldn't write it all, wait for POLLOUT */ -+ set_fd_events( current->reply_fd, POLLOUT ); -+ set_fd_events( current->request_fd, 0 ); -+ return; - } -- else -- { -- struct iovec vec[2]; - -- vec[0].iov_base = (void *)reply; -- vec[0].iov_len = sizeof(*reply); -- vec[1].iov_base = current->reply_data; -- vec[1].iov_len = current->reply_size; -- -- if ((ret = writev( get_unix_fd( current->reply_fd ), vec, 2 )) < sizeof(*reply)) goto error; -- -- if ((current->reply_towrite = current->reply_size - (ret - sizeof(*reply)))) -- { -- /* couldn't write it all, wait for POLLOUT */ -- set_fd_events( current->reply_fd, POLLOUT ); -- set_fd_events( current->request_fd, 0 ); -- return; -- } -- } - if (current->reply_data != current->rep_data) free( current->reply_data ); - current->reply_data = NULL; - return; diff --git a/0013-server-optimization/0001-misc/ps0033-p0004-server-Use-a-pool-for-small-most-thread_wait.patch b/0013-server-optimization/0001-misc/ps0033-p0004-server-Use-a-pool-for-small-most-thread_wait.patch deleted file mode 100644 index 9fd42ed..0000000 --- a/0013-server-optimization/0001-misc/ps0033-p0004-server-Use-a-pool-for-small-most-thread_wait.patch +++ /dev/null @@ -1,90 +0,0 @@ -From 016b15925a0ad462983a061a0ec6a09ad34b226d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 13 Mar 2020 17:12:14 +0100 -Subject: [PATCH 4/4] server: Use a pool for small (most) thread_wait allocs. - ---- - server/thread.c | 47 +++++++++++++++++++++++++++++++++++++++++++++-- - 1 file changed, 45 insertions(+), 2 deletions(-) - -diff --git a/server/thread.c b/server/thread.c -index 11111111111..11111111111 100644 ---- a/server/thread.c -+++ b/server/thread.c -@@ -138,6 +138,7 @@ struct thread_wait - { - struct thread_wait *next; /* next wait structure for this thread */ - struct thread *thread; /* owner thread */ -+ int capacity; /* size of objects */ - int count; /* count of objects */ - int flags; - int abandoned; -@@ -1113,6 +1114,47 @@ void set_wait_status( struct wait_queue_entry *entry, int status ) - entry->wait->status = status; - } - -+static struct thread_wait *wait_free_pool; -+ -+static struct thread_wait *thread_wait_alloc(unsigned int count) -+{ -+ struct thread_wait *wait, *pool; -+ unsigned int i; -+ -+ if (count > 2) -+ return mem_alloc( FIELD_OFFSET(struct thread_wait, queues[count]) ); -+ -+ if (!(wait = wait_free_pool)) -+ { -+ unsigned int size = FIELD_OFFSET( struct thread_wait, queues[2] ); -+ if (!(pool = calloc( 64, size ))) -+ return NULL; -+ -+ for (i = 0; i < 64; ++i) -+ { -+ wait = (struct thread_wait *)((char*)pool + size * i); -+ wait->next = wait_free_pool; -+ wait_free_pool = wait; -+ } -+ } -+ -+ wait_free_pool = wait->next; -+ assert(wait); -+ return wait; -+} -+ -+static void thread_wait_free(struct thread_wait *wait) -+{ -+ if (wait->capacity > 2) -+ { -+ free(wait); -+ return; -+ } -+ -+ wait->next = wait_free_pool; -+ wait_free_pool = wait; -+} -+ - /* finish waiting */ - static unsigned int end_wait( struct thread *thread, unsigned int status ) - { -@@ -1142,7 +1184,7 @@ static unsigned int end_wait( struct thread *thread, unsigned int status ) - for (i = 0, entry = wait->queues; i < wait->count; i++, entry++) - entry->obj->ops->remove_queue( entry->obj, entry ); - if (wait->user) remove_timeout_user( wait->user ); -- free( wait ); -+ thread_wait_free( wait ); - return status; - } - -@@ -1154,9 +1196,10 @@ static int wait_on( const select_op_t *select_op, unsigned int count, struct obj - struct wait_queue_entry *entry; - unsigned int i; - -- if (!(wait = mem_alloc( FIELD_OFFSET(struct thread_wait, queues[count]) ))) return 0; -+ if (!(wait = thread_wait_alloc( count ))) { assert(0); return 0; } - wait->next = current->wait; - wait->thread = current; -+ wait->capacity = count; - wait->count = count; - wait->flags = flags; - wait->select = select_op->op; diff --git a/0013-server-optimization/0001-misc/ps0434-server-Optimize-namespace-element-iteration.patch b/0013-server-optimization/0001-misc/ps0434-server-Optimize-namespace-element-iteration.patch index 7a3c5f1..de8681a 100644 --- a/0013-server-optimization/0001-misc/ps0434-server-Optimize-namespace-element-iteration.patch +++ b/0013-server-optimization/0001-misc/ps0434-server-Optimize-namespace-element-iteration.patch @@ -134,9 +134,9 @@ index 11111111111..11111111111 100644 + void *entry; +}; + + #ifndef NDEBUG extern void mark_block_noaccess( void *ptr, size_t size ); - extern void mark_block_uninitialized( void *ptr, size_t size ); - extern void *mem_alloc( size_t size ) __WINE_ALLOC_SIZE(1) __WINE_DEALLOC(free) __WINE_MALLOC; + #endif @@ -164,6 +170,8 @@ extern void *create_named_object( struct object *parent, const struct object_ops extern void *open_named_object( struct object *parent, const struct object_ops *ops, const struct unicode_str *name, unsigned int attributes ); diff --git a/0013-server-optimization/0001-misc/ps0471-server-Allow-cancelling-alerted-asyncs.patch b/0013-server-optimization/0001-misc/ps0471-server-Allow-cancelling-alerted-asyncs.patch new file mode 100644 index 0000000..6fd7b2d --- /dev/null +++ b/0013-server-optimization/0001-misc/ps0471-server-Allow-cancelling-alerted-asyncs.patch @@ -0,0 +1,61 @@ +From 480299bfd0a995e7f26e0e6429cc017ec96814af Mon Sep 17 00:00:00 2001 +From: Jinoh Kang +Date: Fri, 22 Jul 2022 02:31:13 +0900 +Subject: [PATCH] server: Allow cancelling alerted asyncs. + +--- + server/async.c | 17 ++++++++++++++++- + 1 file changed, 16 insertions(+), 1 deletion(-) + +diff --git a/server/async.c b/server/async.c +index 11111111111..11111111111 100644 +--- a/server/async.c ++++ b/server/async.c +@@ -44,6 +44,7 @@ struct async + struct fd *fd; /* fd associated with an unqueued async */ + struct timeout_user *timeout; + unsigned int timeout_status; /* status to report upon timeout */ ++ unsigned int terminate_status;/* pending termination status, or STATUS_PENDING */ + struct event *event; + async_data_t data; /* data for async I/O call */ + struct iosb *iosb; /* I/O status block */ +@@ -168,6 +169,11 @@ void async_terminate( struct async *async, unsigned int status ) + { + struct iosb *iosb = async->iosb; + ++ if (status != STATUS_ALERTED && async->terminate_status == STATUS_PENDING) ++ { ++ async->terminate_status = status; ++ } ++ + if (async->terminated) return; + + async->terminated = 1; +@@ -271,6 +277,7 @@ struct async *create_async( struct fd *fd, struct thread *thread, const async_da + async->queue = NULL; + async->fd = (struct fd *)grab_object( fd ); + async->initial_status = STATUS_PENDING; ++ async->terminate_status = STATUS_PENDING; + async->signaled = 0; + async->pending = 1; + async->wait_handle = 0; +@@ -500,7 +507,15 @@ void async_set_result( struct object *obj, unsigned int status, apc_param_t tota + { + async->terminated = 0; + async->alerted = 0; +- async_reselect( async ); ++ ++ if (async->terminate_status != STATUS_PENDING) ++ { ++ async_terminate( async, async->terminate_status ); ++ } ++ else ++ { ++ async_reselect( async ); ++ } + } + else + { +-- +0.0.0 + diff --git a/0013-server-optimization/0001-misc/ps0741-ntdll-Make-server_select-a-memory-barrier.patch b/0013-server-optimization/0001-misc/ps0741-ntdll-Make-server_select-a-memory-barrier.patch deleted file mode 100644 index d6bdc03..0000000 --- a/0013-server-optimization/0001-misc/ps0741-ntdll-Make-server_select-a-memory-barrier.patch +++ /dev/null @@ -1,26 +0,0 @@ -From c0a9e5a830d878468c8a6450588c732d4d6b6b90 Mon Sep 17 00:00:00 2001 -From: Torge Matthies -Date: Fri, 2 Sep 2022 22:06:44 +0200 -Subject: [PATCH] ntdll: Make server_select a memory barrier. - ---- - dlls/ntdll/unix/server.c | 3 +++ - 1 files changed, 3 insertions(+) - -diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c -index 51a83f472e1..362c7793cbc 100644 ---- a/dlls/ntdll/unix/server.c -+++ b/dlls/ntdll/unix/server.c -@@ -602,6 +602,9 @@ unsigned int server_select( const select_op_t *select_op, data_size_t size, UINT - sigset_t old_set; - int signaled; - data_size_t reply_size; -+ /* ensure writes so far are visible to other threads */ -+ MemoryBarrier(); -+ - struct - { - union apc_call call; --- -GitLab - diff --git a/0013-server-optimization/0001-misc/ps0741EXT-ntdll-Make-server_select-a-memory-barrier.patch b/0013-server-optimization/0001-misc/ps0741EXT-ntdll-Make-server_select-a-memory-barrier.patch new file mode 100644 index 0000000..33eb6f3 --- /dev/null +++ b/0013-server-optimization/0001-misc/ps0741EXT-ntdll-Make-server_select-a-memory-barrier.patch @@ -0,0 +1,22 @@ +Subject: [PATCH] ntdll: Make server_select a memory barrier. + +--- + dlls/ntdll/unix/server.c | 3 +++ + 1 files changed, 3 insertions(+) + +diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c +index 11111111111..11111111111 100644 +--- a/dlls/ntdll/unix/server.c ++++ b/dlls/ntdll/unix/server.c +@@ -739,6 +739,9 @@ unsigned int server_select( const union select_op *select_op, data_size_t size, + pthread_sigmask( SIG_BLOCK, &server_block_set, &old_set ); + for (;;) + { ++ /* ensure writes so far are visible to other threads */ ++ MemoryBarrier(); ++ + SERVER_START_REQ( select ) + { + req->flags = flags; +-- +0.0.0 \ No newline at end of file diff --git a/0013-server-optimization/0001-misc/ps0741EXT-ntdll-try-FPWB-in-contended-NtWaitForAlertByThr.patch b/0013-server-optimization/0001-misc/ps0741EXT-ntdll-try-FPWB-in-contended-NtWaitForAlertByThr.patch new file mode 100644 index 0000000..45e5f33 --- /dev/null +++ b/0013-server-optimization/0001-misc/ps0741EXT-ntdll-try-FPWB-in-contended-NtWaitForAlertByThr.patch @@ -0,0 +1,31 @@ +From 5c62c3e456ae926fd6330e4d030e63c3d23eb70e Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Thu, 26 Dec 2024 03:10:39 -0800 +Subject: [PATCH] ntdll: Try FPWB in contended NtWaitForAlertByThreadId + +Some tentative benchmarks show that this reduces overall contention in +highly contended scenarios. To be removed if I find a test that shows +otherwise. + +--- + dlls/ntdll/unix/sync.c | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 63d96ffdf67..b89430f3edc 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -4083,6 +4083,10 @@ NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEG + end = get_absolute_timeout( timeout ); + } + ++ if (InterlockedExchange( futex, 0 )) ++ return STATUS_ALERTED; ++ NtFlushProcessWriteBuffers(); ++ + while (!InterlockedExchange( futex, 0 )) + { + if (timeout) +-- +2.47.1 + diff --git a/0013-server-optimization/0001-misc/ps5091-server-Try-to-send-asyncs-to-threads-in-APC-wait.patch b/0013-server-optimization/0001-misc/ps5091-server-Try-to-send-asyncs-to-threads-in-APC-wait.patch new file mode 100644 index 0000000..526a001 --- /dev/null +++ b/0013-server-optimization/0001-misc/ps5091-server-Try-to-send-asyncs-to-threads-in-APC-wait.patch @@ -0,0 +1,90 @@ +From 56930df8beac8a28b06ca98272245d01407b86f3 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Thu, 15 Feb 2024 19:39:49 -0600 +Subject: [PATCH] server: Try to send asyncs to threads in APC wait. + +--- + dlls/kernel32/tests/pipe.c | 2 +- + server/thread.c | 36 ++++++++++++++++++++++-------------- + 2 files changed, 23 insertions(+), 15 deletions(-) + +diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c +index aff65fe2864..74cb726110b 100644 +--- a/dlls/kernel32/tests/pipe.c ++++ b/dlls/kernel32/tests/pipe.c +@@ -127,7 +127,7 @@ static void _test_not_signaled(unsigned line, HANDLE handle) + #define test_signaled(h) _test_signaled(__LINE__,h) + static void _test_signaled(unsigned line, HANDLE handle) + { +- DWORD res = WaitForSingleObject(handle, 0); ++ DWORD res = WaitForSingleObject(handle, 50); + ok_(__FILE__,line)(res == WAIT_OBJECT_0, "WaitForSingleObject returned %lu\n", res); + } + +diff --git a/server/thread.c b/server/thread.c +index 56f57cefd8f..5da980c6c75 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -1090,9 +1090,23 @@ static inline int is_in_apc_wait( struct thread *thread ) + (thread->wait && (thread->wait->flags & SELECT_INTERRUPTIBLE))); + } + ++/* try to find a thread in APC wait */ ++static struct thread *find_thread_in_apc_wait( struct process *process ) ++{ ++ struct thread *thread; ++ ++ LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry ) ++ { ++ if (thread->state == TERMINATED || !is_in_apc_wait( thread )) continue; ++ return thread; ++ } ++ return NULL; ++} ++ + /* queue an existing APC to a given thread */ + static int queue_apc( struct process *process, struct thread *thread, struct thread_apc *apc ) + { ++ struct thread *candidate; + struct list *queue; + + if (thread && thread->state == TERMINATED && process) +@@ -1100,19 +1114,7 @@ static int queue_apc( struct process *process, struct thread *thread, struct thr + + if (!thread) /* find a suitable thread inside the process */ + { +- struct thread *candidate; +- +- /* first try to find a waiting thread */ +- LIST_FOR_EACH_ENTRY( candidate, &process->thread_list, struct thread, proc_entry ) +- { +- if (candidate->state == TERMINATED) continue; +- if (is_in_apc_wait( candidate )) +- { +- thread = candidate; +- break; +- } +- } +- if (!thread) ++ if (!(thread = find_thread_in_apc_wait( process ))) + { + /* then use the first one that accepts a signal */ + LIST_FOR_EACH_ENTRY( candidate, &process->thread_list, struct thread, proc_entry ) +@@ -1134,7 +1136,13 @@ static int queue_apc( struct process *process, struct thread *thread, struct thr + /* send signal for system APCs if needed */ + if (queue == &thread->system_apc && list_empty( queue ) && !is_in_apc_wait( thread )) + { +- if (!send_thread_signal( thread, SIGUSR1 )) return 0; ++ if (process && (candidate = find_thread_in_apc_wait( process ))) ++ { ++ /* System APC which can be queued to any thread, found a thread in APC wait first. */ ++ thread = candidate; ++ if (!(queue = get_apc_queue( thread, apc->call.type ))) return 1; ++ } ++ else if (!send_thread_signal( thread, SIGUSR1 )) return 0; + } + /* cancel a possible previous APC with the same owner */ + if (apc->owner) thread_cancel_apc( thread, apc->owner, apc->call.type ); +-- +GitLab + diff --git a/0013-server-optimization/0003-qpc/9300-qpc-support-hardcode-with-old-kernel-check.patch b/0013-server-optimization/0003-qpc/9300-qpc-support-hardcode-with-old-kernel-check.patch index e54cd52..8a1ef0a 100644 --- a/0013-server-optimization/0003-qpc/9300-qpc-support-hardcode-with-old-kernel-check.patch +++ b/0013-server-optimization/0003-qpc/9300-qpc-support-hardcode-with-old-kernel-check.patch @@ -71,7 +71,7 @@ index 11111111111..11111111111 100644 __u32 time_mult; NTSTATUS s; -+#ifndef HAVE_STRUCT_PERF_EVENT_MMAP_PAGE_CAP_USER_TIME_SHORT ++ + /* allow disabling rdtscp if Wine is built with old Linux kernels (e.g. WineBuilder Ubuntu 20.04) */ + { + const char *e = getenv("WINE_DISABLE_TSC"); @@ -81,7 +81,7 @@ index 11111111111..11111111111 100644 + return STATUS_NOT_SUPPORTED; + } + } -+#endif ++ + if (monotonic_time_raw( &ts )) return STATUS_NOT_SUPPORTED; diff --git a/0013-server-optimization/0004-time-wait/0006-server-Use-clock_gettime-for-set_current_time-if-ava.patch b/0013-server-optimization/0004-time-wait/0006-server-Use-clock_gettime-for-set_current_time-if-ava.patch index 5e17b94..fbabfb0 100644 --- a/0013-server-optimization/0004-time-wait/0006-server-Use-clock_gettime-for-set_current_time-if-ava.patch +++ b/0013-server-optimization/0004-time-wait/0006-server-Use-clock_gettime-for-set_current_time-if-ava.patch @@ -26,7 +26,7 @@ index c565b524d58..43bed51d5b0 100644 + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + timeout_t seconds = (timeout_t)ts.tv_sec * TICKS_PER_SEC; -+ timeout_t nanoseconds = (timeout_t)(ts.tv_nsec / 100); ++ timeout_t nanoseconds = (timeout_t)((ts.tv_nsec + 50) / 100); + + current_time = seconds + nanoseconds + ticks_1601_to_1970; +#else diff --git a/0013-server-optimization/0004-time-wait/0007-server-Use-a-dedicated-thread-for-user_shared_data-t.patch b/0013-server-optimization/0004-time-wait/0007-server-Use-a-dedicated-thread-for-user_shared_data-t.patch new file mode 100644 index 0000000..a8f1aef --- /dev/null +++ b/0013-server-optimization/0004-time-wait/0007-server-Use-a-dedicated-thread-for-user_shared_data-t.patch @@ -0,0 +1,193 @@ +From 469ed056f7fe7f24dd1d6991798716286d8de3e5 Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Tue, 5 Nov 2024 08:19:04 -0800 +Subject: [PATCH] server: Use a dedicated thread for user_shared_data time + updates. + +Based on a patch by Torge Matthies. +--- + server/Makefile.in | 2 +- + server/fd.c | 81 +++++++++++++++++++++++++++++++++++++++------- + 2 files changed, 70 insertions(+), 13 deletions(-) + +diff --git a/server/Makefile.in b/server/Makefile.in +index 1c36003b5df..d8a5da3023f 100644 +--- a/server/Makefile.in ++++ b/server/Makefile.in +@@ -52,6 +52,6 @@ SOURCES = \ + wineserver.man.in \ + winstation.c + +-UNIX_LIBS = $(LDEXECFLAGS) $(RT_LIBS) $(INOTIFY_LIBS) $(PROCSTAT_LIBS) ++UNIX_LIBS = $(LDEXECFLAGS) $(RT_LIBS) $(INOTIFY_LIBS) $(PROCSTAT_LIBS) $(PTHREAD_LIBS) + + unicode_EXTRADEFS = -DBINDIR="\"${bindir}\"" -DDATADIR="\"${datadir}\"" +diff --git a/server/fd.c b/server/fd.c +index d114f420120..94a4f68a511 100644 +--- a/server/fd.c ++++ b/server/fd.c +@@ -29,6 +29,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -349,6 +350,8 @@ static file_pos_t max_unix_offset = OFF_T_MAX; + /****************************************************************/ + /* timeouts support */ + ++#define TICKS_PER_100US 1000 ++ + struct timeout_user + { + struct list entry; /* entry in sorted timeout list */ +@@ -364,7 +367,19 @@ timeout_t monotonic_time; + + struct hypervisor_shared_data *hypervisor_shared_data = NULL; + struct _KUSER_SHARED_DATA *user_shared_data = NULL; +-static const int user_shared_data_timeout = 16; ++ ++static const int user_shared_data_timeout_ticks = TICKS_PER_100US; /* 0.1 ms */ ++ ++static inline void ticks_to_timespec(timeout_t ticks, struct timespec *ts) ++{ ++ ts->tv_sec = ticks / TICKS_PER_SEC; ++ ts->tv_nsec = (ticks % TICKS_PER_SEC) * 100; ++} ++ ++static inline timeout_t timespec_to_ticks(const struct timespec *ts) ++{ ++ return (timeout_t)ts->tv_sec * TICKS_PER_SEC + ts->tv_nsec / 100; ++} + + /* 128-bit multiply a by b and return the high 64 bits, same as __umulh */ + static UINT64 multiply_tsc(UINT64 a, UINT64 b) +@@ -405,8 +420,10 @@ static void atomic_store_long(volatile LONG *ptr, LONG value) + #endif + } + +-static void set_user_shared_data_time(void) ++static void set_user_shared_data_time(timeout_t current_time, timeout_t monotonic_time) + { ++ current_time += user_shared_data_timeout_ticks / 2; ++ monotonic_time += user_shared_data_timeout_ticks / 2; + timeout_t tick_count = monotonic_time / 10000; + static timeout_t last_timezone_update; + timeout_t timezone_bias; +@@ -473,7 +488,7 @@ static void set_user_shared_data_time(void) + user_shared_data->QpcBias = qpc_bias; + } + +-void set_current_time(void) ++static void get_current_time(timeout_t *current_time, timeout_t *monotonic_time) + { + static const timeout_t ticks_1601_to_1970 = (timeout_t)86400 * (369 * 365 + 89) * TICKS_PER_SEC; + +@@ -483,22 +498,21 @@ void set_current_time(void) + timeout_t seconds = (timeout_t)ts.tv_sec * TICKS_PER_SEC; + timeout_t nanoseconds = (timeout_t)((ts.tv_nsec + 50) / 100); + +- current_time = seconds + nanoseconds + ticks_1601_to_1970; ++ *current_time = seconds + nanoseconds + ticks_1601_to_1970; + #else + struct timeval now; + gettimeofday(&now, NULL); + timeout_t seconds = (timeout_t)now.tv_sec * TICKS_PER_SEC; + timeout_t microseconds = (timeout_t)now.tv_usec * 10; + +- current_time = seconds + microseconds + ticks_1601_to_1970; ++ *current_time = seconds + microseconds + ticks_1601_to_1970; + #endif +- /* Somehow, the clock_gettime path revealed a memory ordering bug +- * that either didn't ever occur, or only rarely did, with the gettimeofday path +- */ +- // __atomic_signal_fence(__ATOMIC_SEQ_CST); ++ *monotonic_time = monotonic_counter(); ++} + +- monotonic_time = monotonic_counter(); +- if (user_shared_data) set_user_shared_data_time(); ++void set_current_time(void) ++{ ++ get_current_time(¤t_time, &monotonic_time); + } + + /* add a timeout user */ +@@ -588,6 +602,7 @@ static int allocated_users; /* count of allocated entries in the + static struct fd **freelist; /* list of free entries in the array */ + + static int get_next_timeout(void); ++static void *update_user_shared_data_time_thread(void *param); + + static inline void fd_poll_event( struct fd *fd, int event ) + { +@@ -970,7 +985,7 @@ static void remove_poll_user( struct fd *fd, int user ) + /* process pending timeouts and return the time until the next timeout, in milliseconds */ + static int get_next_timeout(void) + { +- int ret = user_shared_data ? user_shared_data_timeout : -1; ++ int ret = user_shared_data ? 2 : -1; + + if (!list_empty( &abs_timeout_list ) || !list_empty( &rel_timeout_list )) + { +@@ -1033,6 +1048,45 @@ static int get_next_timeout(void) + return ret; + } + ++static void *update_user_shared_data_time_thread(void *param) ++{ ++ struct timespec ts; ++ timeout_t next_update_time; ++ ++ get_current_time(¤t_time, &monotonic_time); ++ next_update_time = monotonic_time + user_shared_data_timeout_ticks; ++ ++ while (active_users) ++ { ++ ticks_to_timespec(next_update_time, &ts); ++ ++ while (clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &ts, NULL) == EINTR); ++ ++ get_current_time(¤t_time, &monotonic_time); ++ set_user_shared_data_time(current_time, monotonic_time); ++ ++ next_update_time += user_shared_data_timeout_ticks; ++ ++ if (next_update_time <= monotonic_time) ++ next_update_time = monotonic_time + user_shared_data_timeout_ticks; ++ } ++ return NULL; ++} ++ ++static void start_user_shared_data_time_thread(void) ++{ ++ pthread_t pthread; ++ int policy; ++ struct sched_param param; ++ if (pthread_create( &pthread, NULL, update_user_shared_data_time_thread, NULL )) ++ fatal_error( "failed to create time update thread\n" ); ++ if (!pthread_getschedparam( pthread_self(), &policy, ¶m ) && (policy || param.sched_priority)) ++ if (pthread_setschedparam( pthread, policy | SCHED_RESET_ON_FORK, ¶m )) ++ pthread_setschedparam( pthread, policy, ¶m ); ++ pthread_setname_np( pthread, "usd_time_thread" ); ++ pthread_detach( pthread ); ++} ++ + /* server main poll() loop */ + void main_loop(void) + { +@@ -1041,6 +1095,9 @@ void main_loop(void) + set_current_time(); + server_start_time = current_time; + ++ set_user_shared_data_time(current_time, monotonic_time); ++ start_user_shared_data_time_thread(); ++ + main_loop_epoll(); + /* fall through to normal poll loop */ + +-- +2.47.1 + diff --git a/0013-server-optimization/0004-time-wait/0008-ntdll-Remove-CLOCK_REALTIME_COARSE-path.patch b/0013-server-optimization/0004-time-wait/0008-ntdll-Remove-CLOCK_REALTIME_COARSE-path.patch new file mode 100644 index 0000000..555fbc8 --- /dev/null +++ b/0013-server-optimization/0004-time-wait/0008-ntdll-Remove-CLOCK_REALTIME_COARSE-path.patch @@ -0,0 +1,40 @@ +From 19ad14bef1c8b08bbf058b883e51427bf567bc9c Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Sat, 28 Dec 2024 06:45:10 -0800 +Subject: [PATCH] ntdll: Remove CLOCK_REALTIME_COARSE path. + +--- + dlls/ntdll/unix/sync.c | 17 +---------------- + 1 file changed, 1 insertion(+), 16 deletions(-) + +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index c2c21162332..56eaf5e4b73 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -2869,22 +2869,7 @@ NTSTATUS WINAPI NtQuerySystemTime( LARGE_INTEGER *time ) + { + #ifdef HAVE_CLOCK_GETTIME + struct timespec ts; +- static clockid_t clock_id = CLOCK_MONOTONIC; /* placeholder */ +- +- if (clock_id == CLOCK_MONOTONIC) +- { +-#ifdef CLOCK_REALTIME_COARSE +- struct timespec res; +- +- /* Use CLOCK_REALTIME_COARSE if it has 1 ms or better resolution */ +- if (!clock_getres( CLOCK_REALTIME_COARSE, &res ) && res.tv_sec == 0 && res.tv_nsec <= 1000000) +- clock_id = CLOCK_REALTIME_COARSE; +- else +-#endif /* CLOCK_REALTIME_COARSE */ +- clock_id = CLOCK_REALTIME; +- } +- +- if (!clock_gettime( clock_id, &ts )) ++ if (!clock_gettime( CLOCK_REALTIME, &ts )) + { + time->QuadPart = ticks_from_time_t( ts.tv_sec ) + (ts.tv_nsec + 50) / 100; + } +-- +2.47.1 + diff --git a/0013-server-optimization/0004-time-wait/0010-use_clock_monotonic.patch b/0013-server-optimization/0004-time-wait/0010-use_clock_monotonic.patch index 5fcfa4e..482855d 100644 --- a/0013-server-optimization/0004-time-wait/0010-use_clock_monotonic.patch +++ b/0013-server-optimization/0004-time-wait/0010-use_clock_monotonic.patch @@ -34,153 +34,4 @@ index c5fd378742a..f8aa63b03d1 100644 +#if 0 if (!clock_gettime( CLOCK_MONOTONIC_RAW, &ts )) return (timeout_t)ts.tv_sec * TICKS_PER_SEC + ts.tv_nsec / 100; - #endif -From 1777861cae08f9915c1b8ea2535ada6e3aa911db Mon Sep 17 00:00:00 2001 -From: Zebediah Figura -Date: Wed, 20 Jan 2021 11:28:46 -0600 -Subject: [PATCH] ntdll: Use clock_gettime64 if supported. - ---- - dlls/ntdll/unix/sync.c | 50 +++++++++++++++++++++++++++++++++++++----- - server/request.c | 50 +++++++++++++++++++++++++++++++++++++----- - 2 files changed, 90 insertions(+), 10 deletions(-) - -diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c -index 5d70ef577ad..f665f91342d 100644 ---- a/dlls/ntdll/unix/sync.c -+++ b/dlls/ntdll/unix/sync.c -@@ -82,5 +82,45 @@ static const LARGE_INTEGER zero_timeout; - } - -+#ifndef __NR_clock_gettime64 -+#define __NR_clock_gettime64 403 -+#endif -+ -+struct timespec64 -+{ -+ long long tv_sec; -+ long long tv_nsec; -+}; -+ -+static inline int do_clock_gettime( clockid_t clock_id, ULONGLONG *ticks ) -+{ -+ static int clock_gettime64_supported = -1; -+ struct timespec64 ts64; -+ struct timespec ts; -+ int ret; -+ -+ if (clock_gettime64_supported < 0) -+ { -+ if (!syscall( __NR_clock_gettime64, clock_id, &ts64 )) -+ { -+ clock_gettime64_supported = 1; -+ *ticks = ts64.tv_sec * (ULONGLONG)TICKSPERSEC + ts64.tv_nsec / 100; -+ return 0; -+ } -+ clock_gettime64_supported = 0; -+ } -+ -+ if (clock_gettime64_supported) -+ { -+ if (!(ret = syscall( __NR_clock_gettime64, clock_id, &ts64 ))) -+ *ticks = ts64.tv_sec * (ULONGLONG)TICKSPERSEC + ts64.tv_nsec / 100; -+ return ret; -+ } -+ -+ if (!(ret = clock_gettime( clock_id, &ts ))) -+ *ticks = ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100; -+ return ret; -+} -+ - /* return a monotonic time counter, in Win32 ticks */ - static inline ULONGLONG monotonic_counter(void) - { -@@ -96,13 +136,13 @@ static inline ULONGLONG monotonic_counter(void) - #endif - return mach_absolute_time() * timebase.numer / timebase.denom / 100; - #elif defined(HAVE_CLOCK_GETTIME) -- struct timespec ts; -+ ULONGLONG ticks; - #if 0 -- if (!clock_gettime( CLOCK_MONOTONIC_RAW, &ts )) -- return ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100; -+ if (!do_clock_gettime( CLOCK_MONOTONIC_RAW, &ticks )) -+ return ticks; - #endif -- if (!clock_gettime( CLOCK_MONOTONIC, &ts )) -- return ts.tv_sec * (ULONGLONG)TICKSPERSEC + ts.tv_nsec / 100; -+ if (!do_clock_gettime( CLOCK_MONOTONIC, &ticks )) -+ return ticks; - #endif - gettimeofday( &now, 0 ); - return now.tv_sec * (ULONGLONG)TICKSPERSEC + now.tv_usec * 10 + TICKS_1601_TO_1970 - server_start_time; -diff --git a/server/request.c b/server/request.c -index f8aa63b03d1..e0c30c906dc 100644 ---- a/server/request.c -+++ b/server/request.c -@@ -524,6 +524,46 @@ int send_client_fd( struct process *process, int fd, obj_handle_t handle ) - return -1; - } - -+#ifndef __NR_clock_gettime64 -+#define __NR_clock_gettime64 403 -+#endif -+ -+struct timespec64 -+{ -+ long long tv_sec; -+ long long tv_nsec; -+}; -+ -+static inline int do_clock_gettime( clockid_t clock_id, ULONGLONG *ticks ) -+{ -+ static int clock_gettime64_supported = -1; -+ struct timespec64 ts64; -+ struct timespec ts; -+ int ret; -+ -+ if (clock_gettime64_supported < 0) -+ { -+ if (!syscall( __NR_clock_gettime64, clock_id, &ts64 )) -+ { -+ clock_gettime64_supported = 1; -+ *ticks = ts64.tv_sec * (ULONGLONG)TICKS_PER_SEC + ts64.tv_nsec / 100; -+ return 0; -+ } -+ clock_gettime64_supported = 0; -+ } -+ -+ if (clock_gettime64_supported) -+ { -+ if (!(ret = syscall( __NR_clock_gettime64, clock_id, &ts64 ))) -+ *ticks = ts64.tv_sec * (ULONGLONG)TICKS_PER_SEC + ts64.tv_nsec / 100; -+ return ret; -+ } -+ -+ if (!(ret = clock_gettime( clock_id, &ts ))) -+ *ticks = ts.tv_sec * (ULONGLONG)TICKS_PER_SEC + ts.tv_nsec / 100; -+ return ret; -+} -+ - /* return a monotonic time counter */ - timeout_t monotonic_counter(void) - { -@@ -537,13 +577,13 @@ timeout_t monotonic_counter(void) - #endif - return mach_absolute_time() * timebase.numer / timebase.denom / 100; - #elif defined(HAVE_CLOCK_GETTIME) -- struct timespec ts; -+ ULONGLONG ticks; - #if 0 -- if (!clock_gettime( CLOCK_MONOTONIC_RAW, &ts )) -- return (timeout_t)ts.tv_sec * TICKS_PER_SEC + ts.tv_nsec / 100; -+ if (!do_clock_gettime( CLOCK_MONOTONIC_RAW, &ticks )) -+ return ticks; - #endif -- if (!clock_gettime( CLOCK_MONOTONIC, &ts )) -- return (timeout_t)ts.tv_sec * TICKS_PER_SEC + ts.tv_nsec / 100; -+ if (!do_clock_gettime( CLOCK_MONOTONIC, &ticks )) -+ return ticks; - #endif - return current_time - server_start_time; - } + #endif \ No newline at end of file diff --git a/0013-server-optimization/0004-time-wait/0015-various-try-barely-yielding-see-what-happens.patch b/0013-server-optimization/0004-time-wait/0015-various-try-barely-yielding-see-what-happens.patch new file mode 100644 index 0000000..3ed925c --- /dev/null +++ b/0013-server-optimization/0004-time-wait/0015-various-try-barely-yielding-see-what-happens.patch @@ -0,0 +1,126 @@ +From e269a27ce64b7d0650698fcf6ea064678d94622a Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Sat, 4 Jan 2025 18:07:18 -0800 +Subject: [PATCH] various: try barely yielding, see what happens + +do some other random bullshit along the way + +"sched_yield in practice is also a wet noodle compared to SwitchToThread" + - Anonymous, 2023 +--- + dlls/kernelbase/thread.c | 6 +++++- + dlls/ntdll/unix/server.c | 2 +- + dlls/ntdll/unix/sync.c | 21 ++++----------------- + dlls/win32u/message.c | 4 ++-- + dlls/wow64/sync.c | 4 +++- + 5 files changed, 15 insertions(+), 22 deletions(-) + +diff --git a/dlls/kernelbase/thread.c b/dlls/kernelbase/thread.c +index 12e1777262a..22658c1ac77 100644 +--- a/dlls/kernelbase/thread.c ++++ b/dlls/kernelbase/thread.c +@@ -638,7 +638,11 @@ DWORD WINAPI DECLSPEC_HOTPATCH SuspendThread( HANDLE thread ) + */ + BOOL WINAPI DECLSPEC_HOTPATCH SwitchToThread(void) + { +- return (NtYieldExecution() != STATUS_NO_YIELD_PERFORMED); ++ static BOOL flushed; ++ if (flushed ^= TRUE) ++ NtFlushProcessWriteBuffers(); ++ ++ return flushed; + } + + +diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c +index 6fab7780f04..d133bff8fa9 100644 +--- a/dlls/ntdll/unix/server.c ++++ b/dlls/ntdll/unix/server.c +@@ -814,7 +814,7 @@ unsigned int server_wait( const union select_op *select_op, data_size_t size, UI + /* A test on Windows 2000 shows that Windows always yields during + a wait, but a wait that is hit by an event gets a priority + boost as well. This seems to model that behavior the closest. */ +- if (ret == STATUS_TIMEOUT) NtYieldExecution(); ++ if (ret == STATUS_TIMEOUT) { YieldProcessor(); sched_yield(); } + return ret; + } + +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 05109e77be9..0b30736e3d9 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -2733,22 +2733,9 @@ NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE signal, HANDLE wait, + */ + NTSTATUS WINAPI NtYieldExecution(void) + { +-#ifdef HAVE_SCHED_YIELD +-#ifdef RUSAGE_THREAD +- struct rusage u1, u2; +- int ret; +- +- ret = getrusage( RUSAGE_THREAD, &u1 ); +-#endif +- sched_yield(); +-#ifdef RUSAGE_THREAD +- if (!ret) ret = getrusage( RUSAGE_THREAD, &u2 ); +- if (!ret && u1.ru_nvcsw == u2.ru_nvcsw && u1.ru_nivcsw == u2.ru_nivcsw) return STATUS_NO_YIELD_PERFORMED; +-#endif +- return STATUS_SUCCESS; +-#else +- return STATUS_NO_YIELD_PERFORMED; +-#endif ++ static BOOL toggle; ++ YieldProcessor(); ++ return ((toggle ^= TRUE) ? STATUS_SUCCESS : STATUS_NO_YIELD_PERFORMED); + } + + +@@ -2793,7 +2780,7 @@ NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeou + } + + /* Note that we yield after establishing the desired timeout */ +- NtYieldExecution(); ++ YieldProcessor(); + if (!when) return STATUS_SUCCESS; + + for (;;) +diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c +index 08e0b9e0e08..665bd717df6 100644 +--- a/dlls/win32u/message.c ++++ b/dlls/win32u/message.c +@@ -3121,7 +3121,7 @@ static DWORD wait_message( DWORD count, const HANDLE *handles, + } + } + +- if (ret == WAIT_TIMEOUT && !count && !timeout) NtYieldExecution(); ++ if (ret == WAIT_TIMEOUT && !count && !timeout) sched_yield(); + if (ret == count - 1) get_user_thread_info()->last_driver_time = get_driver_check_time(); + + KeUserDispatchCallback( ¶ms.dispatch, sizeof(params), &ret_ptr, &ret_len ); +@@ -3307,7 +3307,7 @@ BOOL WINAPI NtUserPeekMessage( MSG *msg_out, HWND hwnd, UINT first, UINT last, U + params.locks = *(DWORD *)ret_ptr; + params.restore = TRUE; + } +- NtYieldExecution(); ++ sched_yield(); + KeUserDispatchCallback( ¶ms.dispatch, sizeof(params), &ret_ptr, &ret_len ); + } + return FALSE; +diff --git a/dlls/wow64/sync.c b/dlls/wow64/sync.c +index 54dca19dc1a..b10af4ae514 100644 +--- a/dlls/wow64/sync.c ++++ b/dlls/wow64/sync.c +@@ -1748,7 +1748,9 @@ NTSTATUS WINAPI wow64_NtWaitForSingleObject( UINT *args ) + */ + NTSTATUS WINAPI wow64_NtYieldExecution( UINT *args ) + { +- return NtYieldExecution(); ++ static BOOL toggle; ++ YieldProcessor(); ++ return ((toggle ^= TRUE) ? STATUS_SUCCESS : STATUS_NO_YIELD_PERFORMED); + } + + +-- +2.47.1 + diff --git a/0013-server-optimization/0007-priority/0002-server-Fallback-to-RTKIT-for-thread-priorities.patch b/0013-server-optimization/0007-priority/0002-server-Fallback-to-RTKIT-for-thread-priorities.patch index 79397fd..1ae9a39 100644 --- a/0013-server-optimization/0007-priority/0002-server-Fallback-to-RTKIT-for-thread-priorities.patch +++ b/0013-server-optimization/0007-priority/0002-server-Fallback-to-RTKIT-for-thread-priorities.patch @@ -28,9 +28,9 @@ index 11111111111..11111111111 100644 wineserver.man.in \ winstation.c --UNIX_LIBS = $(LDEXECFLAGS) $(RT_LIBS) $(INOTIFY_LIBS) $(PROCSTAT_LIBS) +-UNIX_LIBS = $(LDEXECFLAGS) $(RT_LIBS) $(INOTIFY_LIBS) $(PROCSTAT_LIBS) $(PTHREAD_LIBS) +UNIX_CFLAGS = $(DBUS_CFLAGS) -+UNIX_LIBS = $(LDEXECFLAGS) $(RT_LIBS) $(INOTIFY_LIBS) $(PROCSTAT_LIBS) $(DBUS_LIBS) ++UNIX_LIBS = $(LDEXECFLAGS) $(RT_LIBS) $(INOTIFY_LIBS) $(PROCSTAT_LIBS) $(PTHREAD_LIBS) $(DBUS_LIBS) unicode_EXTRADEFS = -DBINDIR="\"${bindir}\"" -DDATADIR="\"${datadir}\"" diff --git a/server/thread.c b/server/thread.c diff --git a/0013-server-optimization/0008-shm-opts/ps2002-HACK-win32u-Skip-setting-the-cursor-position-if-the-.patch b/0013-server-optimization/0008-shm-opts/ps2002-HACK-win32u-Skip-setting-the-cursor-position-if-the-.patch new file mode 100644 index 0000000..d663611 --- /dev/null +++ b/0013-server-optimization/0008-shm-opts/ps2002-HACK-win32u-Skip-setting-the-cursor-position-if-the-.patch @@ -0,0 +1,40 @@ +From c3ec84dd82f38df2364e2aa4efd3d6ce85a46616 Mon Sep 17 00:00:00 2001 +From: Torge Matthies +Date: Tue, 29 Mar 2022 02:13:14 +0200 +Subject: [PATCH 2002/7] HACK: win32u: Skip setting the cursor position if the new + position matches the cached one. + +--- + dlls/win32u/input.c | 14 ++++++++++++++ + 1 file changed, 14 insertions(+) + +diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c +index 11111111111..11111111111 100644 +--- a/dlls/win32u/input.c ++++ b/dlls/win32u/input.c +@@ -706,10 +706,22 @@ UINT WINAPI NtUserSendInput( UINT count, INPUT *inputs, int size ) + */ + BOOL WINAPI NtUserSetCursorPos( INT x, INT y ) + { ++ struct object_lock lock = OBJECT_LOCK_INIT; ++ const desktop_shm_t *desktop_shm; ++ NTSTATUS status; + RECT rect = {x, y, x, y}; + BOOL ret; + INT prev_x, prev_y, new_x, new_y; + ++ /* HACK: Doesn't generate any window messages but skips the server call. */ ++ while ((status = get_shared_desktop( &lock, &desktop_shm )) == STATUS_PENDING) ++ { ++ ret = desktop_shm->cursor.last_change != 0 && ++ x == desktop_shm->cursor.x && ++ y == desktop_shm->cursor.y; ++ } ++ if (ret) return TRUE; ++ + rect = map_rect_virt_to_raw( rect, get_thread_dpi() ); + SERVER_START_REQ( set_cursor ) + { +-- +0.0.0 + diff --git a/0013-server-optimization/0008-shm-opts/ps2005-win32u-winex11.drv-Use-input-shared-memory-for-NtUse.patch b/0013-server-optimization/0008-shm-opts/ps2005-win32u-winex11.drv-Use-input-shared-memory-for-NtUse.patch new file mode 100644 index 0000000..89f8977 --- /dev/null +++ b/0013-server-optimization/0008-shm-opts/ps2005-win32u-winex11.drv-Use-input-shared-memory-for-NtUse.patch @@ -0,0 +1,92 @@ +From d48b09e8c30d70bdd95dad7fc23e8823088ee933 Mon Sep 17 00:00:00 2001 +From: Torge Matthies +Date: Fri, 21 Jul 2023 09:50:40 +0200 +Subject: [PATCH 2005/7] win32u, winex11.drv: Use input shared memory for + NtUserGetCursor. + +--- + dlls/win32u/cursoricon.c | 10 ++++++++++ + dlls/win32u/sysparams.c | 3 +++ + dlls/winex11.drv/mouse.c | 11 +++++++++++ + include/ntuser.h | 1 + + 4 files changed, 25 insertions(+) + +diff --git a/dlls/win32u/cursoricon.c b/dlls/win32u/cursoricon.c +index 11111111111..11111111111 100644 +--- a/dlls/win32u/cursoricon.c ++++ b/dlls/win32u/cursoricon.c +@@ -133,8 +133,16 @@ HCURSOR WINAPI NtUserSetCursor( HCURSOR cursor ) + */ + HCURSOR WINAPI NtUserGetCursor(void) + { ++ struct object_lock lock = OBJECT_LOCK_INIT; ++ const input_shm_t *input_shm; ++ NTSTATUS status; + HCURSOR ret; + ++ while ((status = get_shared_input( 0, &lock, &input_shm )) == STATUS_PENDING) ++ { ++ ret = (HCURSOR)input_shm->cursor; ++ } ++ if (status || !ret) + SERVER_START_REQ( set_cursor ) + { + req->flags = 0; +#diff --git a/dlls/win32u/sysparams.c b/dlls/win32u/sysparams.c +#index 11111111111..11111111111 100644 +#--- a/dlls/win32u/sysparams.c +#+++ b/dlls/win32u/sysparams.c +#@@ -6650,6 +6650,9 @@ ULONG_PTR WINAPI NtUserCallTwoParam( ULONG_PTR arg1, ULONG_PTR arg2, ULONG code +# /* temporary exports */ +# case NtUserAllocWinProc: +# return (UINT_PTR)alloc_winproc( (WNDPROC)arg1, arg2 ); +#+ +#+ case NtUserGetInputSharedMemory: +#+ return (ULONG_PTR)get_shared_input( 0, (struct object_lock *)arg1, (const input_shm_t **)arg2 ); +# +# default: +# FIXME( "invalid code %u\n", (int)code ); +# +#diff --git a/dlls/winex11.drv/mouse.c b/dlls/winex11.drv/mouse.c +#index 11111111111..11111111111 100644 +#--- a/dlls/winex11.drv/mouse.c +#+++ b/dlls/winex11.drv/mouse.c +#@@ -481,6 +481,9 @@ void x11drv_xinput2_init( struct x11drv_thread_data *data ) +# static BOOL grab_clipping_window( const RECT *clip ) +# { +# #ifdef HAVE_X11_EXTENSIONS_XINPUT2_H +#+ struct object_lock lock = OBJECT_LOCK_INIT; +#+ const input_shm_t *input_shm; +#+ NTSTATUS status; +# struct x11drv_thread_data *data = x11drv_thread_data(); +# Window clip_window; +# HCURSOR cursor; +#@@ -529,6 +532,12 @@ static BOOL grab_clipping_window( const RECT *clip ) +# GrabModeAsync, GrabModeAsync, clip_window, None, CurrentTime )) +# clipping_cursor = TRUE; +# +#+ while ((status = (void *)NtUserCallTwoParam( &lock, &input_shm, NtUserCallTwoParam_NtUserGetInputSharedMemory )) == STATUS_PENDING) +#+ { +#+ if (input_shm->cursor_count < 0) cursor = 0; +#+ else cursor = input_shm->cursor; +#+ } +#+ if (status) +# SERVER_START_REQ( set_cursor ) +# { +# req->flags = 0; +# +#diff --git a/include/ntuser.h b/include/ntuser.h +#index 11111111111..11111111111 100644 +#--- a/include/ntuser.h +#+++ b/include/ntuser.h +#@@ -1059,6 +1059,7 @@ enum +# NtUserCallTwoParam_IsWindowRectFullScreen, +# /* temporary exports */ +# NtUserAllocWinProc, +#+ NtUserGetInputSharedMemory, +# }; +# +# static inline DLGPROC NtUserGetDialogProc( DLGPROC proc, BOOL ansi ) +-- +0.0.0 + diff --git a/0013-server-optimization/0008-shm-opts/ps2006-HACK-win32u-Use-desktop-shared-memory-for-some-curso.patch b/0013-server-optimization/0008-shm-opts/ps2006-HACK-win32u-Use-desktop-shared-memory-for-some-curso.patch new file mode 100644 index 0000000..a690e3e --- /dev/null +++ b/0013-server-optimization/0008-shm-opts/ps2006-HACK-win32u-Use-desktop-shared-memory-for-some-curso.patch @@ -0,0 +1,78 @@ +From 7a6987c09a860a9afc0474e3b8682394ffb31197 Mon Sep 17 00:00:00 2001 +From: Torge Matthies +Date: Fri, 21 Jul 2023 10:23:14 +0200 +Subject: [PATCH 2006/7] HACK: win32u: Use desktop shared memory for some + cursor-related things. + +This is theoretically racy. +--- + dlls/win32u/cursoricon.c | 12 ++++++++++++ + dlls/win32u/input.c | 20 ++++++++++++++++++++ + 2 files changed, 32 insertions(+) + +diff --git a/dlls/win32u/cursoricon.c b/dlls/win32u/cursoricon.c +index 11111111111..11111111111 100644 +--- a/dlls/win32u/cursoricon.c ++++ b/dlls/win32u/cursoricon.c +@@ -107,11 +107,20 @@ INT WINAPI NtUserShowCursor( BOOL show ) + */ + HCURSOR WINAPI NtUserSetCursor( HCURSOR cursor ) + { ++ struct object_lock lock = OBJECT_LOCK_INIT; ++ const input_shm_t *input_shm; ++ NTSTATUS status; + struct cursoricon_object *obj; + HCURSOR old_cursor; + BOOL ret; + + TRACE( "%p\n", cursor ); ++ while ((status = get_shared_input( 0, &lock, &input_shm )) == STATUS_PENDING) ++ { ++ old_cursor = (HCURSOR)input_shm->cursor; ++ } ++ if (!status && old_cursor == cursor) ++ return old_cursor; + + SERVER_START_REQ( set_cursor ) + { +#diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c +#index 11111111111..11111111111 100644 +#--- a/dlls/win32u/input.c +#+++ b/dlls/win32u/input.c +#@@ -2663,6 +2663,7 @@ BOOL process_wine_clipcursor( HWND hwnd, UINT flags, BOOL reset ) +# */ +# BOOL WINAPI NtUserClipCursor( const RECT *rect ) +# { +#+ const desktop_shm_t *shared = get_desktop_shared_memory(); +# static int keep_inside_window = -1; +# HWND foreground = NtUserGetForegroundWindow(); +# UINT dpi; +#@@ -2631,6 +2632,25 @@ BOOL WINAPI NtUserClipCursor( const RECT *rect ) +# } +# } +# +#+ if (shared) +#+ { +#+ RECT full_rect, *r = rect; +#+ if (!r && NtUserGetWindowRect( NtUserGetForegroundWindow(), &full_rect )) +#+ r = &full_rect; +#+ if (r) +#+ { +#+ SHARED_READ_BEGIN( shared, desktop_shm_t ) +#+ { +#+ ret = r->left == shared->cursor.clip.left && +#+ r->top == shared->cursor.clip.top && +#+ r->right == shared->cursor.clip.right && +#+ r->bottom == shared->cursor.clip.bottom; +#+ } +#+ SHARED_READ_END; +#+ } +#+ if (ret) return TRUE; +#+ } +#+ +# SERVER_START_REQ( set_cursor ) +# { +# if (rect) +-- +0.0.0 + diff --git a/0013-server-optimization/0008-shm-opts/ps3002-HACK-win32u-Return-async-keyboard-state-in-NtUserGet.patch b/0013-server-optimization/0008-shm-opts/ps3002-HACK-win32u-Return-async-keyboard-state-in-NtUserGet.patch new file mode 100644 index 0000000..28e9218 --- /dev/null +++ b/0013-server-optimization/0008-shm-opts/ps3002-HACK-win32u-Return-async-keyboard-state-in-NtUserGet.patch @@ -0,0 +1,39 @@ +From 39046007acf60453c406ebcaf9cea7636718627c Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Sat, 4 Jan 2025 10:15:33 -0800 +Subject: [PATCH] HACK: win32u: Return async keyboard state in + NtUserGetKeyboardState. + +--- + dlls/win32u/input.c | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c +index ddab781b7aa..4be3e2e5a6c 100644 +--- a/dlls/win32u/input.c ++++ b/dlls/win32u/input.c +@@ -996,17 +996,17 @@ SHORT WINAPI NtUserGetKeyState( INT vkey ) + BOOL WINAPI NtUserGetKeyboardState( BYTE *state ) + { + struct object_lock lock = OBJECT_LOCK_INIT; +- const input_shm_t *input_shm; ++ const desktop_shm_t *desktop_shm; + NTSTATUS status; + UINT i; + + TRACE("(%p)\n", state); + +- while ((status = get_shared_input( GetCurrentThreadId(), &lock, &input_shm )) == STATUS_PENDING) +- memcpy( state, (const void *)input_shm->keystate, 256 ); ++ while ((status = get_shared_desktop( &lock, &desktop_shm )) == STATUS_PENDING) ++ memcpy( state, (const void *)desktop_shm->keystate, 256 ); + if (status) memset( state, 0, 256 ); ++ else for (i = 0; i < 256; i++) state[i] &= 0x81; + +- for (i = 0; i < 256; i++) state[i] &= 0x81; + return TRUE; + } + +-- +2.47.1 + diff --git a/0015-bernhard-asan/0057-d3dx9_36-tests-Start-iteration-with-1-to-avoid-buffe.patch b/0015-bernhard-asan/0057-d3dx9_36-tests-Start-iteration-with-1-to-avoid-buffe.patch deleted file mode 100644 index 75d0787..0000000 --- a/0015-bernhard-asan/0057-d3dx9_36-tests-Start-iteration-with-1-to-avoid-buffe.patch +++ /dev/null @@ -1,89 +0,0 @@ -From 1cf4864c496c7edbedd3dada684af956c3d28058 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Bernhard=20=C3=9Cbelacker?= -Date: Sun, 8 Dec 2024 14:54:39 +0100 -Subject: [PATCH 57/86] d3dx9_36/tests: Start iteration with 1 to avoid buffer - underflow. - -029c:fixme:d3dx:d3dx9_effect_compiler_init ID3DXEffectCompiler implementation is only a stub. -================================================================= -==664==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffffe1fd38c at pc 0x00014006ace1 bp 0x7ffffe1fd200 sp 0x7ffffe1fd248 -READ of size 4 at 0x7ffffe1fd38c thread T0 -029c:fixme:dbghelp:elf_search_auxv can't find symbol in module -029c:fixme:dbghelp_dwarf:compute_location Only supporting one breg (r15/343 -> rbx/329) -029c:fixme:dbghelp_dwarf:dwarf2_load_one_entry Unhandled Tag type 0xa at debug_info(abbrev:00007EDE3C520B80,symt:0000000000000000) in ctx(00007EDE80471590,L"d3dx9_36_test") - #0 0x00014006ace0 in test_effect_parameter_value Z:\home\bernhard\data\entwicklung\2024\wine\wine\dlls\d3dx9_36\tests\effect.c - #1 0x00014003dd81 in func_effect Z:\home\bernhard\data\entwicklung\2024\wine\wine\dlls\d3dx9_36\tests\effect.c:8904 - #2 0x000140223327 in main+0x777 (Z:\home\bernhard\data\entwicklung\2024\wine\wine-build\build-asan-pe\64\obj\dlls\d3dx9_36\tests\x86_64-windows\d3dx9_36_test.exe+0x140223327) - #3 0x00014022527f in mainCRTStartup Z:\home\bernhard\data\entwicklung\2024\wine\wine\dlls\msvcrt\crt_main.c:58 - #4 0x6ffffbfd4808 in BaseThreadInitThunk Z:\home\bernhard\data\entwicklung\2024\wine\wine\dlls\kernel32\thread.c:61 - #5 0x6ffffacefa1a (C:\windows\system32\ntdll.dll+0x17000fa1a) - -Address 0x7ffffe1fd38c is located in stack of thread T0 at offset 268 in frame - #0 0x00014005e66f in test_effect_parameter_value Z:\home\bernhard\data\entwicklung\2024\wine\wine\dlls\d3dx9_36\tests\effect.c:1953 - - This frame has 9 object(s): - [32, 56) 'edesc' (line 1962) - [96, 104) 'effect' (line 1963) - [128, 184) 'pdesc' (line 1981) - [224, 228) 'bvalue' (line 1982) - [240, 244) 'ivalue' (line 1983) - [256, 260) 'fvalue' (line 1984) - [272, 464) 'input_value' (line 1985) <== Memory access at offset 268 underflows this variable - [528, 720) 'expected_value' (line 1986) - [784, 808) 'matrix_pointer_array' (line 1988) -HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork - (longjmp, SEH and C++ exceptions *are* supported) -SUMMARY: AddressSanitizer: stack-buffer-overflow Z:\home\bernhard\data\entwicklung\2024\wine\wine\dlls\d3dx9_36\tests\effect.c in test_effect_parameter_value -Shadow bytes around the buggy address: - 0x7ffffe1fd100: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 0x7ffffe1fd180: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 0x7ffffe1fd200: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 0x7ffffe1fd280: f1 f1 f1 f1 00 00 00 f2 f2 f2 f2 f2 00 f2 f2 f2 - 0x7ffffe1fd300: 00 00 00 00 00 00 00 f2 f2 f2 f2 f2 04 f2 04 f2 -=>0x7ffffe1fd380: 04[f2]00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 0x7ffffe1fd400: 00 00 00 00 00 00 00 00 00 00 f2 f2 f2 f2 f2 f2 - 0x7ffffe1fd480: f2 f2 00 00 00 00 00 00 00 00 00 00 00 00 00 00 - 0x7ffffe1fd500: 00 00 00 00 00 00 00 00 00 00 f2 f2 f2 f2 f2 f2 - 0x7ffffe1fd580: f2 f2 00 00 00 f3 f3 f3 f3 f3 f3 f3 00 00 00 00 - 0x7ffffe1fd600: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 -Shadow byte legend (one shadow byte represents 8 application bytes): - Addressable: 00 - Partially addressable: 01 02 03 04 05 06 07 - Heap left redzone: fa - Freed heap region: fd - Stack left redzone: f1 - Stack mid redzone: f2 - Stack right redzone: f3 - Stack after return: f5 - Stack use after scope: f8 - Global redzone: f9 - Global init order: f6 - Poisoned by user: f7 - Container overflow: fc - Array cookie: ac - Intra object redzone: bb - ASan internal: fe - Left alloca redzone: ca - Right alloca redzone: cb -==664==ABORTING -make: *** [Makefile:105962: dlls/d3dx9_36/tests/x86_64-windows/effect.ok] Fehler 1 ---- - dlls/d3dx9_36/tests/effect.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/d3dx9_36/tests/effect.c b/dlls/d3dx9_36/tests/effect.c -index be0a181885d..c55019f0f7a 100644 ---- a/dlls/d3dx9_36/tests/effect.c -+++ b/dlls/d3dx9_36/tests/effect.c -@@ -2258,7 +2258,7 @@ static void test_effect_parameter_value(IDirect3DDevice9 *device) - - /* SetIntArray */ - *input_value = 123456; -- for (l = 0; l < res[k].bytes / sizeof(*input_value); ++l) -+ for (l = 1; l < res[k].bytes / sizeof(*input_value); ++l) - { - *(input_value + l) = *(input_value + l - 1) + 23; - } --- -2.47.1 - diff --git a/0015-bernhard-asan/0062-dwrite-Avoid-heap-buffer-overflow.patch b/0015-bernhard-asan/0062-dwrite-Avoid-heap-buffer-overflow.patch deleted file mode 100644 index 4a5595d..0000000 --- a/0015-bernhard-asan/0062-dwrite-Avoid-heap-buffer-overflow.patch +++ /dev/null @@ -1,109 +0,0 @@ -From 872014f2a491a272219cc8edfc49b7a7ee6e1ef3 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Bernhard=20=C3=9Cbelacker?= -Date: Mon, 16 Dec 2024 20:26:38 +0100 -Subject: [PATCH 62/86] dwrite: Avoid heap-buffer-overflow. - -/home/bernhard/data/entwicklung/2024/wine/wine/tools/runtest -q -P wine -T . -M dwrite.dll -p dlls/dwrite/tests/x86_64-windows/dwrite_test.exe layout && touch dlls/dwrite/tests/x86_64-windows/layout.ok -================================================================= -==1896==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7efe432f1c52 at pc 0x6ffff849c9eb bp 0x7ffffe1fc180 sp 0x7ffffe1fc1c8 -READ of size 2 at 0x7efe432f1c52 thread T0 -051c:fixme:file:server_get_file_info Unsupported info class e - #0 0x6ffff849c9ea in get_cluster_length /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/analyzer.c:1858:32 - #1 0x6ffff849c9ea in dwritetextanalyzer1_ApplyCharacterSpacing /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/analyzer.c:1917:31 - #2 0x6ffff850a8af in IDWriteTextAnalyzer2_ApplyCharacterSpacing /home/bernhard/data/entwicklung/2024/wine/wine-build/build-asan-pe/64/obj\include\dwrite_2.h:1925:12 - #3 0x6ffff850a8af in layout_shape_apply_character_spacing /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/layout.c:1073:9 - #4 0x6ffff850a8af in layout_shape_get_positions /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/layout.c:1118:14 - #5 0x6ffff850a8af in layout_shape_run /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/layout.c:1135:14 - #6 0x6ffff850a8af in layout_compute_runs /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/layout.c:1221:13 - #7 0x6ffff850a8af in layout_compute /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/layout.c:1267:10 - #8 0x6ffff8502cf7 in layout_compute_effective_runs /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/layout.c:2147:10 - #9 0x6ffff84fbdae in layout_update_metrics /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/layout.c:3706:12 - #10 0x6ffff84fbdae in dwritetextlayout_GetMetrics /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/layout.c:3716:10 - #11 0x6ffff84eb8bd in IDWriteTextLayout_GetMetrics /home/bernhard/data/entwicklung/2024/wine/wine-build/build-asan-pe/64/obj\include\dwrite.h:4360:12 - #12 0x6ffff84eb8bd in dwritetrimmingsign_GetMetrics /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/format.c:824:10 - #13 0x0001400b2bfa in IDWriteInlineObject_GetMetrics /home/bernhard/data/entwicklung/2024/wine/wine-build/build-asan-pe/64/obj\include\dwrite.h:2822:12 - #14 0x0001400b2bfa in test_CreateEllipsisTrimmingSign /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/tests/layout.c:1747:10 - #15 0x0001400b2bfa in func_layout /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/tests/layout.c:7084:5 - #16 0x00014013a4bc in run_test /home/bernhard/data/entwicklung/2024/wine\wine/include/wine/test.h:765:5 - #17 0x00014013a4bc in main /home/bernhard/data/entwicklung/2024/wine\wine/include/wine/test.h:884:12 - #18 0x00014013c36f in mainCRTStartup /home/bernhard/data/entwicklung/2024/wine\wine/dlls/msvcrt/crt_main.c:58:11 - #19 0x6ffffbdc4808 in BaseThreadInitThunk /usr/src/packages/BUILD\dlls/kernel32\thread.c:61:5 - #20 0x6ffffaeffa1a in RtlUserThreadStart (C:\windows\system32\ntdll.dll+0x17000fa1a) - -0x7efe432f1c52 is located 0 bytes after 2-byte region [0x7efe432f1c50,0x7efe432f1c52) -allocated by thread T0 here: - #0 0x6ffff91fa276 in calloc /home/bernhard/data/entwicklung/2024/llvm-mingw/2024-10-18/llvm-mingw/llvm-project/compiler-rt\lib/asan/asan_malloc_win.cpp:91:3 - #1 0x6ffff850a545 in layout_shape_apply_character_spacing /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/layout.c:1036:24 - #2 0x6ffff850a545 in layout_shape_get_positions /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/layout.c:1118:14 - #3 0x6ffff850a545 in layout_shape_run /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/layout.c:1135:14 - #4 0x6ffff850a545 in layout_compute_runs /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/layout.c:1221:13 - #5 0x6ffff850a545 in layout_compute /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/layout.c:1267:10 - #6 0x6ffff8502cf7 in layout_compute_effective_runs /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/layout.c:2147:10 - #7 0x6ffff84fbdae in layout_update_metrics /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/layout.c:3706:12 - #8 0x6ffff84fbdae in dwritetextlayout_GetMetrics /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/layout.c:3716:10 - #9 0x6ffff84eb8bd in IDWriteTextLayout_GetMetrics /home/bernhard/data/entwicklung/2024/wine/wine-build/build-asan-pe/64/obj\include\dwrite.h:4360:12 - #10 0x6ffff84eb8bd in dwritetrimmingsign_GetMetrics /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/format.c:824:10 - #11 0x0001400b2bfa in IDWriteInlineObject_GetMetrics /home/bernhard/data/entwicklung/2024/wine/wine-build/build-asan-pe/64/obj\include\dwrite.h:2822:12 - #12 0x0001400b2bfa in test_CreateEllipsisTrimmingSign /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/tests/layout.c:1747:10 - #13 0x0001400b2bfa in func_layout /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/tests/layout.c:7084:5 - #14 0x00014013a4bc in run_test /home/bernhard/data/entwicklung/2024/wine\wine/include/wine/test.h:765:5 - #15 0x00014013a4bc in main /home/bernhard/data/entwicklung/2024/wine\wine/include/wine/test.h:884:12 - #16 0x00014013c36f in mainCRTStartup /home/bernhard/data/entwicklung/2024/wine\wine/dlls/msvcrt/crt_main.c:58:11 - #17 0x6ffffbdc4808 in BaseThreadInitThunk /usr/src/packages/BUILD\dlls/kernel32\thread.c:61:5 - #18 0x6ffffaeffa1a in RtlUserThreadStart (C:\windows\system32\ntdll.dll+0x17000fa1a) - -SUMMARY: AddressSanitizer: heap-buffer-overflow /home/bernhard/data/entwicklung/2024/wine\wine/dlls/dwrite/analyzer.c:1858:32 in get_cluster_length -Shadow bytes around the buggy address: - 0x7efe432f1980: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa - 0x7efe432f1a00: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa - 0x7efe432f1a80: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa - 0x7efe432f1b00: fa fa 00 fa fa fa 00 fa fa fa 00 fa fa fa 00 fa - 0x7efe432f1b80: fa fa 00 fa fa fa 00 fa fa fa 02 fa fa fa 02 fa -=>0x7efe432f1c00: fa fa 04 fa fa fa 00 fa fa fa[02]fa fa fa fa fa - 0x7efe432f1c80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa - 0x7efe432f1d00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa - 0x7efe432f1d80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa - 0x7efe432f1e00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa - 0x7efe432f1e80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa -Shadow byte legend (one shadow byte represents 8 application bytes): - Addressable: 00 - Partially addressable: 01 02 03 04 05 06 07 - Heap left redzone: fa - Freed heap region: fd - Stack left redzone: f1 - Stack mid redzone: f2 - Stack right redzone: f3 - Stack after return: f5 - Stack use after scope: f8 - Global redzone: f9 - Global init order: f6 - Poisoned by user: f7 - Container overflow: fc - Array cookie: ac - Intra object redzone: bb - ASan internal: fe - Left alloca redzone: ca - Right alloca redzone: cb -==1896==ABORTING -make: *** [Makefile:162532: dlls/dwrite/tests/x86_64-windows/layout.ok] Fehler 1 -051c:fixme:kernelbase:AppPolicyGetProcessTerminationMethod FFFFFFFFFFFFFFFA, 00007FFFFEA8FE80 ---- - dlls/dwrite/analyzer.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/dlls/dwrite/analyzer.c b/dlls/dwrite/analyzer.c -index 0fab5b7142e..a26bcf522b7 100644 ---- a/dlls/dwrite/analyzer.c -+++ b/dlls/dwrite/analyzer.c -@@ -1855,7 +1855,7 @@ static inline UINT32 get_cluster_length(UINT16 const *clustermap, UINT32 start, - UINT16 g = clustermap[start]; - UINT32 length = 1; - -- while (start < text_len && clustermap[++start] == g) -+ while ((start + 1) < text_len && clustermap[++start] == g) - length++; - return length; - } --- -2.47.1 - diff --git a/0015-bernhard-asan/0065-gdi32-Return-immediately-with-negative-count.patch b/0015-bernhard-asan/0065-gdi32-Return-immediately-with-negative-count.patch deleted file mode 100644 index f279db0..0000000 --- a/0015-bernhard-asan/0065-gdi32-Return-immediately-with-negative-count.patch +++ /dev/null @@ -1,46 +0,0 @@ -From 0e9169b6e889a4829d29a4e7263f71634e0709a4 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Bernhard=20=C3=9Cbelacker?= -Date: Wed, 4 Dec 2024 22:34:56 +0100 -Subject: [PATCH 65/86] gdi32: Return immediately with negative count. - -gdi32_test font (ASan) - -ASAN_OPTIONS='verbosity=0:windows_hook_rtl_allocators=1' WINEDLLOVERRIDES="$F=n;*.dll=n" WINEDEBUG= wine64 z:/home/bernhard/data/entwicklung/2024/wine/wine-build/build-asan-pe/64/obj/dlls/gdi32/tests/x86_64-windows/gdi32_test.exe font -... -font.c:1213: Tests skipped: TrueType font for charset 136 is not installed -================================================================= -==1536==ERROR: AddressSanitizer: requested allocation size 0xfffffffffffffffe (0x800 after adjustments for alignment, red zones etc.) exceeds maximum supported size of 0x10000000000 (thread T0) -0614:fixme:file:server_get_file_info Unsupported info class e - #0 0x6ffffa61a8a3 in HeapAlloc /home/bernhard/data/entwicklung/2024/llvm-mingw/2024-10-18/llvm-mingw/llvm-project/compiler-rt\lib/asan/asan_malloc_win.cpp:230:3 - #1 0x6ffffc4c9eff in BIDI_Reorder.isra.0 /home/bernhard/data/entwicklung/2024/wine/wine/dlls/gdi32\text.c:397:16 - #2 0x6ffffc4e5f74 in GetTextExtentExPointW /home/bernhard/data/entwicklung/2024/wine/wine/dlls/gdi32\text.c:1393:5 - #3 0x0001400cc8c1 in test_text_extents /home/bernhard/data/entwicklung/2024/wine\wine/dlls/gdi32/tests/font.c:1481:11 - #4 0x0001400cc8c1 in func_font /home/bernhard/data/entwicklung/2024/wine\wine/dlls/gdi32/tests/font.c:7868:5 - #5 0x0001401bcac1 in run_test /home/bernhard/data/entwicklung/2024/wine\wine/include/wine/test.h:765:5 - #6 0x0001401bcac1 in main /home/bernhard/data/entwicklung/2024/wine\wine/include/wine/test.h:884:12 - #7 0x0001401be9cf in mainCRTStartup /home/bernhard/data/entwicklung/2024/wine\wine/dlls/msvcrt/crt_main.c:58:11 - #8 0x6fffffa54808 in BaseThreadInitThunk /home/bernhard/data/entwicklung/2024/wine/wine/dlls/kernel32\thread.c:61:5 - #9 0x6fffffc2fa1a in RtlUserThreadStart (C:\windows\system32\ntdll.dll+0x17000fa1a) - -==1536==HINT: if you don't care about these errors you may set allocator_may_return_null=1 -SUMMARY: AddressSanitizer: allocation-size-too-big /home/bernhard/data/entwicklung/2024/wine/wine/dlls/gdi32\text.c:397:16 in BIDI_Reorder.isra.0 -==1536==ABORTING ---- - dlls/gdi32/text.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/dlls/gdi32/text.c b/dlls/gdi32/text.c -index 2de68f892d8..815b282ef4f 100644 ---- a/dlls/gdi32/text.c -+++ b/dlls/gdi32/text.c -@@ -1384,6 +1384,7 @@ BOOL WINAPI GetTextExtentExPointW( HDC hdc, const WCHAR *str, INT count, INT max - BOOL ret = TRUE; - - if (!(dc_attr = get_dc_attr( hdc ))) return FALSE; -+ if (count < 0) return FALSE; - - bidi_flags = dc_attr->text_align & TA_RTLREADING ? WINE_GCPW_FORCE_RTL : WINE_GCPW_FORCE_LTR; - bidi_flags |= WINE_GCPW_DISABLE_REORDERING; --- -2.47.1 - diff --git a/0015-bernhard-asan/0074-uiautomationcore-Avoid-double-free.patch b/0015-bernhard-asan/0074-uiautomationcore-Avoid-double-free.patch deleted file mode 100644 index bc7a23f..0000000 --- a/0015-bernhard-asan/0074-uiautomationcore-Avoid-double-free.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 11997d5a92c154789ea0f82b36d061fb0ff1fa57 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Bernhard=20=C3=9Cbelacker?= -Date: Tue, 10 Dec 2024 00:12:57 +0100 -Subject: [PATCH 74/86] uiautomationcore: Avoid double-free. - -================================================================= -==692==ERROR: AddressSanitizer: attempting double-free on 0x7f1e587f85f0 in thread T0: -04a8:fixme:file:server_get_file_info Unsupported info class e - #0 0x6ffff8e8a1a1 in free /home/bernhard/data/entwicklung/2024/llvm-mingw/2024-10-18/llvm-mingw/llvm-project/compiler-rt\lib/asan/asan_malloc_win.cpp:71:3 - #1 0x6ffff8465c3b in uia_event_Release /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_event.c:1062:9 - #2 0x6ffff845f44c in IWineUiaEvent_Release /home/bernhard/data/entwicklung/2024/wine/wine-build/build-asan-pe/64/obj\dlls/uiautomationcore\uia_classes.h:256:12 - #3 0x6ffff845f44c in UiaRemoveEvent /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_event.c:1730:5 - #4 0x6ffff8459c90 in uia_event_handler_destroy /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_com_client.c:1392:9 - #5 0x6ffff8459c90 in uia_event_handler_map_entry_destroy /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_com_client.c:1404:9 - #6 0x6ffff8459afc in uia_event_handlers_remove_handlers /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_com_client.c:1429:9 - #7 0x6ffff8459afc in uia_remove_com_event_handler /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_com_client.c:3840:5 - #8 0x6ffff844a738 in uia_iface_RemoveAutomationEventHandler /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_com_client.c:3861:10 - #9 0x000140053426 in IUIAutomation_RemoveAutomationEventHandler /home/bernhard/data/entwicklung/2024/wine/wine-build/build-asan-pe/64/obj\include\uiautomationclient.h:18546:12 - #10 0x000140053426 in test_IUIAutomationEventHandler /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/tests/uiautomation.c:15125:10 - #11 0x000140053426 in test_CUIAutomation_event_handlers /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/tests/uiautomation.c:16202:5 - #12 0x000140053426 in test_CUIAutomation /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/tests/uiautomation.c:16357:5 - #13 0x00014000f641 in func_uiautomation /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/tests/uiautomation.c:18683:5 - #14 0x0001400f87b3 in run_test /home/bernhard/data/entwicklung/2024/wine\wine/include/wine/test.h:765:5 - #15 0x0001400f81fb in main /home/bernhard/data/entwicklung/2024/wine\wine/include/wine/test.h - #16 0x0001400fa12f in mainCRTStartup /home/bernhard/data/entwicklung/2024/wine\wine/dlls/msvcrt/crt_main.c:58:11 - #17 0x6ffffc1c4808 in BaseThreadInitThunk /home/bernhard/data/entwicklung/2024/wine/wine/dlls/kernel32\thread.c:61:5 - #18 0x6ffffc39fa1a in RtlUserThreadStart (C:\windows\system32\ntdll.dll+0x17000fa1a) - -0x7f1e587f85f0 is located 0 bytes inside of 32-byte region [0x7f1e587f85f0,0x7f1e587f8610) -freed by thread T0 here: - #0 0x6ffff8e8a1a1 in free /home/bernhard/data/entwicklung/2024/llvm-mingw/2024-10-18/llvm-mingw/llvm-project/compiler-rt\lib/asan/asan_malloc_win.cpp:71:3 - #1 0x6ffff8465ff1 in uia_event_advise_events /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_event.c:1107:9 - #2 0x6ffff845f3a2 in IWineUiaEvent_advise_events /home/bernhard/data/entwicklung/2024/wine/wine-build/build-asan-pe/64/obj\dlls/uiautomationcore\uia_classes.h:260:12 - #3 0x6ffff845f3a2 in uia_event_advise /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_event.c:1567:10 - #4 0x6ffff845f3a2 in UiaRemoveEvent /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_event.c:1719:10 - #5 0x6ffff8459c90 in uia_event_handler_destroy /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_com_client.c:1392:9 - #6 0x6ffff8459c90 in uia_event_handler_map_entry_destroy /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_com_client.c:1404:9 - #7 0x6ffff8459afc in uia_event_handlers_remove_handlers /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_com_client.c:1429:9 - #8 0x6ffff8459afc in uia_remove_com_event_handler /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_com_client.c:3840:5 - #9 0x6ffff844a738 in uia_iface_RemoveAutomationEventHandler /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_com_client.c:3861:10 - #10 0x000140053426 in IUIAutomation_RemoveAutomationEventHandler /home/bernhard/data/entwicklung/2024/wine/wine-build/build-asan-pe/64/obj\include\uiautomationclient.h:18546:12 - #11 0x000140053426 in test_IUIAutomationEventHandler /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/tests/uiautomation.c:15125:10 - #12 0x000140053426 in test_CUIAutomation_event_handlers /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/tests/uiautomation.c:16202:5 - #13 0x000140053426 in test_CUIAutomation /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/tests/uiautomation.c:16357:5 - #14 0x00014000f641 in func_uiautomation /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/tests/uiautomation.c:18683:5 - #15 0x0001400f87b3 in run_test /home/bernhard/data/entwicklung/2024/wine\wine/include/wine/test.h:765:5 - #16 0x0001400f81fb in main /home/bernhard/data/entwicklung/2024/wine\wine/include/wine/test.h - #17 0x0001400fa12f in mainCRTStartup /home/bernhard/data/entwicklung/2024/wine\wine/dlls/msvcrt/crt_main.c:58:11 - #18 0x6ffffc1c4808 in BaseThreadInitThunk /home/bernhard/data/entwicklung/2024/wine/wine/dlls/kernel32\thread.c:61:5 - #19 0x6ffffc39fa1a in RtlUserThreadStart (C:\windows\system32\ntdll.dll+0x17000fa1a) - -previously allocated by thread T0 here: - #0 0x6ffff8e8a2c1 in malloc /home/bernhard/data/entwicklung/2024/llvm-mingw/2024-10-18/llvm-mingw/llvm-project/compiler-rt\lib/asan/asan_malloc_win.cpp:80:3 - #1 0x6ffff8e8a5f8 in _recalloc /home/bernhard/data/entwicklung/2024/llvm-mingw/2024-10-18/llvm-mingw/llvm-project/compiler-rt\lib/asan/asan_malloc_win.cpp:131:21 - #2 0x6ffff845d46d in uia_array_reserve /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_private.h:204:20 - #3 0x6ffff845d46d in uia_event_add_event_adviser /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_event.c:1275:10 - #4 0x6ffff845d46d in uia_event_add_provider_event_adviser /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_event.c:1420:10 - #5 0x6ffff8442640 in uia_provider_attach_event /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_client.c:1920:18 - #6 0x6ffff8434b12 in IWineUiaProvider_attach_event /home/bernhard/data/entwicklung/2024/wine/wine-build/build-asan-pe/64/obj\dlls/uiautomationcore\uia_classes.h:430:12 - #7 0x6ffff8434b12 in attach_event_to_node_provider /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_client.c:375:10 - #8 0x6ffff8434b12 in attach_event_to_uia_node /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_client.c:1345:14 - #9 0x6ffff845e505 in uia_add_clientside_event /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_event.c:1647:10 - #10 0x6ffff8457b8e in uia_add_com_event_handler /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_com_client.c:3784:10 - #11 0x6ffff844a517 in uia_iface_AddAutomationEventHandler /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_com_client.c:3823:10 - #12 0x000140053254 in IUIAutomation_AddAutomationEventHandler /home/bernhard/data/entwicklung/2024/wine/wine-build/build-asan-pe/64/obj\include\uiautomationclient.h:18543:12 - #13 0x000140053254 in test_IUIAutomationEventHandler /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/tests/uiautomation.c:15119:10 - #14 0x000140053254 in test_CUIAutomation_event_handlers /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/tests/uiautomation.c:16202:5 - #15 0x000140053254 in test_CUIAutomation /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/tests/uiautomation.c:16357:5 - #16 0x00014000f641 in func_uiautomation /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/tests/uiautomation.c:18683:5 - #17 0x0001400f87b3 in run_test /home/bernhard/data/entwicklung/2024/wine\wine/include/wine/test.h:765:5 - #18 0x0001400f81fb in main /home/bernhard/data/entwicklung/2024/wine\wine/include/wine/test.h - #19 0x0001400fa12f in mainCRTStartup /home/bernhard/data/entwicklung/2024/wine\wine/dlls/msvcrt/crt_main.c:58:11 - #20 0x6ffffc1c4808 in BaseThreadInitThunk /home/bernhard/data/entwicklung/2024/wine/wine/dlls/kernel32\thread.c:61:5 - #21 0x6ffffc39fa1a in RtlUserThreadStart (C:\windows\system32\ntdll.dll+0x17000fa1a) - -SUMMARY: AddressSanitizer: double-free /home/bernhard/data/entwicklung/2024/wine\wine/dlls/uiautomationcore/uia_event.c:1062:9 in uia_event_Release -==692==ABORTING -04a8:fixme:kernelbase:AppPolicyGetProcessTerminationMethod FFFFFFFFFFFFFFFA, 00007FFFFEA8FE80 -make: *** [Makefile:377475: dlls/uiautomationcore/tests/x86_64-windows/uiautomation.ok] Fehler 1 ---- - dlls/uiautomationcore/uia_event.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/dlls/uiautomationcore/uia_event.c b/dlls/uiautomationcore/uia_event.c -index 0106be09999..b36ed813e95 100644 ---- a/dlls/uiautomationcore/uia_event.c -+++ b/dlls/uiautomationcore/uia_event.c -@@ -1105,6 +1105,7 @@ static HRESULT WINAPI uia_event_advise_events(IWineUiaEvent *iface, BOOL advise_ - for (i = 0; i < event->event_advisers_count; i++) - IWineUiaEventAdviser_Release(event->event_advisers[i]); - free(event->event_advisers); -+ event->event_advisers = NULL; - event->event_advisers_count = event->event_advisers_arr_size = 0; - } - --- -2.47.1 - diff --git a/0015-bernhard-asan/0085-ntdll-Avoid-merging-of-memcpy-and-memmove.patch b/0015-bernhard-asan/0085-ntdll-Avoid-merging-of-memcpy-and-memmove.patch deleted file mode 100644 index dc13543..0000000 --- a/0015-bernhard-asan/0085-ntdll-Avoid-merging-of-memcpy-and-memmove.patch +++ /dev/null @@ -1,92 +0,0 @@ -From 5e10edc1cdc88caabccfb6076e02e3c0ad5d2402 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Bernhard=20=C3=9Cbelacker?= -Date: Tue, 17 Dec 2024 23:25:29 +0100 -Subject: [PATCH 85/86] ntdll: Avoid merging of memcpy and memmove. - -They are identical in Wine, maybe therefore the compiler merges -them into a single _memcpy, so both can handle overlapping areas. - -But ASan does not know Wine's memcpy can handle it -and therefore triggers the error. - - -================================================================= -==640==ERROR: AddressSanitizer: memcpy-param-overlap: memory ranges [0x00857b20,0x00857b2e) and [0x00857b21, 0x00857b2f) overlap -02e4:fixme:msvcrt:_set_abort_behavior _WRITE_CALL_REPORTFAULT unhandled -02e4:fixme:file:server_get_file_info Unsupported info class e - #0 0x76e323d1 in memcpy /home/bernhard/data/entwicklung/2024/llvm-mingw/2024-10-18/llvm-mingw/llvm-project/compiler-rt\lib/asan/../sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc:115:5 - #1 0x7891968e in RtlMoveMemory /usr/src/packages/BUILD\dlls/ntdll\string.c:265:13 - #2 0x00655e6e in test_RtlMoveMemory /home/bernhard/data/entwicklung/2024/wine\wine/dlls/ntdll/tests/rtl.c:302:22 - #3 0x00655e6e in func_rtl /home/bernhard/data/entwicklung/2024/wine\wine/dlls/ntdll/tests/rtl.c:4077:5 - #4 0x00776711 in run_test /home/bernhard/data/entwicklung/2024/wine\wine/include/wine/test.h:765:5 - #5 0x00776711 in main /home/bernhard/data/entwicklung/2024/wine\wine/include/wine/test.h:884:12 - #6 0x0077868b in mainCRTStartup /home/bernhard/data/entwicklung/2024/wine\wine/dlls/msvcrt/crt_main.c:58:11 - #7 0x7877ea3f in BaseThreadInitThunk (C:\windows\system32\kernel32.dll+0x7b80ea3f) - #8 0x788fce82 in call_thread_func_wrapper (C:\windows\system32\ntdll.dll+0x7bc0ce82) - #9 0x789304b4 in call_thread_func /usr/src/packages/BUILD\dlls/ntdll\signal_i386.c:524:9 - -Address 0x00857b20 is a wild pointer inside of access range of size 0x0000000e. -Address 0x00857b21 is a wild pointer inside of access range of size 0x0000000e. -SUMMARY: AddressSanitizer: memcpy-param-overlap /usr/src/packages/BUILD\dlls/ntdll\string.c:265:13 in RtlMoveMemory -==640==ABORTING -make: *** [Makefile:305163: dlls/ntdll/tests/i386-windows/rtl.ok] Fehler 1 - - - -$ i686-w64-mingw32-objdump --disassemble build-32/obj/dlls/ntdll/i386-windows/ntdll.dll | grep -E "RtlMoveMemory|RtlCopyMemory" -A13 -7bc19500 <_RtlCopyMemory@12>: -7bc19500: 55 push %ebp -7bc19501: 89 e5 mov %esp,%ebp -7bc19503: 83 ec 0c sub $0xc,%esp -7bc19506: 8b 45 10 mov 0x10(%ebp),%eax -7bc19509: 89 44 24 08 mov %eax,0x8(%esp) -7bc1950d: 8b 45 0c mov 0xc(%ebp),%eax -7bc19510: 89 44 24 04 mov %eax,0x4(%esp) -7bc19514: 8b 45 08 mov 0x8(%ebp),%eax -7bc19517: 89 04 24 mov %eax,(%esp) -7bc1951a: e8 11 71 03 00 call 7bc50630 <_memcpy> -7bc1951f: c9 leave -7bc19520: c2 0c 00 ret $0xc -7bc19523: 90 nop --- -7bc29670 <_RtlMoveMemory@12>: -7bc29670: 55 push %ebp -7bc29671: 89 e5 mov %esp,%ebp -7bc29673: 83 ec 0c sub $0xc,%esp -7bc29676: 8b 45 10 mov 0x10(%ebp),%eax -7bc29679: 89 44 24 08 mov %eax,0x8(%esp) -7bc2967d: 8b 45 0c mov 0xc(%ebp),%eax -7bc29680: 89 44 24 04 mov %eax,0x4(%esp) -7bc29684: 8b 45 08 mov 0x8(%ebp),%eax -7bc29687: 89 04 24 mov %eax,(%esp) -7bc2968a: e8 a1 6f 02 00 call 7bc50630 <_memcpy> -7bc2968f: c9 leave -7bc29690: c2 0c 00 ret $0xc -7bc29693: 90 nop - - - -$ i686-w64-mingw32-gcc --version -i686-w64-mingw32-gcc (GCC) 12-win32 ---- - dlls/ntdll/string.c | 3 ++- - 1 file changed, 2 insertions(+), 1 deletion(-) - -diff --git a/dlls/ntdll/string.c b/dlls/ntdll/string.c -index 46fb80a3a69..5881c047c32 100644 ---- a/dlls/ntdll/string.c -+++ b/dlls/ntdll/string.c -@@ -125,8 +125,9 @@ void * __cdecl memcpy( void *dst, const void *src, size_t n ) - */ - void * __cdecl memmove( void *dst, const void *src, size_t n ) - { -- volatile unsigned char *d = dst; /* avoid gcc optimizations */ - const unsigned char *s = src; -+ volatile unsigned char *d = dst; /* avoid gcc optimizations */ -+ /* changed order to avoid merge with memcpy */ - - if ((size_t)dst - (size_t)src >= n) - { --- -2.47.1 - diff --git a/9000-misc-additions/HACK-ntdll-Unconditionally-save-restore-x87-FPU-cont.patch b/9000-misc-additions/HACK-ntdll-Unconditionally-save-restore-x87-FPU-cont.patch new file mode 100644 index 0000000..228518e --- /dev/null +++ b/9000-misc-additions/HACK-ntdll-Unconditionally-save-restore-x87-FPU-cont.patch @@ -0,0 +1,56 @@ +From 7bcc5f898f2cbb0bd83c0c3d87569eeb36e49419 Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Tue, 7 Jan 2025 04:12:20 -0800 +Subject: [PATCH] HACK: ntdll: Unconditionally save/restore x87 FPU control + word in the unix call dispatchers. + +Workaround for thread suspension issue in osu! causing rounding mode to +remain stuck in a bad state after returning from Unix code. +--- + dlls/ntdll/unix/signal_i386.c | 2 ++ + dlls/ntdll/unix/signal_x86_64.c | 2 ++ + 2 files changed, 4 insertions(+) + +diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c +index 9f43085cd7d..fa38e5fde9e 100644 +--- a/dlls/ntdll/unix/signal_i386.c ++++ b/dlls/ntdll/unix/signal_i386.c +@@ -2798,6 +2798,7 @@ __ASM_GLOBAL_FUNC( __wine_unix_call_dispatcher, + "leal 0x10(%esp),%edx\n\t" + "movl %edx,0x0c(%ecx)\n\t" /* frame->esp */ + __ASM_CFI_CFA_IS_AT1(ecx, 0x0c) ++ "fnstcw 0x40(%ecx)\n\t" /* save x87 FPU CW */ + "movw %cs,0x10(%ecx)\n\t" + "movw %ss,0x12(%ecx)\n\t" + "movw %ds,0x14(%ecx)\n\t" +@@ -2827,6 +2828,7 @@ __ASM_GLOBAL_FUNC( __wine_unix_call_dispatcher, + __ASM_CFI(".cfi_offset %edi,-20\n\t") + "call *(%eax,%edx,4)\n\t" + "leal 16(%esp),%esp\n\t" ++ "fldcw 0x40(%esp)\n\t" /* restore x87 FPU CW */ + "testw $0xffff,2(%esp)\n\t" /* frame->restore_flags */ + "jnz " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") "\n\t" + "movl 0x08(%esp),%ecx\n\t" /* frame->eip */ +diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c +index 40a351cc42b..093d1c7c82d 100644 +--- a/dlls/ntdll/unix/signal_x86_64.c ++++ b/dlls/ntdll/unix/signal_x86_64.c +@@ -3207,6 +3207,7 @@ __ASM_GLOBAL_FUNC( __wine_unix_call_dispatcher, + __ASM_CFI_REG_IS_AT2(rip, rcx, 0xf0,0x00) + "movl $0,0xb4(%rcx)\n\t" /* frame->restore_flags */ + __ASM_LOCAL_LABEL("__wine_unix_call_dispatcher_prolog_end") ":\n\t" ++ "fnstcw 0xc0(%rcx)\n\t" /* save x87 FPU CW to FXSAVE */ + "movq %rbx,0x08(%rcx)\n\t" + __ASM_CFI_REG_IS_AT1(rbx, rcx, 0x08) + "movq %rsi,0x20(%rcx)\n\t" +@@ -3266,6 +3267,7 @@ __ASM_GLOBAL_FUNC( __wine_unix_call_dispatcher, + "movq %r8,%rdi\n\t" /* args */ + "callq *(%r10,%rdx,8)\n\t" + "movq %rsp,%rcx\n\t" ++ "fldcw 0xc0(%rcx)\n\t" /* restore x87 FPU CW from FXSAVE */ + "movdqa 0x1c0(%rcx),%xmm6\n\t" + "movdqa 0x1d0(%rcx),%xmm7\n\t" + "movdqa 0x1e0(%rcx),%xmm8\n\t" +-- +2.47.1 + diff --git a/9000-misc-additions/combase-Perform-a-magic-trick-to-allow-osu-to-work-w.patch b/9000-misc-additions/combase-Perform-a-magic-trick-to-allow-osu-to-work-w.patch deleted file mode 100644 index 2e08a89..0000000 --- a/9000-misc-additions/combase-Perform-a-magic-trick-to-allow-osu-to-work-w.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 6181fe1f1f9ec90cd3f3b716ba3e417c8e0ed44f Mon Sep 17 00:00:00 2001 -From: William Horvath -Date: Fri, 1 Nov 2024 01:29:47 -0700 -Subject: [PATCH] combase: Perform a magic trick to allow osu! to work with - wine_get_version blocked. - -Blind luck. ---- - dlls/combase/roapi.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/dlls/combase/roapi.c b/dlls/combase/roapi.c -index 02d9e0b536e..116b17f9a7e 100644 ---- a/dlls/combase/roapi.c -+++ b/dlls/combase/roapi.c -@@ -208,6 +208,7 @@ HRESULT WINAPI RoGetParameterizedTypeInstanceIID(UINT32 name_element_count, cons - ROPARAMIIDHANDLE *hiid) - { - FIXME("stub: %d %p %p %p %p\n", name_element_count, name_elements, meta_data_locator, iid, hiid); -+ return S_OK; - if (iid) *iid = GUID_NULL; - if (hiid) *hiid = INVALID_HANDLE_VALUE; - return E_NOTIMPL; --- -2.47.0 - diff --git a/9000-misc-additions/gdi32-Map-SwapBuffers-directly-to-opengl32.wglSwapBu.patch b/9000-misc-additions/gdi32-Map-SwapBuffers-directly-to-opengl32.wglSwapBu.patch new file mode 100644 index 0000000..71e8894 --- /dev/null +++ b/9000-misc-additions/gdi32-Map-SwapBuffers-directly-to-opengl32.wglSwapBu.patch @@ -0,0 +1,58 @@ +From e76c5a9ad11c8604e2ca806993a64cfb35f2a9a8 Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Fri, 27 Dec 2024 13:17:14 -0800 +Subject: [PATCH] gdi32: Map SwapBuffers directly to opengl32.wglSwapBuffers. + +Removes one level of indirection, not sure why it was done this way before. + +--- + dlls/gdi32/gdi32.spec | 2 +- + dlls/gdi32/opengl.c | 15 --------------- + 2 files changed, 1 insertion(+), 16 deletions(-) + +diff --git a/dlls/gdi32/gdi32.spec b/dlls/gdi32/gdi32.spec +index 5bde67ea371..a57dbad80d0 100644 +--- a/dlls/gdi32/gdi32.spec ++++ b/dlls/gdi32/gdi32.spec +@@ -635,7 +635,7 @@ + @ stdcall StretchDIBits(long long long long long long long long long ptr ptr long long) + @ stdcall StrokeAndFillPath(long) + @ stdcall StrokePath(long) +-@ stdcall SwapBuffers(long) ++@ stdcall SwapBuffers(long) opengl32.wglSwapBuffers + @ stdcall TextOutA(long long long str long) + @ stdcall TextOutW(long long long wstr long) + @ stdcall TranslateCharsetInfo(ptr ptr long) +diff --git a/dlls/gdi32/opengl.c b/dlls/gdi32/opengl.c +index 0fbd851f67e..d826c59f26d 100644 +--- a/dlls/gdi32/opengl.c ++++ b/dlls/gdi32/opengl.c +@@ -37,7 +37,6 @@ static INT (WINAPI *wglChoosePixelFormat)(HDC,const PIXELFORMATDESCRIPTOR *); + static INT (WINAPI *wglDescribePixelFormat)(HDC,INT,UINT,PIXELFORMATDESCRIPTOR*); + static INT (WINAPI *wglGetPixelFormat)(HDC); + static BOOL (WINAPI *wglSetPixelFormat)(HDC,INT,const PIXELFORMATDESCRIPTOR*); +-static BOOL (WINAPI *wglSwapBuffers)(HDC); + + /****************************************************************************** + * ChoosePixelFormat (GDI32.@) +@@ -94,17 +93,3 @@ BOOL WINAPI SetPixelFormat( HDC hdc, INT fmt, const PIXELFORMATDESCRIPTOR *pfd ) + } + return wglSetPixelFormat( hdc, fmt, pfd ); + } +- +-/****************************************************************************** +- * SwapBuffers (GDI32.@) +- */ +-BOOL WINAPI SwapBuffers( HDC hdc ) +-{ +- if (!wglSwapBuffers) +- { +- if (!opengl32) opengl32 = LoadLibraryW( L"opengl32.dll" ); +- if (!(wglSwapBuffers = (void *)GetProcAddress( opengl32, "wglSwapBuffers" ))) +- return FALSE; +- } +- return wglSwapBuffers( hdc ); +-} +-- +2.47.1 + diff --git a/9000-misc-additions/kernelbase-Add-AppPolicyGetClrCompat-stub.patch b/9000-misc-additions/kernelbase-Add-AppPolicyGetClrCompat-stub.patch new file mode 100644 index 0000000..20cc5b4 --- /dev/null +++ b/9000-misc-additions/kernelbase-Add-AppPolicyGetClrCompat-stub.patch @@ -0,0 +1,77 @@ +From d44a7b780decb7944469959e084f5b0b84bb51a0 Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Fri, 27 Dec 2024 11:45:15 -0800 +Subject: [PATCH] kernelbase: Add AppPolicyGetClrCompat stub. + +--- + dlls/kernelbase/kernelbase.spec | 2 +- + dlls/kernelbase/main.c | 13 +++++++++++++ + include/appmodel.h | 8 ++++++++ + 3 files changed, 22 insertions(+), 1 deletion(-) + +diff --git a/dlls/kernelbase/kernelbase.spec b/dlls/kernelbase/kernelbase.spec +index 27f45edcedf..edbe985d10b 100644 +--- a/dlls/kernelbase/kernelbase.spec ++++ b/dlls/kernelbase/kernelbase.spec +@@ -42,7 +42,7 @@ + # @ stub AppContainerLookupMoniker + # @ stub AppContainerRegisterSid + # @ stub AppContainerUnregisterSid +-# @ stub AppPolicyGetClrCompat ++@ stdcall AppPolicyGetClrCompat(ptr ptr) + # @ stub AppPolicyGetCreateFileAccess + # @ stub AppPolicyGetLifecycleManagement + @ stdcall AppPolicyGetMediaFoundationCodecLoading(ptr ptr) +diff --git a/dlls/kernelbase/main.c b/dlls/kernelbase/main.c +index 60173ba6513..fbfbf9fda0f 100644 +--- a/dlls/kernelbase/main.c ++++ b/dlls/kernelbase/main.c +@@ -81,6 +81,19 @@ INT WINAPI MulDiv( INT a, INT b, INT c ) + return ret; + } + ++/*********************************************************************** ++ * AppPolicyGetClrCompat (KERNELBASE.@) ++ */ ++LONG WINAPI AppPolicyGetClrCompat(HANDLE token, AppPolicyClrCompat *policy) ++{ ++ FIXME("%p, %p\n", token, policy); ++ ++ if(policy) ++ *policy = AppPolicyClrCompat_ClassicDesktop; ++ ++ return ERROR_SUCCESS; ++} ++ + /*********************************************************************** + * AppPolicyGetMediaFoundationCodecLoading (KERNELBASE.@) + */ +diff --git a/include/appmodel.h b/include/appmodel.h +index 8c219e8080a..5c1d5dbc190 100644 +--- a/include/appmodel.h ++++ b/include/appmodel.h +@@ -22,6 +22,13 @@ + extern "C" { + #endif + ++typedef enum AppPolicyClrCompat { ++ AppPolicyClrCompat_Other = 0, ++ AppPolicyClrCompat_ClassicDesktop = 1, ++ AppPolicyClrCompat_Universal = 2, ++ AppPolicyClrCompat_PackagedDesktop = 3 ++} AppPolicyClrCompat; ++ + typedef enum AppPolicyMediaFoundationCodecLoading + { + AppPolicyMediaFoundationCodecLoading_All = 0, +@@ -84,6 +91,7 @@ typedef struct PACKAGE_ID + } + PACKAGE_ID; + ++LONG WINAPI AppPolicyGetClrCompat(HANDLE token, AppPolicyClrCompat *policy); + LONG WINAPI AppPolicyGetMediaFoundationCodecLoading(HANDLE token, AppPolicyMediaFoundationCodecLoading *policy); + LONG WINAPI AppPolicyGetProcessTerminationMethod(HANDLE token, AppPolicyProcessTerminationMethod *policy); + LONG WINAPI AppPolicyGetShowDeveloperDiagnostic(HANDLE token, AppPolicyShowDeveloperDiagnostic *policy); +-- +2.47.1 + diff --git a/9000-misc-additions/roapi-stubs.patch b/9000-misc-additions/roapi-stubs.patch new file mode 100644 index 0000000..d5a1b04 --- /dev/null +++ b/9000-misc-additions/roapi-stubs.patch @@ -0,0 +1,240 @@ +Fixes osu! crashing with WINE_BLOCK_GET_VERSION=1 + +From 3e89c1ee3440ec639a56558076455be18c246708 Mon Sep 17 00:00:00 2001 +From: Santino Mazza +Date: Wed, 5 Oct 2022 14:40:14 -0300 +Subject: [PATCH 1/3] roapi: initial testing + +--- + dlls/combase/roapi.c | 5 ++--- + dlls/combase/tests/roapi.c | 38 ++++++++++++++++++++++++++++++++++ + include/roparameterizediid.idl | 4 ++++ + 3 files changed, 44 insertions(+), 3 deletions(-) + +diff --git a/dlls/combase/roapi.c b/dlls/combase/roapi.c +index 78f35de39d4..9358cd0e795 100644 +--- a/dlls/combase/roapi.c ++++ b/dlls/combase/roapi.c +@@ -212,9 +212,8 @@ HRESULT WINAPI RoGetParameterizedTypeInstanceIID(UINT32 name_element_count, cons + ROPARAMIIDHANDLE *hiid) + { + FIXME("stub: %d %p %p %p %p\n", name_element_count, name_elements, meta_data_locator, iid, hiid); +- if (iid) *iid = GUID_NULL; +- if (hiid) *hiid = INVALID_HANDLE_VALUE; +- return E_NOTIMPL; ++ if (iid) *iid = GUID_NULL; ++ if (hiid) *hiid = INVALID_HANDLE_VALUE; + } + + /*********************************************************************** +#diff --git a/dlls/combase/tests/roapi.c b/dlls/combase/tests/roapi.c +#index f10cbb4507b..943e81061f7 100644 +#--- a/dlls/combase/tests/roapi.c +#+++ b/dlls/combase/tests/roapi.c +#@@ -25,6 +25,7 @@ +# +# #include "initguid.h" +# #include "roapi.h" +#+#include "roparameterizediid.h" +# +# #include "wine/test.h" +# +#@@ -116,6 +117,42 @@ static void test_ActivationFactories(void) +# RoUninitialize(); +# } +# +#+static HRESULT __stdcall locate(IRoMetaDataLocator * This, const WCHAR *typename, IRoSimpleMetaDataBuilder *out) +#+{ +#+ GUID guid; +#+ guid.Data1 = 0xDE; +#+ guid.Data2 = 0xAD; +#+ guid.Data3 = 0xBE; +#+ (((ULONG*)guid.Data4)[0]) = 0xFF; +#+ (((ULONG*)guid.Data4)[1]) = 0; +#+ +#+ todo_wine ok(This != NULL, "Expected This to not be null\n"); +#+ todo_wine ok(typename != NULL, "expected typename to not be null\n"); +#+ todo_wine ok(!wcscmp(typename, L"Testing.test"), "string is not what expected\n"); +#+ todo_wine ok(out != NULL, "expected out to not be null\n"); +#+ out->lpVtbl->SetWinRtInterface(out, guid); +#+ return S_OK; +#+} +#+ +#+static void test_RoGetParameterizedTypeInstanceIID(void) +#+{ +#+ HRESULT hr; +#+ struct IRoMetaDataLocatorVtbl vtbl = { locate }; +#+ IRoMetaDataLocator locator = {&vtbl}; +#+ GUID guid = { 0xFF, 0xFF }; +#+ WCHAR guid_str[39] = { 0 }; +#+ PCWSTR names[1] = { L"Testing.test" }; +#+ +#+ hr = RoInitialize(RO_INIT_MULTITHREADED); +#+ ok(hr == S_OK, "Unexpected hr %#lx.\n", hr); +#+ +#+ hr = RoGetParameterizedTypeInstanceIID(1, names, &locator, &guid, NULL); +#+ todo_wine ok(hr == S_OK, "got %#lx.\n", hr); +#+ StringFromGUID2(&guid, guid_str, sizeof(guid_str)); +#+ todo_wine ok(!wcscmp(guid_str, L"{D4FE793A-2626-552A-AD82-A06A18F32C5E}"), "got guid %ls\n", guid_str); +#+ RoUninitialize(); +#+} +#+ +# START_TEST(roapi) +# { +# BOOL ret; +#@@ -123,6 +160,7 @@ START_TEST(roapi) +# load_resource(L"wine.combase.test.dll"); +# +# test_ActivationFactories(); +#+ test_RoGetParameterizedTypeInstanceIID(); +# +# SetLastError(0xdeadbeef); +# ret = DeleteFileW(L"wine.combase.test.dll"); +diff --git a/include/roparameterizediid.idl b/include/roparameterizediid.idl +index 85ee57d6f94..a9cadc274c6 100644 +--- a/include/roparameterizediid.idl ++++ b/include/roparameterizediid.idl +@@ -93,3 +93,7 @@ interface IRoMetaDataLocator + IRoSimpleMetaDataBuilder *out + ); + } ++ ++HRESULT __stdcall RoGetParameterizedTypeInstanceIID(UINT32 name_element_count, const WCHAR **name_elements, ++ const IRoMetaDataLocator *meta_data_locator, GUID *iid, ++ ROPARAMIIDHANDLE *hiid); +-- +2.47.1 + +From 78713381951543e38ed1d77065c561320ab48cff Mon Sep 17 00:00:00 2001 +From: Santino Mazza +Date: Wed, 5 Oct 2022 18:38:40 -0300 +Subject: [PATCH 2/3] combase: Initial stubs. + +--- + dlls/combase/roapi.c | 103 +++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 103 insertions(+) + +diff --git a/dlls/combase/roapi.c b/dlls/combase/roapi.c +index 9358cd0e795..39399b034c6 100644 +--- a/dlls/combase/roapi.c ++++ b/dlls/combase/roapi.c +@@ -204,6 +204,102 @@ done: + return hr; + } + ++struct metadata_builder { ++ IRoSimpleMetaDataBuilder iface; ++ GUID winrt_interface; ++}; ++ ++static __stdcall HRESULT impl_SetWinRtInterface(IRoSimpleMetaDataBuilder *This, GUID iid) ++{ ++ struct metadata_builder *metadata_builder = (struct metadata_builder*)This; ++ FIXME("stub (%p, %s)\n", This, debugstr_guid(&iid)); ++ metadata_builder->winrt_interface = iid; ++ return S_OK; ++} ++ ++static __stdcall HRESULT impl_SetDelegate(IRoSimpleMetaDataBuilder *This, GUID iid) ++{ ++ FIXME("stub (%p, %s)\n", This, debugstr_guid(&iid)); ++ return S_OK; ++} ++ ++static __stdcall HRESULT impl_SetInterfaceGroupSimpleDefault(IRoSimpleMetaDataBuilder *This, ++ const WCHAR *name, const WCHAR *defaultInterfaceName, ++ const GUID *defaultInterfaceIID) ++{ ++ FIXME("stub (%p, %s, %s, %s)\n", This, debugstr_w(name), debugstr_w(defaultInterfaceName), ++ debugstr_guid(defaultInterfaceIID)); ++ return S_OK; ++} ++ ++static __stdcall HRESULT impl_SetInterfaceGroupParameterizedDefault(IRoSimpleMetaDataBuilder *This, ++ const WCHAR *name, UINT32 elementCount, ++ const WCHAR **defaultInterfaceNameElements) ++{ ++ FIXME("stub (%p, %s, %d, %p)\n", This, debugstr_w(name), elementCount, defaultInterfaceNameElements); ++ return S_OK; ++} ++static __stdcall HRESULT impl_SetRuntimeClassSimpleDefault(IRoSimpleMetaDataBuilder *This, ++ const WCHAR *name, const WCHAR *defaultInterfaceName, ++ const GUID *defaultInterfaceIID) ++{ ++ FIXME("stub (%p, %s, %s, %s)\n", This, debugstr_w(name), debugstr_w(defaultInterfaceName), ++ debugstr_guid(defaultInterfaceIID)); ++ return S_OK; ++} ++ ++static __stdcall HRESULT impl_SetRuntimeClassParameterizedDefault(IRoSimpleMetaDataBuilder *This, ++ const WCHAR *typename, UINT32 name_element_count, ++ const WCHAR **name_elements) ++{ ++ FIXME("stub (%p, %s, %d, %p)\n", This, debugstr_w(typename), name_element_count, name_elements); ++ return S_OK; ++} ++ ++static __stdcall HRESULT impl_SetStruct(IRoSimpleMetaDataBuilder *This, const WCHAR *name, UINT32 numFields, ++ const WCHAR **fieldTypeNames) ++{ ++ FIXME("stub (%p, %s, %d, %p)\n", This, debugstr_w(name), numFields, fieldTypeNames); ++ return S_OK; ++ ++} ++ ++static __stdcall HRESULT impl_SetEnum(IRoSimpleMetaDataBuilder *This, const WCHAR *name, const WCHAR *baseType) ++{ ++ FIXME("stub (%p, %s, %s)\n", This, debugstr_w(name), debugstr_w(baseType)); ++ return S_OK; ++} ++ ++static __stdcall HRESULT impl_SetParameterizedInterface(IRoSimpleMetaDataBuilder *This, GUID piid, UINT32 numArgs) ++{ ++ FIXME("stub (%p, %s, %d)\n", This, debugstr_guid(&piid), numArgs); ++ return S_OK; ++} ++ ++static __stdcall HRESULT impl_SetParameterizedDelegate(IRoSimpleMetaDataBuilder *This, GUID piid, UINT32 numArgs) ++{ ++ FIXME("stub (%p, %s, %d)\n", This, debugstr_guid(&piid), numArgs); ++ return S_OK; ++} ++ ++static IRoSimpleMetaDataBuilderVtbl metadata_builder_vtbl = { ++ impl_SetWinRtInterface, ++ impl_SetDelegate, ++ impl_SetInterfaceGroupSimpleDefault, ++ impl_SetInterfaceGroupParameterizedDefault, ++ impl_SetRuntimeClassSimpleDefault, ++ impl_SetRuntimeClassParameterizedDefault, ++ impl_SetStruct, ++ impl_SetEnum, ++ impl_SetParameterizedInterface, ++ impl_SetParameterizedDelegate ++}; ++ ++static struct metadata_builder metadata_builder = { ++ {&metadata_builder_vtbl}, ++ {0} ++}; ++ + /*********************************************************************** + * RoGetParameterizedTypeInstanceIID (combase.@) + */ +@@ -214,6 +310,13 @@ HRESULT WINAPI RoGetParameterizedTypeInstanceIID(UINT32 name_element_count, cons + FIXME("stub: %d %p %p %p %p\n", name_element_count, name_elements, meta_data_locator, iid, hiid); + if (iid) *iid = GUID_NULL; + if (hiid) *hiid = INVALID_HANDLE_VALUE; ++ for (int i = 0; i < name_element_count; ++i) ++ { ++ //printf("%ls\n", name_elements[i]); ++ meta_data_locator->lpVtbl->Locate(meta_data_locator, name_elements[i], &metadata_builder.iface); ++ } ++ *iid = metadata_builder.winrt_interface; ++ return S_OK; + } + + /*********************************************************************** +-- +2.47.1 + diff --git a/9000-misc-additions/secur32-Disable-CHACHA20-POLY1305-ciphersuites.patch b/9000-misc-additions/secur32-Disable-CHACHA20-POLY1305-ciphersuites.patch index 579c426..a3a7c0a 100644 --- a/9000-misc-additions/secur32-Disable-CHACHA20-POLY1305-ciphersuites.patch +++ b/9000-misc-additions/secur32-Disable-CHACHA20-POLY1305-ciphersuites.patch @@ -1,3 +1,12 @@ +From 42ae7b0a6b719c3d5091c8ec1bc72af6db737979 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Tue, 10 Nov 2020 13:04:45 +0100 +Subject: [PATCH] secur32: Disable CHACHA20-POLY1305 ciphersuites. + +--- + dlls/secur32/schannel_gnutls.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + diff --git a/dlls/secur32/schannel_gnutls.c b/dlls/secur32/schannel_gnutls.c index b26344a..393ea07 100644 --- a/dlls/secur32/schannel_gnutls.c @@ -11,3 +20,6 @@ index b26344a..393ea07 100644 BOOL server = !!(cred->credential_use & SECPKG_CRED_INBOUND); const struct protocol_priority_flag *protocols = +-- +0.0.0 + diff --git a/9000-misc-additions/winex11-Custom-frame-limiter-for-OpenGL.patch b/9000-misc-additions/winex11-Custom-frame-limiter-for-OpenGL.patch index 3195c7f..1eb45cb 100644 --- a/9000-misc-additions/winex11-Custom-frame-limiter-for-OpenGL.patch +++ b/9000-misc-additions/winex11-Custom-frame-limiter-for-OpenGL.patch @@ -4,10 +4,10 @@ Date: Wed, 18 Sep 2024 13:23:09 -0700 Subject: [PATCH] winex11: Custom frame limiter for OpenGL --- - dlls/winex11.drv/opengl.c | 61 ++++++++++++++++++++++++++++++++++ + dlls/winex11.drv/opengl.c | 59 ++++++++++++++++++++++++++++++++ dlls/winex11.drv/x11drv.h | 2 ++ dlls/winex11.drv/x11drv_main.c | 26 +++++++++++++++ - 3 files changed, 89 insertions(+) + 3 files changed, 87 insertions(+) diff --git a/configure.ac b/configure.ac index d539ee50bda..7585324602c 100644 @@ -44,7 +44,7 @@ index 008a92dad98..f46b03ca2e4 100644 #include #include #include -@@ -2807,6 +2808,58 @@ static void X11DRV_WineGL_LoadExtensions(void) +@@ -2807,6 +2808,56 @@ static void X11DRV_WineGL_LoadExtensions(void) } } @@ -58,7 +58,7 @@ index 008a92dad98..f46b03ca2e4 100644 +static long long get_time_ns() { + struct timespec ts; + if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { -+ ERR("clock_gettime failed with errno %d\n", errno); ++ /* ERR("clock_gettime failed with errno %d\n", errno); */ + return 0; + } + return (long long)ts.tv_sec * 1000000000LL + ts.tv_nsec; @@ -75,8 +75,6 @@ index 008a92dad98..f46b03ca2e4 100644 +} + +static void limit_frame_rate() { -+ if (!custom_fps) return; -+ + long long current_time = get_time_ns(); + long long frame_time = current_time - last_frame_time; + long long target_frame_time = 1000000000LL / custom_fps; @@ -103,13 +101,13 @@ index 008a92dad98..f46b03ca2e4 100644 /** * glxdrv_SwapBuffers * -@@ -2880,6 +2933,11 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) +@@ -2880,6 +2931,11 @@ static BOOL glxdrv_wglSwapBuffers( HDC hdc ) present_gl_drawable( hwnd, ctx ? ctx->hdc : hdc, gl, !pglXWaitForSbcOML ); update_gl_drawable_size( gl ); release_gl_drawable( gl ); + +#if defined(HAVE_CLOCK_GETTIME) && defined(HAVE_CLOCK_NANOSLEEP) -+ limit_frame_rate(); ++ if (custom_fps) limit_frame_rate(); +#endif + return TRUE; diff --git a/9500-testing/0001-ntdll-TEST-try-NtFPWB-in-contended-NtWaitForAlertByT.patch b/9500-testing/0001-ntdll-TEST-try-NtFPWB-in-contended-NtWaitForAlertByT.patch deleted file mode 100644 index e3d13f0..0000000 --- a/9500-testing/0001-ntdll-TEST-try-NtFPWB-in-contended-NtWaitForAlertByT.patch +++ /dev/null @@ -1,33 +0,0 @@ -From 8031239529c1e56c46184eb3a430b1c61cdee01a Mon Sep 17 00:00:00 2001 -From: William Horvath -Date: Sat, 21 Dec 2024 14:46:49 -0800 -Subject: [PATCH] ntdll: TEST: try NtFPWB in contended - NtWaitForAlertByThreadId - ---- - dlls/ntdll/unix/sync.c | 2 ++ - 1 file changed, 2 insertions(+) - -diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c -index 67e13bfa6fc..e0962e5af69 100644 ---- a/dlls/ntdll/unix/sync.c -+++ b/dlls/ntdll/unix/sync.c -@@ -3104,6 +3104,7 @@ NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEG - end = get_absolute_timeout( timeout ); - } - -+ NtFlushProcessWriteBuffers(); - while (!InterlockedExchange( futex, 0 )) - { - if (timeout) -@@ -3119,6 +3120,7 @@ NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEG - ret = futex_wait( futex, 0, NULL ); - - if (ret == -1 && errno == ETIMEDOUT) return STATUS_TIMEOUT; -+ NtFlushProcessWriteBuffers(); - } - return STATUS_ALERTED; - } --- -2.47.1 - diff --git a/staging-commit b/staging-commit index 2b301f4..fdae800 100644 --- a/staging-commit +++ b/staging-commit @@ -1 +1 @@ -f10d2d045221c84cb75e9a85919790c2437a647a \ No newline at end of file +c263c6fabba8f952b71bf6ea12a77784b9b43ed2 \ No newline at end of file diff --git a/wine-commit b/wine-commit index 34992fd..dfb3bb5 100644 --- a/wine-commit +++ b/wine-commit @@ -1 +1 @@ -e713c3487f9fc9b7ded528f9ce49844facb99a90 \ No newline at end of file +5942da6c6ca66170d3546016328c4c3e0cf8f1b5 \ No newline at end of file