From b638715dda3cb06c96f0b270e0b77c96a9212665 Mon Sep 17 00:00:00 2001 From: William Horvath Date: Sun, 27 Oct 2024 19:53:10 -0700 Subject: [PATCH] 9.20-2 patchset rebase; change out ntsync for esync/fsync again due to kernel panics; a lot more random stuff that i forget --- .github/workflows/build-aur.yml | 62 +- ...st-of-pending-window-config-requests.patch | 237 ----- ...-matching-configs-with-similar-sizes.patch | 55 -- ...g-RRNotify-events-in-xrandr14-get-id.patch | 118 --- ...rted-rectangles-in-dibdrv-RoundRect-.patch | 36 + ...sforms-which-flip-in-get-arc-points-.patch | 30 + ...integer-before-finding-intersections.patch | 112 +++ ...tate-when-unmapping-embedded-windows.patch | 42 + ...ed-updates-in-terms-of-style-changes.patch | 69 ++ ...fy-updates-in-terms-of-style-changes.patch | 72 ++ ...fy-updates-in-terms-of-style-changes.patch | 101 ++ ...indow-is-currently-visible-or-iconic.patch | 67 ++ ...ide-if-requests-can-be-sent-directly.patch | 44 + ...to-decide-whether-a-window-is-mapped.patch | 76 ++ ...ary-mapped-iconic-net-wm-state-flags.patch | 182 ++++ 0007-ntsync/0001-gcc-13-warnings.patch | 25 - ...-object-operation-to-retrieve-a-fast.patch | 764 --------------- ...t-synchronization-objects-for-events.patch | 443 --------- 0007-ntsync/0004-autoreconf.patch | 44 - ...ate-fast-synchronization-objects-for.patch | 199 ---- ...ate-fast-synchronization-objects-for.patch | 213 ----- ...ate-fast-synchronization-objects-for.patch | 89 -- ...ate-fast-synchronization-objects-for.patch | 197 ---- ...-synchronization-objects-for-console.patch | 110 --- ...st-synchronization-objects-for-debug.patch | 103 -- ...t-synchronization-objects-for-device.patch | 108 --- ...st-synchronization-objects-for-keyed.patch | 75 -- ...ate-fast-synchronization-objects-for.patch | 89 -- ...ast-synchronization-objects-for-jobs.patch | 76 -- ...-synchronization-objects-for-message.patch | 152 --- ...ate-fast-synchronization-objects-for.patch | 88 -- ...t-synchronization-objects-for-timers.patch | 91 -- ...ate-fast-synchronization-objects-for.patch | 224 ----- ...r-add-a-request-to-retrieve-the-fast.patch | 61 -- ...r-add-a-request-to-retrieve-the-fast.patch | 63 -- ...server-introduce-fastselectqueue-and.patch | 124 --- ...ting-an-event-object-for-client-side.patch | 108 --- ...helper-to-wait-on-an-internal-server.patch | 112 --- ...me-traces-to-synchronization-methods.patch | 232 ----- ...dll-use-fast-synchronization-objects.patch | 904 ------------------ ...-serverwaitforobject-when-waiting-on.patch | 35 - ...l-cache-fast-synchronization-objects.patch | 340 ------- ...sabling-fast-synchronization-support.patch | 29 - ...er-add-a-message-to-signal-that-fast.patch | 25 - .../0030-kernel32tests-zigzag-test.patch | 109 --- 0007-ntsync/0031-makereq.patch | 283 ------ 0007-ntsync/0032-extra-debugging.patch | 82 -- ...ts-Add-tests-for-completion-port-sig.patch | 224 +++++ ...e-Set-the-proper-error-code-in-GetQu.patch | 40 + ...gnal-completion-port-waits-on-handle.patch | 152 +++ ...dle-user-APCs-explicitly-in-NtRemove.patch | 206 ++++ ...ign-completion-to-thread-when-wait-f.patch | 441 +++++++++ ...roduce-a-separate-per-thread-object-.patch | 375 ++++++++ .../0007-create-hacks-init.patch | 0 ...for-sys-eventfd.h-ppoll-and-shm_open.patch | 85 ++ ...rver-objects-for-eventfd-based-synch.patch | 448 +++++++++ ...eventfd-based-objects-for-semaphores.patch | 426 +++++++++ ...1-ntdll-Implement-NtReleaseSemaphore.patch | 109 +++ .../0012-ntdll-Implement-NtClose.patch | 78 ++ ...l-Implement-NtWaitForMultipleObjects.patch | 233 +++++ ...ntdll-server-Implement-NtCreateEvent.patch | 130 +++ .../0015-ntdll-Implement-NtSetEvent.patch | 70 ++ .../0016-ntdll-Implement-NtResetEvent.patch | 71 ++ ...ement-waiting-on-manual-reset-events.patch | 60 ++ ...ject-operation-to-grab-the-esync-fil.patch | 722 ++++++++++++++ ...uest-to-get-the-eventfd-file-descrip.patch | 76 ++ ...entfd-file-descriptors-for-process-o.patch | 136 +++ ...lement-waiting-on-server-bound-objec.patch | 226 +++++ ...entfd-file-descriptors-for-event-obj.patch | 144 +++ ...setting-esync-events-on-the-server-s.patch | 118 +++ ...tdll-Try-again-if-poll-returns-EINTR.patch | 70 ++ ...entfd-file-descriptors-for-thread-ob.patch | 90 ++ ...entfd-file-descriptors-for-message-q.patch | 132 +++ ...server-ntdll-Implement-message-waits.patch | 173 ++++ ...entfd-descriptors-for-device-manager.patch | 109 +++ ...tdll-server-Implement-NtCreateMutant.patch | 111 +++ ...0030-ntdll-Implement-NtReleaseMutant.patch | 86 ++ ...1-ntdll-Implement-waiting-on-mutexes.patch | 62 ++ .../0032-ntdll-Implement-wait-all.patch | 187 ++++ .../0033-esync-Add-a-README.patch | 205 ++++ ...ement-NtSignalAndWaitForSingleObject.patch | 81 ++ ...0035-ntdll-Implement-NtOpenSemaphore.patch | 175 ++++ .../0036-ntdll-Implement-NtOpenEvent.patch | 61 ++ .../0037-ntdll-Implement-NtOpenMutant.patch | 61 ++ ...38-server-Implement-esync_map_access.patch | 51 + ...9-server-Implement-NtDuplicateObject.patch | 48 + ...reate-eventfd-descriptors-for-timers.patch | 90 ++ ...dll-server-Implement-alertable-waits.patch | 321 +++++++ .../0042-esync-Update-README.patch | 86 ++ ...ark-some-existing-tests-as-failing-u.patch | 36 + ...044-ntdll-Implement-NtQuerySemaphore.patch | 71 ++ .../0045-ntdll-Implement-NtQueryEvent.patch | 72 ++ .../0046-ntdll-Implement-NtQueryMutant.patch | 72 ++ ...entfd-descriptors-for-pseudo-fd-obje.patch | 130 +++ .../0048-esync-Update-README.patch | 56 ++ ...bout-file-limits-not-being-raised-wh.patch | 42 + ...o-avoid-poll-for-uncontended-objects.patch | 95 ++ ...ry-to-avoid-poll-for-signaled-events.patch | 289 ++++++ .../0052-esync-Update-README.patch | 53 + .../0053-ntdll-Implement-NtPulseEvent.patch | 77 ++ .../0054-esync-Update-README.patch | 25 + ...ync-file-descriptors-for-true-file-o.patch | 42 + ...Abandon-esync-mutexes-on-thread-exit.patch | 194 ++++ ...ync-file-descriptors-for-console-ser.patch | 125 +++ ...only-adjust-hard-limit-in-systemd-20.patch | 29 + ...ing-the-objects-state-on-wait-all-ob.patch | 43 + ...rver-objects-for-futex-based-synchro.patch | 392 ++++++++ ...e-futex-based-objects-for-semaphores.patch | 396 ++++++++ ...2-ntdll-Implement-NtReleaseSemaphore.patch | 96 ++ .../0063-ntdll-Close-fsync-objects.patch | 74 ++ ...l-Implement-waiting-on-fsync-objects.patch | 196 ++++ ...tdll-Create-fsync-objects-for-events.patch | 86 ++ .../0066-ntdll-Implement-NtSetEvent.patch | 78 ++ .../0067-ntdll-Implement-NtResetEvent.patch | 69 ++ ...68-ntdll-Implement-waiting-on-events.patch | 51 + ...ject-operation-to-grab-the-fsync-shm.patch | 732 ++++++++++++++ ...uest-to-get-the-shm-index-associated.patch | 114 +++ ...e-futex-sections-for-process-objects.patch | 171 ++++ ...lement-waiting-on-server-bound-objec.patch | 171 ++++ ...ver-Create-futexes-for-event-objects.patch | 117 +++ ...setting-fsync-events-on-the-server-s.patch | 107 +++ ...er-Create-futexes-for-thread-objects.patch | 78 ++ ...er-Create-futexes-for-message-queues.patch | 146 +++ ...server-ntdll-Implement-message-waits.patch | 171 ++++ ...e-futexes-for-device-manager-objects.patch | 91 ++ .../0079-ntdll-Implement-NtCreateMutant.patch | 89 ++ ...0080-ntdll-Implement-NtReleaseMutant.patch | 74 ++ ...1-ntdll-Implement-waiting-on-mutexes.patch | 45 + .../0082-ntdll-Implement-wait-all.patch | 241 +++++ ...ement-NtSignalAndWaitForSingleObject.patch | 74 ++ ...o-store-the-fsync-type-in-the-server.patch | 116 +++ ...dll-server-Implement-NtOpenSemaphore.patch | 163 ++++ .../0086-ntdll-Implement-NtOpenEvent.patch | 60 ++ .../0087-ntdll-Implement-NtOpenMutant.patch | 60 ++ ...88-server-Implement-fsync_map_access.patch | 50 + ...-server-Implement-handle-duplication.patch | 117 +++ ...dll-server-Implement-alertable-waits.patch | 376 ++++++++ ...ntdll-Wake-all-threads-in-futex_wake.patch | 45 + ...ate-futex-sections-for-timer-objects.patch | 123 +++ ...tex-sections-for-console-input-event.patch | 101 ++ ...094-ntdll-Implement-NtQuerySemaphore.patch | 70 ++ .../0095-ntdll-Implement-NtQueryEvent.patch | 70 ++ .../0096-ntdll-Implement-NtQueryMutant.patch | 71 ++ ...tex-sections-for-pseudo-fd-objects-a.patch | 108 +++ ...tex-sections-for-true-file-objects-a.patch | 82 ++ .../0099-ntdll-Skip-zero-length-waits.patch | 33 + ...r-Add-a-diagnostic-message-for-fsync.patch | 25 + ...e-extra-sure-that-esync-is-never-use.patch | 56 ++ ...2-ntdll-server-Switch-to-testing-ABI.patch | 70 ++ ...0103-ntdll-Check-the-APC-futex-first.patch | 44 + ...er-Fix-an-invalid-use-of-fsync_clear.patch | 26 + ...le-more-careful-about-futex-operatio.patch | 91 ++ ...Catch-closed-handles-more-gracefully.patch | 38 + ...07-ntdll-Implement-fsync_pulse_event.patch | 80 ++ ...essage-when-using-server-side-synchr.patch | 27 + ...fsync-APC-futex-in-the-thread-data-d.patch | 120 +++ ...c-Lock-accessing-the-shm_addrs-array.patch | 45 + ...a-race-condition-when-waiting-on-a-m.patch | 43 + ...-Introduce-a-configurable-spin-count.patch | 147 +++ ...Abandon-fsync-mutexes-on-thread-exit.patch | 200 ++++ ...-ntdll-Default-the-spin-count-to-100.patch | 25 + ...an-esync-fsync-path-for-alertable-Nt.patch | 98 ++ ...usleep-0-instead-of-NtYieldExecution.patch | 43 + ...ll-Call-waitv-just-when-nr_futexes-1.patch | 45 + ...fsync-Encapsulate-timeout-conversion.patch | 164 ++++ ...-ntdll-fsync-Support-futex_waitv-API.patch | 270 ++++++ ...Use-absolute-timeouts-for-futex_wait.patch | 54 ++ ...d-execution-before-alertable-wait-fo.patch | 123 +++ ...SYNC_SIMULATE_SCHED_QUANTUM-config-o.patch | 138 +++ ...Type-check-HANDLE-in-esync_set_event.patch | 27 + ...Type-check-HANDLE-in-fsync_set_event.patch | 27 + ...aphore-grab-attempt-on-wait-all-path.patch | 29 + ...eck-for-NULL-object-on-wait-all-path.patch | 34 + ...nc-Get-rid-of-spin-before-futex-wait.patch | 186 ++++ ...sync-Always-use-futex_waitv-for-wait.patch | 95 ++ ...dll-Include-linux-futex.h-in-fsync.c.patch | 39 + .../0130-fsync-Reuse-shared-mem-indices.patch | 290 ++++++ ...LOCK_MONOTONIC-for-relative-timeouts.patch | 195 ++++ ...opy-of-the-object-instead-of-cache-p.patch | 407 ++++++++ ...c-Synchronize-access-to-object-cache.patch | 120 +++ ...-cache-stores-and-load-instead-of-lo.patch | 177 ++++ ...reference-counting-for-sync-objects-.patch | 592 ++++++++++++ .../0136-fsync-Increase-shm-page-size.patch | 161 ++++ ...-shm_addrs-array-and-get-rid-of-lock.patch | 86 ++ ...sync-Support-waiting-on-file-handles.patch | 28 + ...E_FSYNC_SIMULATE_SCHED_QUANTUM-for-P.patch | 29 + ...E_FSYNC_SIMULATE_SCHED_QUANTUM-for-G.patch | 26 + ...INE_ALERT_SIMULATE_SCHED_QUANTUM-opt.patch | 87 ++ ...simulate-async-file-read-and-IO-canc.patch | 38 + ...bbing-semaphore-if-count-has-changed.patch | 63 ++ .../0144-fsync-Cache-current-process-ID.patch | 54 ++ ...-current-TID-in-__fsync_wait_objects.patch | 94 ++ ...d-WINE_FSYNC_YIELD_TO_WAITERS-option.patch | 149 +++ ...e-WINE_FSYNC_YIELD_TO_WAITERS-for-FF.patch | 26 + ...e-fsync_yield_to_waiters-for-LIGHTNI.patch | 27 + ...e-fsync_yield_to_waiters-for-FFXIII-.patch | 27 + ...-race-between-NtClose-and-get_object.patch | 87 ++ ...-Check-for-NULL-handle-in-get_object.patch | 25 + ...pe-check-HANDLE-in-fsync_reset_event.patch | 36 + ...pe-check-HANDLE-in-fsync_pulse_event.patch | 30 + ...pe-check-HANDLE-in-esync_reset_event.patch | 27 + ...pe-check-HANDLE-in-esync_pulse_event.patch | 27 + ...INE_NO_PRIV_ELEVATION-option-and-aut.patch | 72 ++ ...-objattr-allocation-in-NtCreateSemap.patch | 35 + ...a-separate-per-thread-object-for-int.patch | 328 +++++++ ...pletion-to-thread-when-wait-for-comp.patch | 298 ++++++ ...r-APCs-explicitly-in-NtRemoveIoCompl.patch | 141 +++ ...ompletion-port-waits-on-handle-close.patch | 136 +++ ...he-proper-error-code-in-GetQueuedCom.patch | 40 + ...-tests-for-completion-port-signaling.patch | 224 +++++ ...oduce-explicit-server-wait-helper-an.patch | 75 ++ ...ync-Support-wait-on-completion-ports.patch | 123 +++ ...c-Check-for-port-signal-state-for-ze.patch | 44 + ...server-ntdll-Implement-message-waits.patch | 34 + ...ys-call-get_message-request-after-wa.patch | 96 ++ .../0000-proton-detect-WM-plus-kwin-fix.patch | 70 +- ...-proton-focusin-focusout-workarounds.patch | 76 +- ...inex11-Improved-osu-childwindow-hack.patch | 17 +- ...-SetForegroundWindow-instead-of-SetA.patch | 6 +- ...andling-of-tab-and-non-breaking-spac.patch | 179 ---- ...-Support-referencing-section-objects.patch | 102 -- ...K-Add-WINE_RAM_REPORTING_BIAS-option.patch | 40 +- ...tive-keyed-events-on-the-client-side.patch | 8 +- staging-commit | 2 +- wine-commit | 2 +- 225 files changed, 21669 insertions(+), 6420 deletions(-) delete mode 100644 0003-pending-mrs-and-backports/6569-Draft-winex11-Keep-a-list-of-pending-window-config-requests/0001-winex11-Keep-a-list-of-pending-window-config-requests.patch delete mode 100644 0003-pending-mrs-and-backports/6569-Draft-winex11-Keep-a-list-of-pending-window-config-requests/0002-winex11-Also-discard-near-matching-configs-with-similar-sizes.patch delete mode 100644 0003-pending-mrs-and-backports/6701-winex11-Avoid-processing-RRNotify-events-in-xrandr14-get-id/0001-winex11-Avoid-processing-RRNotify-events-in-xrandr14-get-id.patch create mode 100644 0003-pending-mrs-and-backports/6722-win32u-Yet-more-arc-fixes/0001-win32u-Normalize-inverted-rectangles-in-dibdrv-RoundRect-.patch create mode 100644 0003-pending-mrs-and-backports/6722-win32u-Yet-more-arc-fixes/0002-win32u-Correctly-handle-transforms-which-flip-in-get-arc-points-.patch create mode 100644 0003-pending-mrs-and-backports/6722-win32u-Yet-more-arc-fixes/0003-win32u-Do-not-convert-back-to-integer-before-finding-intersections.patch create mode 100644 0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0001-winex11-Call-window-set-wm-state-when-unmapping-embedded-windows.patch create mode 100644 0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0002-winex11-Compute-WindowPosChanged-updates-in-terms-of-style-changes.patch create mode 100644 0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0003-winex11-Compute-ConfigureNotify-updates-in-terms-of-style-changes.patch create mode 100644 0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0004-winex11-Compute-WM-STATE-notify-updates-in-terms-of-style-changes.patch create mode 100644 0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0005-winex11-Use-the-style-to-decide-whether-a-window-is-currently-visible-or-iconic.patch create mode 100644 0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0006-winex11-Use-pending-state-wm-state-to-decide-if-requests-can-be-sent-directly.patch create mode 100644 0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0007-winex11-Use-pending-state-wm-state-to-decide-whether-a-window-is-mapped.patch create mode 100644 0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0008-winex11-Get-rid-of-the-now-unnecessary-mapped-iconic-net-wm-state-flags.patch delete mode 100644 0007-ntsync/0001-gcc-13-warnings.patch delete mode 100644 0007-ntsync/0002-server-add-an-object-operation-to-retrieve-a-fast.patch delete mode 100644 0007-ntsync/0003-server-create-fast-synchronization-objects-for-events.patch delete mode 100644 0007-ntsync/0004-autoreconf.patch delete mode 100644 0007-ntsync/0005-server-create-fast-synchronization-objects-for.patch delete mode 100644 0007-ntsync/0006-server-create-fast-synchronization-objects-for.patch delete mode 100644 0007-ntsync/0007-server-create-fast-synchronization-objects-for.patch delete mode 100644 0007-ntsync/0008-server-create-fast-synchronization-objects-for.patch delete mode 100644 0007-ntsync/0009-server-create-fast-synchronization-objects-for-console.patch delete mode 100644 0007-ntsync/0010-server-create-fast-synchronization-objects-for-debug.patch delete mode 100644 0007-ntsync/0011-server-create-fast-synchronization-objects-for-device.patch delete mode 100644 0007-ntsync/0012-server-create-fast-synchronization-objects-for-keyed.patch delete mode 100644 0007-ntsync/0013-server-create-fast-synchronization-objects-for.patch delete mode 100644 0007-ntsync/0014-server-create-fast-synchronization-objects-for-jobs.patch delete mode 100644 0007-ntsync/0015-server-create-fast-synchronization-objects-for-message.patch delete mode 100644 0007-ntsync/0016-server-create-fast-synchronization-objects-for.patch delete mode 100644 0007-ntsync/0017-server-create-fast-synchronization-objects-for-timers.patch delete mode 100644 0007-ntsync/0018-server-create-fast-synchronization-objects-for.patch delete mode 100644 0007-ntsync/0019-server-add-a-request-to-retrieve-the-fast.patch delete mode 100644 0007-ntsync/0020-server-add-a-request-to-retrieve-the-fast.patch delete mode 100644 0007-ntsync/0021-server-introduce-fastselectqueue-and.patch delete mode 100644 0007-ntsync/0022-server-allow-creating-an-event-object-for-client-side.patch delete mode 100644 0007-ntsync/0023-ntdll-introduce-a-helper-to-wait-on-an-internal-server.patch delete mode 100644 0007-ntsync/0024-ntdll-add-some-traces-to-synchronization-methods.patch delete mode 100644 0007-ntsync/0025-ntdll-use-fast-synchronization-objects.patch delete mode 100644 0007-ntsync/0026-ntdll-use-serverwaitforobject-when-waiting-on.patch delete mode 100644 0007-ntsync/0027-ntdll-cache-fast-synchronization-objects.patch delete mode 100644 0007-ntsync/0028-server-allow-disabling-fast-synchronization-support.patch delete mode 100644 0007-ntsync/0029-server-add-a-message-to-signal-that-fast.patch delete mode 100644 0007-ntsync/0030-kernel32tests-zigzag-test.patch delete mode 100644 0007-ntsync/0031-makereq.patch delete mode 100644 0007-ntsync/0032-extra-debugging.patch create mode 100644 0007-proton-esync-fsync/0001-Revert-ntdll-tests-Add-tests-for-completion-port-sig.patch create mode 100644 0007-proton-esync-fsync/0002-Revert-kernelbase-Set-the-proper-error-code-in-GetQu.patch create mode 100644 0007-proton-esync-fsync/0003-Revert-server-Signal-completion-port-waits-on-handle.patch create mode 100644 0007-proton-esync-fsync/0004-Revert-ntdll-Handle-user-APCs-explicitly-in-NtRemove.patch create mode 100644 0007-proton-esync-fsync/0005-Revert-ntdll-Assign-completion-to-thread-when-wait-f.patch create mode 100644 0007-proton-esync-fsync/0006-Revert-ntdll-Introduce-a-separate-per-thread-object-.patch rename 0007-ntsync/0000-create-hacks-init.patch => 0007-proton-esync-fsync/0007-create-hacks-init.patch (100%) create mode 100644 0007-proton-esync-fsync/0008-configure-Check-for-sys-eventfd.h-ppoll-and-shm_open.patch create mode 100644 0007-proton-esync-fsync/0009-server-Create-server-objects-for-eventfd-based-synch.patch create mode 100644 0007-proton-esync-fsync/0010-ntdll-Create-eventfd-based-objects-for-semaphores.patch create mode 100644 0007-proton-esync-fsync/0011-ntdll-Implement-NtReleaseSemaphore.patch create mode 100644 0007-proton-esync-fsync/0012-ntdll-Implement-NtClose.patch create mode 100644 0007-proton-esync-fsync/0013-ntdll-Implement-NtWaitForMultipleObjects.patch create mode 100644 0007-proton-esync-fsync/0014-ntdll-server-Implement-NtCreateEvent.patch create mode 100644 0007-proton-esync-fsync/0015-ntdll-Implement-NtSetEvent.patch create mode 100644 0007-proton-esync-fsync/0016-ntdll-Implement-NtResetEvent.patch create mode 100644 0007-proton-esync-fsync/0017-ntdll-Implement-waiting-on-manual-reset-events.patch create mode 100644 0007-proton-esync-fsync/0018-server-Add-an-object-operation-to-grab-the-esync-fil.patch create mode 100644 0007-proton-esync-fsync/0019-server-Add-a-request-to-get-the-eventfd-file-descrip.patch create mode 100644 0007-proton-esync-fsync/0020-server-Create-eventfd-file-descriptors-for-process-o.patch create mode 100644 0007-proton-esync-fsync/0021-ntdll-server-Implement-waiting-on-server-bound-objec.patch create mode 100644 0007-proton-esync-fsync/0022-server-Create-eventfd-file-descriptors-for-event-obj.patch create mode 100644 0007-proton-esync-fsync/0023-server-Allow-re-setting-esync-events-on-the-server-s.patch create mode 100644 0007-proton-esync-fsync/0024-ntdll-Try-again-if-poll-returns-EINTR.patch create mode 100644 0007-proton-esync-fsync/0025-server-Create-eventfd-file-descriptors-for-thread-ob.patch create mode 100644 0007-proton-esync-fsync/0026-server-Create-eventfd-file-descriptors-for-message-q.patch create mode 100644 0007-proton-esync-fsync/0027-server-ntdll-Implement-message-waits.patch create mode 100644 0007-proton-esync-fsync/0028-server-Create-eventfd-descriptors-for-device-manager.patch create mode 100644 0007-proton-esync-fsync/0029-ntdll-server-Implement-NtCreateMutant.patch create mode 100644 0007-proton-esync-fsync/0030-ntdll-Implement-NtReleaseMutant.patch create mode 100644 0007-proton-esync-fsync/0031-ntdll-Implement-waiting-on-mutexes.patch create mode 100644 0007-proton-esync-fsync/0032-ntdll-Implement-wait-all.patch create mode 100644 0007-proton-esync-fsync/0033-esync-Add-a-README.patch create mode 100644 0007-proton-esync-fsync/0034-ntdll-Implement-NtSignalAndWaitForSingleObject.patch create mode 100644 0007-proton-esync-fsync/0035-ntdll-Implement-NtOpenSemaphore.patch create mode 100644 0007-proton-esync-fsync/0036-ntdll-Implement-NtOpenEvent.patch create mode 100644 0007-proton-esync-fsync/0037-ntdll-Implement-NtOpenMutant.patch create mode 100644 0007-proton-esync-fsync/0038-server-Implement-esync_map_access.patch create mode 100644 0007-proton-esync-fsync/0039-server-Implement-NtDuplicateObject.patch create mode 100644 0007-proton-esync-fsync/0040-server-Create-eventfd-descriptors-for-timers.patch create mode 100644 0007-proton-esync-fsync/0041-ntdll-server-Implement-alertable-waits.patch create mode 100644 0007-proton-esync-fsync/0042-esync-Update-README.patch create mode 100644 0007-proton-esync-fsync/0043-kernel32-tests-Mark-some-existing-tests-as-failing-u.patch create mode 100644 0007-proton-esync-fsync/0044-ntdll-Implement-NtQuerySemaphore.patch create mode 100644 0007-proton-esync-fsync/0045-ntdll-Implement-NtQueryEvent.patch create mode 100644 0007-proton-esync-fsync/0046-ntdll-Implement-NtQueryMutant.patch create mode 100644 0007-proton-esync-fsync/0047-server-Create-eventfd-descriptors-for-pseudo-fd-obje.patch create mode 100644 0007-proton-esync-fsync/0048-esync-Update-README.patch create mode 100644 0007-proton-esync-fsync/0049-esync-Add-note-about-file-limits-not-being-raised-wh.patch create mode 100644 0007-proton-esync-fsync/0050-ntdll-Try-to-avoid-poll-for-uncontended-objects.patch create mode 100644 0007-proton-esync-fsync/0051-ntdll-server-Try-to-avoid-poll-for-signaled-events.patch create mode 100644 0007-proton-esync-fsync/0052-esync-Update-README.patch create mode 100644 0007-proton-esync-fsync/0053-ntdll-Implement-NtPulseEvent.patch create mode 100644 0007-proton-esync-fsync/0054-esync-Update-README.patch create mode 100644 0007-proton-esync-fsync/0055-server-Create-esync-file-descriptors-for-true-file-o.patch create mode 100644 0007-proton-esync-fsync/0056-ntdll-server-Abandon-esync-mutexes-on-thread-exit.patch create mode 100644 0007-proton-esync-fsync/0057-server-Create-esync-file-descriptors-for-console-ser.patch create mode 100644 0007-proton-esync-fsync/0058-readme-only-adjust-hard-limit-in-systemd-20.patch create mode 100644 0007-proton-esync-fsync/0059-esync-Fix-restoring-the-objects-state-on-wait-all-ob.patch create mode 100644 0007-proton-esync-fsync/0060-server-Create-server-objects-for-futex-based-synchro.patch create mode 100644 0007-proton-esync-fsync/0061-ntdll-Create-futex-based-objects-for-semaphores.patch create mode 100644 0007-proton-esync-fsync/0062-ntdll-Implement-NtReleaseSemaphore.patch create mode 100644 0007-proton-esync-fsync/0063-ntdll-Close-fsync-objects.patch create mode 100644 0007-proton-esync-fsync/0064-ntdll-Implement-waiting-on-fsync-objects.patch create mode 100644 0007-proton-esync-fsync/0065-ntdll-Create-fsync-objects-for-events.patch create mode 100644 0007-proton-esync-fsync/0066-ntdll-Implement-NtSetEvent.patch create mode 100644 0007-proton-esync-fsync/0067-ntdll-Implement-NtResetEvent.patch create mode 100644 0007-proton-esync-fsync/0068-ntdll-Implement-waiting-on-events.patch create mode 100644 0007-proton-esync-fsync/0069-server-Add-an-object-operation-to-grab-the-fsync-shm.patch create mode 100644 0007-proton-esync-fsync/0070-server-Add-a-request-to-get-the-shm-index-associated.patch create mode 100644 0007-proton-esync-fsync/0071-server-Create-futex-sections-for-process-objects.patch create mode 100644 0007-proton-esync-fsync/0072-ntdll-server-Implement-waiting-on-server-bound-objec.patch create mode 100644 0007-proton-esync-fsync/0073-server-Create-futexes-for-event-objects.patch create mode 100644 0007-proton-esync-fsync/0074-server-Allow-re-setting-fsync-events-on-the-server-s.patch create mode 100644 0007-proton-esync-fsync/0075-server-Create-futexes-for-thread-objects.patch create mode 100644 0007-proton-esync-fsync/0076-server-Create-futexes-for-message-queues.patch create mode 100644 0007-proton-esync-fsync/0077-server-ntdll-Implement-message-waits.patch create mode 100644 0007-proton-esync-fsync/0078-server-Create-futexes-for-device-manager-objects.patch create mode 100644 0007-proton-esync-fsync/0079-ntdll-Implement-NtCreateMutant.patch create mode 100644 0007-proton-esync-fsync/0080-ntdll-Implement-NtReleaseMutant.patch create mode 100644 0007-proton-esync-fsync/0081-ntdll-Implement-waiting-on-mutexes.patch create mode 100644 0007-proton-esync-fsync/0082-ntdll-Implement-wait-all.patch create mode 100644 0007-proton-esync-fsync/0083-ntdll-Implement-NtSignalAndWaitForSingleObject.patch create mode 100644 0007-proton-esync-fsync/0084-server-ntdll-Also-store-the-fsync-type-in-the-server.patch create mode 100644 0007-proton-esync-fsync/0085-ntdll-server-Implement-NtOpenSemaphore.patch create mode 100644 0007-proton-esync-fsync/0086-ntdll-Implement-NtOpenEvent.patch create mode 100644 0007-proton-esync-fsync/0087-ntdll-Implement-NtOpenMutant.patch create mode 100644 0007-proton-esync-fsync/0088-server-Implement-fsync_map_access.patch create mode 100644 0007-proton-esync-fsync/0089-ntdll-server-Implement-handle-duplication.patch create mode 100644 0007-proton-esync-fsync/0090-ntdll-server-Implement-alertable-waits.patch create mode 100644 0007-proton-esync-fsync/0091-ntdll-Wake-all-threads-in-futex_wake.patch create mode 100644 0007-proton-esync-fsync/0092-server-Create-futex-sections-for-timer-objects.patch create mode 100644 0007-proton-esync-fsync/0093-server-Create-futex-sections-for-console-input-event.patch create mode 100644 0007-proton-esync-fsync/0094-ntdll-Implement-NtQuerySemaphore.patch create mode 100644 0007-proton-esync-fsync/0095-ntdll-Implement-NtQueryEvent.patch create mode 100644 0007-proton-esync-fsync/0096-ntdll-Implement-NtQueryMutant.patch create mode 100644 0007-proton-esync-fsync/0097-server-Create-futex-sections-for-pseudo-fd-objects-a.patch create mode 100644 0007-proton-esync-fsync/0098-server-Create-futex-sections-for-true-file-objects-a.patch create mode 100644 0007-proton-esync-fsync/0099-ntdll-Skip-zero-length-waits.patch create mode 100644 0007-proton-esync-fsync/0100-server-Add-a-diagnostic-message-for-fsync.patch create mode 100644 0007-proton-esync-fsync/0101-ntdll-server-Make-extra-sure-that-esync-is-never-use.patch create mode 100644 0007-proton-esync-fsync/0102-ntdll-server-Switch-to-testing-ABI.patch create mode 100644 0007-proton-esync-fsync/0103-ntdll-Check-the-APC-futex-first.patch create mode 100644 0007-proton-esync-fsync/0104-server-Fix-an-invalid-use-of-fsync_clear.patch create mode 100644 0007-proton-esync-fsync/0105-server-Be-a-little-more-careful-about-futex-operatio.patch create mode 100644 0007-proton-esync-fsync/0106-ntdll-Catch-closed-handles-more-gracefully.patch create mode 100644 0007-proton-esync-fsync/0107-ntdll-Implement-fsync_pulse_event.patch create mode 100644 0007-proton-esync-fsync/0108-server-Print-a-message-when-using-server-side-synchr.patch create mode 100644 0007-proton-esync-fsync/0109-ntdll-Store-the-fsync-APC-futex-in-the-thread-data-d.patch create mode 100644 0007-proton-esync-fsync/0110-ntdll-fsync-Lock-accessing-the-shm_addrs-array.patch create mode 100644 0007-proton-esync-fsync/0111-ntdll-fsync-Fix-a-race-condition-when-waiting-on-a-m.patch create mode 100644 0007-proton-esync-fsync/0112-ntdll-fsync-Introduce-a-configurable-spin-count.patch create mode 100644 0007-proton-esync-fsync/0113-ntdll-server-Abandon-fsync-mutexes-on-thread-exit.patch create mode 100644 0007-proton-esync-fsync/0114-ntdll-Default-the-spin-count-to-100.patch create mode 100644 0007-proton-esync-fsync/0115-ntdll-Implement-an-esync-fsync-path-for-alertable-Nt.patch create mode 100644 0007-proton-esync-fsync/0116-esync-fsync-Use-usleep-0-instead-of-NtYieldExecution.patch create mode 100644 0007-proton-esync-fsync/0117-ntdll-Call-waitv-just-when-nr_futexes-1.patch create mode 100644 0007-proton-esync-fsync/0118-ntdll-fsync-Encapsulate-timeout-conversion.patch create mode 100644 0007-proton-esync-fsync/0119-ntdll-fsync-Support-futex_waitv-API.patch create mode 100644 0007-proton-esync-fsync/0120-ntdll-fsync-Use-absolute-timeouts-for-futex_wait.patch create mode 100644 0007-proton-esync-fsync/0121-esync-fsync-Yield-execution-before-alertable-wait-fo.patch create mode 100644 0007-proton-esync-fsync/0122-fsync-Add-WINE_FSYNC_SIMULATE_SCHED_QUANTUM-config-o.patch create mode 100644 0007-proton-esync-fsync/0123-esync-Type-check-HANDLE-in-esync_set_event.patch create mode 100644 0007-proton-esync-fsync/0124-fsync-Type-check-HANDLE-in-fsync_set_event.patch create mode 100644 0007-proton-esync-fsync/0125-fsync-Fix-semaphore-grab-attempt-on-wait-all-path.patch create mode 100644 0007-proton-esync-fsync/0126-fsync-Always-check-for-NULL-object-on-wait-all-path.patch create mode 100644 0007-proton-esync-fsync/0127-fsync-Get-rid-of-spin-before-futex-wait.patch create mode 100644 0007-proton-esync-fsync/0128-fsync-Always-use-futex_waitv-for-wait.patch create mode 100644 0007-proton-esync-fsync/0129-ntdll-Include-linux-futex.h-in-fsync.c.patch create mode 100644 0007-proton-esync-fsync/0130-fsync-Reuse-shared-mem-indices.patch create mode 100644 0007-proton-esync-fsync/0131-fsync-Use-CLOCK_MONOTONIC-for-relative-timeouts.patch create mode 100644 0007-proton-esync-fsync/0132-fsync-Return-a-copy-of-the-object-instead-of-cache-p.patch create mode 100644 0007-proton-esync-fsync/0133-fsync-Synchronize-access-to-object-cache.patch create mode 100644 0007-proton-esync-fsync/0134-fsync-Use-atomic-cache-stores-and-load-instead-of-lo.patch create mode 100644 0007-proton-esync-fsync/0135-fsync-Implement-reference-counting-for-sync-objects-.patch create mode 100644 0007-proton-esync-fsync/0136-fsync-Increase-shm-page-size.patch create mode 100644 0007-proton-esync-fsync/0137-fsync-Use-static-shm_addrs-array-and-get-rid-of-lock.patch create mode 100644 0007-proton-esync-fsync/0138-esync-fsync-Support-waiting-on-file-handles.patch create mode 100644 0007-proton-esync-fsync/0139-ntdll-Enable-WINE_FSYNC_SIMULATE_SCHED_QUANTUM-for-P.patch create mode 100644 0007-proton-esync-fsync/0140-ntdll-Enable-WINE_FSYNC_SIMULATE_SCHED_QUANTUM-for-G.patch create mode 100644 0007-proton-esync-fsync/0141-ntdll-HACK-Add-WINE_ALERT_SIMULATE_SCHED_QUANTUM-opt.patch create mode 100644 0007-proton-esync-fsync/0142-ntdll-HACK-Also-simulate-async-file-read-and-IO-canc.patch create mode 100644 0007-proton-esync-fsync/0143-fsync-Retry-grabbing-semaphore-if-count-has-changed.patch create mode 100644 0007-proton-esync-fsync/0144-fsync-Cache-current-process-ID.patch create mode 100644 0007-proton-esync-fsync/0145-fsync-Cache-current-TID-in-__fsync_wait_objects.patch create mode 100644 0007-proton-esync-fsync/0146-fsync-Add-WINE_FSYNC_YIELD_TO_WAITERS-option.patch create mode 100644 0007-proton-esync-fsync/0147-ntdll-HACK-Enable-WINE_FSYNC_YIELD_TO_WAITERS-for-FF.patch create mode 100644 0007-proton-esync-fsync/0148-ntdll-HACK-Enable-fsync_yield_to_waiters-for-LIGHTNI.patch create mode 100644 0007-proton-esync-fsync/0149-ntdll-HACK-Enable-fsync_yield_to_waiters-for-FFXIII-.patch create mode 100644 0007-proton-esync-fsync/0150-fsync-Avoid-race-between-NtClose-and-get_object.patch create mode 100644 0007-proton-esync-fsync/0151-fsync-Check-for-NULL-handle-in-get_object.patch create mode 100644 0007-proton-esync-fsync/0152-fsync-Type-check-HANDLE-in-fsync_reset_event.patch create mode 100644 0007-proton-esync-fsync/0153-fsync-Type-check-HANDLE-in-fsync_pulse_event.patch create mode 100644 0007-proton-esync-fsync/0154-esync-Type-check-HANDLE-in-esync_reset_event.patch create mode 100644 0007-proton-esync-fsync/0155-esync-Type-check-HANDLE-in-esync_pulse_event.patch create mode 100644 0007-proton-esync-fsync/0156-ntdll-HACK-Add-WINE_NO_PRIV_ELEVATION-option-and-aut.patch create mode 100644 0007-proton-esync-fsync/0157-ntdll-Don-t-leak-objattr-allocation-in-NtCreateSemap.patch create mode 100644 0007-proton-esync-fsync/0158-ntdll-Introduce-a-separate-per-thread-object-for-int.patch create mode 100644 0007-proton-esync-fsync/0159-ntdll-Assign-completion-to-thread-when-wait-for-comp.patch create mode 100644 0007-proton-esync-fsync/0160-ntdll-Handle-user-APCs-explicitly-in-NtRemoveIoCompl.patch create mode 100644 0007-proton-esync-fsync/0161-server-Signal-completion-port-waits-on-handle-close.patch create mode 100644 0007-proton-esync-fsync/0162-kernelbase-Set-the-proper-error-code-in-GetQueuedCom.patch create mode 100644 0007-proton-esync-fsync/0163-ntdll-tests-Add-tests-for-completion-port-signaling.patch create mode 100644 0007-proton-esync-fsync/0164-ntdll-fsync-Introduce-explicit-server-wait-helper-an.patch create mode 100644 0007-proton-esync-fsync/0165-esync-fsync-Support-wait-on-completion-ports.patch create mode 100644 0007-proton-esync-fsync/0166-ntdll-esync-fsync-Check-for-port-signal-state-for-ze.patch create mode 100644 0007-proton-esync-fsync/0167-fixup-server-ntdll-Implement-message-waits.patch create mode 100644 0007-proton-esync-fsync/0168-HACK-user32-Always-call-get_message-request-after-wa.patch delete mode 100644 0013-server-optimization/0001-misc/ps0003-ucrtbase-Fix-handling-of-tab-and-non-breaking-spac.patch delete mode 100644 0013-server-optimization/0001-misc/ps0023-ntoskrnl-server-Support-referencing-section-objects.patch diff --git a/.github/workflows/build-aur.yml b/.github/workflows/build-aur.yml index 6bd2e15..001786d 100644 --- a/.github/workflows/build-aur.yml +++ b/.github/workflows/build-aur.yml @@ -11,6 +11,9 @@ on: description: 'Base package name' required: true default: 'wine-osu-spectator' + push: + tags: + - '*' env: AUR_PACKAGE: ${{ github.event.inputs.aur_package || 'wine-osu-spectator' }} @@ -39,15 +42,11 @@ jobs: run: | pacman -Syu --noconfirm git nodejs npm - - name: Restore pacman setup and package cache + - name: Restore package cache id: cache-restore uses: actions/cache/restore@v3 with: path: | - /etc/pacman.conf - /etc/pacman.d/chaotic-mirrorlist - /etc/pacman.d/gnupg - /etc/makepkg.conf ${{ env.PACKAGE_CACHE }} ${{ env._CCACHE_DIR }} key: ${{ runner.os }}-${{ env.CACHE_KEY }}-${{ github.run_id }} @@ -55,8 +54,7 @@ jobs: ${{ runner.os }}-${{ env.CACHE_KEY }}- # Adding chaotic-aur for more prebuilt dependencies - - name: Set up system (if cache miss) - if: steps.cache-restore.outputs.cache-hit != 'true' + - name: Set up system run: | pacman-key --init pacman-key --populate archlinux @@ -95,6 +93,8 @@ jobs: EOF - name: Install and configure customizepkg + env: + CURRENT_TAG: ${{ github.ref_name }} run: | sudo -u builder bash << EOF if ! paru -Qiq customizepkg-git 1>/dev/null; then @@ -104,7 +104,9 @@ jobs: fi mkdir -p ~/.customizepkg echo "replace#global#_generic_release=false#_generic_release=true" > ~/.customizepkg/${AUR_PACKAGE} + echo "replace#global#^_patchbase_tag=.*#_patchbase_tag=${CURRENT_TAG}" >> ~/.customizepkg/${AUR_PACKAGE} echo "replace#global#_generic_release=false#_generic_release=true" > ~/.customizepkg/${AUR_PACKAGE}-wow64 + echo "replace#global#^_patchbase_tag=.*#_patchbase_tag=${CURRENT_TAG}" >> ~/.customizepkg/${AUR_PACKAGE}-wow64 echo "replace#global#pkgver=3.5#pkgver=3.6" > ~/.customizepkg/lib32-x265 EOF @@ -143,8 +145,8 @@ jobs: run: | sudo -u builder bash << EOF cd ~ - paru -S --nocheck --noconfirm ${AUR_PACKAGE} --assume-installed=ntsync-dkms - paru -S --nocheck --noconfirm ${AUR_PACKAGE}-wow64 --assume-installed=ntsync-dkms + paru -S --nocheck --noconfirm --mflags "--skipinteg" ${AUR_PACKAGE} --assume-installed=ntsync-dkms + paru -S --nocheck --noconfirm --mflags "--skipinteg" ${AUR_PACKAGE}-wow64 --assume-installed=ntsync-dkms EOF - name: Prepare artifacts @@ -189,10 +191,44 @@ jobs: uses: actions/cache/save@v3 with: path: | - /etc/pacman.conf - /etc/pacman.d/chaotic-mirrorlist - /etc/pacman.d/gnupg - /etc/makepkg.conf ${{ env.PACKAGE_CACHE }} ${{ env._CCACHE_DIR }} key: ${{ runner.os }}-${{ env.CACHE_KEY }}-${{ github.run_id }} + + create-release: + needs: build + if: startsWith(github.ref, 'refs/tags/') + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - name: Download all artifacts + uses: actions/download-artifact@v4 + with: + path: artifacts + + - name: Extract version from package name + id: get_version + run: | + PKGFILE=$(ls artifacts/${{ env.AUR_PACKAGE }}/*.pkg.tar.xz | head -n1) + + # from e.g. wine-osu-spectator-9.20.w1.s5a1b9d5-1-x86_64.pkg.tar.xz + # get VERSION=9.20 and RELEASE=1 + VERSION=$(basename "$PKGFILE" | sed -E 's/.*-([0-9]+\.[0-9]+)\..*-([0-9]+)-.*pkg\.tar\.xz/\1/') + RELEASE=$(basename "$PKGFILE" | sed -E 's/.*-([0-9]+\.[0-9]+)\..*-([0-9]+)-.*pkg\.tar\.xz/\2/') + + echo "VERSION=$VERSION" >> $GITHUB_OUTPUT + echo "RELEASE=$RELEASE" >> $GITHUB_OUTPUT + echo "FULL_VERSION=$VERSION-$RELEASE" >> $GITHUB_OUTPUT + + - name: Create Release + uses: softprops/action-gh-release@v2 + with: + name: Release ${{ env.AUR_PACKAGE }}-${{ steps.get_version.outputs.FULL_VERSION }} + draft: false + prerelease: false + files: | + artifacts/${{ env.AUR_PACKAGE }}/*.pkg.tar.xz + artifacts/${{ env.AUR_PACKAGE }}-wow64/*.pkg.tar.xz + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/0003-pending-mrs-and-backports/6569-Draft-winex11-Keep-a-list-of-pending-window-config-requests/0001-winex11-Keep-a-list-of-pending-window-config-requests.patch b/0003-pending-mrs-and-backports/6569-Draft-winex11-Keep-a-list-of-pending-window-config-requests/0001-winex11-Keep-a-list-of-pending-window-config-requests.patch deleted file mode 100644 index 9656b2d..0000000 --- a/0003-pending-mrs-and-backports/6569-Draft-winex11-Keep-a-list-of-pending-window-config-requests/0001-winex11-Keep-a-list-of-pending-window-config-requests.patch +++ /dev/null @@ -1,237 +0,0 @@ -From 097158a3899bdcc61919308ceaa1f57f7412408b Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 26 Sep 2024 13:33:28 +0200 -Subject: [PATCH] winex11: Keep a list of pending window config requests. - -Instead of a single configure serial, which is simply not enough to -mitigate event feedback loops. ---- - dlls/winex11.drv/event.c | 13 +++--- - dlls/winex11.drv/window.c | 93 +++++++++++++++++++++++++++++++++++++-- - dlls/winex11.drv/x11drv.h | 11 ++++- - 3 files changed, 105 insertions(+), 12 deletions(-) - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index c8fc76f5048..8f4a80bcc7e 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -1043,13 +1043,6 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) - if (data->whole_window && !data->managed) goto done; - /* ignore synthetic events on foreign windows */ - if (event->send_event && !data->whole_window) goto done; -- if (data->configure_serial && (long)(data->configure_serial - event->serial) > 0) -- { -- TRACE( "win %p/%lx event %d,%d,%dx%d ignoring old serial %lu/%lu\n", -- hwnd, data->whole_window, event->x, event->y, event->width, event->height, -- event->serial, data->configure_serial ); -- goto done; -- } - - /* Get geometry */ - -@@ -1072,6 +1065,12 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) - else pos = root_to_virtual_screen( x, y ); - - SetRect( &rect, pos.x, pos.y, pos.x + event->width, pos.y + event->height ); -+ if (has_pending_window_config( data, &rect, event->serial )) -+ { -+ TRACE( "Found newer/matching pending config, ignoring event\n" ); -+ goto done; -+ } -+ - rect = window_rect_from_visible( &data->rects, rect ); - if (root_coords) NtUserMapWindowPoints( 0, parent, (POINT *)&rect, 2, 0 /* per-monitor DPI */ ); - -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index f18ab302e5e..40abbde74a1 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -226,6 +226,7 @@ static struct x11drv_win_data *alloc_win_data( Display *display, HWND hwnd ) - data->display = display; - data->vis = default_visual; - data->hwnd = hwnd; -+ list_init( &data->pending_configs ); - pthread_mutex_lock( &win_data_mutex ); - XSaveContext( gdi_display, (XID)hwnd, win_data_context, (char *)data ); - } -@@ -1222,6 +1223,77 @@ static void set_xembed_flags( struct x11drv_win_data *data, unsigned long flags - x11drv_atom(_XEMBED_INFO), 32, PropModeReplace, (unsigned char*)info, 2 ); - } - -+/* discard old/all pending window config requests */ -+static void discard_pending_configs( struct x11drv_win_data *data, BOOL all, unsigned long serial ) -+{ -+ struct config_entry *entry, *next; -+ UINT ticks = NtGetTickCount(); -+ -+ LIST_FOR_EACH_ENTRY_SAFE( entry, next, &data->pending_configs, struct config_entry, entry ) -+ { -+ /* discard all events, or any event with older serial, or queued more than 1s ago */ -+ if (!all && entry->serial >= serial && abs( (int)ticks - (int)entry->ticks ) < 1000) break; -+ WARN( "Discarding old window %p/%lx entry %p, visible_rect %s, serial %ld, ticks %u\n", data->hwnd, -+ data->whole_window, entry, wine_dbgstr_rect(&entry->visible_rect), entry->serial, entry->ticks ); -+ list_remove( &entry->entry ); -+ free( entry ); -+ } -+} -+ -+/* lookup a window config request that matches or supersedes the received event rect / serial */ -+BOOL has_pending_window_config( struct x11drv_win_data *data, const RECT *visible_rect, unsigned long serial ) -+{ -+ struct config_entry *entry, *next, *exact = NULL; -+ UINT ticks = NtGetTickCount(); -+ BOOL found = FALSE; -+ struct list *ptr; -+ -+ TRACE( "window %p/%lx, visible_rect %s, serial %ld, ticks %u\n", data->hwnd, data->whole_window, -+ wine_dbgstr_rect(visible_rect), serial, ticks ); -+ -+ if (!(ptr = list_head( &data->pending_configs ))) return FALSE; -+ entry = LIST_ENTRY( ptr, struct config_entry, entry ); -+ if (entry->serial > serial) return TRUE; /* ignore any serial older than our earliest queued event */ -+ -+ /* lookup for a matching pending window config */ -+ LIST_FOR_EACH_ENTRY( entry, &data->pending_configs, struct config_entry, entry ) -+ { -+ if (EqualRect( &entry->visible_rect, visible_rect )) exact = entry; -+ if (exact) break; -+ } -+ -+ /* discard every event before the matching one */ -+ LIST_FOR_EACH_ENTRY_SAFE( entry, next, &data->pending_configs, struct config_entry, entry ) -+ { -+ found = entry == exact; -+ if (!found) WARN( "Discarding window %p/%lx entry %p, visible_rect %s, serial %ld, ticks %u\n", data->hwnd, -+ data->whole_window, entry, wine_dbgstr_rect(&entry->visible_rect), entry->serial, entry->ticks ); -+ list_remove( &entry->entry ); -+ free( entry ); -+ if (found) break; -+ } -+ -+ if (exact) discard_pending_configs( data, FALSE, serial ); -+ return found; -+} -+ -+/* add a pending window config request with the given visible rect */ -+static void queue_pending_config( struct x11drv_win_data *data, const RECT *visible_rect, unsigned long serial ) -+{ -+ UINT ticks = NtGetTickCount(); -+ struct config_entry *entry; -+ -+ discard_pending_configs( data, FALSE, 0 ); -+ -+ if (!(entry = calloc( 1, sizeof(*entry) ))) return; -+ entry->visible_rect = *visible_rect; -+ entry->serial = serial; -+ entry->ticks = ticks; -+ list_add_tail( &data->pending_configs, &entry->entry ); -+ -+ TRACE( "Queued window %p/%lx entry %p, visible_rect %s, serial %ld, ticks %u\n", data->hwnd, -+ data->whole_window, entry, wine_dbgstr_rect(&entry->visible_rect), entry->serial, entry->ticks ); -+} - - /*********************************************************************** - * map_window -@@ -1246,6 +1318,7 @@ static void map_window( HWND hwnd, DWORD new_style ) - { - update_net_wm_states( data ); - sync_window_style( data ); -+ queue_pending_config( data, &data->rects.visible, NextRequest( data->display ) ); - XMapWindow( data->display, data->whole_window ); - XFlush( data->display ); - } -@@ -1357,14 +1430,15 @@ 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 ); -- data->configure_serial = NextRequest( data->display ); -+ -+ if (data->mapped) queue_pending_config( data, &data->rects.visible, NextRequest( data->display ) ); - XReconfigureWMWindow( data->display, data->whole_window, data->vis.screen, mask, &changes ); - -- TRACE( "win %p/%lx pos %d,%d,%dx%d after %lx changes=%x serial=%lu\n", -+ TRACE( "win %p/%lx pos %d,%d,%dx%d after %lx changes=%x\n", - data->hwnd, data->whole_window, (int)data->rects.visible.left, (int)data->rects.visible.top, - (int)(data->rects.visible.right - data->rects.visible.left), - (int)(data->rects.visible.bottom - data->rects.visible.top), -- changes.sibling, mask, data->configure_serial ); -+ changes.sibling, mask ); - } - - -@@ -1850,6 +1924,7 @@ void X11DRV_DestroyWindow( HWND hwnd ) - free( data->icon_bits ); - XDeleteContext( gdi_display, (XID)hwnd, win_data_context ); - release_win_data( data ); -+ discard_pending_configs( data, TRUE, 0 ); - free( data ); - destroy_gl_drawable( hwnd ); - } -@@ -2675,9 +2750,15 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, BOOL - data->iconic = (new_style & WS_MINIMIZE) != 0; - TRACE( "changing win %p iconic state to %u\n", data->hwnd, data->iconic ); - if (data->iconic) -+ { -+ queue_pending_config( data, &data->rects.visible, NextRequest( data->display ) ); - XIconifyWindow( data->display, data->whole_window, data->vis.screen ); -+ } - else if (is_window_rect_mapped( &new_rects->window )) -+ { -+ queue_pending_config( data, &data->rects.visible, NextRequest( data->display ) ); - XMapWindow( data->display, data->whole_window ); -+ } - update_net_wm_states( data ); - } - else -@@ -2936,7 +3017,11 @@ LRESULT X11DRV_WindowMessage( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ) - if (old_pos.x != pos.x) mask |= CWX; - if (old_pos.y != pos.y) mask |= CWY; - -- if (mask) XReconfigureWMWindow( data->display, data->whole_window, data->vis.screen, mask, &changes ); -+ if (mask) -+ { -+ if (data->mapped) queue_pending_config( data, &data->rects.visible, NextRequest( data->display ) ); -+ XReconfigureWMWindow( data->display, data->whole_window, data->vis.screen, mask, &changes ); -+ } - } - - release_win_data( data ); -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index d2eb35b454e..cb4acdbbf27 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -591,6 +591,14 @@ enum x11drv_net_wm_state - NB_NET_WM_STATES - }; - -+struct config_entry -+{ -+ struct list entry; -+ unsigned long serial; -+ RECT visible_rect; -+ UINT ticks; -+}; -+ - /* x11drv private window data */ - struct x11drv_win_data - { -@@ -616,7 +624,7 @@ struct x11drv_win_data - int wm_state; /* current value of the WM_STATE property */ - DWORD net_wm_state; /* bit mask of active x11drv_net_wm_state values */ - Window embedder; /* window id of embedder */ -- unsigned long configure_serial; /* serial number of last configure request */ -+ struct list pending_configs; /* list of pending struct config_entry */ - Pixmap icon_pixmap; - Pixmap icon_mask; - unsigned long *icon_bits; -@@ -627,6 +635,7 @@ extern struct x11drv_win_data *get_win_data( HWND hwnd ); - extern void release_win_data( struct x11drv_win_data *data ); - extern Window X11DRV_get_whole_window( HWND hwnd ); - extern Window get_dummy_parent(void); -+extern BOOL has_pending_window_config( struct x11drv_win_data *data, const RECT *visible_rect, unsigned long serial ); - - extern void sync_gl_drawable( HWND hwnd, BOOL known_child ); - extern void set_gl_drawable_parent( HWND hwnd, HWND parent ); --- -GitLab - diff --git a/0003-pending-mrs-and-backports/6569-Draft-winex11-Keep-a-list-of-pending-window-config-requests/0002-winex11-Also-discard-near-matching-configs-with-similar-sizes.patch b/0003-pending-mrs-and-backports/6569-Draft-winex11-Keep-a-list-of-pending-window-config-requests/0002-winex11-Also-discard-near-matching-configs-with-similar-sizes.patch deleted file mode 100644 index 1e2d6a9..0000000 --- a/0003-pending-mrs-and-backports/6569-Draft-winex11-Keep-a-list-of-pending-window-config-requests/0002-winex11-Also-discard-near-matching-configs-with-similar-sizes.patch +++ /dev/null @@ -1,55 +0,0 @@ -From 2b7885ce2595abdcf4dc67081408ab1cfaf77d00 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Thu, 26 Sep 2024 13:31:24 +0200 -Subject: [PATCH] winex11: Also discard near-matching configs with similar - sizes. - -When more reconfigurations are known to be pending, and no exact match -is found. ---- - dlls/winex11.drv/window.c | 13 ++++++++++++- - 1 file changed, 12 insertions(+), 1 deletion(-) - -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index 40abbde74a1..33c775b4e7c 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -1243,7 +1243,8 @@ static void discard_pending_configs( struct x11drv_win_data *data, BOOL all, uns - /* lookup a window config request that matches or supersedes the received event rect / serial */ - BOOL has_pending_window_config( struct x11drv_win_data *data, const RECT *visible_rect, unsigned long serial ) - { -- struct config_entry *entry, *next, *exact = NULL; -+ struct config_entry *entry, *next, *exact = NULL, *near = NULL; -+ SIZE current_size, config_size; - UINT ticks = NtGetTickCount(); - BOOL found = FALSE; - struct list *ptr; -@@ -1256,15 +1257,25 @@ BOOL has_pending_window_config( struct x11drv_win_data *data, const RECT *visibl - if (entry->serial > serial) return TRUE; /* ignore any serial older than our earliest queued event */ - - /* lookup for a matching pending window config */ -+ current_size.cx = visible_rect->right - visible_rect->left; -+ current_size.cy = visible_rect->bottom - visible_rect->top; - LIST_FOR_EACH_ENTRY( entry, &data->pending_configs, struct config_entry, entry ) - { -+ config_size.cx = entry->visible_rect.right - entry->visible_rect.left; -+ config_size.cy = entry->visible_rect.bottom - entry->visible_rect.top; -+ if (!near && current_size.cx == config_size.cx && current_size.cy == config_size.cy) near = entry; - if (EqualRect( &entry->visible_rect, visible_rect )) exact = entry; - if (exact) break; - } - -+ /* only match with near configs if we have more pending configs */ -+ if (near && !list_next( &data->pending_configs, &near->entry )) near = NULL; -+ else if (exact) near = NULL; -+ - /* discard every event before the matching one */ - LIST_FOR_EACH_ENTRY_SAFE( entry, next, &data->pending_configs, struct config_entry, entry ) - { -+ if ((found = (entry == near))) break; /* keep near matches in case we can later match them exactly */ - found = entry == exact; - if (!found) WARN( "Discarding window %p/%lx entry %p, visible_rect %s, serial %ld, ticks %u\n", data->hwnd, - data->whole_window, entry, wine_dbgstr_rect(&entry->visible_rect), entry->serial, entry->ticks ); --- -GitLab - diff --git a/0003-pending-mrs-and-backports/6701-winex11-Avoid-processing-RRNotify-events-in-xrandr14-get-id/0001-winex11-Avoid-processing-RRNotify-events-in-xrandr14-get-id.patch b/0003-pending-mrs-and-backports/6701-winex11-Avoid-processing-RRNotify-events-in-xrandr14-get-id/0001-winex11-Avoid-processing-RRNotify-events-in-xrandr14-get-id.patch deleted file mode 100644 index 1f58605..0000000 --- a/0003-pending-mrs-and-backports/6701-winex11-Avoid-processing-RRNotify-events-in-xrandr14-get-id/0001-winex11-Avoid-processing-RRNotify-events-in-xrandr14-get-id.patch +++ /dev/null @@ -1,118 +0,0 @@ -From 7d052c3c94866c1cbf07995a997872ace2e8fef5 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?R=C3=A9mi=20Bernon?= -Date: Fri, 18 Oct 2024 15:52:18 +0200 -Subject: [PATCH] winex11: Avoid processing RRNotify events in xrandr14_get_id. - -This reverts commit b3eb55227aef198a637f80a2fa0bce74aa0a7190. - -Since 278b98f5b21b56abdf9229b12b2a747be6917018 it should be unnecessary to -process the events as the current display mode is written to the registry. - -This fixes a random deadlock that happens when a window is updating its state -while another thread changes the current display settings. ---- - dlls/winex11.drv/event.c | 2 +- - dlls/winex11.drv/window.c | 1 + - dlls/winex11.drv/x11drv.h | 1 - - dlls/winex11.drv/x11drv_main.c | 1 - - dlls/winex11.drv/xrandr.c | 28 ---------------------------- - 5 files changed, 2 insertions(+), 31 deletions(-) - -diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index 34a364e11e3..f1535b31df0 100644 ---- a/dlls/winex11.drv/event.c -+++ b/dlls/winex11.drv/event.c -@@ -404,7 +404,7 @@ static inline BOOL call_event_handler( Display *display, XEvent *event ) - /*********************************************************************** - * process_events - */ --BOOL process_events( Display *display, Bool (*filter)(Display*, XEvent*,XPointer), ULONG_PTR arg ) -+static BOOL process_events( Display *display, Bool (*filter)(Display*, XEvent*,XPointer), ULONG_PTR arg ) - { - XEvent event, prev_event; - int count = 0; -diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index 5400c5bc768..f32e70cf100 100644 ---- a/dlls/winex11.drv/window.c -+++ b/dlls/winex11.drv/window.c -@@ -1998,6 +1998,7 @@ BOOL X11DRV_CreateWindow( HWND hwnd ) - CWOverrideRedirect | CWEventMask, &attr ); - XFlush( data->display ); - NtUserSetProp( hwnd, clip_window_prop, (HANDLE)data->clip_window ); -+ X11DRV_DisplayDevices_RegisterEventHandlers(); - } - return TRUE; - } -diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h -index 6af72fe3e32..a3b6e065f99 100644 ---- a/dlls/winex11.drv/x11drv.h -+++ b/dlls/winex11.drv/x11drv.h -@@ -681,7 +681,6 @@ extern void ungrab_clipping_window(void); - extern void move_resize_window( HWND hwnd, int dir ); - extern void X11DRV_InitKeyboard( Display *display ); - extern void X11DRV_InitMouse( Display *display ); --extern BOOL process_events( Display *display, Bool (*filter)(Display*, XEvent*, XPointer), ULONG_PTR arg ); - extern BOOL X11DRV_ProcessEvents( DWORD mask ); - extern HWND *build_hwnd_list(void); - -diff --git a/dlls/winex11.drv/x11drv_main.c b/dlls/winex11.drv/x11drv_main.c -index 3f8e48a7a8d..a21d85bc6c2 100644 ---- a/dlls/winex11.drv/x11drv_main.c -+++ b/dlls/winex11.drv/x11drv_main.c -@@ -688,7 +688,6 @@ static NTSTATUS x11drv_init( void *arg ) - if (use_xim) use_xim = xim_init( input_style ); - - init_user_driver(); -- X11DRV_DisplayDevices_RegisterEventHandlers(); - return STATUS_SUCCESS; - } - -diff --git a/dlls/winex11.drv/xrandr.c b/dlls/winex11.drv/xrandr.c -index d8e6f476cf7..8333c4e2c5b 100644 ---- a/dlls/winex11.drv/xrandr.c -+++ b/dlls/winex11.drv/xrandr.c -@@ -1244,32 +1244,6 @@ static void xrandr14_register_event_handlers(void) - "XRandR ProviderChange" ); - } - --static Bool filter_rrnotify_event( Display *display, XEvent *event, char *arg ) --{ -- ULONG_PTR event_base = (ULONG_PTR)arg; -- -- if (event->type == event_base + RRNotify_CrtcChange -- || event->type == event_base + RRNotify_OutputChange -- || event->type == event_base + RRNotify_ProviderChange) -- return 1; -- -- return 0; --} -- --static void process_rrnotify_events(void) --{ -- struct x11drv_thread_data *data = x11drv_thread_data(); -- int event_base, error_base; -- -- if (!data) return; -- if (data->current_event) return; /* don't process nested events */ -- -- if (!pXRRQueryExtension( data->display, &event_base, &error_base )) -- return; -- -- process_events( data->display, filter_rrnotify_event, event_base ); --} -- - /* XRandR 1.4 display settings handler */ - static BOOL xrandr14_get_id( const WCHAR *device_name, BOOL is_primary, x11drv_settings_id *id ) - { -@@ -1285,8 +1259,6 @@ static BOOL xrandr14_get_id( const WCHAR *device_name, BOOL is_primary, x11drv_s - if (*end) - return FALSE; - -- process_rrnotify_events(); -- - /* Update cache */ - pthread_mutex_lock( &xrandr_mutex ); - if (!current_modes) --- -GitLab - diff --git a/0003-pending-mrs-and-backports/6722-win32u-Yet-more-arc-fixes/0001-win32u-Normalize-inverted-rectangles-in-dibdrv-RoundRect-.patch b/0003-pending-mrs-and-backports/6722-win32u-Yet-more-arc-fixes/0001-win32u-Normalize-inverted-rectangles-in-dibdrv-RoundRect-.patch new file mode 100644 index 0000000..6bf7a8e --- /dev/null +++ b/0003-pending-mrs-and-backports/6722-win32u-Yet-more-arc-fixes/0001-win32u-Normalize-inverted-rectangles-in-dibdrv-RoundRect-.patch @@ -0,0 +1,36 @@ +From df0921903cee6871c32d81b4ff3ea96b6913ee96 Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura +Date: Tue, 22 Oct 2024 13:23:16 -0500 +Subject: [PATCH] win32u: Normalize inverted rectangles in dibdrv_RoundRect(). + +--- + dlls/win32u/dibdrv/graphics.c | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/dlls/win32u/dibdrv/graphics.c b/dlls/win32u/dibdrv/graphics.c +index cc62d6a681b..e7648cb2596 100644 +--- a/dlls/win32u/dibdrv/graphics.c ++++ b/dlls/win32u/dibdrv/graphics.c +@@ -1556,6 +1556,19 @@ BOOL dibdrv_RoundRect( PHYSDEV dev, INT left, INT top, INT right, INT bottom, + return FALSE; + } + ++ if (right < left) ++ { ++ int tmp = left; ++ left = right; ++ right = tmp; ++ } ++ if (bottom < top) ++ { ++ int tmp = top; ++ top = bottom; ++ bottom = tmp; ++ } ++ + SetRect( &rect, left, top, left + ellipse_width, top + ellipse_height ); + /* Points are relative to the arc center. + * We just need to specify any point on the vector. */ +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/6722-win32u-Yet-more-arc-fixes/0002-win32u-Correctly-handle-transforms-which-flip-in-get-arc-points-.patch b/0003-pending-mrs-and-backports/6722-win32u-Yet-more-arc-fixes/0002-win32u-Correctly-handle-transforms-which-flip-in-get-arc-points-.patch new file mode 100644 index 0000000..5e1ec35 --- /dev/null +++ b/0003-pending-mrs-and-backports/6722-win32u-Yet-more-arc-fixes/0002-win32u-Correctly-handle-transforms-which-flip-in-get-arc-points-.patch @@ -0,0 +1,30 @@ +From 32cb2737c4ea8bfcaf41609fbd78849311d709ca Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura +Date: Tue, 22 Oct 2024 13:24:13 -0500 +Subject: [PATCH] win32u: Correctly handle transforms which flip in + get_arc_points(). + +--- + dlls/win32u/dibdrv/graphics.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/dlls/win32u/dibdrv/graphics.c b/dlls/win32u/dibdrv/graphics.c +index e7648cb2596..64d58ac6ed7 100644 +--- a/dlls/win32u/dibdrv/graphics.c ++++ b/dlls/win32u/dibdrv/graphics.c +@@ -316,6 +316,12 @@ static int get_arc_points( DC *dc, int arc_dir, const RECT *rect, POINT start, P + + count = generate_ellipse_top_half( dc, width, height, points ); + ++ /* The ellipse is always generated counterclockwise from the origin. ++ * This means our points will essentially be backwards if the world ++ * transform includes a flip. Swap the arc direction to correct for this. */ ++ if (dc->xformWorld2Vport.eM11 * dc->xformWorld2Vport.eM22 < dc->xformWorld2Vport.eM12 * dc->xformWorld2Vport.eM21) ++ arc_dir = (arc_dir == AD_CLOCKWISE ? AD_COUNTERCLOCKWISE : AD_CLOCKWISE); ++ + /* Transform the start and end, but do not translate them, so that they + * remain relative to the ellipse center. */ + lp_to_dp_no_translate( dc, &start ); +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/6722-win32u-Yet-more-arc-fixes/0003-win32u-Do-not-convert-back-to-integer-before-finding-intersections.patch b/0003-pending-mrs-and-backports/6722-win32u-Yet-more-arc-fixes/0003-win32u-Do-not-convert-back-to-integer-before-finding-intersections.patch new file mode 100644 index 0000000..3faeb54 --- /dev/null +++ b/0003-pending-mrs-and-backports/6722-win32u-Yet-more-arc-fixes/0003-win32u-Do-not-convert-back-to-integer-before-finding-intersections.patch @@ -0,0 +1,112 @@ +From 40f4a0422b880f3cd6796f98c8eea0df00aa107e Mon Sep 17 00:00:00 2001 +From: Elizabeth Figura +Date: Tue, 22 Oct 2024 16:56:40 -0500 +Subject: [PATCH] win32u: Do not convert back to integer before finding + intersections. + +This unnecessarily loses precision, and if the point is very close to the origin +(as for the internal arcs generated by RoundRect(), but also for those specified +manually) this may generate an incorrect arc. + +This addresses the last artifacts from bug 35331. +--- + dlls/win32u/dibdrv/graphics.c | 41 +++++++++++++++-------------------- + 1 file changed, 17 insertions(+), 24 deletions(-) + +diff --git a/dlls/win32u/dibdrv/graphics.c b/dlls/win32u/dibdrv/graphics.c +index 64d58ac6ed7..7af658230a5 100644 +--- a/dlls/win32u/dibdrv/graphics.c ++++ b/dlls/win32u/dibdrv/graphics.c +@@ -267,7 +267,7 @@ static unsigned int generate_ellipse_top_half( const DC *dc, double width, doubl + return pos; + } + +-static int find_intersection( const POINT *points, int x, int y, int count ) ++static int find_intersection( const POINT *points, double x, double y, int count ) + { + int i; + +@@ -299,15 +299,16 @@ static int find_intersection( const POINT *points, int x, int y, int count ) + } + } + +-static void lp_to_dp_no_translate( DC *dc, POINT *point ) ++static void lp_to_dp_no_translate( DC *dc, double *x, double *y ) + { +- double x = point->x; +- double y = point->y; +- point->x = GDI_ROUND( x * dc->xformWorld2Vport.eM11 + y * dc->xformWorld2Vport.eM21 ); +- point->y = GDI_ROUND( x * dc->xformWorld2Vport.eM12 + y * dc->xformWorld2Vport.eM22 ); ++ double in_x = *x, in_y = *y; ++ ++ *x = in_x * dc->xformWorld2Vport.eM11 + in_y * dc->xformWorld2Vport.eM21; ++ *y = in_x * dc->xformWorld2Vport.eM12 + in_y * dc->xformWorld2Vport.eM22; + } + +-static int get_arc_points( DC *dc, int arc_dir, const RECT *rect, POINT start, POINT end, POINT *points ) ++static int get_arc_points( DC *dc, int arc_dir, const RECT *rect, double start_x, double start_y, ++ double end_x, double end_y, POINT *points ) + { + int i, pos, count, start_pos, end_pos; + int width = rect->right - rect->left; +@@ -324,11 +325,11 @@ static int get_arc_points( DC *dc, int arc_dir, const RECT *rect, POINT start, P + + /* Transform the start and end, but do not translate them, so that they + * remain relative to the ellipse center. */ +- lp_to_dp_no_translate( dc, &start ); +- lp_to_dp_no_translate( dc, &end ); ++ lp_to_dp_no_translate( dc, &start_x, &start_y ); ++ lp_to_dp_no_translate( dc, &end_x, &end_y ); + +- start_pos = find_intersection( points, start.x, start.y, count ); +- end_pos = find_intersection( points, end.x, end.y, count ); ++ start_pos = find_intersection( points, start_x, start_y, count ); ++ end_pos = find_intersection( points, end_x, end_y, count ); + if (arc_dir == AD_CLOCKWISE) + { + int tmp = start_pos; +@@ -429,9 +430,9 @@ static BOOL draw_arc( PHYSDEV dev, INT left, INT top, INT right, INT bottom, + { + points[0] = dc->attr->cur_pos; + lp_to_dp( dc, points, 1 ); +- count = 1 + get_arc_points( dc, dc->attr->arc_direction, &rect, pt[0], pt[1], points + 1 ); ++ count = 1 + get_arc_points( dc, dc->attr->arc_direction, &rect, pt[0].x, pt[0].y, pt[1].x, pt[1].y, points + 1 ); + } +- else count = get_arc_points( dc, dc->attr->arc_direction, &rect, pt[0], pt[1], points ); ++ else count = get_arc_points( dc, dc->attr->arc_direction, &rect, pt[0].x, pt[0].y, pt[1].x, pt[1].y, points ); + + if (count > max_points) + ERR( "point count %u exceeds max points %u\n", count, max_points ); +@@ -1538,7 +1539,7 @@ BOOL dibdrv_RoundRect( PHYSDEV dev, INT left, INT top, INT right, INT bottom, + dibdrv_physdev *pdev = get_dibdrv_pdev( dev ); + DC *dc = get_physdev_dc( dev ); + RECT rect; +- POINT start, end, rect_center, *points, *top_points; ++ POINT rect_center, *points, *top_points; + int count, max_points; + BOOL ret = TRUE; + HRGN outline = 0, interior = 0; +@@ -1578,18 +1579,10 @@ BOOL dibdrv_RoundRect( PHYSDEV dev, INT left, INT top, INT right, INT bottom, + SetRect( &rect, left, top, left + ellipse_width, top + ellipse_height ); + /* Points are relative to the arc center. + * We just need to specify any point on the vector. */ +- start.x = -1; +- start.y = 0; +- end.x = 0; +- end.y = -1; +- count = get_arc_points( dc, AD_CLOCKWISE, &rect, start, end, top_points ); ++ count = get_arc_points( dc, AD_CLOCKWISE, &rect, -1.0, 0.0, 0.0, -1.0, top_points ); + + SetRect( &rect, right - ellipse_width, top, right, top + ellipse_height ); +- start.x = 0; +- start.y = -1; +- end.x = 1; +- end.y = 0; +- count += get_arc_points( dc, AD_CLOCKWISE, &rect, start, end, top_points + count ); ++ count += get_arc_points( dc, AD_CLOCKWISE, &rect, 0.0, -1.0, 1.0, 0.0, top_points + count ); + + if (count * 2 > max_points) + ERR( "point count %u * 2 exceeds max points %u\n", count, max_points ); +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0001-winex11-Call-window-set-wm-state-when-unmapping-embedded-windows.patch b/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0001-winex11-Call-window-set-wm-state-when-unmapping-embedded-windows.patch new file mode 100644 index 0000000..c2ecf2e --- /dev/null +++ b/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0001-winex11-Call-window-set-wm-state-when-unmapping-embedded-windows.patch @@ -0,0 +1,42 @@ +From 1c91ef50127b26e184d453510262b08254de4ee8 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Sat, 19 Oct 2024 10:43:41 +0200 +Subject: [PATCH] winex11: Call window_set_wm_state when unmapping embedded + windows. + +--- + dlls/winex11.drv/window.c | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c +index 58fc99275f4..46006874dfa 100644 +--- a/dlls/winex11.drv/window.c ++++ b/dlls/winex11.drv/window.c +@@ -2398,17 +2398,19 @@ void X11DRV_SystrayDockClear( HWND hwnd ) + BOOL X11DRV_SystrayDockRemove( HWND hwnd ) + { + struct x11drv_win_data *data; +- BOOL ret; ++ BOOL ret = FALSE; + +- /* make sure we don't try to unmap it, it confuses some systray docks */ + if ((data = get_win_data( hwnd ))) + { +- if ((ret = data->embedded)) data->mapped = FALSE; ++ if ((ret = data->embedded)) ++ { ++ window_set_wm_state( data, WithdrawnState ); ++ data->mapped = FALSE; ++ } + release_win_data( data ); +- return ret; + } + +- return FALSE; ++ return ret; + } + + +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0002-winex11-Compute-WindowPosChanged-updates-in-terms-of-style-changes.patch b/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0002-winex11-Compute-WindowPosChanged-updates-in-terms-of-style-changes.patch new file mode 100644 index 0000000..3085c80 --- /dev/null +++ b/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0002-winex11-Compute-WindowPosChanged-updates-in-terms-of-style-changes.patch @@ -0,0 +1,69 @@ +From 92a31166855bd2c0acd15093890f49815c373080 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Sat, 19 Oct 2024 10:25:45 +0200 +Subject: [PATCH] winex11: Compute WindowPosChanged updates in terms of style + changes. + +Making the changes computation more readable, matching styles between +the last requested (pending_state) style and the current style. +--- + dlls/winex11.drv/window.c | 16 ++++++++++++---- + 1 file changed, 12 insertions(+), 4 deletions(-) + +diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c +index 46006874dfa..d75afa33ff9 100644 +--- a/dlls/winex11.drv/window.c ++++ b/dlls/winex11.drv/window.c +@@ -2773,13 +2773,21 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, BOOL + { + struct x11drv_thread_data *thread_data; + struct x11drv_win_data *data; +- UINT new_style = NtUserGetWindowLongW( hwnd, GWL_STYLE ); ++ UINT new_style = NtUserGetWindowLongW( hwnd, GWL_STYLE ), old_style; + struct window_rects old_rects; + BOOL was_fullscreen; + int event_type; + + if (!(data = get_win_data( hwnd ))) return; + ++ /* Compute the necessary changes to transition from the last requested ++ * window state (old_style), to the desired window state (new_style). ++ */ ++ old_style = new_style & ~(WS_VISIBLE | WS_MINIMIZE | WS_MAXIMIZE); ++ if (data->pending_state.wm_state == IconicState) old_style |= WS_MINIMIZE; ++ if (data->pending_state.wm_state != WithdrawnState) old_style |= WS_VISIBLE; ++ if (data->pending_state.net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)) old_style |= WS_MAXIMIZE; ++ + thread_data = x11drv_thread_data(); + + old_rects = data->rects; +@@ -2816,7 +2824,7 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, BOOL + event_type = 0; /* ignore other events */ + } + +- if (data->mapped && event_type != ReparentNotify) ++ if ((old_style & WS_VISIBLE) && event_type != ReparentNotify) + { + if (((swp_flags & SWP_HIDEWINDOW) && !(new_style & WS_VISIBLE)) || + (!event_type && !(new_style & WS_MINIMIZE) && +@@ -2853,7 +2861,7 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, BOOL + if ((new_style & WS_VISIBLE) && + ((new_style & WS_MINIMIZE) || is_window_rect_mapped( &new_rects->window ))) + { +- if (!data->mapped) ++ if (!(old_style & WS_VISIBLE)) + { + BOOL needs_icon = !data->icon_pixmap; + BOOL needs_map = TRUE; +@@ -2866,7 +2874,7 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, BOOL + if (needs_map) map_window( hwnd, new_style ); + return; + } +- else if ((swp_flags & SWP_STATECHANGED) && (!data->iconic != !(new_style & WS_MINIMIZE))) ++ else if ((swp_flags & SWP_STATECHANGED) && (old_style & WS_MINIMIZE) != (new_style & WS_MINIMIZE)) + { + set_wm_hints( data ); + data->iconic = (new_style & WS_MINIMIZE) != 0; +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0003-winex11-Compute-ConfigureNotify-updates-in-terms-of-style-changes.patch b/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0003-winex11-Compute-ConfigureNotify-updates-in-terms-of-style-changes.patch new file mode 100644 index 0000000..e101012 --- /dev/null +++ b/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0003-winex11-Compute-ConfigureNotify-updates-in-terms-of-style-changes.patch @@ -0,0 +1,72 @@ +From 0c73fa6637664622b41210476fdc0db06aab58f1 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Sat, 19 Oct 2024 10:34:49 +0200 +Subject: [PATCH] winex11: Compute ConfigureNotify updates in terms of style + changes. + +Making the changes computation more readable, matching styles between +the current Win32 style and the current X11 (current_state) style. +--- + dlls/winex11.drv/event.c | 21 ++++++++++++++------- + 1 file changed, 14 insertions(+), 7 deletions(-) + +diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c +index 21bc5fc2813..2a95552b8d6 100644 +--- a/dlls/winex11.drv/event.c ++++ b/dlls/winex11.drv/event.c +@@ -1062,9 +1062,8 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) + struct x11drv_win_data *data; + RECT rect; + POINT pos = {event->x, event->y}; +- UINT flags; ++ UINT flags, old_style, new_style; + int cx, cy, x, y; +- DWORD style; + + if (!hwnd) return FALSE; + if (!(data = get_win_data( hwnd ))) return FALSE; +@@ -1083,6 +1082,15 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) + SetRect( &rect, pos.x, pos.y, pos.x + event->width, pos.y + event->height ); + window_configure_notify( data, event->serial, &rect ); + ++ /* Compute the necessary changes to transition from the current Win32 ++ * window state (old_style), to the current X11 window state (new_style). ++ */ ++ old_style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ); ++ new_style = old_style & ~(WS_VISIBLE | WS_MINIMIZE | WS_MAXIMIZE); ++ if (data->current_state.wm_state == IconicState) new_style |= WS_MINIMIZE; ++ if (data->current_state.wm_state != WithdrawnState) new_style |= WS_VISIBLE; ++ if (data->current_state.net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)) new_style |= WS_MAXIMIZE; ++ + if (!data->mapped || data->iconic) goto done; + if (!data->whole_window || !data->managed) goto done; + if (data->configure_serial && (long)(data->configure_serial - event->serial) > 0) +@@ -1124,13 +1132,12 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) + hwnd, (int)(data->rects.window.right - data->rects.window.left), + (int)(data->rects.window.bottom - data->rects.window.top), cx, cy ); + +- style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ); +- if ((style & WS_CAPTION) == WS_CAPTION || !data->is_fullscreen) ++ if ((old_style & WS_CAPTION) == WS_CAPTION || !data->is_fullscreen) + { + data->net_wm_state = get_window_net_wm_state( event->display, data->whole_window ); +- if ((data->net_wm_state & (1 << NET_WM_STATE_MAXIMIZED))) ++ if ((new_style & WS_MAXIMIZE)) + { +- if (!(style & WS_MAXIMIZE)) ++ if (!(old_style & WS_MAXIMIZE)) + { + TRACE( "win %p/%lx is maximized\n", data->hwnd, data->whole_window ); + release_win_data( data ); +@@ -1138,7 +1145,7 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) + return TRUE; + } + } +- else if (style & WS_MAXIMIZE) ++ else if (old_style & WS_MAXIMIZE) + { + TRACE( "window %p/%lx is no longer maximized\n", data->hwnd, data->whole_window ); + release_win_data( data ); +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0004-winex11-Compute-WM-STATE-notify-updates-in-terms-of-style-changes.patch b/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0004-winex11-Compute-WM-STATE-notify-updates-in-terms-of-style-changes.patch new file mode 100644 index 0000000..cef0b51 --- /dev/null +++ b/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0004-winex11-Compute-WM-STATE-notify-updates-in-terms-of-style-changes.patch @@ -0,0 +1,101 @@ +From 01e72c56fbfc0a57e1188a9c287118f7573af6f2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Sat, 19 Oct 2024 10:52:16 +0200 +Subject: [PATCH] winex11: Compute WM_STATE notify updates in terms of style + changes. + +Making the changes computation more readable, matching styles between +the current Win32 style and the current X11 (current_state) style. +--- + dlls/winex11.drv/event.c | 33 ++++++++++++++++++++------------- + 1 file changed, 20 insertions(+), 13 deletions(-) + +diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c +index 2a95552b8d6..088a124654e 100644 +--- a/dlls/winex11.drv/event.c ++++ b/dlls/winex11.drv/event.c +@@ -1226,12 +1226,21 @@ static int get_window_xembed_info( Display *display, Window window ) + static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL update_window ) + { + struct x11drv_win_data *data; +- UINT style, value = 0; ++ UINT old_style, new_style, value = 0; + + if (!(data = get_win_data( hwnd ))) return; + if (event->state == PropertyNewValue) value = get_window_wm_state( event->display, event->window ); + if (update_window) window_wm_state_notify( data, event->serial, value ); + ++ /* Compute the necessary changes to transition from the current Win32 ++ * window state (old_style), to the current X11 window state (new_style). ++ */ ++ old_style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ); ++ new_style = old_style & ~(WS_VISIBLE | WS_MINIMIZE | WS_MAXIMIZE); ++ if (data->current_state.wm_state == IconicState) new_style |= WS_MINIMIZE; ++ if (data->current_state.wm_state != WithdrawnState) new_style |= WS_VISIBLE; ++ if (data->current_state.net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)) new_style |= WS_MAXIMIZE; ++ + switch(event->state) + { + case PropertyDelete: +@@ -1257,48 +1266,46 @@ static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL updat + + if (!update_window || !data->managed || !data->mapped) goto done; + +- style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ); +- +- if (data->iconic && data->wm_state == NormalState) /* restore window */ ++ if ((old_style & WS_MINIMIZE) && !(new_style & WS_MINIMIZE)) /* restore window */ + { + data->iconic = FALSE; + data->net_wm_state = get_window_net_wm_state( event->display, data->whole_window ); +- if ((style & WS_CAPTION) == WS_CAPTION && (data->net_wm_state & (1 << NET_WM_STATE_MAXIMIZED))) ++ if ((old_style & WS_CAPTION) == WS_CAPTION && (new_style & WS_MAXIMIZE)) + { +- if ((style & WS_MAXIMIZEBOX) && !(style & WS_DISABLED)) ++ if ((old_style & WS_MAXIMIZEBOX) && !(old_style & WS_DISABLED)) + { + TRACE( "restoring to max %p/%lx\n", data->hwnd, data->whole_window ); + release_win_data( data ); + send_message( hwnd, WM_SYSCOMMAND, SC_MAXIMIZE, 0 ); + return; + } +- TRACE( "not restoring to max win %p/%lx style %08x\n", data->hwnd, data->whole_window, style ); ++ TRACE( "window %p/%lx style %#x not restoring to max\n", data->hwnd, data->whole_window, old_style ); + } + else + { +- if (style & (WS_MINIMIZE | WS_MAXIMIZE)) ++ if (old_style & (WS_MINIMIZE | WS_MAXIMIZE)) + { + TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window ); + release_win_data( data ); +- if ((style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE)) ++ if ((old_style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE)) + NtUserSetActiveWindow( hwnd ); + send_message( hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 ); + return; + } +- TRACE( "not restoring win %p/%lx style %08x\n", data->hwnd, data->whole_window, style ); ++ TRACE( "window %p/%lx style %#x not restoring\n", data->hwnd, data->whole_window, old_style ); + } + } +- else if (!data->iconic && data->wm_state == IconicState) ++ else if (!(old_style & WS_MINIMIZE) && (new_style & WS_MINIMIZE)) + { + data->iconic = TRUE; +- if ((style & WS_MINIMIZEBOX) && !(style & WS_DISABLED)) ++ if ((old_style & WS_MINIMIZEBOX) && !(old_style & WS_DISABLED)) + { + TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window ); + release_win_data( data ); + send_message( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, 0 ); + return; + } +- TRACE( "not minimizing win %p/%lx style %08x\n", data->hwnd, data->whole_window, style ); ++ TRACE( "window %p/%lx style %#x not minimizing\n", data->hwnd, data->whole_window, old_style ); + } + done: + release_win_data( data ); +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0005-winex11-Use-the-style-to-decide-whether-a-window-is-currently-visible-or-iconic.patch b/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0005-winex11-Use-the-style-to-decide-whether-a-window-is-currently-visible-or-iconic.patch new file mode 100644 index 0000000..c5ab66b --- /dev/null +++ b/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0005-winex11-Use-the-style-to-decide-whether-a-window-is-currently-visible-or-iconic.patch @@ -0,0 +1,67 @@ +From 84bbfcdb916752bbe3e72827aaff7752c6ee913d Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Fri, 25 Oct 2024 08:40:37 +0200 +Subject: [PATCH] winex11: Use the style to decide whether a window is + currently visible or iconic. + +The mapped and iconic flags should match the last requested state at +all time. Unless we've missed sending an update this should match the +current Win32 state, and we should be able use it instead as a more +accurate source of information about the supposed window state. + +When receiving config changes, we don't want to apply changes to a +window which is supposed to be hidden or minimized. When receiving state +changes, we don't want to apply changes to a window which is supposed to +be hidden, regardless of the X11 believes. +--- + dlls/winex11.drv/event.c | 4 ++-- + dlls/winex11.drv/window.c | 4 ++-- + 2 files changed, 4 insertions(+), 4 deletions(-) + +diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c +index 088a124654e..5e4e1e458dd 100644 +--- a/dlls/winex11.drv/event.c ++++ b/dlls/winex11.drv/event.c +@@ -1091,7 +1091,7 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) + if (data->current_state.wm_state != WithdrawnState) new_style |= WS_VISIBLE; + if (data->current_state.net_wm_state & (1 << NET_WM_STATE_MAXIMIZED)) new_style |= WS_MAXIMIZE; + +- if (!data->mapped || data->iconic) goto done; ++ if (!(old_style & WS_VISIBLE) || (old_style & WS_MINIMIZE)) goto done; + if (!data->whole_window || !data->managed) goto done; + if (data->configure_serial && (long)(data->configure_serial - event->serial) > 0) + { +@@ -1264,7 +1264,7 @@ static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL updat + break; + } + +- if (!update_window || !data->managed || !data->mapped) goto done; ++ if (!update_window || !data->managed || !(old_style & WS_VISIBLE)) goto done; + + if ((old_style & WS_MINIMIZE) && !(new_style & WS_MINIMIZE)) /* restore window */ + { +diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c +index d75afa33ff9..0bb7175c29c 100644 +--- a/dlls/winex11.drv/window.c ++++ b/dlls/winex11.drv/window.c +@@ -1613,7 +1613,7 @@ static void sync_window_position( struct x11drv_win_data *data, UINT swp_flags ) + DWORD ex_style = NtUserGetWindowLongW( data->hwnd, GWL_EXSTYLE ); + BOOL above = FALSE; + +- if (data->managed && data->iconic) return; ++ if (data->managed && (style & WS_MINIMIZE)) return; + + if (!(swp_flags & SWP_NOZORDER) || (swp_flags & SWP_SHOWWINDOW)) + { +@@ -2927,7 +2927,7 @@ UINT X11DRV_ShowWindow( HWND hwnd, INT cmd, RECT *rect, UINT swp ) + } + goto done; + } +- if (!data->managed || !data->mapped || data->iconic) goto done; ++ if (!data->managed || !(style & WS_VISIBLE) || (style & WS_MINIMIZE)) goto done; + + /* only fetch the new rectangle if the ShowWindow was a result of a window manager event */ + +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0006-winex11-Use-pending-state-wm-state-to-decide-if-requests-can-be-sent-directly.patch b/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0006-winex11-Use-pending-state-wm-state-to-decide-if-requests-can-be-sent-directly.patch new file mode 100644 index 0000000..108df75 --- /dev/null +++ b/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0006-winex11-Use-pending-state-wm-state-to-decide-if-requests-can-be-sent-directly.patch @@ -0,0 +1,44 @@ +From 96d1d62cbfdb5f508c8df2c608db01cbe5a80a17 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Sat, 19 Oct 2024 10:40:45 +0200 +Subject: [PATCH] winex11: Use pending_state.wm_state to decide if requests can + be sent directly. + +--- + dlls/winex11.drv/window.c | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c +index 0bb7175c29c..035f8d5cf0b 100644 +--- a/dlls/winex11.drv/window.c ++++ b/dlls/winex11.drv/window.c +@@ -1187,7 +1187,7 @@ static void update_net_wm_fullscreen_monitors( struct x11drv_win_data *data ) + && !data->net_wm_fullscreen_monitors_set) + return; + +- if (!data->mapped) ++ if (data->pending_state.wm_state == WithdrawnState) + { + XChangeProperty( data->display, data->whole_window, x11drv_atom(_NET_WM_FULLSCREEN_MONITORS), + XA_CARDINAL, 32, PropModeReplace, (unsigned char *)monitors, 4 ); +@@ -1215,7 +1215,7 @@ static void window_set_net_wm_state( struct x11drv_win_data *data, UINT new_stat + + if (!data->whole_window) return; /* no window, nothing to update */ + +- if (!data->mapped) /* set the _NET_WM_STATE atom directly */ ++ if (data->pending_state.wm_state == WithdrawnState) /* set the _NET_WM_STATE atom directly */ + { + Atom atoms[NB_NET_WM_STATES + 1]; + +@@ -3272,7 +3272,7 @@ void X11DRV_FlashWindowEx( FLASHWINFO *pfinfo ) + if (!data) + return; + +- if (data->mapped) ++ if (data->pending_state.wm_state != WithdrawnState) + { + xev.type = ClientMessage; + xev.xclient.window = data->whole_window; +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0007-winex11-Use-pending-state-wm-state-to-decide-whether-a-window-is-mapped.patch b/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0007-winex11-Use-pending-state-wm-state-to-decide-whether-a-window-is-mapped.patch new file mode 100644 index 0000000..9e947ab --- /dev/null +++ b/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0007-winex11-Use-pending-state-wm-state-to-decide-whether-a-window-is-mapped.patch @@ -0,0 +1,76 @@ +From dba762f95b157d1a63853b73fc9fc97301d19b67 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Sun, 20 Oct 2024 11:03:10 +0200 +Subject: [PATCH] winex11: Use pending_state.wm_state to decide whether a + window is mapped. + +--- + dlls/winex11.drv/event.c | 2 +- + dlls/winex11.drv/window.c | 10 +++++----- + 2 files changed, 6 insertions(+), 6 deletions(-) + +diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c +index 5e4e1e458dd..11e93a3a100 100644 +--- a/dlls/winex11.drv/event.c ++++ b/dlls/winex11.drv/event.c +@@ -998,7 +998,7 @@ static BOOL X11DRV_MapNotify( HWND hwnd, XEvent *event ) + + if (!(data = get_win_data( hwnd ))) return FALSE; + +- if (!data->managed && !data->embedded && data->mapped) ++ if (!data->managed && !data->embedded && data->pending_state.wm_state == NormalState) + { + HWND hwndFocus = get_focus(); + if (hwndFocus && NtUserIsChild( hwnd, hwndFocus )) +diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c +index 035f8d5cf0b..dcba464daf8 100644 +--- a/dlls/winex11.drv/window.c ++++ b/dlls/winex11.drv/window.c +@@ -1448,7 +1448,7 @@ static void map_window( HWND hwnd, DWORD new_style ) + + if (!(data = get_win_data( hwnd ))) return; + +- if (data->whole_window && !data->mapped) ++ if (data->whole_window && data->pending_state.wm_state == WithdrawnState) + { + TRACE( "win %p/%lx\n", data->hwnd, data->whole_window ); + +@@ -1479,7 +1479,7 @@ static void unmap_window( HWND hwnd ) + + if (!(data = get_win_data( hwnd ))) return; + +- if (data->mapped) ++ if (data->pending_state.wm_state != WithdrawnState) + { + TRACE( "win %p/%lx\n", data->hwnd, data->whole_window ); + window_set_wm_state( data, WithdrawnState ); +@@ -3018,7 +3018,7 @@ void X11DRV_SetLayeredWindowAttributes( HWND hwnd, COLORREF key, BYTE alpha, DWO + sync_window_opacity( data->display, data->whole_window, alpha, flags ); + + data->layered = TRUE; +- if (!data->mapped) /* mapping is delayed until attributes are set */ ++ if (data->pending_state.wm_state == WithdrawnState) /* mapping is delayed until attributes are set */ + { + DWORD style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ); + +@@ -3054,7 +3054,7 @@ void X11DRV_UpdateLayeredWindow( HWND hwnd, UINT flags ) + BOOL mapped; + + if (!(data = get_win_data( hwnd ))) return; +- mapped = data->mapped; ++ mapped = data->pending_state.wm_state != WithdrawnState; + release_win_data( data ); + + /* layered windows are mapped only once their attributes are set */ +@@ -3206,7 +3206,7 @@ LRESULT X11DRV_SysCommand( HWND hwnd, WPARAM wparam, LPARAM lparam ) + if (wparam == SC_SCREENSAVE && hwnd == NtUserGetDesktopWindow()) return start_screensaver(); + return -1; + } +- if (!data->whole_window || !data->managed || !data->mapped) goto failed; ++ if (!data->whole_window || !data->managed || data->pending_state.wm_state == WithdrawnState) goto failed; + + switch (wparam & 0xfff0) + { +-- +GitLab + diff --git a/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0008-winex11-Get-rid-of-the-now-unnecessary-mapped-iconic-net-wm-state-flags.patch b/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0008-winex11-Get-rid-of-the-now-unnecessary-mapped-iconic-net-wm-state-flags.patch new file mode 100644 index 0000000..4c8c3f9 --- /dev/null +++ b/0003-pending-mrs-and-backports/6731-winex11-Replace-win-data-iconic-mapped-net-wm-state-flags/0008-winex11-Get-rid-of-the-now-unnecessary-mapped-iconic-net-wm-state-flags.patch @@ -0,0 +1,182 @@ +From 0f5161d4b419ea31a88175fb2fdea9e0bcb1a5f5 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Sat, 19 Oct 2024 10:25:45 +0200 +Subject: [PATCH] winex11: Get rid of the now unnecessary + mapped/iconic/net_wm_state flags. + +--- + dlls/winex11.drv/event.c | 8 ++------ + dlls/winex11.drv/window.c | 34 ++++++++-------------------------- + dlls/winex11.drv/x11drv.h | 3 --- + 3 files changed, 10 insertions(+), 35 deletions(-) + +diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c +index 11e93a3a100..ccbf4f43688 100644 +--- a/dlls/winex11.drv/event.c ++++ b/dlls/winex11.drv/event.c +@@ -1134,7 +1134,6 @@ static BOOL X11DRV_ConfigureNotify( HWND hwnd, XEvent *xev ) + + if ((old_style & WS_CAPTION) == WS_CAPTION || !data->is_fullscreen) + { +- data->net_wm_state = get_window_net_wm_state( event->display, data->whole_window ); + if ((new_style & WS_MAXIMIZE)) + { + if (!(old_style & WS_MAXIMIZE)) +@@ -1268,8 +1267,6 @@ static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL updat + + if ((old_style & WS_MINIMIZE) && !(new_style & WS_MINIMIZE)) /* restore window */ + { +- data->iconic = FALSE; +- data->net_wm_state = get_window_net_wm_state( event->display, data->whole_window ); + if ((old_style & WS_CAPTION) == WS_CAPTION && (new_style & WS_MAXIMIZE)) + { + if ((old_style & WS_MAXIMIZEBOX) && !(old_style & WS_DISABLED)) +@@ -1297,7 +1294,6 @@ static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL updat + } + else if (!(old_style & WS_MINIMIZE) && (new_style & WS_MINIMIZE)) + { +- data->iconic = TRUE; + if ((old_style & WS_MINIMIZEBOX) && !(old_style & WS_DISABLED)) + { + TRACE( "minimizing win %p/%lx\n", data->hwnd, data->whole_window ); +@@ -1376,9 +1372,9 @@ void wait_for_withdrawn_state( HWND hwnd, BOOL set ) + if (!(data = get_win_data( hwnd ))) break; + if (!data->managed || data->embedded || data->display != display) break; + if (!(window = data->whole_window)) break; +- if (!data->mapped == !set) ++ if ((data->pending_state.wm_state == WithdrawnState) == !set) + { +- TRACE( "window %p/%lx now %smapped\n", hwnd, window, data->mapped ? "" : "un" ); ++ TRACE( "window %p/%lx now %smapped\n", hwnd, window, (data->pending_state.wm_state != WithdrawnState) ? "" : "un" ); + break; + } + if ((data->wm_state == WithdrawnState) != !set) +diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c +index dcba464daf8..8d7c5dd4b1c 100644 +--- a/dlls/winex11.drv/window.c ++++ b/dlls/winex11.drv/window.c +@@ -1155,13 +1155,13 @@ static void update_desktop_fullscreen( Display *display ) + + /* Update _NET_WM_FULLSCREEN_MONITORS when _NET_WM_STATE_FULLSCREEN is set to support fullscreen + * windows spanning multiple monitors */ +-static void update_net_wm_fullscreen_monitors( struct x11drv_win_data *data ) ++static void update_net_wm_fullscreen_monitors( struct x11drv_win_data *data, UINT style ) + { + long monitors[4]; + XEvent xev; + +- if (!(data->net_wm_state & (1 << NET_WM_STATE_FULLSCREEN)) || is_virtual_desktop() +- || NtUserGetWindowLongW( data->hwnd, GWL_STYLE ) & WS_MINIMIZE) ++ if (!(data->pending_state.net_wm_state & (1 << NET_WM_STATE_FULLSCREEN)) || ++ is_virtual_desktop() || (style & WS_MINIMIZE)) + return; + + /* If the current display device handler cannot detect dynamic device changes, do not use +@@ -1322,7 +1322,7 @@ static void update_net_wm_states( struct x11drv_win_data *data ) + + style = NtUserGetWindowLongW( data->hwnd, GWL_STYLE ); + if (style & WS_MINIMIZE) +- new_state |= data->net_wm_state & ((1 << NET_WM_STATE_FULLSCREEN)|(1 << NET_WM_STATE_MAXIMIZED)); ++ new_state |= data->pending_state.net_wm_state & ((1 << NET_WM_STATE_FULLSCREEN)|(1 << NET_WM_STATE_MAXIMIZED)); + if (data->is_fullscreen) + { + if ((style & WS_MAXIMIZE) && (style & WS_CAPTION) == WS_CAPTION) +@@ -1346,8 +1346,7 @@ static void update_net_wm_states( struct x11drv_win_data *data ) + } + + window_set_net_wm_state( data, new_state ); +- data->net_wm_state = new_state; +- update_net_wm_fullscreen_monitors( data ); ++ update_net_wm_fullscreen_monitors( data, style ); + } + + /*********************************************************************** +@@ -1460,9 +1459,7 @@ static void map_window( HWND hwnd, DWORD new_style ) + window_set_wm_state( data, (new_style & WS_MINIMIZE) ? IconicState : NormalState ); + XFlush( data->display ); + +- data->mapped = TRUE; +- data->iconic = (new_style & WS_MINIMIZE) != 0; +- update_net_wm_fullscreen_monitors( data ); ++ update_net_wm_fullscreen_monitors( data, new_style ); + } + release_win_data( data ); + } +@@ -1478,14 +1475,7 @@ static void unmap_window( HWND hwnd ) + wait_for_withdrawn_state( hwnd, FALSE ); + + if (!(data = get_win_data( hwnd ))) return; +- +- if (data->pending_state.wm_state != WithdrawnState) +- { +- TRACE( "win %p/%lx\n", data->hwnd, data->whole_window ); +- window_set_wm_state( data, WithdrawnState ); +- data->mapped = FALSE; +- data->net_wm_state = 0; +- } ++ window_set_wm_state( data, WithdrawnState ); + release_win_data( data ); + } + +@@ -1594,7 +1584,6 @@ void make_window_embedded( struct x11drv_win_data *data ) + { + /* the window cannot be mapped before being embedded */ + window_set_wm_state( data, WithdrawnState ); +- data->net_wm_state = 0; + data->embedded = TRUE; + data->managed = TRUE; + sync_window_style( data ); +@@ -2006,8 +1995,6 @@ static void destroy_whole_window( struct x11drv_win_data *data, BOOL already_des + data->whole_window = data->client_window = 0; + data->whole_colormap = 0; + data->wm_state = WithdrawnState; +- data->net_wm_state = 0; +- data->mapped = FALSE; + + memset( &data->pending_state, 0, sizeof(data->pending_state) ); + memset( &data->current_state, 0, sizeof(data->current_state) ); +@@ -2402,11 +2389,7 @@ BOOL X11DRV_SystrayDockRemove( HWND hwnd ) + + if ((data = get_win_data( hwnd ))) + { +- if ((ret = data->embedded)) +- { +- window_set_wm_state( data, WithdrawnState ); +- data->mapped = FALSE; +- } ++ if ((ret = data->embedded)) window_set_wm_state( data, WithdrawnState ); + release_win_data( data ); + } + +@@ -2877,7 +2860,6 @@ void X11DRV_WindowPosChanged( HWND hwnd, HWND insert_after, UINT swp_flags, BOOL + else if ((swp_flags & SWP_STATECHANGED) && (old_style & WS_MINIMIZE) != (new_style & WS_MINIMIZE)) + { + set_wm_hints( data ); +- data->iconic = (new_style & WS_MINIMIZE) != 0; + window_set_wm_state( data, (new_style & WS_MINIMIZE) ? IconicState : NormalState ); + update_net_wm_states( data ); + } +diff --git a/dlls/winex11.drv/x11drv.h b/dlls/winex11.drv/x11drv.h +index 86749b1211f..c440fb73aea 100644 +--- a/dlls/winex11.drv/x11drv.h ++++ b/dlls/winex11.drv/x11drv.h +@@ -622,8 +622,6 @@ struct x11drv_win_data + struct host_window *parent; /* the host window parent, frame or embedder, NULL if root_window */ + XIC xic; /* X input context */ + UINT managed : 1; /* is window managed? */ +- UINT mapped : 1; /* is window mapped? (in either normal or iconic state) */ +- UINT iconic : 1; /* is window in iconic state? */ + UINT embedded : 1; /* is window an XEMBED client? */ + UINT shaped : 1; /* is window using a custom region shape? */ + UINT layered : 1; /* is window layered and with valid attributes? */ +@@ -634,7 +632,6 @@ struct x11drv_win_data + UINT is_fullscreen : 1; /* is the window visible rect fullscreen */ + UINT parent_invalid : 1; /* is the parent host window possibly invalid */ + int wm_state; /* current value of the WM_STATE property */ +- DWORD net_wm_state; /* bit mask of active x11drv_net_wm_state values */ + Window embedder; /* window id of embedder */ + Pixmap icon_pixmap; + Pixmap icon_mask; +-- +GitLab + diff --git a/0007-ntsync/0001-gcc-13-warnings.patch b/0007-ntsync/0001-gcc-13-warnings.patch deleted file mode 100644 index 42b0407..0000000 --- a/0007-ntsync/0001-gcc-13-warnings.patch +++ /dev/null @@ -1,25 +0,0 @@ -From: Elizabeth Figura -Date: Tue, 31 Oct 2023 12:23:30 -0500 -Subject: [PATCH 01/32] gcc 13 warnings - ---- - dlls/webservices/tests/channel.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/dlls/webservices/tests/channel.c b/dlls/webservices/tests/channel.c -index c64027fb86d..ddcf8964f23 100644 ---- a/dlls/webservices/tests/channel.c -+++ b/dlls/webservices/tests/channel.c -@@ -1214,6 +1214,9 @@ static const char send_record_begin[] = { - static const char send_record_middle[] = { 0x01, 0x56, 0x0e, 0x42 }; - static const char send_record_end[] = { 0x08, 0x02, 0x6e, 0x73, 0x89, 0xff, 0x01, 0x01 }; - -+#pragma GCC diagnostic ignored "-Warray-bounds" -+#pragma GCC diagnostic ignored "-Wstringop-overflow" -+ - static BOOL send_dict_str( int sock, char *addr, const char *str, int dict_str_count ) - { - char buf[512], dict_buf[256], body_buf[128], dict_size_buf[5]; --- -2.46.0 - diff --git a/0007-ntsync/0002-server-add-an-object-operation-to-retrieve-a-fast.patch b/0007-ntsync/0002-server-add-an-object-operation-to-retrieve-a-fast.patch deleted file mode 100644 index e3b7552..0000000 --- a/0007-ntsync/0002-server-add-an-object-operation-to-retrieve-a-fast.patch +++ /dev/null @@ -1,764 +0,0 @@ -From: Elizabeth Figura -Date: Mon, 8 Mar 2021 14:31:06 -0600 -Subject: [PATCH 02/32] server: Add an object operation to retrieve a fast - synchronization object. - ---- - server/async.c | 2 ++ - server/atom.c | 1 + - server/change.c | 1 + - server/clipboard.c | 1 + - server/completion.c | 1 + - server/console.c | 7 +++++++ - server/debugger.c | 2 ++ - server/device.c | 4 ++++ - server/directory.c | 2 ++ - server/event.c | 2 ++ - server/fd.c | 4 ++++ - server/file.c | 1 + - server/handle.c | 1 + - server/hook.c | 1 + - server/mailslot.c | 4 ++++ - server/mapping.c | 3 +++ - server/mutex.c | 1 + - server/named_pipe.c | 5 +++++ - server/object.c | 6 ++++++ - server/object.h | 7 +++++++ - server/process.c | 3 +++ - server/protocol.def | 12 ++++++++++++ - server/queue.c | 2 ++ - server/registry.c | 1 + - server/request.c | 1 + - server/semaphore.c | 1 + - server/serial.c | 1 + - server/signal.c | 1 + - server/sock.c | 3 +++ - server/symlink.c | 1 + - server/thread.c | 3 +++ - server/timer.c | 1 + - server/token.c | 1 + - server/window.c | 1 + - server/winstation.c | 2 ++ - 35 files changed, 90 insertions(+) - -diff --git a/server/async.c b/server/async.c -index 3c9b9588c6e..6a1cdbf5ada 100644 ---- a/server/async.c -+++ b/server/async.c -@@ -89,6 +89,7 @@ static const struct object_ops async_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - async_destroy /* destroy */ - }; -@@ -698,6 +699,7 @@ static const struct object_ops iosb_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - iosb_destroy /* destroy */ - }; -diff --git a/server/atom.c b/server/atom.c -index ff0799f5880..ba320c4c630 100644 ---- a/server/atom.c -+++ b/server/atom.c -@@ -91,6 +91,7 @@ static const struct object_ops atom_table_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - atom_table_destroy /* destroy */ - }; -diff --git a/server/change.c b/server/change.c -index f773ccf8831..d687deeb21b 100644 ---- a/server/change.c -+++ b/server/change.c -@@ -124,6 +124,7 @@ static const struct object_ops dir_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - dir_close_handle, /* close_handle */ - dir_destroy /* destroy */ - }; -diff --git a/server/clipboard.c b/server/clipboard.c -index 8118a467dd8..de9f84f74d0 100644 ---- a/server/clipboard.c -+++ b/server/clipboard.c -@@ -88,6 +88,7 @@ static const struct object_ops clipboard_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - clipboard_destroy /* destroy */ - }; -diff --git a/server/completion.c b/server/completion.c -index 6933195e72d..dd16787c63c 100644 ---- a/server/completion.c -+++ b/server/completion.c -@@ -87,6 +87,7 @@ static const struct object_ops completion_ops = - default_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - completion_destroy /* destroy */ - }; -diff --git a/server/console.c b/server/console.c -index b64283baf4a..5b7e08920e8 100644 ---- a/server/console.c -+++ b/server/console.c -@@ -93,6 +93,7 @@ static const struct object_ops console_ops = - NULL, /* unlink_name */ - console_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - console_destroy /* destroy */ - }; -@@ -170,6 +171,7 @@ static const struct object_ops console_server_ops = - NULL, /* unlink_name */ - console_server_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - console_server_destroy /* destroy */ - }; -@@ -239,6 +241,7 @@ static const struct object_ops screen_buffer_ops = - NULL, /* unlink_name */ - screen_buffer_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - screen_buffer_destroy /* destroy */ - }; -@@ -288,6 +291,7 @@ static const struct object_ops console_device_ops = - default_unlink_name, /* unlink_name */ - console_device_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - no_destroy /* destroy */ - }; -@@ -325,6 +329,7 @@ static const struct object_ops console_input_ops = - default_unlink_name, /* unlink_name */ - console_input_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - console_input_destroy /* destroy */ - }; -@@ -382,6 +387,7 @@ static const struct object_ops console_output_ops = - default_unlink_name, /* unlink_name */ - console_output_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - console_output_destroy /* destroy */ - }; -@@ -440,6 +446,7 @@ static const struct object_ops console_connection_ops = - default_unlink_name, /* unlink_name */ - console_connection_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - console_connection_close_handle, /* close_handle */ - console_connection_destroy /* destroy */ - }; -diff --git a/server/debugger.c b/server/debugger.c -index c59a0abea77..cee0c57fab3 100644 ---- a/server/debugger.c -+++ b/server/debugger.c -@@ -98,6 +98,7 @@ static const struct object_ops debug_event_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - debug_event_destroy /* destroy */ - }; -@@ -126,6 +127,7 @@ static const struct object_ops debug_obj_ops = - default_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - debug_obj_destroy /* destroy */ - }; -diff --git a/server/device.c b/server/device.c -index 436dac6bfe9..691c0eb6b5f 100644 ---- a/server/device.c -+++ b/server/device.c -@@ -78,6 +78,7 @@ static const struct object_ops irp_call_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - irp_call_destroy /* destroy */ - }; -@@ -118,6 +119,7 @@ static const struct object_ops device_manager_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - device_manager_destroy /* destroy */ - }; -@@ -175,6 +177,7 @@ static const struct object_ops device_ops = - default_unlink_name, /* unlink_name */ - device_open_file, /* open_file */ - device_get_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - device_destroy /* destroy */ - }; -@@ -227,6 +230,7 @@ static const struct object_ops device_file_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - device_file_get_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - device_file_close_handle, /* close_handle */ - device_file_destroy /* destroy */ - }; -diff --git a/server/directory.c b/server/directory.c -index b3f055dfd01..0c9c103b6ea 100644 ---- a/server/directory.c -+++ b/server/directory.c -@@ -81,6 +81,7 @@ static const struct object_ops object_type_ops = - default_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - no_destroy /* destroy */ - }; -@@ -131,6 +132,7 @@ static const struct object_ops directory_ops = - default_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - directory_destroy /* destroy */ - }; -diff --git a/server/event.c b/server/event.c -index f1b79b1b35e..d2ed6ae3df7 100644 ---- a/server/event.c -+++ b/server/event.c -@@ -84,6 +84,7 @@ static const struct object_ops event_ops = - default_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ - event_get_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - no_destroy /* destroy */ - }; -@@ -131,6 +132,7 @@ static const struct object_ops keyed_event_ops = - default_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - no_destroy /* destroy */ - }; -diff --git a/server/fd.c b/server/fd.c -index f28937466fc..4c0d054c673 100644 ---- a/server/fd.c -+++ b/server/fd.c -@@ -181,6 +181,7 @@ static const struct object_ops fd_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - fd_destroy /* destroy */ - }; -@@ -222,6 +223,7 @@ static const struct object_ops device_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - device_destroy /* destroy */ - }; -@@ -262,6 +264,7 @@ static const struct object_ops inode_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - inode_destroy /* destroy */ - }; -@@ -304,6 +307,7 @@ static const struct object_ops file_lock_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - no_destroy /* destroy */ - }; -diff --git a/server/file.c b/server/file.c -index 76c687833c9..50d1cc21188 100644 ---- a/server/file.c -+++ b/server/file.c -@@ -106,6 +106,7 @@ static const struct object_ops file_ops = - NULL, /* unlink_name */ - file_open_file, /* open_file */ - file_get_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - file_destroy /* destroy */ - }; -diff --git a/server/handle.c b/server/handle.c -index ef243e06e0b..782889daadc 100644 ---- a/server/handle.c -+++ b/server/handle.c -@@ -138,6 +138,7 @@ static const struct object_ops handle_table_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - handle_table_destroy /* destroy */ - }; -diff --git a/server/hook.c b/server/hook.c -index c2d2823cd61..419995333ba 100644 ---- a/server/hook.c -+++ b/server/hook.c -@@ -93,6 +93,7 @@ static const struct object_ops hook_table_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - hook_table_destroy /* destroy */ - }; -diff --git a/server/mailslot.c b/server/mailslot.c -index 7defbccdb44..40dfc8ad9d3 100644 ---- a/server/mailslot.c -+++ b/server/mailslot.c -@@ -93,6 +93,7 @@ static const struct object_ops mailslot_ops = - default_unlink_name, /* unlink_name */ - mailslot_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - mailslot_destroy /* destroy */ - }; -@@ -154,6 +155,7 @@ static const struct object_ops mail_writer_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - mail_writer_destroy /* destroy */ - }; -@@ -219,6 +221,7 @@ static const struct object_ops mailslot_device_ops = - default_unlink_name, /* unlink_name */ - mailslot_device_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - mailslot_device_destroy /* destroy */ - }; -@@ -249,6 +252,7 @@ static const struct object_ops mailslot_device_file_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - mailslot_device_file_destroy /* destroy */ - }; -diff --git a/server/mapping.c b/server/mapping.c -index 8a34760b10e..e8980539416 100644 ---- a/server/mapping.c -+++ b/server/mapping.c -@@ -79,6 +79,7 @@ static const struct object_ops ranges_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - ranges_destroy /* destroy */ - }; -@@ -115,6 +116,7 @@ static const struct object_ops shared_map_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - shared_map_destroy /* destroy */ - }; -@@ -188,6 +190,7 @@ static const struct object_ops mapping_ops = - default_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - mapping_destroy /* destroy */ - }; -diff --git a/server/mutex.c b/server/mutex.c -index af0efe72132..f7ad1e800c9 100644 ---- a/server/mutex.c -+++ b/server/mutex.c -@@ -85,6 +85,7 @@ static const struct object_ops mutex_ops = - default_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - mutex_destroy /* destroy */ - }; -diff --git a/server/named_pipe.c b/server/named_pipe.c -index dd8c14b30a9..5eb57f320a2 100644 ---- a/server/named_pipe.c -+++ b/server/named_pipe.c -@@ -131,6 +131,7 @@ static const struct object_ops named_pipe_ops = - default_unlink_name, /* unlink_name */ - named_pipe_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - named_pipe_destroy /* destroy */ - }; -@@ -179,6 +180,7 @@ static const struct object_ops pipe_server_ops = - NULL, /* unlink_name */ - pipe_server_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - async_close_obj_handle, /* close_handle */ - pipe_server_destroy /* destroy */ - }; -@@ -223,6 +225,7 @@ static const struct object_ops pipe_client_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - async_close_obj_handle, /* close_handle */ - pipe_end_destroy /* destroy */ - }; -@@ -270,6 +273,7 @@ static const struct object_ops named_pipe_device_ops = - default_unlink_name, /* unlink_name */ - named_pipe_device_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - named_pipe_device_destroy /* destroy */ - }; -@@ -301,6 +305,7 @@ static const struct object_ops named_pipe_device_file_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - named_pipe_device_file_destroy /* destroy */ - }; -diff --git a/server/object.c b/server/object.c -index 36c9c60fb65..55a1573d11f 100644 ---- a/server/object.c -+++ b/server/object.c -@@ -553,6 +553,12 @@ struct fd *no_get_fd( struct object *obj ) - return NULL; - } - -+struct fast_sync *no_get_fast_sync( struct object *obj ) -+{ -+ set_error( STATUS_OBJECT_TYPE_MISMATCH ); -+ return NULL; -+} -+ - unsigned int default_map_access( struct object *obj, unsigned int access ) - { - return map_access( access, &obj->ops->type->mapping ); -diff --git a/server/object.h b/server/object.h -index 2337ee88231..2b916f26f2f 100644 ---- a/server/object.h -+++ b/server/object.h -@@ -42,6 +42,7 @@ struct async; - struct async_queue; - struct winstation; - struct object_type; -+struct fast_sync; - - - struct unicode_str -@@ -103,6 +104,8 @@ struct object_ops - unsigned int options); - /* return list of kernel objects */ - struct list *(*get_kernel_obj_list)(struct object *); -+ /* get a client-waitable fast-synchronization handle to this object */ -+ struct fast_sync *(*get_fast_sync)(struct object *); - /* close a handle to this object */ - int (*close_handle)(struct object *,struct process *,obj_handle_t); - /* destroy on refcount == 0 */ -@@ -221,6 +224,10 @@ extern void reset_event( struct event *event ); - - extern void abandon_mutexes( struct thread *thread ); - -+/* fast-synchronization functions */ -+ -+extern struct fast_sync *no_get_fast_sync( struct object *obj ); -+ - /* serial functions */ - - int get_serial_async_timeout(struct object *obj, int type, int count); -diff --git a/server/process.c b/server/process.c -index 155dc050d95..68b4ccff51e 100644 ---- a/server/process.c -+++ b/server/process.c -@@ -117,6 +117,7 @@ static const struct object_ops process_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - process_get_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - process_destroy /* destroy */ - }; -@@ -168,6 +169,7 @@ static const struct object_ops startup_info_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - startup_info_destroy /* destroy */ - }; -@@ -229,6 +231,7 @@ static const struct object_ops job_ops = - default_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - job_close_handle, /* close_handle */ - job_destroy /* destroy */ - }; -diff --git a/server/protocol.def b/server/protocol.def -index 2c791cbdd46..1f718bf80b8 100644 ---- a/server/protocol.def -+++ b/server/protocol.def -@@ -3953,3 +3953,15 @@ struct handle_info - @REPLY - int enable; /* previous state of auto-repeat enable */ - @END -+ -+ -+enum fast_sync_type -+{ -+ FAST_SYNC_SEMAPHORE = 1, -+ FAST_SYNC_MUTEX, -+ FAST_SYNC_AUTO_EVENT, -+ FAST_SYNC_MANUAL_EVENT, -+ FAST_SYNC_AUTO_SERVER, -+ FAST_SYNC_MANUAL_SERVER, -+ FAST_SYNC_QUEUE, -+}; -diff --git a/server/queue.c b/server/queue.c -index 0156a4c66f2..c946b8b4a1c 100644 ---- a/server/queue.c -+++ b/server/queue.c -@@ -176,6 +176,7 @@ static const struct object_ops msg_queue_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - msg_queue_destroy /* destroy */ - }; -@@ -213,6 +214,7 @@ static const struct object_ops thread_input_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - thread_input_destroy /* destroy */ - }; -diff --git a/server/registry.c b/server/registry.c -index 804cfcc638b..f6bb34e322f 100644 ---- a/server/registry.c -+++ b/server/registry.c -@@ -192,6 +192,7 @@ static const struct object_ops key_ops = - key_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - key_close_handle, /* close_handle */ - key_destroy /* destroy */ - }; -diff --git a/server/request.c b/server/request.c -index 2691e0c7cff..e0585be3203 100644 ---- a/server/request.c -+++ b/server/request.c -@@ -102,6 +102,7 @@ static const struct object_ops master_socket_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - master_socket_destroy /* destroy */ - }; -diff --git a/server/semaphore.c b/server/semaphore.c -index 53b42a886df..1a89bd0886b 100644 ---- a/server/semaphore.c -+++ b/server/semaphore.c -@@ -82,6 +82,7 @@ static const struct object_ops semaphore_ops = - default_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - no_destroy /* destroy */ - }; -diff --git a/server/serial.c b/server/serial.c -index 209f2e9174e..9a6837c3bff 100644 ---- a/server/serial.c -+++ b/server/serial.c -@@ -103,6 +103,7 @@ static const struct object_ops serial_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - serial_destroy /* destroy */ - }; -diff --git a/server/signal.c b/server/signal.c -index 19b76d44c16..e5def3dc899 100644 ---- a/server/signal.c -+++ b/server/signal.c -@@ -74,6 +74,7 @@ static const struct object_ops handler_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - handler_destroy /* destroy */ - }; -diff --git a/server/sock.c b/server/sock.c -index 06ffd1b81f8..11a6f3465fc 100644 ---- a/server/sock.c -+++ b/server/sock.c -@@ -465,6 +465,7 @@ static const struct object_ops sock_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - sock_close_handle, /* close_handle */ - sock_destroy /* destroy */ - }; -@@ -3574,6 +3575,7 @@ static const struct object_ops ifchange_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - ifchange_destroy /* destroy */ - }; -@@ -3795,6 +3797,7 @@ static const struct object_ops socket_device_ops = - default_unlink_name, /* unlink_name */ - socket_device_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - no_destroy /* destroy */ - }; -diff --git a/server/symlink.c b/server/symlink.c -index dd28efd3a75..4a7cf68f269 100644 ---- a/server/symlink.c -+++ b/server/symlink.c -@@ -83,6 +83,7 @@ static const struct object_ops symlink_ops = - default_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - symlink_destroy /* destroy */ - }; -diff --git a/server/thread.c b/server/thread.c -index 6542e1584ab..77ef21a7e9b 100644 ---- a/server/thread.c -+++ b/server/thread.c -@@ -108,6 +108,7 @@ static const struct object_ops thread_apc_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - thread_apc_destroy /* destroy */ - }; -@@ -150,6 +151,7 @@ static const struct object_ops context_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - no_destroy /* destroy */ - }; -@@ -199,6 +201,7 @@ static const struct object_ops thread_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - thread_get_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - destroy_thread /* destroy */ - }; -diff --git a/server/timer.c b/server/timer.c -index 96dc9d00ca1..d4a69bf8794 100644 ---- a/server/timer.c -+++ b/server/timer.c -@@ -88,6 +88,7 @@ static const struct object_ops timer_ops = - default_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - timer_destroy /* destroy */ - }; -diff --git a/server/token.c b/server/token.c -index da7f0bb7ff2..137dc1a6c7f 100644 ---- a/server/token.c -+++ b/server/token.c -@@ -157,6 +157,7 @@ static const struct object_ops token_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - token_destroy /* destroy */ - }; -diff --git a/server/window.c b/server/window.c -index 564c69bf18d..56f8df33063 100644 ---- a/server/window.c -+++ b/server/window.c -@@ -118,6 +118,7 @@ static const struct object_ops window_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - window_destroy /* destroy */ - }; -diff --git a/server/winstation.c b/server/winstation.c -index 76a23b197a4..87c3e64acac 100644 ---- a/server/winstation.c -+++ b/server/winstation.c -@@ -88,6 +88,7 @@ static const struct object_ops winstation_ops = - default_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - winstation_close_handle, /* close_handle */ - winstation_destroy /* destroy */ - }; -@@ -128,6 +129,7 @@ static const struct object_ops desktop_ops = - default_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ - desktop_close_handle, /* close_handle */ - desktop_destroy /* destroy */ - }; --- -2.46.0 - - diff --git a/0007-ntsync/0003-server-create-fast-synchronization-objects-for-events.patch b/0007-ntsync/0003-server-create-fast-synchronization-objects-for-events.patch deleted file mode 100644 index 0b047eb..0000000 --- a/0007-ntsync/0003-server-create-fast-synchronization-objects-for-events.patch +++ /dev/null @@ -1,443 +0,0 @@ -From: Elizabeth Figura -Date: Mon, 8 Mar 2021 16:38:18 -0600 -Subject: [PATCH 03/32] server: Create fast synchronization objects for events. - ---- - configure.ac | 1 + - server/Makefile.in | 1 + - server/event.c | 30 ++++- - server/fast_sync.c | 299 +++++++++++++++++++++++++++++++++++++++++++++ - server/object.h | 4 + - 5 files changed, 333 insertions(+), 2 deletions(-) - create mode 100644 server/fast_sync.c - -diff --git a/configure.ac b/configure.ac -index c015c049831..a2e348b3073 100644 ---- a/configure.ac -+++ b/configure.ac -@@ -380,6 +380,7 @@ AC_CHECK_HEADERS(\ - linux/input.h \ - linux/ioctl.h \ - linux/major.h \ -+ linux/ntsync.h \ - linux/param.h \ - linux/serial.h \ - linux/types.h \ -diff --git a/server/Makefile.in b/server/Makefile.in -index 7e571ac2ba6..fb5998bed8b 100644 ---- a/server/Makefile.in -+++ b/server/Makefile.in -@@ -12,6 +12,7 @@ SOURCES = \ - device.c \ - directory.c \ - event.c \ -+ fast_sync.c \ - fd.c \ - file.c \ - handle.c \ -diff --git a/server/event.c b/server/event.c -index d2ed6ae3df7..8c82f8445c4 100644 ---- a/server/event.c -+++ b/server/event.c -@@ -56,6 +56,7 @@ struct event - struct list kernel_object; /* list of kernel object pointers */ - int manual_reset; /* is it a manual reset event? */ - int signaled; /* event has been signaled */ -+ struct fast_sync *fast_sync; /* fast synchronization object */ - }; - - static void event_dump( struct object *obj, int verbose ); -@@ -63,6 +64,8 @@ static int event_signaled( struct object *obj, struct wait_queue_entry *entry ); - static void event_satisfied( struct object *obj, struct wait_queue_entry *entry ); - static int event_signal( struct object *obj, unsigned int access); - static struct list *event_get_kernel_obj_list( struct object *obj ); -+static struct fast_sync *event_get_fast_sync( struct object *obj ); -+static void event_destroy( struct object *obj ); - - static const struct object_ops event_ops = - { -@@ -84,9 +87,9 @@ static const struct object_ops event_ops = - default_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ - event_get_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ event_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ -- no_destroy /* destroy */ -+ event_destroy /* destroy */ - }; - - -@@ -152,6 +155,7 @@ struct event *create_event( struct object *root, const struct unicode_str *name, - list_init( &event->kernel_object ); - event->manual_reset = manual_reset; - event->signaled = initial_state; -+ event->fast_sync = NULL; - } - } - return event; -@@ -175,11 +179,13 @@ void set_event( struct event *event ) - event->signaled = 1; - /* wake up all waiters if manual reset, a single one otherwise */ - wake_up( &event->obj, !event->manual_reset ); -+ fast_set_event( event->fast_sync ); - } - - void reset_event( struct event *event ) - { - event->signaled = 0; -+ fast_reset_event( event->fast_sync ); - } - - static void event_dump( struct object *obj, int verbose ) -@@ -225,6 +231,26 @@ static struct list *event_get_kernel_obj_list( struct object *obj ) - return &event->kernel_object; - } - -+static struct fast_sync *event_get_fast_sync( struct object *obj ) -+{ -+ struct event *event = (struct event *)obj; -+ -+ if (!event->fast_sync) -+ { -+ enum fast_sync_type type = event->manual_reset ? FAST_SYNC_MANUAL_EVENT : FAST_SYNC_AUTO_EVENT; -+ event->fast_sync = fast_create_event( type, event->signaled ); -+ } -+ if (event->fast_sync) grab_object( event->fast_sync ); -+ return event->fast_sync; -+} -+ -+static void event_destroy( struct object *obj ) -+{ -+ struct event *event = (struct event *)obj; -+ -+ if (event->fast_sync) release_object( event->fast_sync ); -+} -+ - struct keyed_event *create_keyed_event( struct object *root, const struct unicode_str *name, - unsigned int attr, const struct security_descriptor *sd ) - { -diff --git a/server/fast_sync.c b/server/fast_sync.c -new file mode 100644 -index 00000000000..3100abd2630 ---- /dev/null -+++ b/server/fast_sync.c -@@ -0,0 +1,299 @@ -+/* -+ * Fast synchronization primitives -+ * -+ * Copyright (C) 2021-2022 Elizabeth Figura 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 -+ */ -+ -+#include "config.h" -+ -+#include -+#include -+#include -+ -+#include "ntstatus.h" -+#define WIN32_NO_STATUS -+#include "winternl.h" -+ -+#include "file.h" -+#include "thread.h" -+ -+#ifdef HAVE_LINUX_NTSYNC_H -+ -+#include -+#include -+#include -+#include -+#include -+ -+struct linux_device -+{ -+ struct object obj; /* object header */ -+ struct fd *fd; /* fd for unix fd */ -+}; -+ -+static struct linux_device *linux_device_object; -+ -+static void linux_device_dump( struct object *obj, int verbose ); -+static struct fd *linux_device_get_fd( struct object *obj ); -+static void linux_device_destroy( struct object *obj ); -+static enum server_fd_type fast_sync_get_fd_type( struct fd *fd ); -+ -+static const struct object_ops linux_device_ops = -+{ -+ sizeof(struct linux_device), /* size */ -+ &no_type, /* type */ -+ linux_device_dump, /* dump */ -+ no_add_queue, /* add_queue */ -+ NULL, /* remove_queue */ -+ NULL, /* signaled */ -+ NULL, /* satisfied */ -+ no_signal, /* signal */ -+ linux_device_get_fd, /* get_fd */ -+ default_map_access, /* map_access */ -+ default_get_sd, /* get_sd */ -+ default_set_sd, /* set_sd */ -+ no_get_full_name, /* get_full_name */ -+ no_lookup_name, /* lookup_name */ -+ no_link_name, /* link_name */ -+ NULL, /* unlink_name */ -+ no_open_file, /* open_file */ -+ no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ -+ no_close_handle, /* close_handle */ -+ linux_device_destroy /* destroy */ -+}; -+ -+static const struct fd_ops fast_sync_fd_ops = -+{ -+ default_fd_get_poll_events, /* get_poll_events */ -+ default_poll_event, /* poll_event */ -+ fast_sync_get_fd_type, /* get_fd_type */ -+ no_fd_read, /* read */ -+ no_fd_write, /* write */ -+ no_fd_flush, /* flush */ -+ no_fd_get_file_info, /* get_file_info */ -+ no_fd_get_volume_info, /* get_volume_info */ -+ no_fd_ioctl, /* ioctl */ -+ default_fd_cancel_async, /* cancel_async */ -+ no_fd_queue_async, /* queue_async */ -+ default_fd_reselect_async /* reselect_async */ -+}; -+ -+static void linux_device_dump( struct object *obj, int verbose ) -+{ -+ struct linux_device *device = (struct linux_device *)obj; -+ assert( obj->ops == &linux_device_ops ); -+ fprintf( stderr, "Fast synchronization device fd=%p\n", device->fd ); -+} -+ -+static struct fd *linux_device_get_fd( struct object *obj ) -+{ -+ struct linux_device *device = (struct linux_device *)obj; -+ return (struct fd *)grab_object( device->fd ); -+} -+ -+static void linux_device_destroy( struct object *obj ) -+{ -+ struct linux_device *device = (struct linux_device *)obj; -+ assert( obj->ops == &linux_device_ops ); -+ if (device->fd) release_object( device->fd ); -+ linux_device_object = NULL; -+} -+ -+static enum server_fd_type fast_sync_get_fd_type( struct fd *fd ) -+{ -+ return FD_TYPE_FILE; -+} -+ -+static struct linux_device *get_linux_device(void) -+{ -+ struct linux_device *device; -+ int unix_fd; -+ -+ if (linux_device_object) -+ return (struct linux_device *)grab_object( linux_device_object ); -+ -+ unix_fd = open( "/dev/ntsync", O_CLOEXEC | O_RDONLY ); -+ if (unix_fd == -1) -+ { -+ file_set_error(); -+ return NULL; -+ } -+ -+ if (!(device = alloc_object( &linux_device_ops ))) -+ { -+ close( unix_fd ); -+ set_error( STATUS_NO_MEMORY ); -+ return NULL; -+ } -+ -+ if (!(device->fd = create_anonymous_fd( &fast_sync_fd_ops, unix_fd, &device->obj, 0 ))) -+ { -+ release_object( device ); -+ return NULL; -+ } -+ -+ linux_device_object = device; -+ return device; -+} -+ -+struct fast_sync -+{ -+ struct object obj; -+ enum fast_sync_type type; -+ struct fd *fd; -+}; -+ -+static void linux_obj_dump( struct object *obj, int verbose ); -+static void linux_obj_destroy( struct object *obj ); -+ -+static const struct object_ops fast_sync_ops = -+{ -+ sizeof(struct fast_sync), /* size */ -+ &no_type, /* type */ -+ linux_obj_dump, /* dump */ -+ no_add_queue, /* add_queue */ -+ NULL, /* remove_queue */ -+ NULL, /* signaled */ -+ NULL, /* satisfied */ -+ no_signal, /* signal */ -+ no_get_fd, /* get_fd */ -+ default_map_access, /* map_access */ -+ default_get_sd, /* get_sd */ -+ default_set_sd, /* set_sd */ -+ no_get_full_name, /* get_full_name */ -+ no_lookup_name, /* lookup_name */ -+ no_link_name, /* link_name */ -+ NULL, /* unlink_name */ -+ no_open_file, /* open_file */ -+ no_kernel_obj_list, /* get_kernel_obj_list */ -+ no_get_fast_sync, /* get_fast_sync */ -+ no_close_handle, /* close_handle */ -+ linux_obj_destroy /* destroy */ -+}; -+ -+static void linux_obj_dump( struct object *obj, int verbose ) -+{ -+ struct fast_sync *fast_sync = (struct fast_sync *)obj; -+ assert( obj->ops == &fast_sync_ops ); -+ fprintf( stderr, "Fast synchronization object type=%u fd=%p\n", fast_sync->type, fast_sync->fd ); -+} -+ -+static void linux_obj_destroy( struct object *obj ) -+{ -+ struct fast_sync *fast_sync = (struct fast_sync *)obj; -+ assert( obj->ops == &fast_sync_ops ); -+ if (fast_sync->fd) release_object( fast_sync->fd ); -+} -+ -+static struct fast_sync *create_fast_sync( enum fast_sync_type type, int unix_fd ) -+{ -+ struct fast_sync *fast_sync; -+ -+ if (!(fast_sync = alloc_object( &fast_sync_ops ))) -+ { -+ close( unix_fd ); -+ return NULL; -+ } -+ -+ fast_sync->type = type; -+ -+ if (!(fast_sync->fd = create_anonymous_fd( &fast_sync_fd_ops, unix_fd, &fast_sync->obj, 0 ))) -+ { -+ release_object( fast_sync ); -+ return NULL; -+ } -+ -+ return fast_sync; -+} -+ -+struct fast_sync *fast_create_event( enum fast_sync_type type, int signaled ) -+{ -+ struct ntsync_event_args args = {0}; -+ struct linux_device *device; -+ -+ if (!(device = get_linux_device())) return NULL; -+ -+ args.signaled = signaled; -+ switch (type) -+ { -+ case FAST_SYNC_AUTO_EVENT: -+ case FAST_SYNC_AUTO_SERVER: -+ args.manual = 0; -+ break; -+ -+ case FAST_SYNC_MANUAL_EVENT: -+ case FAST_SYNC_MANUAL_SERVER: -+ case FAST_SYNC_QUEUE: -+ args.manual = 1; -+ break; -+ -+ case FAST_SYNC_MUTEX: -+ case FAST_SYNC_SEMAPHORE: -+ assert(0); -+ break; -+ } -+ if (ioctl( get_unix_fd( device->fd ), NTSYNC_IOC_CREATE_EVENT, &args ) < 0) -+ { -+ file_set_error(); -+ release_object( device ); -+ return NULL; -+ } -+ release_object( device ); -+ -+ return create_fast_sync( type, args.event ); -+} -+ -+void fast_set_event( struct fast_sync *fast_sync ) -+{ -+ __u32 count; -+ -+ if (!fast_sync) return; -+ -+ if (debug_level) fprintf( stderr, "fast_set_event %p\n", fast_sync->fd ); -+ -+ ioctl( get_unix_fd( fast_sync->fd ), NTSYNC_IOC_EVENT_SET, &count ); -+} -+ -+void fast_reset_event( struct fast_sync *fast_sync ) -+{ -+ __u32 count; -+ -+ if (!fast_sync) return; -+ -+ if (debug_level) fprintf( stderr, "fast_set_event %p\n", fast_sync->fd ); -+ -+ ioctl( get_unix_fd( fast_sync->fd ), NTSYNC_IOC_EVENT_RESET, &count ); -+} -+ -+#else -+ -+struct fast_sync *fast_create_event( enum fast_sync_type type, int signaled ) -+{ -+ set_error( STATUS_NOT_IMPLEMENTED ); -+ return NULL; -+} -+ -+void fast_set_event( struct fast_sync *fast_sync ) -+{ -+} -+ -+void fast_reset_event( struct fast_sync *obj ) -+{ -+} -+ -+#endif -diff --git a/server/object.h b/server/object.h -index 2b916f26f2f..5e2a4e246e4 100644 ---- a/server/object.h -+++ b/server/object.h -@@ -226,6 +226,10 @@ extern void abandon_mutexes( struct thread *thread ); - - /* fast-synchronization functions */ - -+extern struct fast_sync *fast_create_event( enum fast_sync_type type, int signaled ); -+extern void fast_set_event( struct fast_sync *obj ); -+extern void fast_reset_event( struct fast_sync *obj ); -+ - extern struct fast_sync *no_get_fast_sync( struct object *obj ); - - /* serial functions */ --- -2.46.0 - - diff --git a/0007-ntsync/0004-autoreconf.patch b/0007-ntsync/0004-autoreconf.patch deleted file mode 100644 index 702e88a..0000000 --- a/0007-ntsync/0004-autoreconf.patch +++ /dev/null @@ -1,44 +0,0 @@ -From: Elizabeth Figura -Date: Fri, 16 Sep 2022 17:56:13 -0500 -Subject: [PATCH 04/32] autoreconf - ---- - configure | 6 ++++++ - include/config.h.in | 3 +++ - 2 files changed, 9 insertions(+) - -diff --git a/configure b/configure -index ca5b35c7e42..bb28d7a5dcf 100755 ---- a/configure -+++ b/configure -@@ -7988,6 +7988,12 @@ if test "x$ac_cv_header_linux_major_h" = xyes - then : - printf "%s\n" "#define HAVE_LINUX_MAJOR_H 1" >>confdefs.h - -+fi -+ac_fn_c_check_header_compile "$LINENO" "linux/ntsync.h" "ac_cv_header_linux_ntsync_h" "$ac_includes_default" -+if test "x$ac_cv_header_linux_ntsync_h" = xyes -+then : -+ printf "%s\n" "#define HAVE_LINUX_NTSYNC_H 1" >>confdefs.h -+ - fi - ac_fn_c_check_header_compile "$LINENO" "linux/param.h" "ac_cv_header_linux_param_h" "$ac_includes_default" - if test "x$ac_cv_header_linux_param_h" = xyes -diff --git a/include/config.h.in b/include/config.h.in -index aa066a87ad7..41e4696f028 100644 ---- a/include/config.h.in -+++ b/include/config.h.in -@@ -180,6 +180,9 @@ - /* Define to 1 if you have the header file. */ - #undef HAVE_LINUX_MAJOR_H - -+/* Define to 1 if you have the header file. */ -+#undef HAVE_LINUX_NTSYNC_H -+ - /* Define to 1 if you have the header file. */ - #undef HAVE_LINUX_PARAM_H - --- -2.46.0 - - diff --git a/0007-ntsync/0005-server-create-fast-synchronization-objects-for.patch b/0007-ntsync/0005-server-create-fast-synchronization-objects-for.patch deleted file mode 100644 index b4babb2..0000000 --- a/0007-ntsync/0005-server-create-fast-synchronization-objects-for.patch +++ /dev/null @@ -1,199 +0,0 @@ -From: Elizabeth Figura -Date: Thu, 11 Mar 2021 16:45:30 -0600 -Subject: [PATCH 05/32] server: Create fast synchronization objects for - semaphores. - ---- - server/fast_sync.c | 48 ++++++++++++++++++++++++++++++++++++++++------ - server/object.h | 1 + - server/semaphore.c | 25 ++++++++++++++++++++++-- - 3 files changed, 66 insertions(+), 8 deletions(-) - -diff --git a/server/fast_sync.c b/server/fast_sync.c -index 3100abd2630..7b21f54e2b6 100644 ---- a/server/fast_sync.c -+++ b/server/fast_sync.c -@@ -81,7 +81,7 @@ static const struct fd_ops fast_sync_fd_ops = - { - default_fd_get_poll_events, /* get_poll_events */ - default_poll_event, /* poll_event */ -- fast_sync_get_fd_type, /* get_fd_type */ -+ fast_sync_get_fd_type, /* get_fd_type */ - no_fd_read, /* read */ - no_fd_write, /* write */ - no_fd_flush, /* flush */ -@@ -160,8 +160,9 @@ struct fast_sync - - static void linux_obj_dump( struct object *obj, int verbose ); - static void linux_obj_destroy( struct object *obj ); -+static struct fd *linux_obj_get_fd( struct object *obj ); - --static const struct object_ops fast_sync_ops = -+static const struct object_ops linux_obj_ops = - { - sizeof(struct fast_sync), /* size */ - &no_type, /* type */ -@@ -171,7 +172,7 @@ static const struct object_ops fast_sync_ops = - NULL, /* signaled */ - NULL, /* satisfied */ - no_signal, /* signal */ -- no_get_fd, /* get_fd */ -+ linux_obj_get_fd, /* get_fd */ - default_map_access, /* map_access */ - default_get_sd, /* get_sd */ - default_set_sd, /* set_sd */ -@@ -189,22 +190,29 @@ static const struct object_ops fast_sync_ops = - static void linux_obj_dump( struct object *obj, int verbose ) - { - struct fast_sync *fast_sync = (struct fast_sync *)obj; -- assert( obj->ops == &fast_sync_ops ); -+ assert( obj->ops == &linux_obj_ops ); - fprintf( stderr, "Fast synchronization object type=%u fd=%p\n", fast_sync->type, fast_sync->fd ); - } - - static void linux_obj_destroy( struct object *obj ) - { - struct fast_sync *fast_sync = (struct fast_sync *)obj; -- assert( obj->ops == &fast_sync_ops ); -+ assert( obj->ops == &linux_obj_ops ); - if (fast_sync->fd) release_object( fast_sync->fd ); - } - -+static struct fd *linux_obj_get_fd( struct object *obj ) -+{ -+ struct fast_sync *fast_sync = (struct fast_sync *)obj; -+ assert( obj->ops == &linux_obj_ops ); -+ return (struct fd *)grab_object( fast_sync->fd ); -+} -+ - static struct fast_sync *create_fast_sync( enum fast_sync_type type, int unix_fd ) - { - struct fast_sync *fast_sync; - -- if (!(fast_sync = alloc_object( &fast_sync_ops ))) -+ if (!(fast_sync = alloc_object( &linux_obj_ops ))) - { - close( unix_fd ); - return NULL; -@@ -258,6 +266,28 @@ struct fast_sync *fast_create_event( enum fast_sync_type type, int signaled ) - return create_fast_sync( type, args.event ); - } - -+struct fast_sync *fast_create_semaphore( unsigned int count, unsigned int max ) -+{ -+ struct ntsync_sem_args args = {0}; -+ struct linux_device *device; -+ struct fast_sync *fast_sync; -+ -+ if (!(device = get_linux_device())) return NULL; -+ -+ args.count = count; -+ args.max = max; -+ if (ioctl( get_unix_fd( device->fd ), NTSYNC_IOC_CREATE_SEM, &args ) < 0) -+ { -+ file_set_error(); -+ release_object( device ); -+ return NULL; -+ } -+ -+ release_object( device ); -+ -+ return create_fast_sync( FAST_SYNC_SEMAPHORE, args.sem ); -+} -+ - void fast_set_event( struct fast_sync *fast_sync ) - { - __u32 count; -@@ -288,6 +318,12 @@ struct fast_sync *fast_create_event( enum fast_sync_type type, int signaled ) - return NULL; - } - -+struct fast_sync *fast_create_semaphore( unsigned int count, unsigned int max ) -+{ -+ set_error( STATUS_NOT_IMPLEMENTED ); -+ return NULL; -+} -+ - void fast_set_event( struct fast_sync *fast_sync ) - { - } -diff --git a/server/object.h b/server/object.h -index 5e2a4e246e4..237f55a3c9c 100644 ---- a/server/object.h -+++ b/server/object.h -@@ -227,6 +227,7 @@ extern void abandon_mutexes( struct thread *thread ); - /* fast-synchronization functions */ - - extern struct fast_sync *fast_create_event( enum fast_sync_type type, int signaled ); -+extern struct fast_sync *fast_create_semaphore( unsigned int count, unsigned int max ); - extern void fast_set_event( struct fast_sync *obj ); - extern void fast_reset_event( struct fast_sync *obj ); - -diff --git a/server/semaphore.c b/server/semaphore.c -index 1a89bd0886b..99409198d68 100644 ---- a/server/semaphore.c -+++ b/server/semaphore.c -@@ -55,12 +55,15 @@ struct semaphore - struct object obj; /* object header */ - unsigned int count; /* current count */ - unsigned int max; /* maximum possible count */ -+ struct fast_sync *fast_sync; /* fast synchronization object */ - }; - - static void semaphore_dump( struct object *obj, int verbose ); - static int semaphore_signaled( struct object *obj, struct wait_queue_entry *entry ); - static void semaphore_satisfied( struct object *obj, struct wait_queue_entry *entry ); - static int semaphore_signal( struct object *obj, unsigned int access ); -+static struct fast_sync *semaphore_get_fast_sync( struct object *obj ); -+static void semaphore_destroy( struct object *obj ); - - static const struct object_ops semaphore_ops = - { -@@ -82,9 +85,9 @@ static const struct object_ops semaphore_ops = - default_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ semaphore_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ -- no_destroy /* destroy */ -+ semaphore_destroy /* destroy */ - }; - - -@@ -106,6 +109,7 @@ static struct semaphore *create_semaphore( struct object *root, const struct uni - /* initialize it if it didn't already exist */ - sem->count = initial; - sem->max = max; -+ sem->fast_sync = NULL; - } - } - return sem; -@@ -168,6 +172,23 @@ static int semaphore_signal( struct object *obj, unsigned int access ) - return release_semaphore( sem, 1, NULL ); - } - -+static struct fast_sync *semaphore_get_fast_sync( struct object *obj ) -+{ -+ struct semaphore *semaphore = (struct semaphore *)obj; -+ -+ if (!semaphore->fast_sync) -+ semaphore->fast_sync = fast_create_semaphore( semaphore->count, semaphore->max ); -+ if (semaphore->fast_sync) grab_object( semaphore->fast_sync ); -+ return semaphore->fast_sync; -+} -+ -+static void semaphore_destroy( struct object *obj ) -+{ -+ struct semaphore *semaphore = (struct semaphore *)obj; -+ -+ if (semaphore->fast_sync) release_object( semaphore->fast_sync ); -+} -+ - /* create a semaphore */ - DECL_HANDLER(create_semaphore) - { --- -2.46.0 - - diff --git a/0007-ntsync/0006-server-create-fast-synchronization-objects-for.patch b/0007-ntsync/0006-server-create-fast-synchronization-objects-for.patch deleted file mode 100644 index dbb27ff..0000000 --- a/0007-ntsync/0006-server-create-fast-synchronization-objects-for.patch +++ /dev/null @@ -1,213 +0,0 @@ -From: Elizabeth Figura -Date: Thu, 11 Mar 2021 16:52:55 -0600 -Subject: [PATCH 06/32] server: Create fast synchronization objects for - mutexes. - ---- - server/fast_sync.c | 37 ++++++++++++++++++++++++++++++++++++- - server/mutex.c | 42 +++++++++++++++++++++++++++++++++++++----- - server/object.h | 2 ++ - 3 files changed, 75 insertions(+), 6 deletions(-) - -diff --git a/server/fast_sync.c b/server/fast_sync.c -index 7b21f54e2b6..4b9fc8a8f76 100644 ---- a/server/fast_sync.c -+++ b/server/fast_sync.c -@@ -270,7 +270,6 @@ struct fast_sync *fast_create_semaphore( unsigned int count, unsigned int max ) - { - struct ntsync_sem_args args = {0}; - struct linux_device *device; -- struct fast_sync *fast_sync; - - if (!(device = get_linux_device())) return NULL; - -@@ -288,6 +287,27 @@ struct fast_sync *fast_create_semaphore( unsigned int count, unsigned int max ) - return create_fast_sync( FAST_SYNC_SEMAPHORE, args.sem ); - } - -+struct fast_sync *fast_create_mutex( thread_id_t owner, unsigned int count ) -+{ -+ struct ntsync_mutex_args args = {0}; -+ struct linux_device *device; -+ -+ if (!(device = get_linux_device())) return NULL; -+ -+ args.owner = owner; -+ args.count = count; -+ if (ioctl( get_unix_fd( device->fd ), NTSYNC_IOC_CREATE_MUTEX, &args ) < 0) -+ { -+ file_set_error(); -+ release_object( device ); -+ return NULL; -+ } -+ -+ release_object( device ); -+ -+ return create_fast_sync( FAST_SYNC_MUTEX, args.mutex ); -+} -+ - void fast_set_event( struct fast_sync *fast_sync ) - { - __u32 count; -@@ -310,6 +330,11 @@ void fast_reset_event( struct fast_sync *fast_sync ) - ioctl( get_unix_fd( fast_sync->fd ), NTSYNC_IOC_EVENT_RESET, &count ); - } - -+void fast_abandon_mutex( thread_id_t tid, struct fast_sync *fast_sync ) -+{ -+ ioctl( get_unix_fd( fast_sync->fd ), NTSYNC_IOC_MUTEX_KILL, &tid ); -+} -+ - #else - - struct fast_sync *fast_create_event( enum fast_sync_type type, int signaled ) -@@ -324,6 +349,12 @@ struct fast_sync *fast_create_semaphore( unsigned int count, unsigned int max ) - return NULL; - } - -+struct fast_sync *fast_create_mutex( thread_id_t owner, unsigned int count ) -+{ -+ set_error( STATUS_NOT_IMPLEMENTED ); -+ return NULL; -+} -+ - void fast_set_event( struct fast_sync *fast_sync ) - { - } -@@ -332,4 +363,8 @@ void fast_reset_event( struct fast_sync *obj ) - { - } - -+void fast_abandon_mutex( thread_id_t tid, struct fast_sync *fast_sync ) -+{ -+} -+ - #endif -diff --git a/server/mutex.c b/server/mutex.c -index f7ad1e800c9..167c236e014 100644 ---- a/server/mutex.c -+++ b/server/mutex.c -@@ -38,6 +38,8 @@ - - static const WCHAR mutex_name[] = {'M','u','t','a','n','t'}; - -+static struct list fast_mutexes = LIST_INIT(fast_mutexes); -+ - struct type_descr mutex_type = - { - { mutex_name, sizeof(mutex_name) }, /* name */ -@@ -57,6 +59,8 @@ struct mutex - unsigned int count; /* recursion count */ - int abandoned; /* has it been abandoned? */ - struct list entry; /* entry in owner thread mutex list */ -+ struct list fast_mutexes_entry; /* entry in fast_mutexes list */ -+ struct fast_sync *fast_sync; /* fast synchronization object */ - }; - - static void mutex_dump( struct object *obj, int verbose ); -@@ -64,6 +68,7 @@ static int mutex_signaled( struct object *obj, struct wait_queue_entry *entry ); - static void mutex_satisfied( struct object *obj, struct wait_queue_entry *entry ); - static void mutex_destroy( struct object *obj ); - static int mutex_signal( struct object *obj, unsigned int access ); -+static struct fast_sync *mutex_get_fast_sync( struct object *obj ); - - static const struct object_ops mutex_ops = - { -@@ -85,7 +90,7 @@ static const struct object_ops mutex_ops = - default_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ mutex_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - mutex_destroy /* destroy */ - }; -@@ -128,6 +133,7 @@ static struct mutex *create_mutex( struct object *root, const struct unicode_str - mutex->owner = NULL; - mutex->abandoned = 0; - if (owned) do_grab( mutex, current ); -+ mutex->fast_sync = NULL; - } - } - return mutex; -@@ -135,16 +141,22 @@ static struct mutex *create_mutex( struct object *root, const struct unicode_str - - void abandon_mutexes( struct thread *thread ) - { -+ struct mutex *mutex; - struct list *ptr; - - while ((ptr = list_head( &thread->mutex_list )) != NULL) - { -- struct mutex *mutex = LIST_ENTRY( ptr, struct mutex, entry ); -+ mutex = LIST_ENTRY( ptr, struct mutex, entry ); - assert( mutex->owner == thread ); - mutex->count = 0; - mutex->abandoned = 1; - do_release( mutex ); - } -+ -+ LIST_FOR_EACH_ENTRY(mutex, &fast_mutexes, struct mutex, fast_mutexes_entry) -+ { -+ fast_abandon_mutex( thread->id, mutex->fast_sync ); -+ } - } - - static void mutex_dump( struct object *obj, int verbose ) -@@ -190,14 +202,34 @@ static int mutex_signal( struct object *obj, unsigned int access ) - return 1; - } - -+static struct fast_sync *mutex_get_fast_sync( struct object *obj ) -+{ -+ struct mutex *mutex = (struct mutex *)obj; -+ -+ if (!mutex->fast_sync) -+ { -+ mutex->fast_sync = fast_create_mutex( mutex->owner ? mutex->owner->id : 0, mutex->count ); -+ if (mutex->fast_sync) list_add_tail( &fast_mutexes, &mutex->fast_mutexes_entry ); -+ } -+ if (mutex->fast_sync) grab_object( mutex->fast_sync ); -+ return mutex->fast_sync; -+} -+ - static void mutex_destroy( struct object *obj ) - { - struct mutex *mutex = (struct mutex *)obj; - assert( obj->ops == &mutex_ops ); - -- if (!mutex->count) return; -- mutex->count = 0; -- do_release( mutex ); -+ if (mutex->count) -+ { -+ mutex->count = 0; -+ do_release( mutex ); -+ } -+ if (mutex->fast_sync) -+ { -+ release_object( mutex->fast_sync ); -+ list_remove( &mutex->fast_mutexes_entry ); -+ } - } - - /* create a mutex */ -diff --git a/server/object.h b/server/object.h -index 237f55a3c9c..6029e31a3a6 100644 ---- a/server/object.h -+++ b/server/object.h -@@ -228,8 +228,10 @@ extern void abandon_mutexes( struct thread *thread ); - - extern struct fast_sync *fast_create_event( enum fast_sync_type type, int signaled ); - extern struct fast_sync *fast_create_semaphore( unsigned int count, unsigned int max ); -+extern struct fast_sync *fast_create_mutex( thread_id_t owner, unsigned int count ); - extern void fast_set_event( struct fast_sync *obj ); - extern void fast_reset_event( struct fast_sync *obj ); -+extern void fast_abandon_mutex( thread_id_t tid, struct fast_sync *fast_sync ); - - extern struct fast_sync *no_get_fast_sync( struct object *obj ); - --- -2.46.0 - - diff --git a/0007-ntsync/0007-server-create-fast-synchronization-objects-for.patch b/0007-ntsync/0007-server-create-fast-synchronization-objects-for.patch deleted file mode 100644 index 63f9114..0000000 --- a/0007-ntsync/0007-server-create-fast-synchronization-objects-for.patch +++ /dev/null @@ -1,89 +0,0 @@ -From: Elizabeth Figura -Date: Thu, 11 Mar 2021 20:32:58 -0600 -Subject: [PATCH 07/32] server: Create fast synchronization objects for - completion ports. - ---- - server/completion.c | 19 ++++++++++++++++++- - 1 file changed, 18 insertions(+), 1 deletion(-) - -diff --git a/server/completion.c b/server/completion.c -index dd16787c63c..5ec6d209d13 100644 ---- a/server/completion.c -+++ b/server/completion.c -@@ -61,10 +61,12 @@ struct completion - struct object obj; - struct list queue; - unsigned int depth; -+ struct fast_sync *fast_sync; - }; - - static void completion_dump( struct object*, int ); - static int completion_signaled( struct object *obj, struct wait_queue_entry *entry ); -+static struct fast_sync *completion_get_fast_sync( struct object *obj ); - static void completion_destroy( struct object * ); - - static const struct object_ops completion_ops = -@@ -87,7 +89,7 @@ static const struct object_ops completion_ops = - default_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ completion_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - completion_destroy /* destroy */ - }; -@@ -110,6 +112,7 @@ static void completion_destroy( struct object *obj) - { - free( tmp ); - } -+ if (completion->fast_sync) release_object( completion->fast_sync ); - } - - static void completion_dump( struct object *obj, int verbose ) -@@ -127,6 +130,16 @@ static int completion_signaled( struct object *obj, struct wait_queue_entry *ent - return !list_empty( &completion->queue ); - } - -+static struct fast_sync *completion_get_fast_sync( struct object *obj ) -+{ -+ struct completion *completion = (struct completion *)obj; -+ -+ if (!completion->fast_sync) -+ completion->fast_sync = fast_create_event( FAST_SYNC_MANUAL_SERVER, !list_empty( &completion->queue ) ); -+ if (completion->fast_sync) grab_object( completion->fast_sync ); -+ return completion->fast_sync; -+} -+ - static struct completion *create_completion( struct object *root, const struct unicode_str *name, - unsigned int attr, unsigned int concurrent, - const struct security_descriptor *sd ) -@@ -139,6 +152,7 @@ static struct completion *create_completion( struct object *root, const struct u - { - list_init( &completion->queue ); - completion->depth = 0; -+ completion->fast_sync = NULL; - } - } - -@@ -166,6 +180,7 @@ void add_completion( struct completion *completion, apc_param_t ckey, apc_param_ - list_add_tail( &completion->queue, &msg->queue_entry ); - completion->depth++; - wake_up( &completion->obj, 1 ); -+ fast_set_event( completion->fast_sync ); - } - - /* create a completion */ -@@ -232,6 +247,8 @@ DECL_HANDLER(remove_completion) - reply->status = msg->status; - reply->information = msg->information; - free( msg ); -+ if (list_empty( &completion->queue )) -+ fast_reset_event( completion->fast_sync ); - } - - release_object( completion ); --- -2.46.0 - - diff --git a/0007-ntsync/0008-server-create-fast-synchronization-objects-for.patch b/0007-ntsync/0008-server-create-fast-synchronization-objects-for.patch deleted file mode 100644 index 563ac59..0000000 --- a/0007-ntsync/0008-server-create-fast-synchronization-objects-for.patch +++ /dev/null @@ -1,197 +0,0 @@ -From: Elizabeth Figura -Date: Mon, 8 Mar 2021 16:54:34 -0600 -Subject: [PATCH 08/32] server: Create fast synchronization objects for - consoles. - ---- - server/console.c | 64 ++++++++++++++++++++++++++++++++++++++++++++---- - 1 file changed, 59 insertions(+), 5 deletions(-) - -diff --git a/server/console.c b/server/console.c -index 5b7e08920e8..a9f254c2ef3 100644 ---- a/server/console.c -+++ b/server/console.c -@@ -61,6 +61,7 @@ struct console - struct fd *fd; /* for bare console, attached input fd */ - struct async_queue ioctl_q; /* ioctl queue */ - struct async_queue read_q; /* read queue */ -+ struct fast_sync *fast_sync; /* fast synchronization object */ - }; - - static void console_dump( struct object *obj, int verbose ); -@@ -72,6 +73,7 @@ static struct object *console_lookup_name( struct object *obj, struct unicode_st - static struct object *console_open_file( struct object *obj, unsigned int access, - unsigned int sharing, unsigned int options ); - static int console_add_queue( struct object *obj, struct wait_queue_entry *entry ); -+static struct fast_sync *console_get_fast_sync( struct object *obj ); - - static const struct object_ops console_ops = - { -@@ -93,7 +95,7 @@ static const struct object_ops console_ops = - NULL, /* unlink_name */ - console_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ console_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - console_destroy /* destroy */ - }; -@@ -220,6 +222,7 @@ static int screen_buffer_add_queue( struct object *obj, struct wait_queue_entry - static struct fd *screen_buffer_get_fd( struct object *obj ); - static struct object *screen_buffer_open_file( struct object *obj, unsigned int access, - unsigned int sharing, unsigned int options ); -+static struct fast_sync *screen_buffer_get_fast_sync( struct object *obj ); - - static const struct object_ops screen_buffer_ops = - { -@@ -241,7 +244,7 @@ static const struct object_ops screen_buffer_ops = - NULL, /* unlink_name */ - screen_buffer_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ screen_buffer_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - screen_buffer_destroy /* destroy */ - }; -@@ -307,6 +310,7 @@ static struct object *console_input_open_file( struct object *obj, unsigned int - unsigned int sharing, unsigned int options ); - static int console_input_add_queue( struct object *obj, struct wait_queue_entry *entry ); - static struct fd *console_input_get_fd( struct object *obj ); -+static struct fast_sync *console_input_get_fast_sync( struct object *obj ); - static void console_input_destroy( struct object *obj ); - - static const struct object_ops console_input_ops = -@@ -329,7 +333,7 @@ static const struct object_ops console_input_ops = - default_unlink_name, /* unlink_name */ - console_input_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ console_input_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - console_input_destroy /* destroy */ - }; -@@ -365,6 +369,7 @@ static int console_output_add_queue( struct object *obj, struct wait_queue_entry - static struct fd *console_output_get_fd( struct object *obj ); - static struct object *console_output_open_file( struct object *obj, unsigned int access, - unsigned int sharing, unsigned int options ); -+static struct fast_sync *console_output_get_fast_sync( struct object *obj ); - static void console_output_destroy( struct object *obj ); - - static const struct object_ops console_output_ops = -@@ -387,7 +392,7 @@ static const struct object_ops console_output_ops = - default_unlink_name, /* unlink_name */ - console_output_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ console_output_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - console_output_destroy /* destroy */ - }; -@@ -546,6 +551,7 @@ static struct object *create_console(void) - console->server = NULL; - console->fd = NULL; - console->last_id = 0; -+ console->fast_sync = NULL; - init_async_queue( &console->ioctl_q ); - init_async_queue( &console->read_q ); - -@@ -771,6 +777,8 @@ static void console_destroy( struct object *obj ) - free_async_queue( &console->read_q ); - if (console->fd) - release_object( console->fd ); -+ -+ if (console->fast_sync) release_object( console->fast_sync ); - } - - static struct object *create_console_connection( struct console *console ) -@@ -818,6 +826,16 @@ static struct object *console_open_file( struct object *obj, unsigned int access - return grab_object( obj ); - } - -+static struct fast_sync *console_get_fast_sync( struct object *obj ) -+{ -+ struct console *console = (struct console *)obj; -+ -+ if (!console->fast_sync) -+ console->fast_sync = fast_create_event( FAST_SYNC_MANUAL_SERVER, console->signaled ); -+ if (console->fast_sync) grab_object( console->fast_sync ); -+ return console->fast_sync; -+} -+ - static void screen_buffer_dump( struct object *obj, int verbose ) - { - struct screen_buffer *screen_buffer = (struct screen_buffer *)obj; -@@ -867,6 +885,17 @@ static struct fd *screen_buffer_get_fd( struct object *obj ) - return NULL; - } - -+static struct fast_sync *screen_buffer_get_fast_sync( struct object *obj ) -+{ -+ struct screen_buffer *screen_buffer = (struct screen_buffer *)obj; -+ if (!screen_buffer->input) -+ { -+ set_error( STATUS_ACCESS_DENIED ); -+ return NULL; -+ } -+ return console_get_fast_sync( &screen_buffer->input->obj ); -+} -+ - static void console_server_dump( struct object *obj, int verbose ) - { - assert( obj->ops == &console_server_ops ); -@@ -1409,6 +1438,16 @@ static struct object *console_input_open_file( struct object *obj, unsigned int - return grab_object( obj ); - } - -+static struct fast_sync *console_input_get_fast_sync( struct object *obj ) -+{ -+ if (!current->process->console) -+ { -+ set_error( STATUS_ACCESS_DENIED ); -+ return NULL; -+ } -+ return console_get_fast_sync( ¤t->process->console->obj ); -+} -+ - static void console_input_destroy( struct object *obj ) - { - struct console_input *console_input = (struct console_input *)obj; -@@ -1481,6 +1520,16 @@ static struct object *console_output_open_file( struct object *obj, unsigned int - return grab_object( obj ); - } - -+static struct fast_sync *console_output_get_fast_sync( struct object *obj ) -+{ -+ if (!current->process->console || !current->process->console->active) -+ { -+ set_error( STATUS_ACCESS_DENIED ); -+ return NULL; -+ } -+ return console_get_fast_sync( ¤t->process->console->obj ); -+} -+ - static void console_output_destroy( struct object *obj ) - { - struct console_output *console_output = (struct console_output *)obj; -@@ -1538,11 +1587,16 @@ DECL_HANDLER(get_next_console_request) - - if (!server->console->renderer) server->console->renderer = current; - -- if (!req->signal) server->console->signaled = 0; -+ if (!req->signal) -+ { -+ server->console->signaled = 0; -+ fast_reset_event( server->console->fast_sync ); -+ } - else if (!server->console->signaled) - { - server->console->signaled = 1; - wake_up( &server->console->obj, 0 ); -+ fast_set_event( server->console->fast_sync ); - } - - if (req->read) --- -2.46.0 - - diff --git a/0007-ntsync/0009-server-create-fast-synchronization-objects-for-console.patch b/0007-ntsync/0009-server-create-fast-synchronization-objects-for-console.patch deleted file mode 100644 index ee17139..0000000 --- a/0007-ntsync/0009-server-create-fast-synchronization-objects-for-console.patch +++ /dev/null @@ -1,110 +0,0 @@ -From: Elizabeth Figura -Date: Mon, 8 Mar 2021 17:00:51 -0600 -Subject: [PATCH 09/32] server: Create fast synchronization objects for console - servers. - ---- - server/console.c | 24 +++++++++++++++++++++++- - 1 file changed, 23 insertions(+), 1 deletion(-) - -diff --git a/server/console.c b/server/console.c -index a9f254c2ef3..17708df7953 100644 ---- a/server/console.c -+++ b/server/console.c -@@ -142,6 +142,7 @@ struct console_server - unsigned int once_input : 1; /* flag if input thread has already been requested */ - int term_fd; /* UNIX terminal fd */ - struct termios termios; /* original termios */ -+ struct fast_sync *fast_sync; /* fast synchronization object */ - }; - - static void console_server_dump( struct object *obj, int verbose ); -@@ -152,6 +153,7 @@ static struct object *console_server_lookup_name( struct object *obj, struct uni - unsigned int attr, struct object *root ); - static struct object *console_server_open_file( struct object *obj, unsigned int access, - unsigned int sharing, unsigned int options ); -+static struct fast_sync *console_server_get_fast_sync( struct object *obj ); - - static const struct object_ops console_server_ops = - { -@@ -173,7 +175,7 @@ static const struct object_ops console_server_ops = - NULL, /* unlink_name */ - console_server_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ console_server_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - console_server_destroy /* destroy */ - }; -@@ -591,6 +593,7 @@ static int queue_host_ioctl( struct console_server *server, unsigned int code, u - } - list_add_tail( &server->queue, &ioctl->entry ); - wake_up( &server->obj, 0 ); -+ fast_set_event( server->fast_sync ); - if (async) set_error( STATUS_PENDING ); - return 1; - } -@@ -623,6 +626,7 @@ static void disconnect_console_server( struct console_server *server ) - server->console->server = NULL; - server->console = NULL; - wake_up( &server->obj, 0 ); -+ fast_set_event( server->fast_sync ); - } - } - -@@ -908,6 +912,7 @@ static void console_server_destroy( struct object *obj ) - assert( obj->ops == &console_server_ops ); - disconnect_console_server( server ); - if (server->fd) release_object( server->fd ); -+ if (server->fast_sync) release_object( server->fast_sync ); - } - - static struct object *console_server_lookup_name( struct object *obj, struct unicode_str *name, -@@ -962,6 +967,17 @@ static struct object *console_server_open_file( struct object *obj, unsigned int - return grab_object( obj ); - } - -+static struct fast_sync *console_server_get_fast_sync( struct object *obj ) -+{ -+ struct console_server *server = (struct console_server *)obj; -+ int signaled = !server->console || !list_empty( &server->queue ); -+ -+ if (!server->fast_sync) -+ server->fast_sync = fast_create_event( FAST_SYNC_MANUAL_SERVER, signaled ); -+ if (server->fast_sync) grab_object( server->fast_sync ); -+ return server->fast_sync; -+} -+ - static struct object *create_console_server( void ) - { - struct console_server *server; -@@ -973,6 +989,7 @@ static struct object *create_console_server( void ) - server->term_fd = -1; - list_init( &server->queue ); - list_init( &server->read_queue ); -+ server->fast_sync = NULL; - server->fd = alloc_pseudo_fd( &console_server_fd_ops, &server->obj, FILE_SYNCHRONOUS_IO_NONALERT ); - if (!server->fd) - { -@@ -1618,6 +1635,8 @@ DECL_HANDLER(get_next_console_request) - /* set result of previous ioctl */ - ioctl = LIST_ENTRY( list_head( &server->queue ), struct console_host_ioctl, entry ); - list_remove( &ioctl->entry ); -+ if (list_empty( &server->queue )) -+ fast_reset_event( server->fast_sync ); - } - - if (ioctl) -@@ -1704,5 +1723,8 @@ DECL_HANDLER(get_next_console_request) - set_error( STATUS_PENDING ); - } - -+ if (list_empty( &server->queue )) -+ fast_reset_event( server->fast_sync ); -+ - release_object( server ); - } --- -2.46.0 - - diff --git a/0007-ntsync/0010-server-create-fast-synchronization-objects-for-debug.patch b/0007-ntsync/0010-server-create-fast-synchronization-objects-for-debug.patch deleted file mode 100644 index e93b1c9..0000000 --- a/0007-ntsync/0010-server-create-fast-synchronization-objects-for-debug.patch +++ /dev/null @@ -1,103 +0,0 @@ -From: Elizabeth Figura -Date: Mon, 8 Mar 2021 17:11:03 -0600 -Subject: [PATCH 10/32] server: Create fast synchronization objects for debug - objects. - ---- - server/debugger.c | 23 ++++++++++++++++++++++- - 1 file changed, 22 insertions(+), 1 deletion(-) - -diff --git a/server/debugger.c b/server/debugger.c -index cee0c57fab3..7975fc44006 100644 ---- a/server/debugger.c -+++ b/server/debugger.c -@@ -71,6 +71,7 @@ struct debug_obj - struct object obj; /* object header */ - struct list event_queue; /* pending events queue */ - unsigned int flags; /* debug flags */ -+ struct fast_sync *fast_sync; /* fast synchronization object */ - }; - - -@@ -105,6 +106,7 @@ static const struct object_ops debug_event_ops = - - static void debug_obj_dump( struct object *obj, int verbose ); - static int debug_obj_signaled( struct object *obj, struct wait_queue_entry *entry ); -+static struct fast_sync *debug_obj_get_fast_sync( struct object *obj ); - static void debug_obj_destroy( struct object *obj ); - - static const struct object_ops debug_obj_ops = -@@ -127,7 +129,7 @@ static const struct object_ops debug_obj_ops = - default_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ debug_obj_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - debug_obj_destroy /* destroy */ - }; -@@ -255,6 +257,7 @@ static void link_event( struct debug_obj *debug_obj, struct debug_event *event ) - /* grab reference since debugger could be killed while trying to wake up */ - grab_object( debug_obj ); - wake_up( &debug_obj->obj, 0 ); -+ fast_set_event( debug_obj->fast_sync ); - release_object( debug_obj ); - } - } -@@ -267,6 +270,7 @@ static void resume_event( struct debug_obj *debug_obj, struct debug_event *event - { - grab_object( debug_obj ); - wake_up( &debug_obj->obj, 0 ); -+ fast_set_event( debug_obj->fast_sync ); - release_object( debug_obj ); - } - } -@@ -332,6 +336,17 @@ static int debug_obj_signaled( struct object *obj, struct wait_queue_entry *entr - return find_event_to_send( debug_obj ) != NULL; - } - -+static struct fast_sync *debug_obj_get_fast_sync( struct object *obj ) -+{ -+ struct debug_obj *debug_obj = (struct debug_obj *)obj; -+ int signaled = find_event_to_send( debug_obj ) != NULL; -+ -+ if (!debug_obj->fast_sync) -+ debug_obj->fast_sync = fast_create_event( FAST_SYNC_MANUAL_SERVER, signaled ); -+ if (debug_obj->fast_sync) grab_object( debug_obj->fast_sync ); -+ return debug_obj->fast_sync; -+} -+ - static void debug_obj_destroy( struct object *obj ) - { - struct list *ptr; -@@ -344,6 +359,8 @@ static void debug_obj_destroy( struct object *obj ) - /* free all pending events */ - while ((ptr = list_head( &debug_obj->event_queue ))) - unlink_event( debug_obj, LIST_ENTRY( ptr, struct debug_event, entry )); -+ -+ if (debug_obj->fast_sync) release_object( debug_obj->fast_sync ); - } - - struct debug_obj *get_debug_obj( struct process *process, obj_handle_t handle, unsigned int access ) -@@ -363,6 +380,7 @@ static struct debug_obj *create_debug_obj( struct object *root, const struct uni - { - debug_obj->flags = flags; - list_init( &debug_obj->event_queue ); -+ debug_obj->fast_sync = NULL; - } - } - return debug_obj; -@@ -571,6 +589,9 @@ DECL_HANDLER(wait_debug_event) - reply->tid = get_thread_id( event->sender ); - alloc_event_handles( event, current->process ); - set_reply_data( &event->data, min( get_reply_max_size(), sizeof(event->data) )); -+ -+ if (!find_event_to_send( debug_obj )) -+ fast_reset_event( debug_obj->fast_sync ); - } - else - { --- -2.46.0 - - diff --git a/0007-ntsync/0011-server-create-fast-synchronization-objects-for-device.patch b/0007-ntsync/0011-server-create-fast-synchronization-objects-for-device.patch deleted file mode 100644 index 8657be3..0000000 --- a/0007-ntsync/0011-server-create-fast-synchronization-objects-for-device.patch +++ /dev/null @@ -1,108 +0,0 @@ -From: Elizabeth Figura -Date: Wed, 10 Mar 2021 11:02:42 -0600 -Subject: [PATCH 11/32] server: Create fast synchronization objects for device - managers. - ---- - server/device.c | 31 +++++++++++++++++++++++++++++-- - 1 file changed, 29 insertions(+), 2 deletions(-) - -diff --git a/server/device.c b/server/device.c -index 691c0eb6b5f..e718263ebb5 100644 ---- a/server/device.c -+++ b/server/device.c -@@ -93,10 +93,12 @@ struct device_manager - struct list requests; /* list of pending irps across all devices */ - struct irp_call *current_call; /* call currently executed on client side */ - struct wine_rb_tree kernel_objects; /* map of objects that have client side pointer associated */ -+ struct fast_sync *fast_sync; /* fast synchronization object */ - }; - - static void device_manager_dump( struct object *obj, int verbose ); - static int device_manager_signaled( struct object *obj, struct wait_queue_entry *entry ); -+static struct fast_sync *device_manager_get_fast_sync( struct object *obj ); - static void device_manager_destroy( struct object *obj ); - - static const struct object_ops device_manager_ops = -@@ -119,7 +121,7 @@ static const struct object_ops device_manager_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ device_manager_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - device_manager_destroy /* destroy */ - }; -@@ -421,7 +423,12 @@ static void add_irp_to_queue( struct device_manager *manager, struct irp_call *i - irp->thread = thread ? (struct thread *)grab_object( thread ) : NULL; - if (irp->file) list_add_tail( &irp->file->requests, &irp->dev_entry ); - list_add_tail( &manager->requests, &irp->mgr_entry ); -- if (list_head( &manager->requests ) == &irp->mgr_entry) wake_up( &manager->obj, 0 ); /* first one */ -+ if (list_head( &manager->requests ) == &irp->mgr_entry) -+ { -+ /* first one */ -+ wake_up( &manager->obj, 0 ); -+ fast_set_event( manager->fast_sync ); -+ } - } - - static struct object *device_open_file( struct object *obj, unsigned int access, -@@ -755,6 +762,9 @@ static void delete_file( struct device_file *file ) - set_irp_result( irp, STATUS_FILE_DELETED, NULL, 0, 0 ); - } - -+ if (list_empty( &file->device->manager->requests )) -+ fast_reset_event( file->device->manager->fast_sync ); -+ - release_object( file ); - } - -@@ -786,6 +796,16 @@ static int device_manager_signaled( struct object *obj, struct wait_queue_entry - return !list_empty( &manager->requests ); - } - -+static struct fast_sync *device_manager_get_fast_sync( struct object *obj ) -+{ -+ struct device_manager *manager = (struct device_manager *)obj; -+ -+ if (!manager->fast_sync) -+ manager->fast_sync = fast_create_event( FAST_SYNC_MANUAL_SERVER, !list_empty( &manager->requests ) ); -+ if (manager->fast_sync) grab_object( manager->fast_sync ); -+ return manager->fast_sync; -+} -+ - static void device_manager_destroy( struct object *obj ) - { - struct device_manager *manager = (struct device_manager *)obj; -@@ -820,6 +840,8 @@ static void device_manager_destroy( struct object *obj ) - assert( !irp->file && !irp->async ); - release_object( irp ); - } -+ -+ if (manager->fast_sync) release_object( manager->fast_sync ); - } - - static struct device_manager *create_device_manager(void) -@@ -829,6 +851,7 @@ static struct device_manager *create_device_manager(void) - if ((manager = alloc_object( &device_manager_ops ))) - { - manager->current_call = NULL; -+ manager->fast_sync = NULL; - list_init( &manager->devices ); - list_init( &manager->requests ); - wine_rb_init( &manager->kernel_objects, compare_kernel_object ); -@@ -1018,6 +1041,10 @@ DECL_HANDLER(get_next_device_request) - } - list_remove( &irp->mgr_entry ); - list_init( &irp->mgr_entry ); -+ -+ if (list_empty( &manager->requests )) -+ fast_reset_event( manager->fast_sync ); -+ - /* we already own the object if it's only on manager queue */ - if (irp->file) grab_object( irp ); - manager->current_call = irp; --- -2.46.0 - - diff --git a/0007-ntsync/0012-server-create-fast-synchronization-objects-for-keyed.patch b/0007-ntsync/0012-server-create-fast-synchronization-objects-for-keyed.patch deleted file mode 100644 index 825d74b..0000000 --- a/0007-ntsync/0012-server-create-fast-synchronization-objects-for-keyed.patch +++ /dev/null @@ -1,75 +0,0 @@ -From: Elizabeth Figura -Date: Mon, 8 Mar 2021 17:13:20 -0600 -Subject: [PATCH 12/32] server: Create fast synchronization objects for keyed - events. - ---- - server/event.c | 25 +++++++++++++++++++++++-- - 1 file changed, 23 insertions(+), 2 deletions(-) - -diff --git a/server/event.c b/server/event.c -index 8c82f8445c4..b750a22487b 100644 ---- a/server/event.c -+++ b/server/event.c -@@ -110,10 +110,13 @@ struct type_descr keyed_event_type = - struct keyed_event - { - struct object obj; /* object header */ -+ struct fast_sync *fast_sync; /* fast synchronization object */ - }; - - static void keyed_event_dump( struct object *obj, int verbose ); - static int keyed_event_signaled( struct object *obj, struct wait_queue_entry *entry ); -+static struct fast_sync *keyed_event_get_fast_sync( struct object *obj ); -+static void keyed_event_destroy( struct object *obj ); - - static const struct object_ops keyed_event_ops = - { -@@ -135,9 +138,9 @@ static const struct object_ops keyed_event_ops = - default_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ keyed_event_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ -- no_destroy /* destroy */ -+ keyed_event_destroy /* destroy */ - }; - - -@@ -261,6 +264,7 @@ struct keyed_event *create_keyed_event( struct object *root, const struct unicod - if (get_error() != STATUS_OBJECT_NAME_EXISTS) - { - /* initialize it if it didn't already exist */ -+ event->fast_sync = NULL; - } - } - return event; -@@ -304,6 +308,23 @@ static int keyed_event_signaled( struct object *obj, struct wait_queue_entry *en - return 0; - } - -+static struct fast_sync *keyed_event_get_fast_sync( struct object *obj ) -+{ -+ struct keyed_event *event = (struct keyed_event *)obj; -+ -+ if (!event->fast_sync) -+ event->fast_sync = fast_create_event( FAST_SYNC_MANUAL_SERVER, 1 ); -+ if (event->fast_sync) grab_object( event->fast_sync ); -+ return event->fast_sync; -+} -+ -+static void keyed_event_destroy( struct object *obj ) -+{ -+ struct keyed_event *event = (struct keyed_event *)obj; -+ -+ if (event->fast_sync) release_object( event->fast_sync ); -+} -+ - /* create an event */ - DECL_HANDLER(create_event) - { --- -2.46.0 - - diff --git a/0007-ntsync/0013-server-create-fast-synchronization-objects-for.patch b/0007-ntsync/0013-server-create-fast-synchronization-objects-for.patch deleted file mode 100644 index 7a30fa2..0000000 --- a/0007-ntsync/0013-server-create-fast-synchronization-objects-for.patch +++ /dev/null @@ -1,89 +0,0 @@ -From: Elizabeth Figura -Date: Mon, 8 Mar 2021 17:16:53 -0600 -Subject: [PATCH 13/32] server: Create fast synchronization objects for - processes. - ---- - server/process.c | 17 ++++++++++++++++- - server/process.h | 1 + - 2 files changed, 17 insertions(+), 1 deletion(-) - -diff --git a/server/process.c b/server/process.c -index 68b4ccff51e..4daf9c9929f 100644 ---- a/server/process.c -+++ b/server/process.c -@@ -94,6 +94,7 @@ static unsigned int process_map_access( struct object *obj, unsigned int access - static struct security_descriptor *process_get_sd( struct object *obj ); - static void process_poll_event( struct fd *fd, int event ); - static struct list *process_get_kernel_obj_list( struct object *obj ); -+static struct fast_sync *process_get_fast_sync( struct object *obj ); - static void process_destroy( struct object *obj ); - static void terminate_process( struct process *process, struct thread *skip, int exit_code ); - -@@ -117,7 +118,7 @@ static const struct object_ops process_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - process_get_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ process_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - process_destroy /* destroy */ - }; -@@ -686,6 +687,7 @@ struct process *create_process( int fd, struct process *parent, unsigned int fla - process->rawinput_device_count = 0; - process->rawinput_mouse = NULL; - process->rawinput_kbd = NULL; -+ process->fast_sync = NULL; - memset( &process->image_info, 0, sizeof(process->image_info) ); - list_init( &process->rawinput_entry ); - list_init( &process->kernel_object ); -@@ -786,6 +788,8 @@ static void process_destroy( struct object *obj ) - free( process->rawinput_devices ); - free( process->dir_cache ); - free( process->image ); -+ -+ if (process->fast_sync) release_object( process->fast_sync ); - } - - /* dump a process on stdout for debugging purposes */ -@@ -817,6 +821,16 @@ static struct list *process_get_kernel_obj_list( struct object *obj ) - return &process->kernel_object; - } - -+static struct fast_sync *process_get_fast_sync( struct object *obj ) -+{ -+ struct process *process = (struct process *)obj; -+ -+ if (!process->fast_sync) -+ process->fast_sync = fast_create_event( FAST_SYNC_MANUAL_SERVER, !process->running_threads ); -+ if (process->fast_sync) grab_object( process->fast_sync ); -+ return process->fast_sync; -+} -+ - static struct security_descriptor *process_get_sd( struct object *obj ) - { - static struct security_descriptor *process_default_sd; -@@ -981,6 +995,7 @@ static void process_killed( struct process *process ) - release_job_process( process ); - start_sigkill_timer( process ); - wake_up( &process->obj, 0 ); -+ fast_set_event( process->fast_sync ); - } - - /* add a thread to a process running threads list */ -diff --git a/server/process.h b/server/process.h -index 1e73e9d47dc..2140427902b 100644 ---- a/server/process.h -+++ b/server/process.h -@@ -86,6 +86,7 @@ struct process - struct list rawinput_entry; /* entry in the rawinput process list */ - struct list kernel_object; /* list of kernel object pointers */ - pe_image_info_t image_info; /* main exe image info */ -+ struct fast_sync *fast_sync; /* fast synchronization object */ - }; - - /* process functions */ --- -2.46.0 - - diff --git a/0007-ntsync/0014-server-create-fast-synchronization-objects-for-jobs.patch b/0007-ntsync/0014-server-create-fast-synchronization-objects-for-jobs.patch deleted file mode 100644 index 125feb3..0000000 --- a/0007-ntsync/0014-server-create-fast-synchronization-objects-for-jobs.patch +++ /dev/null @@ -1,76 +0,0 @@ -From: Elizabeth Figura -Date: Mon, 8 Mar 2021 17:17:35 -0600 -Subject: [PATCH 14/32] server: Create fast synchronization objects for jobs. - ---- - server/process.c | 18 +++++++++++++++++- - 1 file changed, 17 insertions(+), 1 deletion(-) - -diff --git a/server/process.c b/server/process.c -index 4daf9c9929f..388786192dc 100644 ---- a/server/process.c -+++ b/server/process.c -@@ -193,6 +193,7 @@ struct type_descr job_type = - - static void job_dump( struct object *obj, int verbose ); - static int job_signaled( struct object *obj, struct wait_queue_entry *entry ); -+static struct fast_sync *job_get_fast_sync( struct object *obj ); - static int job_close_handle( struct object *obj, struct process *process, obj_handle_t handle ); - static void job_destroy( struct object *obj ); - -@@ -210,6 +211,7 @@ struct job - struct job *parent; - struct list parent_job_entry; /* list entry for parent job */ - struct list child_job_list; /* list of child jobs */ -+ struct fast_sync *fast_sync; /* fast synchronization object */ - }; - - static const struct object_ops job_ops = -@@ -232,7 +234,7 @@ static const struct object_ops job_ops = - default_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ job_get_fast_sync, /* get_fast_sync */ - job_close_handle, /* close_handle */ - job_destroy /* destroy */ - }; -@@ -257,6 +259,7 @@ static struct job *create_job_object( struct object *root, const struct unicode_ - job->completion_port = NULL; - job->completion_key = 0; - job->parent = NULL; -+ job->fast_sync = NULL; - } - } - return job; -@@ -413,6 +416,17 @@ static void terminate_job( struct job *job, int exit_code ) - job->terminating = 0; - job->signaled = 1; - wake_up( &job->obj, 0 ); -+ fast_set_event( job->fast_sync ); -+} -+ -+static struct fast_sync *job_get_fast_sync( struct object *obj ) -+{ -+ struct job *job = (struct job *)obj; -+ -+ if (!job->fast_sync) -+ job->fast_sync = fast_create_event( FAST_SYNC_MANUAL_SERVER, job->signaled ); -+ if (job->fast_sync) grab_object( job->fast_sync ); -+ return job->fast_sync; - } - - static int job_close_handle( struct object *obj, struct process *process, obj_handle_t handle ) -@@ -443,6 +457,8 @@ static void job_destroy( struct object *obj ) - list_remove( &job->parent_job_entry ); - release_object( job->parent ); - } -+ -+ if (job->fast_sync) release_object( job->fast_sync ); - } - - static void job_dump( struct object *obj, int verbose ) --- -2.46.0 - - diff --git a/0007-ntsync/0015-server-create-fast-synchronization-objects-for-message.patch b/0007-ntsync/0015-server-create-fast-synchronization-objects-for-message.patch deleted file mode 100644 index 3bcc46e..0000000 --- a/0007-ntsync/0015-server-create-fast-synchronization-objects-for-message.patch +++ /dev/null @@ -1,152 +0,0 @@ -From: Elizabeth Figura -Date: Mon, 8 Mar 2021 17:24:15 -0600 -Subject: [PATCH 15/32] server: Create fast synchronization objects for message - queues. - ---- - server/queue.c | 43 ++++++++++++++++++++++++++++++++++++++++--- - 1 file changed, 40 insertions(+), 3 deletions(-) - -diff --git a/server/queue.c b/server/queue.c -index c946b8b4a1c..9857c9d85a4 100644 ---- a/server/queue.c -+++ b/server/queue.c -@@ -133,6 +133,7 @@ struct msg_queue - int keystate_lock; /* owns an input keystate lock */ - const queue_shm_t *shared; /* queue in session shared memory */ - unsigned int ignore_post_msg; /* ignore post messages newer than this unique id */ -+ struct fast_sync *fast_sync; /* fast synchronization object */ - }; - - struct hotkey -@@ -150,6 +151,7 @@ static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *ent - static void msg_queue_remove_queue( struct object *obj, struct wait_queue_entry *entry ); - static int msg_queue_signaled( struct object *obj, struct wait_queue_entry *entry ); - static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *entry ); -+static struct fast_sync *msg_queue_get_fast_sync( struct object *obj ); - static void msg_queue_destroy( struct object *obj ); - static void msg_queue_poll_event( struct fd *fd, int event ); - static void thread_input_dump( struct object *obj, int verbose ); -@@ -176,7 +178,7 @@ static const struct object_ops msg_queue_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ msg_queue_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - msg_queue_destroy /* destroy */ - }; -@@ -314,6 +316,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ - queue->last_get_msg = current_time; - queue->keystate_lock = 0; - queue->ignore_post_msg = 0; -+ queue->fast_sync = NULL; - list_init( &queue->send_result ); - list_init( &queue->callback_result ); - list_init( &queue->pending_timers ); -@@ -722,7 +725,11 @@ static inline void set_queue_bits( struct msg_queue *queue, unsigned int bits ) - } - SHARED_WRITE_END; - -- if (is_signaled( queue )) wake_up( &queue->obj, 0 ); -+ if (is_signaled( queue )) -+ { -+ wake_up( &queue->obj, 0 ); -+ fast_set_event( queue->fast_sync ); -+ } - } - - /* clear some queue bits */ -@@ -742,6 +749,8 @@ static inline void clear_queue_bits( struct msg_queue *queue, unsigned int bits - if (queue->keystate_lock) unlock_input_keystate( queue->input ); - queue->keystate_lock = 0; - } -+ if (!is_signaled( queue )) -+ fast_reset_event( queue->fast_sync ); - } - - /* check if message is matched by the filter */ -@@ -1286,6 +1295,17 @@ static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *en - shared->changed_mask = 0; - } - SHARED_WRITE_END; -+ fast_reset_event( queue->fast_sync ); -+} -+ -+static struct fast_sync *msg_queue_get_fast_sync( struct object *obj ) -+{ -+ struct msg_queue *queue = (struct msg_queue *)obj; -+ -+ if (!queue->fast_sync) -+ queue->fast_sync = fast_create_event( FAST_SYNC_QUEUE, is_signaled( queue ) ); -+ if (queue->fast_sync) grab_object( queue->fast_sync ); -+ return queue->fast_sync; - } - - static void msg_queue_destroy( struct object *obj ) -@@ -1331,6 +1351,7 @@ static void msg_queue_destroy( struct object *obj ) - if (queue->hooks) release_object( queue->hooks ); - if (queue->fd) release_object( queue->fd ); - if (queue->shared) free_shared_object( queue->shared ); -+ if (queue->fast_sync) release_object( queue->fast_sync ); - } - - static void msg_queue_poll_event( struct fd *fd, int event ) -@@ -1341,6 +1362,7 @@ static void msg_queue_poll_event( struct fd *fd, int event ) - if (event & (POLLERR | POLLHUP)) set_fd_events( fd, -1 ); - else set_fd_events( queue->fd, 0 ); - wake_up( &queue->obj, 0 ); -+ fast_set_event( queue->fast_sync ); - } - - static void thread_input_dump( struct object *obj, int verbose ) -@@ -3105,8 +3127,17 @@ DECL_HANDLER(set_queue_mask) - shared->changed_mask = 0; - } - SHARED_WRITE_END; -+ fast_reset_event( queue->fast_sync ); -+ } -+ else -+ { -+ wake_up( &queue->obj, 0 ); -+ fast_set_event( queue->fast_sync ); - } -- else wake_up( &queue->obj, 0 ); -+ } -+ else -+ { -+ fast_reset_event( queue->fast_sync ); - } - } - } -@@ -3128,6 +3159,8 @@ DECL_HANDLER(get_queue_status) - shared->changed_bits &= ~req->clear_bits; - } - SHARED_WRITE_END; -+ if (!is_signaled( queue )) -+ fast_reset_event( queue->fast_sync ); - } - else reply->wake_bits = reply->changed_bits = 0; - } -@@ -3325,6 +3358,9 @@ DECL_HANDLER(get_message) - } - SHARED_WRITE_END; - -+ if (!is_signaled( queue )) -+ fast_reset_event( queue->fast_sync ); -+ - /* then check for posted messages */ - if ((filter & QS_POSTMESSAGE) && - get_posted_message( queue, get_win, req->get_first, req->get_last, req->flags, reply )) -@@ -3384,6 +3420,7 @@ DECL_HANDLER(get_message) - } - SHARED_WRITE_END; - -+ fast_reset_event( queue->fast_sync ); - set_error( STATUS_PENDING ); /* FIXME */ - } - --- -2.46.0 - - diff --git a/0007-ntsync/0016-server-create-fast-synchronization-objects-for.patch b/0007-ntsync/0016-server-create-fast-synchronization-objects-for.patch deleted file mode 100644 index d97a24b..0000000 --- a/0007-ntsync/0016-server-create-fast-synchronization-objects-for.patch +++ /dev/null @@ -1,88 +0,0 @@ -From: Elizabeth Figura -Date: Mon, 8 Mar 2021 17:26:35 -0600 -Subject: [PATCH 16/32] server: Create fast synchronization objects for - threads. - ---- - server/thread.c | 16 +++++++++++++++- - server/thread.h | 1 + - 2 files changed, 16 insertions(+), 1 deletion(-) - -diff --git a/server/thread.c b/server/thread.c -index 77ef21a7e9b..03369346c6a 100644 ---- a/server/thread.c -+++ b/server/thread.c -@@ -179,6 +179,7 @@ static int thread_signaled( struct object *obj, struct wait_queue_entry *entry ) - static unsigned int thread_map_access( struct object *obj, unsigned int access ); - static void thread_poll_event( struct fd *fd, int event ); - static struct list *thread_get_kernel_obj_list( struct object *obj ); -+static struct fast_sync *thread_get_fast_sync( struct object *obj ); - static void destroy_thread( struct object *obj ); - - static const struct object_ops thread_ops = -@@ -201,7 +202,7 @@ static const struct object_ops thread_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - thread_get_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ thread_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - destroy_thread /* destroy */ - }; -@@ -249,6 +250,7 @@ static inline void init_thread_structure( struct thread *thread ) - thread->desc = NULL; - thread->desc_len = 0; - thread->exit_poll = NULL; -+ thread->fast_sync = NULL; - - thread->creation_time = current_time; - thread->exit_time = 0; -@@ -399,6 +401,16 @@ static struct list *thread_get_kernel_obj_list( struct object *obj ) - return &thread->kernel_object; - } - -+static struct fast_sync *thread_get_fast_sync( struct object *obj ) -+{ -+ struct thread *thread = (struct thread *)obj; -+ -+ if (!thread->fast_sync) -+ thread->fast_sync = fast_create_event( FAST_SYNC_MANUAL_SERVER, thread->state == TERMINATED ); -+ if (thread->fast_sync) grab_object( thread->fast_sync ); -+ return thread->fast_sync; -+} -+ - /* cleanup everything that is no longer needed by a dead thread */ - /* used by destroy_thread and kill_thread */ - static void cleanup_thread( struct thread *thread ) -@@ -453,6 +465,7 @@ static void destroy_thread( struct object *obj ) - release_object( thread->process ); - if (thread->id) free_ptid( thread->id ); - if (thread->token) release_object( thread->token ); -+ if (thread->fast_sync) release_object( thread->fast_sync ); - } - - /* dump a thread on stdout for debugging purposes */ -@@ -1293,6 +1306,7 @@ void kill_thread( struct thread *thread, int violent_death ) - check_terminated( thread ); - } - else wake_up( &thread->obj, 0 ); -+ fast_set_event( thread->fast_sync ); - cleanup_thread( thread ); - remove_process_thread( thread->process, thread ); - release_object( thread ); -diff --git a/server/thread.h b/server/thread.h -index 766ed78a72f..7b11a548a78 100644 ---- a/server/thread.h -+++ b/server/thread.h -@@ -91,6 +91,7 @@ struct thread - data_size_t desc_len; /* thread description length in bytes */ - WCHAR *desc; /* thread description string */ - struct timeout_user *exit_poll; /* poll if the thread/process has exited already */ -+ struct fast_sync *fast_sync; /* fast synchronization object */ - }; - - extern struct thread *current; --- -2.46.0 - - diff --git a/0007-ntsync/0017-server-create-fast-synchronization-objects-for-timers.patch b/0007-ntsync/0017-server-create-fast-synchronization-objects-for-timers.patch deleted file mode 100644 index 9dbbe9e..0000000 --- a/0007-ntsync/0017-server-create-fast-synchronization-objects-for-timers.patch +++ /dev/null @@ -1,91 +0,0 @@ -From: Elizabeth Figura -Date: Mon, 8 Mar 2021 17:29:38 -0600 -Subject: [PATCH 17/32] server: Create fast synchronization objects for timers. - ---- - server/timer.c | 21 ++++++++++++++++++++- - 1 file changed, 20 insertions(+), 1 deletion(-) - -diff --git a/server/timer.c b/server/timer.c -index d4a69bf8794..854a8e1f7f2 100644 ---- a/server/timer.c -+++ b/server/timer.c -@@ -61,11 +61,13 @@ struct timer - struct thread *thread; /* thread that set the APC function */ - client_ptr_t callback; /* callback APC function */ - client_ptr_t arg; /* callback argument */ -+ struct fast_sync *fast_sync; /* fast synchronization object */ - }; - - static void timer_dump( struct object *obj, int verbose ); - static int timer_signaled( struct object *obj, struct wait_queue_entry *entry ); - static void timer_satisfied( struct object *obj, struct wait_queue_entry *entry ); -+static struct fast_sync *timer_get_fast_sync( struct object *obj ); - static void timer_destroy( struct object *obj ); - - static const struct object_ops timer_ops = -@@ -88,7 +90,7 @@ static const struct object_ops timer_ops = - default_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ timer_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - timer_destroy /* destroy */ - }; -@@ -111,6 +113,7 @@ static struct timer *create_timer( struct object *root, const struct unicode_str - timer->period = 0; - timer->timeout = NULL; - timer->thread = NULL; -+ timer->fast_sync = NULL; - } - } - return timer; -@@ -152,6 +155,7 @@ static void timer_callback( void *private ) - /* wake up waiters */ - timer->signaled = 1; - wake_up( &timer->obj, 0 ); -+ fast_set_event( timer->fast_sync ); - } - - /* cancel a running timer */ -@@ -182,6 +186,7 @@ static int set_timer( struct timer *timer, timeout_t expire, unsigned int period - { - period = 0; /* period doesn't make any sense for a manual timer */ - timer->signaled = 0; -+ fast_reset_event( timer->fast_sync ); - } - timer->when = (expire <= 0) ? expire - monotonic_time : max( expire, current_time ); - timer->period = period; -@@ -216,6 +221,19 @@ static void timer_satisfied( struct object *obj, struct wait_queue_entry *entry - if (!timer->manual) timer->signaled = 0; - } - -+static struct fast_sync *timer_get_fast_sync( struct object *obj ) -+{ -+ struct timer *timer = (struct timer *)obj; -+ -+ if (!timer->fast_sync) -+ { -+ enum fast_sync_type type = timer->manual ? FAST_SYNC_MANUAL_SERVER : FAST_SYNC_AUTO_SERVER; -+ timer->fast_sync = fast_create_event( type, timer->signaled ); -+ } -+ if (timer->fast_sync) grab_object( timer->fast_sync ); -+ return timer->fast_sync; -+} -+ - static void timer_destroy( struct object *obj ) - { - struct timer *timer = (struct timer *)obj; -@@ -223,6 +241,7 @@ static void timer_destroy( struct object *obj ) - - if (timer->timeout) remove_timeout_user( timer->timeout ); - if (timer->thread) release_object( timer->thread ); -+ if (timer->fast_sync) release_object( timer->fast_sync ); - } - - /* create a timer */ --- -2.46.0 - - diff --git a/0007-ntsync/0018-server-create-fast-synchronization-objects-for.patch b/0007-ntsync/0018-server-create-fast-synchronization-objects-for.patch deleted file mode 100644 index d22714f..0000000 --- a/0007-ntsync/0018-server-create-fast-synchronization-objects-for.patch +++ /dev/null @@ -1,224 +0,0 @@ -From: Elizabeth Figura -Date: Mon, 8 Mar 2021 17:40:57 -0600 -Subject: [PATCH 18/32] server: Create fast synchronization objects for - fd-based objects. - ---- - server/change.c | 2 +- - server/device.c | 2 +- - server/fd.c | 27 ++++++++++++++++++++++++++- - server/file.c | 2 +- - server/file.h | 1 + - server/mailslot.c | 4 ++-- - server/named_pipe.c | 6 +++--- - server/serial.c | 2 +- - server/sock.c | 2 +- - 9 files changed, 37 insertions(+), 11 deletions(-) - -diff --git a/server/change.c b/server/change.c -index d687deeb21b..d90257800a9 100644 ---- a/server/change.c -+++ b/server/change.c -@@ -124,7 +124,7 @@ static const struct object_ops dir_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ default_fd_get_fast_sync, /* get_fast_sync */ - dir_close_handle, /* close_handle */ - dir_destroy /* destroy */ - }; -diff --git a/server/device.c b/server/device.c -index e718263ebb5..698fee63f03 100644 ---- a/server/device.c -+++ b/server/device.c -@@ -232,7 +232,7 @@ static const struct object_ops device_file_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - device_file_get_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ default_fd_get_fast_sync, /* get_fast_sync */ - device_file_close_handle, /* close_handle */ - device_file_destroy /* destroy */ - }; -diff --git a/server/fd.c b/server/fd.c -index 4c0d054c673..511fc54efb2 100644 ---- a/server/fd.c -+++ b/server/fd.c -@@ -156,6 +156,7 @@ struct fd - struct completion *completion; /* completion object attached to this fd */ - apc_param_t comp_key; /* completion key to set in completion events */ - unsigned int comp_flags; /* completion flags */ -+ struct fast_sync *fast_sync; /* fast synchronization object */ - }; - - static void fd_dump( struct object *obj, int verbose ); -@@ -1569,6 +1570,7 @@ static void fd_destroy( struct object *obj ) - if (fd->unix_fd != -1) close( fd->unix_fd ); - free( fd->unix_name ); - } -+ if (fd->fast_sync) release_object( fd->fast_sync ); - } - - /* check if the desired access is possible without violating */ -@@ -1687,6 +1689,7 @@ static struct fd *alloc_fd_object(void) - fd->poll_index = -1; - fd->completion = NULL; - fd->comp_flags = 0; -+ fd->fast_sync = NULL; - init_async_queue( &fd->read_q ); - init_async_queue( &fd->write_q ); - init_async_queue( &fd->wait_q ); -@@ -1727,6 +1730,7 @@ struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *use - fd->poll_index = -1; - fd->completion = NULL; - fd->comp_flags = 0; -+ fd->fast_sync = NULL; - fd->no_fd_status = STATUS_BAD_DEVICE_TYPE; - init_async_queue( &fd->read_q ); - init_async_queue( &fd->write_q ); -@@ -2143,7 +2147,15 @@ void set_fd_signaled( struct fd *fd, int signaled ) - { - if (fd->comp_flags & FILE_SKIP_SET_EVENT_ON_HANDLE) return; - fd->signaled = signaled; -- if (signaled) wake_up( fd->user, 0 ); -+ if (signaled) -+ { -+ wake_up( fd->user, 0 ); -+ fast_set_event( fd->fast_sync ); -+ } -+ else -+ { -+ fast_reset_event( fd->fast_sync ); -+ } - } - - /* check if events are pending and if yes return which one(s) */ -@@ -2169,6 +2181,19 @@ int default_fd_signaled( struct object *obj, struct wait_queue_entry *entry ) - return ret; - } - -+struct fast_sync *default_fd_get_fast_sync( struct object *obj ) -+{ -+ struct fd *fd = get_obj_fd( obj ); -+ struct fast_sync *ret; -+ -+ if (!fd->fast_sync) -+ fd->fast_sync = fast_create_event( FAST_SYNC_MANUAL_SERVER, fd->signaled ); -+ ret = fd->fast_sync; -+ release_object( fd ); -+ if (ret) grab_object( ret ); -+ return ret; -+} -+ - int default_fd_get_poll_events( struct fd *fd ) - { - int events = 0; -diff --git a/server/file.c b/server/file.c -index 50d1cc21188..1191303c35a 100644 ---- a/server/file.c -+++ b/server/file.c -@@ -106,7 +106,7 @@ static const struct object_ops file_ops = - NULL, /* unlink_name */ - file_open_file, /* open_file */ - file_get_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ default_fd_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - file_destroy /* destroy */ - }; -diff --git a/server/file.h b/server/file.h -index 006b5a8e324..a8a584af3dd 100644 ---- a/server/file.h -+++ b/server/file.h -@@ -108,6 +108,7 @@ extern char *dup_fd_name( struct fd *root, const char *name ) __WINE_DEALLOC(fre - extern void get_nt_name( struct fd *fd, struct unicode_str *name ); - - extern int default_fd_signaled( struct object *obj, struct wait_queue_entry *entry ); -+extern struct fast_sync *default_fd_get_fast_sync( struct object *obj ); - extern int default_fd_get_poll_events( struct fd *fd ); - extern void default_poll_event( struct fd *fd, int event ); - extern void fd_cancel_async( struct fd *fd, struct async *async ); -diff --git a/server/mailslot.c b/server/mailslot.c -index 40dfc8ad9d3..9ccf6dd1ea8 100644 ---- a/server/mailslot.c -+++ b/server/mailslot.c -@@ -93,7 +93,7 @@ static const struct object_ops mailslot_ops = - default_unlink_name, /* unlink_name */ - mailslot_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ default_fd_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - mailslot_destroy /* destroy */ - }; -@@ -252,7 +252,7 @@ static const struct object_ops mailslot_device_file_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ default_fd_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - mailslot_device_file_destroy /* destroy */ - }; -diff --git a/server/named_pipe.c b/server/named_pipe.c -index 5eb57f320a2..00d6c69f22d 100644 ---- a/server/named_pipe.c -+++ b/server/named_pipe.c -@@ -180,7 +180,7 @@ static const struct object_ops pipe_server_ops = - NULL, /* unlink_name */ - pipe_server_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ default_fd_get_fast_sync, /* get_fast_sync */ - async_close_obj_handle, /* close_handle */ - pipe_server_destroy /* destroy */ - }; -@@ -225,7 +225,7 @@ static const struct object_ops pipe_client_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ default_fd_get_fast_sync, /* get_fast_sync */ - async_close_obj_handle, /* close_handle */ - pipe_end_destroy /* destroy */ - }; -@@ -305,7 +305,7 @@ static const struct object_ops named_pipe_device_file_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ default_fd_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - named_pipe_device_file_destroy /* destroy */ - }; -diff --git a/server/serial.c b/server/serial.c -index 9a6837c3bff..46cadbef7fd 100644 ---- a/server/serial.c -+++ b/server/serial.c -@@ -103,7 +103,7 @@ static const struct object_ops serial_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ default_fd_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - serial_destroy /* destroy */ - }; -diff --git a/server/sock.c b/server/sock.c -index 11a6f3465fc..a7e4cb0fb0d 100644 ---- a/server/sock.c -+++ b/server/sock.c -@@ -465,7 +465,7 @@ static const struct object_ops sock_ops = - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ -- no_get_fast_sync, /* get_fast_sync */ -+ default_fd_get_fast_sync, /* get_fast_sync */ - sock_close_handle, /* close_handle */ - sock_destroy /* destroy */ - }; --- -2.46.0 - - diff --git a/0007-ntsync/0019-server-add-a-request-to-retrieve-the-fast.patch b/0007-ntsync/0019-server-add-a-request-to-retrieve-the-fast.patch deleted file mode 100644 index fb22ab2..0000000 --- a/0007-ntsync/0019-server-add-a-request-to-retrieve-the-fast.patch +++ /dev/null @@ -1,61 +0,0 @@ -From: Elizabeth Figura -Date: Mon, 8 Mar 2021 17:46:06 -0600 -Subject: [PATCH 19/32] server: Add a request to retrieve the fast - synchronization device. - ---- - server/fast_sync.c | 17 +++++++++++++++++ - server/protocol.def | 7 +++++++ - 2 files changed, 24 insertions(+) - -diff --git a/server/fast_sync.c b/server/fast_sync.c -index 4b9fc8a8f76..926aff0e132 100644 ---- a/server/fast_sync.c -+++ b/server/fast_sync.c -@@ -29,6 +29,8 @@ - #include "winternl.h" - - #include "file.h" -+#include "handle.h" -+#include "request.h" - #include "thread.h" - - #ifdef HAVE_LINUX_NTSYNC_H -@@ -368,3 +370,18 @@ void fast_abandon_mutex( thread_id_t tid, struct fast_sync *fast_sync ) - } - - #endif -+ -+DECL_HANDLER(get_linux_sync_device) -+{ -+#ifdef HAVE_LINUX_NTSYNC_H -+ struct linux_device *device; -+ -+ if ((device = get_linux_device())) -+ { -+ reply->handle = alloc_handle( current->process, device, 0, 0 ); -+ release_object( device ); -+ } -+#else -+ set_error( STATUS_NOT_IMPLEMENTED ); -+#endif -+} -diff --git a/server/protocol.def b/server/protocol.def -index 1f718bf80b8..bce8e15d038 100644 ---- a/server/protocol.def -+++ b/server/protocol.def -@@ -3965,3 +3965,10 @@ enum fast_sync_type - FAST_SYNC_MANUAL_SERVER, - FAST_SYNC_QUEUE, - }; -+ -+ -+/* Obtain a handle to the fast synchronization device object */ -+@REQ(get_linux_sync_device) -+@REPLY -+ obj_handle_t handle; /* handle to the device */ -+@END --- -2.46.0 - - diff --git a/0007-ntsync/0020-server-add-a-request-to-retrieve-the-fast.patch b/0007-ntsync/0020-server-add-a-request-to-retrieve-the-fast.patch deleted file mode 100644 index e249eb3..0000000 --- a/0007-ntsync/0020-server-add-a-request-to-retrieve-the-fast.patch +++ /dev/null @@ -1,63 +0,0 @@ -From: Elizabeth Figura -Date: Mon, 8 Mar 2021 17:55:00 -0600 -Subject: [PATCH 20/32] server: Add a request to retrieve the fast - synchronization object from a handle. - ---- - server/fast_sync.c | 23 +++++++++++++++++++++++ - server/protocol.def | 10 ++++++++++ - 2 files changed, 33 insertions(+) - -diff --git a/server/fast_sync.c b/server/fast_sync.c -index 926aff0e132..12cd8eb3c6e 100644 ---- a/server/fast_sync.c -+++ b/server/fast_sync.c -@@ -385,3 +385,26 @@ DECL_HANDLER(get_linux_sync_device) - set_error( STATUS_NOT_IMPLEMENTED ); - #endif - } -+ -+DECL_HANDLER(get_linux_sync_obj) -+{ -+#ifdef HAVE_LINUX_NTSYNC_H -+ struct object *obj; -+ -+ if ((obj = get_handle_obj( current->process, req->handle, 0, NULL ))) -+ { -+ struct fast_sync *fast_sync; -+ -+ if ((fast_sync = obj->ops->get_fast_sync( obj ))) -+ { -+ reply->handle = alloc_handle( current->process, fast_sync, 0, 0 ); -+ reply->type = fast_sync->type; -+ reply->access = get_handle_access( current->process, req->handle ); -+ release_object( fast_sync ); -+ } -+ release_object( obj ); -+ } -+#else -+ set_error( STATUS_NOT_IMPLEMENTED ); -+#endif -+} -diff --git a/server/protocol.def b/server/protocol.def -index bce8e15d038..eaf97f387dc 100644 ---- a/server/protocol.def -+++ b/server/protocol.def -@@ -3972,3 +3972,13 @@ enum fast_sync_type - @REPLY - obj_handle_t handle; /* handle to the device */ - @END -+ -+ -+/* Get the fast synchronization object associated with the given handle */ -+@REQ(get_linux_sync_obj) -+ obj_handle_t handle; /* handle to the object */ -+@REPLY -+ obj_handle_t handle; /* handle to the fast synchronization object */ -+ int type; /* object type */ -+ unsigned int access; /* handle access rights */ -+@END --- -2.46.0 - - diff --git a/0007-ntsync/0021-server-introduce-fastselectqueue-and.patch b/0007-ntsync/0021-server-introduce-fastselectqueue-and.patch deleted file mode 100644 index 6a3bc1b..0000000 --- a/0007-ntsync/0021-server-introduce-fastselectqueue-and.patch +++ /dev/null @@ -1,124 +0,0 @@ -From: Elizabeth Figura -Date: Tue, 9 Mar 2021 11:32:25 -0600 -Subject: [PATCH 21/32] server: Introduce fast_select_queue and - fast_unselect_queue requests. - ---- - server/protocol.def | 13 ++++++++++ - server/queue.c | 60 +++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 73 insertions(+) - -diff --git a/server/protocol.def b/server/protocol.def -index eaf97f387dc..af2a7f9b67c 100644 ---- a/server/protocol.def -+++ b/server/protocol.def -@@ -3982,3 +3982,16 @@ enum fast_sync_type - int type; /* object type */ - unsigned int access; /* handle access rights */ - @END -+ -+ -+/* Begin a client-side wait on a message queue */ -+@REQ(fast_select_queue) -+ obj_handle_t handle; /* handle to the queue */ -+@END -+ -+ -+/* End a client-side wait on a message queue */ -+@REQ(fast_unselect_queue) -+ obj_handle_t handle; /* handle to the queue */ -+ int signaled; /* was the queue signaled? */ -+@END -diff --git a/server/queue.c b/server/queue.c -index 9857c9d85a4..bb529d24e64 100644 ---- a/server/queue.c -+++ b/server/queue.c -@@ -134,6 +134,7 @@ struct msg_queue - int keystate_lock; /* owns an input keystate lock */ - const queue_shm_t *shared; /* queue in session shared memory */ - struct fast_sync *fast_sync; /* fast synchronization object */ -+ int in_fast_wait; /* are we in a client-side wait? */ - }; - - struct hotkey -@@ -317,6 +318,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ - queue->last_get_msg = current_time; - queue->keystate_lock = 0; - queue->fast_sync = NULL; -+ queue->in_fast_wait = 0; - list_init( &queue->send_result ); - list_init( &queue->callback_result ); - list_init( &queue->pending_timers ); -@@ -1230,6 +1232,10 @@ static int is_queue_hung( struct msg_queue *queue ) - if (get_wait_queue_thread(entry)->queue == queue) - return 0; /* thread is waiting on queue -> not hung */ - } -+ -+ if (queue->in_fast_wait) -+ return 0; /* thread is waiting on queue in absentia -> not hung */ -+ - return 1; - } - -@@ -4212,3 +4218,57 @@ DECL_HANDLER(set_keyboard_repeat) - - release_object( desktop ); - } -+ -+DECL_HANDLER(fast_select_queue) -+{ -+ struct msg_queue *queue; -+ -+ if (!(queue = (struct msg_queue *)get_handle_obj( current->process, req->handle, -+ SYNCHRONIZE, &msg_queue_ops ))) -+ return; -+ -+ /* a thread can only wait on its own queue */ -+ if (current->queue != queue || queue->in_fast_wait) -+ { -+ set_error( STATUS_ACCESS_DENIED ); -+ } -+ else -+ { -+ const queue_shm_t *queue_shm = queue->shared; -+ if (current->process->idle_event && !(queue_shm->wake_mask & QS_SMRESULT)) -+ set_event( current->process->idle_event ); -+ -+ if (queue->fd) -+ set_fd_events( queue->fd, POLLIN ); -+ -+ queue->in_fast_wait = 1; -+ } -+ -+ release_object( queue ); -+} -+ -+DECL_HANDLER(fast_unselect_queue) -+{ -+ struct msg_queue *queue; -+ -+ if (!(queue = (struct msg_queue *)get_handle_obj( current->process, req->handle, -+ SYNCHRONIZE, &msg_queue_ops ))) -+ return; -+ -+ if (current->queue != queue || !queue->in_fast_wait) -+ { -+ set_error( STATUS_ACCESS_DENIED ); -+ } -+ else -+ { -+ if (queue->fd) -+ set_fd_events( queue->fd, 0 ); -+ -+ if (req->signaled) -+ msg_queue_satisfied( &queue->obj, NULL ); -+ -+ queue->in_fast_wait = 0; -+ } -+ -+ release_object( queue ); -+} --- -2.46.0 - - diff --git a/0007-ntsync/0022-server-allow-creating-an-event-object-for-client-side.patch b/0007-ntsync/0022-server-allow-creating-an-event-object-for-client-side.patch deleted file mode 100644 index 8bafe88..0000000 --- a/0007-ntsync/0022-server-allow-creating-an-event-object-for-client-side.patch +++ /dev/null @@ -1,108 +0,0 @@ -From: Elizabeth Figura -Date: Thu, 21 Apr 2022 16:11:14 -0500 -Subject: [PATCH 22/32] server: Allow creating an event object for client-side - user APC signaling. - ---- - server/protocol.def | 7 +++++++ - server/thread.c | 21 +++++++++++++++++++++ - server/thread.h | 1 + - 3 files changed, 29 insertions(+) - -diff --git a/server/protocol.def b/server/protocol.def -index af2a7f9b67c..56be06de6d2 100644 ---- a/server/protocol.def -+++ b/server/protocol.def -@@ -3995,3 +3995,10 @@ enum fast_sync_type - obj_handle_t handle; /* handle to the queue */ - int signaled; /* was the queue signaled? */ - @END -+ -+ -+/* Get an event handle to be used for thread alerts with fast synchronization */ -+@REQ(get_fast_alert_event) -+@REPLY -+ obj_handle_t handle; /* handle to the event */ -+@END -diff --git a/server/thread.c b/server/thread.c -index 03369346c6a..075a40a759f 100644 ---- a/server/thread.c -+++ b/server/thread.c -@@ -251,6 +251,7 @@ static inline void init_thread_structure( struct thread *thread ) - thread->desc = NULL; - thread->desc_len = 0; - thread->fast_sync = NULL; -+ thread->fast_alert_event = NULL; - - thread->creation_time = current_time; - thread->exit_time = 0; -@@ -466,6 +467,7 @@ static void destroy_thread( struct object *obj ) - if (thread->id) free_ptid( thread->id ); - if (thread->token) release_object( thread->token ); - if (thread->fast_sync) release_object( thread->fast_sync ); -+ if (thread->fast_alert_event) release_object( thread->fast_alert_event ); - } - - /* dump a thread on stdout for debugging purposes */ -@@ -1163,8 +1165,13 @@ static int queue_apc( struct process *process, struct thread *thread, struct thr - grab_object( apc ); - list_add_tail( queue, &apc->entry ); - if (!list_prev( queue, &apc->entry )) /* first one */ -+ { - wake_thread( thread ); - -+ if (apc->call.type == APC_USER && thread->fast_alert_event) -+ set_event( thread->fast_alert_event ); -+ } -+ - return 1; - } - -@@ -1195,6 +1202,8 @@ void thread_cancel_apc( struct thread *thread, struct object *owner, enum apc_ty - apc->executed = 1; - wake_up( &apc->obj, 0 ); - release_object( apc ); -+ if (list_empty( &thread->user_apc ) && thread->fast_alert_event) -+ reset_event( thread->fast_alert_event ); - return; - } - } -@@ -1209,6 +1218,9 @@ static struct thread_apc *thread_dequeue_apc( struct thread *thread, int system - { - apc = LIST_ENTRY( ptr, struct thread_apc, entry ); - list_remove( ptr ); -+ -+ if (list_empty( &thread->user_apc ) && thread->fast_alert_event) -+ reset_event( thread->fast_alert_event ); - } - return apc; - } -@@ -2050,3 +2062,12 @@ DECL_HANDLER(get_next_thread) - set_error( STATUS_NO_MORE_ENTRIES ); - release_object( process ); - } -+ -+DECL_HANDLER(get_fast_alert_event) -+{ -+ if (!current->fast_alert_event) -+ current->fast_alert_event = create_event( NULL, NULL, 0, 1, !list_empty( ¤t->user_apc ), NULL ); -+ -+ if (current->fast_alert_event) -+ reply->handle = alloc_handle( current->process, current->fast_alert_event, SYNCHRONIZE, 0 ); -+} -diff --git a/server/thread.h b/server/thread.h -index 7b11a548a78..9bf4b489821 100644 ---- a/server/thread.h -+++ b/server/thread.h -@@ -92,6 +92,7 @@ struct thread - data_size_t desc_len; /* thread description length in bytes */ - WCHAR *desc; /* thread description string */ - struct fast_sync *fast_sync; /* fast synchronization object */ -+ struct event *fast_alert_event; /* fast synchronization alert event */ - }; - - extern struct thread *current; --- -2.46.0 - - diff --git a/0007-ntsync/0023-ntdll-introduce-a-helper-to-wait-on-an-internal-server.patch b/0007-ntsync/0023-ntdll-introduce-a-helper-to-wait-on-an-internal-server.patch deleted file mode 100644 index 24fa616..0000000 --- a/0007-ntsync/0023-ntdll-introduce-a-helper-to-wait-on-an-internal-server.patch +++ /dev/null @@ -1,112 +0,0 @@ -From: Elizabeth Figura -Date: Mon, 8 Mar 2021 18:07:23 -0600 -Subject: [PATCH 23/32] ntdll: Introduce a helper to wait on an internal server - handle. - ---- - dlls/ntdll/unix/file.c | 2 +- - dlls/ntdll/unix/process.c | 2 +- - dlls/ntdll/unix/server.c | 17 ++++++++++++++++- - dlls/ntdll/unix/thread.c | 2 +- - dlls/ntdll/unix/unix_private.h | 3 ++- - 5 files changed, 21 insertions(+), 5 deletions(-) - -diff --git a/dlls/ntdll/unix/file.c b/dlls/ntdll/unix/file.c -index ca95dd347eb..b0299c6e874 100644 ---- a/dlls/ntdll/unix/file.c -+++ b/dlls/ntdll/unix/file.c -@@ -6440,7 +6440,7 @@ NTSTATUS WINAPI NtLockFile( HANDLE file, HANDLE event, PIO_APC_ROUTINE apc, void - } - if (handle) - { -- NtWaitForSingleObject( handle, FALSE, NULL ); -+ server_wait_for_object( handle, FALSE, NULL ); - NtClose( handle ); - } - else /* Unix lock conflict, sleep a bit and retry */ -diff --git a/dlls/ntdll/unix/process.c b/dlls/ntdll/unix/process.c -index 1815b46b0fc..12a00660c30 100644 ---- a/dlls/ntdll/unix/process.c -+++ b/dlls/ntdll/unix/process.c -@@ -920,7 +920,7 @@ NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_ - - /* wait for the new process info to be ready */ - -- NtWaitForSingleObject( process_info, FALSE, NULL ); -+ server_wait_for_object( process_info, FALSE, NULL ); - SERVER_START_REQ( get_new_process_info ) - { - req->info = wine_server_obj_handle( process_info ); -diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c -index f3ffd99c3fc..bcbd889953e 100644 ---- a/dlls/ntdll/unix/server.c -+++ b/dlls/ntdll/unix/server.c -@@ -789,6 +789,21 @@ unsigned int server_wait( const select_op_t *select_op, data_size_t size, UINT f - } - - -+/* helper function to perform a server-side wait on an internal handle without -+ * using the fast synchronization path */ -+unsigned int server_wait_for_object( HANDLE handle, BOOL alertable, const LARGE_INTEGER *timeout ) -+{ -+ select_op_t select_op; -+ UINT flags = SELECT_INTERRUPTIBLE; -+ -+ if (alertable) flags |= SELECT_ALERTABLE; -+ -+ select_op.wait.op = SELECT_WAIT; -+ select_op.wait.handles[0] = wine_server_obj_handle( handle ); -+ return server_wait( &select_op, offsetof( select_op_t, wait.handles[1] ), flags, timeout ); -+} -+ -+ - /*********************************************************************** - * NtContinue (NTDLL.@) - */ -@@ -850,7 +865,7 @@ unsigned int server_queue_process_apc( HANDLE process, const apc_call_t *call, a - } - else - { -- NtWaitForSingleObject( handle, FALSE, NULL ); -+ server_wait_for_object( handle, FALSE, NULL ); - - SERVER_START_REQ( get_apc_result ) - { -diff --git a/dlls/ntdll/unix/thread.c b/dlls/ntdll/unix/thread.c -index 3d151e7b2b8..68339d77884 100644 ---- a/dlls/ntdll/unix/thread.c -+++ b/dlls/ntdll/unix/thread.c -@@ -1798,7 +1798,7 @@ NTSTATUS get_thread_context( HANDLE handle, void *context, BOOL *self, USHORT ma - - if (ret == STATUS_PENDING) - { -- NtWaitForSingleObject( context_handle, FALSE, NULL ); -+ server_wait_for_object( context_handle, FALSE, NULL ); - - SERVER_START_REQ( get_thread_context ) - { -diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h -index ee5630e76f1..74eccd46c29 100644 ---- a/dlls/ntdll/unix/unix_private.h -+++ b/dlls/ntdll/unix/unix_private.h -@@ -211,6 +211,7 @@ extern unsigned int server_select( const select_op_t *select_op, data_size_t siz - timeout_t abs_timeout, context_t *context, user_apc_t *user_apc ); - extern unsigned int server_wait( const select_op_t *select_op, data_size_t size, UINT flags, - const LARGE_INTEGER *timeout ); -+extern unsigned int server_wait_for_object( HANDLE handle, BOOL alertable, const LARGE_INTEGER *timeout ); - extern unsigned int server_queue_process_apc( HANDLE process, const apc_call_t *call, - apc_result_t *result ); - extern int server_get_unix_fd( HANDLE handle, unsigned int wanted_access, int *unix_fd, -@@ -447,7 +448,7 @@ static inline async_data_t server_async( HANDLE handle, struct async_fileio *use - - static inline NTSTATUS wait_async( HANDLE handle, BOOL alertable ) - { -- return NtWaitForSingleObject( handle, alertable, NULL ); -+ return server_wait_for_object( handle, alertable, NULL ); - } - - static inline BOOL in_wow64_call(void) --- -2.46.0 - - diff --git a/0007-ntsync/0024-ntdll-add-some-traces-to-synchronization-methods.patch b/0007-ntsync/0024-ntdll-add-some-traces-to-synchronization-methods.patch deleted file mode 100644 index d4146d8..0000000 --- a/0007-ntsync/0024-ntdll-add-some-traces-to-synchronization-methods.patch +++ /dev/null @@ -1,232 +0,0 @@ -From: Elizabeth Figura -Date: Tue, 9 Mar 2021 12:08:29 -0600 -Subject: [PATCH 24/32] ntdll: Add some traces to synchronization methods. - -Normally we can rely on +server for these, but with fast synchronization we'll -be skipping the server. ---- - dlls/ntdll/unix/sync.c | 59 ++++++++++++++++++++++++++++++++++++++++-- - 1 file changed, 57 insertions(+), 2 deletions(-) - -diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c -index 21e66f01875..8c024fc7496 100644 ---- a/dlls/ntdll/unix/sync.c -+++ b/dlls/ntdll/unix/sync.c -@@ -74,9 +74,11 @@ HANDLE keyed_event = 0; - static const char *debugstr_timeout( const LARGE_INTEGER *timeout ) - { - if (!timeout) return "(infinite)"; -- return wine_dbgstr_longlong( timeout->QuadPart ); -+ return wine_dbg_sprintf( "%lld.%07ld", (long long)(timeout->QuadPart / TICKSPERSEC), -+ (long)(timeout->QuadPart % TICKSPERSEC) ); - } - -+ - /* return a monotonic time counter, in Win32 ticks */ - static inline ULONGLONG monotonic_counter(void) - { -@@ -315,6 +317,9 @@ NTSTATUS WINAPI NtCreateSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJ - data_size_t len; - struct object_attributes *objattr; - -+ TRACE( "access %#x, name %s, initial %d, max %d\n", (int)access, -+ attr ? debugstr_us(attr->ObjectName) : "(null)", (int)initial, (int)max ); -+ - *handle = 0; - if (max <= 0 || initial < 0 || initial > max) return STATUS_INVALID_PARAMETER; - if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; -@@ -342,6 +347,8 @@ NTSTATUS WINAPI NtOpenSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJEC - { - unsigned int ret; - -+ TRACE( "access %#x, name %s\n", (int)access, attr ? debugstr_us(attr->ObjectName) : "(null)" ); -+ - *handle = 0; - if ((ret = validate_open_object_attributes( attr ))) return ret; - -@@ -401,6 +408,8 @@ NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, ULONG *previous - { - unsigned int ret; - -+ TRACE( "handle %p, count %u, prev_count %p\n", handle, (int)count, previous ); -+ - SERVER_START_REQ( release_semaphore ) - { - req->handle = wine_server_obj_handle( handle ); -@@ -425,6 +434,9 @@ NTSTATUS WINAPI NtCreateEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ - data_size_t len; - struct object_attributes *objattr; - -+ TRACE( "access %#x, name %s, type %u, state %u\n", (int)access, -+ attr ? debugstr_us(attr->ObjectName) : "(null)", type, state ); -+ - *handle = 0; - if (type != NotificationEvent && type != SynchronizationEvent) return STATUS_INVALID_PARAMETER; - if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; -@@ -452,6 +464,8 @@ NTSTATUS WINAPI NtOpenEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_AT - { - unsigned int ret; - -+ TRACE( "access %#x, name %s\n", (int)access, attr ? debugstr_us(attr->ObjectName) : "(null)" ); -+ - *handle = 0; - if ((ret = validate_open_object_attributes( attr ))) return ret; - -@@ -477,6 +491,8 @@ NTSTATUS WINAPI NtSetEvent( HANDLE handle, LONG *prev_state ) - { - unsigned int ret; - -+ TRACE( "handle %p, prev_state %p\n", handle, prev_state ); -+ - SERVER_START_REQ( event_op ) - { - req->handle = wine_server_obj_handle( handle ); -@@ -496,6 +512,8 @@ NTSTATUS WINAPI NtResetEvent( HANDLE handle, LONG *prev_state ) - { - unsigned int ret; - -+ TRACE( "handle %p, prev_state %p\n", handle, prev_state ); -+ - SERVER_START_REQ( event_op ) - { - req->handle = wine_server_obj_handle( handle ); -@@ -525,6 +543,8 @@ NTSTATUS WINAPI NtPulseEvent( HANDLE handle, LONG *prev_state ) - { - unsigned int ret; - -+ TRACE( "handle %p, prev_state %p\n", handle, prev_state ); -+ - SERVER_START_REQ( event_op ) - { - req->handle = wine_server_obj_handle( handle ); -@@ -581,6 +601,9 @@ NTSTATUS WINAPI NtCreateMutant( HANDLE *handle, ACCESS_MASK access, const OBJECT - data_size_t len; - struct object_attributes *objattr; - -+ TRACE( "access %#x, name %s, owned %u\n", (int)access, -+ attr ? debugstr_us(attr->ObjectName) : "(null)", owned ); -+ - *handle = 0; - if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; - -@@ -606,6 +629,8 @@ NTSTATUS WINAPI NtOpenMutant( HANDLE *handle, ACCESS_MASK access, const OBJECT_A - { - unsigned int ret; - -+ TRACE( "access %#x, name %s\n", (int)access, attr ? debugstr_us(attr->ObjectName) : "(null)" ); -+ - *handle = 0; - if ((ret = validate_open_object_attributes( attr ))) return ret; - -@@ -631,6 +656,8 @@ NTSTATUS WINAPI NtReleaseMutant( HANDLE handle, LONG *prev_count ) - { - unsigned int ret; - -+ TRACE( "handle %p, prev_count %p\n", handle, prev_count ); -+ - SERVER_START_REQ( release_mutex ) - { - req->handle = wine_server_obj_handle( handle ); -@@ -1430,6 +1457,9 @@ NTSTATUS WINAPI NtCreateTimer( HANDLE *handle, ACCESS_MASK access, const OBJECT_ - data_size_t len; - struct object_attributes *objattr; - -+ TRACE( "access %#x, name %s, type %u\n", (int)access, -+ attr ? debugstr_us(attr->ObjectName) : "(null)", type ); -+ - *handle = 0; - if (type != NotificationTimer && type != SynchronizationTimer) return STATUS_INVALID_PARAMETER; - if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; -@@ -1457,6 +1487,8 @@ NTSTATUS WINAPI NtOpenTimer( HANDLE *handle, ACCESS_MASK access, const OBJECT_AT - { - unsigned int ret; - -+ TRACE( "access %#x, name %s\n", (int)access, attr ? debugstr_us(attr->ObjectName) : "(null)" ); -+ - *handle = 0; - if ((ret = validate_open_object_attributes( attr ))) return ret; - -@@ -1510,6 +1542,8 @@ NTSTATUS WINAPI NtCancelTimer( HANDLE handle, BOOLEAN *state ) - { - unsigned int ret; - -+ TRACE( "handle %p, state %p\n", handle, state ); -+ - SERVER_START_REQ( cancel_timer ) - { - req->handle = wine_server_obj_handle( handle ); -@@ -1578,13 +1612,23 @@ NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles, BO - { - select_op_t select_op; - UINT i, flags = SELECT_INTERRUPTIBLE; -+ unsigned int ret; - - if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1; - -+ if (TRACE_ON(sync)) -+ { -+ TRACE( "wait_any %u, alertable %u, handles {%p", wait_any, alertable, handles[0] ); -+ for (i = 1; i < count; i++) TRACE( ", %p", handles[i] ); -+ TRACE( "}, timeout %s\n", debugstr_timeout(timeout) ); -+ } -+ - if (alertable) flags |= SELECT_ALERTABLE; - select_op.wait.op = wait_any ? SELECT_WAIT : SELECT_WAIT_ALL; - for (i = 0; i < count; i++) select_op.wait.handles[i] = wine_server_obj_handle( handles[i] ); -- return server_wait( &select_op, offsetof( select_op_t, wait.handles[count] ), flags, timeout ); -+ ret = server_wait( &select_op, offsetof( select_op_t, wait.handles[count] ), flags, timeout ); -+ TRACE( "-> %#x\n", ret ); -+ return ret; - } - - -@@ -1606,6 +1650,8 @@ NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE signal, HANDLE wait, - select_op_t select_op; - UINT flags = SELECT_INTERRUPTIBLE; - -+ TRACE( "signal %p, wait %p, alertable %u, timeout %s\n", signal, wait, alertable, debugstr_timeout(timeout) ); -+ - if (!signal) return STATUS_INVALID_HANDLE; - - if (alertable) flags |= SELECT_ALERTABLE; -@@ -1840,6 +1886,9 @@ NTSTATUS WINAPI NtCreateKeyedEvent( HANDLE *handle, ACCESS_MASK access, - data_size_t len; - struct object_attributes *objattr; - -+ TRACE( "access %#x, name %s, flags %#x\n", (int)access, -+ attr ? debugstr_us(attr->ObjectName) : "(null)", (int)flags ); -+ - *handle = 0; - if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; - -@@ -1864,6 +1913,8 @@ NTSTATUS WINAPI NtOpenKeyedEvent( HANDLE *handle, ACCESS_MASK access, const OBJE - { - unsigned int ret; - -+ TRACE( "access %#x, name %s\n", (int)access, attr ? debugstr_us(attr->ObjectName) : "(null)" ); -+ - *handle = 0; - if ((ret = validate_open_object_attributes( attr ))) return ret; - -@@ -1890,6 +1941,8 @@ NTSTATUS WINAPI NtWaitForKeyedEvent( HANDLE handle, const void *key, - select_op_t select_op; - UINT flags = SELECT_INTERRUPTIBLE; - -+ TRACE( "handle %p, key %p, alertable %u, timeout %s\n", handle, key, alertable, debugstr_timeout(timeout) ); -+ - if (!handle) handle = keyed_event; - if ((ULONG_PTR)key & 1) return STATUS_INVALID_PARAMETER_1; - if (alertable) flags |= SELECT_ALERTABLE; -@@ -1909,6 +1962,8 @@ NTSTATUS WINAPI NtReleaseKeyedEvent( HANDLE handle, const void *key, - select_op_t select_op; - UINT flags = SELECT_INTERRUPTIBLE; - -+ TRACE( "handle %p, key %p, alertable %u, timeout %s\n", handle, key, alertable, debugstr_timeout(timeout) ); -+ - if (!handle) handle = keyed_event; - if ((ULONG_PTR)key & 1) return STATUS_INVALID_PARAMETER_1; - if (alertable) flags |= SELECT_ALERTABLE; --- -2.46.0 - - diff --git a/0007-ntsync/0025-ntdll-use-fast-synchronization-objects.patch b/0007-ntsync/0025-ntdll-use-fast-synchronization-objects.patch deleted file mode 100644 index bea74a6..0000000 --- a/0007-ntsync/0025-ntdll-use-fast-synchronization-objects.patch +++ /dev/null @@ -1,904 +0,0 @@ -From: Elizabeth Figura -Date: Tue, 6 Apr 2021 15:37:02 -0500 -Subject: [PATCH 25/32] ntdll: Use fast synchronization objects. - ---- - dlls/ntdll/unix/sync.c | 761 +++++++++++++++++++++++++++++++++ - dlls/ntdll/unix/unix_private.h | 2 + - 2 files changed, 763 insertions(+) - -diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c -index 8c024fc7496..40d4dc327a7 100644 ---- a/dlls/ntdll/unix/sync.c -+++ b/dlls/ntdll/unix/sync.c -@@ -30,9 +30,11 @@ - #include - #include - #include -+#include - #include - #include - #include -+#include - #include - #ifdef HAVE_SYS_SYSCALL_H - #include -@@ -48,6 +50,7 @@ - #endif - #include - #include -+#include - #include - #include - #include -@@ -57,6 +60,9 @@ - #ifdef HAVE_KQUEUE - # include - #endif -+#ifdef HAVE_LINUX_NTSYNC_H -+# include -+#endif - - #include "ntstatus.h" - #define WIN32_NO_STATUS -@@ -307,6 +313,718 @@ static unsigned int validate_open_object_attributes( const OBJECT_ATTRIBUTES *at - } - - -+#ifdef HAVE_LINUX_NTSYNC_H -+ -+static int get_linux_sync_device(void) -+{ -+ static LONG fast_sync_fd = -2; -+ -+ if (fast_sync_fd == -2) -+ { -+ HANDLE device; -+ int fd, needs_close; -+ NTSTATUS ret; -+ -+ SERVER_START_REQ( get_linux_sync_device ) -+ { -+ if (!(ret = wine_server_call( req ))) device = wine_server_ptr_handle( reply->handle ); -+ } -+ SERVER_END_REQ; -+ -+ if (!ret) -+ { -+ if (!server_get_unix_fd( device, 0, &fd, &needs_close, NULL, NULL )) -+ { -+ if (InterlockedCompareExchange( &fast_sync_fd, fd, -2 ) != -2) -+ { -+ /* someone beat us to it */ -+ if (needs_close) close( fd ); -+ NtClose( device ); -+ } -+ /* otherwise don't close the device */ -+ } -+ else -+ { -+ InterlockedCompareExchange( &fast_sync_fd, -1, -2 ); -+ NtClose( device ); -+ } -+ } -+ else -+ { -+ InterlockedCompareExchange( &fast_sync_fd, -1, -2 ); -+ } -+ } -+ return fast_sync_fd; -+} -+ -+/* It's possible for synchronization primitives to remain alive even after being -+ * closed, because a thread is still waiting on them. It's rare in practice, and -+ * documented as being undefined behaviour by Microsoft, but it works, and some -+ * applications rely on it. This means we need to refcount handles, and defer -+ * deleting them on the server side until the refcount reaches zero. We do this -+ * by having each client process hold a handle to the fast synchronization -+ * object, as well as a private refcount. When the client refcount reaches zero, -+ * it closes the handle; when all handles are closed, the server deletes the -+ * fast synchronization object. -+ * -+ * We want lookup of objects from the cache to be very fast; ideally, it should -+ * be lock-free. We achieve this by using atomic modifications to "refcount", -+ * and guaranteeing that all other fields are valid and correct *as long as* -+ * refcount is nonzero, and we store the entire structure in memory which will -+ * never be freed. -+ * -+ * This means that acquiring the object can't use a simple atomic increment; it -+ * has to use a compare-and-swap loop to ensure that it doesn't try to increment -+ * an object with a zero refcount. That's still leagues better than a real lock, -+ * though, and release can be a single atomic decrement. -+ * -+ * It also means that threads modifying the cache need to take a lock, to -+ * prevent other threads from writing to it concurrently. -+ * -+ * It's possible for an object currently in use (by a waiter) to be closed and -+ * the same handle immediately reallocated to a different object. This should be -+ * a very rare situation, and in that case we simply don't cache the handle. -+ */ -+struct fast_sync_cache_entry -+{ -+ LONG refcount; -+ int fd; -+ enum fast_sync_type type; -+ unsigned int access; -+ BOOL closed; -+ /* handle to the underlying fast sync object, stored as obj_handle_t to save -+ * space */ -+ obj_handle_t handle; -+}; -+ -+ -+static void release_fast_sync_obj( struct fast_sync_cache_entry *cache ) -+{ -+ /* save the handle and fd now; as soon as the refcount hits 0 we cannot -+ * access the cache anymore */ -+ HANDLE handle = wine_server_ptr_handle( cache->handle ); -+ int fd = cache->fd; -+ LONG refcount = InterlockedDecrement( &cache->refcount ); -+ -+ assert( refcount >= 0 ); -+ -+ if (!refcount) -+ { -+ NTSTATUS ret = NtClose( handle ); -+ assert( !ret ); -+ close( fd ); -+ } -+} -+ -+ -+static BOOL fast_sync_types_match( enum fast_sync_type a, enum fast_sync_type b ) -+{ -+ if (a == b) return TRUE; -+ if (a == FAST_SYNC_AUTO_EVENT && b == FAST_SYNC_MANUAL_EVENT) return TRUE; -+ if (b == FAST_SYNC_AUTO_EVENT && a == FAST_SYNC_MANUAL_EVENT) return TRUE; -+ return FALSE; -+} -+ -+ -+/* returns a pointer to a cache entry; if the object could not be cached, -+ * returns "stack_cache" instead, which should be allocated on stack */ -+static NTSTATUS get_fast_sync_obj( HANDLE handle, enum fast_sync_type desired_type, ACCESS_MASK desired_access, -+ struct fast_sync_cache_entry *stack_cache, -+ struct fast_sync_cache_entry **ret_cache ) -+{ -+ struct fast_sync_cache_entry *cache = stack_cache; -+ int needs_close; -+ NTSTATUS ret; -+ -+ *ret_cache = stack_cache; -+ -+ SERVER_START_REQ( get_linux_sync_obj ) -+ { -+ req->handle = wine_server_obj_handle( handle ); -+ if (!(ret = wine_server_call( req ))) -+ { -+ cache->handle = reply->handle; -+ cache->access = reply->access; -+ cache->type = reply->type; -+ cache->refcount = 1; -+ cache->closed = FALSE; -+ } -+ } -+ SERVER_END_REQ; -+ -+ if (ret) return ret; -+ -+ if ((ret = server_get_unix_fd( wine_server_ptr_handle( cache->handle ), -+ 0, &cache->fd, &needs_close, NULL, NULL ))) -+ return ret; -+ -+ if (desired_type && !fast_sync_types_match( cache->type, desired_type )) -+ { -+ release_fast_sync_obj( cache ); -+ return STATUS_OBJECT_TYPE_MISMATCH; -+ } -+ -+ if ((cache->access & desired_access) != desired_access) -+ { -+ release_fast_sync_obj( cache ); -+ return STATUS_ACCESS_DENIED; -+ } -+ -+ return STATUS_SUCCESS; -+} -+ -+ -+static NTSTATUS linux_release_semaphore_obj( int obj, ULONG count, ULONG *prev_count ) -+{ -+ NTSTATUS ret; -+ -+ ret = ioctl( obj, NTSYNC_IOC_SEM_POST, &count ); -+ if (ret < 0) -+ { -+ if (errno == EOVERFLOW) -+ return STATUS_SEMAPHORE_LIMIT_EXCEEDED; -+ else -+ return errno_to_status( errno ); -+ } -+ if (prev_count) *prev_count = count; -+ return STATUS_SUCCESS; -+} -+ -+ -+static NTSTATUS fast_release_semaphore( HANDLE handle, ULONG count, ULONG *prev_count ) -+{ -+ struct fast_sync_cache_entry stack_cache, *cache; -+ NTSTATUS ret; -+ -+ if ((ret = get_fast_sync_obj( handle, FAST_SYNC_SEMAPHORE, -+ SEMAPHORE_MODIFY_STATE, &stack_cache, &cache ))) -+ return ret; -+ -+ ret = linux_release_semaphore_obj( cache->fd, count, prev_count ); -+ -+ release_fast_sync_obj( cache ); -+ return ret; -+} -+ -+ -+static NTSTATUS linux_query_semaphore_obj( int obj, SEMAPHORE_BASIC_INFORMATION *info ) -+{ -+ struct ntsync_sem_args args = {0}; -+ NTSTATUS ret; -+ -+ ret = ioctl( obj, NTSYNC_IOC_SEM_READ, &args ); -+ if (ret < 0) -+ return errno_to_status( errno ); -+ info->CurrentCount = args.count; -+ info->MaximumCount = args.max; -+ return STATUS_SUCCESS; -+} -+ -+ -+static NTSTATUS fast_query_semaphore( HANDLE handle, SEMAPHORE_BASIC_INFORMATION *info ) -+{ -+ struct fast_sync_cache_entry stack_cache, *cache; -+ NTSTATUS ret; -+ -+ if ((ret = get_fast_sync_obj( handle, FAST_SYNC_SEMAPHORE, -+ SEMAPHORE_QUERY_STATE, &stack_cache, &cache ))) -+ return ret; -+ -+ ret = linux_query_semaphore_obj( cache->fd, info ); -+ -+ release_fast_sync_obj( cache ); -+ return ret; -+} -+ -+ -+static NTSTATUS linux_set_event_obj( int obj, LONG *prev_state ) -+{ -+ NTSTATUS ret; -+ __u32 prev; -+ -+ ret = ioctl( obj, NTSYNC_IOC_EVENT_SET, &prev ); -+ if (ret < 0) -+ return errno_to_status( errno ); -+ if (prev_state) *prev_state = prev; -+ return STATUS_SUCCESS; -+} -+ -+ -+static NTSTATUS fast_set_event( HANDLE handle, LONG *prev_state ) -+{ -+ struct fast_sync_cache_entry stack_cache, *cache; -+ NTSTATUS ret; -+ -+ if ((ret = get_fast_sync_obj( handle, FAST_SYNC_AUTO_EVENT, -+ EVENT_MODIFY_STATE, &stack_cache, &cache ))) -+ return ret; -+ -+ ret = linux_set_event_obj( cache->fd, prev_state ); -+ -+ release_fast_sync_obj( cache ); -+ return ret; -+} -+ -+ -+static NTSTATUS linux_reset_event_obj( int obj, LONG *prev_state ) -+{ -+ NTSTATUS ret; -+ __u32 prev; -+ -+ ret = ioctl( obj, NTSYNC_IOC_EVENT_RESET, &prev ); -+ if (ret < 0) -+ return errno_to_status( errno ); -+ if (prev_state) *prev_state = prev; -+ return STATUS_SUCCESS; -+} -+ -+ -+static NTSTATUS fast_reset_event( HANDLE handle, LONG *prev_state ) -+{ -+ struct fast_sync_cache_entry stack_cache, *cache; -+ NTSTATUS ret; -+ -+ if ((ret = get_fast_sync_obj( handle, FAST_SYNC_AUTO_EVENT, -+ EVENT_MODIFY_STATE, &stack_cache, &cache ))) -+ return ret; -+ -+ ret = linux_reset_event_obj( cache->fd, prev_state ); -+ -+ release_fast_sync_obj( cache ); -+ return ret; -+} -+ -+ -+static NTSTATUS linux_pulse_event_obj( int obj, LONG *prev_state ) -+{ -+ NTSTATUS ret; -+ __u32 prev; -+ -+ ret = ioctl( obj, NTSYNC_IOC_EVENT_PULSE, &prev ); -+ if (ret < 0) -+ return errno_to_status( errno ); -+ if (prev_state) *prev_state = prev; -+ return STATUS_SUCCESS; -+} -+ -+ -+static NTSTATUS fast_pulse_event( HANDLE handle, LONG *prev_state ) -+{ -+ struct fast_sync_cache_entry stack_cache, *cache; -+ NTSTATUS ret; -+ -+ if ((ret = get_fast_sync_obj( handle, FAST_SYNC_AUTO_EVENT, -+ EVENT_MODIFY_STATE, &stack_cache, &cache ))) -+ return ret; -+ -+ ret = linux_pulse_event_obj( cache->fd, prev_state ); -+ -+ release_fast_sync_obj( cache ); -+ return ret; -+} -+ -+ -+static NTSTATUS linux_query_event_obj( int obj, enum fast_sync_type type, EVENT_BASIC_INFORMATION *info ) -+{ -+ struct ntsync_event_args args = {0}; -+ NTSTATUS ret; -+ -+ ret = ioctl( obj, NTSYNC_IOC_EVENT_READ, &args ); -+ if (ret < 0) -+ return errno_to_status( errno ); -+ info->EventType = (type == FAST_SYNC_AUTO_EVENT) ? SynchronizationEvent : NotificationEvent; -+ info->EventState = args.signaled; -+ return STATUS_SUCCESS; -+} -+ -+ -+static NTSTATUS fast_query_event( HANDLE handle, EVENT_BASIC_INFORMATION *info ) -+{ -+ struct fast_sync_cache_entry stack_cache, *cache; -+ NTSTATUS ret; -+ -+ if ((ret = get_fast_sync_obj( handle, FAST_SYNC_AUTO_EVENT, -+ EVENT_QUERY_STATE, &stack_cache, &cache ))) -+ return ret; -+ -+ ret = linux_query_event_obj( cache->fd, cache->type, info ); -+ -+ release_fast_sync_obj( cache ); -+ return ret; -+} -+ -+ -+static NTSTATUS linux_release_mutex_obj( int obj, LONG *prev_count ) -+{ -+ struct ntsync_mutex_args args = {0}; -+ NTSTATUS ret; -+ -+ args.owner = GetCurrentThreadId(); -+ ret = ioctl( obj, NTSYNC_IOC_MUTEX_UNLOCK, &args ); -+ -+ if (ret < 0) -+ { -+ if (errno == EOVERFLOW) -+ return STATUS_MUTANT_LIMIT_EXCEEDED; -+ else if (errno == EPERM) -+ return STATUS_MUTANT_NOT_OWNED; -+ else -+ return errno_to_status( errno ); -+ } -+ if (prev_count) *prev_count = 1 - args.count; -+ return STATUS_SUCCESS; -+} -+ -+ -+static NTSTATUS fast_release_mutex( HANDLE handle, LONG *prev_count ) -+{ -+ struct fast_sync_cache_entry stack_cache, *cache; -+ NTSTATUS ret; -+ -+ if ((ret = get_fast_sync_obj( handle, FAST_SYNC_MUTEX, 0, &stack_cache, &cache ))) -+ return ret; -+ -+ ret = linux_release_mutex_obj( cache->fd, prev_count ); -+ -+ release_fast_sync_obj( cache ); -+ return ret; -+} -+ -+ -+static NTSTATUS linux_query_mutex_obj( int obj, MUTANT_BASIC_INFORMATION *info ) -+{ -+ struct ntsync_mutex_args args = {0}; -+ NTSTATUS ret; -+ -+ ret = ioctl( obj, NTSYNC_IOC_MUTEX_READ, &args ); -+ -+ if (ret < 0) -+ { -+ if (errno == EOWNERDEAD) -+ { -+ info->AbandonedState = TRUE; -+ info->OwnedByCaller = FALSE; -+ info->CurrentCount = 1; -+ return STATUS_SUCCESS; -+ } -+ else -+ return errno_to_status( errno ); -+ } -+ info->AbandonedState = FALSE; -+ info->OwnedByCaller = (args.owner == GetCurrentThreadId()); -+ info->CurrentCount = 1 - args.count; -+ return STATUS_SUCCESS; -+} -+ -+ -+static NTSTATUS fast_query_mutex( HANDLE handle, MUTANT_BASIC_INFORMATION *info ) -+{ -+ struct fast_sync_cache_entry stack_cache, *cache; -+ NTSTATUS ret; -+ -+ if ((ret = get_fast_sync_obj( handle, FAST_SYNC_MUTEX, MUTANT_QUERY_STATE, -+ &stack_cache, &cache ))) -+ return ret; -+ -+ ret = linux_query_mutex_obj( cache->fd, info ); -+ -+ release_fast_sync_obj( cache ); -+ return ret; -+} -+ -+static void select_queue( HANDLE queue ) -+{ -+ SERVER_START_REQ( fast_select_queue ) -+ { -+ req->handle = wine_server_obj_handle( queue ); -+ wine_server_call( req ); -+ } -+ SERVER_END_REQ; -+} -+ -+static void unselect_queue( HANDLE queue, BOOL signaled ) -+{ -+ SERVER_START_REQ( fast_unselect_queue ) -+ { -+ req->handle = wine_server_obj_handle( queue ); -+ req->signaled = signaled; -+ wine_server_call( req ); -+ } -+ SERVER_END_REQ; -+} -+ -+static int get_fast_alert_obj(void) -+{ -+ struct ntdll_thread_data *data = ntdll_get_thread_data(); -+ struct fast_sync_cache_entry stack_cache, *cache; -+ HANDLE alert_handle; -+ unsigned int ret; -+ -+ if (!data->fast_alert_obj) -+ { -+ SERVER_START_REQ( get_fast_alert_event ) -+ { -+ if ((ret = wine_server_call( req ))) -+ ERR( "failed to get fast alert event, status %#x\n", ret ); -+ alert_handle = wine_server_ptr_handle( reply->handle ); -+ } -+ SERVER_END_REQ; -+ -+ if ((ret = get_fast_sync_obj( alert_handle, 0, SYNCHRONIZE, &stack_cache, &cache ))) -+ ERR( "failed to get fast alert obj, status %#x\n", ret ); -+ data->fast_alert_obj = cache->fd; -+ /* Set the fd to -1 so release_fast_sync_obj() won't close it. -+ * Manhandling the cache entry here is fine since we're the only thread -+ * that can access our own alert event. */ -+ cache->fd = -1; -+ release_fast_sync_obj( cache ); -+ NtClose( alert_handle ); -+ } -+ -+ return data->fast_alert_obj; -+} -+ -+static NTSTATUS linux_wait_objs( int device, const DWORD count, const int *objs, -+ BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) -+{ -+ struct ntsync_wait_args args = {0}; -+ unsigned long request; -+ struct timespec now; -+ int ret; -+ -+ if (!timeout || timeout->QuadPart == TIMEOUT_INFINITE) -+ { -+ args.timeout = ~(__u64)0; -+ } -+ else if (timeout->QuadPart <= 0) -+ { -+ clock_gettime( CLOCK_MONOTONIC, &now ); -+ args.timeout = (now.tv_sec * NSECPERSEC) + now.tv_nsec + (-timeout->QuadPart * 100); -+ } -+ else -+ { -+ args.timeout = (timeout->QuadPart * 100) - (SECS_1601_TO_1970 * NSECPERSEC); -+ args.flags |= NTSYNC_WAIT_REALTIME; -+ } -+ -+ args.objs = (uintptr_t)objs; -+ args.count = count; -+ args.owner = GetCurrentThreadId(); -+ args.index = ~0u; -+ -+ if (alertable) -+ args.alert = get_fast_alert_obj(); -+ -+ if (wait_any || count == 1) -+ request = NTSYNC_IOC_WAIT_ANY; -+ else -+ request = NTSYNC_IOC_WAIT_ALL; -+ -+ do -+ { -+ ret = ioctl( device, request, &args ); -+ } while (ret < 0 && errno == EINTR); -+ -+ if (!ret) -+ { -+ if (args.index == count) -+ { -+ static const LARGE_INTEGER timeout; -+ -+ ret = server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, &timeout ); -+ assert( ret == STATUS_USER_APC ); -+ return ret; -+ } -+ -+ return wait_any ? args.index : 0; -+ } -+ else if (errno == EOWNERDEAD) -+ return STATUS_ABANDONED + (wait_any ? args.index : 0); -+ else if (errno == ETIMEDOUT) -+ return STATUS_TIMEOUT; -+ else -+ return errno_to_status( errno ); -+} -+ -+static NTSTATUS fast_wait( DWORD count, const HANDLE *handles, BOOLEAN wait_any, -+ BOOLEAN alertable, const LARGE_INTEGER *timeout ) -+{ -+ struct fast_sync_cache_entry stack_cache[64], *cache[64]; -+ int device, objs[64]; -+ HANDLE queue = NULL; -+ NTSTATUS ret; -+ DWORD i, j; -+ -+ if ((device = get_linux_sync_device()) < 0) -+ return STATUS_NOT_IMPLEMENTED; -+ -+ for (i = 0; i < count; ++i) -+ { -+ if ((ret = get_fast_sync_obj( handles[i], 0, SYNCHRONIZE, &stack_cache[i], &cache[i] ))) -+ { -+ for (j = 0; j < i; ++j) -+ release_fast_sync_obj( cache[j] ); -+ return ret; -+ } -+ if (cache[i]->type == FAST_SYNC_QUEUE) -+ queue = handles[i]; -+ -+ objs[i] = cache[i]->fd; -+ } -+ -+ if (queue) select_queue( queue ); -+ -+ ret = linux_wait_objs( device, count, objs, wait_any, alertable, timeout ); -+ -+ if (queue) unselect_queue( queue, handles[ret] == queue ); -+ -+ for (i = 0; i < count; ++i) -+ release_fast_sync_obj( cache[i] ); -+ -+ return ret; -+} -+ -+static NTSTATUS fast_signal_and_wait( HANDLE signal, HANDLE wait, -+ BOOLEAN alertable, const LARGE_INTEGER *timeout ) -+{ -+ struct fast_sync_cache_entry signal_stack_cache, *signal_cache; -+ struct fast_sync_cache_entry wait_stack_cache, *wait_cache; -+ HANDLE queue = NULL; -+ NTSTATUS ret; -+ int device; -+ -+ if ((device = get_linux_sync_device()) < 0) -+ return STATUS_NOT_IMPLEMENTED; -+ -+ if ((ret = get_fast_sync_obj( signal, 0, 0, &signal_stack_cache, &signal_cache ))) -+ return ret; -+ -+ switch (signal_cache->type) -+ { -+ case FAST_SYNC_SEMAPHORE: -+ if (!(signal_cache->access & SEMAPHORE_MODIFY_STATE)) -+ { -+ release_fast_sync_obj( signal_cache ); -+ return STATUS_ACCESS_DENIED; -+ } -+ break; -+ -+ case FAST_SYNC_AUTO_EVENT: -+ case FAST_SYNC_MANUAL_EVENT: -+ if (!(signal_cache->access & EVENT_MODIFY_STATE)) -+ { -+ release_fast_sync_obj( signal_cache ); -+ return STATUS_ACCESS_DENIED; -+ } -+ break; -+ -+ case FAST_SYNC_MUTEX: -+ break; -+ -+ default: -+ /* can't be signaled */ -+ release_fast_sync_obj( signal_cache ); -+ return STATUS_OBJECT_TYPE_MISMATCH; -+ } -+ -+ if ((ret = get_fast_sync_obj( wait, 0, SYNCHRONIZE, &wait_stack_cache, &wait_cache ))) -+ { -+ release_fast_sync_obj( signal_cache ); -+ return ret; -+ } -+ -+ if (wait_cache->type == FAST_SYNC_QUEUE) -+ queue = wait; -+ -+ switch (signal_cache->type) -+ { -+ case FAST_SYNC_SEMAPHORE: -+ ret = linux_release_semaphore_obj( signal_cache->fd, 1, NULL ); -+ break; -+ -+ case FAST_SYNC_AUTO_EVENT: -+ case FAST_SYNC_MANUAL_EVENT: -+ ret = linux_set_event_obj( signal_cache->fd, NULL ); -+ break; -+ -+ case FAST_SYNC_MUTEX: -+ ret = linux_release_mutex_obj( signal_cache->fd, NULL ); -+ break; -+ -+ default: -+ assert( 0 ); -+ break; -+ } -+ -+ if (!ret) -+ { -+ if (queue) select_queue( queue ); -+ ret = linux_wait_objs( device, 1, &wait_cache->fd, TRUE, alertable, timeout ); -+ if (queue) unselect_queue( queue, !ret ); -+ } -+ -+ release_fast_sync_obj( signal_cache ); -+ release_fast_sync_obj( wait_cache ); -+ return ret; -+} -+ -+#else -+ -+static NTSTATUS fast_release_semaphore( HANDLE handle, ULONG count, ULONG *prev_count ) -+{ -+ return STATUS_NOT_IMPLEMENTED; -+} -+ -+static NTSTATUS fast_query_semaphore( HANDLE handle, SEMAPHORE_BASIC_INFORMATION *info ) -+{ -+ return STATUS_NOT_IMPLEMENTED; -+} -+ -+static NTSTATUS fast_set_event( HANDLE handle, LONG *prev_state ) -+{ -+ return STATUS_NOT_IMPLEMENTED; -+} -+ -+static NTSTATUS fast_reset_event( HANDLE handle, LONG *prev_state ) -+{ -+ return STATUS_NOT_IMPLEMENTED; -+} -+ -+static NTSTATUS fast_pulse_event( HANDLE handle, LONG *prev_state ) -+{ -+ return STATUS_NOT_IMPLEMENTED; -+} -+ -+static NTSTATUS fast_query_event( HANDLE handle, EVENT_BASIC_INFORMATION *info ) -+{ -+ return STATUS_NOT_IMPLEMENTED; -+} -+ -+static NTSTATUS fast_release_mutex( HANDLE handle, LONG *prev_count ) -+{ -+ return STATUS_NOT_IMPLEMENTED; -+} -+ -+static NTSTATUS fast_query_mutex( HANDLE handle, MUTANT_BASIC_INFORMATION *info ) -+{ -+ return STATUS_NOT_IMPLEMENTED; -+} -+ -+static NTSTATUS fast_wait( DWORD count, const HANDLE *handles, BOOLEAN wait_any, -+ BOOLEAN alertable, const LARGE_INTEGER *timeout ) -+{ -+ return STATUS_NOT_IMPLEMENTED; -+} -+ -+static NTSTATUS fast_signal_and_wait( HANDLE signal, HANDLE wait, -+ BOOLEAN alertable, const LARGE_INTEGER *timeout ) -+{ -+ return STATUS_NOT_IMPLEMENTED; -+} -+ -+#endif -+ -+ - /****************************************************************************** - * NtCreateSemaphore (NTDLL.@) - */ -@@ -386,6 +1104,12 @@ NTSTATUS WINAPI NtQuerySemaphore( HANDLE handle, SEMAPHORE_INFORMATION_CLASS cla - - if (len != sizeof(SEMAPHORE_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH; - -+ if ((ret = fast_query_semaphore( handle, out )) != STATUS_NOT_IMPLEMENTED) -+ { -+ if (!ret && ret_len) *ret_len = sizeof(SEMAPHORE_BASIC_INFORMATION); -+ return ret; -+ } -+ - SERVER_START_REQ( query_semaphore ) - { - req->handle = wine_server_obj_handle( handle ); -@@ -410,6 +1134,9 @@ NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, ULONG *previous - - TRACE( "handle %p, count %u, prev_count %p\n", handle, (int)count, previous ); - -+ if ((ret = fast_release_semaphore( handle, count, previous )) != STATUS_NOT_IMPLEMENTED) -+ return ret; -+ - SERVER_START_REQ( release_semaphore ) - { - req->handle = wine_server_obj_handle( handle ); -@@ -493,6 +1220,9 @@ NTSTATUS WINAPI NtSetEvent( HANDLE handle, LONG *prev_state ) - - TRACE( "handle %p, prev_state %p\n", handle, prev_state ); - -+ if ((ret = fast_set_event( handle, prev_state )) != STATUS_NOT_IMPLEMENTED) -+ return ret; -+ - SERVER_START_REQ( event_op ) - { - req->handle = wine_server_obj_handle( handle ); -@@ -514,6 +1244,9 @@ NTSTATUS WINAPI NtResetEvent( HANDLE handle, LONG *prev_state ) - - TRACE( "handle %p, prev_state %p\n", handle, prev_state ); - -+ if ((ret = fast_reset_event( handle, prev_state )) != STATUS_NOT_IMPLEMENTED) -+ return ret; -+ - SERVER_START_REQ( event_op ) - { - req->handle = wine_server_obj_handle( handle ); -@@ -545,6 +1278,9 @@ NTSTATUS WINAPI NtPulseEvent( HANDLE handle, LONG *prev_state ) - - TRACE( "handle %p, prev_state %p\n", handle, prev_state ); - -+ if ((ret = fast_pulse_event( handle, prev_state )) != STATUS_NOT_IMPLEMENTED) -+ return ret; -+ - SERVER_START_REQ( event_op ) - { - req->handle = wine_server_obj_handle( handle ); -@@ -576,6 +1312,12 @@ NTSTATUS WINAPI NtQueryEvent( HANDLE handle, EVENT_INFORMATION_CLASS class, - - if (len != sizeof(EVENT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH; - -+ if ((ret = fast_query_event( handle, out )) != STATUS_NOT_IMPLEMENTED) -+ { -+ if (!ret && ret_len) *ret_len = sizeof(EVENT_BASIC_INFORMATION); -+ return ret; -+ } -+ - SERVER_START_REQ( query_event ) - { - req->handle = wine_server_obj_handle( handle ); -@@ -658,6 +1400,9 @@ NTSTATUS WINAPI NtReleaseMutant( HANDLE handle, LONG *prev_count ) - - TRACE( "handle %p, prev_count %p\n", handle, prev_count ); - -+ if ((ret = fast_release_mutex( handle, prev_count )) != STATUS_NOT_IMPLEMENTED) -+ return ret; -+ - SERVER_START_REQ( release_mutex ) - { - req->handle = wine_server_obj_handle( handle ); -@@ -688,6 +1433,12 @@ NTSTATUS WINAPI NtQueryMutant( HANDLE handle, MUTANT_INFORMATION_CLASS class, - - if (len != sizeof(MUTANT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH; - -+ if ((ret = fast_query_mutex( handle, out )) != STATUS_NOT_IMPLEMENTED) -+ { -+ if (!ret && ret_len) *ret_len = sizeof(MUTANT_BASIC_INFORMATION); -+ return ret; -+ } -+ - SERVER_START_REQ( query_mutex ) - { - req->handle = wine_server_obj_handle( handle ); -@@ -1623,6 +2374,12 @@ NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles, BO - TRACE( "}, timeout %s\n", debugstr_timeout(timeout) ); - } - -+ if ((ret = fast_wait( count, handles, wait_any, alertable, timeout )) != STATUS_NOT_IMPLEMENTED) -+ { -+ TRACE( "-> %#x\n", ret ); -+ return ret; -+ } -+ - if (alertable) flags |= SELECT_ALERTABLE; - select_op.wait.op = wait_any ? SELECT_WAIT : SELECT_WAIT_ALL; - for (i = 0; i < count; i++) select_op.wait.handles[i] = wine_server_obj_handle( handles[i] ); -@@ -1649,11 +2406,15 @@ NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE signal, HANDLE wait, - { - select_op_t select_op; - UINT flags = SELECT_INTERRUPTIBLE; -+ NTSTATUS ret; - - TRACE( "signal %p, wait %p, alertable %u, timeout %s\n", signal, wait, alertable, debugstr_timeout(timeout) ); - - if (!signal) return STATUS_INVALID_HANDLE; - -+ if ((ret = fast_signal_and_wait( signal, wait, alertable, timeout )) != STATUS_NOT_IMPLEMENTED) -+ return ret; -+ - if (alertable) flags |= SELECT_ALERTABLE; - select_op.signal_and_wait.op = SELECT_SIGNAL_AND_WAIT; - select_op.signal_and_wait.wait = wine_server_obj_handle( wait ); -diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h -index 74eccd46c29..fdaa92df1e4 100644 ---- a/dlls/ntdll/unix/unix_private.h -+++ b/dlls/ntdll/unix/unix_private.h -@@ -111,6 +111,7 @@ struct ntdll_thread_data - PRTL_THREAD_START_ROUTINE start; /* thread entry point */ - void *param; /* thread entry point parameter */ - void *jmp_buf; /* setjmp buffer for exception handling */ -+ int fast_alert_obj; /* fd for the fast alert event */ - }; - - C_ASSERT( sizeof(struct ntdll_thread_data) <= sizeof(((TEB *)0)->GdiTebBatch) ); -@@ -383,6 +384,7 @@ extern void call_raise_user_exception_dispatcher(void); - #define IMAGE_DLLCHARACTERISTICS_PREFER_NATIVE 0x0010 /* Wine extension */ - - #define TICKSPERSEC 10000000 -+#define NSECPERSEC 1000000000 - #define SECS_1601_TO_1970 ((369 * 365 + 89) * (ULONGLONG)86400) - - static inline ULONGLONG ticks_from_time_t( time_t time ) --- -2.46.0 - - diff --git a/0007-ntsync/0026-ntdll-use-serverwaitforobject-when-waiting-on.patch b/0007-ntsync/0026-ntdll-use-serverwaitforobject-when-waiting-on.patch deleted file mode 100644 index 08a6f94..0000000 --- a/0007-ntsync/0026-ntdll-use-serverwaitforobject-when-waiting-on.patch +++ /dev/null @@ -1,35 +0,0 @@ -From: Elizabeth Figura -Date: Tue, 20 Apr 2021 17:55:59 -0500 -Subject: [PATCH 26/32] ntdll: Use server_wait_for_object() when waiting on - only the queue object. - ---- - dlls/ntdll/unix/sync.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c -index 40d4dc327a7..fa2a8d84c3d 100644 ---- a/dlls/ntdll/unix/sync.c -+++ b/dlls/ntdll/unix/sync.c -@@ -872,6 +872,17 @@ static NTSTATUS fast_wait( DWORD count, const HANDLE *handles, BOOLEAN wait_any, - objs[i] = cache[i]->fd; - } - -+ /* It's common to wait on the message queue alone. Some applications wait -+ * on it in fast paths, with a zero timeout. Since we take two server calls -+ * instead of one when going through fast_wait_objs(), and since we only -+ * need to go through that path if we're waiting on other objects, just -+ * delegate to the server if we're only waiting on the message queue. */ -+ if (count == 1 && queue) -+ { -+ release_fast_sync_obj( cache[0] ); -+ return server_wait_for_object( handles[0], alertable, timeout ); -+ } -+ - if (queue) select_queue( queue ); - - ret = linux_wait_objs( device, count, objs, wait_any, alertable, timeout ); --- -2.46.0 - - diff --git a/0007-ntsync/0027-ntdll-cache-fast-synchronization-objects.patch b/0007-ntsync/0027-ntdll-cache-fast-synchronization-objects.patch deleted file mode 100644 index ba17ab2..0000000 --- a/0007-ntsync/0027-ntdll-cache-fast-synchronization-objects.patch +++ /dev/null @@ -1,340 +0,0 @@ -From: Elizabeth Figura -Date: Fri, 12 Mar 2021 15:04:17 -0600 -Subject: [PATCH 27/32] ntdll: Cache fast synchronization objects. - ---- - dlls/ntdll/unix/server.c | 11 +- - dlls/ntdll/unix/sync.c | 195 +++++++++++++++++++++++++++++++-- - dlls/ntdll/unix/unix_private.h | 4 + - 3 files changed, 198 insertions(+), 12 deletions(-) - -diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c -index bcbd889953e..6e0ecf92247 100644 ---- a/dlls/ntdll/unix/server.c -+++ b/dlls/ntdll/unix/server.c -@@ -103,7 +103,7 @@ sigset_t server_block_set; /* signals to block during server calls */ - static int fd_socket = -1; /* socket to exchange file descriptors with the server */ - static int initial_cwd = -1; - static pid_t server_pid; --static pthread_mutex_t fd_cache_mutex = PTHREAD_MUTEX_INITIALIZER; -+pthread_mutex_t fd_cache_mutex = PTHREAD_MUTEX_INITIALIZER; - - /* atomically exchange a 64-bit value */ - static inline LONG64 interlocked_xchg64( LONG64 *dest, LONG64 val ) -@@ -1768,12 +1768,17 @@ NTSTATUS WINAPI NtDuplicateObject( HANDLE source_process, HANDLE source, HANDLE - return result.dup_handle.status; - } - -+ /* hold fd_cache_mutex to prevent the fd from being added again between the -+ * call to remove_fd_from_cache and close_handle */ - server_enter_uninterrupted_section( &fd_cache_mutex, &sigset ); - - /* always remove the cached fd; if the server request fails we'll just - * retrieve it again */ - if (options & DUPLICATE_CLOSE_SOURCE) -+ { - fd = remove_fd_from_cache( source ); -+ close_fast_sync_obj( source ); -+ } - - SERVER_START_REQ( dup_handle ) - { -@@ -1839,12 +1844,16 @@ NTSTATUS WINAPI NtClose( HANDLE handle ) - if (HandleToLong( handle ) >= ~5 && HandleToLong( handle ) <= ~0) - return STATUS_SUCCESS; - -+ /* hold fd_cache_mutex to prevent the fd from being added again between the -+ * call to remove_fd_from_cache and close_handle */ - server_enter_uninterrupted_section( &fd_cache_mutex, &sigset ); - - /* always remove the cached fd; if the server request fails we'll just - * retrieve it again */ - fd = remove_fd_from_cache( handle ); - -+ close_fast_sync_obj( handle ); -+ - SERVER_START_REQ( close_handle ) - { - req->handle = wine_server_obj_handle( handle ); -diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c -index fa2a8d84c3d..235944e3809 100644 ---- a/dlls/ntdll/unix/sync.c -+++ b/dlls/ntdll/unix/sync.c -@@ -367,6 +367,12 @@ static int get_linux_sync_device(void) - * it closes the handle; when all handles are closed, the server deletes the - * fast synchronization object. - * -+ * We also need this for signal-and-wait. The signal and wait operations aren't -+ * atomic, but we can't perform the signal and then return STATUS_INVALID_HANDLE -+ * for the wait—we need to either do both operations or neither. That means we -+ * need to grab references to both objects, and prevent them from being -+ * destroyed before we're done with them. -+ * - * We want lookup of objects from the cache to be very fast; ideally, it should - * be lock-free. We achieve this by using atomic modifications to "refcount", - * and guaranteeing that all other fields are valid and correct *as long as* -@@ -410,13 +416,140 @@ static void release_fast_sync_obj( struct fast_sync_cache_entry *cache ) - - if (!refcount) - { -- NTSTATUS ret = NtClose( handle ); -+ NTSTATUS ret; -+ -+ /* we can't call NtClose here as we may be inside fd_cache_mutex */ -+ SERVER_START_REQ( close_handle ) -+ { -+ req->handle = wine_server_obj_handle( handle ); -+ ret = wine_server_call( req ); -+ } -+ SERVER_END_REQ; -+ - assert( !ret ); - close( fd ); - } - } - - -+#define FAST_SYNC_CACHE_BLOCK_SIZE (65536 / sizeof(struct fast_sync_cache_entry)) -+#define FAST_SYNC_CACHE_ENTRIES 128 -+ -+static struct fast_sync_cache_entry *fast_sync_cache[FAST_SYNC_CACHE_ENTRIES]; -+static struct fast_sync_cache_entry fast_sync_cache_initial_block[FAST_SYNC_CACHE_BLOCK_SIZE]; -+ -+static inline unsigned int fast_sync_handle_to_index( HANDLE handle, unsigned int *entry ) -+{ -+ unsigned int idx = (wine_server_obj_handle(handle) >> 2) - 1; -+ *entry = idx / FAST_SYNC_CACHE_BLOCK_SIZE; -+ return idx % FAST_SYNC_CACHE_BLOCK_SIZE; -+} -+ -+ -+static struct fast_sync_cache_entry *cache_fast_sync_obj( HANDLE handle, obj_handle_t fast_sync, int fd, -+ enum fast_sync_type type, unsigned int access ) -+{ -+ unsigned int entry, idx = fast_sync_handle_to_index( handle, &entry ); -+ struct fast_sync_cache_entry *cache; -+ sigset_t sigset; -+ int refcount; -+ -+ if (entry >= FAST_SYNC_CACHE_ENTRIES) -+ { -+ FIXME( "too many allocated handles, not caching %p\n", handle ); -+ return NULL; -+ } -+ -+ if (!fast_sync_cache[entry]) /* do we need to allocate a new block of entries? */ -+ { -+ if (!entry) fast_sync_cache[0] = fast_sync_cache_initial_block; -+ else -+ { -+ static const size_t size = FAST_SYNC_CACHE_BLOCK_SIZE * sizeof(struct fast_sync_cache_entry); -+ void *ptr = anon_mmap_alloc( size, PROT_READ | PROT_WRITE ); -+ if (ptr == MAP_FAILED) return NULL; -+ if (InterlockedCompareExchangePointer( (void **)&fast_sync_cache[entry], ptr, NULL )) -+ munmap( ptr, size ); /* someone beat us to it */ -+ } -+ } -+ -+ cache = &fast_sync_cache[entry][idx]; -+ -+ /* Hold fd_cache_mutex instead of a separate mutex, to prevent the same -+ * race between this function and NtClose. That is, prevent the object from -+ * being cached again between close_fast_sync_obj() and close_handle. */ -+ server_enter_uninterrupted_section( &fd_cache_mutex, &sigset ); -+ -+ if (InterlockedCompareExchange( &cache->refcount, 0, 0 )) -+ { -+ /* We lost the race with another thread trying to cache this object, or -+ * the handle is currently being used for another object (i.e. it was -+ * closed and then reused). We have no way of knowing which, and in the -+ * latter case we can't cache this object until the old one is -+ * completely destroyed, so always return failure. */ -+ server_leave_uninterrupted_section( &fd_cache_mutex, &sigset ); -+ return NULL; -+ } -+ -+ cache->handle = fast_sync; -+ cache->fd = fd; -+ cache->type = type; -+ cache->access = access; -+ cache->closed = FALSE; -+ /* Make sure we set the other members before the refcount; this store needs -+ * release semantics [paired with the load in get_cached_fast_sync_obj()]. -+ * Set the refcount to 2 (one for the handle, one for the caller). */ -+ refcount = InterlockedExchange( &cache->refcount, 2 ); -+ assert( !refcount ); -+ -+ server_leave_uninterrupted_section( &fd_cache_mutex, &sigset ); -+ -+ return cache; -+} -+ -+ -+/* returns the previous value */ -+static inline LONG interlocked_inc_if_nonzero( LONG *dest ) -+{ -+ LONG val, tmp; -+ for (val = *dest;; val = tmp) -+ { -+ if (!val || (tmp = InterlockedCompareExchange( dest, val + 1, val )) == val) -+ break; -+ } -+ return val; -+} -+ -+ -+static struct fast_sync_cache_entry *get_cached_fast_sync_obj( HANDLE handle ) -+{ -+ unsigned int entry, idx = fast_sync_handle_to_index( handle, &entry ); -+ struct fast_sync_cache_entry *cache; -+ -+ if (entry >= FAST_SYNC_CACHE_ENTRIES || !fast_sync_cache[entry]) -+ return NULL; -+ -+ cache = &fast_sync_cache[entry][idx]; -+ -+ /* this load needs acquire semantics [paired with the store in -+ * cache_fast_sync_obj()] */ -+ if (!interlocked_inc_if_nonzero( &cache->refcount )) -+ return NULL; -+ -+ if (cache->closed) -+ { -+ /* The object is still being used, but "handle" has been closed. The -+ * handle value might have been reused for another object in the -+ * meantime, in which case we have to report that valid object, so -+ * force the caller to check the server. */ -+ release_fast_sync_obj( cache ); -+ return NULL; -+ } -+ -+ return cache; -+} -+ -+ - static BOOL fast_sync_types_match( enum fast_sync_type a, enum fast_sync_type b ) - { - if (a == b) return TRUE; -@@ -432,32 +565,53 @@ static NTSTATUS get_fast_sync_obj( HANDLE handle, enum fast_sync_type desired_ty - struct fast_sync_cache_entry *stack_cache, - struct fast_sync_cache_entry **ret_cache ) - { -- struct fast_sync_cache_entry *cache = stack_cache; -- int needs_close; -+ struct fast_sync_cache_entry *cache; -+ obj_handle_t fast_sync_handle; -+ enum fast_sync_type type; -+ unsigned int access; -+ int fd, needs_close; - NTSTATUS ret; - -- *ret_cache = stack_cache; -+ /* try to find it in the cache already */ -+ if ((cache = get_cached_fast_sync_obj( handle ))) -+ { -+ *ret_cache = cache; -+ return STATUS_SUCCESS; -+ } - -+ /* try to retrieve it from the server */ - SERVER_START_REQ( get_linux_sync_obj ) - { - req->handle = wine_server_obj_handle( handle ); - if (!(ret = wine_server_call( req ))) - { -- cache->handle = reply->handle; -- cache->access = reply->access; -- cache->type = reply->type; -- cache->refcount = 1; -- cache->closed = FALSE; -+ fast_sync_handle = reply->handle; -+ access = reply->access; -+ type = reply->type; - } - } - SERVER_END_REQ; - - if (ret) return ret; - -- if ((ret = server_get_unix_fd( wine_server_ptr_handle( cache->handle ), -- 0, &cache->fd, &needs_close, NULL, NULL ))) -+ if ((ret = server_get_unix_fd( wine_server_ptr_handle( fast_sync_handle ), -+ 0, &fd, &needs_close, NULL, NULL ))) - return ret; - -+ cache = cache_fast_sync_obj( handle, fast_sync_handle, fd, type, access ); -+ if (!cache) -+ { -+ cache = stack_cache; -+ cache->handle = fast_sync_handle; -+ cache->fd = fd; -+ cache->type = type; -+ cache->access = access; -+ cache->closed = FALSE; -+ cache->refcount = 1; -+ } -+ -+ *ret_cache = cache; -+ - if (desired_type && !fast_sync_types_match( cache->type, desired_type )) - { - release_fast_sync_obj( cache ); -@@ -474,6 +628,21 @@ static NTSTATUS get_fast_sync_obj( HANDLE handle, enum fast_sync_type desired_ty - } - - -+/* caller must hold fd_cache_mutex */ -+void close_fast_sync_obj( HANDLE handle ) -+{ -+ struct fast_sync_cache_entry *cache = get_cached_fast_sync_obj( handle ); -+ -+ if (cache) -+ { -+ cache->closed = TRUE; -+ /* once for the reference we just grabbed, and once for the handle */ -+ release_fast_sync_obj( cache ); -+ release_fast_sync_obj( cache ); -+ } -+} -+ -+ - static NTSTATUS linux_release_semaphore_obj( int obj, ULONG count, ULONG *prev_count ) - { - NTSTATUS ret; -@@ -981,6 +1150,10 @@ static NTSTATUS fast_signal_and_wait( HANDLE signal, HANDLE wait, - - #else - -+void close_fast_sync_obj( HANDLE handle ) -+{ -+} -+ - static NTSTATUS fast_release_semaphore( HANDLE handle, ULONG count, ULONG *prev_count ) - { - return STATUS_NOT_IMPLEMENTED; -diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h -index fdaa92df1e4..5e984d10765 100644 ---- a/dlls/ntdll/unix/unix_private.h -+++ b/dlls/ntdll/unix/unix_private.h -@@ -205,6 +205,8 @@ extern NTSTATUS load_start_exe( WCHAR **image, void **module ); - extern ULONG_PTR redirect_arm64ec_rva( void *module, ULONG_PTR rva, const IMAGE_ARM64EC_METADATA *metadata ); - extern void start_server( BOOL debug ); - -+extern pthread_mutex_t fd_cache_mutex; -+ - extern unsigned int server_call_unlocked( void *req_ptr ); - extern void server_enter_uninterrupted_section( pthread_mutex_t *mutex, sigset_t *sigset ); - extern void server_leave_uninterrupted_section( pthread_mutex_t *mutex, sigset_t *sigset ); -@@ -376,6 +378,8 @@ extern NTSTATUS wow64_wine_spawnvp( void *args ); - - extern void dbg_init(void); - -+extern void close_fast_sync_obj( HANDLE handle ); -+ - extern NTSTATUS call_user_apc_dispatcher( CONTEXT *context_ptr, ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3, - PNTAPCFUNC func, NTSTATUS status ); - extern NTSTATUS call_user_exception_dispatcher( EXCEPTION_RECORD *rec, CONTEXT *context ); --- -2.46.0 - - diff --git a/0007-ntsync/0028-server-allow-disabling-fast-synchronization-support.patch b/0007-ntsync/0028-server-allow-disabling-fast-synchronization-support.patch deleted file mode 100644 index a651a9b..0000000 --- a/0007-ntsync/0028-server-allow-disabling-fast-synchronization-support.patch +++ /dev/null @@ -1,29 +0,0 @@ -From: Elizabeth Figura -Date: Sat, 13 Mar 2021 16:20:30 -0600 -Subject: [PATCH 28/32] server: Allow disabling fast synchronization support. - ---- - server/fast_sync.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/server/fast_sync.c b/server/fast_sync.c -index 12cd8eb3c6e..ce7a564926d 100644 ---- a/server/fast_sync.c -+++ b/server/fast_sync.c -@@ -126,6 +126,12 @@ static struct linux_device *get_linux_device(void) - struct linux_device *device; - int unix_fd; - -+ if (getenv( "WINE_DISABLE_FAST_SYNC" ) && atoi( getenv( "WINE_DISABLE_FAST_SYNC" ) )) -+ { -+ set_error( STATUS_NOT_IMPLEMENTED ); -+ return NULL; -+ } -+ - if (linux_device_object) - return (struct linux_device *)grab_object( linux_device_object ); - --- -2.46.0 - - diff --git a/0007-ntsync/0029-server-add-a-message-to-signal-that-fast.patch b/0007-ntsync/0029-server-add-a-message-to-signal-that-fast.patch deleted file mode 100644 index f2f631f..0000000 --- a/0007-ntsync/0029-server-add-a-message-to-signal-that-fast.patch +++ /dev/null @@ -1,25 +0,0 @@ -From: Elizabeth Figura -Date: Sun, 14 Mar 2021 11:08:02 -0500 -Subject: [PATCH 29/32] server: Add a message to signal that fast - synchronization is indeed active. - ---- - server/fast_sync.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/server/fast_sync.c b/server/fast_sync.c -index ce7a564926d..51fe32ea631 100644 ---- a/server/fast_sync.c -+++ b/server/fast_sync.c -@@ -155,6 +155,7 @@ static struct linux_device *get_linux_device(void) - return NULL; - } - -+ fprintf( stderr, "wine: using fast synchronization.\n" ); - linux_device_object = device; - return device; - } --- -2.46.0 - - diff --git a/0007-ntsync/0030-kernel32tests-zigzag-test.patch b/0007-ntsync/0030-kernel32tests-zigzag-test.patch deleted file mode 100644 index a6354e6..0000000 --- a/0007-ntsync/0030-kernel32tests-zigzag-test.patch +++ /dev/null @@ -1,109 +0,0 @@ -From: Elizabeth Figura -Date: Tue, 26 Jun 2018 18:44:44 -0500 -Subject: [PATCH 30/32] kernel32/tests: Zigzag test. - -The primary function is to check for races. The secondary function is to measure performance. ---- - dlls/kernel32/tests/sync.c | 79 ++++++++++++++++++++++++++++++++++++++ - 1 file changed, 79 insertions(+) - -diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c -index 49420e4519f..2c69073db10 100644 ---- a/dlls/kernel32/tests/sync.c -+++ b/dlls/kernel32/tests/sync.c -@@ -2904,6 +2904,84 @@ static void test_QueueUserAPC(void) - ok(apc_count == 1, "APC count %u\n", apc_count); - } - -+static int zigzag_state, zigzag_count[2], zigzag_stop; -+ -+static DWORD CALLBACK zigzag_event0(void *arg) -+{ -+ HANDLE *events = arg; -+ -+ while (!zigzag_stop) -+ { -+ WaitForSingleObject(events[0], INFINITE); -+ ResetEvent(events[0]); -+ ok(zigzag_state == 0, "got wrong state %d\n", zigzag_state); -+ zigzag_state++; -+ SetEvent(events[1]); -+ zigzag_count[0]++; -+ } -+ trace("thread 0 got done\n"); -+ return 0; -+} -+ -+static DWORD CALLBACK zigzag_event1(void *arg) -+{ -+ HANDLE *events = arg; -+ -+ while (!zigzag_stop) -+ { -+ WaitForSingleObject(events[1], INFINITE); -+ ResetEvent(events[1]); -+ ok(zigzag_state == 1, "got wrong state %d\n", zigzag_state); -+ zigzag_state--; -+ SetEvent(events[0]); -+ zigzag_count[1]++; -+ } -+ trace("thread 1 got done\n"); -+ return 0; -+} -+ -+static void test_zigzag_event(void) -+{ -+ /* The basic idea is to test SetEvent/Wait back and forth between two -+ * threads. Each thread clears their own event, sets some common data, -+ * signals the other's, then waits on their own. We make sure the common -+ * data is always in the right state. We also print performance data. */ -+ -+ HANDLE threads[2], events[2]; -+ BOOL ret; -+ -+ events[0] = CreateEventA(NULL, FALSE, FALSE, NULL); -+ events[1] = CreateEventA(NULL, FALSE, FALSE, NULL); -+ -+ threads[0] = CreateThread(NULL, 0, zigzag_event0, events, 0, NULL); -+ threads[1] = CreateThread(NULL, 0, zigzag_event1, events, 0, NULL); -+ -+ zigzag_state = 0; -+ zigzag_count[0] = zigzag_count[1] = 0; -+ zigzag_stop = 0; -+ -+ trace("starting zigzag test (events)\n"); -+ SetEvent(events[0]); -+ Sleep(2000); -+ zigzag_stop = 1; -+ ret = WaitForMultipleObjects(2, threads, FALSE, INFINITE); -+ trace("%d\n", ret); -+ ok(ret == 0 || ret == 1, "wait failed: %u\n", ret); -+ -+ ok(zigzag_count[0] == zigzag_count[1] || zigzag_count[0] == zigzag_count[1] + 1, -+ "count did not match: %d != %d\n", zigzag_count[0], zigzag_count[1]); -+ -+ /* signal the other thread to finish, if it didn't already -+ * (in theory they both would at the same time, but there's a slight race on teardown if we get -+ * thread 1 SetEvent -> thread 0 ResetEvent -> thread 0 Wait -> thread 1 exits */ -+ zigzag_state = 1-ret; -+ SetEvent(events[1-ret]); -+ ret = WaitForSingleObject(threads[1-ret], 1000); -+ ok(!ret, "wait failed: %u\n", ret); -+ -+ trace("count: %d\n", zigzag_count[0]); -+} -+ - START_TEST(sync) - { - char **argv; -@@ -2974,5 +3052,6 @@ START_TEST(sync) - test_srwlock_example(); - test_alertable_wait(); - test_apc_deadlock(); -+ test_zigzag_event(); - test_crit_section(); - } --- -2.46.0 - - diff --git a/0007-ntsync/0031-makereq.patch b/0007-ntsync/0031-makereq.patch deleted file mode 100644 index 3137549..0000000 --- a/0007-ntsync/0031-makereq.patch +++ /dev/null @@ -1,283 +0,0 @@ -From: Elizabeth Figura -Date: Tue, 30 Jan 2024 18:11:04 -0600 -Subject: [PATCH 31/32] make_req - ---- - include/wine/server_protocol.h | 97 ++++++++++++++++++++++++++++++++++ - server/request.h | 27 ++++++++++ - server/trace.c | 56 ++++++++++++++++++++ - 3 files changed, 180 insertions(+) - -diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h -index 74bf0f0c839..f12d4368519 100644 ---- a/include/wine/server_protocol.h -+++ b/include/wine/server_protocol.h -@@ -5707,6 +5707,88 @@ struct get_next_thread_reply - }; - - -+enum fast_sync_type -+{ -+ FAST_SYNC_SEMAPHORE = 1, -+ FAST_SYNC_MUTEX, -+ FAST_SYNC_AUTO_EVENT, -+ FAST_SYNC_MANUAL_EVENT, -+ FAST_SYNC_AUTO_SERVER, -+ FAST_SYNC_MANUAL_SERVER, -+ FAST_SYNC_QUEUE, -+}; -+ -+ -+ -+struct get_linux_sync_device_request -+{ -+ struct request_header __header; -+ char __pad_12[4]; -+}; -+struct get_linux_sync_device_reply -+{ -+ struct reply_header __header; -+ obj_handle_t handle; -+ char __pad_12[4]; -+}; -+ -+ -+ -+struct get_linux_sync_obj_request -+{ -+ struct request_header __header; -+ obj_handle_t handle; -+}; -+struct get_linux_sync_obj_reply -+{ -+ struct reply_header __header; -+ obj_handle_t handle; -+ int type; -+ unsigned int access; -+ char __pad_20[4]; -+}; -+ -+ -+ -+struct fast_select_queue_request -+{ -+ struct request_header __header; -+ obj_handle_t handle; -+}; -+struct fast_select_queue_reply -+{ -+ struct reply_header __header; -+}; -+ -+ -+ -+struct fast_unselect_queue_request -+{ -+ struct request_header __header; -+ obj_handle_t handle; -+ int signaled; -+ char __pad_20[4]; -+}; -+struct fast_unselect_queue_reply -+{ -+ struct reply_header __header; -+}; -+ -+ -+ -+struct get_fast_alert_event_request -+{ -+ struct request_header __header; -+ char __pad_12[4]; -+}; -+struct get_fast_alert_event_reply -+{ -+ struct reply_header __header; -+ obj_handle_t handle; -+ char __pad_12[4]; -+}; -+ -+ - - struct set_keyboard_repeat_request - { -@@ -6011,6 +6093,11 @@ enum request - REQ_resume_process, - REQ_get_next_thread, - REQ_set_keyboard_repeat, -+ REQ_get_linux_sync_device, -+ REQ_get_linux_sync_obj, -+ REQ_fast_select_queue, -+ REQ_fast_unselect_queue, -+ REQ_get_fast_alert_event, - REQ_NB_REQUESTS - }; - -@@ -6304,6 +6391,11 @@ union generic_request - struct resume_process_request resume_process_request; - struct get_next_thread_request get_next_thread_request; - struct set_keyboard_repeat_request set_keyboard_repeat_request; -+ struct get_linux_sync_device_request get_linux_sync_device_request; -+ struct get_linux_sync_obj_request get_linux_sync_obj_request; -+ struct fast_select_queue_request fast_select_queue_request; -+ struct fast_unselect_queue_request fast_unselect_queue_request; -+ struct get_fast_alert_event_request get_fast_alert_event_request; - }; - union generic_reply - { -@@ -6595,6 +6687,11 @@ union generic_reply - struct resume_process_reply resume_process_reply; - struct get_next_thread_reply get_next_thread_reply; - struct set_keyboard_repeat_reply set_keyboard_repeat_reply; -+ struct get_linux_sync_device_reply get_linux_sync_device_reply; -+ struct get_linux_sync_obj_reply get_linux_sync_obj_reply; -+ struct fast_select_queue_reply fast_select_queue_reply; -+ struct fast_unselect_queue_reply fast_unselect_queue_reply; -+ struct get_fast_alert_event_reply get_fast_alert_event_reply; - }; - - /* ### protocol_version begin ### */ -diff --git a/server/request.h b/server/request.h -index 6158aefdb78..734f01ecd36 100644 ---- a/server/request.h -+++ b/server/request.h -@@ -405,6 +405,11 @@ DECL_HANDLER(suspend_process); - DECL_HANDLER(resume_process); - DECL_HANDLER(get_next_thread); - DECL_HANDLER(set_keyboard_repeat); -+DECL_HANDLER(get_linux_sync_device); -+DECL_HANDLER(get_linux_sync_obj); -+DECL_HANDLER(fast_select_queue); -+DECL_HANDLER(fast_unselect_queue); -+DECL_HANDLER(get_fast_alert_event); - - #ifdef WANT_REQUEST_HANDLERS - -@@ -697,6 +702,11 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = - (req_handler)req_resume_process, - (req_handler)req_get_next_thread, - (req_handler)req_set_keyboard_repeat, -+ (req_handler)req_get_linux_sync_device, -+ (req_handler)req_get_linux_sync_obj, -+ (req_handler)req_fast_select_queue, -+ (req_handler)req_fast_unselect_queue, -+ (req_handler)req_get_fast_alert_event, - }; - - C_ASSERT( sizeof(abstime_t) == 8 ); -@@ -2341,6 +2351,23 @@ C_ASSERT( FIELD_OFFSET(struct set_keyboard_repeat_request, period) == 20 ); - C_ASSERT( sizeof(struct set_keyboard_repeat_request) == 24 ); - C_ASSERT( FIELD_OFFSET(struct set_keyboard_repeat_reply, enable) == 8 ); - C_ASSERT( sizeof(struct set_keyboard_repeat_reply) == 16 ); -+C_ASSERT( sizeof(struct get_linux_sync_device_request) == 16 ); -+C_ASSERT( FIELD_OFFSET(struct get_linux_sync_device_reply, handle) == 8 ); -+C_ASSERT( sizeof(struct get_linux_sync_device_reply) == 16 ); -+C_ASSERT( FIELD_OFFSET(struct get_linux_sync_obj_request, handle) == 12 ); -+C_ASSERT( sizeof(struct get_linux_sync_obj_request) == 16 ); -+C_ASSERT( FIELD_OFFSET(struct get_linux_sync_obj_reply, handle) == 8 ); -+C_ASSERT( FIELD_OFFSET(struct get_linux_sync_obj_reply, type) == 12 ); -+C_ASSERT( FIELD_OFFSET(struct get_linux_sync_obj_reply, access) == 16 ); -+C_ASSERT( sizeof(struct get_linux_sync_obj_reply) == 24 ); -+C_ASSERT( FIELD_OFFSET(struct fast_select_queue_request, handle) == 12 ); -+C_ASSERT( sizeof(struct fast_select_queue_request) == 16 ); -+C_ASSERT( FIELD_OFFSET(struct fast_unselect_queue_request, handle) == 12 ); -+C_ASSERT( FIELD_OFFSET(struct fast_unselect_queue_request, signaled) == 16 ); -+C_ASSERT( sizeof(struct fast_unselect_queue_request) == 24 ); -+C_ASSERT( sizeof(struct get_fast_alert_event_request) == 16 ); -+C_ASSERT( FIELD_OFFSET(struct get_fast_alert_event_reply, handle) == 8 ); -+C_ASSERT( sizeof(struct get_fast_alert_event_reply) == 16 ); - - #endif /* WANT_REQUEST_HANDLERS */ - -diff --git a/server/trace.c b/server/trace.c -index 96dc5781d4c..e358f64d10f 100644 ---- a/server/trace.c -+++ b/server/trace.c -@@ -4629,6 +4629,47 @@ static void dump_get_next_thread_reply( const struct get_next_thread_reply *req - fprintf( stderr, " handle=%04x", req->handle ); - } - -+static void dump_get_linux_sync_device_request( const struct get_linux_sync_device_request *req ) -+{ -+} -+ -+static void dump_get_linux_sync_device_reply( const struct get_linux_sync_device_reply *req ) -+{ -+ fprintf( stderr, " handle=%04x", req->handle ); -+} -+ -+static void dump_get_linux_sync_obj_request( const struct get_linux_sync_obj_request *req ) -+{ -+ fprintf( stderr, " handle=%04x", req->handle ); -+} -+ -+static void dump_get_linux_sync_obj_reply( const struct get_linux_sync_obj_reply *req ) -+{ -+ fprintf( stderr, " handle=%04x", req->handle ); -+ fprintf( stderr, ", type=%d", req->type ); -+ fprintf( stderr, ", access=%08x", req->access ); -+} -+ -+static void dump_fast_select_queue_request( const struct fast_select_queue_request *req ) -+{ -+ fprintf( stderr, " handle=%04x", req->handle ); -+} -+ -+static void dump_fast_unselect_queue_request( const struct fast_unselect_queue_request *req ) -+{ -+ fprintf( stderr, " handle=%04x", req->handle ); -+ fprintf( stderr, ", signaled=%d", req->signaled ); -+} -+ -+static void dump_get_fast_alert_event_request( const struct get_fast_alert_event_request *req ) -+{ -+} -+ -+static void dump_get_fast_alert_event_reply( const struct get_fast_alert_event_reply *req ) -+{ -+ fprintf( stderr, " handle=%04x", req->handle ); -+} -+ - static void dump_set_keyboard_repeat_request( const struct set_keyboard_repeat_request *req ) - { - fprintf( stderr, " enable=%d", req->enable ); -@@ -4928,6 +4969,11 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { - (dump_func)dump_resume_process_request, - (dump_func)dump_get_next_thread_request, - (dump_func)dump_set_keyboard_repeat_request, -+ (dump_func)dump_get_linux_sync_device_request, -+ (dump_func)dump_get_linux_sync_obj_request, -+ (dump_func)dump_fast_select_queue_request, -+ (dump_func)dump_fast_unselect_queue_request, -+ (dump_func)dump_get_fast_alert_event_request, - }; - - static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { -@@ -5217,6 +5263,11 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { - NULL, - (dump_func)dump_get_next_thread_reply, - (dump_func)dump_set_keyboard_repeat_reply, -+ (dump_func)dump_get_linux_sync_device_reply, -+ (dump_func)dump_get_linux_sync_obj_reply, -+ NULL, -+ NULL, -+ (dump_func)dump_get_fast_alert_event_reply, - }; - - static const char * const req_names[REQ_NB_REQUESTS] = { -@@ -5506,6 +5557,11 @@ static const char * const req_names[REQ_NB_REQUESTS] = { - "resume_process", - "get_next_thread", - "set_keyboard_repeat", -+ "get_linux_sync_device", -+ "get_linux_sync_obj", -+ "fast_select_queue", -+ "fast_unselect_queue", -+ "get_fast_alert_event", - }; - - static const struct --- -2.46.0 - - diff --git a/0007-ntsync/0032-extra-debugging.patch b/0007-ntsync/0032-extra-debugging.patch deleted file mode 100644 index 392134e..0000000 --- a/0007-ntsync/0032-extra-debugging.patch +++ /dev/null @@ -1,82 +0,0 @@ -From: Elizabeth Figura -Date: Fri, 3 May 2024 14:35:50 -0400 -Subject: [PATCH 32/32] extra debugging - ---- - server/fast_sync.c | 23 ++++++++++++++++++++--- - 1 file changed, 20 insertions(+), 3 deletions(-) - -diff --git a/server/fast_sync.c b/server/fast_sync.c -index 51fe32ea631..fed6eb90639 100644 ---- a/server/fast_sync.c -+++ b/server/fast_sync.c -@@ -21,6 +21,7 @@ - #include "config.h" - - #include -+#include - #include - #include - -@@ -124,21 +125,34 @@ static enum server_fd_type fast_sync_get_fd_type( struct fd *fd ) - static struct linux_device *get_linux_device(void) - { - struct linux_device *device; -+ static int initialized; - int unix_fd; - -+ if (initialized) -+ { -+ if (linux_device_object) -+ grab_object( linux_device_object ); -+ else -+ set_error( STATUS_NOT_IMPLEMENTED ); -+ return linux_device_object; -+ } -+ - if (getenv( "WINE_DISABLE_FAST_SYNC" ) && atoi( getenv( "WINE_DISABLE_FAST_SYNC" ) )) - { -+ static int once; - set_error( STATUS_NOT_IMPLEMENTED ); -+ if (!once++) fprintf(stderr, "ntsync is explicitly disabled.\n"); -+ initialized = 1; - return NULL; - } - -- if (linux_device_object) -- return (struct linux_device *)grab_object( linux_device_object ); -- - unix_fd = open( "/dev/ntsync", O_CLOEXEC | O_RDONLY ); - if (unix_fd == -1) - { -+ static int once; - file_set_error(); -+ if (!once++) fprintf(stderr, "Cannot open /dev/ntsync: %s\n", strerror(errno)); -+ initialized = 1; - return NULL; - } - -@@ -146,17 +160,20 @@ static struct linux_device *get_linux_device(void) - { - close( unix_fd ); - set_error( STATUS_NO_MEMORY ); -+ initialized = 1; - return NULL; - } - - if (!(device->fd = create_anonymous_fd( &fast_sync_fd_ops, unix_fd, &device->obj, 0 ))) - { - release_object( device ); -+ initialized = 1; - return NULL; - } - - fprintf( stderr, "wine: using fast synchronization.\n" ); - linux_device_object = device; -+ initialized = 1; - return device; - } - --- -2.46.0 - diff --git a/0007-proton-esync-fsync/0001-Revert-ntdll-tests-Add-tests-for-completion-port-sig.patch b/0007-proton-esync-fsync/0001-Revert-ntdll-tests-Add-tests-for-completion-port-sig.patch new file mode 100644 index 0000000..6029e26 --- /dev/null +++ b/0007-proton-esync-fsync/0001-Revert-ntdll-tests-Add-tests-for-completion-port-sig.patch @@ -0,0 +1,224 @@ +From 5d4d73d66ed6a0bb6817b2f5f1a25316e6fe7eec Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Thu, 24 Oct 2024 11:19:21 -0700 +Subject: [PATCH 1/6] Revert "ntdll/tests: Add tests for completion port + signaling." + +This reverts commit 59993d73123fd1e6e967b8133af76e4e0d91c021. +--- + dlls/ntdll/tests/sync.c | 194 ---------------------------------------- + 1 file changed, 194 deletions(-) + +diff --git a/dlls/ntdll/tests/sync.c b/dlls/ntdll/tests/sync.c +index 3ab89bbf361..f356d3ec38f 100644 +--- a/dlls/ntdll/tests/sync.c ++++ b/dlls/ntdll/tests/sync.c +@@ -837,199 +837,6 @@ static void test_tid_alert( char **argv ) + CloseHandle( pi.hThread ); + } + +-struct test_completion_port_scheduling_param +-{ +- HANDLE ready, test_ready; +- HANDLE port; +- int index; +-}; +- +-static DWORD WINAPI test_completion_port_scheduling_thread(void *param) +-{ +- struct test_completion_port_scheduling_param *p = param; +- FILE_IO_COMPLETION_INFORMATION info; +- OVERLAPPED_ENTRY overlapped_entry; +- OVERLAPPED *overlapped; +- IO_STATUS_BLOCK iosb; +- ULONG_PTR key, value; +- NTSTATUS status; +- DWORD ret, err; +- ULONG count; +- BOOL bret; +- +- /* both threads are woken when comleption added. */ +- ret = WaitForSingleObject( p->ready, INFINITE ); +- ok( ret == WAIT_OBJECT_0, "got %#lx.\n", ret ); +- ret = WaitForSingleObject( p->port, INFINITE ); +- ok( ret == WAIT_OBJECT_0, "got %#lx.\n", ret ); +- SetEvent( p->test_ready ); +- +- /* if a thread is waiting for completion which is added threads which wait on port handle are not woken. */ +- ret = WaitForSingleObject( p->ready, INFINITE ); +- if (p->index) +- { +- bret = GetQueuedCompletionStatus( p->port, &count, &key, &overlapped, INFINITE ); +- ok( bret, "got error %lu.\n", GetLastError() ); +- } +- else +- { +- ret = WaitForSingleObject( p->port, 100 ); +- ok( ret == WAIT_TIMEOUT || broken( !ret ) /* before Win10 1607 */, "got %#lx.\n", ret ); +- } +- SetEvent( p->test_ready ); +- +- /* Two threads in GetQueuedCompletionStatus, the second is supposed to start first. */ +- ret = WaitForSingleObject( p->ready, INFINITE ); +- ok( ret == WAIT_OBJECT_0, "got %#lx.\n", ret ); +- bret = GetQueuedCompletionStatus( p->port, &count, &key, &overlapped, INFINITE ); +- ok( bret, "got error %lu.\n", GetLastError() ); +- ok( key == 3 + p->index || broken( p->index && key == 5 ) /* before Win10 */, "got %Iu, expected %u.\n", key, 3 + p->index ); +- SetEvent( p->test_ready ); +- +- /* Port is being closed. */ +- ret = WaitForSingleObject( p->ready, INFINITE ); +- ret = WaitForSingleObject( p->port, INFINITE ); +- if (ret == WAIT_FAILED) +- skip( "Handle closed before wait started.\n" ); +- else +- ok( ret == WAIT_OBJECT_0, "got %#lx.\n", ret ); +- SetEvent( p->test_ready ); +- +- /* Port is being closed. */ +- ret = WaitForSingleObject( p->ready, INFINITE ); +- ok( ret == WAIT_OBJECT_0, "got %#lx.\n", ret ); +- SetEvent( p->test_ready ); +- status = NtRemoveIoCompletion( p->port, &key, &value, &iosb, NULL ); +- if (status == STATUS_INVALID_HANDLE) +- skip( "Handle closed before wait started.\n" ); +- else +- ok( status == STATUS_ABANDONED_WAIT_0, "got %#lx.\n", status ); +- +- /* Port is being closed. */ +- ret = WaitForSingleObject( p->ready, INFINITE ); +- ok( ret == WAIT_OBJECT_0, "got %#lx.\n", ret ); +- SetEvent( p->test_ready ); +- count = 0xdeadbeef; +- status = NtRemoveIoCompletionEx( p->port, &info, 1, &count, NULL, FALSE ); +- ok( count <= 1, "Got unexpected count %lu.\n", count ); +- if (status == STATUS_INVALID_HANDLE) +- skip( "Handle closed before wait started.\n" ); +- else +- ok( status == STATUS_ABANDONED_WAIT_0, "got %#lx.\n", status ); +- +- /* Port is being closed. */ +- ret = WaitForSingleObject( p->ready, INFINITE ); +- ok( ret == WAIT_OBJECT_0, "got %#lx.\n", ret ); +- SetEvent( p->test_ready ); +- bret = GetQueuedCompletionStatus( p->port, &count, &key, &overlapped, INFINITE ); +- err = GetLastError(); +- ok( !bret, "got %d.\n", bret ); +- if (err == ERROR_INVALID_HANDLE) +- skip( "Handle closed before wait started.\n" ); +- else +- ok( err == ERROR_ABANDONED_WAIT_0, "got error %#lx.\n", err ); +- +- /* Port is being closed. */ +- ret = WaitForSingleObject( p->ready, INFINITE ); +- ok( ret == WAIT_OBJECT_0, "got %#lx.\n", ret ); +- SetEvent( p->test_ready ); +- bret = GetQueuedCompletionStatusEx( p->port, &overlapped_entry, 1, &count, INFINITE, TRUE ); +- err = GetLastError(); +- ok( !bret, "got %d.\n", bret ); +- if (err == ERROR_INVALID_HANDLE) +- skip( "Handle closed before wait started.\n" ); +- else +- ok( err == ERROR_ABANDONED_WAIT_0, "got error %#lx.\n", err ); +- +- return 0; +-} +- +-static void test_completion_port_scheduling(void) +-{ +- struct test_completion_port_scheduling_param p[2]; +- HANDLE threads[2], port; +- OVERLAPPED *overlapped; +- unsigned int i, j; +- DWORD ret, count; +- NTSTATUS status; +- ULONG_PTR key; +- BOOL bret; +- +- for (i = 0; i < 2; ++i) +- { +- p[i].index = 0; +- p[i].ready = CreateEventA(NULL, FALSE, FALSE, NULL); +- p[i].test_ready = CreateEventA(NULL, FALSE, FALSE, NULL); +- threads[i] = CreateThread( NULL, 0, test_completion_port_scheduling_thread, &p[i], 0, NULL ); +- ok( !!threads[i], "got error %lu.\n", GetLastError() ); +- } +- +- status = NtCreateIoCompletion( &port, IO_COMPLETION_ALL_ACCESS, NULL, 0 ); +- ok( !status, "got %#lx.\n", status ); +- /* Waking multiple threads directly waiting on port */ +- for (i = 0; i < 2; ++i) +- { +- p[i].index = i; +- p[i].port = port; +- SetEvent( p[i].ready ); +- } +- PostQueuedCompletionStatus( port, 0, 1, NULL ); +- for (i = 0; i < 2; ++i) WaitForSingleObject( p[i].test_ready, INFINITE ); +- bret = GetQueuedCompletionStatus( port, &count, &key, &overlapped, INFINITE ); +- ok( bret, "got error %lu.\n", GetLastError() ); +- +- /* One thread is waiting on port, another in GetQueuedCompletionStatus(). */ +- SetEvent( p[1].ready ); +- Sleep( 40 ); +- SetEvent( p[0].ready ); +- Sleep( 10 ); +- PostQueuedCompletionStatus( port, 0, 2, NULL ); +- for (i = 0; i < 2; ++i) WaitForSingleObject( p[i].test_ready, INFINITE ); +- +- /* Both threads are waiting in GetQueuedCompletionStatus, LIFO wake up order. */ +- SetEvent( p[1].ready ); +- Sleep( 40 ); +- SetEvent( p[0].ready ); +- Sleep( 20 ); +- PostQueuedCompletionStatus( port, 0, 3, NULL ); +- PostQueuedCompletionStatus( port, 0, 4, NULL ); +- PostQueuedCompletionStatus( port, 0, 5, NULL ); +- bret = GetQueuedCompletionStatus( p->port, &count, &key, &overlapped, INFINITE ); +- ok( bret, "got error %lu.\n", GetLastError() ); +- ok( key == 5 || broken( key == 4 ) /* before Win10 */, "got %Iu, expected 5.\n", key ); +- +- /* Close port handle while threads are waiting on it directly. */ +- for (i = 0; i < 2; ++i) SetEvent( p[i].ready ); +- Sleep( 20 ); +- NtClose( port ); +- for (i = 0; i < 2; ++i) WaitForSingleObject( p[i].test_ready, INFINITE ); +- +- /* Test signaling on port close. */ +- for (i = 0; i < 4; ++i) +- { +- status = NtCreateIoCompletion( &port, IO_COMPLETION_ALL_ACCESS, NULL, 0 ); +- ok( !status, "got %#lx.\n", status ); +- for (j = 0; j < 2; ++j) +- { +- p[j].port = port; +- ret = SignalObjectAndWait( p[j].ready, p[j].test_ready, +- INFINITE, FALSE ); +- ok( ret == WAIT_OBJECT_0, "got %#lx.\n", ret ); +- } +- Sleep( 20 ); +- status = NtClose( port ); +- ok( !status, "got %#lx.\n", status ); +- } +- +- WaitForMultipleObjects( 2, threads, TRUE, INFINITE ); +- for (i = 0; i < 2; ++i) +- { +- CloseHandle( threads[i] ); +- CloseHandle( p[i].ready ); +- CloseHandle( p[i].test_ready ); +- } +-} +- + START_TEST(sync) + { + HMODULE module = GetModuleHandleA("ntdll.dll"); +@@ -1077,5 +884,4 @@ START_TEST(sync) + test_keyed_events(); + test_resource(); + test_tid_alert( argv ); +- test_completion_port_scheduling(); + } +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0002-Revert-kernelbase-Set-the-proper-error-code-in-GetQu.patch b/0007-proton-esync-fsync/0002-Revert-kernelbase-Set-the-proper-error-code-in-GetQu.patch new file mode 100644 index 0000000..350766f --- /dev/null +++ b/0007-proton-esync-fsync/0002-Revert-kernelbase-Set-the-proper-error-code-in-GetQu.patch @@ -0,0 +1,40 @@ +From 543105b17a7d76ec84cb554db0dcc54778e7351d Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Thu, 24 Oct 2024 11:19:21 -0700 +Subject: [PATCH 2/6] Revert "kernelbase: Set the proper error code in + GetQueuedCompletionStatus{Ex} when the handle is closed." + +This reverts commit 764162fc5c855ccd2d238bfc21361cc852e2685c. +--- + dlls/kernelbase/sync.c | 8 +++----- + 1 file changed, 3 insertions(+), 5 deletions(-) + +diff --git a/dlls/kernelbase/sync.c b/dlls/kernelbase/sync.c +index f03a6c3150a..1d935b02ddf 100644 +--- a/dlls/kernelbase/sync.c ++++ b/dlls/kernelbase/sync.c +@@ -1197,8 +1197,7 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetQueuedCompletionStatus( HANDLE port, LPDWORD co + return FALSE; + } + +- if (status == STATUS_TIMEOUT) SetLastError( WAIT_TIMEOUT ); +- else if (status == STATUS_ABANDONED) SetLastError( ERROR_ABANDONED_WAIT_0 ); ++ if (status == STATUS_TIMEOUT) SetLastError( WAIT_TIMEOUT ); + else SetLastError( RtlNtStatusToDosError(status) ); + return FALSE; + } +@@ -1218,9 +1217,8 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetQueuedCompletionStatusEx( HANDLE port, OVERLAPP + ret = NtRemoveIoCompletionEx( port, (FILE_IO_COMPLETION_INFORMATION *)entries, count, + written, get_nt_timeout( &time, timeout ), alertable ); + if (ret == STATUS_SUCCESS) return TRUE; +- else if (ret == STATUS_TIMEOUT) SetLastError( WAIT_TIMEOUT ); +- else if (ret == STATUS_USER_APC) SetLastError( WAIT_IO_COMPLETION ); +- else if (ret == STATUS_ABANDONED) SetLastError( ERROR_ABANDONED_WAIT_0 ); ++ else if (ret == STATUS_TIMEOUT) SetLastError( WAIT_TIMEOUT ); ++ else if (ret == STATUS_USER_APC) SetLastError( WAIT_IO_COMPLETION ); + else SetLastError( RtlNtStatusToDosError(ret) ); + return FALSE; + } +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0003-Revert-server-Signal-completion-port-waits-on-handle.patch b/0007-proton-esync-fsync/0003-Revert-server-Signal-completion-port-waits-on-handle.patch new file mode 100644 index 0000000..31723dd --- /dev/null +++ b/0007-proton-esync-fsync/0003-Revert-server-Signal-completion-port-waits-on-handle.patch @@ -0,0 +1,152 @@ +From fa1885ab5adf4ddff5fca545712ffec5ac113cbf Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Thu, 24 Oct 2024 11:19:21 -0700 +Subject: [PATCH 3/6] Revert "server: Signal completion port waits on handle + close." + +This reverts commit 291888be7400726792aa15985de8875ff0b02cf5. +--- + server/completion.c | 52 +++++++++++++-------------------------------- + 1 file changed, 15 insertions(+), 37 deletions(-) + +diff --git a/server/completion.c b/server/completion.c +index f9e68c523f1..108aff46818 100644 +--- a/server/completion.c ++++ b/server/completion.c +@@ -19,7 +19,11 @@ + * + */ + +-/* FIXME: "max concurrent active threads" parameter is not used */ ++/* FIXMEs: ++ * - built-in wait queues used which means: ++ * + "max concurrent active threads" parameter not used ++ * + completion handle is waitable, while native isn't ++ */ + + #include "config.h" + +@@ -76,7 +80,6 @@ struct completion + struct list queue; + struct list wait_queue; + unsigned int depth; +- int closed; + }; + + static void completion_wait_dump( struct object*, int ); +@@ -128,7 +131,6 @@ static int completion_wait_signaled( struct object *obj, struct wait_queue_entry + struct completion_wait *wait = (struct completion_wait *)obj; + + assert( obj->ops == &completion_wait_ops ); +- if (!wait->completion) return 1; + return wait->completion->depth; + } + +@@ -139,11 +141,6 @@ static void completion_wait_satisfied( struct object *obj, struct wait_queue_ent + struct comp_msg *msg; + + assert( obj->ops == &completion_wait_ops ); +- if (!wait->completion) +- { +- make_wait_abandoned( entry ); +- return; +- } + msg_entry = list_head( &wait->completion->queue ); + assert( msg_entry ); + msg = LIST_ENTRY( msg_entry, struct comp_msg, queue_entry ); +@@ -155,7 +152,6 @@ static void completion_wait_satisfied( struct object *obj, struct wait_queue_ent + + static void completion_dump( struct object*, int ); + static int completion_signaled( struct object *obj, struct wait_queue_entry *entry ); +-static int completion_close_handle( struct object *obj, struct process *process, obj_handle_t handle ); + static void completion_destroy( struct object * ); + + static const struct object_ops completion_ops = +@@ -178,19 +174,26 @@ static const struct object_ops completion_ops = + default_unlink_name, /* unlink_name */ + no_open_file, /* open_file */ + no_kernel_obj_list, /* get_kernel_obj_list */ +- completion_close_handle, /* close_handle */ ++ no_close_handle, /* close_handle */ + completion_destroy /* destroy */ + }; + + static void completion_destroy( struct object *obj) + { + struct completion *completion = (struct completion *) obj; ++ struct completion_wait *wait, *wait_next; + struct comp_msg *tmp, *next; + + LIST_FOR_EACH_ENTRY_SAFE( tmp, next, &completion->queue, struct comp_msg, queue_entry ) + { + free( tmp ); + } ++ ++ LIST_FOR_EACH_ENTRY_SAFE( wait, wait_next, &completion->wait_queue, struct completion_wait, wait_queue_entry ) ++ { ++ assert( wait->completion ); ++ cleanup_thread_completion( wait->thread ); ++ } + } + + static void completion_dump( struct object *obj, int verbose ) +@@ -205,30 +208,7 @@ static int completion_signaled( struct object *obj, struct wait_queue_entry *ent + { + struct completion *completion = (struct completion *)obj; + +- return !list_empty( &completion->queue ) || completion->closed; +-} +- +-static int completion_close_handle( struct object *obj, struct process *process, obj_handle_t handle ) +-{ +- struct completion *completion = (struct completion *)obj; +- struct completion_wait *wait, *wait_next; +- +- if (completion->obj.handle_count != 1) return 1; +- +- LIST_FOR_EACH_ENTRY_SAFE( wait, wait_next, &completion->wait_queue, struct completion_wait, wait_queue_entry ) +- { +- assert( wait->completion ); +- wait->completion = NULL; +- list_remove( &wait->wait_queue_entry ); +- if (!wait->msg) +- { +- wake_up( &wait->obj, 0 ); +- cleanup_thread_completion( wait->thread ); +- } +- } +- completion->closed = 1; +- wake_up( obj, 0 ); +- return 1; ++ return !list_empty( &completion->queue ); + } + + void cleanup_thread_completion( struct thread *thread ) +@@ -240,7 +220,7 @@ void cleanup_thread_completion( struct thread *thread ) + close_handle( thread->process, thread->completion_wait->handle ); + thread->completion_wait->handle = 0; + } +- if (thread->completion_wait->completion) list_remove( &thread->completion_wait->wait_queue_entry ); ++ list_remove( &thread->completion_wait->wait_queue_entry ); + release_object( &thread->completion_wait->obj ); + thread->completion_wait = NULL; + } +@@ -274,7 +254,6 @@ static struct completion *create_completion( struct object *root, const struct u + list_init( &completion->queue ); + list_init( &completion->wait_queue ); + completion->depth = 0; +- completion->closed = 0; + } + } + +@@ -418,7 +397,6 @@ DECL_HANDLER(get_thread_completion) + reply->information = msg->information; + free( msg ); + current->completion_wait->msg = NULL; +- if (!current->completion_wait->completion) cleanup_thread_completion( current ); + } + + /* get queue depth for completion port */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0004-Revert-ntdll-Handle-user-APCs-explicitly-in-NtRemove.patch b/0007-proton-esync-fsync/0004-Revert-ntdll-Handle-user-APCs-explicitly-in-NtRemove.patch new file mode 100644 index 0000000..95f3cfa --- /dev/null +++ b/0007-proton-esync-fsync/0004-Revert-ntdll-Handle-user-APCs-explicitly-in-NtRemove.patch @@ -0,0 +1,206 @@ +From f60e01d8a68411c75ea275b9c9e96403ad3e277b Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Thu, 24 Oct 2024 11:19:21 -0700 +Subject: [PATCH 4/6] Revert "ntdll: Handle user APCs explicitly in + NtRemoveIoCompletionEx()." + +This reverts commit b6904756a4d922fcdfa4a2324654a8b4317db93b. +--- + dlls/ntdll/tests/file.c | 47 +--------------------------------- + dlls/ntdll/unix/sync.c | 14 +++------- + include/wine/server_protocol.h | 4 +-- + server/completion.c | 7 ----- + server/protocol.def | 1 - + server/request.h | 3 +-- + server/trace.c | 1 - + 7 files changed, 6 insertions(+), 71 deletions(-) + +diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c +index e60d392346b..0adc0998ee2 100644 +--- a/dlls/ntdll/tests/file.c ++++ b/dlls/ntdll/tests/file.c +@@ -958,59 +958,14 @@ static void test_set_io_completion(void) + NTSTATUS res; + ULONG count; + SIZE_T size = 3; +- HANDLE h, h2; ++ HANDLE h; + + if (sizeof(size) > 4) size |= (ULONGLONG)0x12345678 << 32; + +- res = pNtCreateIoCompletion( &h2, IO_COMPLETION_ALL_ACCESS, NULL, 0 ); +- ok( res == STATUS_SUCCESS, "NtCreateIoCompletion failed: %#lx\n", res ); +- ok( h2 && h2 != INVALID_HANDLE_VALUE, "got invalid handle %p\n", h2 ); +- res = pNtSetIoCompletion( h2, 123, 456, 789, size ); +- ok( res == STATUS_SUCCESS, "NtSetIoCompletion failed: %#lx\n", res ); +- res = pNtRemoveIoCompletionEx( h2, info, 2, &count, &timeout, TRUE ); +- ok( res == STATUS_SUCCESS, "NtRemoveIoCompletionEx failed: %#lx\n", res ); +- ok( count == 1, "wrong count %lu\n", count ); +- + res = pNtCreateIoCompletion( &h, IO_COMPLETION_ALL_ACCESS, NULL, 0 ); + ok( res == STATUS_SUCCESS, "NtCreateIoCompletion failed: %#lx\n", res ); + ok( h && h != INVALID_HANDLE_VALUE, "got invalid handle %p\n", h ); + +- apc_count = 0; +- QueueUserAPC( user_apc_proc, GetCurrentThread(), (ULONG_PTR)&apc_count ); +- res = pNtSetIoCompletion( h, 123, 456, 789, size ); +- ok( res == STATUS_SUCCESS, "NtSetIoCompletion failed: %#lx\n", res ); +- res = pNtRemoveIoCompletionEx( h, info, 2, &count, &timeout, TRUE ); +- /* APC goes first associated with completion port APC takes priority over pending completion. +- * Even if the thread is associated with some other completion port. */ +- ok( res == STATUS_USER_APC, "NtRemoveIoCompletionEx unexpected status %#lx\n", res ); +- ok( apc_count == 1, "wrong apc count %u\n", apc_count ); +- +- CloseHandle( h2 ); +- +- apc_count = 0; +- QueueUserAPC( user_apc_proc, GetCurrentThread(), (ULONG_PTR)&apc_count ); +- res = pNtRemoveIoCompletionEx( h, info, 2, &count, &timeout, TRUE ); +- /* Previous call resulted in STATUS_USER_APC did not associate the thread with the port. */ +- ok( res == STATUS_USER_APC, "NtRemoveIoCompletion unexpected status %#lx\n", res ); +- ok( apc_count == 1, "wrong apc count %u\n", apc_count ); +- +- res = pNtRemoveIoCompletionEx( h, info, 2, &count, &timeout, TRUE ); +- /* Now the thread is associated. */ +- ok( res == STATUS_SUCCESS, "NtRemoveIoCompletion failed: %#lx\n", res ); +- ok( count == 1, "wrong count %lu\n", count ); +- +- apc_count = 0; +- QueueUserAPC( user_apc_proc, GetCurrentThread(), (ULONG_PTR)&apc_count ); +- res = pNtSetIoCompletion( h, 123, 456, 789, size ); +- ok( res == STATUS_SUCCESS, "NtSetIoCompletion failed: %#lx\n", res ); +- res = pNtRemoveIoCompletionEx( h, info, 2, &count, &timeout, TRUE ); +- /* After a thread is associated with completion port existing completion is returned if APC is pending. */ +- ok( res == STATUS_SUCCESS, "NtRemoveIoCompletionEx failed: %#lx\n", res ); +- ok( count == 1, "wrong count %lu\n", count ); +- ok( apc_count == 0, "wrong apc count %u\n", apc_count ); +- SleepEx( 0, TRUE); +- ok( apc_count == 1, "wrong apc count %u\n", apc_count ); +- + res = pNtRemoveIoCompletion( h, &key, &value, &iosb, &timeout ); + ok( res == STATUS_TIMEOUT, "NtRemoveIoCompletion failed: %#lx\n", res ); + +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 80f82c18730..f5536e398b5 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -2007,7 +2007,6 @@ NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR * + SERVER_START_REQ( remove_completion ) + { + req->handle = wine_server_obj_handle( handle ); +- req->alertable = 0; + if (!(status = wine_server_call( req ))) + { + *key = reply->ckey; +@@ -2056,7 +2055,6 @@ NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORM + SERVER_START_REQ( remove_completion ) + { + req->handle = wine_server_obj_handle( handle ); +- req->alertable = alertable; + if (!(status = wine_server_call( req ))) + { + info[i].CompletionKey = reply->ckey; +@@ -2070,19 +2068,13 @@ NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORM + if (status != STATUS_SUCCESS) break; + ++i; + } +- if (i || (status != STATUS_PENDING && status != STATUS_USER_APC)) ++ if (i || status != STATUS_PENDING) + { + if (i) status = STATUS_SUCCESS; + goto done; + } +- if (status == STATUS_USER_APC) +- { +- status = NtDelayExecution( TRUE, NULL ); +- assert( status == STATUS_USER_APC ); +- goto done; +- } +- if (!timeout || timeout->QuadPart) status = NtWaitForSingleObject( wait_handle, alertable, timeout ); +- else status = STATUS_TIMEOUT; ++ if (!timeout || timeout->QuadPart || alertable) status = NtWaitForSingleObject( wait_handle, alertable, timeout ); ++ else status = STATUS_TIMEOUT; + if (status != WAIT_OBJECT_0) goto done; + + SERVER_START_REQ( get_thread_completion ) +diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h +index f246490791e..3abb1279ba9 100644 +--- a/include/wine/server_protocol.h ++++ b/include/wine/server_protocol.h +@@ -5402,8 +5402,6 @@ struct remove_completion_request + { + struct request_header __header; + obj_handle_t handle; +- int alertable; +- char __pad_20[4]; + }; + struct remove_completion_reply + { +@@ -6733,7 +6731,7 @@ union generic_reply + + /* ### protocol_version begin ### */ + +-#define SERVER_PROTOCOL_VERSION 846 ++#define SERVER_PROTOCOL_VERSION 845 + + /* ### protocol_version end ### */ + +diff --git a/server/completion.c b/server/completion.c +index 108aff46818..f56162aa22d 100644 +--- a/server/completion.c ++++ b/server/completion.c +@@ -341,13 +341,6 @@ DECL_HANDLER(remove_completion) + if (!completion) return; + + entry = list_head( &completion->queue ); +- if (req->alertable && !list_empty( ¤t->user_apc ) +- && !(entry && current->completion_wait && current->completion_wait->completion == completion)) +- { +- set_error( STATUS_USER_APC ); +- release_object( completion ); +- return; +- } + if (current->completion_wait) + { + list_remove( ¤t->completion_wait->wait_queue_entry ); +diff --git a/server/protocol.def b/server/protocol.def +index ac22f9853e5..0ad102283d1 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3793,7 +3793,6 @@ typedef union + /* get completion from completion port queue */ + @REQ(remove_completion) + obj_handle_t handle; /* port handle */ +- int alertable; /* completion wait is alertable */ + @REPLY + apc_param_t ckey; /* completion key */ + apc_param_t cvalue; /* completion value */ +diff --git a/server/request.h b/server/request.h +index 68fa71e39fb..8222fc73dc4 100644 +--- a/server/request.h ++++ b/server/request.h +@@ -2237,8 +2237,7 @@ C_ASSERT( FIELD_OFFSET(struct add_completion_request, information) == 32 ); + C_ASSERT( FIELD_OFFSET(struct add_completion_request, status) == 40 ); + C_ASSERT( sizeof(struct add_completion_request) == 48 ); + C_ASSERT( FIELD_OFFSET(struct remove_completion_request, handle) == 12 ); +-C_ASSERT( FIELD_OFFSET(struct remove_completion_request, alertable) == 16 ); +-C_ASSERT( sizeof(struct remove_completion_request) == 24 ); ++C_ASSERT( sizeof(struct remove_completion_request) == 16 ); + C_ASSERT( FIELD_OFFSET(struct remove_completion_reply, ckey) == 8 ); + C_ASSERT( FIELD_OFFSET(struct remove_completion_reply, cvalue) == 16 ); + C_ASSERT( FIELD_OFFSET(struct remove_completion_reply, information) == 24 ); +diff --git a/server/trace.c b/server/trace.c +index 7142c37218a..a59cf6c5b5f 100644 +--- a/server/trace.c ++++ b/server/trace.c +@@ -4519,7 +4519,6 @@ static void dump_add_completion_request( const struct add_completion_request *re + static void dump_remove_completion_request( const struct remove_completion_request *req ) + { + fprintf( stderr, " handle=%04x", req->handle ); +- fprintf( stderr, ", alertable=%d", req->alertable ); + } + + static void dump_remove_completion_reply( const struct remove_completion_reply *req ) +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0005-Revert-ntdll-Assign-completion-to-thread-when-wait-f.patch b/0007-proton-esync-fsync/0005-Revert-ntdll-Assign-completion-to-thread-when-wait-f.patch new file mode 100644 index 0000000..487dbbb --- /dev/null +++ b/0007-proton-esync-fsync/0005-Revert-ntdll-Assign-completion-to-thread-when-wait-f.patch @@ -0,0 +1,441 @@ +From 5e7b0852b96d66257a7f7b4aef1626f6cb317746 Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Thu, 24 Oct 2024 11:19:21 -0700 +Subject: [PATCH 5/6] Revert "ntdll: Assign completion to thread when wait for + completion is satisfied." + +This reverts commit dc7bdc3db6aa057f0255765e18fb6f852244db4c. +--- + dlls/ntdll/unix/sync.c | 95 +++++++++++++--------------------- + include/wine/server_protocol.h | 22 +------- + server/completion.c | 62 ++++------------------ + server/protocol.def | 10 ---- + server/request.h | 8 --- + server/trace.c | 15 ------ + 6 files changed, 47 insertions(+), 165 deletions(-) + +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index f5536e398b5..e4a659f93bb 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -2004,37 +2004,25 @@ NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR * + + TRACE( "(%p, %p, %p, %p, %p)\n", handle, key, value, io, timeout ); + +- SERVER_START_REQ( remove_completion ) +- { +- req->handle = wine_server_obj_handle( handle ); +- if (!(status = wine_server_call( req ))) +- { +- *key = reply->ckey; +- *value = reply->cvalue; +- io->Information = reply->information; +- io->Status = reply->status; +- } +- else wait_handle = wine_server_ptr_handle( reply->wait_handle ); +- } +- SERVER_END_REQ; +- if (status != STATUS_PENDING) return status; +- if (!timeout || timeout->QuadPart) status = NtWaitForSingleObject( wait_handle, FALSE, timeout ); +- else status = STATUS_TIMEOUT; +- if (status != WAIT_OBJECT_0) return status; +- +- SERVER_START_REQ( get_thread_completion ) ++ for (;;) + { +- if (!(status = wine_server_call( req ))) ++ SERVER_START_REQ( remove_completion ) + { +- *key = reply->ckey; +- *value = reply->cvalue; +- io->Information = reply->information; +- io->Status = reply->status; ++ req->handle = wine_server_obj_handle( handle ); ++ if (!(status = wine_server_call( req ))) ++ { ++ *key = reply->ckey; ++ *value = reply->cvalue; ++ io->Information = reply->information; ++ io->Status = reply->status; ++ } ++ else wait_handle = wine_server_ptr_handle( reply->wait_handle ); + } ++ SERVER_END_REQ; ++ if (status != STATUS_PENDING) return status; ++ status = NtWaitForSingleObject( wait_handle, FALSE, timeout ); ++ if (status != WAIT_OBJECT_0) return status; + } +- SERVER_END_REQ; +- +- return status; + } + + +@@ -2050,47 +2038,34 @@ NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORM + + TRACE( "%p %p %u %p %p %u\n", handle, info, (int)count, written, timeout, alertable ); + +- while (i < count) ++ for (;;) + { +- SERVER_START_REQ( remove_completion ) ++ while (i < count) + { +- req->handle = wine_server_obj_handle( handle ); +- if (!(status = wine_server_call( req ))) ++ SERVER_START_REQ( remove_completion ) + { +- info[i].CompletionKey = reply->ckey; +- info[i].CompletionValue = reply->cvalue; +- info[i].IoStatusBlock.Information = reply->information; +- info[i].IoStatusBlock.Status = reply->status; ++ req->handle = wine_server_obj_handle( handle ); ++ if (!(status = wine_server_call( req ))) ++ { ++ info[i].CompletionKey = reply->ckey; ++ info[i].CompletionValue = reply->cvalue; ++ info[i].IoStatusBlock.Information = reply->information; ++ info[i].IoStatusBlock.Status = reply->status; ++ } ++ else wait_handle = wine_server_ptr_handle( reply->wait_handle ); + } +- else wait_handle = wine_server_ptr_handle( reply->wait_handle ); ++ SERVER_END_REQ; ++ if (status != STATUS_SUCCESS) break; ++ ++i; + } +- SERVER_END_REQ; +- if (status != STATUS_SUCCESS) break; +- ++i; +- } +- if (i || status != STATUS_PENDING) +- { +- if (i) status = STATUS_SUCCESS; +- goto done; +- } +- if (!timeout || timeout->QuadPart || alertable) status = NtWaitForSingleObject( wait_handle, alertable, timeout ); +- else status = STATUS_TIMEOUT; +- if (status != WAIT_OBJECT_0) goto done; +- +- SERVER_START_REQ( get_thread_completion ) +- { +- if (!(status = wine_server_call( req ))) ++ if (i || status != STATUS_PENDING) + { +- info[i].CompletionKey = reply->ckey; +- info[i].CompletionValue = reply->cvalue; +- info[i].IoStatusBlock.Information = reply->information; +- info[i].IoStatusBlock.Status = reply->status; +- ++i; ++ if (status == STATUS_PENDING) status = STATUS_SUCCESS; ++ break; + } ++ status = NtWaitForSingleObject( wait_handle, alertable, timeout ); ++ if (status != WAIT_OBJECT_0) break; + } +- SERVER_END_REQ; +- +-done: + *written = i ? i : 1; + return status; + } +diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h +index 3abb1279ba9..15e89227884 100644 +--- a/include/wine/server_protocol.h ++++ b/include/wine/server_protocol.h +@@ -5415,23 +5415,6 @@ struct remove_completion_reply + + + +-struct get_thread_completion_request +-{ +- struct request_header __header; +- char __pad_12[4]; +-}; +-struct get_thread_completion_reply +-{ +- struct reply_header __header; +- apc_param_t ckey; +- apc_param_t cvalue; +- apc_param_t information; +- unsigned int status; +- char __pad_36[4]; +-}; +- +- +- + struct query_completion_request + { + struct request_header __header; +@@ -6107,7 +6090,6 @@ enum request + REQ_open_completion, + REQ_add_completion, + REQ_remove_completion, +- REQ_get_thread_completion, + REQ_query_completion, + REQ_set_completion_info, + REQ_add_fd_completion, +@@ -6404,7 +6386,6 @@ union generic_request + struct open_completion_request open_completion_request; + struct add_completion_request add_completion_request; + struct remove_completion_request remove_completion_request; +- struct get_thread_completion_request get_thread_completion_request; + struct query_completion_request query_completion_request; + struct set_completion_info_request set_completion_info_request; + struct add_fd_completion_request add_fd_completion_request; +@@ -6699,7 +6680,6 @@ union generic_reply + struct open_completion_reply open_completion_reply; + struct add_completion_reply add_completion_reply; + struct remove_completion_reply remove_completion_reply; +- struct get_thread_completion_reply get_thread_completion_reply; + struct query_completion_reply query_completion_reply; + struct set_completion_info_reply set_completion_info_reply; + struct add_fd_completion_reply add_fd_completion_reply; +@@ -6731,7 +6711,7 @@ union generic_reply + + /* ### protocol_version begin ### */ + +-#define SERVER_PROTOCOL_VERSION 845 ++#define SERVER_PROTOCOL_VERSION 844 + + /* ### protocol_version end ### */ + +diff --git a/server/completion.c b/server/completion.c +index f56162aa22d..f00962a306d 100644 +--- a/server/completion.c ++++ b/server/completion.c +@@ -21,6 +21,7 @@ + + /* FIXMEs: + * - built-in wait queues used which means: ++ * + threads are awaken FIFO and not LIFO as native does + * + "max concurrent active threads" parameter not used + * + completion handle is waitable, while native isn't + */ +@@ -55,22 +56,12 @@ struct type_descr completion_type = + }, + }; + +-struct comp_msg +-{ +- struct list queue_entry; +- apc_param_t ckey; +- apc_param_t cvalue; +- apc_param_t information; +- unsigned int status; +-}; +- + struct completion_wait + { + struct object obj; + obj_handle_t handle; + struct completion *completion; + struct thread *thread; +- struct comp_msg *msg; + struct list wait_queue_entry; + }; + +@@ -84,7 +75,6 @@ struct completion + + static void completion_wait_dump( struct object*, int ); + static int completion_wait_signaled( struct object *obj, struct wait_queue_entry *entry ); +-static void completion_wait_satisfied( struct object *obj, struct wait_queue_entry *entry ); + static void completion_wait_destroy( struct object * ); + + static const struct object_ops completion_wait_ops = +@@ -95,7 +85,7 @@ static const struct object_ops completion_wait_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + completion_wait_signaled, /* signaled */ +- completion_wait_satisfied, /* satisfied */ ++ no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ + default_map_access, /* map_access */ +@@ -113,9 +103,6 @@ static const struct object_ops completion_wait_ops = + + static void completion_wait_destroy( struct object *obj ) + { +- struct completion_wait *wait = (struct completion_wait *)obj; +- +- free( wait->msg ); + } + + static void completion_wait_dump( struct object *obj, int verbose ) +@@ -134,22 +121,6 @@ static int completion_wait_signaled( struct object *obj, struct wait_queue_entry + return wait->completion->depth; + } + +-static void completion_wait_satisfied( struct object *obj, struct wait_queue_entry *entry ) +-{ +- struct completion_wait *wait = (struct completion_wait *)obj; +- struct list *msg_entry; +- struct comp_msg *msg; +- +- assert( obj->ops == &completion_wait_ops ); +- msg_entry = list_head( &wait->completion->queue ); +- assert( msg_entry ); +- msg = LIST_ENTRY( msg_entry, struct comp_msg, queue_entry ); +- --wait->completion->depth; +- list_remove( &msg->queue_entry ); +- if (wait->msg) free( wait->msg ); +- wait->msg = msg; +-} +- + static void completion_dump( struct object*, int ); + static int completion_signaled( struct object *obj, struct wait_queue_entry *entry ); + static void completion_destroy( struct object * ); +@@ -178,6 +149,15 @@ static const struct object_ops completion_ops = + completion_destroy /* destroy */ + }; + ++struct comp_msg ++{ ++ struct list queue_entry; ++ apc_param_t ckey; ++ apc_param_t cvalue; ++ apc_param_t information; ++ unsigned int status; ++}; ++ + static void completion_destroy( struct object *obj) + { + struct completion *completion = (struct completion *) obj; +@@ -232,7 +212,6 @@ static struct completion_wait *create_completion_wait( struct thread *thread ) + if (!(wait = alloc_object( &completion_wait_ops ))) return NULL; + wait->completion = NULL; + wait->thread = thread; +- wait->msg = NULL; + if (!(wait->handle = alloc_handle( current->process, wait, SYNCHRONIZE, 0 ))) + { + release_object( &wait->obj ); +@@ -373,25 +352,6 @@ DECL_HANDLER(remove_completion) + release_object( completion ); + } + +-/* get completion after successful waiting for it */ +-DECL_HANDLER(get_thread_completion) +-{ +- struct comp_msg *msg; +- +- if (!current->completion_wait || !(msg = current->completion_wait->msg)) +- { +- set_error( STATUS_INVALID_HANDLE ); +- return; +- } +- +- reply->ckey = msg->ckey; +- reply->cvalue = msg->cvalue; +- reply->status = msg->status; +- reply->information = msg->information; +- free( msg ); +- current->completion_wait->msg = NULL; +-} +- + /* get queue depth for completion port */ + DECL_HANDLER(query_completion) + { +diff --git a/server/protocol.def b/server/protocol.def +index 0ad102283d1..693a20e3437 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3802,16 +3802,6 @@ typedef union + @END + + +-/* get completion after successful wait */ +-@REQ(get_thread_completion) +-@REPLY +- apc_param_t ckey; /* completion key */ +- apc_param_t cvalue; /* completion value */ +- apc_param_t information; /* IO_STATUS_BLOCK Information */ +- unsigned int status; /* completion result */ +-@END +- +- + /* get completion queue depth */ + @REQ(query_completion) + obj_handle_t handle; /* port handle */ +diff --git a/server/request.h b/server/request.h +index 8222fc73dc4..b2679ceae9a 100644 +--- a/server/request.h ++++ b/server/request.h +@@ -381,7 +381,6 @@ DECL_HANDLER(create_completion); + DECL_HANDLER(open_completion); + DECL_HANDLER(add_completion); + DECL_HANDLER(remove_completion); +-DECL_HANDLER(get_thread_completion); + DECL_HANDLER(query_completion); + DECL_HANDLER(set_completion_info); + DECL_HANDLER(add_fd_completion); +@@ -677,7 +676,6 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] = + (req_handler)req_open_completion, + (req_handler)req_add_completion, + (req_handler)req_remove_completion, +- (req_handler)req_get_thread_completion, + (req_handler)req_query_completion, + (req_handler)req_set_completion_info, + (req_handler)req_add_fd_completion, +@@ -2244,12 +2242,6 @@ C_ASSERT( FIELD_OFFSET(struct remove_completion_reply, information) == 24 ); + C_ASSERT( FIELD_OFFSET(struct remove_completion_reply, status) == 32 ); + C_ASSERT( FIELD_OFFSET(struct remove_completion_reply, wait_handle) == 36 ); + C_ASSERT( sizeof(struct remove_completion_reply) == 40 ); +-C_ASSERT( sizeof(struct get_thread_completion_request) == 16 ); +-C_ASSERT( FIELD_OFFSET(struct get_thread_completion_reply, ckey) == 8 ); +-C_ASSERT( FIELD_OFFSET(struct get_thread_completion_reply, cvalue) == 16 ); +-C_ASSERT( FIELD_OFFSET(struct get_thread_completion_reply, information) == 24 ); +-C_ASSERT( FIELD_OFFSET(struct get_thread_completion_reply, status) == 32 ); +-C_ASSERT( sizeof(struct get_thread_completion_reply) == 40 ); + C_ASSERT( FIELD_OFFSET(struct query_completion_request, handle) == 12 ); + C_ASSERT( sizeof(struct query_completion_request) == 16 ); + C_ASSERT( FIELD_OFFSET(struct query_completion_reply, depth) == 8 ); +diff --git a/server/trace.c b/server/trace.c +index a59cf6c5b5f..66ff3000c65 100644 +--- a/server/trace.c ++++ b/server/trace.c +@@ -4530,18 +4530,6 @@ static void dump_remove_completion_reply( const struct remove_completion_reply * + fprintf( stderr, ", wait_handle=%04x", req->wait_handle ); + } + +-static void dump_get_thread_completion_request( const struct get_thread_completion_request *req ) +-{ +-} +- +-static void dump_get_thread_completion_reply( const struct get_thread_completion_reply *req ) +-{ +- dump_uint64( " ckey=", &req->ckey ); +- dump_uint64( ", cvalue=", &req->cvalue ); +- dump_uint64( ", information=", &req->information ); +- fprintf( stderr, ", status=%08x", req->status ); +-} +- + static void dump_query_completion_request( const struct query_completion_request *req ) + { + fprintf( stderr, " handle=%04x", req->handle ); +@@ -5047,7 +5035,6 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = { + (dump_func)dump_open_completion_request, + (dump_func)dump_add_completion_request, + (dump_func)dump_remove_completion_request, +- (dump_func)dump_get_thread_completion_request, + (dump_func)dump_query_completion_request, + (dump_func)dump_set_completion_info_request, + (dump_func)dump_add_fd_completion_request, +@@ -5340,7 +5327,6 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = { + (dump_func)dump_open_completion_reply, + NULL, + (dump_func)dump_remove_completion_reply, +- (dump_func)dump_get_thread_completion_reply, + (dump_func)dump_query_completion_reply, + NULL, + NULL, +@@ -5633,7 +5619,6 @@ static const char * const req_names[REQ_NB_REQUESTS] = { + "open_completion", + "add_completion", + "remove_completion", +- "get_thread_completion", + "query_completion", + "set_completion_info", + "add_fd_completion", +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0006-Revert-ntdll-Introduce-a-separate-per-thread-object-.patch b/0007-proton-esync-fsync/0006-Revert-ntdll-Introduce-a-separate-per-thread-object-.patch new file mode 100644 index 0000000..47354b0 --- /dev/null +++ b/0007-proton-esync-fsync/0006-Revert-ntdll-Introduce-a-separate-per-thread-object-.patch @@ -0,0 +1,375 @@ +From a3bd1d84c1da0759de2757de7f87e8e2808c6fa7 Mon Sep 17 00:00:00 2001 +From: William Horvath +Date: Thu, 24 Oct 2024 11:19:21 -0700 +Subject: [PATCH 6/6] Revert "ntdll: Introduce a separate per-thread object for + internal completion waits." + +This reverts commit e01b70851fae74c9a4067e00f4c48f17f319ed2d. +--- + dlls/ntdll/unix/sync.c | 8 +-- + include/wine/server_protocol.h | 4 +- + server/completion.c | 118 +-------------------------------- + server/file.h | 1 - + server/protocol.def | 1 - + server/request.h | 1 - + server/thread.c | 2 - + server/thread.h | 2 - + server/trace.c | 1 - + 9 files changed, 5 insertions(+), 133 deletions(-) + +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index e4a659f93bb..4269873be6c 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -1999,7 +1999,6 @@ NTSTATUS WINAPI NtSetIoCompletion( HANDLE handle, ULONG_PTR key, ULONG_PTR value + NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR *value, + IO_STATUS_BLOCK *io, LARGE_INTEGER *timeout ) + { +- HANDLE wait_handle = NULL; + unsigned int status; + + TRACE( "(%p, %p, %p, %p, %p)\n", handle, key, value, io, timeout ); +@@ -2016,11 +2015,10 @@ NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR * + io->Information = reply->information; + io->Status = reply->status; + } +- else wait_handle = wine_server_ptr_handle( reply->wait_handle ); + } + SERVER_END_REQ; + if (status != STATUS_PENDING) return status; +- status = NtWaitForSingleObject( wait_handle, FALSE, timeout ); ++ status = NtWaitForSingleObject( handle, FALSE, timeout ); + if (status != WAIT_OBJECT_0) return status; + } + } +@@ -2032,7 +2030,6 @@ NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR * + NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORMATION *info, ULONG count, + ULONG *written, LARGE_INTEGER *timeout, BOOLEAN alertable ) + { +- HANDLE wait_handle = NULL; + unsigned int status; + ULONG i = 0; + +@@ -2052,7 +2049,6 @@ NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORM + info[i].IoStatusBlock.Information = reply->information; + info[i].IoStatusBlock.Status = reply->status; + } +- else wait_handle = wine_server_ptr_handle( reply->wait_handle ); + } + SERVER_END_REQ; + if (status != STATUS_SUCCESS) break; +@@ -2063,7 +2059,7 @@ NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORM + if (status == STATUS_PENDING) status = STATUS_SUCCESS; + break; + } +- status = NtWaitForSingleObject( wait_handle, alertable, timeout ); ++ status = NtWaitForSingleObject( handle, alertable, timeout ); + if (status != WAIT_OBJECT_0) break; + } + *written = i ? i : 1; +diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h +index 15e89227884..ab190e1be2a 100644 +--- a/include/wine/server_protocol.h ++++ b/include/wine/server_protocol.h +@@ -5410,7 +5410,7 @@ struct remove_completion_reply + apc_param_t cvalue; + apc_param_t information; + unsigned int status; +- obj_handle_t wait_handle; ++ char __pad_36[4]; + }; + + +@@ -6711,7 +6711,7 @@ union generic_reply + + /* ### protocol_version begin ### */ + +-#define SERVER_PROTOCOL_VERSION 844 ++#define SERVER_PROTOCOL_VERSION 843 + + /* ### protocol_version end ### */ + +diff --git a/server/completion.c b/server/completion.c +index f00962a306d..6933195e72d 100644 +--- a/server/completion.c ++++ b/server/completion.c +@@ -56,71 +56,13 @@ struct type_descr completion_type = + }, + }; + +-struct completion_wait +-{ +- struct object obj; +- obj_handle_t handle; +- struct completion *completion; +- struct thread *thread; +- struct list wait_queue_entry; +-}; +- + struct completion + { + struct object obj; + struct list queue; +- struct list wait_queue; + unsigned int depth; + }; + +-static void completion_wait_dump( struct object*, int ); +-static int completion_wait_signaled( struct object *obj, struct wait_queue_entry *entry ); +-static void completion_wait_destroy( struct object * ); +- +-static const struct object_ops completion_wait_ops = +-{ +- sizeof(struct completion_wait), /* size */ +- &no_type, /* type */ +- completion_wait_dump, /* dump */ +- add_queue, /* add_queue */ +- remove_queue, /* remove_queue */ +- completion_wait_signaled, /* signaled */ +- no_satisfied, /* satisfied */ +- no_signal, /* signal */ +- no_get_fd, /* get_fd */ +- default_map_access, /* map_access */ +- default_get_sd, /* get_sd */ +- default_set_sd, /* set_sd */ +- no_get_full_name, /* get_full_name */ +- no_lookup_name, /* lookup_name */ +- no_link_name, /* link_name */ +- NULL, /* unlink_name */ +- no_open_file, /* open_file */ +- no_kernel_obj_list, /* get_kernel_obj_list */ +- no_close_handle, /* close_handle */ +- completion_wait_destroy /* destroy */ +-}; +- +-static void completion_wait_destroy( struct object *obj ) +-{ +-} +- +-static void completion_wait_dump( struct object *obj, int verbose ) +-{ +- struct completion_wait *wait = (struct completion_wait *)obj; +- +- assert( obj->ops == &completion_wait_ops ); +- fprintf( stderr, "Completion wait completion=%p\n", wait->completion ); +-} +- +-static int completion_wait_signaled( struct object *obj, struct wait_queue_entry *entry ) +-{ +- struct completion_wait *wait = (struct completion_wait *)obj; +- +- assert( obj->ops == &completion_wait_ops ); +- return wait->completion->depth; +-} +- + static void completion_dump( struct object*, int ); + static int completion_signaled( struct object *obj, struct wait_queue_entry *entry ); + static void completion_destroy( struct object * ); +@@ -161,19 +103,12 @@ struct comp_msg + static void completion_destroy( struct object *obj) + { + struct completion *completion = (struct completion *) obj; +- struct completion_wait *wait, *wait_next; + struct comp_msg *tmp, *next; + + LIST_FOR_EACH_ENTRY_SAFE( tmp, next, &completion->queue, struct comp_msg, queue_entry ) + { + free( tmp ); + } +- +- LIST_FOR_EACH_ENTRY_SAFE( wait, wait_next, &completion->wait_queue, struct completion_wait, wait_queue_entry ) +- { +- assert( wait->completion ); +- cleanup_thread_completion( wait->thread ); +- } + } + + static void completion_dump( struct object *obj, int verbose ) +@@ -191,35 +126,6 @@ static int completion_signaled( struct object *obj, struct wait_queue_entry *ent + return !list_empty( &completion->queue ); + } + +-void cleanup_thread_completion( struct thread *thread ) +-{ +- if (!thread->completion_wait) return; +- +- if (thread->completion_wait->handle) +- { +- close_handle( thread->process, thread->completion_wait->handle ); +- thread->completion_wait->handle = 0; +- } +- list_remove( &thread->completion_wait->wait_queue_entry ); +- release_object( &thread->completion_wait->obj ); +- thread->completion_wait = NULL; +-} +- +-static struct completion_wait *create_completion_wait( struct thread *thread ) +-{ +- struct completion_wait *wait; +- +- if (!(wait = alloc_object( &completion_wait_ops ))) return NULL; +- wait->completion = NULL; +- wait->thread = thread; +- if (!(wait->handle = alloc_handle( current->process, wait, SYNCHRONIZE, 0 ))) +- { +- release_object( &wait->obj ); +- return NULL; +- } +- return wait; +-} +- + static struct completion *create_completion( struct object *root, const struct unicode_str *name, + unsigned int attr, unsigned int concurrent, + const struct security_descriptor *sd ) +@@ -231,7 +137,6 @@ static struct completion *create_completion( struct object *root, const struct u + if (get_error() != STATUS_OBJECT_NAME_EXISTS) + { + list_init( &completion->queue ); +- list_init( &completion->wait_queue ); + completion->depth = 0; + } + } +@@ -248,7 +153,6 @@ void add_completion( struct completion *completion, apc_param_t ckey, apc_param_ + unsigned int status, apc_param_t information ) + { + struct comp_msg *msg = mem_alloc( sizeof( *msg ) ); +- struct completion_wait *wait; + + if (!msg) + return; +@@ -260,12 +164,7 @@ void add_completion( struct completion *completion, apc_param_t ckey, apc_param_ + + list_add_tail( &completion->queue, &msg->queue_entry ); + completion->depth++; +- LIST_FOR_EACH_ENTRY( wait, &completion->wait_queue, struct completion_wait, wait_queue_entry ) +- { +- wake_up( &wait->obj, 1 ); +- if (list_empty( &completion->queue )) return; +- } +- if (!list_empty( &completion->queue )) wake_up( &completion->obj, 0 ); ++ wake_up( &completion->obj, 1 ); + } + + /* create a completion */ +@@ -320,22 +219,8 @@ DECL_HANDLER(remove_completion) + if (!completion) return; + + entry = list_head( &completion->queue ); +- if (current->completion_wait) +- { +- list_remove( ¤t->completion_wait->wait_queue_entry ); +- } +- else if (!(current->completion_wait = create_completion_wait( current ))) +- { +- release_object( completion ); +- return; +- } +- current->completion_wait->completion = completion; +- list_add_head( &completion->wait_queue, ¤t->completion_wait->wait_queue_entry ); + if (!entry) +- { +- reply->wait_handle = current->completion_wait->handle; + set_error( STATUS_PENDING ); +- } + else + { + list_remove( entry ); +@@ -346,7 +231,6 @@ DECL_HANDLER(remove_completion) + reply->status = msg->status; + reply->information = msg->information; + free( msg ); +- reply->wait_handle = 0; + } + + release_object( completion ); +diff --git a/server/file.h b/server/file.h +index 3d7cdc460ff..f486f823f25 100644 +--- a/server/file.h ++++ b/server/file.h +@@ -238,7 +238,6 @@ extern struct dir *get_dir_obj( struct process *process, obj_handle_t handle, un + extern struct completion *get_completion_obj( struct process *process, obj_handle_t handle, unsigned int access ); + extern void add_completion( struct completion *completion, apc_param_t ckey, apc_param_t cvalue, + unsigned int status, apc_param_t information ); +-extern void cleanup_thread_completion( struct thread *thread ); + + /* serial port functions */ + +diff --git a/server/protocol.def b/server/protocol.def +index 693a20e3437..a4f25e805f8 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3798,7 +3798,6 @@ typedef union + apc_param_t cvalue; /* completion value */ + apc_param_t information; /* IO_STATUS_BLOCK Information */ + unsigned int status; /* completion result */ +- obj_handle_t wait_handle; /* handle to completion wait internal object */ + @END + + +diff --git a/server/request.h b/server/request.h +index b2679ceae9a..9e1bdf403ea 100644 +--- a/server/request.h ++++ b/server/request.h +@@ -2240,7 +2240,6 @@ C_ASSERT( FIELD_OFFSET(struct remove_completion_reply, ckey) == 8 ); + C_ASSERT( FIELD_OFFSET(struct remove_completion_reply, cvalue) == 16 ); + C_ASSERT( FIELD_OFFSET(struct remove_completion_reply, information) == 24 ); + C_ASSERT( FIELD_OFFSET(struct remove_completion_reply, status) == 32 ); +-C_ASSERT( FIELD_OFFSET(struct remove_completion_reply, wait_handle) == 36 ); + C_ASSERT( sizeof(struct remove_completion_reply) == 40 ); + C_ASSERT( FIELD_OFFSET(struct query_completion_request, handle) == 12 ); + C_ASSERT( sizeof(struct query_completion_request) == 16 ); +diff --git a/server/thread.c b/server/thread.c +index f3880eebedb..6542e1584ab 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -249,7 +249,6 @@ static inline void init_thread_structure( struct thread *thread ) + + thread->creation_time = current_time; + thread->exit_time = 0; +- thread->completion_wait = NULL; + + list_init( &thread->mutex_list ); + list_init( &thread->system_apc ); +@@ -403,7 +402,6 @@ static void cleanup_thread( struct thread *thread ) + { + int i; + +- cleanup_thread_completion( thread ); + if (thread->context) + { + thread->context->status = STATUS_ACCESS_DENIED; +diff --git a/server/thread.h b/server/thread.h +index 3448f332b0b..766ed78a72f 100644 +--- a/server/thread.h ++++ b/server/thread.h +@@ -31,7 +31,6 @@ struct thread_apc; + struct debug_obj; + struct debug_event; + struct msg_queue; +-struct completion_wait; + + enum run_state + { +@@ -92,7 +91,6 @@ struct thread + struct list kernel_object; /* list of kernel object pointers */ + data_size_t desc_len; /* thread description length in bytes */ + WCHAR *desc; /* thread description string */ +- struct completion_wait *completion_wait; /* completion port wait object the thread is associated with */ + struct timeout_user *exit_poll; /* poll if the thread/process has exited already */ + }; + +diff --git a/server/trace.c b/server/trace.c +index 66ff3000c65..a108043ea8d 100644 +--- a/server/trace.c ++++ b/server/trace.c +@@ -4527,7 +4527,6 @@ static void dump_remove_completion_reply( const struct remove_completion_reply * + dump_uint64( ", cvalue=", &req->cvalue ); + dump_uint64( ", information=", &req->information ); + fprintf( stderr, ", status=%08x", req->status ); +- fprintf( stderr, ", wait_handle=%04x", req->wait_handle ); + } + + static void dump_query_completion_request( const struct query_completion_request *req ) +-- +2.47.0 + diff --git a/0007-ntsync/0000-create-hacks-init.patch b/0007-proton-esync-fsync/0007-create-hacks-init.patch similarity index 100% rename from 0007-ntsync/0000-create-hacks-init.patch rename to 0007-proton-esync-fsync/0007-create-hacks-init.patch diff --git a/0007-proton-esync-fsync/0008-configure-Check-for-sys-eventfd.h-ppoll-and-shm_open.patch b/0007-proton-esync-fsync/0008-configure-Check-for-sys-eventfd.h-ppoll-and-shm_open.patch new file mode 100644 index 0000000..2895a33 --- /dev/null +++ b/0007-proton-esync-fsync/0008-configure-Check-for-sys-eventfd.h-ppoll-and-shm_open.patch @@ -0,0 +1,85 @@ +From 6dbedd8d7aebe117b013c61f9549848f13619f0e Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Wed, 13 Jun 2018 10:44:49 -0500 +Subject: [PATCH] configure: Check for sys/eventfd.h, ppoll(), and shm_open(). + +We use ppoll() instead of poll() for the better time granularity. + +Although perhaps we shouldn't since the server doesn't do this. +--- + configure.ac | 8 ++++++++ + include/config.h.in | 11 ++++++++++- + 2 files changed, 18 insertions(+), 1 deletion(-) + +diff --git a/configure.ac b/configure.ac +index 67775f9cd15..c03d4c3688b 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -407,6 +407,7 @@ AC_CHECK_HEADERS(\ + sys/cdio.h \ + sys/epoll.h \ + sys/event.h \ ++ sys/eventfd.h \ + sys/extattr.h \ + sys/filio.h \ + sys/ipc.h \ +@@ -2067,6 +2068,7 @@ AC_CHECK_FUNCS(\ + port_create \ + posix_fadvise \ + posix_fallocate \ ++ ppoll \ + prctl \ + sched_yield \ + renameat \ +@@ -2087,6 +2089,12 @@ AC_SEARCH_LIBS(clock_gettime, rt, + test "$ac_res" = "none required" || AC_SUBST(RT_LIBS,"$ac_res")]) + LIBS=$ac_save_LIBS + ++ac_save_LIBS=$LIBS ++AC_SEARCH_LIBS(shm_open, rt, ++ [AC_DEFINE(HAVE_SHM_OPEN, 1, [Define to 1 if you have the `shm_open' function.]) ++ test "$ac_res" = "none required" || AC_SUBST(RT_LIBS,"$ac_res")]) ++LIBS=$ac_save_LIBS ++ + AC_CACHE_CHECK([for sched_setaffinity],wine_cv_have_sched_setaffinity, + AC_LINK_IFELSE([AC_LANG_PROGRAM( + [[#include ]], [[sched_setaffinity(0, 0, 0);]])],[wine_cv_have_sched_setaffinity=yes],[wine_cv_have_sched_setaffinity=no])) +diff --git a/include/config.h.in b/include/config.h.in +index 1c3d4c4d62b..e9686e04a2a 100644 +--- a/include/config.h.in ++++ b/include/config.h.in +@@ -318,6 +318,9 @@ + /* Define to 1 if you have the 'posix_fallocate' function. */ + #undef HAVE_POSIX_FALLOCATE + ++/* Define to 1 if you have the `ppoll' function. */ ++#undef HAVE_PPOLL ++ + /* Define to 1 if you have the 'prctl' function. */ + #undef HAVE_PRCTL + +@@ -375,7 +378,10 @@ + /* Define to 1 if 'interface_id' is a member of 'sg_io_hdr_t'. */ + #undef HAVE_SG_IO_HDR_T_INTERFACE_ID + +-/* Define to 1 if 'si_fd' is a member of 'siginfo_t'. */ ++/* Define to 1 if you have the `shm_open' function. */ ++#undef HAVE_SHM_OPEN ++ ++/* Define to 1 if `si_fd' is a member of `siginfo_t'. */ + #undef HAVE_SIGINFO_T_SI_FD + + /* Define to 1 if you have the 'sigprocmask' function. */ +@@ -504,6 +510,9 @@ + /* Define to 1 if you have the header file. */ + #undef HAVE_SYS_EPOLL_H + ++/* Define to 1 if you have the header file. */ ++#undef HAVE_SYS_EVENTFD_H ++ + /* Define to 1 if you have the header file. */ + #undef HAVE_SYS_EVENT_H + +-- +2.45.2 + diff --git a/0007-proton-esync-fsync/0009-server-Create-server-objects-for-eventfd-based-synch.patch b/0007-proton-esync-fsync/0009-server-Create-server-objects-for-eventfd-based-synch.patch new file mode 100644 index 0000000..4e17b1e --- /dev/null +++ b/0007-proton-esync-fsync/0009-server-Create-server-objects-for-eventfd-based-synch.patch @@ -0,0 +1,448 @@ +From 41923549a7e5abfbe13fc4a4578bf6247510c2a3 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Thu, 7 Jun 2018 20:09:59 -0500 +Subject: [PATCH 0429/2346] server: Create server objects for eventfd-based + synchronization objects. + +Wine-Staging: eventfd_synchronization +--- + server/Makefile.in | 1 + + server/esync.c | 318 ++++++++++++++++++++++++++++++++++++++++++++ + server/esync.h | 24 ++++ + server/main.c | 4 + + server/protocol.def | 25 +++- + 5 files changed, 371 insertions(+), 1 deletion(-) + create mode 100644 server/esync.c + create mode 100644 server/esync.h + +diff --git a/server/Makefile.in b/server/Makefile.in +index 7b46b924c46..79d05f2318c 100644 +--- a/server/Makefile.in ++++ b/server/Makefile.in +@@ -11,6 +11,7 @@ SOURCES = \ + debugger.c \ + device.c \ + directory.c \ ++ esync.c \ + event.c \ + fd.c \ + file.c \ +diff --git a/server/esync.c b/server/esync.c +new file mode 100644 +index 00000000000..35b4833fd4c +--- /dev/null ++++ b/server/esync.c +@@ -0,0 +1,318 @@ ++/* ++ * eventfd-based synchronization objects ++ * ++ * Copyright (C) 2018 Zebediah Figura ++ * ++ * 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 ++ */ ++ ++#include "config.h" ++ ++ ++#include ++#include ++#include ++#ifdef HAVE_SYS_EVENTFD_H ++# include ++#endif ++#include ++#ifdef HAVE_SYS_STAT_H ++# include ++#endif ++#include ++ ++#include "ntstatus.h" ++#define WIN32_NO_STATUS ++#include "windef.h" ++#include "winternl.h" ++ ++#include "handle.h" ++#include "request.h" ++#include "file.h" ++ ++int do_esync(void) ++{ ++#ifdef HAVE_SYS_EVENTFD_H ++ static int do_esync_cached = -1; ++ ++ if (do_esync_cached == -1) ++ do_esync_cached = getenv("WINEESYNC") && atoi(getenv("WINEESYNC")); ++ ++ return do_esync_cached; ++#else ++ return 0; ++#endif ++} ++ ++static char shm_name[29]; ++static int shm_fd; ++static off_t shm_size; ++static void **shm_addrs; ++static int shm_addrs_size; /* length of the allocated shm_addrs array */ ++static long pagesize; ++ ++static void shm_cleanup(void) ++{ ++ close( shm_fd ); ++ if (shm_unlink( shm_name ) == -1) ++ perror( "shm_unlink" ); ++} ++ ++void esync_init(void) ++{ ++ struct stat st; ++ ++ if (fstat( config_dir_fd, &st ) == -1) ++ fatal_error( "cannot stat config dir\n" ); ++ ++ if (st.st_ino != (unsigned long)st.st_ino) ++ sprintf( shm_name, "/wine-%lx%08lx-esync", (unsigned long)((unsigned long long)st.st_ino >> 32), (unsigned long)st.st_ino ); ++ else ++ sprintf( shm_name, "/wine-%lx-esync", (unsigned long)st.st_ino ); ++ ++ shm_unlink( shm_name ); ++ ++ shm_fd = shm_open( shm_name, O_RDWR | O_CREAT | O_EXCL, 0644 ); ++ if (shm_fd == -1) ++ perror( "shm_open" ); ++ ++ pagesize = sysconf( _SC_PAGESIZE ); ++ ++ shm_addrs = calloc( 128, sizeof(shm_addrs[0]) ); ++ shm_addrs_size = 128; ++ ++ shm_size = pagesize; ++ if (ftruncate( shm_fd, shm_size ) == -1) ++ perror( "ftruncate" ); ++ ++ fprintf( stderr, "esync: up and running.\n" ); ++ ++ atexit( shm_cleanup ); ++} ++ ++struct esync ++{ ++ struct object obj; /* object header */ ++ int fd; /* eventfd file descriptor */ ++ enum esync_type type; ++ unsigned int shm_idx; /* index into the shared memory section */ ++}; ++ ++static void esync_dump( struct object *obj, int verbose ); ++static void esync_destroy( struct object *obj ); ++ ++static const struct object_ops esync_ops = ++{ ++ sizeof(struct esync), /* size */ ++ &no_type, /* type */ ++ esync_dump, /* dump */ ++ no_add_queue, /* add_queue */ ++ NULL, /* remove_queue */ ++ NULL, /* signaled */ ++ NULL, /* satisfied */ ++ no_signal, /* signal */ ++ no_get_fd, /* get_fd */ ++ default_map_access, /* map_access */ ++ default_get_sd, /* get_sd */ ++ default_set_sd, /* set_sd */ ++ default_get_full_name, /* get_full_name */ ++ no_lookup_name, /* lookup_name */ ++ directory_link_name, /* link_name */ ++ default_unlink_name, /* unlink_name */ ++ no_open_file, /* open_file */ ++ no_kernel_obj_list, /* get_kernel_obj_list */ ++ no_close_handle, /* close_handle */ ++ esync_destroy /* destroy */ ++}; ++ ++static void esync_dump( struct object *obj, int verbose ) ++{ ++ struct esync *esync = (struct esync *)obj; ++ assert( obj->ops == &esync_ops ); ++ fprintf( stderr, "esync fd=%d\n", esync->fd ); ++} ++ ++static void esync_destroy( struct object *obj ) ++{ ++ struct esync *esync = (struct esync *)obj; ++ close( esync->fd ); ++} ++ ++static int type_matches( enum esync_type type1, enum esync_type type2 ) ++{ ++ return (type1 == type2) || ++ ((type1 == ESYNC_AUTO_EVENT || type1 == ESYNC_MANUAL_EVENT) && ++ (type2 == ESYNC_AUTO_EVENT || type2 == ESYNC_MANUAL_EVENT)); ++} ++ ++static void *get_shm( unsigned int idx ) ++{ ++ int entry = (idx * 8) / pagesize; ++ int offset = (idx * 8) % pagesize; ++ ++ if (entry >= shm_addrs_size) ++ { ++ int new_size = max(shm_addrs_size * 2, entry + 1); ++ ++ if (!(shm_addrs = realloc( shm_addrs, new_size * sizeof(shm_addrs[0]) ))) ++ fprintf( stderr, "esync: couldn't expand shm_addrs array to size %d\n", entry + 1 ); ++ ++ memset( shm_addrs + shm_addrs_size, 0, (new_size - shm_addrs_size) * sizeof(shm_addrs[0]) ); ++ ++ shm_addrs_size = new_size; ++ } ++ ++ if (!shm_addrs[entry]) ++ { ++ void *addr = mmap( NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, entry * pagesize ); ++ if (addr == (void *)-1) ++ { ++ fprintf( stderr, "esync: failed to map page %d (offset %#lx): ", entry, entry * pagesize ); ++ perror( "mmap" ); ++ } ++ ++ if (debug_level) ++ fprintf( stderr, "esync: Mapping page %d at %p.\n", entry, addr ); ++ ++ if (__sync_val_compare_and_swap( &shm_addrs[entry], 0, addr )) ++ munmap( addr, pagesize ); /* someone beat us to it */ ++ } ++ ++ return (void *)((unsigned long)shm_addrs[entry] + offset); ++} ++ ++struct semaphore ++{ ++ int max; ++ int count; ++}; ++C_ASSERT(sizeof(struct semaphore) == 8); ++ ++struct esync *create_esync( struct object *root, const struct unicode_str *name, ++ unsigned int attr, int initval, int max, enum esync_type type, ++ const struct security_descriptor *sd ) ++{ ++#ifdef HAVE_SYS_EVENTFD_H ++ struct esync *esync; ++ ++ if ((esync = create_named_object( root, &esync_ops, name, attr, sd ))) ++ { ++ if (get_error() != STATUS_OBJECT_NAME_EXISTS) ++ { ++ int flags = EFD_CLOEXEC | EFD_NONBLOCK; ++ ++ if (type == ESYNC_SEMAPHORE) ++ flags |= EFD_SEMAPHORE; ++ ++ /* initialize it if it didn't already exist */ ++ esync->fd = eventfd( initval, flags ); ++ if (esync->fd == -1) ++ { ++ perror( "eventfd" ); ++ file_set_error(); ++ release_object( esync ); ++ return NULL; ++ } ++ esync->type = type; ++ ++ /* Use the fd as index, since that'll be unique across all ++ * processes, but should hopefully end up also allowing reuse. */ ++ esync->shm_idx = esync->fd + 1; /* we keep index 0 reserved */ ++ while (esync->shm_idx * 8 >= shm_size) ++ { ++ /* Better expand the shm section. */ ++ shm_size += pagesize; ++ if (ftruncate( shm_fd, shm_size ) == -1) ++ { ++ fprintf( stderr, "esync: couldn't expand %s to size %ld: ", ++ shm_name, (long)shm_size ); ++ perror( "ftruncate" ); ++ } ++ } ++ ++ /* Initialize the shared memory portion. We want to do this on the ++ * server side to avoid a potential though unlikely race whereby ++ * the same object is opened and used between the time it's created ++ * and the time its shared memory portion is initialized. */ ++ switch (type) ++ { ++ case ESYNC_SEMAPHORE: ++ { ++ struct semaphore *semaphore = get_shm( esync->shm_idx ); ++ semaphore->max = max; ++ semaphore->count = initval; ++ break; ++ } ++ default: ++ assert( 0 ); ++ } ++ } ++ else ++ { ++ /* validate the type */ ++ if (!type_matches( type, esync->type )) ++ { ++ release_object( &esync->obj ); ++ set_error( STATUS_OBJECT_TYPE_MISMATCH ); ++ return NULL; ++ } ++ } ++ } ++ return esync; ++#else ++ /* FIXME: Provide a fallback implementation using pipe(). */ ++ set_error( STATUS_NOT_IMPLEMENTED ); ++ return NULL; ++#endif ++} ++ ++DECL_HANDLER(create_esync) ++{ ++ struct esync *esync; ++ struct unicode_str name; ++ struct object *root; ++ const struct security_descriptor *sd; ++ const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root ); ++ ++ if (!do_esync()) ++ { ++ set_error( STATUS_NOT_IMPLEMENTED ); ++ return; ++ } ++ ++ if (!req->type) ++ { ++ set_error( STATUS_INVALID_PARAMETER ); ++ return; ++ } ++ ++ if (!objattr) return; ++ ++ if ((esync = create_esync( root, &name, objattr->attributes, req->initval, req->max, req->type, sd ))) ++ { ++ if (get_error() == STATUS_OBJECT_NAME_EXISTS) ++ reply->handle = alloc_handle( current->process, esync, req->access, objattr->attributes ); ++ else ++ reply->handle = alloc_handle_no_access_check( current->process, esync, ++ req->access, objattr->attributes ); ++ ++ reply->type = esync->type; ++ reply->shm_idx = esync->shm_idx; ++ send_client_fd( current->process, esync->fd, reply->handle ); ++ release_object( esync ); ++ } ++ ++ if (root) release_object( root ); ++} +diff --git a/server/esync.h b/server/esync.h +new file mode 100644 +index 00000000000..00f9e638d83 +--- /dev/null ++++ b/server/esync.h +@@ -0,0 +1,24 @@ ++/* ++ * eventfd-based synchronization objects ++ * ++ * Copyright (C) 2018 Zebediah Figura ++ * ++ * 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 ++ */ ++ ++#include ++ ++extern int do_esync(void); ++void esync_init(void); +diff --git a/server/main.c b/server/main.c +index e2ae1bcaabc..c4bb790db8a 100644 +--- a/server/main.c ++++ b/server/main.c +@@ -34,6 +34,7 @@ + #include "thread.h" + #include "request.h" + #include "unicode.h" ++#include "esync.h" + + /* command-line options */ + int debug_level = 0; +@@ -229,6 +230,9 @@ int main( int argc, char *argv[] ) + sock_init(); + open_master_socket(); + ++ if (do_esync()) ++ esync_init(); ++ + if (debug_level) fprintf( stderr, "wineserver: starting (pid=%ld)\n", (long) getpid() ); + set_current_time(); + init_signals(); +diff --git a/server/protocol.def b/server/protocol.def +index 4051b8d25d4..a9fb8a2ede0 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3928,7 +3928,6 @@ struct handle_info + obj_handle_t handle; /* process handle */ + @END + +- + /* Iterate thread list for process */ + @REQ(get_next_thread) + obj_handle_t process; /* process handle */ +@@ -3939,3 +3938,27 @@ struct handle_info + @REPLY + obj_handle_t handle; /* next thread handle */ + @END ++ ++enum esync_type ++{ ++ ESYNC_SEMAPHORE = 1, ++ ESYNC_AUTO_EVENT, ++ ESYNC_MANUAL_EVENT, ++ ESYNC_MUTEX, ++ ESYNC_AUTO_SERVER, ++ ESYNC_MANUAL_SERVER, ++ ESYNC_QUEUE, ++}; ++ ++/* Create a new eventfd-based synchronization object */ ++@REQ(create_esync) ++ unsigned int access; /* wanted access rights */ ++ int initval; /* initial value */ ++ int type; /* type of esync object */ ++ int max; /* maximum count on a semaphore */ ++ VARARG(objattr,object_attributes); /* object attributes */ ++@REPLY ++ obj_handle_t handle; /* handle to the object */ ++ int type; /* actual type (may be different for events) */ ++ unsigned int shm_idx; ++@END +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0010-ntdll-Create-eventfd-based-objects-for-semaphores.patch b/0007-proton-esync-fsync/0010-ntdll-Create-eventfd-based-objects-for-semaphores.patch new file mode 100644 index 0000000..321932c --- /dev/null +++ b/0007-proton-esync-fsync/0010-ntdll-Create-eventfd-based-objects-for-semaphores.patch @@ -0,0 +1,426 @@ +From ebfe11c9ea76eb1ec1d04b6aa3a103df58a73d0e Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 12:09:22 -0500 +Subject: [PATCH 0430/2346] ntdll: Create eventfd-based objects for semaphores. + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/Makefile.in | 1 + + dlls/ntdll/unix/esync.c | 270 +++++++++++++++++++++++++++++++++++++++ + dlls/ntdll/unix/esync.h | 35 +++++ + dlls/ntdll/unix/loader.c | 2 + + dlls/ntdll/unix/server.c | 4 +- + dlls/ntdll/unix/sync.c | 4 + + server/esync.c | 1 + + 7 files changed, 315 insertions(+), 2 deletions(-) + create mode 100644 dlls/ntdll/unix/esync.c + create mode 100644 dlls/ntdll/unix/esync.h + +diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in +index d3f2a0e5523..70fac547c57 100644 +--- a/dlls/ntdll/Makefile.in ++++ b/dlls/ntdll/Makefile.in +@@ -48,6 +48,7 @@ SOURCES = \ + unix/cdrom.c \ + unix/debug.c \ + unix/env.c \ ++ unix/esync.c \ + unix/file.c \ + unix/loader.c \ + unix/loadorder.c \ +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +new file mode 100644 +index 00000000000..89b8542433e +--- /dev/null ++++ b/dlls/ntdll/unix/esync.c +@@ -0,0 +1,270 @@ ++/* ++ * eventfd-based synchronization objects ++ * ++ * Copyright (C) 2018 Zebediah Figura ++ * ++ * 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 ++ */ ++ ++#if 0 ++#pragma makedep unix ++#endif ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef HAVE_SYS_STAT_H ++# include ++#endif ++#include ++#include ++ ++#include "ntstatus.h" ++#define WIN32_NO_STATUS ++#include "windef.h" ++#include "winternl.h" ++#include "wine/server.h" ++#include "wine/debug.h" ++ ++#include "unix_private.h" ++#include "esync.h" ++ ++WINE_DEFAULT_DEBUG_CHANNEL(esync); ++ ++int do_esync(void) ++{ ++#ifdef HAVE_SYS_EVENTFD_H ++ static int do_esync_cached = -1; ++ ++ if (do_esync_cached == -1) ++ do_esync_cached = getenv("WINEESYNC") && atoi(getenv("WINEESYNC")); ++ ++ return do_esync_cached; ++#else ++ static int once; ++ if (!once++) ++ FIXME("eventfd not supported on this platform.\n"); ++ return 0; ++#endif ++} ++ ++struct esync ++{ ++ enum esync_type type; ++ int fd; ++ void *shm; ++}; ++ ++struct semaphore ++{ ++ int max; ++ int count; ++}; ++C_ASSERT(sizeof(struct semaphore) == 8); ++ ++static char shm_name[29]; ++static int shm_fd; ++static void **shm_addrs; ++static int shm_addrs_size; /* length of the allocated shm_addrs array */ ++static long pagesize; ++ ++static pthread_mutex_t shm_addrs_mutex = PTHREAD_MUTEX_INITIALIZER; ++ ++static void *get_shm( unsigned int idx ) ++{ ++ int entry = (idx * 8) / pagesize; ++ int offset = (idx * 8) % pagesize; ++ void *ret; ++ ++ pthread_mutex_lock( &shm_addrs_mutex ); ++ ++ if (entry >= shm_addrs_size) ++ { ++ int new_size = max(shm_addrs_size * 2, entry + 1); ++ ++ if (!(shm_addrs = realloc( shm_addrs, new_size * sizeof(shm_addrs[0]) ))) ++ ERR("Failed to grow shm_addrs array to size %d.\n", shm_addrs_size); ++ memset( shm_addrs + shm_addrs_size, 0, (new_size - shm_addrs_size) * sizeof(shm_addrs[0]) ); ++ shm_addrs_size = new_size; ++ } ++ ++ if (!shm_addrs[entry]) ++ { ++ void *addr = mmap( NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, entry * pagesize ); ++ if (addr == (void *)-1) ++ ERR("Failed to map page %d (offset %#lx).\n", entry, entry * pagesize); ++ ++ TRACE("Mapping page %d at %p.\n", entry, addr); ++ ++ if (InterlockedCompareExchangePointer( &shm_addrs[entry], addr, 0 )) ++ munmap( addr, pagesize ); /* someone beat us to it */ ++ } ++ ++ ret = (void *)((unsigned long)shm_addrs[entry] + offset); ++ ++ pthread_mutex_unlock( &shm_addrs_mutex ); ++ ++ return ret; ++} ++ ++/* We'd like lookup to be fast. To that end, we use a static list indexed by handle. ++ * This is copied and adapted from the fd cache code. */ ++ ++#define ESYNC_LIST_BLOCK_SIZE (65536 / sizeof(struct esync)) ++#define ESYNC_LIST_ENTRIES 256 ++ ++static struct esync *esync_list[ESYNC_LIST_ENTRIES]; ++static struct esync esync_list_initial_block[ESYNC_LIST_BLOCK_SIZE]; ++ ++static inline UINT_PTR handle_to_index( HANDLE handle, UINT_PTR *entry ) ++{ ++ UINT_PTR idx = (((UINT_PTR)handle) >> 2) - 1; ++ *entry = idx / ESYNC_LIST_BLOCK_SIZE; ++ return idx % ESYNC_LIST_BLOCK_SIZE; ++} ++ ++static struct esync *add_to_list( HANDLE handle, enum esync_type type, int fd, void *shm ) ++{ ++ UINT_PTR entry, idx = handle_to_index( handle, &entry ); ++ ++ if (entry >= ESYNC_LIST_ENTRIES) ++ { ++ FIXME( "too many allocated handles, not caching %p\n", handle ); ++ return FALSE; ++ } ++ ++ if (!esync_list[entry]) /* do we need to allocate a new block of entries? */ ++ { ++ if (!entry) esync_list[0] = esync_list_initial_block; ++ else ++ { ++ void *ptr = anon_mmap_alloc( ESYNC_LIST_BLOCK_SIZE * sizeof(struct esync), ++ PROT_READ | PROT_WRITE ); ++ if (ptr == MAP_FAILED) return FALSE; ++ esync_list[entry] = ptr; ++ } ++ } ++ ++ if (!InterlockedCompareExchange( (LONG *)&esync_list[entry][idx].type, type, 0 )) ++ { ++ esync_list[entry][idx].fd = fd; ++ esync_list[entry][idx].shm = shm; ++ } ++ return &esync_list[entry][idx]; ++} ++ ++static NTSTATUS create_esync( enum esync_type type, HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr, int initval, int max ) ++{ ++ NTSTATUS ret; ++ data_size_t len; ++ struct object_attributes *objattr; ++ obj_handle_t fd_handle; ++ unsigned int shm_idx; ++ sigset_t sigset; ++ int fd; ++ ++ if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; ++ ++ /* We have to synchronize on the fd cache CS so that our calls to ++ * receive_fd don't race with theirs. */ ++ server_enter_uninterrupted_section( &fd_cache_mutex, &sigset ); ++ SERVER_START_REQ( create_esync ) ++ { ++ req->access = access; ++ req->initval = initval; ++ req->type = type; ++ req->max = max; ++ wine_server_add_data( req, objattr, len ); ++ ret = wine_server_call( req ); ++ if (!ret || ret == STATUS_OBJECT_NAME_EXISTS) ++ { ++ *handle = wine_server_ptr_handle( reply->handle ); ++ type = reply->type; ++ shm_idx = reply->shm_idx; ++ fd = receive_fd( &fd_handle ); ++ assert( wine_server_ptr_handle(fd_handle) == *handle ); ++ } ++ } ++ SERVER_END_REQ; ++ server_leave_uninterrupted_section( &fd_cache_mutex, &sigset ); ++ ++ if (!ret || ret == STATUS_OBJECT_NAME_EXISTS) ++ { ++ add_to_list( *handle, type, fd, shm_idx ? get_shm( shm_idx ) : 0 ); ++ TRACE("-> handle %p, fd %d.\n", *handle, fd); ++ } ++ ++ free( objattr ); ++ return ret; ++} ++ ++extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max) ++{ ++ TRACE("name %s, initial %d, max %d.\n", ++ attr ? debugstr_us(attr->ObjectName) : "", (int)initial, (int)max); ++ ++ return create_esync( ESYNC_SEMAPHORE, handle, access, attr, initial, max ); ++} ++ ++void esync_init(void) ++{ ++ struct stat st; ++ ++ if (!do_esync()) ++ { ++ /* make sure the server isn't running with WINEESYNC */ ++ HANDLE handle; ++ NTSTATUS ret; ++ ++ ret = create_esync( 0, &handle, 0, NULL, 0, 0 ); ++ if (ret != STATUS_NOT_IMPLEMENTED) ++ { ++ ERR("Server is running with WINEESYNC but this process is not, please enable WINEESYNC or restart wineserver.\n"); ++ exit(1); ++ } ++ ++ return; ++ } ++ ++ if (stat( config_dir, &st ) == -1) ++ ERR("Cannot stat %s\n", config_dir); ++ ++ if (st.st_ino != (unsigned long)st.st_ino) ++ sprintf( shm_name, "/wine-%lx%08lx-esync", (unsigned long)((unsigned long long)st.st_ino >> 32), (unsigned long)st.st_ino ); ++ else ++ sprintf( shm_name, "/wine-%lx-esync", (unsigned long)st.st_ino ); ++ ++ if ((shm_fd = shm_open( shm_name, O_RDWR, 0644 )) == -1) ++ { ++ /* probably the server isn't running with WINEESYNC, tell the user and bail */ ++ if (errno == ENOENT) ++ ERR("Failed to open esync shared memory file; make sure no stale wineserver instances are running without WINEESYNC.\n"); ++ else ++ ERR("Failed to initialize shared memory: %s\n", strerror( errno )); ++ exit(1); ++ } ++ ++ pagesize = sysconf( _SC_PAGESIZE ); ++ ++ shm_addrs = calloc( 128, sizeof(shm_addrs[0]) ); ++ shm_addrs_size = 128; ++} +diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h +new file mode 100644 +index 00000000000..5fec18860f8 +--- /dev/null ++++ b/dlls/ntdll/unix/esync.h +@@ -0,0 +1,35 @@ ++/* ++ * eventfd-based synchronization objects ++ * ++ * Copyright (C) 2018 Zebediah Figura ++ * ++ * 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 ++ */ ++ ++extern int do_esync(void); ++extern void esync_init(void); ++ ++extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max); ++ ++ ++/* We have to synchronize on the fd cache mutex so that our calls to receive_fd ++ * don't race with theirs. It looks weird, I know. ++ * ++ * If we weren't trying to avoid touching the code I'd rename the mutex to ++ * "server_fd_mutex" or something similar. */ ++extern pthread_mutex_t fd_cache_mutex; ++ ++extern int receive_fd( obj_handle_t *handle ); +diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c +index dd30c79f755..93331de1b1f 100644 +--- a/dlls/ntdll/unix/loader.c ++++ b/dlls/ntdll/unix/loader.c +@@ -88,6 +88,7 @@ extern char **environ; + #include "winioctl.h" + #include "winternl.h" + #include "unix_private.h" ++#include "esync.h" + #include "wine/list.h" + #include "ntsyscalls.h" + #include "wine/debug.h" +@@ -1959,6 +1960,7 @@ static void start_main_thread(void) + dbg_init(); + startup_info_size = server_init_process(); + hacks_init(); ++ esync_init(); + virtual_map_user_shared_data(); + init_cpu_info(); + init_files(); +diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c +index 53fcc61ccf3..79e2a9171c3 100644 +--- a/dlls/ntdll/unix/server.c ++++ b/dlls/ntdll/unix/server.c +@@ -103,7 +103,7 @@ sigset_t server_block_set; /* signals to block during server calls */ + static int fd_socket = -1; /* socket to exchange file descriptors with the server */ + static int initial_cwd = -1; + static pid_t server_pid; +-static pthread_mutex_t fd_cache_mutex = PTHREAD_MUTEX_INITIALIZER; ++pthread_mutex_t fd_cache_mutex = PTHREAD_MUTEX_INITIALIZER; + + /* atomically exchange a 64-bit value */ + static inline LONG64 interlocked_xchg64( LONG64 *dest, LONG64 val ) +@@ -918,7 +918,7 @@ void wine_server_send_fd( int fd ) + * + * Receive a file descriptor passed from the server. + */ +-static int receive_fd( obj_handle_t *handle ) ++int receive_fd( obj_handle_t *handle ) + { + struct iovec vec; + struct msghdr msghdr; +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index bfbcaf4a851..f21ceb80298 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -63,6 +63,7 @@ + #include "wine/server.h" + #include "wine/debug.h" + #include "unix_private.h" ++#include "esync.h" + + WINE_DEFAULT_DEBUG_CHANNEL(sync); + +@@ -272,6 +273,9 @@ NTSTATUS WINAPI NtCreateSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJ + if (max <= 0 || initial < 0 || initial > max) return STATUS_INVALID_PARAMETER; + if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; + ++ if (do_esync()) ++ return esync_create_semaphore( handle, access, attr, initial, max ); ++ + SERVER_START_REQ( create_semaphore ) + { + req->access = access; +diff --git a/server/esync.c b/server/esync.c +index 35b4833fd4c..75ef586df30 100644 +--- a/server/esync.c ++++ b/server/esync.c +@@ -41,6 +41,7 @@ + #include "handle.h" + #include "request.h" + #include "file.h" ++#include "esync.h" + + int do_esync(void) + { +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0011-ntdll-Implement-NtReleaseSemaphore.patch b/0007-proton-esync-fsync/0011-ntdll-Implement-NtReleaseSemaphore.patch new file mode 100644 index 0000000..1fd6c8f --- /dev/null +++ b/0007-proton-esync-fsync/0011-ntdll-Implement-NtReleaseSemaphore.patch @@ -0,0 +1,109 @@ +From 1082e15153485344d6037fbbb6fb008fcbc22b9f Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 12:16:34 -0500 +Subject: [PATCH 0431/2346] ntdll: Implement NtReleaseSemaphore(). + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 43 +++++++++++++++++++++++++++++++++++++++++ + dlls/ntdll/unix/esync.h | 1 + + dlls/ntdll/unix/sync.c | 3 +++ + 3 files changed, 47 insertions(+) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 89b8542433e..50bf84eabe5 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -28,6 +28,7 @@ + #include + #include + #include ++#include + #include + #include + #ifdef HAVE_SYS_STAT_H +@@ -170,6 +171,16 @@ static struct esync *add_to_list( HANDLE handle, enum esync_type type, int fd, v + return &esync_list[entry][idx]; + } + ++static struct esync *get_cached_object( HANDLE handle ) ++{ ++ UINT_PTR entry, idx = handle_to_index( handle, &entry ); ++ ++ if (entry >= ESYNC_LIST_ENTRIES || !esync_list[entry]) return NULL; ++ if (!esync_list[entry][idx].type) return NULL; ++ ++ return &esync_list[entry][idx]; ++} ++ + static NTSTATUS create_esync( enum esync_type type, HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, int initval, int max ) + { +@@ -225,6 +236,38 @@ extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access, + return create_esync( ESYNC_SEMAPHORE, handle, access, attr, initial, max ); + } + ++NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) ++{ ++ struct esync *obj; ++ struct semaphore *semaphore; ++ uint64_t count64 = count; ++ ULONG current; ++ ++ TRACE("%p, %d, %p.\n", handle, (int)count, prev); ++ ++ if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; ++ semaphore = obj->shm; ++ ++ do ++ { ++ current = semaphore->count; ++ ++ if (count + current > semaphore->max) ++ return STATUS_SEMAPHORE_LIMIT_EXCEEDED; ++ } while (InterlockedCompareExchange( (LONG *)&semaphore->count, count + current, current ) != current); ++ ++ if (prev) *prev = current; ++ ++ /* We don't have to worry about a race between increasing the count and ++ * write(). The fact that we were able to increase the count means that we ++ * have permission to actually write that many releases to the semaphore. */ ++ ++ if (write( obj->fd, &count64, sizeof(count64) ) == -1) ++ return errno_to_status( errno ); ++ ++ return STATUS_SUCCESS; ++} ++ + void esync_init(void) + { + struct stat st; +diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h +index 5fec18860f8..cbaaed3e308 100644 +--- a/dlls/ntdll/unix/esync.h ++++ b/dlls/ntdll/unix/esync.h +@@ -23,6 +23,7 @@ extern void esync_init(void); + + extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max); ++extern NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ); + + + /* We have to synchronize on the fd cache mutex so that our calls to receive_fd +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index f21ceb80298..c85f985b4f3 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -358,6 +358,9 @@ NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, ULONG *previous + { + unsigned int ret; + ++ if (do_esync()) ++ return esync_release_semaphore( handle, count, previous ); ++ + SERVER_START_REQ( release_semaphore ) + { + req->handle = wine_server_obj_handle( handle ); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0012-ntdll-Implement-NtClose.patch b/0007-proton-esync-fsync/0012-ntdll-Implement-NtClose.patch new file mode 100644 index 0000000..be93ee7 --- /dev/null +++ b/0007-proton-esync-fsync/0012-ntdll-Implement-NtClose.patch @@ -0,0 +1,78 @@ +From 892833113c5867a74a59aea5e514634d9ce90c6a Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 12:20:44 -0500 +Subject: [PATCH 0432/2346] ntdll: Implement NtClose(). + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 18 ++++++++++++++++++ + dlls/ntdll/unix/esync.h | 1 + + dlls/ntdll/unix/server.c | 4 ++++ + 3 files changed, 23 insertions(+) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 50bf84eabe5..e289dc13c01 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -181,6 +181,24 @@ static struct esync *get_cached_object( HANDLE handle ) + return &esync_list[entry][idx]; + } + ++NTSTATUS esync_close( HANDLE handle ) ++{ ++ UINT_PTR entry, idx = handle_to_index( handle, &entry ); ++ ++ TRACE("%p.\n", handle); ++ ++ if (entry < ESYNC_LIST_ENTRIES && esync_list[entry]) ++ { ++ if (InterlockedExchange((LONG *)&esync_list[entry][idx].type, 0)) ++ { ++ close( esync_list[entry][idx].fd ); ++ return STATUS_SUCCESS; ++ } ++ } ++ ++ return STATUS_INVALID_HANDLE; ++} ++ + static NTSTATUS create_esync( enum esync_type type, HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, int initval, int max ) + { +diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h +index cbaaed3e308..c63491dcaad 100644 +--- a/dlls/ntdll/unix/esync.h ++++ b/dlls/ntdll/unix/esync.h +@@ -20,6 +20,7 @@ + + extern int do_esync(void); + extern void esync_init(void); ++extern NTSTATUS esync_close( HANDLE handle ); + + extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max); +diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c +index 79e2a9171c3..8cbebd34b5f 100644 +--- a/dlls/ntdll/unix/server.c ++++ b/dlls/ntdll/unix/server.c +@@ -79,6 +79,7 @@ + #include "wine/server.h" + #include "wine/debug.h" + #include "unix_private.h" ++#include "esync.h" + #include "ddk/wdm.h" + + WINE_DEFAULT_DEBUG_CHANNEL(server); +@@ -1841,6 +1842,9 @@ NTSTATUS WINAPI NtClose( HANDLE handle ) + * retrieve it again */ + fd = remove_fd_from_cache( handle ); + ++ if (do_esync()) ++ esync_close( handle ); ++ + SERVER_START_REQ( close_handle ) + { + req->handle = wine_server_obj_handle( handle ); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0013-ntdll-Implement-NtWaitForMultipleObjects.patch b/0007-proton-esync-fsync/0013-ntdll-Implement-NtWaitForMultipleObjects.patch new file mode 100644 index 0000000..9de013d --- /dev/null +++ b/0007-proton-esync-fsync/0013-ntdll-Implement-NtWaitForMultipleObjects.patch @@ -0,0 +1,233 @@ +From 4aed3c7ce6138708368dec1aea1a01475b1043b5 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 12:34:42 -0500 +Subject: [PATCH 0433/2346] ntdll: Implement NtWaitForMultipleObjects(). + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 168 ++++++++++++++++++++++++++++++++++++++++ + dlls/ntdll/unix/esync.h | 3 + + dlls/ntdll/unix/sync.c | 7 ++ + 3 files changed, 178 insertions(+) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index e289dc13c01..660809bcfab 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -34,6 +34,12 @@ + #ifdef HAVE_SYS_STAT_H + # include + #endif ++#ifdef HAVE_POLL_H ++#include ++#endif ++#ifdef HAVE_SYS_POLL_H ++# include ++#endif + #include + #include + +@@ -286,6 +292,168 @@ NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) + return STATUS_SUCCESS; + } + ++#define TICKSPERSEC 10000000 ++#define TICKSPERMSEC 10000 ++ ++static LONGLONG update_timeout( ULONGLONG end ) ++{ ++ LARGE_INTEGER now; ++ LONGLONG timeleft; ++ ++ NtQuerySystemTime( &now ); ++ timeleft = end - now.QuadPart; ++ if (timeleft < 0) timeleft = 0; ++ return timeleft; ++} ++ ++static int do_poll( struct pollfd *fds, nfds_t nfds, ULONGLONG *end ) ++{ ++ if (end) ++ { ++ LONGLONG timeleft = update_timeout( *end ); ++ ++#ifdef HAVE_PPOLL ++ /* We use ppoll() if available since the time granularity is better. */ ++ struct timespec tmo_p; ++ tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; ++ tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; ++ return ppoll( fds, nfds, &tmo_p, NULL ); ++#else ++ return poll( fds, nfds, timeleft / TICKSPERMSEC ); ++#endif ++ } ++ else ++ return poll( fds, nfds, -1 ); ++} ++ ++static void update_grabbed_object( struct esync *obj ) ++{ ++ if (obj->type == ESYNC_SEMAPHORE) ++ { ++ struct semaphore *semaphore = obj->shm; ++ /* We don't have to worry about a race between this and read(); the ++ * fact that we were able to grab it at all means the count is nonzero, ++ * and if someone else grabbed it then the count must have been >= 2, ++ * etc. */ ++ InterlockedExchangeAdd( (LONG *)&semaphore->count, -1 ); ++ } ++} ++ ++/* A value of STATUS_NOT_IMPLEMENTED returned from this function means that we ++ * need to delegate to server_select(). */ ++NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, ++ BOOLEAN alertable, const LARGE_INTEGER *timeout ) ++{ ++ struct esync *objs[MAXIMUM_WAIT_OBJECTS]; ++ struct pollfd fds[MAXIMUM_WAIT_OBJECTS]; ++ int has_esync = 0, has_server = 0; ++ LONGLONG timeleft; ++ LARGE_INTEGER now; ++ ULONGLONG end; ++ int i, ret; ++ ++ NtQuerySystemTime( &now ); ++ if (timeout) ++ { ++ if (timeout->QuadPart == TIMEOUT_INFINITE) ++ timeout = NULL; ++ else if (timeout->QuadPart >= 0) ++ end = timeout->QuadPart; ++ else ++ end = now.QuadPart - timeout->QuadPart; ++ } ++ ++ for (i = 0; i < count; i++) ++ { ++ if ((objs[i] = get_cached_object( handles[i] ))) ++ has_esync = 1; ++ else ++ has_server = 1; ++ } ++ ++ if (has_esync && has_server) ++ FIXME("Can't wait on esync and server objects at the same time!\n"); ++ else if (has_server) ++ return STATUS_NOT_IMPLEMENTED; ++ ++ if (TRACE_ON(esync)) ++ { ++ TRACE("Waiting for %s of %d handles:", wait_any ? "any" : "all", (int)count); ++ for (i = 0; i < count; i++) ++ TRACE(" %p", handles[i]); ++ ++ if (!timeout) ++ TRACE(", timeout = INFINITE.\n"); ++ else ++ { ++ timeleft = update_timeout( end ); ++ TRACE(", timeout = %ld.%07ld sec.\n", ++ (long) timeleft / TICKSPERSEC, (long) timeleft % TICKSPERSEC); ++ } ++ } ++ ++ if (wait_any || count == 1) ++ { ++ for (i = 0; i < count; i++) ++ { ++ fds[i].fd = objs[i] ? objs[i]->fd : -1; ++ fds[i].events = POLLIN; ++ } ++ ++ while (1) ++ { ++ ret = do_poll( fds, count, timeout ? &end : NULL ); ++ if (ret > 0) ++ { ++ /* Find out which object triggered the wait. */ ++ for (i = 0; i < count; i++) ++ { ++ struct esync *obj = objs[i]; ++ ++ if (fds[i].revents & (POLLERR | POLLHUP | POLLNVAL)) ++ { ++ ERR("Polling on fd %d returned %#x.\n", fds[i].fd, fds[i].revents); ++ return STATUS_INVALID_HANDLE; ++ } ++ ++ if (obj) ++ { ++ int64_t value; ++ ssize_t size; ++ ++ if ((size = read( fds[i].fd, &value, sizeof(value) )) == sizeof(value)) ++ { ++ /* We found our object. */ ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ update_grabbed_object( obj ); ++ return i; ++ } ++ } ++ } ++ ++ /* If we got here, someone else stole (or reset, etc.) whatever ++ * we were waiting for. So keep waiting. */ ++ NtQuerySystemTime( &now ); ++ } ++ else if (ret == 0) ++ { ++ TRACE("Wait timed out.\n"); ++ return STATUS_TIMEOUT; ++ } ++ else ++ { ++ ERR("ppoll failed: %s\n", strerror( errno )); ++ return errno_to_status( errno ); ++ } ++ } ++ } ++ else ++ { ++ FIXME("Wait-all not implemented.\n"); ++ return STATUS_NOT_IMPLEMENTED; ++ } ++} ++ + void esync_init(void) + { + struct stat st; +diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h +index c63491dcaad..92b609ebd27 100644 +--- a/dlls/ntdll/unix/esync.h ++++ b/dlls/ntdll/unix/esync.h +@@ -26,6 +26,9 @@ extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max); + extern NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ); + ++extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, ++ BOOLEAN alertable, const LARGE_INTEGER *timeout ); ++ + + /* We have to synchronize on the fd cache mutex so that our calls to receive_fd + * don't race with theirs. It looks weird, I know. +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index c85f985b4f3..79141999e33 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -1479,6 +1479,13 @@ NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles, BO + + if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1; + ++ if (do_esync()) ++ { ++ NTSTATUS ret = esync_wait_objects( count, handles, wait_any, alertable, timeout ); ++ if (ret != STATUS_NOT_IMPLEMENTED) ++ return ret; ++ } ++ + if (alertable) flags |= SELECT_ALERTABLE; + select_op.wait.op = wait_any ? SELECT_WAIT : SELECT_WAIT_ALL; + for (i = 0; i < count; i++) select_op.wait.handles[i] = wine_server_obj_handle( handles[i] ); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0014-ntdll-server-Implement-NtCreateEvent.patch b/0007-proton-esync-fsync/0014-ntdll-server-Implement-NtCreateEvent.patch new file mode 100644 index 0000000..1e579ce --- /dev/null +++ b/0007-proton-esync-fsync/0014-ntdll-server-Implement-NtCreateEvent.patch @@ -0,0 +1,130 @@ +From 3376970bcc3053275aa658efbf0ede282e089eac Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 14:40:43 -0500 +Subject: [PATCH 0434/2346] ntdll, server: Implement NtCreateEvent(). + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 27 +++++++++++++++++++++++++++ + dlls/ntdll/unix/esync.h | 3 +++ + dlls/ntdll/unix/sync.c | 4 ++++ + server/esync.c | 15 +++++++++++++++ + 4 files changed, 49 insertions(+) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 660809bcfab..a072f6f4804 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -86,6 +86,13 @@ struct semaphore + }; + C_ASSERT(sizeof(struct semaphore) == 8); + ++struct event ++{ ++ int signaled; ++ int locked; ++}; ++C_ASSERT(sizeof(struct event) == 8); ++ + static char shm_name[29]; + static int shm_fd; + static void **shm_addrs; +@@ -292,6 +299,18 @@ NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) + return STATUS_SUCCESS; + } + ++NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr, EVENT_TYPE event_type, BOOLEAN initial ) ++{ ++ enum esync_type type = (event_type == SynchronizationEvent ? ESYNC_AUTO_EVENT : ESYNC_MANUAL_EVENT); ++ ++ TRACE("name %s, %s-reset, initial %d.\n", ++ attr ? debugstr_us(attr->ObjectName) : "", ++ event_type == NotificationEvent ? "manual" : "auto", initial); ++ ++ return create_esync( type, handle, access, attr, initial, 0 ); ++} ++ + #define TICKSPERSEC 10000000 + #define TICKSPERMSEC 10000 + +@@ -337,6 +356,14 @@ static void update_grabbed_object( struct esync *obj ) + * etc. */ + InterlockedExchangeAdd( (LONG *)&semaphore->count, -1 ); + } ++ else if (obj->type == ESYNC_AUTO_EVENT) ++ { ++ struct event *event = obj->shm; ++ /* We don't have to worry about a race between this and read(), since ++ * this is just a hint, and the real state is in the kernel object. ++ * This might already be 0, but that's okay! */ ++ event->signaled = 0; ++ } + } + + /* A value of STATUS_NOT_IMPLEMENTED returned from this function means that we +diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h +index 92b609ebd27..7bb963faf51 100644 +--- a/dlls/ntdll/unix/esync.h ++++ b/dlls/ntdll/unix/esync.h +@@ -26,6 +26,9 @@ extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max); + extern NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ); + ++extern NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ); ++ + extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, + BOOLEAN alertable, const LARGE_INTEGER *timeout ); + +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 79141999e33..161c170f59c 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -387,6 +387,10 @@ NTSTATUS WINAPI NtCreateEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ + + *handle = 0; + if (type != NotificationEvent && type != SynchronizationEvent) return STATUS_INVALID_PARAMETER; ++ ++ if (do_esync()) ++ return esync_create_event( handle, access, attr, type, state ); ++ + if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; + + SERVER_START_REQ( create_event ) +diff --git a/server/esync.c b/server/esync.c +index 75ef586df30..6a63c0dd5e9 100644 +--- a/server/esync.c ++++ b/server/esync.c +@@ -201,6 +201,13 @@ struct semaphore + }; + C_ASSERT(sizeof(struct semaphore) == 8); + ++struct event ++{ ++ int signaled; ++ int locked; ++}; ++C_ASSERT(sizeof(struct event) == 8); ++ + struct esync *create_esync( struct object *root, const struct unicode_str *name, + unsigned int attr, int initval, int max, enum esync_type type, + const struct security_descriptor *sd ) +@@ -256,6 +263,14 @@ struct esync *create_esync( struct object *root, const struct unicode_str *name, + semaphore->count = initval; + break; + } ++ case ESYNC_AUTO_EVENT: ++ case ESYNC_MANUAL_EVENT: ++ { ++ struct event *event = get_shm( esync->shm_idx ); ++ event->signaled = initval ? 1 : 0; ++ event->locked = 0; ++ break; ++ } + default: + assert( 0 ); + } +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0015-ntdll-Implement-NtSetEvent.patch b/0007-proton-esync-fsync/0015-ntdll-Implement-NtSetEvent.patch new file mode 100644 index 0000000..ce5e98a --- /dev/null +++ b/0007-proton-esync-fsync/0015-ntdll-Implement-NtSetEvent.patch @@ -0,0 +1,70 @@ +From 08d235715f47953ae5c9d5d00cf2bf8c008b6741 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 14:46:24 -0500 +Subject: [PATCH 0435/2346] ntdll: Implement NtSetEvent(). + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 15 +++++++++++++++ + dlls/ntdll/unix/esync.h | 1 + + dlls/ntdll/unix/sync.c | 4 ++++ + 3 files changed, 20 insertions(+) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index a072f6f4804..34314d8cb32 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -311,6 +311,21 @@ NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, + return create_esync( type, handle, access, attr, initial, 0 ); + } + ++NTSTATUS esync_set_event( HANDLE handle ) ++{ ++ static const uint64_t value = 1; ++ struct esync *obj; ++ ++ TRACE("%p.\n", handle); ++ ++ if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; ++ ++ if (write( obj->fd, &value, sizeof(value) ) == -1) ++ ERR("write: %s\n", strerror(errno)); ++ ++ return STATUS_SUCCESS; ++} ++ + #define TICKSPERSEC 10000000 + #define TICKSPERMSEC 10000 + +diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h +index 7bb963faf51..d92165214d6 100644 +--- a/dlls/ntdll/unix/esync.h ++++ b/dlls/ntdll/unix/esync.h +@@ -28,6 +28,7 @@ extern NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev + + extern NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ); ++extern NTSTATUS esync_set_event( HANDLE handle ); + + extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, + BOOLEAN alertable, const LARGE_INTEGER *timeout ); +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 161c170f59c..706d381d7c7 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -439,8 +439,12 @@ NTSTATUS WINAPI NtOpenEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_AT + */ + NTSTATUS WINAPI NtSetEvent( HANDLE handle, LONG *prev_state ) + { ++ /* This comment is a dummy to make sure this patch applies in the right place. */ + unsigned int ret; + ++ if (do_esync()) ++ return esync_set_event( handle ); ++ + SERVER_START_REQ( event_op ) + { + req->handle = wine_server_obj_handle( handle ); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0016-ntdll-Implement-NtResetEvent.patch b/0007-proton-esync-fsync/0016-ntdll-Implement-NtResetEvent.patch new file mode 100644 index 0000000..f10251c --- /dev/null +++ b/0007-proton-esync-fsync/0016-ntdll-Implement-NtResetEvent.patch @@ -0,0 +1,71 @@ +From c3bb69414f02d41a29d3df6eb7e79b64af8b1a27 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 14:51:21 -0500 +Subject: [PATCH 0436/2346] ntdll: Implement NtResetEvent(). + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 15 +++++++++++++++ + dlls/ntdll/unix/esync.h | 1 + + dlls/ntdll/unix/sync.c | 5 +++++ + 3 files changed, 21 insertions(+) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 34314d8cb32..5f4904d4872 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -326,6 +326,21 @@ NTSTATUS esync_set_event( HANDLE handle ) + return STATUS_SUCCESS; + } + ++NTSTATUS esync_reset_event( HANDLE handle ) ++{ ++ uint64_t value; ++ struct esync *obj; ++ ++ TRACE("%p.\n", handle); ++ ++ if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; ++ ++ if (read( obj->fd, &value, sizeof(value) ) == -1 && errno != EWOULDBLOCK && errno != EAGAIN) ++ ERR("read: %s\n", strerror(errno)); ++ ++ return STATUS_SUCCESS; ++} ++ + #define TICKSPERSEC 10000000 + #define TICKSPERMSEC 10000 + +diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h +index d92165214d6..6e5d6233a2e 100644 +--- a/dlls/ntdll/unix/esync.h ++++ b/dlls/ntdll/unix/esync.h +@@ -28,6 +28,7 @@ extern NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev + + extern NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ); ++extern NTSTATUS esync_reset_event( HANDLE handle ); + extern NTSTATUS esync_set_event( HANDLE handle ); + + extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 706d381d7c7..fdf4215039b 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -462,8 +462,13 @@ NTSTATUS WINAPI NtSetEvent( HANDLE handle, LONG *prev_state ) + */ + NTSTATUS WINAPI NtResetEvent( HANDLE handle, LONG *prev_state ) + { ++ /* This comment is a dummy to make sure this patch applies in the right place. */ + unsigned int ret; + ++ if (do_esync()) ++ return esync_reset_event( handle ); ++ ++ + SERVER_START_REQ( event_op ) + { + req->handle = wine_server_obj_handle( handle ); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0017-ntdll-Implement-waiting-on-manual-reset-events.patch b/0007-proton-esync-fsync/0017-ntdll-Implement-waiting-on-manual-reset-events.patch new file mode 100644 index 0000000..c14d143 --- /dev/null +++ b/0007-proton-esync-fsync/0017-ntdll-Implement-waiting-on-manual-reset-events.patch @@ -0,0 +1,60 @@ +From fa7783e45e59c933a8938079d6733fe64e61b040 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 14:57:42 -0500 +Subject: [PATCH 0437/2346] ntdll: Implement waiting on manual-reset events. + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 27 +++++++++++++++++---------- + 1 file changed, 17 insertions(+), 10 deletions(-) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 5f4904d4872..0d15defdd9c 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -34,12 +34,7 @@ + #ifdef HAVE_SYS_STAT_H + # include + #endif +-#ifdef HAVE_POLL_H + #include +-#endif +-#ifdef HAVE_SYS_POLL_H +-# include +-#endif + #include + #include + +@@ -478,12 +473,24 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an + int64_t value; + ssize_t size; + +- if ((size = read( fds[i].fd, &value, sizeof(value) )) == sizeof(value)) ++ if (obj->type == ESYNC_MANUAL_EVENT) ++ { ++ /* Don't grab the object, just check if it's signaled. */ ++ if (fds[i].revents & POLLIN) ++ { ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ return i; ++ } ++ } ++ else + { +- /* We found our object. */ +- TRACE("Woken up by handle %p [%d].\n", handles[i], i); +- update_grabbed_object( obj ); +- return i; ++ if ((size = read( fds[i].fd, &value, sizeof(value) )) == sizeof(value)) ++ { ++ /* We found our object. */ ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ update_grabbed_object( obj ); ++ return i; ++ } + } + } + } +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0018-server-Add-an-object-operation-to-grab-the-esync-fil.patch b/0007-proton-esync-fsync/0018-server-Add-an-object-operation-to-grab-the-esync-fil.patch new file mode 100644 index 0000000..d7fb16d --- /dev/null +++ b/0007-proton-esync-fsync/0018-server-Add-an-object-operation-to-grab-the-esync-fil.patch @@ -0,0 +1,722 @@ +From 37eb12f03153dfad7554e7fee4a621ec501167f7 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. + +Split off to decrease patch size. + +Wine-Staging: eventfd_synchronization +--- + server/async.c | 2 ++ + server/atom.c | 1 + + server/change.c | 1 + + server/clipboard.c | 1 + + server/completion.c | 1 + + server/console.c | 7 +++++++ + server/debugger.c | 2 ++ + server/device.c | 4 ++++ + server/directory.c | 2 ++ + server/esync.c | 1 + + server/event.c | 2 ++ + server/fd.c | 4 ++++ + server/file.c | 1 + + server/handle.c | 1 + + server/hook.c | 1 + + server/mailslot.c | 4 ++++ + server/mapping.c | 3 +++ + server/mutex.c | 1 + + server/named_pipe.c | 5 +++++ + server/object.h | 2 ++ + server/process.c | 3 +++ + server/queue.c | 2 ++ + server/registry.c | 1 + + server/request.c | 1 + + server/semaphore.c | 1 + + server/serial.c | 1 + + server/signal.c | 1 + + server/sock.c | 3 +++ + server/symlink.c | 1 + + server/thread.c | 3 +++ + server/timer.c | 1 + + server/token.c | 1 + + server/window.c | 1 + + server/winstation.c | 2 ++ + 34 files changed, 68 insertions(+) + +diff --git a/server/async.c b/server/async.c +index 9cb251df5ce..337bba8631b 100644 +--- a/server/async.c ++++ b/server/async.c +@@ -77,6 +77,7 @@ static const struct object_ops async_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + async_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + async_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -676,6 +677,7 @@ static const struct object_ops iosb_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/atom.c b/server/atom.c +index ff0799f5880..d9824de8eac 100644 +--- a/server/atom.c ++++ b/server/atom.c +@@ -79,6 +79,7 @@ static const struct object_ops atom_table_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/change.c b/server/change.c +index 843e495411c..5f1cf9b880b 100644 +--- a/server/change.c ++++ b/server/change.c +@@ -112,6 +112,7 @@ static const struct object_ops dir_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + dir_get_fd, /* get_fd */ +diff --git a/server/clipboard.c b/server/clipboard.c +index 8118a467dd8..8b265f2dcea 100644 +--- a/server/clipboard.c ++++ b/server/clipboard.c +@@ -76,6 +76,7 @@ static const struct object_ops clipboard_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/completion.c b/server/completion.c +index 6933195e72d..3d4be86a212 100644 +--- a/server/completion.c ++++ b/server/completion.c +@@ -75,6 +75,7 @@ static const struct object_ops completion_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + completion_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/console.c b/server/console.c +index b64283baf4a..1cc9eea6a50 100644 +--- a/server/console.c ++++ b/server/console.c +@@ -81,6 +81,7 @@ static const struct object_ops console_ops = + console_add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + console_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + console_get_fd, /* get_fd */ +@@ -158,6 +159,7 @@ static const struct object_ops console_server_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + console_server_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + console_server_get_fd, /* get_fd */ +@@ -227,6 +229,7 @@ static const struct object_ops screen_buffer_ops = + screen_buffer_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + screen_buffer_get_fd, /* get_fd */ +@@ -276,6 +279,7 @@ static const struct object_ops console_device_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 */ +@@ -313,6 +317,7 @@ static const struct object_ops console_input_ops = + console_input_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + console_input_get_fd, /* get_fd */ +@@ -370,6 +375,7 @@ static const struct object_ops console_output_ops = + console_output_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + console_output_get_fd, /* get_fd */ +@@ -428,6 +434,7 @@ static const struct object_ops console_connection_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + console_connection_get_fd, /* get_fd */ +diff --git a/server/debugger.c b/server/debugger.c +index 48adb244b09..d85a2000684 100644 +--- a/server/debugger.c ++++ b/server/debugger.c +@@ -86,6 +86,7 @@ static const struct object_ops debug_event_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + debug_event_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -114,6 +115,7 @@ static const struct object_ops debug_obj_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + debug_obj_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/device.c b/server/device.c +index 436dac6bfe9..f730fa81afa 100644 +--- a/server/device.c ++++ b/server/device.c +@@ -66,6 +66,7 @@ static const struct object_ops irp_call_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -106,6 +107,7 @@ static const struct object_ops device_manager_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + device_manager_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -163,6 +165,7 @@ static const struct object_ops device_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 */ +@@ -215,6 +218,7 @@ static const struct object_ops device_file_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + device_file_get_fd, /* get_fd */ +diff --git a/server/directory.c b/server/directory.c +index e169cc2d011..dc3f0cf3cf8 100644 +--- a/server/directory.c ++++ b/server/directory.c +@@ -70,6 +70,7 @@ static const struct object_ops object_type_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -120,6 +121,7 @@ static const struct object_ops directory_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/esync.c b/server/esync.c +index 6a63c0dd5e9..f95dc5a391f 100644 +--- a/server/esync.c ++++ b/server/esync.c +@@ -122,6 +122,7 @@ static const struct object_ops esync_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/event.c b/server/event.c +index f1b79b1b35e..c727bfdd1ba 100644 +--- a/server/event.c ++++ b/server/event.c +@@ -72,6 +72,7 @@ static const struct object_ops event_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + event_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + event_satisfied, /* satisfied */ + event_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -119,6 +120,7 @@ static const struct object_ops keyed_event_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + keyed_event_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/fd.c b/server/fd.c +index 8576882aaa9..f9f747016b3 100644 +--- a/server/fd.c ++++ b/server/fd.c +@@ -169,6 +169,7 @@ static const struct object_ops fd_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -210,6 +211,7 @@ static const struct object_ops device_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -250,6 +252,7 @@ static const struct object_ops inode_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -292,6 +295,7 @@ static const struct object_ops file_lock_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + file_lock_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/file.c b/server/file.c +index 76c687833c9..26c62809d33 100644 +--- a/server/file.c ++++ b/server/file.c +@@ -94,6 +94,7 @@ static const struct object_ops file_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + file_get_fd, /* get_fd */ +diff --git a/server/handle.c b/server/handle.c +index 0595fdb403b..d41c7e86454 100644 +--- a/server/handle.c ++++ b/server/handle.c +@@ -126,6 +126,7 @@ static const struct object_ops handle_table_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/hook.c b/server/hook.c +index dd3657c2eac..95a588c843b 100644 +--- a/server/hook.c ++++ b/server/hook.c +@@ -80,6 +80,7 @@ static const struct object_ops hook_table_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/mailslot.c b/server/mailslot.c +index 2d8697ec9bd..4cf9b73f784 100644 +--- a/server/mailslot.c ++++ b/server/mailslot.c +@@ -74,6 +74,7 @@ static const struct object_ops mailslot_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + mailslot_get_fd, /* get_fd */ +@@ -133,6 +134,7 @@ static const struct object_ops mail_writer_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + mail_writer_get_fd, /* get_fd */ +@@ -196,6 +198,7 @@ static const struct object_ops mailslot_device_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 */ +@@ -226,6 +229,7 @@ static const struct object_ops mailslot_device_file_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + mailslot_device_file_get_fd, /* get_fd */ +diff --git a/server/mapping.c b/server/mapping.c +index 7a07575bca2..bc971fa91c4 100644 +--- a/server/mapping.c ++++ b/server/mapping.c +@@ -72,6 +72,7 @@ static const struct object_ops ranges_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -108,6 +109,7 @@ static const struct object_ops shared_map_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -182,6 +184,7 @@ static const struct object_ops mapping_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + mapping_get_fd, /* get_fd */ +diff --git a/server/mutex.c b/server/mutex.c +index af0efe72132..4785a830e92 100644 +--- a/server/mutex.c ++++ b/server/mutex.c +@@ -73,6 +73,7 @@ static const struct object_ops mutex_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + mutex_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + mutex_satisfied, /* satisfied */ + mutex_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/named_pipe.c b/server/named_pipe.c +index f3404a33c3b..f28cb14cb45 100644 +--- a/server/named_pipe.c ++++ b/server/named_pipe.c +@@ -119,6 +119,7 @@ static const struct object_ops named_pipe_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -167,6 +168,7 @@ static const struct object_ops pipe_server_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + pipe_end_get_fd, /* get_fd */ +@@ -211,6 +213,7 @@ static const struct object_ops pipe_client_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + pipe_end_get_fd, /* get_fd */ +@@ -258,6 +261,7 @@ static const struct object_ops named_pipe_device_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 */ +@@ -289,6 +293,7 @@ static const struct object_ops named_pipe_device_file_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + named_pipe_device_file_get_fd, /* get_fd */ +diff --git a/server/object.h b/server/object.h +index 66012fbc4af..51ee819415a 100644 +--- a/server/object.h ++++ b/server/object.h +@@ -78,6 +78,8 @@ struct object_ops + void (*remove_queue)(struct object *,struct wait_queue_entry *); + /* is object signaled? */ + int (*signaled)(struct object *,struct wait_queue_entry *); ++ /* return the esync fd for this object */ ++ int (*get_esync_fd)(struct object *, enum esync_type *type); + /* wait satisfied */ + 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 +--- a/server/process.c ++++ b/server/process.c +@@ -105,6 +105,7 @@ static const struct object_ops process_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + process_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -156,6 +157,7 @@ static const struct object_ops startup_info_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + startup_info_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -217,6 +219,7 @@ static const struct object_ops job_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + job_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/queue.c b/server/queue.c +index 7a4d45659ba..e709f0348f8 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -166,6 +166,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 */ ++ NULL, /* get_esync_fd */ + msg_queue_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -203,6 +204,7 @@ static const struct object_ops thread_input_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/registry.c b/server/registry.c +index 0128b8be9d8..c071f42532b 100644 +--- a/server/registry.c ++++ b/server/registry.c +@@ -180,6 +180,7 @@ static const struct object_ops key_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/request.c b/server/request.c +index 7021741c765..ca83fdbd2af 100644 +--- a/server/request.c ++++ b/server/request.c +@@ -90,6 +90,7 @@ static const struct object_ops master_socket_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/semaphore.c b/server/semaphore.c +index 53b42a886df..e3889f24601 100644 +--- a/server/semaphore.c ++++ b/server/semaphore.c +@@ -70,6 +70,7 @@ static const struct object_ops semaphore_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + semaphore_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + semaphore_satisfied, /* satisfied */ + semaphore_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/serial.c b/server/serial.c +index d665eb7fa35..11e204e4419 100644 +--- a/server/serial.c ++++ b/server/serial.c +@@ -85,6 +85,7 @@ static const struct object_ops serial_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + serial_get_fd, /* get_fd */ +diff --git a/server/signal.c b/server/signal.c +index 19b76d44c16..55cd6aa037e 100644 +--- a/server/signal.c ++++ b/server/signal.c +@@ -62,6 +62,7 @@ static const struct object_ops handler_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/sock.c b/server/sock.c +index 84c0d4a4931..177e7e6dded 100644 +--- a/server/sock.c ++++ b/server/sock.c +@@ -453,6 +453,7 @@ static const struct object_ops sock_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + sock_get_fd, /* get_fd */ +@@ -3554,6 +3555,7 @@ static const struct object_ops ifchange_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + ifchange_get_fd, /* get_fd */ +@@ -3775,6 +3777,7 @@ static const struct object_ops socket_device_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/symlink.c b/server/symlink.c +index dd28efd3a75..c7f34412317 100644 +--- a/server/symlink.c ++++ b/server/symlink.c +@@ -71,6 +71,7 @@ static const struct object_ops symlink_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/thread.c b/server/thread.c +index 08742786b03..f579ffddad8 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -100,6 +100,7 @@ static const struct object_ops thread_apc_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + thread_apc_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -142,6 +143,7 @@ static const struct object_ops context_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + context_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -191,6 +193,7 @@ static const struct object_ops thread_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + thread_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/timer.c b/server/timer.c +index 96dc9d00ca1..f59902d5607 100644 +--- a/server/timer.c ++++ b/server/timer.c +@@ -76,6 +76,7 @@ static const struct object_ops timer_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + timer_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ + timer_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/token.c b/server/token.c +index 4df8d2e0c6e..8b4d2f0c1b1 100644 +--- a/server/token.c ++++ b/server/token.c +@@ -143,6 +143,7 @@ static const struct object_ops token_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/window.c b/server/window.c +index bd11d0d32de..f6b9a25baa4 100644 +--- a/server/window.c ++++ b/server/window.c +@@ -107,6 +107,7 @@ static const struct object_ops window_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/winstation.c b/server/winstation.c +index a0c41ea21a2..ae1123c1d38 100644 +--- a/server/winstation.c ++++ b/server/winstation.c +@@ -76,6 +76,7 @@ static const struct object_ops winstation_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -116,6 +117,7 @@ static const struct object_ops desktop_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ ++ NULL, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0019-server-Add-a-request-to-get-the-eventfd-file-descrip.patch b/0007-proton-esync-fsync/0019-server-Add-a-request-to-get-the-eventfd-file-descrip.patch new file mode 100644 index 0000000..6565607 --- /dev/null +++ b/0007-proton-esync-fsync/0019-server-Add-a-request-to-get-the-eventfd-file-descrip.patch @@ -0,0 +1,76 @@ +From b277f205b956f0ef0f66259e2f9d0cd97514c206 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Fri, 8 Jun 2018 18:55:49 -0500 +Subject: [PATCH 0439/2346] server: Add a request to get the eventfd file + descriptor associated with a waitable handle. + +Wine-Staging: eventfd_synchronization +--- + server/esync.c | 37 +++++++++++++++++++++++++++++++++++++ + server/protocol.def | 8 ++++++++ + 2 files changed, 45 insertions(+) + +diff --git a/server/esync.c b/server/esync.c +index f95dc5a391f..85f7f1e060f 100644 +--- a/server/esync.c ++++ b/server/esync.c +@@ -333,3 +333,40 @@ DECL_HANDLER(create_esync) + + if (root) release_object( root ); + } ++ ++/* Retrieve a file descriptor for an esync object which will be signaled by the ++ * server. The client should only read from (i.e. wait on) this object. */ ++DECL_HANDLER(get_esync_fd) ++{ ++ struct object *obj; ++ enum esync_type type; ++ int fd; ++ ++ if (!(obj = get_handle_obj( current->process, req->handle, SYNCHRONIZE, NULL ))) ++ return; ++ ++ if (obj->ops->get_esync_fd) ++ { ++ fd = obj->ops->get_esync_fd( obj, &type ); ++ reply->type = type; ++ if (obj->ops == &esync_ops) ++ { ++ struct esync *esync = (struct esync *)obj; ++ reply->shm_idx = esync->shm_idx; ++ } ++ else ++ reply->shm_idx = 0; ++ send_client_fd( current->process, fd, req->handle ); ++ } ++ else ++ { ++ if (debug_level) ++ { ++ fprintf( stderr, "%04x: esync: can't wait on object: ", current->id ); ++ obj->ops->dump( obj, 0 ); ++ } ++ set_error( STATUS_NOT_IMPLEMENTED ); ++ } ++ ++ release_object( obj ); ++} +diff --git a/server/protocol.def b/server/protocol.def +index a9fb8a2ede0..6e67af1636e 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3962,3 +3962,11 @@ enum esync_type + int type; /* actual type (may be different for events) */ + unsigned int shm_idx; + @END ++ ++/* Retrieve the esync fd for an object. */ ++@REQ(get_esync_fd) ++ obj_handle_t handle; /* handle to the object */ ++@REPLY ++ int type; ++ unsigned int shm_idx; ++@END +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0020-server-Create-eventfd-file-descriptors-for-process-o.patch b/0007-proton-esync-fsync/0020-server-Create-eventfd-file-descriptors-for-process-o.patch new file mode 100644 index 0000000..7de322d --- /dev/null +++ b/0007-proton-esync-fsync/0020-server-Create-eventfd-file-descriptors-for-process-o.patch @@ -0,0 +1,136 @@ +From f8408057d3999cc4f481f8cad37642e4458c3834 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 15:11:12 -0500 +Subject: [PATCH 0440/2346] server: Create eventfd file descriptors for process + objects. + +Wine-Staging: eventfd_synchronization +--- + server/esync.c | 18 ++++++++++++++++++ + server/esync.h | 1 + + server/process.c | 16 +++++++++++++++- + server/process.h | 1 + + 4 files changed, 35 insertions(+), 1 deletion(-) + +diff --git a/server/esync.c b/server/esync.c +index 85f7f1e060f..44214e5fe02 100644 +--- a/server/esync.c ++++ b/server/esync.c +@@ -295,6 +295,24 @@ struct esync *create_esync( struct object *root, const struct unicode_str *name, + #endif + } + ++/* Create a file descriptor for an existing handle. ++ * Caller must close the handle when it's done; it's not linked to an esync ++ * server object in any way. */ ++int esync_create_fd( int initval, int flags ) ++{ ++#ifdef HAVE_SYS_EVENTFD_H ++ int fd; ++ ++ fd = eventfd( initval, flags | EFD_CLOEXEC | EFD_NONBLOCK ); ++ if (fd == -1) ++ perror( "eventfd" ); ++ ++ return fd; ++#else ++ return -1; ++#endif ++} ++ + DECL_HANDLER(create_esync) + { + struct esync *esync; +diff --git a/server/esync.h b/server/esync.h +index 00f9e638d83..8522d8a69ae 100644 +--- a/server/esync.h ++++ b/server/esync.h +@@ -22,3 +22,4 @@ + + extern int do_esync(void); + void esync_init(void); ++int esync_create_fd( int initval, int flags ); +diff --git a/server/process.c b/server/process.c +index 777bf7c2fe2..f5b919cba00 100644 +--- a/server/process.c ++++ b/server/process.c +@@ -63,6 +63,7 @@ + #include "request.h" + #include "user.h" + #include "security.h" ++#include "esync.h" + + /* process object */ + +@@ -95,6 +96,7 @@ static struct security_descriptor *process_get_sd( struct object *obj ); + static void process_poll_event( struct fd *fd, int event ); + static struct list *process_get_kernel_obj_list( struct object *obj ); + static void process_destroy( struct object *obj ); ++static int process_get_esync_fd( struct object *obj, enum esync_type *type ); + static void terminate_process( struct process *process, struct thread *skip, int exit_code ); + + static const struct object_ops process_ops = +@@ -105,7 +107,7 @@ static const struct object_ops process_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + process_signaled, /* signaled */ +- NULL, /* get_esync_fd */ ++ process_get_esync_fd, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -686,6 +688,7 @@ struct process *create_process( int fd, struct process *parent, unsigned int fla + process->rawinput_mouse = NULL; + process->rawinput_kbd = NULL; + memset( &process->image_info, 0, sizeof(process->image_info) ); ++ process->esync_fd = -1; + list_init( &process->rawinput_entry ); + list_init( &process->kernel_object ); + list_init( &process->thread_list ); +@@ -742,6 +745,9 @@ struct process *create_process( int fd, struct process *parent, unsigned int fla + if (!token_assign_label( process->token, &high_label_sid )) + goto error; + ++ if (do_esync()) ++ process->esync_fd = esync_create_fd( 0, 0 ); ++ + set_fd_events( process->msg_fd, POLLIN ); /* start listening to events */ + return process; + +@@ -789,6 +795,7 @@ static void process_destroy( struct object *obj ) + free( process->rawinput_devices ); + free( process->dir_cache ); + free( process->image ); ++ if (do_esync()) close( process->esync_fd ); + } + + /* dump a process on stdout for debugging purposes */ +@@ -806,6 +813,13 @@ static int process_signaled( struct object *obj, struct wait_queue_entry *entry + return !process->running_threads; + } + ++static int process_get_esync_fd( struct object *obj, enum esync_type *type ) ++{ ++ struct process *process = (struct process *)obj; ++ *type = ESYNC_MANUAL_SERVER; ++ return process->esync_fd; ++} ++ + static unsigned int process_map_access( struct object *obj, unsigned int access ) + { + access = default_map_access( obj, access ); +diff --git a/server/process.h b/server/process.h +index 97e0d455ece..a0a071d8f88 100644 +--- a/server/process.h ++++ b/server/process.h +@@ -85,6 +85,7 @@ struct process + const struct rawinput_device *rawinput_kbd; /* rawinput keyboard device, if any */ + struct list kernel_object; /* list of kernel object pointers */ + pe_image_info_t image_info; /* main exe image info */ ++ int esync_fd; /* esync file descriptor (signaled on exit) */ + }; + + /* process functions */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0021-ntdll-server-Implement-waiting-on-server-bound-objec.patch b/0007-proton-esync-fsync/0021-ntdll-server-Implement-waiting-on-server-bound-objec.patch new file mode 100644 index 0000000..7e936c7 --- /dev/null +++ b/0007-proton-esync-fsync/0021-ntdll-server-Implement-waiting-on-server-bound-objec.patch @@ -0,0 +1,226 @@ +From 07524cd5960a10c10b2e357e1c385563d3f264db Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 15:19:37 -0500 +Subject: [PATCH 0441/2346] ntdll, server: Implement waiting on server-bound + objects. + +The code here is sort of self-explanatory, but since I split it up over +several patches I'll provide a quick explanation. The basic principle is +that we can create an eventfd descriptor for any synchronizable handle, and +signal it on the server side whenever a wakeup would be triggered. This means +not only that we can wait simultaneously on esync primitives and on other +primitives, but that we can do it all in "user-mode", i.e. without having to +make a server call. + +With this patch we break waiting on svcctl.exe. + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 84 ++++++++++++++++++++++++++++++++++++++--- + server/esync.c | 16 ++++++++ + server/esync.h | 1 + + server/thread.c | 4 ++ + 4 files changed, 99 insertions(+), 6 deletions(-) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 0d15defdd9c..e783517f644 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -189,6 +189,72 @@ static struct esync *get_cached_object( HANDLE handle ) + return &esync_list[entry][idx]; + } + ++/* Gets an object. This is either a proper esync object (i.e. an event, ++ * semaphore, etc. created using create_esync) or a generic synchronizable ++ * server-side object which the server will signal (e.g. a process, thread, ++ * message queue, etc.) */ ++static NTSTATUS get_object( HANDLE handle, struct esync **obj ) ++{ ++ NTSTATUS ret = STATUS_SUCCESS; ++ enum esync_type type = 0; ++ unsigned int shm_idx = 0; ++ obj_handle_t fd_handle; ++ sigset_t sigset; ++ int fd = -1; ++ ++ if ((*obj = get_cached_object( handle ))) return STATUS_SUCCESS; ++ ++ if ((INT_PTR)handle < 0) ++ { ++ /* We can deal with pseudo-handles, but it's just easier this way */ ++ return STATUS_NOT_IMPLEMENTED; ++ } ++ ++ if (!handle) ++ { ++ /* Shadow of the Tomb Raider really likes passing in NULL handles to ++ * various functions. Concerning, but let's avoid a server call. */ ++ return STATUS_INVALID_HANDLE; ++ } ++ ++ /* We need to try grabbing it from the server. */ ++ server_enter_uninterrupted_section( &fd_cache_mutex, &sigset ); ++ if (!(*obj = get_cached_object( handle ))) ++ { ++ SERVER_START_REQ( get_esync_fd ) ++ { ++ req->handle = wine_server_obj_handle( handle ); ++ if (!(ret = wine_server_call( req ))) ++ { ++ type = reply->type; ++ shm_idx = reply->shm_idx; ++ fd = receive_fd( &fd_handle ); ++ assert( wine_server_ptr_handle(fd_handle) == handle ); ++ } ++ } ++ SERVER_END_REQ; ++ } ++ server_leave_uninterrupted_section( &fd_cache_mutex, &sigset ); ++ ++ if (*obj) ++ { ++ /* We managed to grab it while in the CS; return it. */ ++ return STATUS_SUCCESS; ++ } ++ ++ if (ret) ++ { ++ WARN("Failed to retrieve fd for handle %p, status %#x.\n", handle, (unsigned int)ret); ++ *obj = NULL; ++ return ret; ++ } ++ ++ TRACE("Got fd %d for handle %p.\n", fd, handle); ++ ++ *obj = add_to_list( handle, type, fd, shm_idx ? get_shm( shm_idx ) : 0 ); ++ return ret; ++} ++ + NTSTATUS esync_close( HANDLE handle ) + { + UINT_PTR entry, idx = handle_to_index( handle, &entry ); +@@ -268,10 +334,11 @@ NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) + struct semaphore *semaphore; + uint64_t count64 = count; + ULONG current; ++ NTSTATUS ret; + + TRACE("%p, %d, %p.\n", handle, (int)count, prev); + +- if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; ++ if ((ret = get_object( handle, &obj))) return ret; + semaphore = obj->shm; + + do +@@ -310,10 +377,11 @@ NTSTATUS esync_set_event( HANDLE handle ) + { + static const uint64_t value = 1; + struct esync *obj; ++ NTSTATUS ret; + + TRACE("%p.\n", handle); + +- if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; ++ if ((ret = get_object( handle, &obj))) return ret; + + if (write( obj->fd, &value, sizeof(value) ) == -1) + ERR("write: %s\n", strerror(errno)); +@@ -325,10 +393,11 @@ NTSTATUS esync_reset_event( HANDLE handle ) + { + uint64_t value; + struct esync *obj; ++ NTSTATUS ret; + + TRACE("%p.\n", handle); + +- if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; ++ if ((ret = get_object( handle, &obj))) return ret; + + if (read( obj->fd, &value, sizeof(value) ) == -1 && errno != EWOULDBLOCK && errno != EAGAIN) + ERR("read: %s\n", strerror(errno)); +@@ -417,10 +486,13 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an + + for (i = 0; i < count; i++) + { +- if ((objs[i] = get_cached_object( handles[i] ))) ++ ret = get_object( handles[i], &objs[i] ); ++ if (ret == STATUS_SUCCESS) + has_esync = 1; +- else ++ else if (ret == STATUS_NOT_IMPLEMENTED) + has_server = 1; ++ else ++ return ret; + } + + if (has_esync && has_server) +@@ -473,7 +545,7 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an + int64_t value; + ssize_t size; + +- if (obj->type == ESYNC_MANUAL_EVENT) ++ if (obj->type == ESYNC_MANUAL_EVENT || obj->type == ESYNC_MANUAL_SERVER) + { + /* Don't grab the object, just check if it's signaled. */ + if (fds[i].revents & POLLIN) +diff --git a/server/esync.c b/server/esync.c +index 44214e5fe02..60e98936455 100644 +--- a/server/esync.c ++++ b/server/esync.c +@@ -313,6 +313,22 @@ int esync_create_fd( int initval, int flags ) + #endif + } + ++/* Wake up a server-side esync object. */ ++void esync_wake_up( struct object *obj ) ++{ ++ static const uint64_t value = 1; ++ enum esync_type dummy; ++ int fd; ++ ++ if (obj->ops->get_esync_fd) ++ { ++ fd = obj->ops->get_esync_fd( obj, &dummy ); ++ ++ if (write( fd, &value, sizeof(value) ) == -1) ++ perror( "esync: write" ); ++ } ++} ++ + DECL_HANDLER(create_esync) + { + struct esync *esync; +diff --git a/server/esync.h b/server/esync.h +index 8522d8a69ae..1241e6d9f1a 100644 +--- a/server/esync.h ++++ b/server/esync.h +@@ -23,3 +23,4 @@ + extern int do_esync(void); + void esync_init(void); + int esync_create_fd( int initval, int flags ); ++void esync_wake_up( struct object *obj ); +diff --git a/server/thread.c b/server/thread.c +index f579ffddad8..e744b98feaa 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -54,6 +54,7 @@ + #include "request.h" + #include "user.h" + #include "security.h" ++#include "esync.h" + + + /* thread queues */ +@@ -1218,6 +1219,9 @@ void wake_up( struct object *obj, int max ) + struct list *ptr; + int ret; + ++ if (do_esync()) ++ esync_wake_up( obj ); ++ + LIST_FOR_EACH( ptr, &obj->wait_queue ) + { + struct wait_queue_entry *entry = LIST_ENTRY( ptr, struct wait_queue_entry, entry ); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0022-server-Create-eventfd-file-descriptors-for-event-obj.patch b/0007-proton-esync-fsync/0022-server-Create-eventfd-file-descriptors-for-event-obj.patch new file mode 100644 index 0000000..7a86c64 --- /dev/null +++ b/0007-proton-esync-fsync/0022-server-Create-eventfd-file-descriptors-for-event-obj.patch @@ -0,0 +1,144 @@ +From 4b3bbaaa8ca4bad55cdecc530af304c147b18311 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Fri, 8 Jun 2018 21:01:24 -0500 +Subject: [PATCH 0442/2346] server: Create eventfd file descriptors for event + objects. + +We still need this, since there are some events which the server signals. + +This lets system processes shut down. + +Wine-Staging: eventfd_synchronization +--- + server/esync.c | 8 ++++++++ + server/esync.h | 1 + + server/event.c | 29 +++++++++++++++++++++++++++-- + 3 files changed, 36 insertions(+), 2 deletions(-) + +diff --git a/server/esync.c b/server/esync.c +index 60e98936455..b37438cbecc 100644 +--- a/server/esync.c ++++ b/server/esync.c +@@ -329,6 +329,14 @@ void esync_wake_up( struct object *obj ) + } + } + ++void esync_clear( int fd ) ++{ ++ uint64_t value; ++ ++ /* we don't care about the return value */ ++ read( fd, &value, sizeof(value) ); ++} ++ + DECL_HANDLER(create_esync) + { + struct esync *esync; +diff --git a/server/esync.h b/server/esync.h +index 1241e6d9f1a..d259b5f604d 100644 +--- a/server/esync.h ++++ b/server/esync.h +@@ -24,3 +24,4 @@ extern int do_esync(void); + void esync_init(void); + int esync_create_fd( int initval, int flags ); + void esync_wake_up( struct object *obj ); ++void esync_clear( int fd ); +diff --git a/server/event.c b/server/event.c +index c727bfdd1ba..f1a88e3d23f 100644 +--- a/server/event.c ++++ b/server/event.c +@@ -35,6 +35,7 @@ + #include "thread.h" + #include "request.h" + #include "security.h" ++#include "esync.h" + + static const WCHAR event_name[] = {'E','v','e','n','t'}; + +@@ -56,13 +57,16 @@ struct event + struct list kernel_object; /* list of kernel object pointers */ + int manual_reset; /* is it a manual reset event? */ + int signaled; /* event has been signaled */ ++ int esync_fd; /* esync file descriptor */ + }; + + static void event_dump( struct object *obj, int verbose ); + static int event_signaled( struct object *obj, struct wait_queue_entry *entry ); + static void event_satisfied( struct object *obj, struct wait_queue_entry *entry ); ++static int event_get_esync_fd( struct object *obj, enum esync_type *type ); + static int event_signal( struct object *obj, unsigned int access); + static struct list *event_get_kernel_obj_list( struct object *obj ); ++static void event_destroy( struct object *obj ); + + static const struct object_ops event_ops = + { +@@ -72,7 +76,7 @@ static const struct object_ops event_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + event_signaled, /* signaled */ +- NULL, /* get_esync_fd */ ++ event_get_esync_fd, /* get_esync_fd */ + event_satisfied, /* satisfied */ + event_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -86,7 +90,7 @@ static const struct object_ops event_ops = + no_open_file, /* open_file */ + event_get_kernel_obj_list, /* get_kernel_obj_list */ + no_close_handle, /* close_handle */ +- no_destroy /* destroy */ ++ event_destroy /* destroy */ + }; + + +@@ -152,6 +156,9 @@ struct event *create_event( struct object *root, const struct unicode_str *name, + list_init( &event->kernel_object ); + event->manual_reset = manual_reset; + event->signaled = initial_state; ++ ++ if (do_esync()) ++ event->esync_fd = esync_create_fd( initial_state, 0 ); + } + } + return event; +@@ -180,6 +187,9 @@ void set_event( struct event *event ) + void reset_event( struct event *event ) + { + event->signaled = 0; ++ ++ if (do_esync()) ++ esync_clear( event->esync_fd ); + } + + static void event_dump( struct object *obj, int verbose ) +@@ -197,6 +207,13 @@ static int event_signaled( struct object *obj, struct wait_queue_entry *entry ) + return event->signaled; + } + ++static int event_get_esync_fd( struct object *obj, enum esync_type *type ) ++{ ++ struct event *event = (struct event *)obj; ++ *type = event->manual_reset ? ESYNC_MANUAL_SERVER : ESYNC_AUTO_SERVER; ++ return event->esync_fd; ++} ++ + static void event_satisfied( struct object *obj, struct wait_queue_entry *entry ) + { + struct event *event = (struct event *)obj; +@@ -225,6 +242,14 @@ static struct list *event_get_kernel_obj_list( struct object *obj ) + return &event->kernel_object; + } + ++static void event_destroy( struct object *obj ) ++{ ++ struct event *event = (struct event *)obj; ++ ++ if (do_esync()) ++ close( event->esync_fd ); ++} ++ + struct keyed_event *create_keyed_event( struct object *root, const struct unicode_str *name, + unsigned int attr, const struct security_descriptor *sd ) + { +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0023-server-Allow-re-setting-esync-events-on-the-server-s.patch b/0007-proton-esync-fsync/0023-server-Allow-re-setting-esync-events-on-the-server-s.patch new file mode 100644 index 0000000..658f410 --- /dev/null +++ b/0007-proton-esync-fsync/0023-server-Allow-re-setting-esync-events-on-the-server-s.patch @@ -0,0 +1,118 @@ +From edfac69959a40121a7e3aa22981bbe03a8cd1119 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Fri, 8 Jun 2018 21:43:37 -0500 +Subject: [PATCH 0443/2346] server: Allow (re)setting esync events on the + server side. + +Some server calls pass an event handle, most notably asyncs. We need to be +able to handle these correctly. Accordingly we pass them along to esync if +it turns out the underlying object is actually an esync object. + +In an ideal world we'd just convert all instances of events on the server +side to use esyncs instead. But we want to keep esync perfectly configurable, +so this is how we do it. + +Wine-Staging: eventfd_synchronization +--- + server/esync.c | 22 +++++++++++++++++++++- + server/esync.h | 6 ++++++ + server/event.c | 15 +++++++++++++++ + 3 files changed, 42 insertions(+), 1 deletion(-) + +diff --git a/server/esync.c b/server/esync.c +index b37438cbecc..669afbc70d7 100644 +--- a/server/esync.c ++++ b/server/esync.c +@@ -114,7 +114,7 @@ struct esync + static void esync_dump( struct object *obj, int verbose ); + static void esync_destroy( struct object *obj ); + +-static const struct object_ops esync_ops = ++const struct object_ops esync_ops = + { + sizeof(struct esync), /* size */ + &no_type, /* type */ +@@ -337,6 +337,26 @@ void esync_clear( int fd ) + read( fd, &value, sizeof(value) ); + } + ++/* Server-side event support. */ ++void esync_set_event( struct esync *esync ) ++{ ++ static const uint64_t value = 1; ++ ++ assert( esync->obj.ops == &esync_ops ); ++ if (write( esync->fd, &value, sizeof(value) ) == -1) ++ perror( "esync: write" ); ++} ++ ++void esync_reset_event( struct esync *esync ) ++{ ++ static uint64_t value = 1; ++ ++ assert( esync->obj.ops == &esync_ops ); ++ ++ /* we don't care about the return value */ ++ read( esync->fd, &value, sizeof(value) ); ++} ++ + DECL_HANDLER(create_esync) + { + struct esync *esync; +diff --git a/server/esync.h b/server/esync.h +index d259b5f604d..689d8569b73 100644 +--- a/server/esync.h ++++ b/server/esync.h +@@ -25,3 +25,9 @@ void esync_init(void); + int esync_create_fd( int initval, int flags ); + void esync_wake_up( struct object *obj ); + void esync_clear( int fd ); ++ ++struct esync; ++ ++extern const struct object_ops esync_ops; ++void esync_set_event( struct esync *esync ); ++void esync_reset_event( struct esync *esync ); +diff --git a/server/event.c b/server/event.c +index f1a88e3d23f..f4ca3e48c6f 100644 +--- a/server/event.c ++++ b/server/event.c +@@ -166,6 +166,10 @@ struct event *create_event( struct object *root, const struct unicode_str *name, + + struct event *get_event_obj( struct process *process, obj_handle_t handle, unsigned int access ) + { ++ struct object *obj; ++ if (do_esync() && (obj = get_handle_obj( process, handle, access, &esync_ops))) ++ return (struct event *)obj; /* even though it's not an event */ ++ + return (struct event *)get_handle_obj( process, handle, access, &event_ops ); + } + +@@ -179,6 +183,12 @@ static void pulse_event( struct event *event ) + + void set_event( struct event *event ) + { ++ if (do_esync() && event->obj.ops == &esync_ops) ++ { ++ esync_set_event( (struct esync *)event ); ++ return; ++ } ++ + event->signaled = 1; + /* wake up all waiters if manual reset, a single one otherwise */ + wake_up( &event->obj, !event->manual_reset ); +@@ -186,6 +196,11 @@ void set_event( struct event *event ) + + void reset_event( struct event *event ) + { ++ if (do_esync() && event->obj.ops == &esync_ops) ++ { ++ esync_reset_event( (struct esync *)event ); ++ return; ++ } + event->signaled = 0; + + if (do_esync()) +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0024-ntdll-Try-again-if-poll-returns-EINTR.patch b/0007-proton-esync-fsync/0024-ntdll-Try-again-if-poll-returns-EINTR.patch new file mode 100644 index 0000000..92a8290 --- /dev/null +++ b/0007-proton-esync-fsync/0024-ntdll-Try-again-if-poll-returns-EINTR.patch @@ -0,0 +1,70 @@ +From 2b4d4ea92fbc8b06c21cef2eb2d8a4e3e0514503 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Fri, 8 Jun 2018 21:58:37 -0500 +Subject: [PATCH 0444/2346] ntdll: Try again if poll() returns EINTR. + +I originally had this return STATUS_USER_APC, but that isn't correct. The +server code here is a bit confusing, but only the thread that waits *during* +the suspend should receive STATUS_USER_APC (and I imagine that it really +should receive STATUS_KERNEL_APC instead). The thread that is suspended +should just keep on waiting. + +Besides, we could be suspended for reasons other than to deliver a system +APC. + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 32 +++++++++++++++++++++----------- + 1 file changed, 21 insertions(+), 11 deletions(-) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index e783517f644..2f402eb77cd 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -421,22 +421,32 @@ static LONGLONG update_timeout( ULONGLONG end ) + + static int do_poll( struct pollfd *fds, nfds_t nfds, ULONGLONG *end ) + { +- if (end) ++ int ret; ++ ++ do + { +- LONGLONG timeleft = update_timeout( *end ); ++ if (end) ++ { ++ LONGLONG timeleft = update_timeout( *end ); + + #ifdef HAVE_PPOLL +- /* We use ppoll() if available since the time granularity is better. */ +- struct timespec tmo_p; +- tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; +- tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; +- return ppoll( fds, nfds, &tmo_p, NULL ); ++ /* We use ppoll() if available since the time granularity is better. */ ++ struct timespec tmo_p; ++ tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; ++ tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; ++ ret = ppoll( fds, nfds, &tmo_p, NULL ); + #else +- return poll( fds, nfds, timeleft / TICKSPERMSEC ); ++ ret = poll( fds, nfds, timeleft / TICKSPERMSEC ); + #endif +- } +- else +- return poll( fds, nfds, -1 ); ++ } ++ else ++ ret = poll( fds, nfds, -1 ); ++ ++ /* If we receive EINTR we were probably suspended (SIGUSR1), possibly for a ++ * system APC. The right thing to do is just try again. */ ++ } while (ret < 0 && errno == EINTR); ++ ++ return ret; + } + + static void update_grabbed_object( struct esync *obj ) +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0025-server-Create-eventfd-file-descriptors-for-thread-ob.patch b/0007-proton-esync-fsync/0025-server-Create-eventfd-file-descriptors-for-thread-ob.patch new file mode 100644 index 0000000..297ceb6 --- /dev/null +++ b/0007-proton-esync-fsync/0025-server-Create-eventfd-file-descriptors-for-thread-ob.patch @@ -0,0 +1,90 @@ +From 1d1b08a9f3723c4494c8b3e1817d25dc4add0c4f Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Fri, 8 Jun 2018 22:04:29 -0500 +Subject: [PATCH 0445/2346] server: Create eventfd file descriptors for thread + objects. + +Wine-Staging: eventfd_synchronization +--- + server/thread.c | 17 ++++++++++++++++- + server/thread.h | 1 + + 2 files changed, 17 insertions(+), 1 deletion(-) + +diff --git a/server/thread.c b/server/thread.c +index e744b98feaa..69b919d400e 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -181,6 +181,7 @@ struct type_descr thread_type = + + static void dump_thread( struct object *obj, int verbose ); + static int thread_signaled( struct object *obj, struct wait_queue_entry *entry ); ++static int thread_get_esync_fd( struct object *obj, enum esync_type *type ); + static unsigned int thread_map_access( struct object *obj, unsigned int access ); + static void thread_poll_event( struct fd *fd, int event ); + static struct list *thread_get_kernel_obj_list( struct object *obj ); +@@ -194,7 +195,7 @@ static const struct object_ops thread_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + thread_signaled, /* signaled */ +- NULL, /* get_esync_fd */ ++ thread_get_esync_fd, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -262,6 +263,7 @@ static inline void init_thread_structure( struct thread *thread ) + thread->context = NULL; + thread->teb = 0; + thread->entry_point = 0; ++ thread->esync_fd = -1; + thread->system_regs = 0; + thread->queue = NULL; + thread->wait = NULL; +@@ -474,6 +476,9 @@ struct thread *create_thread( int fd, struct process *process, const struct secu + } + } + ++ if (do_esync()) ++ thread->esync_fd = esync_create_fd( 0, 0 ); ++ + set_fd_events( thread->request_fd, POLLIN ); /* start listening to events */ + add_process_thread( thread->process, thread ); + return thread; +@@ -556,6 +561,9 @@ static void destroy_thread( struct object *obj ) + release_object( thread->process ); + if (thread->id) free_ptid( thread->id ); + if (thread->token) release_object( thread->token ); ++ ++ if (do_esync()) ++ close( thread->esync_fd ); + } + + /* dump a thread on stdout for debugging purposes */ +@@ -574,6 +582,13 @@ static int thread_signaled( struct object *obj, struct wait_queue_entry *entry ) + return (mythread->state == TERMINATED); + } + ++static int thread_get_esync_fd( struct object *obj, enum esync_type *type ) ++{ ++ struct thread *thread = (struct thread *)obj; ++ *type = ESYNC_MANUAL_SERVER; ++ return thread->esync_fd; ++} ++ + static unsigned int thread_map_access( struct object *obj, unsigned int access ) + { + access = default_map_access( obj, access ); +diff --git a/server/thread.h b/server/thread.h +index 0c28242533e..8086a98156e 100644 +--- a/server/thread.h ++++ b/server/thread.h +@@ -54,6 +54,7 @@ struct thread + struct process *process; + thread_id_t id; /* thread id */ + struct list mutex_list; /* list of currently owned mutexes */ ++ int esync_fd; /* esync file descriptor (signalled on exit) */ + unsigned int system_regs; /* which system regs have been set */ + struct msg_queue *queue; /* message queue */ + struct thread_wait *wait; /* current wait condition if sleeping */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0026-server-Create-eventfd-file-descriptors-for-message-q.patch b/0007-proton-esync-fsync/0026-server-Create-eventfd-file-descriptors-for-message-q.patch new file mode 100644 index 0000000..c90fe27 --- /dev/null +++ b/0007-proton-esync-fsync/0026-server-Create-eventfd-file-descriptors-for-message-q.patch @@ -0,0 +1,132 @@ +From 4caea3cb53a249f3d9d20e6ddc56e2367eb89bae Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 16:01:56 -0500 +Subject: [PATCH 0447/2346] server: Create eventfd file descriptors for message + queues. + +Wine-Staging: eventfd_synchronization +--- + server/queue.c | 30 +++++++++++++++++++++++++++++- + 1 file changed, 29 insertions(+), 1 deletion(-) + +diff --git a/server/queue.c b/server/queue.c +index e709f0348f8..a0071d231cc 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -42,6 +42,7 @@ + #include "process.h" + #include "request.h" + #include "user.h" ++#include "esync.h" + + #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE + #define WM_NCMOUSELAST (WM_NCMOUSEFIRST+(WM_MOUSELAST-WM_MOUSEFIRST)) +@@ -135,6 +136,7 @@ struct msg_queue + int keystate_lock; /* owns an input keystate lock */ + const queue_shm_t *shared; /* queue in session shared memory */ + unsigned int ignore_post_msg; /* ignore post messages newer than this unique id */ ++ int esync_fd; /* esync file descriptor (signalled on message) */ + }; + + struct hotkey +@@ -151,6 +153,7 @@ static void msg_queue_dump( struct object *obj, int verbose ); + static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *entry ); + static void msg_queue_remove_queue( struct object *obj, struct wait_queue_entry *entry ); + static int msg_queue_signaled( struct object *obj, struct wait_queue_entry *entry ); ++static int msg_queue_get_esync_fd( struct object *obj, enum esync_type *type ); + static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *entry ); + static void msg_queue_destroy( struct object *obj ); + static void msg_queue_poll_event( struct fd *fd, int event ); +@@ -166,7 +169,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 */ +- NULL, /* get_esync_fd */ ++ msg_queue_get_esync_fd, /* get_esync_fd */ + msg_queue_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -336,6 +339,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ + queue->last_get_msg = current_time; + queue->keystate_lock = 0; + queue->ignore_post_msg = 0; ++ queue->esync_fd = -1; + list_init( &queue->send_result ); + list_init( &queue->callback_result ); + list_init( &queue->pending_timers ); +@@ -348,6 +352,9 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ + } + SHARED_WRITE_END + ++ if (do_esync()) ++ queue->esync_fd = esync_create_fd( 0, 0 ); ++ + thread->queue = queue; + } + if (new_input) +@@ -693,6 +700,9 @@ static inline void clear_queue_bits( struct msg_queue *queue, unsigned int bits + { + const queue_shm_t *queue_shm = queue->shared; + ++ if (do_esync() && !is_signaled( queue )) ++ esync_clear( queue->esync_fd ); ++ + SHARED_WRITE_BEGIN( queue_shm, queue_shm_t ) + { + shared->wake_bits &= ~bits; +@@ -1264,6 +1274,13 @@ static int msg_queue_signaled( struct object *obj, struct wait_queue_entry *entr + return ret || is_signaled( queue ); + } + ++static int msg_queue_get_esync_fd( struct object *obj, enum esync_type *type ) ++{ ++ struct msg_queue *queue = (struct msg_queue *)obj; ++ *type = ESYNC_QUEUE; ++ return queue->esync_fd; ++} ++ + static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *entry ) + { + struct msg_queue *queue = (struct msg_queue *)obj; +@@ -1320,6 +1337,7 @@ static void cleanup_msg_queue( struct msg_queue *queue ) + if (queue->hooks) release_object( queue->hooks ); + if (queue->fd) release_object( queue->fd ); + if (queue->shared) free_shared_object( queue->shared ); ++ if (do_esync()) close( queue->esync_fd ); + } + + static void msg_queue_destroy( struct object *obj ) +@@ -2897,6 +2915,9 @@ DECL_HANDLER(set_queue_mask) + } + else wake_up( &queue->obj, 0 ); + } ++ ++ if (do_esync() && !is_signaled( queue )) ++ esync_clear( queue->esync_fd ); + } + } + +@@ -2911,6 +2932,9 @@ DECL_HANDLER(get_queue_status) + reply->wake_bits = queue_shm->wake_bits; + reply->changed_bits = queue_shm->changed_bits; + ++ if (do_esync() && !is_signaled( queue )) ++ esync_clear( queue->esync_fd ); ++ + SHARED_WRITE_BEGIN( queue_shm, queue_shm_t ) + { + shared->changed_bits &= ~req->clear_bits; +@@ -3168,6 +3192,10 @@ DECL_HANDLER(get_message) + SHARED_WRITE_END; + + set_error( STATUS_PENDING ); /* FIXME */ ++ ++ if (do_esync() && !is_signaled( queue )) ++ esync_clear( queue->esync_fd ); ++ + return; + + found_msg: +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0027-server-ntdll-Implement-message-waits.patch b/0007-proton-esync-fsync/0027-server-ntdll-Implement-message-waits.patch new file mode 100644 index 0000000..6b23477 --- /dev/null +++ b/0007-proton-esync-fsync/0027-server-ntdll-Implement-message-waits.patch @@ -0,0 +1,173 @@ +From dcd0f106ec9a64ddc0eb3fb94003290987b25e8a Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 16:11:23 -0500 +Subject: [PATCH 0448/2346] server, ntdll: Implement message waits. + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 51 +++++++++++++++++++++++++++++++++++++++-- + server/protocol.def | 5 ++++ + server/queue.c | 21 +++++++++++++++++ + 3 files changed, 75 insertions(+), 2 deletions(-) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 2f402eb77cd..91ac73399e5 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -472,12 +472,13 @@ static void update_grabbed_object( struct esync *obj ) + + /* A value of STATUS_NOT_IMPLEMENTED returned from this function means that we + * need to delegate to server_select(). */ +-NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, ++static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, + BOOLEAN alertable, const LARGE_INTEGER *timeout ) + { + struct esync *objs[MAXIMUM_WAIT_OBJECTS]; + struct pollfd fds[MAXIMUM_WAIT_OBJECTS]; + int has_esync = 0, has_server = 0; ++ BOOL msgwait = FALSE; + LONGLONG timeleft; + LARGE_INTEGER now; + ULONGLONG end; +@@ -505,6 +506,9 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an + return ret; + } + ++ if (objs[count - 1] && objs[count - 1]->type == ESYNC_QUEUE) ++ msgwait = TRUE; ++ + if (has_esync && has_server) + FIXME("Can't wait on esync and server objects at the same time!\n"); + else if (has_server) +@@ -516,6 +520,9 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an + for (i = 0; i < count; i++) + TRACE(" %p", handles[i]); + ++ if (msgwait) ++ TRACE(" or driver events"); ++ + if (!timeout) + TRACE(", timeout = INFINITE.\n"); + else +@@ -555,7 +562,9 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an + int64_t value; + ssize_t size; + +- if (obj->type == ESYNC_MANUAL_EVENT || obj->type == ESYNC_MANUAL_SERVER) ++ if (obj->type == ESYNC_MANUAL_EVENT ++ || obj->type == ESYNC_MANUAL_SERVER ++ || obj->type == ESYNC_QUEUE) + { + /* Don't grab the object, just check if it's signaled. */ + if (fds[i].revents & POLLIN) +@@ -600,6 +609,44 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an + } + } + ++/* We need to let the server know when we are doing a message wait, and when we ++ * are done with one, so that all of the code surrounding hung queues works. ++ * We also need this for WaitForInputIdle(). */ ++static void server_set_msgwait( int in_msgwait ) ++{ ++ SERVER_START_REQ( esync_msgwait ) ++ { ++ req->in_msgwait = in_msgwait; ++ wine_server_call( req ); ++ } ++ SERVER_END_REQ; ++} ++ ++/* This is a very thin wrapper around the proper implementation above. The ++ * purpose is to make sure the server knows when we are doing a message wait. ++ * This is separated into a wrapper function since there are at least a dozen ++ * exit paths from esync_wait_objects(). */ ++NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, ++ BOOLEAN alertable, const LARGE_INTEGER *timeout ) ++{ ++ BOOL msgwait = FALSE; ++ struct esync *obj; ++ NTSTATUS ret; ++ ++ if (count && !get_object( handles[count - 1], &obj ) && obj->type == ESYNC_QUEUE) ++ { ++ msgwait = TRUE; ++ server_set_msgwait( 1 ); ++ } ++ ++ ret = __esync_wait_objects( count, handles, wait_any, alertable, timeout ); ++ ++ if (msgwait) ++ server_set_msgwait( 0 ); ++ ++ return ret; ++} ++ + void esync_init(void) + { + struct stat st; +diff --git a/server/protocol.def b/server/protocol.def +index 6e67af1636e..2d6581d5d6c 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3970,3 +3970,8 @@ enum esync_type + int type; + unsigned int shm_idx; + @END ++ ++/* Notify the server that we are doing a message wait or done with one. */ ++@REQ(esync_msgwait) ++ int in_msgwait; /* are we in a message wait? */ ++@END +diff --git a/server/queue.c b/server/queue.c +index a0071d231cc..ce818042475 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -137,6 +137,7 @@ struct msg_queue + int keystate_lock; /* owns an input keystate lock */ + const queue_shm_t *shared; /* thread queue shared memory ptr */ + int esync_fd; /* esync file descriptor (signalled on message) */ ++ int esync_in_msgwait; /* our thread is currently waiting on us */ + }; + + struct hotkey +@@ -340,6 +341,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ + queue->keystate_lock = 0; + queue->shared = thread->queue_shared; + queue->esync_fd = -1; ++ queue->esync_in_msgwait = 0; + list_init( &queue->send_result ); + list_init( &queue->callback_result ); + list_init( &queue->pending_timers ); +@@ -1219,6 +1221,10 @@ static int is_queue_hung( struct msg_queue *queue ) + if (get_wait_queue_thread(entry)->queue == queue) + return 0; /* thread is waiting on queue -> not hung */ + } ++ ++ if (do_esync() && queue->esync_in_msgwait) ++ return 0; /* thread is waiting on queue in absentia -> not hung */ ++ + return 1; + } + +@@ -3949,3 +3955,18 @@ DECL_HANDLER(update_rawinput_devices) + process->rawinput_mouse = find_rawinput_device( process, 1, 2 ); + process->rawinput_kbd = find_rawinput_device( process, 1, 6 ); + } ++ ++DECL_HANDLER(esync_msgwait) ++{ ++ struct msg_queue *queue = get_current_queue(); ++ ++ if (!queue) return; ++ queue->esync_in_msgwait = req->in_msgwait; ++ ++ if (current->process->idle_event && !(queue->wake_mask & QS_SMRESULT)) ++ set_event( current->process->idle_event ); ++ ++ /* and start/stop waiting on the driver */ ++ if (queue->fd) ++ set_fd_events( queue->fd, req->in_msgwait ? POLLIN : 0 ); ++} +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0028-server-Create-eventfd-descriptors-for-device-manager.patch b/0007-proton-esync-fsync/0028-server-Create-eventfd-descriptors-for-device-manager.patch new file mode 100644 index 0000000..b609cc2 --- /dev/null +++ b/0007-proton-esync-fsync/0028-server-Create-eventfd-descriptors-for-device-manager.patch @@ -0,0 +1,109 @@ +From 67e226dcbabfe017accf8a615de92af64df3f012 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 9 Jun 2018 15:39:37 -0500 +Subject: [PATCH 0449/2346] server: Create eventfd descriptors for device + manager objects. + +We don't have to worry about synchronization here because +wine_ntoskrnl_main_loop() is only ever called from one thread per winedevice +process. + +This lets drivers like mountmgr finally work, and so winecfg can open the +Drives tab. + +Wine-Staging: eventfd_synchronization +--- + server/device.c | 24 +++++++++++++++++++++++- + 1 file changed, 23 insertions(+), 1 deletion(-) + +diff --git a/server/device.c b/server/device.c +index f730fa81afa..c45d0102a56 100644 +--- a/server/device.c ++++ b/server/device.c +@@ -38,6 +38,7 @@ + #include "handle.h" + #include "request.h" + #include "process.h" ++#include "esync.h" + + /* IRP object */ + +@@ -93,10 +94,12 @@ struct device_manager + struct list requests; /* list of pending irps across all devices */ + struct irp_call *current_call; /* call currently executed on client side */ + struct wine_rb_tree kernel_objects; /* map of objects that have client side pointer associated */ ++ int esync_fd; /* esync file descriptor */ + }; + + static void device_manager_dump( struct object *obj, int verbose ); + static int device_manager_signaled( struct object *obj, struct wait_queue_entry *entry ); ++static int device_manager_get_esync_fd( struct object *obj, enum esync_type *type ); + static void device_manager_destroy( struct object *obj ); + + static const struct object_ops device_manager_ops = +@@ -107,7 +110,7 @@ static const struct object_ops device_manager_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + device_manager_signaled, /* signaled */ +- NULL, /* get_esync_fd */ ++ device_manager_get_esync_fd, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -751,6 +754,9 @@ static void delete_file( struct device_file *file ) + /* terminate all pending requests */ + LIST_FOR_EACH_ENTRY_SAFE( irp, next, &file->requests, struct irp_call, dev_entry ) + { ++ if (do_esync() && file->device->manager && list_empty( &file->device->manager->requests )) ++ esync_clear( file->device->manager->esync_fd ); ++ + list_remove( &irp->mgr_entry ); + set_irp_result( irp, STATUS_FILE_DELETED, NULL, 0, 0 ); + } +@@ -786,6 +792,13 @@ static int device_manager_signaled( struct object *obj, struct wait_queue_entry + return !list_empty( &manager->requests ); + } + ++static int device_manager_get_esync_fd( struct object *obj, enum esync_type *type ) ++{ ++ struct device_manager *manager = (struct device_manager *)obj; ++ *type = ESYNC_MANUAL_SERVER; ++ return manager->esync_fd; ++} ++ + static void device_manager_destroy( struct object *obj ) + { + struct device_manager *manager = (struct device_manager *)obj; +@@ -820,6 +833,9 @@ static void device_manager_destroy( struct object *obj ) + assert( !irp->file && !irp->async ); + release_object( irp ); + } ++ ++ if (do_esync()) ++ close( manager->esync_fd ); + } + + static struct device_manager *create_device_manager(void) +@@ -832,6 +848,9 @@ static struct device_manager *create_device_manager(void) + list_init( &manager->devices ); + list_init( &manager->requests ); + wine_rb_init( &manager->kernel_objects, compare_kernel_object ); ++ ++ if (do_esync()) ++ manager->esync_fd = esync_create_fd( 0, 0 ); + } + return manager; + } +@@ -1021,6 +1040,9 @@ DECL_HANDLER(get_next_device_request) + /* we already own the object if it's only on manager queue */ + if (irp->file) grab_object( irp ); + manager->current_call = irp; ++ ++ if (do_esync() && list_empty( &manager->requests )) ++ esync_clear( manager->esync_fd ); + } + else close_handle( current->process, reply->next ); + } +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0029-ntdll-server-Implement-NtCreateMutant.patch b/0007-proton-esync-fsync/0029-ntdll-server-Implement-NtCreateMutant.patch new file mode 100644 index 0000000..b5e9d19 --- /dev/null +++ b/0007-proton-esync-fsync/0029-ntdll-server-Implement-NtCreateMutant.patch @@ -0,0 +1,111 @@ +From 2efbebccaf4811f0be28e11e7a9bef6222a9230b Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 16:34:56 -0500 +Subject: [PATCH 0450/2346] ntdll, server: Implement NtCreateMutant(). + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 16 ++++++++++++++++ + dlls/ntdll/unix/esync.h | 3 +++ + dlls/ntdll/unix/sync.c | 4 ++++ + server/esync.c | 14 ++++++++++++++ + 4 files changed, 37 insertions(+) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 91ac73399e5..263b3ef2184 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -81,6 +81,13 @@ struct semaphore + }; + C_ASSERT(sizeof(struct semaphore) == 8); + ++struct mutex ++{ ++ DWORD tid; ++ int count; /* recursion count */ ++}; ++C_ASSERT(sizeof(struct mutex) == 8); ++ + struct event + { + int signaled; +@@ -405,6 +412,15 @@ NTSTATUS esync_reset_event( HANDLE handle ) + return STATUS_SUCCESS; + } + ++NTSTATUS esync_create_mutex( HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ) ++{ ++ TRACE("name %s, initial %d.\n", ++ attr ? debugstr_us(attr->ObjectName) : "", initial); ++ ++ return create_esync( ESYNC_MUTEX, handle, access, attr, initial ? 0 : 1, 0 ); ++} ++ + #define TICKSPERSEC 10000000 + #define TICKSPERMSEC 10000 + +diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h +index 6e5d6233a2e..9b2f88670d1 100644 +--- a/dlls/ntdll/unix/esync.h ++++ b/dlls/ntdll/unix/esync.h +@@ -31,6 +31,9 @@ extern NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, + extern NTSTATUS esync_reset_event( HANDLE handle ); + extern NTSTATUS esync_set_event( HANDLE handle ); + ++extern NTSTATUS esync_create_mutex( HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ); ++ + extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, + BOOLEAN alertable, const LARGE_INTEGER *timeout ); + +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index fdf4215039b..1bf4a381a8f 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -555,6 +555,10 @@ NTSTATUS WINAPI NtCreateMutant( HANDLE *handle, ACCESS_MASK access, const OBJECT + struct object_attributes *objattr; + + *handle = 0; ++ ++ if (do_esync()) ++ return esync_create_mutex( handle, access, attr, owned ); ++ + if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; + + SERVER_START_REQ( create_mutex ) +diff --git a/server/esync.c b/server/esync.c +index 669afbc70d7..3f1c61bc1f0 100644 +--- a/server/esync.c ++++ b/server/esync.c +@@ -202,6 +202,13 @@ struct semaphore + }; + C_ASSERT(sizeof(struct semaphore) == 8); + ++struct mutex ++{ ++ DWORD tid; ++ int count; /* recursion count */ ++}; ++C_ASSERT(sizeof(struct mutex) == 8); ++ + struct event + { + int signaled; +@@ -272,6 +279,13 @@ struct esync *create_esync( struct object *root, const struct unicode_str *name, + event->locked = 0; + break; + } ++ case ESYNC_MUTEX: ++ { ++ struct mutex *mutex = get_shm( esync->shm_idx ); ++ mutex->tid = initval ? 0 : current->id; ++ mutex->count = initval ? 0 : 1; ++ break; ++ } + default: + assert( 0 ); + } +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0030-ntdll-Implement-NtReleaseMutant.patch b/0007-proton-esync-fsync/0030-ntdll-Implement-NtReleaseMutant.patch new file mode 100644 index 0000000..fd0b9dc --- /dev/null +++ b/0007-proton-esync-fsync/0030-ntdll-Implement-NtReleaseMutant.patch @@ -0,0 +1,86 @@ +From c6ce38566956dac83f8b3e63b50578c54446ebbf Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 16:37:49 -0500 +Subject: [PATCH 0451/2346] ntdll: Implement NtReleaseMutant(). + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 34 ++++++++++++++++++++++++++++++++++ + dlls/ntdll/unix/esync.h | 1 + + dlls/ntdll/unix/sync.c | 3 +++ + 3 files changed, 38 insertions(+) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 263b3ef2184..829388bc68b 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -421,6 +421,40 @@ NTSTATUS esync_create_mutex( HANDLE *handle, ACCESS_MASK access, + return create_esync( ESYNC_MUTEX, handle, access, attr, initial ? 0 : 1, 0 ); + } + ++NTSTATUS esync_release_mutex( HANDLE *handle, LONG *prev ) ++{ ++ struct esync *obj; ++ struct mutex *mutex; ++ static const uint64_t value = 1; ++ NTSTATUS ret; ++ ++ TRACE("%p, %p.\n", handle, prev); ++ ++ if ((ret = get_object( handle, &obj ))) return ret; ++ mutex = obj->shm; ++ ++ /* This is thread-safe, because the only thread that can change the tid to ++ * or from our tid is ours. */ ++ if (mutex->tid != GetCurrentThreadId()) return STATUS_MUTANT_NOT_OWNED; ++ ++ if (prev) *prev = mutex->count; ++ ++ mutex->count--; ++ ++ if (!mutex->count) ++ { ++ /* This is also thread-safe, as long as signaling the file is the last ++ * thing we do. Other threads don't care about the tid if it isn't ++ * theirs. */ ++ mutex->tid = 0; ++ ++ if (write( obj->fd, &value, sizeof(value) ) == -1) ++ return errno_to_status( errno ); ++ } ++ ++ return STATUS_SUCCESS; ++} ++ + #define TICKSPERSEC 10000000 + #define TICKSPERMSEC 10000 + +diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h +index 9b2f88670d1..8eaa79a5823 100644 +--- a/dlls/ntdll/unix/esync.h ++++ b/dlls/ntdll/unix/esync.h +@@ -33,6 +33,7 @@ extern NTSTATUS esync_set_event( HANDLE handle ); + + extern NTSTATUS esync_create_mutex( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ); ++extern NTSTATUS esync_release_mutex( HANDLE *handle, LONG *prev ); + + extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, + BOOLEAN alertable, const LARGE_INTEGER *timeout ); +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 1bf4a381a8f..20391617e40 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -608,6 +608,9 @@ NTSTATUS WINAPI NtReleaseMutant( HANDLE handle, LONG *prev_count ) + { + unsigned int ret; + ++ if (do_esync()) ++ return esync_release_mutex( handle, prev_count ); ++ + SERVER_START_REQ( release_mutex ) + { + req->handle = wine_server_obj_handle( handle ); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0031-ntdll-Implement-waiting-on-mutexes.patch b/0007-proton-esync-fsync/0031-ntdll-Implement-waiting-on-mutexes.patch new file mode 100644 index 0000000..38e7fb4 --- /dev/null +++ b/0007-proton-esync-fsync/0031-ntdll-Implement-waiting-on-mutexes.patch @@ -0,0 +1,62 @@ +From 7cb103e34b950b766bce97d1ee8b79459c7fdaf7 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 16:42:13 -0500 +Subject: [PATCH 0452/2346] ntdll: Implement waiting on mutexes. + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 31 +++++++++++++++++++++++++++++-- + 1 file changed, 29 insertions(+), 2 deletions(-) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 829388bc68b..7c09f8a3503 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -501,7 +501,16 @@ static int do_poll( struct pollfd *fds, nfds_t nfds, ULONGLONG *end ) + + static void update_grabbed_object( struct esync *obj ) + { +- if (obj->type == ESYNC_SEMAPHORE) ++ if (obj->type == ESYNC_MUTEX) ++ { ++ struct mutex *mutex = obj->shm; ++ /* We don't have to worry about a race between this and read(); the ++ * fact that we grabbed it means the count is now zero, so nobody else ++ * can (and the only thread that can release it is us). */ ++ mutex->tid = GetCurrentThreadId(); ++ mutex->count++; ++ } ++ else if (obj->type == ESYNC_SEMAPHORE) + { + struct semaphore *semaphore = obj->shm; + /* We don't have to worry about a race between this and read(); the +@@ -587,7 +596,25 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA + { + for (i = 0; i < count; i++) + { +- fds[i].fd = objs[i] ? objs[i]->fd : -1; ++ struct esync *obj = objs[i]; ++ ++ if (obj && obj->type == ESYNC_MUTEX) ++ { ++ /* If we already own the mutex, return immediately. */ ++ /* Note: This violates the assumption that the *first* object ++ * to be signaled will be returned. If that becomes a problem, ++ * we can always check the state of each object before waiting. */ ++ struct mutex *mutex = (struct mutex *)obj; ++ ++ if (mutex->tid == GetCurrentThreadId()) ++ { ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ mutex->count++; ++ return i; ++ } ++ } ++ ++ fds[i].fd = obj ? obj->fd : -1; + fds[i].events = POLLIN; + } + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0032-ntdll-Implement-wait-all.patch b/0007-proton-esync-fsync/0032-ntdll-Implement-wait-all.patch new file mode 100644 index 0000000..38cb5d1 --- /dev/null +++ b/0007-proton-esync-fsync/0032-ntdll-Implement-wait-all.patch @@ -0,0 +1,187 @@ +From 4a3db556ba9c895b0a6f3230b57e421304c08b9a Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 16:47:38 -0500 +Subject: [PATCH 0453/2346] ntdll: Implement wait-all. + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 142 ++++++++++++++++++++++++++++++++++++---- + 1 file changed, 129 insertions(+), 13 deletions(-) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 7c09f8a3503..8874a16d475 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -541,7 +541,9 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA + LONGLONG timeleft; + LARGE_INTEGER now; + ULONGLONG end; +- int i, ret; ++ int64_t value; ++ ssize_t size; ++ int i, j, ret; + + NtQuerySystemTime( &now ); + if (timeout) +@@ -636,9 +638,6 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA + + if (obj) + { +- int64_t value; +- ssize_t size; +- + if (obj->type == ESYNC_MANUAL_EVENT + || obj->type == ESYNC_MANUAL_SERVER + || obj->type == ESYNC_QUEUE) +@@ -667,22 +666,139 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA + * we were waiting for. So keep waiting. */ + NtQuerySystemTime( &now ); + } +- else if (ret == 0) ++ else ++ goto err; ++ } ++ } ++ else ++ { ++ /* Wait-all is a little trickier to implement correctly. Fortunately, ++ * it's not as common. ++ * ++ * The idea is basically just to wait in sequence on every object in the ++ * set. Then when we're done, try to grab them all in a tight loop. If ++ * that fails, release any resources we've grabbed (and yes, we can ++ * reliably do this—it's just mutexes and semaphores that we have to ++ * put back, and in both cases we just put back 1), and if any of that ++ * fails we start over. ++ * ++ * What makes this inherently bad is that we might temporarily grab a ++ * resource incorrectly. Hopefully it'll be quick (and hey, it won't ++ * block on wineserver) so nobody will notice. Besides, consider: if ++ * object A becomes signaled but someone grabs it before we can grab it ++ * and everything else, then they could just as well have grabbed it ++ * before it became signaled. Similarly if object A was signaled and we ++ * were blocking on object B, then B becomes available and someone grabs ++ * A before we can, then they might have grabbed A before B became ++ * signaled. In either case anyone who tries to wait on A or B will be ++ * waiting for an instant while we put things back. */ ++ ++ while (1) ++ { ++tryagain: ++ /* First step: try to poll on each object in sequence. */ ++ fds[0].events = POLLIN; ++ for (i = 0; i < count; i++) + { +- TRACE("Wait timed out.\n"); +- return STATUS_TIMEOUT; ++ struct esync *obj = objs[i]; ++ ++ fds[0].fd = obj ? obj->fd : -1; ++ ++ if (obj && obj->type == ESYNC_MUTEX) ++ { ++ /* It might be ours. */ ++ struct mutex *mutex = obj->shm; ++ ++ if (mutex->tid == GetCurrentThreadId()) ++ continue; ++ } ++ ++ ret = do_poll( fds, 1, timeout ? &end : NULL ); ++ if (ret <= 0) ++ goto err; ++ ++ if (fds[0].revents & (POLLHUP | POLLERR | POLLNVAL)) ++ { ++ ERR("Polling on fd %d returned %#x.\n", fds[0].fd, fds[0].revents); ++ return STATUS_INVALID_HANDLE; ++ } + } +- else ++ ++ /* If we got here and we haven't timed out, that means all of the ++ * handles were signaled. Check to make sure they still are. */ ++ for (i = 0; i < count; i++) + { +- ERR("ppoll failed: %s\n", strerror( errno )); +- return errno_to_status( errno ); ++ fds[i].fd = objs[i] ? objs[i]->fd : -1; ++ fds[i].events = POLLIN; + } +- } ++ ++ /* Poll everything to see if they're still signaled. */ ++ ret = poll( fds, count, 0 ); ++ if (ret == count) ++ { ++ /* Quick, grab everything. */ ++ for (i = 0; i < count; i++) ++ { ++ struct esync *obj = objs[i]; ++ ++ switch (obj->type) ++ { ++ case ESYNC_MUTEX: ++ { ++ struct mutex *mutex = obj->shm; ++ if (mutex->tid == GetCurrentThreadId()) ++ break; ++ /* otherwise fall through */ ++ } ++ case ESYNC_SEMAPHORE: ++ case ESYNC_AUTO_EVENT: ++ if ((size = read( fds[i].fd, &value, sizeof(value) )) != sizeof(value)) ++ { ++ /* We were too slow. Put everything back. */ ++ value = 1; ++ for (j = i; j >= 0; j--) ++ { ++ if (write( obj->fd, &value, sizeof(value) ) == -1) ++ return errno_to_status( errno ); ++ } ++ ++ goto tryagain; /* break out of two loops and a switch */ ++ } ++ break; ++ default: ++ /* If a manual-reset event changed between there and ++ * here, it's shouldn't be a problem. */ ++ break; ++ } ++ } ++ ++ /* If we got here, we successfully waited on every object. */ ++ /* Make sure to let ourselves know that we grabbed the mutexes ++ * and semaphores. */ ++ for (i = 0; i < count; i++) ++ update_grabbed_object( objs[i] ); ++ ++ TRACE("Wait successful.\n"); ++ return STATUS_SUCCESS; ++ } ++ ++ /* If we got here, ppoll() returned less than all of our objects. ++ * So loop back to the beginning and try again. */ ++ } /* while(1) */ ++ } /* else (wait-all) */ ++ ++err: ++ /* We should only get here if poll() failed. */ ++ ++ if (ret == 0) ++ { ++ TRACE("Wait timed out.\n"); ++ return STATUS_TIMEOUT; + } + else + { +- FIXME("Wait-all not implemented.\n"); +- return STATUS_NOT_IMPLEMENTED; ++ ERR("ppoll failed: %s\n", strerror(errno)); ++ return errno_to_status( errno ); + } + } + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0033-esync-Add-a-README.patch b/0007-proton-esync-fsync/0033-esync-Add-a-README.patch new file mode 100644 index 0000000..2f6bf94 --- /dev/null +++ b/0007-proton-esync-fsync/0033-esync-Add-a-README.patch @@ -0,0 +1,205 @@ +From 6ca8127be5a379e1e72a64eedaa1f6149c0ed7dd Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 9 Jun 2018 22:44:57 -0500 +Subject: [PATCH 0454/2346] esync: Add a README. + +Wine-Staging: eventfd_synchronization +--- + README.esync | 184 +++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 184 insertions(+) + create mode 100644 README.esync + +diff --git a/README.esync b/README.esync +new file mode 100644 +index 00000000000..8fcb969011b +--- /dev/null ++++ b/README.esync +@@ -0,0 +1,184 @@ ++This is eventfd-based synchronization, or 'esync' for short. Turn it on with ++WINEESYNC=1 (note that it checks the presence and not the value); debug it ++with +esync. ++ ++The aim is to execute all synchronization operations in "user-space", that is, ++without going through wineserver. We do this using Linux's eventfd ++facility. The main impetus to using eventfd is so that we can poll multiple ++objects at once; in particular we can't do this with futexes, or pthread ++semaphores, or the like. The only way I know of to wait on any of multiple ++objects is to use select/poll/epoll to wait on multiple fds, and eventfd gives ++us those fds in a quite usable way. ++ ++Whenever a semaphore, event, or mutex is created, we have the server, instead ++of creating a traditional server-side event/semaphore/mutex, instead create an ++'esync' primitive. These live in esync.c and are very slim objects; in fact, ++they don't even know what type of primitive they are. The server is involved ++at all because we still need a way of creating named objects, passing handles ++to another process, etc. ++ ++The server creates an eventfd file descriptor with the requested parameters ++and passes it back to ntdll. ntdll creates an object of the appropriate type, ++then caches it in a table. This table is copied almost wholesale from the fd ++cache code in server.c. ++ ++Specific operations follow quite straightforwardly from eventfd: ++ ++* To release an object, or set an event, we simply write() to it. ++* An object is signalled if read() succeeds on it. Notably, we create all ++ eventfd descriptors with O_NONBLOCK, so that we can atomically check if an ++ object is signalled and grab it if it is. This also lets us reset events. ++* For objects whose state should not be reset upon waiting—e.g. manual-reset ++ events—we simply check for the POLLIN flag instead of reading. ++* Semaphores are handled by the EFD_SEMAPHORE flag. This matches up quite well ++ (although with some difficulties; see below). ++* Mutexes store their owner thread locally. This isn't reliable information if ++ a different process's thread owns the mutex, but this doesn't matter—a ++ thread should only care whether it owns the mutex, so it knows whether to ++ try waiting on it or simply to increase the recursion count. ++ ++The interesting part about esync is that (almost) all waits happen in ntdll, ++including those on server-bound objects. The idea here is that on the server ++side, for any waitable object, we create an eventfd file descriptor (not an ++esync primitive), and then pass it to ntdll if the program tries to wait on ++it. These are cached too, so only the first wait will require a round trip to ++the server. Then the server signals the file descriptor as appropriate, and ++thereby wakes up the client. So far this is implemented for processes, ++threads, message queues (difficult; see below), and device managers (necessary ++for drivers to work). All of these are necessarily server-bound, so we ++wouldn't really gain anything by signalling on the client side instead. Of ++course, except possibly for message queues, it's not likely that any program ++(cutting-edge D3D game or not) is going to be causing a great wineserver load ++by waiting on any of these objects; the motivation was rather to provide a way ++to wait on ntdll-bound and server-bound objects at the same time. ++ ++Some cases are still passed to the server, and there's probably no reason not ++to keep them that way. Those that I noticed while testing include: async ++objects, which are internal to the file APIs and never exposed to userspace, ++startup_info objects, which are internal to the loader and signalled when a ++process starts, and keyed events, which are exposed through an ntdll API ++(although not through kernel32) but can't be mixed with other objects (you ++have to use NtWaitForKeyedEvent()). Other cases include: named pipes, debug ++events, sockets, and timers. It's unlikely we'll want to optimize debug events ++or sockets (or any of the other, rather rare, objects), but it is possible ++we'll want to optimize named pipes or timers. ++ ++There were two sort of complications when working out the above. The first one ++was events. The trouble is that (1) the server actually creates some events by ++itself and (2) the server sometimes manipulates events passed by the ++client. Resolving the first case was easy enough, and merely entailed creating ++eventfd descriptors for the events the same way as for processes and threads ++(note that we don't really lose anything this way; the events include ++"LowMemoryCondition" and the event that signals system processes to shut ++down). For the second case I basically had to hook the server-side event ++functions to redirect to esync versions if the event was actually an esync ++primitive. ++ ++The second complication was message queues. The difficulty here is that X11 ++signals events by writing into a pipe (at least I think it's a pipe?), and so ++as a result wineserver has to poll on that descriptor. In theory we could just ++let wineserver do so and then signal us as appropriate, except that wineserver ++only polls on the pipe when the thread is waiting for events (otherwise we'd ++get e.g. keyboard input while the thread is doing something else, and spin ++forever trying to wake up a thread that doesn't care). The obvious solution is ++just to poll on that fd ourselves, and that's what I did—it's just that ++getting the fd from wineserver was kind of ugly, and the code for waiting was ++also kind of ugly basically because we have to wait on both X11's fd and the ++"normal" process/thread-style wineserver fd that we use to signal sent ++messages. The upshot about the whole thing was that races are basically ++impossible, since a thread can only wait on its own queue. ++ ++I had kind of figured that APCs just wouldn't work, but then poll() spat EINTR ++at me and I realized that this wasn't necessarily true. It seems that the ++server will suspend a thread when trying to deliver a system APC to a thread ++that's not waiting, and since the server has no idea that we're waiting it ++just suspends us. This of course interrupts poll(), which complains at us, and ++it turns out that just returning STATUS_USER_APC in that case is enough to ++make rpcrt4 happy. ++ ++There are a couple things that this infrastructure can't handle, although ++surprisingly there aren't that many. In particular: ++* We can't return the previous count on a semaphore, since we have no way to ++ query the count on a semaphore through eventfd. Currently the code lies and ++ returns 1 every time. We can make this work (in a single process, or [if ++ necessary] in multiple processes through shared memory) by keeping a count ++ locally. We can't guarantee that it's the exact count at the moment the ++ semaphore was released, but I guess any program that runs into that race ++ shouldn't be depending on that fact anyway. ++* Similarly, we can't enforce the maximum count on a semaphore, since we have ++ no way to get the current count and subsequently compare it with the ++ maximum. ++* We can't use NtQueryMutant to get the mutant's owner or count if it lives in ++ a different process. If necessary we can use shared memory to make this ++ work, I guess, but see below. ++* User APCs don't work. However, it's not impossible to make them work; in ++ particular I think this could be relatively easily implemented by waiting on ++ another internal file descriptor when we execute an alertable wait. ++* Implementing wait-all, i.e. WaitForMultipleObjects(..., TRUE, ...), is not ++ exactly possible the way we'd like it to be possible. In theory that ++ function should wait until it knows all objects are available, then grab ++ them all at once atomically. The server (like the kernel) can do this ++ because the server is single-threaded and can't race with itself. We can't ++ do this in ntdll, though. The approach I've taken I've laid out in great ++ detail in the relevant patch, but for a quick summary we poll on each object ++ until it's signaled (but don't grab it), check them all again, and if ++ they're all signaled we try to grab them all at once in a tight loop, and if ++ we fail on any of them we reset the count on whatever we shouldn't have ++ consumed. Such a blip would necessarily be very quick. ++* The whole patchset only works on Linux, where eventfd is available. However, ++ it should be possible to make it work on a Mac, since eventfd is just a ++ quicker, easier way to use pipes (i.e. instead of writing 1 to the fd you'd ++ write 1 byte; instead of reading a 64-bit value from the fd you'd read as ++ many bytes as you can carry, which is admittedly less than 2**64 but ++ can probably be something reasonable.) It's also possible, although I ++ haven't yet looked, to use some different kind of synchronization ++ primitives, but pipes would be easiest to tack onto this framework. ++* We might hit the maximum number of open fd's. On my system the soft limit is ++ 1024 and the hard limit is 1048576. I'm inclined to hope this won't be an ++ issue, since a hypothetical Linux port of any application might just as well ++ use the same number of eventfds. ++* PulseEvent() can't work the way it's supposed to work. Fortunately it's rare ++ and deprecated. It's also explicitly mentioned on MSDN that a thread can ++ miss the notification for a kernel APC, so in a sense we're not necessarily ++ doing anything wrong. ++ ++There are some things that are perfectly implementable but that I just haven't ++done yet: ++* NtOpen* (aka Open*). This is just a matter of adding another open_esync ++ request analogous to those for other server primitives. ++* NtQuery*. This can be done to some degree (the difficulties are outlined ++ above). That said, these APIs aren't exposed through kernel32 in any way, so ++ I doubt anyone is going to be using them. ++* SignalObjectAndWait(). The server combines this into a single operation, but ++ according to MSDN it doesn't need to be atomic, so we can just signal the ++ appropriate object and wait, and woe betide anyone who gets in the way of ++ those two operations. ++* Other synchronizable server primitives. It's unlikely we'll need any of ++ these, except perhaps named pipes (which would honestly be rather difficult) ++ and (maybe) timers. ++ ++This patchset was inspired by Daniel Santos' "hybrid synchronization" ++patchset. My idea was to create a framework whereby even contended waits could ++be executed in userspace, eliminating a lot of the complexity that his ++synchronization primitives used. I do however owe some significant gratitude ++toward him for setting me on the right path. ++ ++I've tried to maximize code separation, both to make any potential rebases ++easier and to ensure that esync is only active when configured. All code in ++existing source files is guarded with "if (do_esync())", and generally that ++condition is followed by "return esync_version_of_this_method(...);", where ++the latter lives in esync.c and is declared in esync.h. I've also tried to ++make the patchset very clear and readable—to write it as if I were going to ++submit it upstream. (Some intermediate patches do break things, which Wine is ++generally against, but I think it's for the better in this case.) I have cut ++some corners, though; there is some error checking missing, or implicit ++assumptions that the program is behaving correctly. ++ ++I've tried to be careful about races. There are a lot of comments whose ++purpose are basically to assure me that races are impossible. In most cases we ++don't have to worry about races since all of the low-level synchronization is ++done by the kernel. ++ ++Anyway, yeah, this is esync. Use it if you like. ++ ++--Zebediah Figura +\ No newline at end of file +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0034-ntdll-Implement-NtSignalAndWaitForSingleObject.patch b/0007-proton-esync-fsync/0034-ntdll-Implement-NtSignalAndWaitForSingleObject.patch new file mode 100644 index 0000000..181cbc1 --- /dev/null +++ b/0007-proton-esync-fsync/0034-ntdll-Implement-NtSignalAndWaitForSingleObject.patch @@ -0,0 +1,81 @@ +From f54eec6bf472cedebd2c37d8b99624057071123d Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 16:52:39 -0500 +Subject: [PATCH 0455/2346] ntdll: Implement NtSignalAndWaitForSingleObject(). + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 28 ++++++++++++++++++++++++++++ + dlls/ntdll/unix/esync.h | 2 ++ + dlls/ntdll/unix/sync.c | 3 +++ + 3 files changed, 33 insertions(+) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 8874a16d475..2c7702cd120 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -840,6 +840,34 @@ NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an + return ret; + } + ++NTSTATUS esync_signal_and_wait( HANDLE signal, HANDLE wait, BOOLEAN alertable, ++ const LARGE_INTEGER *timeout ) ++{ ++ struct esync *obj; ++ NTSTATUS ret; ++ ++ if ((ret = get_object( signal, &obj ))) return ret; ++ ++ switch (obj->type) ++ { ++ case ESYNC_SEMAPHORE: ++ ret = esync_release_semaphore( signal, 1, NULL ); ++ break; ++ case ESYNC_AUTO_EVENT: ++ case ESYNC_MANUAL_EVENT: ++ ret = esync_set_event( signal ); ++ break; ++ case ESYNC_MUTEX: ++ ret = esync_release_mutex( signal, NULL ); ++ break; ++ default: ++ return STATUS_OBJECT_TYPE_MISMATCH; ++ } ++ if (ret) return ret; ++ ++ return esync_wait_objects( 1, &wait, TRUE, alertable, timeout ); ++} ++ + void esync_init(void) + { + struct stat st; +diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h +index 8eaa79a5823..88a6d5c8975 100644 +--- a/dlls/ntdll/unix/esync.h ++++ b/dlls/ntdll/unix/esync.h +@@ -37,6 +37,8 @@ extern NTSTATUS esync_release_mutex( HANDLE *handle, LONG *prev ); + + extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, + BOOLEAN alertable, const LARGE_INTEGER *timeout ); ++extern NTSTATUS esync_signal_and_wait( HANDLE signal, HANDLE wait, BOOLEAN alertable, ++ const LARGE_INTEGER *timeout ); + + + /* We have to synchronize on the fd cache mutex so that our calls to receive_fd +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 20391617e40..12ed44f7a8e 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -1531,6 +1531,9 @@ NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE signal, HANDLE wait, + select_op_t select_op; + UINT flags = SELECT_INTERRUPTIBLE; + ++ if (do_esync()) ++ return esync_signal_and_wait( signal, wait, alertable, timeout ); ++ + if (!signal) return STATUS_INVALID_HANDLE; + + if (alertable) flags |= SELECT_ALERTABLE; +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0035-ntdll-Implement-NtOpenSemaphore.patch b/0007-proton-esync-fsync/0035-ntdll-Implement-NtOpenSemaphore.patch new file mode 100644 index 0000000..e297567 --- /dev/null +++ b/0007-proton-esync-fsync/0035-ntdll-Implement-NtOpenSemaphore.patch @@ -0,0 +1,175 @@ +From 97c459e2f765693d80bb9ce79a1f6725c67621bd Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 16:56:09 -0500 +Subject: [PATCH 0456/2346] ntdll: Implement NtOpenSemaphore(). + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 47 +++++++++++++++++++++++++++++++++++++++++ + dlls/ntdll/unix/esync.h | 2 ++ + dlls/ntdll/unix/sync.c | 4 ++++ + server/esync.c | 31 +++++++++++++++++++++++++++ + server/protocol.def | 12 +++++++++++ + 5 files changed, 96 insertions(+) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 2c7702cd120..ee550e29b74 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -326,6 +326,45 @@ static NTSTATUS create_esync( enum esync_type type, HANDLE *handle, ACCESS_MASK + return ret; + } + ++static NTSTATUS open_esync( enum esync_type type, HANDLE *handle, ++ ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr ) ++{ ++ NTSTATUS ret; ++ obj_handle_t fd_handle; ++ unsigned int shm_idx; ++ sigset_t sigset; ++ int fd; ++ ++ server_enter_uninterrupted_section( &fd_cache_mutex, &sigset ); ++ SERVER_START_REQ( open_esync ) ++ { ++ req->access = access; ++ req->attributes = attr->Attributes; ++ req->rootdir = wine_server_obj_handle( attr->RootDirectory ); ++ req->type = type; ++ if (attr->ObjectName) ++ wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length ); ++ if (!(ret = wine_server_call( req ))) ++ { ++ *handle = wine_server_ptr_handle( reply->handle ); ++ type = reply->type; ++ shm_idx = reply->shm_idx; ++ fd = receive_fd( &fd_handle ); ++ assert( wine_server_ptr_handle(fd_handle) == *handle ); ++ } ++ } ++ SERVER_END_REQ; ++ server_leave_uninterrupted_section( &fd_cache_mutex, &sigset ); ++ ++ if (!ret) ++ { ++ add_to_list( *handle, type, fd, shm_idx ? get_shm( shm_idx ) : 0 ); ++ ++ TRACE("-> handle %p, fd %d.\n", *handle, fd); ++ } ++ return ret; ++} ++ + extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max) + { +@@ -335,6 +374,14 @@ extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access, + return create_esync( ESYNC_SEMAPHORE, handle, access, attr, initial, max ); + } + ++NTSTATUS esync_open_semaphore( HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr ) ++{ ++ TRACE("name %s.\n", debugstr_us(attr->ObjectName)); ++ ++ return open_esync( ESYNC_SEMAPHORE, handle, access, attr ); ++} ++ + NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) + { + struct esync *obj; +diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h +index 88a6d5c8975..6818be9c16f 100644 +--- a/dlls/ntdll/unix/esync.h ++++ b/dlls/ntdll/unix/esync.h +@@ -24,6 +24,8 @@ extern NTSTATUS esync_close( HANDLE handle ); + + extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max); ++extern NTSTATUS esync_open_semaphore( HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr ); + extern NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ); + + extern NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 12ed44f7a8e..31253e2235b 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -300,6 +300,10 @@ NTSTATUS WINAPI NtOpenSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJEC + unsigned int ret; + + *handle = 0; ++ ++ if (do_esync()) ++ return esync_open_semaphore( handle, access, attr ); ++ + if ((ret = validate_open_object_attributes( attr ))) return ret; + + SERVER_START_REQ( open_semaphore ) +diff --git a/server/esync.c b/server/esync.c +index 3f1c61bc1f0..eca9b6aa67d 100644 +--- a/server/esync.c ++++ b/server/esync.c +@@ -410,6 +410,37 @@ DECL_HANDLER(create_esync) + if (root) release_object( root ); + } + ++DECL_HANDLER(open_esync) ++{ ++ struct unicode_str name = get_req_unicode_str(); ++ ++ reply->handle = open_object( current->process, req->rootdir, req->access, ++ &esync_ops, &name, req->attributes ); ++ ++ /* send over the fd */ ++ if (reply->handle) ++ { ++ struct esync *esync; ++ ++ if (!(esync = (struct esync *)get_handle_obj( current->process, reply->handle, ++ 0, &esync_ops ))) ++ return; ++ ++ if (!type_matches( req->type, esync->type )) ++ { ++ set_error( STATUS_OBJECT_TYPE_MISMATCH ); ++ release_object( esync ); ++ return; ++ } ++ ++ reply->type = esync->type; ++ reply->shm_idx = esync->shm_idx; ++ ++ send_client_fd( current->process, esync->fd, reply->handle ); ++ release_object( esync ); ++ } ++} ++ + /* Retrieve a file descriptor for an esync object which will be signaled by the + * server. The client should only read from (i.e. wait on) this object. */ + DECL_HANDLER(get_esync_fd) +diff --git a/server/protocol.def b/server/protocol.def +index 2d6581d5d6c..0786eca012b 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3963,6 +3963,18 @@ enum esync_type + unsigned int shm_idx; + @END + ++@REQ(open_esync) ++ unsigned int access; /* wanted access rights */ ++ unsigned int attributes; /* object attributes */ ++ obj_handle_t rootdir; /* root directory */ ++ int type; /* type of esync object (above) */ ++ VARARG(name,unicode_str); /* object name */ ++@REPLY ++ obj_handle_t handle; /* handle to the event */ ++ int type; /* type of esync object (above) */ ++ unsigned int shm_idx; /* this object's index into the shm section */ ++@END ++ + /* Retrieve the esync fd for an object. */ + @REQ(get_esync_fd) + obj_handle_t handle; /* handle to the object */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0036-ntdll-Implement-NtOpenEvent.patch b/0007-proton-esync-fsync/0036-ntdll-Implement-NtOpenEvent.patch new file mode 100644 index 0000000..3d3ed01 --- /dev/null +++ b/0007-proton-esync-fsync/0036-ntdll-Implement-NtOpenEvent.patch @@ -0,0 +1,61 @@ +From 217a9bb77005954046ccd91168b818ce51f6e86d Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 16:58:19 -0500 +Subject: [PATCH 0457/2346] ntdll: Implement NtOpenEvent(). + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 8 ++++++++ + dlls/ntdll/unix/esync.h | 2 ++ + dlls/ntdll/unix/sync.c | 3 +++ + 3 files changed, 13 insertions(+) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index ee550e29b74..38a6d30c868 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -427,6 +427,14 @@ NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, + return create_esync( type, handle, access, attr, initial, 0 ); + } + ++NTSTATUS esync_open_event( HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr ) ++{ ++ TRACE("name %s.\n", debugstr_us(attr->ObjectName)); ++ ++ return open_esync( ESYNC_AUTO_EVENT, handle, access, attr ); /* doesn't matter which */ ++} ++ + NTSTATUS esync_set_event( HANDLE handle ) + { + static const uint64_t value = 1; +diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h +index 6818be9c16f..03894d61fcf 100644 +--- a/dlls/ntdll/unix/esync.h ++++ b/dlls/ntdll/unix/esync.h +@@ -30,6 +30,8 @@ extern NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev + + extern NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ); ++extern NTSTATUS esync_open_event( HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr ); + extern NTSTATUS esync_reset_event( HANDLE handle ); + extern NTSTATUS esync_set_event( HANDLE handle ); + +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 31253e2235b..fcd0413ce42 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -423,6 +423,9 @@ NTSTATUS WINAPI NtOpenEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_AT + *handle = 0; + if ((ret = validate_open_object_attributes( attr ))) return ret; + ++ if (do_esync()) ++ return esync_open_event( handle, access, attr ); ++ + SERVER_START_REQ( open_event ) + { + req->access = access; +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0037-ntdll-Implement-NtOpenMutant.patch b/0007-proton-esync-fsync/0037-ntdll-Implement-NtOpenMutant.patch new file mode 100644 index 0000000..05809cd --- /dev/null +++ b/0007-proton-esync-fsync/0037-ntdll-Implement-NtOpenMutant.patch @@ -0,0 +1,61 @@ +From b2bf453be8d56fb68c59440de0fb704186353317 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 16:59:35 -0500 +Subject: [PATCH 0458/2346] ntdll: Implement NtOpenMutant(). + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 8 ++++++++ + dlls/ntdll/unix/esync.h | 2 ++ + dlls/ntdll/unix/sync.c | 3 +++ + 3 files changed, 13 insertions(+) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 38a6d30c868..875bf9cd652 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -476,6 +476,14 @@ NTSTATUS esync_create_mutex( HANDLE *handle, ACCESS_MASK access, + return create_esync( ESYNC_MUTEX, handle, access, attr, initial ? 0 : 1, 0 ); + } + ++NTSTATUS esync_open_mutex( HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr ) ++{ ++ TRACE("name %s.\n", debugstr_us(attr->ObjectName)); ++ ++ return open_esync( ESYNC_MUTEX, handle, access, attr ); ++} ++ + NTSTATUS esync_release_mutex( HANDLE *handle, LONG *prev ) + { + struct esync *obj; +diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h +index 03894d61fcf..ac12604a815 100644 +--- a/dlls/ntdll/unix/esync.h ++++ b/dlls/ntdll/unix/esync.h +@@ -37,6 +37,8 @@ extern NTSTATUS esync_set_event( HANDLE handle ); + + extern NTSTATUS esync_create_mutex( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ); ++extern NTSTATUS esync_open_mutex( HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr ); + extern NTSTATUS esync_release_mutex( HANDLE *handle, LONG *prev ); + + extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index fcd0413ce42..33a1dc77c47 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -593,6 +593,9 @@ NTSTATUS WINAPI NtOpenMutant( HANDLE *handle, ACCESS_MASK access, const OBJECT_A + *handle = 0; + if ((ret = validate_open_object_attributes( attr ))) return ret; + ++ if (do_esync()) ++ return esync_open_mutex( handle, access, attr ); ++ + SERVER_START_REQ( open_mutex ) + { + req->access = access; +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0038-server-Implement-esync_map_access.patch b/0007-proton-esync-fsync/0038-server-Implement-esync_map_access.patch new file mode 100644 index 0000000..8959f29 --- /dev/null +++ b/0007-proton-esync-fsync/0038-server-Implement-esync_map_access.patch @@ -0,0 +1,51 @@ +From 0d096bf619ddde6fbbaafc2ddbe8e3255ecd6cef Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sun, 10 Jun 2018 19:08:18 -0500 +Subject: [PATCH 0459/2346] server: Implement esync_map_access(). + +Wine-Staging: eventfd_synchronization +--- + server/esync.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/server/esync.c b/server/esync.c +index eca9b6aa67d..3a334b3b330 100644 +--- a/server/esync.c ++++ b/server/esync.c +@@ -112,6 +112,7 @@ struct esync + }; + + static void esync_dump( struct object *obj, int verbose ); ++static unsigned int esync_map_access( struct object *obj, unsigned int access ); + static void esync_destroy( struct object *obj ); + + const struct object_ops esync_ops = +@@ -126,7 +127,7 @@ const struct object_ops esync_ops = + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +- default_map_access, /* map_access */ ++ esync_map_access, /* map_access */ + default_get_sd, /* get_sd */ + default_set_sd, /* set_sd */ + default_get_full_name, /* get_full_name */ +@@ -146,6 +147,16 @@ static void esync_dump( struct object *obj, int verbose ) + fprintf( stderr, "esync fd=%d\n", esync->fd ); + } + ++static unsigned int esync_map_access( struct object *obj, unsigned int access ) ++{ ++ /* Sync objects have the same flags. */ ++ if (access & GENERIC_READ) access |= STANDARD_RIGHTS_READ | EVENT_QUERY_STATE; ++ if (access & GENERIC_WRITE) access |= STANDARD_RIGHTS_WRITE | EVENT_MODIFY_STATE; ++ if (access & GENERIC_EXECUTE) access |= STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE; ++ if (access & GENERIC_ALL) access |= STANDARD_RIGHTS_ALL | EVENT_QUERY_STATE | EVENT_MODIFY_STATE; ++ return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL); ++} ++ + static void esync_destroy( struct object *obj ) + { + struct esync *esync = (struct esync *)obj; +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0039-server-Implement-NtDuplicateObject.patch b/0007-proton-esync-fsync/0039-server-Implement-NtDuplicateObject.patch new file mode 100644 index 0000000..87102b7 --- /dev/null +++ b/0007-proton-esync-fsync/0039-server-Implement-NtDuplicateObject.patch @@ -0,0 +1,48 @@ +From 3d360c4c106f11e82520d6f307b1b780038a02c8 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 17:03:05 -0500 +Subject: [PATCH 0460/2346] server: Implement NtDuplicateObject(). + +Wine-Staging: eventfd_synchronization +--- + server/esync.c | 10 +++++++++- + 1 file changed, 9 insertions(+), 1 deletion(-) + +diff --git a/server/esync.c b/server/esync.c +index 3a334b3b330..c5587bef6cf 100644 +--- a/server/esync.c ++++ b/server/esync.c +@@ -112,6 +112,7 @@ struct esync + }; + + static void esync_dump( struct object *obj, int verbose ); ++static int esync_get_esync_fd( struct object *obj, enum esync_type *type ); + static unsigned int esync_map_access( struct object *obj, unsigned int access ); + static void esync_destroy( struct object *obj ); + +@@ -123,7 +124,7 @@ const struct object_ops esync_ops = + no_add_queue, /* add_queue */ + NULL, /* remove_queue */ + NULL, /* signaled */ +- NULL, /* get_esync_fd */ ++ esync_get_esync_fd, /* get_esync_fd */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -147,6 +148,13 @@ static void esync_dump( struct object *obj, int verbose ) + fprintf( stderr, "esync fd=%d\n", esync->fd ); + } + ++static int esync_get_esync_fd( struct object *obj, enum esync_type *type ) ++{ ++ struct esync *esync = (struct esync *)obj; ++ *type = esync->type; ++ return esync->fd; ++} ++ + static unsigned int esync_map_access( struct object *obj, unsigned int access ) + { + /* Sync objects have the same flags. */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0040-server-Create-eventfd-descriptors-for-timers.patch b/0007-proton-esync-fsync/0040-server-Create-eventfd-descriptors-for-timers.patch new file mode 100644 index 0000000..65510ec --- /dev/null +++ b/0007-proton-esync-fsync/0040-server-Create-eventfd-descriptors-for-timers.patch @@ -0,0 +1,90 @@ +From 89d9005f294387a5ecb00a4badc9d7829a733100 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Fri, 15 Jun 2018 11:01:44 -0500 +Subject: [PATCH 0461/2346] server: Create eventfd descriptors for timers. + +Wine-Staging: eventfd_synchronization +--- + server/timer.c | 20 +++++++++++++++++++- + 1 file changed, 19 insertions(+), 1 deletion(-) + +diff --git a/server/timer.c b/server/timer.c +index f59902d5607..36645a2a8d2 100644 +--- a/server/timer.c ++++ b/server/timer.c +@@ -35,6 +35,7 @@ + #include "file.h" + #include "handle.h" + #include "request.h" ++#include "esync.h" + + static const WCHAR timer_name[] = {'T','i','m','e','r'}; + +@@ -61,10 +62,12 @@ struct timer + struct thread *thread; /* thread that set the APC function */ + client_ptr_t callback; /* callback APC function */ + client_ptr_t arg; /* callback argument */ ++ int esync_fd; /* esync file descriptor */ + }; + + static void timer_dump( struct object *obj, int verbose ); + static int timer_signaled( struct object *obj, struct wait_queue_entry *entry ); ++static int timer_get_esync_fd( struct object *obj, enum esync_type *type ); + static void timer_satisfied( struct object *obj, struct wait_queue_entry *entry ); + static void timer_destroy( struct object *obj ); + +@@ -76,7 +79,7 @@ static const struct object_ops timer_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + timer_signaled, /* signaled */ +- NULL, /* get_esync_fd */ ++ timer_get_esync_fd, /* get_esync_fd */ + timer_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -111,6 +114,10 @@ static struct timer *create_timer( struct object *root, const struct unicode_str + timer->period = 0; + timer->timeout = NULL; + timer->thread = NULL; ++ timer->esync_fd = -1; ++ ++ if (do_esync()) ++ timer->esync_fd = esync_create_fd( 0, 0 ); + } + } + return timer; +@@ -182,6 +189,9 @@ static int set_timer( struct timer *timer, timeout_t expire, unsigned int period + { + period = 0; /* period doesn't make any sense for a manual timer */ + timer->signaled = 0; ++ ++ if (do_esync()) ++ esync_clear( timer->esync_fd ); + } + timer->when = (expire <= 0) ? expire - monotonic_time : max( expire, current_time ); + timer->period = period; +@@ -209,6 +219,13 @@ static int timer_signaled( struct object *obj, struct wait_queue_entry *entry ) + return timer->signaled; + } + ++static int timer_get_esync_fd( struct object *obj, enum esync_type *type ) ++{ ++ struct timer *timer = (struct timer *)obj; ++ *type = timer->manual ? ESYNC_MANUAL_SERVER : ESYNC_AUTO_SERVER; ++ return timer->esync_fd; ++} ++ + static void timer_satisfied( struct object *obj, struct wait_queue_entry *entry ) + { + struct timer *timer = (struct timer *)obj; +@@ -223,6 +240,7 @@ static void timer_destroy( struct object *obj ) + + if (timer->timeout) remove_timeout_user( timer->timeout ); + if (timer->thread) release_object( timer->thread ); ++ if (do_esync()) close( timer->esync_fd ); + } + + /* create a timer */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0041-ntdll-server-Implement-alertable-waits.patch b/0007-proton-esync-fsync/0041-ntdll-server-Implement-alertable-waits.patch new file mode 100644 index 0000000..b22c715 --- /dev/null +++ b/0007-proton-esync-fsync/0041-ntdll-server-Implement-alertable-waits.patch @@ -0,0 +1,321 @@ +From 821c9f6c8d7ae56c0d879f6daff06f10f2ccc111 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 17:17:31 -0500 +Subject: [PATCH 0462/2346] ntdll, server: Implement alertable waits. + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 77 +++++++++++++++++++++++++++++++--- + dlls/ntdll/unix/unix_private.h | 1 + + dlls/ntdll/unix/virtual.c | 1 + + server/esync.c | 20 +++++++-- + server/esync.h | 1 + + server/protocol.def | 4 ++ + server/thread.c | 13 ++++++ + server/thread.h | 1 + + 8 files changed, 109 insertions(+), 9 deletions(-) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 875bf9cd652..db453daa229 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -597,17 +597,42 @@ static void update_grabbed_object( struct esync *obj ) + static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, + BOOLEAN alertable, const LARGE_INTEGER *timeout ) + { ++ static const LARGE_INTEGER zero; ++ + struct esync *objs[MAXIMUM_WAIT_OBJECTS]; +- struct pollfd fds[MAXIMUM_WAIT_OBJECTS]; ++ struct pollfd fds[MAXIMUM_WAIT_OBJECTS + 1]; + int has_esync = 0, has_server = 0; + BOOL msgwait = FALSE; + LONGLONG timeleft; + LARGE_INTEGER now; ++ DWORD pollcount; + ULONGLONG end; + int64_t value; + ssize_t size; + int i, j, ret; + ++ /* Grab the APC fd if we don't already have it. */ ++ if (alertable && ntdll_get_thread_data()->esync_apc_fd == -1) ++ { ++ obj_handle_t fd_handle; ++ sigset_t sigset; ++ int fd = -1; ++ ++ server_enter_uninterrupted_section( &fd_cache_mutex, &sigset ); ++ SERVER_START_REQ( get_esync_apc_fd ) ++ { ++ if (!(ret = wine_server_call( req ))) ++ { ++ fd = receive_fd( &fd_handle ); ++ assert( fd_handle == GetCurrentThreadId() ); ++ } ++ } ++ SERVER_END_REQ; ++ server_leave_uninterrupted_section( &fd_cache_mutex, &sigset ); ++ ++ ntdll_get_thread_data()->esync_apc_fd = fd; ++ } ++ + NtQuerySystemTime( &now ); + if (timeout) + { +@@ -646,6 +671,8 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA + + if (msgwait) + TRACE(" or driver events"); ++ if (alertable) ++ TRACE(", alertable"); + + if (!timeout) + TRACE(", timeout = INFINITE.\n"); +@@ -682,12 +709,27 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA + fds[i].fd = obj ? obj->fd : -1; + fds[i].events = POLLIN; + } ++ if (alertable) ++ { ++ fds[i].fd = ntdll_get_thread_data()->esync_apc_fd; ++ fds[i].events = POLLIN; ++ i++; ++ } ++ pollcount = i; + + while (1) + { +- ret = do_poll( fds, count, timeout ? &end : NULL ); ++ ret = do_poll( fds, pollcount, timeout ? &end : NULL ); + if (ret > 0) + { ++ /* We must check this first! The server may set an event that ++ * we're waiting on, but we need to return STATUS_USER_APC. */ ++ if (alertable) ++ { ++ if (fds[pollcount - 1].revents & POLLIN) ++ goto userapc; ++ } ++ + /* Find out which object triggered the wait. */ + for (i = 0; i < count; i++) + { +@@ -761,6 +803,14 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA + tryagain: + /* First step: try to poll on each object in sequence. */ + fds[0].events = POLLIN; ++ pollcount = 1; ++ if (alertable) ++ { ++ /* We also need to wait on APCs. */ ++ fds[1].fd = ntdll_get_thread_data()->esync_apc_fd; ++ fds[1].events = POLLIN; ++ pollcount++; ++ } + for (i = 0; i < count; i++) + { + struct esync *obj = objs[i]; +@@ -776,9 +826,11 @@ tryagain: + continue; + } + +- ret = do_poll( fds, 1, timeout ? &end : NULL ); ++ ret = do_poll( fds, pollcount, timeout ? &end : NULL ); + if (ret <= 0) + goto err; ++ else if (alertable && (fds[1].revents & POLLIN)) ++ goto userapc; + + if (fds[0].revents & (POLLHUP | POLLERR | POLLNVAL)) + { +@@ -794,10 +846,12 @@ tryagain: + fds[i].fd = objs[i] ? objs[i]->fd : -1; + fds[i].events = POLLIN; + } ++ /* There's no reason to check for APCs here. */ ++ pollcount = i; + + /* Poll everything to see if they're still signaled. */ +- ret = poll( fds, count, 0 ); +- if (ret == count) ++ ret = poll( fds, pollcount, 0 ); ++ if (ret == pollcount) + { + /* Quick, grab everything. */ + for (i = 0; i < count; i++) +@@ -863,6 +917,19 @@ err: + ERR("ppoll failed: %s\n", strerror(errno)); + return errno_to_status( errno ); + } ++ ++userapc: ++ TRACE("Woken up by user APC.\n"); ++ ++ /* We have to make a server call anyway to get the APC to execute, so just ++ * delegate down to server_select(). */ ++ ret = server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, &zero ); ++ ++ /* This can happen if we received a system APC, and the APC fd was woken up ++ * before we got SIGUSR1. poll() doesn't return EINTR in that case. The ++ * right thing to do seems to be to return STATUS_USER_APC anyway. */ ++ if (ret == STATUS_TIMEOUT) ret = STATUS_USER_APC; ++ return ret; + } + + /* We need to let the server know when we are doing a message wait, and when we +diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h +index 20fb3b6b7c9..48bb596df99 100644 +--- a/dlls/ntdll/unix/unix_private.h ++++ b/dlls/ntdll/unix/unix_private.h +@@ -93,6 +93,7 @@ struct ntdll_thread_data + { + void *cpu_data[16]; /* reserved for CPU-specific data */ + void *kernel_stack; /* stack for thread startup and kernel syscalls */ ++ int esync_apc_fd; /* fd to wait on for user APCs */ + int request_fd; /* fd for sending server requests */ + int reply_fd; /* fd for receiving server replies */ + int wait_fd[2]; /* fd for sleeping server requests */ +diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c +index d2d07829e34..2309f936f66 100644 +--- a/dlls/ntdll/unix/virtual.c ++++ b/dlls/ntdll/unix/virtual.c +@@ -3707,6 +3707,7 @@ static TEB *init_teb( void *ptr, BOOL is_wow ) + teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer; + teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); + thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch; ++ thread_data->esync_apc_fd = -1; + thread_data->request_fd = -1; + thread_data->reply_fd = -1; + thread_data->wait_fd[0] = -1; +diff --git a/server/esync.c b/server/esync.c +index c5587bef6cf..0c365006f0b 100644 +--- a/server/esync.c ++++ b/server/esync.c +@@ -346,19 +346,25 @@ int esync_create_fd( int initval, int flags ) + #endif + } + ++/* Wake up a specific fd. */ ++void esync_wake_fd( int fd ) ++{ ++ static const uint64_t value = 1; ++ ++ if (write( fd, &value, sizeof(value) ) == -1) ++ perror( "esync: write" ); ++} ++ + /* Wake up a server-side esync object. */ + void esync_wake_up( struct object *obj ) + { +- static const uint64_t value = 1; + enum esync_type dummy; + int fd; + + if (obj->ops->get_esync_fd) + { + fd = obj->ops->get_esync_fd( obj, &dummy ); +- +- if (write( fd, &value, sizeof(value) ) == -1) +- perror( "esync: write" ); ++ esync_wake_fd( fd ); + } + } + +@@ -496,3 +502,9 @@ DECL_HANDLER(get_esync_fd) + + release_object( obj ); + } ++ ++/* Return the fd used for waiting on user APCs. */ ++DECL_HANDLER(get_esync_apc_fd) ++{ ++ send_client_fd( current->process, current->esync_apc_fd, current->id ); ++} +diff --git a/server/esync.h b/server/esync.h +index 689d8569b73..e1588d205d9 100644 +--- a/server/esync.h ++++ b/server/esync.h +@@ -23,6 +23,7 @@ + extern int do_esync(void); + void esync_init(void); + int esync_create_fd( int initval, int flags ); ++void esync_wake_fd( int fd ); + void esync_wake_up( struct object *obj ); + void esync_clear( int fd ); + +diff --git a/server/protocol.def b/server/protocol.def +index 0786eca012b..d5026dce3d9 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3987,3 +3987,7 @@ enum esync_type + @REQ(esync_msgwait) + int in_msgwait; /* are we in a message wait? */ + @END ++ ++/* Retrieve the fd to wait on for user APCs. */ ++@REQ(get_esync_apc_fd) ++@END +diff --git a/server/thread.c b/server/thread.c +index 69b919d400e..9592ae6c8bf 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -264,6 +264,7 @@ static inline void init_thread_structure( struct thread *thread ) + thread->teb = 0; + thread->entry_point = 0; + thread->esync_fd = -1; ++ thread->esync_apc_fd = -1; + thread->system_regs = 0; + thread->queue = NULL; + thread->wait = NULL; +@@ -477,7 +478,10 @@ struct thread *create_thread( int fd, struct process *process, const struct secu + } + + if (do_esync()) ++ { + thread->esync_fd = esync_create_fd( 0, 0 ); ++ thread->esync_apc_fd = esync_create_fd( 0, 0 ); ++ } + + set_fd_events( thread->request_fd, POLLIN ); /* start listening to events */ + add_process_thread( thread->process, thread ); +@@ -1321,8 +1325,13 @@ static int queue_apc( struct process *process, struct thread *thread, struct thr + grab_object( apc ); + list_add_tail( queue, &apc->entry ); + if (!list_prev( queue, &apc->entry )) /* first one */ ++ { + wake_thread( thread ); + ++ if (do_esync() && queue == &thread->user_apc) ++ esync_wake_fd( thread->esync_apc_fd ); ++ } ++ + return 1; + } + +@@ -1368,6 +1377,10 @@ static struct thread_apc *thread_dequeue_apc( struct thread *thread, int system + apc = LIST_ENTRY( ptr, struct thread_apc, entry ); + list_remove( ptr ); + } ++ ++ if (do_esync() && list_empty( &thread->system_apc ) && list_empty( &thread->user_apc )) ++ esync_clear( thread->esync_apc_fd ); ++ + return apc; + } + +diff --git a/server/thread.h b/server/thread.h +index 8086a98156e..a01d492361d 100644 +--- a/server/thread.h ++++ b/server/thread.h +@@ -55,6 +55,7 @@ struct thread + thread_id_t id; /* thread id */ + struct list mutex_list; /* list of currently owned mutexes */ + int esync_fd; /* esync file descriptor (signalled on exit) */ ++ int esync_apc_fd; /* esync apc fd (signalled when APCs are present) */ + unsigned int system_regs; /* which system regs have been set */ + struct msg_queue *queue; /* message queue */ + struct thread_wait *wait; /* current wait condition if sleeping */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0042-esync-Update-README.patch b/0007-proton-esync-fsync/0042-esync-Update-README.patch new file mode 100644 index 0000000..fa29c9f --- /dev/null +++ b/0007-proton-esync-fsync/0042-esync-Update-README.patch @@ -0,0 +1,86 @@ +From 669f8f0620dfa0b6cc02abeaf9f58fc4c5ef01a6 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sun, 10 Jun 2018 13:53:08 -0500 +Subject: [PATCH 0463/2346] esync: Update README. + +Wine-Staging: eventfd_synchronization +--- + README.esync | 48 +++++++++++++++++------------------------------- + 1 file changed, 17 insertions(+), 31 deletions(-) + +diff --git a/README.esync b/README.esync +index 8fcb969011b..627cc3f481e 100644 +--- a/README.esync ++++ b/README.esync +@@ -88,32 +88,23 @@ also kind of ugly basically because we have to wait on both X11's fd and the + messages. The upshot about the whole thing was that races are basically + impossible, since a thread can only wait on its own queue. + +-I had kind of figured that APCs just wouldn't work, but then poll() spat EINTR +-at me and I realized that this wasn't necessarily true. It seems that the +-server will suspend a thread when trying to deliver a system APC to a thread +-that's not waiting, and since the server has no idea that we're waiting it +-just suspends us. This of course interrupts poll(), which complains at us, and +-it turns out that just returning STATUS_USER_APC in that case is enough to +-make rpcrt4 happy. ++System APCs already work, since the server will forcibly suspend a thread if ++it's not already waiting, and so we just need to check for EINTR from ++poll(). User APCs and alertable waits are implemented in a similar style to ++message queues (well, sort of): whenever someone executes an alertable wait, ++we add an additional eventfd to the list, which the server signals when an APC ++arrives. If that eventfd gets signaled, we hand it off to the server to take ++care of, and return STATUS_USER_APC. ++ ++Originally I kept the volatile state of semaphores and mutexes inside a ++variable local to the handle, with the knowledge that this would break if ++someone tried to open the handle elsewhere or duplicate it. It did, and so now ++this state is stored inside shared memory. This is of the POSIX variety, is ++allocated by the server (but never mapped there) and lives under the path ++"/wine-esync". + + There are a couple things that this infrastructure can't handle, although + surprisingly there aren't that many. In particular: +-* We can't return the previous count on a semaphore, since we have no way to +- query the count on a semaphore through eventfd. Currently the code lies and +- returns 1 every time. We can make this work (in a single process, or [if +- necessary] in multiple processes through shared memory) by keeping a count +- locally. We can't guarantee that it's the exact count at the moment the +- semaphore was released, but I guess any program that runs into that race +- shouldn't be depending on that fact anyway. +-* Similarly, we can't enforce the maximum count on a semaphore, since we have +- no way to get the current count and subsequently compare it with the +- maximum. +-* We can't use NtQueryMutant to get the mutant's owner or count if it lives in +- a different process. If necessary we can use shared memory to make this +- work, I guess, but see below. +-* User APCs don't work. However, it's not impossible to make them work; in +- particular I think this could be relatively easily implemented by waiting on +- another internal file descriptor when we execute an alertable wait. + * Implementing wait-all, i.e. WaitForMultipleObjects(..., TRUE, ...), is not + exactly possible the way we'd like it to be possible. In theory that + function should wait until it knows all objects are available, then grab +@@ -144,18 +135,13 @@ surprisingly there aren't that many. In particular: + + There are some things that are perfectly implementable but that I just haven't + done yet: +-* NtOpen* (aka Open*). This is just a matter of adding another open_esync +- request analogous to those for other server primitives. +-* NtQuery*. This can be done to some degree (the difficulties are outlined +- above). That said, these APIs aren't exposed through kernel32 in any way, so ++* NtQuery*. That said, these APIs aren't exposed through kernel32 in any way, so + I doubt anyone is going to be using them. +-* SignalObjectAndWait(). The server combines this into a single operation, but +- according to MSDN it doesn't need to be atomic, so we can just signal the +- appropriate object and wait, and woe betide anyone who gets in the way of +- those two operations. + * Other synchronizable server primitives. It's unlikely we'll need any of + these, except perhaps named pipes (which would honestly be rather difficult) + and (maybe) timers. ++* Access masks. We'd need to store these inside ntdll, and validate them when ++ someone tries to execute esync operations. + + This patchset was inspired by Daniel Santos' "hybrid synchronization" + patchset. My idea was to create a framework whereby even contended waits could +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0043-kernel32-tests-Mark-some-existing-tests-as-failing-u.patch b/0007-proton-esync-fsync/0043-kernel32-tests-Mark-some-existing-tests-as-failing-u.patch new file mode 100644 index 0000000..a3469ae --- /dev/null +++ b/0007-proton-esync-fsync/0043-kernel32-tests-Mark-some-existing-tests-as-failing-u.patch @@ -0,0 +1,36 @@ +From 108d555ad71a121603a44316382c545136edf5b8 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Wed, 13 Jun 2018 22:25:40 -0500 +Subject: [PATCH 0464/2346] kernel32/tests: Mark some existing tests as failing + under esync. + +Wine-Staging: eventfd_synchronization +--- + dlls/kernel32/tests/sync.c | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/dlls/kernel32/tests/sync.c b/dlls/kernel32/tests/sync.c +index 56a9d6e4859..f1ea2d671be 100644 +--- a/dlls/kernel32/tests/sync.c ++++ b/dlls/kernel32/tests/sync.c +@@ -268,7 +268,8 @@ static void test_mutex(void) + SetLastError(0xdeadbeef); + hOpened = OpenMutexA(GENERIC_READ | GENERIC_WRITE, FALSE, "WineTestMutex"); + ok(hOpened != NULL, "OpenMutex failed with error %ld\n", GetLastError()); +- wait_ret = WaitForSingleObject(hOpened, INFINITE); ++ wait_ret = WaitForSingleObject(hOpened, 0); ++todo_wine_if(getenv("WINEESYNC")) /* XFAIL: validation is not implemented */ + ok(wait_ret == WAIT_FAILED, "WaitForSingleObject succeeded\n"); + CloseHandle(hOpened); + +@@ -299,6 +300,7 @@ static void test_mutex(void) + + SetLastError(0xdeadbeef); + ret = ReleaseMutex(hCreated); ++todo_wine_if(getenv("WINEESYNC")) /* XFAIL: due to the above */ + ok(!ret && (GetLastError() == ERROR_NOT_OWNER), + "ReleaseMutex should have failed with ERROR_NOT_OWNER instead of %ld\n", GetLastError()); + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0044-ntdll-Implement-NtQuerySemaphore.patch b/0007-proton-esync-fsync/0044-ntdll-Implement-NtQuerySemaphore.patch new file mode 100644 index 0000000..cba7a09 --- /dev/null +++ b/0007-proton-esync-fsync/0044-ntdll-Implement-NtQuerySemaphore.patch @@ -0,0 +1,71 @@ +From 5009d4b08a1018e563f3a7138e8acc3b35c006ee Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 17:24:17 -0500 +Subject: [PATCH 0470/2346] ntdll: Implement NtQuerySemaphore(). + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 19 +++++++++++++++++++ + dlls/ntdll/unix/esync.h | 1 + + dlls/ntdll/unix/sync.c | 3 +++ + 3 files changed, 23 insertions(+) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index db453daa229..d0ddd0c265e 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -415,6 +415,25 @@ NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) + return STATUS_SUCCESS; + } + ++NTSTATUS esync_query_semaphore( HANDLE handle, void *info, ULONG *ret_len ) ++{ ++ struct esync *obj; ++ struct semaphore *semaphore; ++ SEMAPHORE_BASIC_INFORMATION *out = info; ++ NTSTATUS ret; ++ ++ TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len); ++ ++ if ((ret = get_object( handle, &obj ))) return ret; ++ semaphore = obj->shm; ++ ++ out->CurrentCount = semaphore->count; ++ out->MaximumCount = semaphore->max; ++ if (ret_len) *ret_len = sizeof(*out); ++ ++ return STATUS_SUCCESS; ++} ++ + NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, EVENT_TYPE event_type, BOOLEAN initial ) + { +diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h +index ac12604a815..e7d4cd2aba4 100644 +--- a/dlls/ntdll/unix/esync.h ++++ b/dlls/ntdll/unix/esync.h +@@ -26,6 +26,7 @@ extern NTSTATUS esync_create_semaphore(HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max); + extern NTSTATUS esync_open_semaphore( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr ); ++extern NTSTATUS esync_query_semaphore( HANDLE handle, void *info, ULONG *ret_len ); + extern NTSTATUS esync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ); + + extern NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 33a1dc77c47..c9450003ce3 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -340,6 +340,9 @@ NTSTATUS WINAPI NtQuerySemaphore( HANDLE handle, SEMAPHORE_INFORMATION_CLASS cla + + if (len != sizeof(SEMAPHORE_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH; + ++ if (do_esync()) ++ return esync_query_semaphore( handle, info, ret_len ); ++ + SERVER_START_REQ( query_semaphore ) + { + req->handle = wine_server_obj_handle( handle ); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0045-ntdll-Implement-NtQueryEvent.patch b/0007-proton-esync-fsync/0045-ntdll-Implement-NtQueryEvent.patch new file mode 100644 index 0000000..d5f38e4 --- /dev/null +++ b/0007-proton-esync-fsync/0045-ntdll-Implement-NtQueryEvent.patch @@ -0,0 +1,72 @@ +From f1725526e31e3aa76bccf2094b10c34836d4dcea Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 17:26:56 -0500 +Subject: [PATCH 0471/2346] ntdll: Implement NtQueryEvent(). + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 20 ++++++++++++++++++++ + dlls/ntdll/unix/esync.h | 1 + + dlls/ntdll/unix/sync.c | 3 +++ + 3 files changed, 24 insertions(+) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index d0ddd0c265e..e5d6ca145a5 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -486,6 +486,26 @@ NTSTATUS esync_reset_event( HANDLE handle ) + return STATUS_SUCCESS; + } + ++NTSTATUS esync_query_event( HANDLE handle, void *info, ULONG *ret_len ) ++{ ++ struct esync *obj; ++ EVENT_BASIC_INFORMATION *out = info; ++ struct pollfd fd; ++ NTSTATUS ret; ++ ++ TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len); ++ ++ if ((ret = get_object( handle, &obj ))) return ret; ++ ++ fd.fd = obj->fd; ++ fd.events = POLLIN; ++ out->EventState = poll( &fd, 1, 0 ); ++ out->EventType = (obj->type == ESYNC_AUTO_EVENT ? SynchronizationEvent : NotificationEvent); ++ if (ret_len) *ret_len = sizeof(*out); ++ ++ return STATUS_SUCCESS; ++} ++ + NTSTATUS esync_create_mutex( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ) + { +diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h +index e7d4cd2aba4..9a0fcd163dd 100644 +--- a/dlls/ntdll/unix/esync.h ++++ b/dlls/ntdll/unix/esync.h +@@ -33,6 +33,7 @@ extern NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ); + extern NTSTATUS esync_open_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr ); ++extern NTSTATUS esync_query_event( HANDLE handle, void *info, ULONG *ret_len ); + extern NTSTATUS esync_reset_event( HANDLE handle ); + extern NTSTATUS esync_set_event( HANDLE handle ); + +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index c9450003ce3..2fea9f532bd 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -539,6 +539,9 @@ NTSTATUS WINAPI NtQueryEvent( HANDLE handle, EVENT_INFORMATION_CLASS class, + + if (len != sizeof(EVENT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH; + ++ if (do_esync()) ++ return esync_query_event( handle, info, ret_len ); ++ + SERVER_START_REQ( query_event ) + { + req->handle = wine_server_obj_handle( handle ); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0046-ntdll-Implement-NtQueryMutant.patch b/0007-proton-esync-fsync/0046-ntdll-Implement-NtQueryMutant.patch new file mode 100644 index 0000000..203cde2 --- /dev/null +++ b/0007-proton-esync-fsync/0046-ntdll-Implement-NtQueryMutant.patch @@ -0,0 +1,72 @@ +From 241f39c02ac5a89f36f2ee1c452c481c56f6f639 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 17:28:58 -0500 +Subject: [PATCH 0472/2346] ntdll: Implement NtQueryMutant(). + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 20 ++++++++++++++++++++ + dlls/ntdll/unix/esync.h | 1 + + dlls/ntdll/unix/sync.c | 3 +++ + 3 files changed, 24 insertions(+) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index e5d6ca145a5..7ee00ab3489 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -557,6 +557,26 @@ NTSTATUS esync_release_mutex( HANDLE *handle, LONG *prev ) + return STATUS_SUCCESS; + } + ++NTSTATUS esync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) ++{ ++ struct esync *obj; ++ struct mutex *mutex; ++ MUTANT_BASIC_INFORMATION *out = info; ++ NTSTATUS ret; ++ ++ TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len); ++ ++ if ((ret = get_object( handle, &obj ))) return ret; ++ mutex = obj->shm; ++ ++ out->CurrentCount = 1 - mutex->count; ++ out->OwnedByCaller = (mutex->tid == GetCurrentThreadId()); ++ out->AbandonedState = FALSE; ++ if (ret_len) *ret_len = sizeof(*out); ++ ++ return STATUS_SUCCESS; ++} ++ + #define TICKSPERSEC 10000000 + #define TICKSPERMSEC 10000 + +diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h +index 9a0fcd163dd..61846238ab7 100644 +--- a/dlls/ntdll/unix/esync.h ++++ b/dlls/ntdll/unix/esync.h +@@ -41,6 +41,7 @@ extern NTSTATUS esync_create_mutex( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ); + extern NTSTATUS esync_open_mutex( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr ); ++extern NTSTATUS esync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ); + extern NTSTATUS esync_release_mutex( HANDLE *handle, LONG *prev ); + + extern NTSTATUS esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 2fea9f532bd..5d25f086d5d 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -657,6 +657,9 @@ NTSTATUS WINAPI NtQueryMutant( HANDLE handle, MUTANT_INFORMATION_CLASS class, + + if (len != sizeof(MUTANT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH; + ++ if (do_esync()) ++ return esync_query_mutex( handle, info, ret_len ); ++ + SERVER_START_REQ( query_mutex ) + { + req->handle = wine_server_obj_handle( handle ); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0047-server-Create-eventfd-descriptors-for-pseudo-fd-obje.patch b/0007-proton-esync-fsync/0047-server-Create-eventfd-descriptors-for-pseudo-fd-obje.patch new file mode 100644 index 0000000..dec972d --- /dev/null +++ b/0007-proton-esync-fsync/0047-server-Create-eventfd-descriptors-for-pseudo-fd-obje.patch @@ -0,0 +1,130 @@ +From 30a2b74e116fd703dbdea5d9423e40dfaff0c349 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 7 Jul 2018 12:57:47 +0200 +Subject: [PATCH 0473/2346] server: Create eventfd descriptors for pseudo-fd + objects and use them for named pipes. + +Wine-Staging: eventfd_synchronization +--- + server/fd.c | 22 ++++++++++++++++++++++ + server/file.h | 1 + + server/named_pipe.c | 4 ++-- + 3 files changed, 25 insertions(+), 2 deletions(-) + +diff --git a/server/fd.c b/server/fd.c +index f9f747016b3..75af39b134e 100644 +--- a/server/fd.c ++++ b/server/fd.c +@@ -96,6 +96,7 @@ + #include "handle.h" + #include "process.h" + #include "request.h" ++#include "esync.h" + + #include "winternl.h" + #include "winioctl.h" +@@ -156,6 +157,7 @@ struct fd + struct completion *completion; /* completion object attached to this fd */ + apc_param_t comp_key; /* completion key to set in completion events */ + unsigned int comp_flags; /* completion flags */ ++ int esync_fd; /* esync file descriptor */ + }; + + static void fd_dump( struct object *obj, int verbose ); +@@ -1569,6 +1571,9 @@ static void fd_destroy( struct object *obj ) + if (fd->unix_fd != -1) close( fd->unix_fd ); + free( fd->unix_name ); + } ++ ++ if (do_esync()) ++ close( fd->esync_fd ); + } + + /* check if the desired access is possible without violating */ +@@ -1687,6 +1692,7 @@ static struct fd *alloc_fd_object(void) + fd->poll_index = -1; + fd->completion = NULL; + fd->comp_flags = 0; ++ fd->esync_fd = -1; + init_async_queue( &fd->read_q ); + init_async_queue( &fd->write_q ); + init_async_queue( &fd->wait_q ); +@@ -1728,11 +1734,15 @@ struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *use + fd->completion = NULL; + fd->comp_flags = 0; + fd->no_fd_status = STATUS_BAD_DEVICE_TYPE; ++ fd->esync_fd = -1; + init_async_queue( &fd->read_q ); + init_async_queue( &fd->write_q ); + init_async_queue( &fd->wait_q ); + list_init( &fd->inode_entry ); + list_init( &fd->locks ); ++ ++ if (do_esync()) ++ fd->esync_fd = esync_create_fd( 0, 0 ); + return fd; + } + +@@ -2144,6 +2154,9 @@ void set_fd_signaled( struct fd *fd, int signaled ) + if (fd->comp_flags & FILE_SKIP_SET_EVENT_ON_HANDLE) return; + fd->signaled = signaled; + if (signaled) wake_up( fd->user, 0 ); ++ ++ if (do_esync() && !signaled) ++ esync_clear( fd->esync_fd ); + } + + /* check if events are pending and if yes return which one(s) */ +@@ -2169,6 +2182,15 @@ int default_fd_signaled( struct object *obj, struct wait_queue_entry *entry ) + return ret; + } + ++int default_fd_get_esync_fd( struct object *obj, enum esync_type *type ) ++{ ++ struct fd *fd = get_obj_fd( obj ); ++ int ret = fd->esync_fd; ++ *type = ESYNC_MANUAL_SERVER; ++ release_object( fd ); ++ return ret; ++} ++ + int default_fd_get_poll_events( struct fd *fd ) + { + int events = 0; +diff --git a/server/file.h b/server/file.h +index b8edec64af4..fadb3436add 100644 +--- a/server/file.h ++++ b/server/file.h +@@ -108,6 +108,7 @@ extern char *dup_fd_name( struct fd *root, const char *name ) __WINE_DEALLOC(fre + extern void get_nt_name( struct fd *fd, struct unicode_str *name ); + + extern int default_fd_signaled( struct object *obj, struct wait_queue_entry *entry ); ++extern int default_fd_get_esync_fd( struct object *obj, enum esync_type *type ); + extern int default_fd_get_poll_events( struct fd *fd ); + extern void default_poll_event( struct fd *fd, int event ); + extern void fd_cancel_async( struct fd *fd, struct async *async ); +diff --git a/server/named_pipe.c b/server/named_pipe.c +index f28cb14cb45..a90ec606226 100644 +--- a/server/named_pipe.c ++++ b/server/named_pipe.c +@@ -168,7 +168,7 @@ static const struct object_ops pipe_server_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ +- NULL, /* get_esync_fd */ ++ default_fd_get_esync_fd, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + pipe_end_get_fd, /* get_fd */ +@@ -213,7 +213,7 @@ static const struct object_ops pipe_client_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ +- NULL, /* get_esync_fd */ ++ default_fd_get_esync_fd, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + pipe_end_get_fd, /* get_fd */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0048-esync-Update-README.patch b/0007-proton-esync-fsync/0048-esync-Update-README.patch new file mode 100644 index 0000000..4d4d820 --- /dev/null +++ b/0007-proton-esync-fsync/0048-esync-Update-README.patch @@ -0,0 +1,56 @@ +From ba4b209b18de66f13e7719109ec5cf56eda46fec Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Wed, 4 Jul 2018 14:58:33 +0200 +Subject: [PATCH 0474/2346] esync: Update README. + +Wine-Staging: eventfd_synchronization +--- + README.esync | 25 +++++++++++++++++++++++-- + 1 file changed, 23 insertions(+), 2 deletions(-) + +diff --git a/README.esync b/README.esync +index 627cc3f481e..30e241755ad 100644 +--- a/README.esync ++++ b/README.esync +@@ -2,6 +2,29 @@ This is eventfd-based synchronization, or 'esync' for short. Turn it on with + WINEESYNC=1 (note that it checks the presence and not the value); debug it + with +esync. + ++== BUGS AND LIMITATIONS == ++ ++Please let me know if you find any bugs. If you can, also attach a log with +++seh,+pid,+esync,+server. ++ ++If you get something like "eventfd: Too many open files" and then things start ++crashing, you've probably run out of file descriptors. esync creates one ++eventfd descriptor for each synchronization object, and some games may use a ++large number of these. Linux by default limits a process to 4096 file ++descriptors, which probably was reasonable back in the nineties but isn't ++really anymore. (Fortunately Debian and derivatives [Ubuntu, Mint] already ++have a reasonable limit.) To raise the limit you'll want to edit ++/etc/security/limits.conf and add a line like ++ ++* hard nofile 1048576 ++ ++then restart your session. ++ ++Also note that if the wineserver has esync active, all clients also must, and ++vice versa. Otherwise things will probably crash quite badly. ++ ++== EXPLANATION == ++ + The aim is to execute all synchronization operations in "user-space", that is, + without going through wineserver. We do this using Linux's eventfd + facility. The main impetus to using eventfd is so that we can poll multiple +@@ -135,8 +158,6 @@ surprisingly there aren't that many. In particular: + + There are some things that are perfectly implementable but that I just haven't + done yet: +-* NtQuery*. That said, these APIs aren't exposed through kernel32 in any way, so +- I doubt anyone is going to be using them. + * Other synchronizable server primitives. It's unlikely we'll need any of + these, except perhaps named pipes (which would honestly be rather difficult) + and (maybe) timers. +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0049-esync-Add-note-about-file-limits-not-being-raised-wh.patch b/0007-proton-esync-fsync/0049-esync-Add-note-about-file-limits-not-being-raised-wh.patch new file mode 100644 index 0000000..b989e4e --- /dev/null +++ b/0007-proton-esync-fsync/0049-esync-Add-note-about-file-limits-not-being-raised-wh.patch @@ -0,0 +1,42 @@ +From 036b4bd7e6f57acca2c3dcb879e9d8af8f874ae7 Mon Sep 17 00:00:00 2001 +From: Mathieu Comandon +Date: Sat, 21 Jul 2018 12:56:50 -0700 +Subject: [PATCH 0475/2346] esync: Add note about file limits not being raised + when using systemd. + +Wine-Staging: eventfd_synchronization +--- + README.esync | 12 +++++++++++- + 1 file changed, 11 insertions(+), 1 deletion(-) + +diff --git a/README.esync b/README.esync +index 30e241755ad..7706f395ebd 100644 +--- a/README.esync ++++ b/README.esync +@@ -20,6 +20,16 @@ have a reasonable limit.) To raise the limit you'll want to edit + + then restart your session. + ++On distributions using systemd, the settings in `/etc/security/limits.conf` will ++be overridden by systemd's own settings. If you run `ulimit -Hn` and it returns ++a lower number than the one you've previously set then you can set ++ ++DefaultLimitNOFILE=100000 ++ ++in both `/etc/systemd/system.conf` and `/etc/systemd/user.conf`. You can then ++execute `sudo systemctl daemon-reexec` and restart your session. Check again ++with `ulimit -Hn` that the limit is correct. ++ + Also note that if the wineserver has esync active, all clients also must, and + vice versa. Otherwise things will probably crash quite badly. + +@@ -188,4 +198,4 @@ done by the kernel. + + Anyway, yeah, this is esync. Use it if you like. + +---Zebediah Figura +\ No newline at end of file ++--Zebediah Figura +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0050-ntdll-Try-to-avoid-poll-for-uncontended-objects.patch b/0007-proton-esync-fsync/0050-ntdll-Try-to-avoid-poll-for-uncontended-objects.patch new file mode 100644 index 0000000..70539d9 --- /dev/null +++ b/0007-proton-esync-fsync/0050-ntdll-Try-to-avoid-poll-for-uncontended-objects.patch @@ -0,0 +1,95 @@ +From 5dad82cbddd503a32ec243ff44c33b790a71787e Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 17:37:29 -0500 +Subject: [PATCH 0476/2346] ntdll: Try to avoid poll() for uncontended objects. + +Just semaphores and mutexes thus far. + +We don't have to worry about races because this is just a hint: we still call read() eventually. + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 60 ++++++++++++++++++++++++++++++++++------- + 1 file changed, 50 insertions(+), 10 deletions(-) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 7ee00ab3489..84a4dc18a14 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -745,23 +745,63 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA + + if (wait_any || count == 1) + { ++ /* Try to check objects now, so we can obviate poll() at least. */ + for (i = 0; i < count; i++) + { + struct esync *obj = objs[i]; + +- if (obj && obj->type == ESYNC_MUTEX) ++ if (obj) + { +- /* If we already own the mutex, return immediately. */ +- /* Note: This violates the assumption that the *first* object +- * to be signaled will be returned. If that becomes a problem, +- * we can always check the state of each object before waiting. */ +- struct mutex *mutex = (struct mutex *)obj; ++ switch (obj->type) ++ { ++ case ESYNC_MUTEX: ++ { ++ struct mutex *mutex = obj->shm; + +- if (mutex->tid == GetCurrentThreadId()) ++ if (mutex->tid == GetCurrentThreadId()) ++ { ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ mutex->count++; ++ return i; ++ } ++ else if (!mutex->count) ++ { ++ if ((size = read( obj->fd, &value, sizeof(value) )) == sizeof(value)) ++ { ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ mutex->tid = GetCurrentThreadId(); ++ mutex->count++; ++ return i; ++ } ++ } ++ break; ++ } ++ case ESYNC_SEMAPHORE: + { +- TRACE("Woken up by handle %p [%d].\n", handles[i], i); +- mutex->count++; +- return i; ++ struct semaphore *semaphore = obj->shm; ++ ++ if (semaphore->count) ++ { ++ if ((size = read( obj->fd, &value, sizeof(value) )) == sizeof(value)) ++ { ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ InterlockedDecrement( (LONG *)&semaphore->count ); ++ return i; ++ } ++ } ++ break; ++ } ++ case ESYNC_AUTO_EVENT: ++ case ESYNC_MANUAL_EVENT: ++ /* TODO */ ++ break; ++ case ESYNC_AUTO_SERVER: ++ case ESYNC_MANUAL_SERVER: ++ case ESYNC_QUEUE: ++ /* We can't wait on any of these. Fortunately I don't think ++ * they'll ever be uncontended anyway (at least, they won't be ++ * performance-critical). */ ++ break; + } + } + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0051-ntdll-server-Try-to-avoid-poll-for-signaled-events.patch b/0007-proton-esync-fsync/0051-ntdll-server-Try-to-avoid-poll-for-signaled-events.patch new file mode 100644 index 0000000..786cded --- /dev/null +++ b/0007-proton-esync-fsync/0051-ntdll-server-Try-to-avoid-poll-for-signaled-events.patch @@ -0,0 +1,289 @@ +From fb516e619e24bf38290a733a4aa02989b4cb5949 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 17:44:26 -0500 +Subject: [PATCH 0477/2346] ntdll, server: Try to avoid poll() for signaled + events. + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 147 ++++++++++++++++++++++++++++++++++++++-- + server/esync.c | 61 +++++++++++++++-- + 2 files changed, 197 insertions(+), 11 deletions(-) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 84a4dc18a14..880cf5006ae 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -454,18 +454,103 @@ NTSTATUS esync_open_event( HANDLE *handle, ACCESS_MASK access, + return open_esync( ESYNC_AUTO_EVENT, handle, access, attr ); /* doesn't matter which */ + } + ++static inline void small_pause(void) ++{ ++#ifdef __i386__ ++ __asm__ __volatile__( "rep;nop" : : : "memory" ); ++#else ++ __asm__ __volatile__( "" : : : "memory" ); ++#endif ++} ++ ++/* Manual-reset events are actually racier than other objects in terms of shm ++ * state. With other objects, races don't matter, because we only treat the shm ++ * state as a hint that lets us skip poll()—we still have to read(). But with ++ * manual-reset events we don't, which means that the shm state can be out of ++ * sync with the actual state. ++ * ++ * In general we shouldn't have to worry about races between modifying the ++ * event and waiting on it. If the state changes while we're waiting, it's ++ * equally plausible that we caught it before or after the state changed. ++ * However, we can have races between SetEvent() and ResetEvent(), so that the ++ * event has inconsistent internal state. ++ * ++ * To solve this we have to use the other field to lock the event. Currently ++ * this is implemented as a spinlock, but I'm not sure if a futex might be ++ * better. I'm also not sure if it's possible to obviate locking by arranging ++ * writes and reads in a certain way. ++ * ++ * Note that we don't have to worry about locking in esync_wait_objects(). ++ * There's only two general patterns: ++ * ++ * WaitFor() SetEvent() ++ * ------------------------- ++ * read() ++ * signaled = 0 ++ * signaled = 1 ++ * write() ++ * ------------------------- ++ * read() ++ * signaled = 1 ++ * signaled = 0 ++ * ++ * ------------------------- ++ * ++ * That is, if SetEvent() tries to signal the event before WaitFor() resets its ++ * signaled state, it won't bother trying to write(), and then the signaled ++ * state will be reset, so the result is a consistent non-signaled event. ++ * There's several variations to this pattern but all of them are protected in ++ * the same way. Note however this is why we have to use interlocked_xchg() ++ * event inside of the lock. ++ */ ++ ++/* Removing this spinlock is harder than it looks. esync_wait_objects() can ++ * deal with inconsistent state well enough, and a race between SetEvent() and ++ * ResetEvent() gives us license to yield either result as long as we act ++ * consistently, but that's not enough. Notably, esync_wait_objects() should ++ * probably act like a fence, so that the second half of esync_set_event() does ++ * not seep past a subsequent reset. That's one problem, but no guarantee there ++ * aren't others. */ ++ + NTSTATUS esync_set_event( HANDLE handle ) + { + static const uint64_t value = 1; + struct esync *obj; ++ struct event *event; + NTSTATUS ret; + + TRACE("%p.\n", handle); + +- if ((ret = get_object( handle, &obj))) return ret; ++ if ((ret = get_object( handle, &obj ))) return ret; ++ event = obj->shm; ++ ++ if (obj->type == ESYNC_MANUAL_EVENT) ++ { ++ /* Acquire the spinlock. */ ++ while (InterlockedCompareExchange( (LONG *)&event->locked, 1, 0 )) ++ small_pause(); ++ } ++ ++ /* For manual-reset events, as long as we're in a lock, we can take the ++ * optimization of only calling write() if the event wasn't already ++ * signaled. ++ * ++ * For auto-reset events, esync_wait_objects() must grab the kernel object. ++ * Thus if we got into a race so that the shm state is signaled but the ++ * eventfd is unsignaled (i.e. reset shm, set shm, set fd, reset fd), we ++ * *must* signal the fd now, or any waiting threads will never wake up. */ ++ ++ if (!InterlockedExchange( (LONG *)&event->signaled, 1 ) || obj->type == ESYNC_AUTO_EVENT) ++ { ++ if (write( obj->fd, &value, sizeof(value) ) == -1) ++ ERR("write: %s\n", strerror(errno)); ++ } + +- if (write( obj->fd, &value, sizeof(value) ) == -1) +- ERR("write: %s\n", strerror(errno)); ++ if (obj->type == ESYNC_MANUAL_EVENT) ++ { ++ /* Release the spinlock. */ ++ event->locked = 0; ++ } + + return STATUS_SUCCESS; + } +@@ -474,14 +559,40 @@ NTSTATUS esync_reset_event( HANDLE handle ) + { + uint64_t value; + struct esync *obj; ++ struct event *event; + NTSTATUS ret; + + TRACE("%p.\n", handle); + +- if ((ret = get_object( handle, &obj))) return ret; ++ if ((ret = get_object( handle, &obj ))) return ret; ++ event = obj->shm; + +- if (read( obj->fd, &value, sizeof(value) ) == -1 && errno != EWOULDBLOCK && errno != EAGAIN) +- ERR("read: %s\n", strerror(errno)); ++ if (obj->type == ESYNC_MANUAL_EVENT) ++ { ++ /* Acquire the spinlock. */ ++ while (InterlockedCompareExchange( (LONG *)&event->locked, 1, 0 )) ++ small_pause(); ++ } ++ ++ /* For manual-reset events, as long as we're in a lock, we can take the ++ * optimization of only calling read() if the event was already signaled. ++ * ++ * For auto-reset events, we have no guarantee that the previous "signaled" ++ * state is actually correct. We need to leave both states unsignaled after ++ * leaving this function, so we always have to read(). */ ++ if (InterlockedExchange( (LONG *)&event->signaled, 0 ) || obj->type == ESYNC_AUTO_EVENT) ++ { ++ if (read( obj->fd, &value, sizeof(value) ) == -1 && errno != EWOULDBLOCK && errno != EAGAIN) ++ { ++ ERR("read: %s\n", strerror(errno)); ++ } ++ } ++ ++ if (obj->type == ESYNC_MANUAL_EVENT) ++ { ++ /* Release the spinlock. */ ++ event->locked = 0; ++ } + + return STATUS_SUCCESS; + } +@@ -792,9 +903,31 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA + break; + } + case ESYNC_AUTO_EVENT: ++ { ++ struct event *event = obj->shm; ++ ++ if (event->signaled) ++ { ++ if ((size = read( obj->fd, &value, sizeof(value) )) == sizeof(value)) ++ { ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ event->signaled = 0; ++ return i; ++ } ++ } ++ break; ++ } + case ESYNC_MANUAL_EVENT: +- /* TODO */ ++ { ++ struct event *event = obj->shm; ++ ++ if (event->signaled) ++ { ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ return i; ++ } + break; ++ } + case ESYNC_AUTO_SERVER: + case ESYNC_MANUAL_SERVER: + case ESYNC_QUEUE: +diff --git a/server/esync.c b/server/esync.c +index 0c365006f0b..20ea97869e9 100644 +--- a/server/esync.c ++++ b/server/esync.c +@@ -376,24 +376,77 @@ void esync_clear( int fd ) + read( fd, &value, sizeof(value) ); + } + ++static inline void small_pause(void) ++{ ++#ifdef __i386__ ++ __asm__ __volatile__( "rep;nop" : : : "memory" ); ++#else ++ __asm__ __volatile__( "" : : : "memory" ); ++#endif ++} ++ + /* Server-side event support. */ + void esync_set_event( struct esync *esync ) + { + static const uint64_t value = 1; ++ struct event *event = get_shm( esync->shm_idx ); + + assert( esync->obj.ops == &esync_ops ); +- if (write( esync->fd, &value, sizeof(value) ) == -1) +- perror( "esync: write" ); ++ assert( event != NULL ); ++ ++ if (debug_level) ++ fprintf( stderr, "esync_set_event() fd=%d\n", esync->fd ); ++ ++ if (esync->type == ESYNC_MANUAL_EVENT) ++ { ++ /* Acquire the spinlock. */ ++ while (__sync_val_compare_and_swap( &event->locked, 0, 1 )) ++ small_pause(); ++ } ++ ++ if (!__atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST )) ++ { ++ if (write( esync->fd, &value, sizeof(value) ) == -1) ++ perror( "esync: write" ); ++ } ++ ++ if (esync->type == ESYNC_MANUAL_EVENT) ++ { ++ /* Release the spinlock. */ ++ event->locked = 0; ++ } + } + + void esync_reset_event( struct esync *esync ) + { + static uint64_t value = 1; ++ struct event *event = get_shm( esync->shm_idx ); + + assert( esync->obj.ops == &esync_ops ); ++ assert( event != NULL ); + +- /* we don't care about the return value */ +- read( esync->fd, &value, sizeof(value) ); ++ if (debug_level) ++ fprintf( stderr, "esync_reset_event() fd=%d\n", esync->fd ); ++ ++ if (esync->type == ESYNC_MANUAL_EVENT) ++ { ++ /* Acquire the spinlock. */ ++ while (__sync_val_compare_and_swap( &event->locked, 0, 1 )) ++ small_pause(); ++ } ++ ++ /* Only bother signaling the fd if we weren't already signaled. */ ++ if (__atomic_exchange_n( &event->signaled, 0, __ATOMIC_SEQ_CST )) ++ { ++ /* we don't care about the return value */ ++ read( esync->fd, &value, sizeof(value) ); ++ } ++ ++ if (esync->type == ESYNC_MANUAL_EVENT) ++ { ++ /* Release the spinlock. */ ++ event->locked = 0; ++ } + } + + DECL_HANDLER(create_esync) +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0052-esync-Update-README.patch b/0007-proton-esync-fsync/0052-esync-Update-README.patch new file mode 100644 index 0000000..90f340b --- /dev/null +++ b/0007-proton-esync-fsync/0052-esync-Update-README.patch @@ -0,0 +1,53 @@ +From 0677cd8b3178c76cc8f0331f1721bfcf38f2036e Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 4 Aug 2018 15:18:24 -0500 +Subject: [PATCH 0478/2346] esync: Update README. + +Wine-Staging: eventfd_synchronization +--- + README.esync | 14 +++++--------- + 1 file changed, 5 insertions(+), 9 deletions(-) + +diff --git a/README.esync b/README.esync +index 7706f395ebd..b64bfefc1a3 100644 +--- a/README.esync ++++ b/README.esync +@@ -5,7 +5,7 @@ with +esync. + == BUGS AND LIMITATIONS == + + Please let me know if you find any bugs. If you can, also attach a log with +-+seh,+pid,+esync,+server. +++seh,+pid,+esync,+server,+timestamp. + + If you get something like "eventfd: Too many open files" and then things start + crashing, you've probably run out of file descriptors. esync creates one +@@ -20,11 +20,11 @@ have a reasonable limit.) To raise the limit you'll want to edit + + then restart your session. + +-On distributions using systemd, the settings in `/etc/security/limits.conf` will +-be overridden by systemd's own settings. If you run `ulimit -Hn` and it returns +-a lower number than the one you've previously set then you can set ++On distributions using systemd, the settings in `/etc/security/limits.conf` ++will be overridden by systemd's own settings. If you run `ulimit -Hn` and it ++returns a lower number than the one you've previously set, then you can set + +-DefaultLimitNOFILE=100000 ++DefaultLimitNOFILE=1048576 + + in both `/etc/systemd/system.conf` and `/etc/systemd/user.conf`. You can then + execute `sudo systemctl daemon-reexec` and restart your session. Check again +@@ -157,10 +157,6 @@ surprisingly there aren't that many. In particular: + can probably be something reasonable.) It's also possible, although I + haven't yet looked, to use some different kind of synchronization + primitives, but pipes would be easiest to tack onto this framework. +-* We might hit the maximum number of open fd's. On my system the soft limit is +- 1024 and the hard limit is 1048576. I'm inclined to hope this won't be an +- issue, since a hypothetical Linux port of any application might just as well +- use the same number of eventfds. + * PulseEvent() can't work the way it's supposed to work. Fortunately it's rare + and deprecated. It's also explicitly mentioned on MSDN that a thread can + miss the notification for a kernel APC, so in a sense we're not necessarily +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0053-ntdll-Implement-NtPulseEvent.patch b/0007-proton-esync-fsync/0053-ntdll-Implement-NtPulseEvent.patch new file mode 100644 index 0000000..a3a0f69 --- /dev/null +++ b/0007-proton-esync-fsync/0053-ntdll-Implement-NtPulseEvent.patch @@ -0,0 +1,77 @@ +From 3285ff0dfa705fd2a861c020c07d89fc80edc02a Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 17:56:40 -0500 +Subject: [PATCH 0479/2346] ntdll: Implement NtPulseEvent(). + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 25 +++++++++++++++++++++++++ + dlls/ntdll/unix/esync.h | 1 + + dlls/ntdll/unix/sync.c | 3 +++ + 3 files changed, 29 insertions(+) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 880cf5006ae..e9aa3b5194f 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -597,6 +597,31 @@ NTSTATUS esync_reset_event( HANDLE handle ) + return STATUS_SUCCESS; + } + ++NTSTATUS esync_pulse_event( HANDLE handle ) ++{ ++ uint64_t value = 1; ++ struct esync *obj; ++ NTSTATUS ret; ++ ++ TRACE("%p.\n", handle); ++ ++ if ((ret = get_object( handle, &obj ))) return ret; ++ ++ /* This isn't really correct; an application could miss the write. ++ * Unfortunately we can't really do much better. Fortunately this is rarely ++ * used (and publicly deprecated). */ ++ if (write( obj->fd, &value, sizeof(value) ) == -1) ++ return errno_to_status( errno ); ++ ++ /* Try to give other threads a chance to wake up. Hopefully erring on this ++ * side is the better thing to do... */ ++ NtYieldExecution(); ++ ++ read( obj->fd, &value, sizeof(value) ); ++ ++ return STATUS_SUCCESS; ++} ++ + NTSTATUS esync_query_event( HANDLE handle, void *info, ULONG *ret_len ) + { + struct esync *obj; +diff --git a/dlls/ntdll/unix/esync.h b/dlls/ntdll/unix/esync.h +index 61846238ab7..59f8809fc1a 100644 +--- a/dlls/ntdll/unix/esync.h ++++ b/dlls/ntdll/unix/esync.h +@@ -33,6 +33,7 @@ extern NTSTATUS esync_create_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ); + extern NTSTATUS esync_open_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr ); ++extern NTSTATUS esync_pulse_event( HANDLE handle ); + extern NTSTATUS esync_query_event( HANDLE handle, void *info, ULONG *ret_len ); + extern NTSTATUS esync_reset_event( HANDLE handle ); + extern NTSTATUS esync_set_event( HANDLE handle ); +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 5d25f086d5d..3a9fc76c2e4 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -508,6 +508,9 @@ NTSTATUS WINAPI NtPulseEvent( HANDLE handle, LONG *prev_state ) + { + unsigned int ret; + ++ if (do_esync()) ++ return esync_pulse_event( handle ); ++ + SERVER_START_REQ( event_op ) + { + req->handle = wine_server_obj_handle( handle ); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0054-esync-Update-README.patch b/0007-proton-esync-fsync/0054-esync-Update-README.patch new file mode 100644 index 0000000..32581bb --- /dev/null +++ b/0007-proton-esync-fsync/0054-esync-Update-README.patch @@ -0,0 +1,25 @@ +From bdcb61bc3a5b3bd4f2c722793b1b4dde54275a6c Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sun, 19 Aug 2018 13:40:05 -0500 +Subject: [PATCH 0480/2346] esync: Update README. + +Wine-Staging: eventfd_synchronization +--- + README.esync | 3 +-- + 1 file changed, 1 insertion(+), 2 deletions(-) + +diff --git a/README.esync b/README.esync +index b64bfefc1a3..11d86563a10 100644 +--- a/README.esync ++++ b/README.esync +@@ -1,6 +1,5 @@ + This is eventfd-based synchronization, or 'esync' for short. Turn it on with +-WINEESYNC=1 (note that it checks the presence and not the value); debug it +-with +esync. ++WINEESYNC=1; debug it with +esync. + + == BUGS AND LIMITATIONS == + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0055-server-Create-esync-file-descriptors-for-true-file-o.patch b/0007-proton-esync-fsync/0055-server-Create-esync-file-descriptors-for-true-file-o.patch new file mode 100644 index 0000000..0c001c4 --- /dev/null +++ b/0007-proton-esync-fsync/0055-server-Create-esync-file-descriptors-for-true-file-o.patch @@ -0,0 +1,42 @@ +From 15fe50402be3d8379befa4fd2ee63b6fd874a1cc Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Wed, 24 Apr 2019 23:21:25 -0500 +Subject: [PATCH 0481/2346] server: Create esync file descriptors for true file + objects and use them for directory change notifications. + +Wine-Staging: eventfd_synchronization +--- + server/change.c | 2 +- + server/fd.c | 3 +++ + 2 files changed, 4 insertions(+), 1 deletion(-) + +diff --git a/server/change.c b/server/change.c +index 5f1cf9b880b..6bd6920fdb5 100644 +--- a/server/change.c ++++ b/server/change.c +@@ -112,7 +112,7 @@ static const struct object_ops dir_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ +- NULL, /* get_esync_fd */ ++ default_fd_get_esync_fd, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + dir_get_fd, /* get_fd */ +diff --git a/server/fd.c b/server/fd.c +index 75af39b134e..4149c9d4637 100644 +--- a/server/fd.c ++++ b/server/fd.c +@@ -1699,6 +1699,9 @@ static struct fd *alloc_fd_object(void) + list_init( &fd->inode_entry ); + list_init( &fd->locks ); + ++ if (do_esync()) ++ fd->esync_fd = esync_create_fd( 1, 0 ); ++ + if ((fd->poll_index = add_poll_user( fd )) == -1) + { + release_object( fd ); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0056-ntdll-server-Abandon-esync-mutexes-on-thread-exit.patch b/0007-proton-esync-fsync/0056-ntdll-server-Abandon-esync-mutexes-on-thread-exit.patch new file mode 100644 index 0000000..4f1c1ea --- /dev/null +++ b/0007-proton-esync-fsync/0056-ntdll-server-Abandon-esync-mutexes-on-thread-exit.patch @@ -0,0 +1,194 @@ +From 8a63663844f682e6736bd0992801ffb578b32a56 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 18:01:32 -0500 +Subject: [PATCH 0482/2346] ntdll, server: Abandon esync mutexes on thread + exit. + +Wine-Staging: eventfd_synchronization +--- + dlls/ntdll/unix/esync.c | 31 ++++++++++++++++++++++++++----- + server/esync.c | 25 +++++++++++++++++++++++++ + server/esync.h | 1 + + server/thread.c | 2 ++ + 4 files changed, 54 insertions(+), 5 deletions(-) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index e9aa3b5194f..da3d3a2ab29 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -707,7 +707,7 @@ NTSTATUS esync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) + + out->CurrentCount = 1 - mutex->count; + out->OwnedByCaller = (mutex->tid == GetCurrentThreadId()); +- out->AbandonedState = FALSE; ++ out->AbandonedState = (mutex->tid == ~0); + if (ret_len) *ret_len = sizeof(*out); + + return STATUS_SUCCESS; +@@ -757,14 +757,19 @@ static int do_poll( struct pollfd *fds, nfds_t nfds, ULONGLONG *end ) + return ret; + } + +-static void update_grabbed_object( struct esync *obj ) ++/* Return TRUE if abandoned. */ ++static BOOL update_grabbed_object( struct esync *obj ) + { ++ BOOL ret = FALSE; ++ + if (obj->type == ESYNC_MUTEX) + { + struct mutex *mutex = obj->shm; + /* We don't have to worry about a race between this and read(); the + * fact that we grabbed it means the count is now zero, so nobody else + * can (and the only thread that can release it is us). */ ++ if (mutex->tid == ~0) ++ ret = TRUE; + mutex->tid = GetCurrentThreadId(); + mutex->count++; + } +@@ -785,6 +790,8 @@ static void update_grabbed_object( struct esync *obj ) + * This might already be 0, but that's okay! */ + event->signaled = 0; + } ++ ++ return ret; + } + + /* A value of STATUS_NOT_IMPLEMENTED returned from this function means that we +@@ -904,7 +911,13 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA + { + if ((size = read( obj->fd, &value, sizeof(value) )) == sizeof(value)) + { +- TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ if (mutex->tid == ~0) ++ { ++ TRACE("Woken up by abandoned mutex %p [%d].\n", handles[i], i); ++ i += STATUS_ABANDONED_WAIT_0; ++ } ++ else ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); + mutex->tid = GetCurrentThreadId(); + mutex->count++; + return i; +@@ -1017,7 +1030,8 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA + { + /* We found our object. */ + TRACE("Woken up by handle %p [%d].\n", handles[i], i); +- update_grabbed_object( obj ); ++ if (update_grabbed_object( obj )) ++ return STATUS_ABANDONED_WAIT_0 + i; + return i; + } + } +@@ -1110,6 +1124,8 @@ tryagain: + ret = poll( fds, pollcount, 0 ); + if (ret == pollcount) + { ++ BOOL abandoned = FALSE; ++ + /* Quick, grab everything. */ + for (i = 0; i < count; i++) + { +@@ -1150,8 +1166,13 @@ tryagain: + /* Make sure to let ourselves know that we grabbed the mutexes + * and semaphores. */ + for (i = 0; i < count; i++) +- update_grabbed_object( objs[i] ); ++ abandoned |= update_grabbed_object( objs[i] ); + ++ if (abandoned) ++ { ++ TRACE("Wait successful, but some object(s) were abandoned.\n"); ++ return STATUS_ABANDONED; ++ } + TRACE("Wait successful.\n"); + return STATUS_SUCCESS; + } +diff --git a/server/esync.c b/server/esync.c +index 20ea97869e9..e193f61b3a7 100644 +--- a/server/esync.c ++++ b/server/esync.c +@@ -103,12 +103,15 @@ void esync_init(void) + atexit( shm_cleanup ); + } + ++static struct list mutex_list = LIST_INIT(mutex_list); ++ + struct esync + { + struct object obj; /* object header */ + int fd; /* eventfd file descriptor */ + enum esync_type type; + unsigned int shm_idx; /* index into the shared memory section */ ++ struct list mutex_entry; /* entry in the mutex list (if applicable) */ + }; + + static void esync_dump( struct object *obj, int verbose ); +@@ -168,6 +171,8 @@ static unsigned int esync_map_access( struct object *obj, unsigned int access ) + static void esync_destroy( struct object *obj ) + { + struct esync *esync = (struct esync *)obj; ++ if (esync->type == ESYNC_MUTEX) ++ list_remove( &esync->mutex_entry ); + close( esync->fd ); + } + +@@ -303,6 +308,7 @@ struct esync *create_esync( struct object *root, const struct unicode_str *name, + struct mutex *mutex = get_shm( esync->shm_idx ); + mutex->tid = initval ? 0 : current->id; + mutex->count = initval ? 0 : 1; ++ list_add_tail( &mutex_list, &esync->mutex_entry ); + break; + } + default: +@@ -449,6 +455,25 @@ void esync_reset_event( struct esync *esync ) + } + } + ++void esync_abandon_mutexes( struct thread *thread ) ++{ ++ struct esync *esync; ++ ++ LIST_FOR_EACH_ENTRY( esync, &mutex_list, struct esync, mutex_entry ) ++ { ++ struct mutex *mutex = get_shm( esync->shm_idx ); ++ ++ if (mutex->tid == thread->id) ++ { ++ if (debug_level) ++ fprintf( stderr, "esync_abandon_mutexes() fd=%d\n", esync->fd ); ++ mutex->tid = ~0; ++ mutex->count = 0; ++ esync_wake_fd( esync->fd ); ++ } ++ } ++} ++ + DECL_HANDLER(create_esync) + { + struct esync *esync; +diff --git a/server/esync.h b/server/esync.h +index e1588d205d9..d39f4efa3ec 100644 +--- a/server/esync.h ++++ b/server/esync.h +@@ -32,3 +32,4 @@ struct esync; + extern const struct object_ops esync_ops; + void esync_set_event( struct esync *esync ); + void esync_reset_event( struct esync *esync ); ++void esync_abandon_mutexes( struct thread *thread ); +diff --git a/server/thread.c b/server/thread.c +index 9592ae6c8bf..e906e0c07c9 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -1476,6 +1476,8 @@ void kill_thread( struct thread *thread, int violent_death ) + } + kill_console_processes( thread, 0 ); + abandon_mutexes( thread ); ++ if (do_esync()) ++ esync_abandon_mutexes( thread ); + if (violent_death) + { + send_thread_signal( thread, SIGQUIT ); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0057-server-Create-esync-file-descriptors-for-console-ser.patch b/0007-proton-esync-fsync/0057-server-Create-esync-file-descriptors-for-console-ser.patch new file mode 100644 index 0000000..acc1602 --- /dev/null +++ b/0007-proton-esync-fsync/0057-server-Create-esync-file-descriptors-for-console-ser.patch @@ -0,0 +1,125 @@ +From 87810e31a5ae52e59fd8ef6f14d9e868c72e0952 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 17 Oct 2020 19:13:16 -0500 +Subject: [PATCH 0483/2346] server: Create esync file descriptors for console + servers. + +Wine-Staging: eventfd_synchronization +--- + server/console.c | 37 +++++++++++++++++++++++++++++-------- + 1 file changed, 29 insertions(+), 8 deletions(-) + +diff --git a/server/console.c b/server/console.c +index 1cc9eea6a50..dbd4a97459c 100644 +--- a/server/console.c ++++ b/server/console.c +@@ -41,6 +41,7 @@ + #include "wincon.h" + #include "winternl.h" + #include "wine/condrv.h" ++#include "esync.h" + + struct screen_buffer; + +@@ -131,20 +132,22 @@ struct console_host_ioctl + + struct console_server + { +- struct object obj; /* object header */ +- struct fd *fd; /* pseudo-fd for ioctls */ +- struct console *console; /* attached console */ +- struct list queue; /* ioctl queue */ +- struct list read_queue; /* blocking read queue */ ++ struct object obj; /* object header */ ++ struct fd *fd; /* pseudo-fd for ioctls */ ++ struct console *console; /* attached console */ ++ struct list queue; /* ioctl queue */ ++ struct list read_queue; /* blocking read queue */ + unsigned int busy : 1; /* flag if server processing an ioctl */ + unsigned int once_input : 1; /* flag if input thread has already been requested */ +- int term_fd; /* UNIX terminal fd */ +- struct termios termios; /* original termios */ ++ int term_fd; /* UNIX terminal fd */ ++ struct termios termios; /* original termios */ ++ int esync_fd; + }; + + static void console_server_dump( struct object *obj, int verbose ); + static void console_server_destroy( struct object *obj ); + static int console_server_signaled( struct object *obj, struct wait_queue_entry *entry ); ++static int console_server_get_esync_fd( struct object *obj, enum esync_type *type ); + static struct fd *console_server_get_fd( struct object *obj ); + static struct object *console_server_lookup_name( struct object *obj, struct unicode_str *name, + unsigned int attr, struct object *root ); +@@ -159,7 +162,7 @@ static const struct object_ops console_server_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + console_server_signaled, /* signaled */ +- NULL, /* get_esync_fd */ ++ console_server_get_esync_fd, /* get_esync_fd */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + console_server_get_fd, /* get_fd */ +@@ -597,6 +600,8 @@ static void disconnect_console_server( struct console_server *server ) + list_remove( &call->entry ); + console_host_ioctl_terminate( call, STATUS_CANCELLED ); + } ++ if (do_esync()) ++ esync_clear( server->esync_fd ); + while (!list_empty( &server->read_queue )) + { + struct console_host_ioctl *call = LIST_ENTRY( list_head( &server->read_queue ), struct console_host_ioctl, entry ); +@@ -879,6 +884,7 @@ static void console_server_destroy( struct object *obj ) + assert( obj->ops == &console_server_ops ); + disconnect_console_server( server ); + if (server->fd) release_object( server->fd ); ++ if (do_esync()) close( server->esync_fd ); + } + + static struct object *console_server_lookup_name( struct object *obj, struct unicode_str *name, +@@ -920,6 +926,13 @@ static int console_server_signaled( struct object *obj, struct wait_queue_entry + return !server->console || !list_empty( &server->queue ); + } + ++static int console_server_get_esync_fd( struct object *obj, enum esync_type *type ) ++{ ++ struct console_server *server = (struct console_server*)obj; ++ *type = ESYNC_MANUAL_SERVER; ++ return server->esync_fd; ++} ++ + static struct fd *console_server_get_fd( struct object* obj ) + { + struct console_server *server = (struct console_server*)obj; +@@ -951,6 +964,10 @@ static struct object *create_console_server( void ) + return NULL; + } + allow_fd_caching(server->fd); ++ server->esync_fd = -1; ++ ++ if (do_esync()) ++ server->esync_fd = esync_create_fd( 0, 0 ); + + return &server->obj; + } +@@ -1564,6 +1581,8 @@ DECL_HANDLER(get_next_console_request) + /* set result of previous ioctl */ + ioctl = LIST_ENTRY( list_head( &server->queue ), struct console_host_ioctl, entry ); + list_remove( &ioctl->entry ); ++ if (do_esync() && list_empty( &server->queue )) ++ esync_clear( server->esync_fd ); + } + + if (ioctl) +@@ -1649,6 +1668,8 @@ DECL_HANDLER(get_next_console_request) + { + set_error( STATUS_PENDING ); + } ++ if (do_esync() && list_empty( &server->queue )) ++ esync_clear( server->esync_fd ); + + release_object( server ); + } +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0058-readme-only-adjust-hard-limit-in-systemd-20.patch b/0007-proton-esync-fsync/0058-readme-only-adjust-hard-limit-in-systemd-20.patch new file mode 100644 index 0000000..c4b53db --- /dev/null +++ b/0007-proton-esync-fsync/0058-readme-only-adjust-hard-limit-in-systemd-20.patch @@ -0,0 +1,29 @@ +From 38b5ef03fd17dc439b90a43d6c7209ee9ce41308 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Kamil=20P=C3=A1ral?= +Date: Wed, 10 Oct 2018 19:17:00 +0200 +Subject: [PATCH 0484/2346] readme: only adjust hard limit in systemd (#20) + +Instead of increasing both soft and hard fileno limit in systemd +instructions, increase just the hard limit. Soft limit needs to stay at +1024 for compatibility with programs using select() instead of newer +poll()/epoll(), otherwise such programs might fail. +--- + README.esync | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/README.esync b/README.esync +index 11d86563a10..6520f2da564 100644 +--- a/README.esync ++++ b/README.esync +@@ -23,7 +23,7 @@ On distributions using systemd, the settings in `/etc/security/limits.conf` + will be overridden by systemd's own settings. If you run `ulimit -Hn` and it + returns a lower number than the one you've previously set, then you can set + +-DefaultLimitNOFILE=1048576 ++DefaultLimitNOFILE=1024:1048576 + + in both `/etc/systemd/system.conf` and `/etc/systemd/user.conf`. You can then + execute `sudo systemctl daemon-reexec` and restart your session. Check again +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0059-esync-Fix-restoring-the-objects-state-on-wait-all-ob.patch b/0007-proton-esync-fsync/0059-esync-Fix-restoring-the-objects-state-on-wait-all-ob.patch new file mode 100644 index 0000000..64b07e8 --- /dev/null +++ b/0007-proton-esync-fsync/0059-esync-Fix-restoring-the-objects-state-on-wait-all-ob.patch @@ -0,0 +1,43 @@ +From a2481b61e9cb5390bd4a942a1f3f8517fa031916 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Fri, 12 Mar 2021 23:58:39 +0300 +Subject: [PATCH 0485/2346] esync: Fix restoring the objects state on wait all + objects retry. + +For Forza Horizon 4. +--- + dlls/ntdll/unix/esync.c | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index da3d3a2ab29..6eea9d3afc4 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -1146,10 +1146,22 @@ tryagain: + { + /* We were too slow. Put everything back. */ + value = 1; +- for (j = i; j >= 0; j--) ++ for (j = i - 1; j >= 0; j--) + { +- if (write( obj->fd, &value, sizeof(value) ) == -1) ++ struct esync *obj = objs[j]; ++ ++ if (obj->type == ESYNC_MUTEX) ++ { ++ struct mutex *mutex = obj->shm; ++ ++ if (mutex->tid == GetCurrentThreadId()) ++ continue; ++ } ++ if (write( fds[j].fd, &value, sizeof(value) ) == -1) ++ { ++ ERR("write failed.\n"); + return errno_to_status( errno ); ++ } + } + + goto tryagain; /* break out of two loops and a switch */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0060-server-Create-server-objects-for-futex-based-synchro.patch b/0007-proton-esync-fsync/0060-server-Create-server-objects-for-futex-based-synchro.patch new file mode 100644 index 0000000..1c595ba --- /dev/null +++ b/0007-proton-esync-fsync/0060-server-Create-server-objects-for-futex-based-synchro.patch @@ -0,0 +1,392 @@ +From 6eb724bcb051bf7e56cebf4df70fd5f72d53b00e Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 1 Sep 2018 15:17:29 -0500 +Subject: [PATCH 0486/2346] server: Create server objects for futex-based + synchronization objects. + +--- + server/Makefile.in | 1 + + server/fsync.c | 286 ++++++++++++++++++++++++++++++++++++++++++++ + server/fsync.h | 22 ++++ + server/main.c | 4 + + server/protocol.def | 11 ++ + 5 files changed, 324 insertions(+) + create mode 100644 server/fsync.c + create mode 100644 server/fsync.h + +diff --git a/server/Makefile.in b/server/Makefile.in +index 79d05f2318c..a98615cce72 100644 +--- a/server/Makefile.in ++++ b/server/Makefile.in +@@ -15,6 +15,7 @@ SOURCES = \ + event.c \ + fd.c \ + file.c \ ++ fsync.c \ + handle.c \ + hook.c \ + mach.c \ +diff --git a/server/fsync.c b/server/fsync.c +new file mode 100644 +index 00000000000..5f36e988803 +--- /dev/null ++++ b/server/fsync.c +@@ -0,0 +1,286 @@ ++/* ++ * futex-based synchronization objects ++ * ++ * Copyright (C) 2018 Zebediah Figura ++ * ++ * 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 ++ */ ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include ++#include ++#ifdef HAVE_SYS_STAT_H ++# include ++#endif ++#ifdef HAVE_SYS_SYSCALL_H ++# include ++#endif ++#include ++ ++#include "ntstatus.h" ++#define WIN32_NO_STATUS ++#include "windef.h" ++#include "winternl.h" ++ ++#include "handle.h" ++#include "request.h" ++#include "fsync.h" ++ ++#include "pshpack4.h" ++struct futex_wait_block ++{ ++ int *addr; ++#if __SIZEOF_POINTER__ == 4 ++ int pad; ++#endif ++ int val; ++}; ++#include "poppack.h" ++ ++static inline int futex_wait_multiple( const struct futex_wait_block *futexes, ++ int count, const struct timespec *timeout ) ++{ ++ return syscall( __NR_futex, futexes, 13, count, timeout, 0, 0 ); ++} ++ ++int do_fsync(void) ++{ ++#ifdef __linux__ ++ static int do_fsync_cached = -1; ++ ++ if (do_fsync_cached == -1) ++ { ++ static const struct timespec zero; ++ futex_wait_multiple( NULL, 0, &zero ); ++ do_fsync_cached = getenv("WINEFSYNC") && atoi(getenv("WINEFSYNC")) && errno != ENOSYS; ++ } ++ ++ return do_fsync_cached; ++#else ++ return 0; ++#endif ++} ++ ++static char shm_name[29]; ++static int shm_fd; ++static off_t shm_size; ++static void **shm_addrs; ++static int shm_addrs_size; /* length of the allocated shm_addrs array */ ++static long pagesize; ++ ++static void shm_cleanup(void) ++{ ++ close( shm_fd ); ++ if (shm_unlink( shm_name ) == -1) ++ perror( "shm_unlink" ); ++} ++ ++void fsync_init(void) ++{ ++ struct stat st; ++ ++ if (fstat( config_dir_fd, &st ) == -1) ++ fatal_error( "cannot stat config dir\n" ); ++ ++ if (st.st_ino != (unsigned long)st.st_ino) ++ sprintf( shm_name, "/wine-%lx%08lx-fsync", (unsigned long)((unsigned long long)st.st_ino >> 32), (unsigned long)st.st_ino ); ++ else ++ sprintf( shm_name, "/wine-%lx-fsync", (unsigned long)st.st_ino ); ++ ++ if (!shm_unlink( shm_name )) ++ fprintf( stderr, "fsync: warning: a previous shm file %s was not properly removed\n", shm_name ); ++ ++ shm_fd = shm_open( shm_name, O_RDWR | O_CREAT | O_EXCL, 0644 ); ++ if (shm_fd == -1) ++ perror( "shm_open" ); ++ ++ pagesize = sysconf( _SC_PAGESIZE ); ++ ++ shm_addrs = calloc( 128, sizeof(shm_addrs[0]) ); ++ shm_addrs_size = 128; ++ ++ shm_size = pagesize; ++ if (ftruncate( shm_fd, shm_size ) == -1) ++ perror( "ftruncate" ); ++ ++ atexit( shm_cleanup ); ++} ++ ++struct fsync ++{ ++ struct object obj; ++ unsigned int shm_idx; ++}; ++ ++static void fsync_dump( struct object *obj, int verbose ); ++static void fsync_destroy( struct object *obj ); ++ ++static const struct object_ops fsync_ops = ++{ ++ sizeof(struct fsync), /* size */ ++ &no_type, /* type */ ++ fsync_dump, /* dump */ ++ no_add_queue, /* add_queue */ ++ NULL, /* remove_queue */ ++ NULL, /* signaled */ ++ NULL, /* get_esync_fd */ ++ NULL, /* satisfied */ ++ no_signal, /* signal */ ++ no_get_fd, /* get_fd */ ++ default_map_access, /* map_access */ ++ default_get_sd, /* get_sd */ ++ default_set_sd, /* set_sd */ ++ default_get_full_name, /* get_full_name */ ++ no_lookup_name, /* lookup_name */ ++ directory_link_name, /* link_name */ ++ default_unlink_name, /* unlink_name */ ++ no_open_file, /* open_file */ ++ no_kernel_obj_list, /* get_kernel_obj_list */ ++ no_close_handle, /* close_handle */ ++ fsync_destroy /* destroy */ ++}; ++ ++static void fsync_dump( struct object *obj, int verbose ) ++{ ++ struct fsync *fsync = (struct fsync *)obj; ++ assert( obj->ops == &fsync_ops ); ++ fprintf( stderr, "fsync idx=%d\n", fsync->shm_idx ); ++} ++ ++static void fsync_destroy( struct object *obj ) ++{ ++} ++ ++static void *get_shm( unsigned int idx ) ++{ ++ int entry = (idx * 8) / pagesize; ++ int offset = (idx * 8) % pagesize; ++ ++ if (entry >= shm_addrs_size) ++ { ++ int new_size = max(shm_addrs_size * 2, entry + 1); ++ ++ if (!(shm_addrs = realloc( shm_addrs, new_size * sizeof(shm_addrs[0]) ))) ++ fprintf( stderr, "fsync: couldn't expand shm_addrs array to size %d\n", entry + 1 ); ++ ++ memset( shm_addrs + shm_addrs_size, 0, (new_size - shm_addrs_size) * sizeof(shm_addrs[0]) ); ++ ++ shm_addrs_size = new_size; ++ } ++ ++ if (!shm_addrs[entry]) ++ { ++ void *addr = mmap( NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, entry * pagesize ); ++ if (addr == (void *)-1) ++ { ++ fprintf( stderr, "fsync: failed to map page %d (offset %#lx): ", entry, entry * pagesize ); ++ perror( "mmap" ); ++ } ++ ++ if (debug_level) ++ fprintf( stderr, "fsync: Mapping page %d at %p.\n", entry, addr ); ++ ++ if (__sync_val_compare_and_swap( &shm_addrs[entry], 0, addr )) ++ munmap( addr, pagesize ); /* someone beat us to it */ ++ } ++ ++ return (void *)((unsigned long)shm_addrs[entry] + offset); ++} ++ ++/* FIXME: This is rather inefficient... */ ++static unsigned int shm_idx_counter = 1; ++ ++struct fsync *create_fsync( struct object *root, const struct unicode_str *name, ++ unsigned int attr, int low, int high, ++ const struct security_descriptor *sd ) ++{ ++#ifdef __linux__ ++ struct fsync *fsync; ++ ++ if ((fsync = create_named_object( root, &fsync_ops, name, attr, sd ))) ++ { ++ if (get_error() != STATUS_OBJECT_NAME_EXISTS) ++ { ++ int *shm; ++ ++ /* initialize it if it didn't already exist */ ++ ++ fsync->shm_idx = shm_idx_counter++; ++ while (fsync->shm_idx * 8 >= shm_size) ++ { ++ /* Better expand the shm section. */ ++ shm_size += pagesize; ++ if (ftruncate( shm_fd, shm_size ) == -1) ++ { ++ fprintf( stderr, "fsync: couldn't expand %s to size %lld: ", ++ shm_name, (long long)shm_size ); ++ perror( "ftruncate" ); ++ } ++ } ++ ++ /* Initialize the shared memory portion. We want to do this on the ++ * server side to avoid a potential though unlikely race whereby ++ * the same object is opened and used between the time it's created ++ * and the time its shared memory portion is initialized. */ ++ ++ shm = get_shm( fsync->shm_idx ); ++ assert(shm); ++ shm[0] = low; ++ shm[1] = high; ++ } ++ } ++ ++ return fsync; ++#else ++ set_error( STATUS_NOT_IMPLEMENTED ); ++ return NULL; ++#endif ++} ++ ++DECL_HANDLER(create_fsync) ++{ ++ struct fsync *fsync; ++ struct unicode_str name; ++ struct object *root; ++ const struct security_descriptor *sd; ++ const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root ); ++ ++ if (!do_fsync()) ++ { ++ set_error( STATUS_NOT_IMPLEMENTED ); ++ return; ++ } ++ ++ if (!objattr) return; ++ ++ if ((fsync = create_fsync( root, &name, objattr->attributes, req->low, ++ req->high, sd ))) ++ { ++ if (get_error() == STATUS_OBJECT_NAME_EXISTS) ++ reply->handle = alloc_handle( current->process, fsync, req->access, objattr->attributes ); ++ else ++ reply->handle = alloc_handle_no_access_check( current->process, fsync, ++ req->access, objattr->attributes ); ++ ++ reply->shm_idx = fsync->shm_idx; ++ release_object( fsync ); ++ } ++ ++ if (root) release_object( root ); ++} +diff --git a/server/fsync.h b/server/fsync.h +new file mode 100644 +index 00000000000..0b7e46cdaf3 +--- /dev/null ++++ b/server/fsync.h +@@ -0,0 +1,22 @@ ++/* ++ * futex-based synchronization objects ++ * ++ * Copyright (C) 2018 Zebediah Figura ++ * ++ * 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 ++ */ ++ ++extern int do_fsync(void); ++extern void fsync_init(void); +diff --git a/server/main.c b/server/main.c +index c4bb790db8a..457b044a36a 100644 +--- a/server/main.c ++++ b/server/main.c +@@ -35,6 +35,7 @@ + #include "request.h" + #include "unicode.h" + #include "esync.h" ++#include "fsync.h" + + /* command-line options */ + int debug_level = 0; +@@ -230,6 +231,9 @@ int main( int argc, char *argv[] ) + sock_init(); + open_master_socket(); + ++ if (do_fsync()) ++ fsync_init(); ++ + if (do_esync()) + esync_init(); + +diff --git a/server/protocol.def b/server/protocol.def +index d5026dce3d9..2243d97dcfe 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3991,3 +3991,14 @@ enum esync_type + /* Retrieve the fd to wait on for user APCs. */ + @REQ(get_esync_apc_fd) + @END ++ ++/* Create a new futex-based synchronization object */ ++@REQ(create_fsync) ++ unsigned int access; /* wanted access rights */ ++ int low; /* initial value of low word */ ++ int high; /* initial value of high word */ ++ VARARG(objattr,object_attributes); /* object attributes */ ++@REPLY ++ obj_handle_t handle; /* handle to the object */ ++ unsigned int shm_idx; /* this object's index into the shm section */ ++@END +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0061-ntdll-Create-futex-based-objects-for-semaphores.patch b/0007-proton-esync-fsync/0061-ntdll-Create-futex-based-objects-for-semaphores.patch new file mode 100644 index 0000000..5bbe9d4 --- /dev/null +++ b/0007-proton-esync-fsync/0061-ntdll-Create-futex-based-objects-for-semaphores.patch @@ -0,0 +1,396 @@ +From aa5882ca868f95b82b392f7363e1ad4c998b1b8f Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 19:14:24 -0500 +Subject: [PATCH 0487/2346] ntdll: Create futex-based objects for semaphores. + +--- + dlls/ntdll/Makefile.in | 1 + + dlls/ntdll/unix/fsync.c | 287 +++++++++++++++++++++++++++++++++++++++ + dlls/ntdll/unix/fsync.h | 25 ++++ + dlls/ntdll/unix/loader.c | 2 + + dlls/ntdll/unix/sync.c | 4 + + 5 files changed, 319 insertions(+) + create mode 100644 dlls/ntdll/unix/fsync.c + create mode 100644 dlls/ntdll/unix/fsync.h + +diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in +index 70fac547c57..0ce1f44a34d 100644 +--- a/dlls/ntdll/Makefile.in ++++ b/dlls/ntdll/Makefile.in +@@ -50,6 +50,7 @@ SOURCES = \ + unix/env.c \ + unix/esync.c \ + unix/file.c \ ++ unix/fsync.c \ + unix/loader.c \ + unix/loadorder.c \ + unix/process.c \ +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +new file mode 100644 +index 00000000000..c1530300e18 +--- /dev/null ++++ b/dlls/ntdll/unix/fsync.c +@@ -0,0 +1,287 @@ ++/* ++ * futex-based synchronization objects ++ * ++ * Copyright (C) 2018 Zebediah Figura ++ * ++ * 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 ++ */ ++ ++#if 0 ++#pragma makedep unix ++#endif ++ ++#include "config.h" ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++#ifdef HAVE_SYS_STAT_H ++# include ++#endif ++#ifdef HAVE_SYS_SYSCALL_H ++# include ++#endif ++#include ++ ++#include "ntstatus.h" ++#define WIN32_NO_STATUS ++#include "windef.h" ++#include "winternl.h" ++#include "wine/debug.h" ++#include "wine/server.h" ++ ++#include "unix_private.h" ++#include "fsync.h" ++ ++WINE_DEFAULT_DEBUG_CHANNEL(fsync); ++ ++#include "pshpack4.h" ++struct futex_wait_block ++{ ++ int *addr; ++#if __SIZEOF_POINTER__ == 4 ++ int pad; ++#endif ++ int val; ++}; ++#include "poppack.h" ++ ++static inline int futex_wait_multiple( const struct futex_wait_block *futexes, ++ int count, const struct timespec *timeout ) ++{ ++ return syscall( __NR_futex, futexes, 13, count, timeout, 0, 0 ); ++} ++ ++int do_fsync(void) ++{ ++#ifdef __linux__ ++ static int do_fsync_cached = -1; ++ ++ if (do_fsync_cached == -1) ++ { ++ static const struct timespec zero; ++ futex_wait_multiple( NULL, 0, &zero ); ++ do_fsync_cached = getenv("WINEFSYNC") && atoi(getenv("WINEFSYNC")) && errno != ENOSYS; ++ } ++ ++ return do_fsync_cached; ++#else ++ static int once; ++ if (!once++) ++ FIXME("futexes not supported on this platform.\n"); ++ return 0; ++#endif ++} ++ ++enum fsync_type ++{ ++ FSYNC_SEMAPHORE = 1, ++}; ++ ++struct fsync ++{ ++ enum fsync_type type; ++ void *shm; /* pointer to shm section */ ++}; ++ ++struct semaphore ++{ ++ int count; ++ int max; ++}; ++C_ASSERT(sizeof(struct semaphore) == 8); ++ ++ ++static char shm_name[29]; ++static int shm_fd; ++static void **shm_addrs; ++static int shm_addrs_size; /* length of the allocated shm_addrs array */ ++static long pagesize; ++ ++static void *get_shm( unsigned int idx ) ++{ ++ int entry = (idx * 8) / pagesize; ++ int offset = (idx * 8) % pagesize; ++ ++ if (entry >= shm_addrs_size) ++ { ++ int new_size = max(shm_addrs_size * 2, entry + 1); ++ ++ if (!(shm_addrs = realloc( shm_addrs, new_size * sizeof(shm_addrs[0]) ))) ++ ERR("Failed to grow shm_addrs array to size %d.\n", shm_addrs_size); ++ memset( shm_addrs + shm_addrs_size, 0, (new_size - shm_addrs_size) * sizeof(shm_addrs[0]) ); ++ shm_addrs_size = new_size; ++ } ++ ++ if (!shm_addrs[entry]) ++ { ++ void *addr = mmap( NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, entry * pagesize ); ++ if (addr == (void *)-1) ++ ERR("Failed to map page %d (offset %#lx).\n", entry, entry * pagesize); ++ ++ TRACE("Mapping page %d at %p.\n", entry, addr); ++ ++ if (__sync_val_compare_and_swap( &shm_addrs[entry], 0, addr )) ++ munmap( addr, pagesize ); /* someone beat us to it */ ++ } ++ ++ return (void *)((unsigned long)shm_addrs[entry] + offset); ++} ++ ++/* We'd like lookup to be fast. To that end, we use a static list indexed by handle. ++ * This is copied and adapted from the fd cache code. */ ++ ++#define FSYNC_LIST_BLOCK_SIZE (65536 / sizeof(struct fsync)) ++#define FSYNC_LIST_ENTRIES 256 ++ ++static struct fsync *fsync_list[FSYNC_LIST_ENTRIES]; ++static struct fsync fsync_list_initial_block[FSYNC_LIST_BLOCK_SIZE]; ++ ++static inline UINT_PTR handle_to_index( HANDLE handle, UINT_PTR *entry ) ++{ ++ UINT_PTR idx = (((UINT_PTR)handle) >> 2) - 1; ++ *entry = idx / FSYNC_LIST_BLOCK_SIZE; ++ return idx % FSYNC_LIST_BLOCK_SIZE; ++} ++ ++static struct fsync *add_to_list( HANDLE handle, enum fsync_type type, void *shm ) ++{ ++ UINT_PTR entry, idx = handle_to_index( handle, &entry ); ++ ++ if (entry >= FSYNC_LIST_ENTRIES) ++ { ++ FIXME( "too many allocated handles, not caching %p\n", handle ); ++ return FALSE; ++ } ++ ++ if (!fsync_list[entry]) /* do we need to allocate a new block of entries? */ ++ { ++ if (!entry) fsync_list[0] = fsync_list_initial_block; ++ else ++ { ++ void *ptr = anon_mmap_alloc( FSYNC_LIST_BLOCK_SIZE * sizeof(struct fsync), ++ PROT_READ | PROT_WRITE ); ++ if (ptr == MAP_FAILED) return FALSE; ++ fsync_list[entry] = ptr; ++ } ++ } ++ ++ if (!__sync_val_compare_and_swap((int *)&fsync_list[entry][idx].type, 0, type )) ++ fsync_list[entry][idx].shm = shm; ++ ++ return &fsync_list[entry][idx]; ++} ++ ++static struct fsync *get_cached_object( HANDLE handle ) ++{ ++ UINT_PTR entry, idx = handle_to_index( handle, &entry ); ++ ++ if (entry >= FSYNC_LIST_ENTRIES || !fsync_list[entry]) return NULL; ++ if (!fsync_list[entry][idx].type) return NULL; ++ ++ return &fsync_list[entry][idx]; ++} ++ ++static NTSTATUS create_fsync( enum fsync_type type, HANDLE *handle, ++ ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, int low, int high ) ++{ ++ NTSTATUS ret; ++ data_size_t len; ++ struct object_attributes *objattr; ++ unsigned int shm_idx; ++ ++ if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; ++ ++ SERVER_START_REQ( create_fsync ) ++ { ++ req->access = access; ++ req->low = low; ++ req->high = high; ++ wine_server_add_data( req, objattr, len ); ++ ret = wine_server_call( req ); ++ if (!ret || ret == STATUS_OBJECT_NAME_EXISTS) ++ { ++ *handle = wine_server_ptr_handle( reply->handle ); ++ shm_idx = reply->shm_idx; ++ } ++ } ++ SERVER_END_REQ; ++ ++ if (!ret || ret == STATUS_OBJECT_NAME_EXISTS) ++ { ++ add_to_list( *handle, type, get_shm( shm_idx )); ++ TRACE("-> handle %p, shm index %d.\n", *handle, shm_idx); ++ } ++ ++ free( objattr ); ++ return ret; ++} ++ ++void fsync_init(void) ++{ ++ struct stat st; ++ ++ if (!do_fsync()) ++ { ++ /* make sure the server isn't running with WINEFSYNC */ ++ HANDLE handle; ++ NTSTATUS ret; ++ ++ ret = create_fsync( 0, &handle, 0, NULL, 0, 0 ); ++ if (ret != STATUS_NOT_IMPLEMENTED) ++ { ++ ERR("Server is running with WINEFSYNC but this process is not, please enable WINEFSYNC or restart wineserver.\n"); ++ exit(1); ++ } ++ ++ return; ++ } ++ ++ if (stat( config_dir, &st ) == -1) ++ ERR("Cannot stat %s\n", config_dir); ++ ++ if (st.st_ino != (unsigned long)st.st_ino) ++ sprintf( shm_name, "/wine-%lx%08lx-fsync", (unsigned long)((unsigned long long)st.st_ino >> 32), (unsigned long)st.st_ino ); ++ else ++ sprintf( shm_name, "/wine-%lx-fsync", (unsigned long)st.st_ino ); ++ ++ if ((shm_fd = shm_open( shm_name, O_RDWR, 0644 )) == -1) ++ { ++ /* probably the server isn't running with WINEFSYNC, tell the user and bail */ ++ if (errno == ENOENT) ++ ERR("Failed to open fsync shared memory file; make sure no stale wineserver instances are running without WINEFSYNC.\n"); ++ else ++ ERR("Failed to initialize shared memory: %s\n", strerror( errno )); ++ exit(1); ++ } ++ ++ pagesize = sysconf( _SC_PAGESIZE ); ++ ++ shm_addrs = calloc( 128, sizeof(shm_addrs[0]) ); ++ shm_addrs_size = 128; ++} ++ ++NTSTATUS fsync_create_semaphore( HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max ) ++{ ++ TRACE("name %s, initial %d, max %d.\n", ++ attr ? debugstr_us(attr->ObjectName) : "", (int)initial, (int)max); ++ ++ return create_fsync( FSYNC_SEMAPHORE, handle, access, attr, initial, max ); ++} +diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h +new file mode 100644 +index 00000000000..273a4817dd0 +--- /dev/null ++++ b/dlls/ntdll/unix/fsync.h +@@ -0,0 +1,25 @@ ++/* ++ * futex-based synchronization objects ++ * ++ * Copyright (C) 2018 Zebediah Figura ++ * ++ * 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 ++ */ ++ ++extern int do_fsync(void); ++extern void fsync_init(void); ++ ++extern NTSTATUS fsync_create_semaphore(HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max); +diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c +index 93331de1b1f..0712ddd3fdf 100644 +--- a/dlls/ntdll/unix/loader.c ++++ b/dlls/ntdll/unix/loader.c +@@ -89,6 +89,7 @@ extern char **environ; + #include "winternl.h" + #include "unix_private.h" + #include "esync.h" ++#include "fsync.h" + #include "wine/list.h" + #include "ntsyscalls.h" + #include "wine/debug.h" +@@ -1960,6 +1961,7 @@ static void start_main_thread(void) + dbg_init(); + startup_info_size = server_init_process(); + hacks_init(); ++ fsync_init(); + esync_init(); + virtual_map_user_shared_data(); + init_cpu_info(); +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 3a9fc76c2e4..08ee792d0ec 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -64,6 +64,7 @@ + #include "wine/debug.h" + #include "unix_private.h" + #include "esync.h" ++#include "fsync.h" + + WINE_DEFAULT_DEBUG_CHANNEL(sync); + +@@ -273,6 +274,9 @@ NTSTATUS WINAPI NtCreateSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJ + if (max <= 0 || initial < 0 || initial > max) return STATUS_INVALID_PARAMETER; + if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; + ++ if (do_fsync()) ++ return fsync_create_semaphore( handle, access, attr, initial, max ); ++ + if (do_esync()) + return esync_create_semaphore( handle, access, attr, initial, max ); + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0062-ntdll-Implement-NtReleaseSemaphore.patch b/0007-proton-esync-fsync/0062-ntdll-Implement-NtReleaseSemaphore.patch new file mode 100644 index 0000000..4ececb8 --- /dev/null +++ b/0007-proton-esync-fsync/0062-ntdll-Implement-NtReleaseSemaphore.patch @@ -0,0 +1,96 @@ +From c0afb2dfba2d8c229d64b4e2f8983ee4ae9c5fd4 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 19:21:55 -0500 +Subject: [PATCH 0488/2346] ntdll: Implement NtReleaseSemaphore(). + +--- + dlls/ntdll/unix/fsync.c | 31 +++++++++++++++++++++++++++++++ + dlls/ntdll/unix/fsync.h | 1 + + dlls/ntdll/unix/sync.c | 3 +++ + server/esync.c | 1 + + 4 files changed, 36 insertions(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index c1530300e18..5281d1cbce8 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -68,6 +68,11 @@ static inline int futex_wait_multiple( const struct futex_wait_block *futexes, + return syscall( __NR_futex, futexes, 13, count, timeout, 0, 0 ); + } + ++static inline int futex_wake( int *addr, int val ) ++{ ++ return syscall( __NR_futex, addr, 1, val, NULL, 0, 0 ); ++} ++ + int do_fsync(void) + { + #ifdef __linux__ +@@ -285,3 +290,29 @@ NTSTATUS fsync_create_semaphore( HANDLE *handle, ACCESS_MASK access, + + return create_fsync( FSYNC_SEMAPHORE, handle, access, attr, initial, max ); + } ++ ++NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) ++{ ++ struct fsync *obj; ++ struct semaphore *semaphore; ++ ULONG current; ++ ++ TRACE("%p, %d, %p.\n", handle, (int)count, prev); ++ ++ if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; ++ semaphore = obj->shm; ++ ++ do ++ { ++ current = semaphore->count; ++ if (count + current > semaphore->max) ++ return STATUS_SEMAPHORE_LIMIT_EXCEEDED; ++ } while (__sync_val_compare_and_swap( &semaphore->count, current, count + current ) != current); ++ ++ if (prev) *prev = current; ++ ++ if (!current) ++ futex_wake( &semaphore->count, count ); ++ ++ return STATUS_SUCCESS; ++} +diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h +index 273a4817dd0..0ec618385ed 100644 +--- a/dlls/ntdll/unix/fsync.h ++++ b/dlls/ntdll/unix/fsync.h +@@ -23,3 +23,4 @@ extern void fsync_init(void); + + extern NTSTATUS fsync_create_semaphore(HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max); ++extern NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ); +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 08ee792d0ec..075c93b6bad 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -369,6 +369,9 @@ NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, ULONG *previous + { + unsigned int ret; + ++ if (do_fsync()) ++ return fsync_release_semaphore( handle, count, previous ); ++ + if (do_esync()) + return esync_release_semaphore( handle, count, previous ); + +diff --git a/server/esync.c b/server/esync.c +index e193f61b3a7..fc8120f9449 100644 +--- a/server/esync.c ++++ b/server/esync.c +@@ -23,6 +23,7 @@ + + #include + #include ++#include + #include + #ifdef HAVE_SYS_EVENTFD_H + # include +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0063-ntdll-Close-fsync-objects.patch b/0007-proton-esync-fsync/0063-ntdll-Close-fsync-objects.patch new file mode 100644 index 0000000..e38580d --- /dev/null +++ b/0007-proton-esync-fsync/0063-ntdll-Close-fsync-objects.patch @@ -0,0 +1,74 @@ +From 888ffe704d9797af9eb00860be4532a2feeb4bfa Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 1 Sep 2018 15:50:37 -0500 +Subject: [PATCH 0489/2346] ntdll: Close fsync objects. + +--- + dlls/ntdll/unix/fsync.c | 15 +++++++++++++++ + dlls/ntdll/unix/fsync.h | 1 + + dlls/ntdll/unix/server.c | 4 ++++ + 3 files changed, 20 insertions(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 5281d1cbce8..2f199286950 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -203,6 +203,21 @@ static struct fsync *get_cached_object( HANDLE handle ) + return &fsync_list[entry][idx]; + } + ++NTSTATUS fsync_close( HANDLE handle ) ++{ ++ UINT_PTR entry, idx = handle_to_index( handle, &entry ); ++ ++ TRACE("%p.\n", handle); ++ ++ if (entry < FSYNC_LIST_ENTRIES && fsync_list[entry]) ++ { ++ if (__atomic_exchange_n( &fsync_list[entry][idx].type, 0, __ATOMIC_SEQ_CST )) ++ return STATUS_SUCCESS; ++ } ++ ++ return STATUS_INVALID_HANDLE; ++} ++ + static NTSTATUS create_fsync( enum fsync_type type, HANDLE *handle, + ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, int low, int high ) + { +diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h +index 0ec618385ed..ed10eeb2d7b 100644 +--- a/dlls/ntdll/unix/fsync.h ++++ b/dlls/ntdll/unix/fsync.h +@@ -20,6 +20,7 @@ + + extern int do_fsync(void); + extern void fsync_init(void); ++extern NTSTATUS fsync_close( HANDLE handle ); + + extern NTSTATUS fsync_create_semaphore(HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max); +diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c +index 8cbebd34b5f..9fb202bc430 100644 +--- a/dlls/ntdll/unix/server.c ++++ b/dlls/ntdll/unix/server.c +@@ -80,6 +80,7 @@ + #include "wine/debug.h" + #include "unix_private.h" + #include "esync.h" ++#include "fsync.h" + #include "ddk/wdm.h" + + WINE_DEFAULT_DEBUG_CHANNEL(server); +@@ -1842,6 +1843,9 @@ NTSTATUS WINAPI NtClose( HANDLE handle ) + * retrieve it again */ + fd = remove_fd_from_cache( handle ); + ++ if (do_fsync()) ++ fsync_close( handle ); ++ + if (do_esync()) + esync_close( handle ); + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0064-ntdll-Implement-waiting-on-fsync-objects.patch b/0007-proton-esync-fsync/0064-ntdll-Implement-waiting-on-fsync-objects.patch new file mode 100644 index 0000000..f9e71cb --- /dev/null +++ b/0007-proton-esync-fsync/0064-ntdll-Implement-waiting-on-fsync-objects.patch @@ -0,0 +1,196 @@ +From 9122ffe93b3bff7b3592db594d3ac148f793c8a0 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 1 Sep 2018 16:25:59 -0500 +Subject: [PATCH 0490/2346] ntdll: Implement waiting on fsync objects. + +--- + dlls/ntdll/unix/fsync.c | 145 ++++++++++++++++++++++++++++++++++++++++ + dlls/ntdll/unix/fsync.h | 3 + + dlls/ntdll/unix/sync.c | 7 ++ + 3 files changed, 155 insertions(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 2f199286950..504806ae10a 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -331,3 +331,148 @@ NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) + + return STATUS_SUCCESS; + } ++ ++static LONGLONG update_timeout( ULONGLONG end ) ++{ ++ LARGE_INTEGER now; ++ LONGLONG timeleft; ++ ++ NtQuerySystemTime( &now ); ++ timeleft = end - now.QuadPart; ++ if (timeleft < 0) timeleft = 0; ++ return timeleft; ++} ++ ++NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, ++ BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) ++{ ++ struct futex_wait_block futexes[MAXIMUM_WAIT_OBJECTS]; ++ struct fsync *objs[MAXIMUM_WAIT_OBJECTS]; ++ int has_fsync = 0, has_server = 0; ++ int dummy_futex = 0; ++ LONGLONG timeleft; ++ LARGE_INTEGER now; ++ ULONGLONG end; ++ int i, ret; ++ ++ NtQuerySystemTime( &now ); ++ if (timeout) ++ { ++ if (timeout->QuadPart == TIMEOUT_INFINITE) ++ timeout = NULL; ++ else if (timeout->QuadPart > 0) ++ end = timeout->QuadPart; ++ else ++ end = now.QuadPart - timeout->QuadPart; ++ } ++ ++ for (i = 0; i < count; i++) ++ { ++ if ((objs[i] = get_cached_object( handles[i] ))) ++ has_fsync = 1; ++ else ++ has_server = 1; ++ } ++ ++ if (has_fsync && has_server) ++ FIXME("Can't wait on fsync and server objects at the same time!\n"); ++ else if (has_server) ++ return STATUS_NOT_IMPLEMENTED; ++ ++ if (TRACE_ON(fsync)) ++ { ++ TRACE("Waiting for %s of %d handles:", wait_any ? "any" : "all", (int)count); ++ for (i = 0; i < count; i++) ++ TRACE(" %p", handles[i]); ++ ++ if (!timeout) ++ TRACE(", timeout = INFINITE.\n"); ++ else ++ { ++ timeleft = update_timeout( end ); ++ TRACE(", timeout = %ld.%07ld sec.\n", ++ (long) (timeleft / TICKSPERSEC), (long) (timeleft % TICKSPERSEC)); ++ } ++ } ++ ++ if (wait_any || count == 1) ++ { ++ while (1) ++ { ++ /* Try to grab anything. */ ++ ++ for (i = 0; i < count; i++) ++ { ++ struct fsync *obj = objs[i]; ++ ++ if (obj) ++ { ++ switch (obj->type) ++ { ++ case FSYNC_SEMAPHORE: ++ { ++ struct semaphore *semaphore = obj->shm; ++ int current; ++ ++ do ++ { ++ if (!(current = semaphore->count)) break; ++ } while (__sync_val_compare_and_swap( &semaphore->count, current, current - 1 ) != current); ++ ++ if (current) ++ { ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ return i; ++ } ++ ++ futexes[i].addr = &semaphore->count; ++ futexes[i].val = current; ++ break; ++ } ++ default: ++ assert(0); ++ } ++ } ++ else ++ { ++ /* Avoid breaking things entirely. */ ++ futexes[i].addr = &dummy_futex; ++ futexes[i].val = dummy_futex; ++ } ++ ++#if __SIZEOF_POINTER__ == 4 ++ futexes[i].pad = 0; ++#endif ++ } ++ ++ /* Looks like everything is contended, so wait. */ ++ ++ if (timeout) ++ { ++ LONGLONG timeleft = update_timeout( end ); ++ struct timespec tmo_p; ++ tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; ++ tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; ++ ++ ret = futex_wait_multiple( futexes, count, &tmo_p ); ++ } ++ else ++ ret = futex_wait_multiple( futexes, count, NULL ); ++ ++ /* FUTEX_WAIT_MULTIPLE can succeed or return -EINTR, -EAGAIN, ++ * -EFAULT/-EACCES, -ETIMEDOUT. In the first three cases we need to ++ * try again, bad address is already handled by the fact that we ++ * tried to read from it, so only break out on a timeout. */ ++ if (ret == -1 && errno == ETIMEDOUT) ++ { ++ TRACE("Wait timed out.\n"); ++ return STATUS_TIMEOUT; ++ } ++ } /* while (1) */ ++ } ++ else ++ { ++ FIXME("Wait-all not implemented.\n"); ++ return STATUS_NOT_IMPLEMENTED; ++ } ++} +diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h +index ed10eeb2d7b..4a5c00ca0a7 100644 +--- a/dlls/ntdll/unix/fsync.h ++++ b/dlls/ntdll/unix/fsync.h +@@ -25,3 +25,6 @@ extern NTSTATUS fsync_close( HANDLE handle ); + extern NTSTATUS fsync_create_semaphore(HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max); + extern NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ); ++ ++extern NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, ++ BOOLEAN alertable, const LARGE_INTEGER *timeout ); +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 075c93b6bad..d9ef3cb6bde 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -1528,6 +1528,13 @@ NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles, BO + + if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1; + ++ if (do_fsync()) ++ { ++ NTSTATUS ret = fsync_wait_objects( count, handles, wait_any, alertable, timeout ); ++ if (ret != STATUS_NOT_IMPLEMENTED) ++ return ret; ++ } ++ + if (do_esync()) + { + NTSTATUS ret = esync_wait_objects( count, handles, wait_any, alertable, timeout ); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0065-ntdll-Create-fsync-objects-for-events.patch b/0007-proton-esync-fsync/0065-ntdll-Create-fsync-objects-for-events.patch new file mode 100644 index 0000000..8d5103e --- /dev/null +++ b/0007-proton-esync-fsync/0065-ntdll-Create-fsync-objects-for-events.patch @@ -0,0 +1,86 @@ +From 6bea0e083d3e36b4aab3d09d99787f2ab2de3b6a Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 1 Sep 2018 16:31:54 -0500 +Subject: [PATCH 0491/2346] ntdll: Create fsync objects for events. + +--- + dlls/ntdll/unix/fsync.c | 20 ++++++++++++++++++++ + dlls/ntdll/unix/fsync.h | 2 ++ + dlls/ntdll/unix/sync.c | 3 +++ + 3 files changed, 25 insertions(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 504806ae10a..2a7dee5f661 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -97,6 +97,8 @@ int do_fsync(void) + enum fsync_type + { + FSYNC_SEMAPHORE = 1, ++ FSYNC_AUTO_EVENT, ++ FSYNC_MANUAL_EVENT, + }; + + struct fsync +@@ -112,6 +114,12 @@ struct semaphore + }; + C_ASSERT(sizeof(struct semaphore) == 8); + ++struct event ++{ ++ int signaled; ++ int unused; ++}; ++C_ASSERT(sizeof(struct event) == 8); + + static char shm_name[29]; + static int shm_fd; +@@ -332,6 +340,18 @@ NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) + return STATUS_SUCCESS; + } + ++NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr, EVENT_TYPE event_type, BOOLEAN initial ) ++{ ++ enum fsync_type type = (event_type == SynchronizationEvent ? FSYNC_AUTO_EVENT : FSYNC_MANUAL_EVENT); ++ ++ TRACE("name %s, %s-reset, initial %d.\n", ++ attr ? debugstr_us(attr->ObjectName) : "", ++ event_type == NotificationEvent ? "manual" : "auto", initial); ++ ++ return create_fsync( type, handle, access, attr, initial, 0xdeadbeef ); ++} ++ + static LONGLONG update_timeout( ULONGLONG end ) + { + LARGE_INTEGER now; +diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h +index 4a5c00ca0a7..cc93044f38f 100644 +--- a/dlls/ntdll/unix/fsync.h ++++ b/dlls/ntdll/unix/fsync.h +@@ -25,6 +25,8 @@ extern NTSTATUS fsync_close( HANDLE handle ); + extern NTSTATUS fsync_create_semaphore(HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max); + extern NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ); ++extern NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ); + + extern NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, + BOOLEAN alertable, const LARGE_INTEGER *timeout ); +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index d9ef3cb6bde..fe11bc38233 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -402,6 +402,9 @@ NTSTATUS WINAPI NtCreateEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_ + *handle = 0; + if (type != NotificationEvent && type != SynchronizationEvent) return STATUS_INVALID_PARAMETER; + ++ if (do_fsync()) ++ return fsync_create_event( handle, access, attr, type, state ); ++ + if (do_esync()) + return esync_create_event( handle, access, attr, type, state ); + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0066-ntdll-Implement-NtSetEvent.patch b/0007-proton-esync-fsync/0066-ntdll-Implement-NtSetEvent.patch new file mode 100644 index 0000000..f6b1470 --- /dev/null +++ b/0007-proton-esync-fsync/0066-ntdll-Implement-NtSetEvent.patch @@ -0,0 +1,78 @@ +From c51c998b497f66a708cd44c964e726a1e13c657b Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 1 Sep 2018 16:36:16 -0500 +Subject: [PATCH 0492/2346] ntdll: Implement NtSetEvent(). + +--- + dlls/ntdll/unix/fsync.c | 20 ++++++++++++++++++++ + dlls/ntdll/unix/fsync.h | 1 + + dlls/ntdll/unix/sync.c | 3 +++ + 3 files changed, 24 insertions(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 2a7dee5f661..a8c364162cc 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -27,6 +27,7 @@ + #include + #include + #include ++#include + #include + #include + #include +@@ -352,6 +353,25 @@ NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, + return create_fsync( type, handle, access, attr, initial, 0xdeadbeef ); + } + ++NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) ++{ ++ struct event *event; ++ struct fsync *obj; ++ LONG current; ++ ++ TRACE("%p.\n", handle); ++ ++ if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; ++ event = obj->shm; ++ ++ if (!(current = __atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST ))) ++ futex_wake( &event->signaled, obj->type == FSYNC_AUTO_EVENT ? 1 : INT_MAX ); ++ ++ if (prev) *prev = current; ++ ++ return STATUS_SUCCESS; ++} ++ + static LONGLONG update_timeout( ULONGLONG end ) + { + LARGE_INTEGER now; +diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h +index cc93044f38f..2ba03261c17 100644 +--- a/dlls/ntdll/unix/fsync.h ++++ b/dlls/ntdll/unix/fsync.h +@@ -27,6 +27,7 @@ extern NTSTATUS fsync_create_semaphore(HANDLE *handle, ACCESS_MASK access, + extern NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ); + extern NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ); ++extern NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ); + + extern NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, + BOOLEAN alertable, const LARGE_INTEGER *timeout ); +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index fe11bc38233..854799c30ec 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -462,6 +462,9 @@ NTSTATUS WINAPI NtSetEvent( HANDLE handle, LONG *prev_state ) + /* This comment is a dummy to make sure this patch applies in the right place. */ + unsigned int ret; + ++ if (do_fsync()) ++ return fsync_set_event( handle, prev_state ); ++ + if (do_esync()) + return esync_set_event( handle ); + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0067-ntdll-Implement-NtResetEvent.patch b/0007-proton-esync-fsync/0067-ntdll-Implement-NtResetEvent.patch new file mode 100644 index 0000000..6e177a8 --- /dev/null +++ b/0007-proton-esync-fsync/0067-ntdll-Implement-NtResetEvent.patch @@ -0,0 +1,69 @@ +From bcba4f81e31d4118608bda66cbbde7a6f1959679 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 1 Sep 2018 16:39:38 -0500 +Subject: [PATCH 0493/2346] ntdll: Implement NtResetEvent(). + +--- + dlls/ntdll/unix/fsync.c | 18 ++++++++++++++++++ + dlls/ntdll/unix/fsync.h | 1 + + dlls/ntdll/unix/sync.c | 3 +++ + 3 files changed, 22 insertions(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index a8c364162cc..c7b4ee1a298 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -372,6 +372,24 @@ NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) + return STATUS_SUCCESS; + } + ++NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) ++{ ++ struct event *event; ++ struct fsync *obj; ++ LONG current; ++ ++ TRACE("%p.\n", handle); ++ ++ if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; ++ event = obj->shm; ++ ++ current = __atomic_exchange_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); ++ ++ if (prev) *prev = current; ++ ++ return STATUS_SUCCESS; ++} ++ + static LONGLONG update_timeout( ULONGLONG end ) + { + LARGE_INTEGER now; +diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h +index 2ba03261c17..56afeb1f9e8 100644 +--- a/dlls/ntdll/unix/fsync.h ++++ b/dlls/ntdll/unix/fsync.h +@@ -28,6 +28,7 @@ extern NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev + extern NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ); + extern NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ); ++extern NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ); + + extern NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, + BOOLEAN alertable, const LARGE_INTEGER *timeout ); +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 854799c30ec..ef39b1b8b42 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -488,6 +488,9 @@ NTSTATUS WINAPI NtResetEvent( HANDLE handle, LONG *prev_state ) + /* This comment is a dummy to make sure this patch applies in the right place. */ + unsigned int ret; + ++ if (do_fsync()) ++ return fsync_reset_event( handle, prev_state ); ++ + if (do_esync()) + return esync_reset_event( handle ); + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0068-ntdll-Implement-waiting-on-events.patch b/0007-proton-esync-fsync/0068-ntdll-Implement-waiting-on-events.patch new file mode 100644 index 0000000..3bbfc23 --- /dev/null +++ b/0007-proton-esync-fsync/0068-ntdll-Implement-waiting-on-events.patch @@ -0,0 +1,51 @@ +From c7546a222f0e7ed2e81fe1f43656d23067d438fe Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 1 Sep 2018 16:45:43 -0500 +Subject: [PATCH 0494/2346] ntdll: Implement waiting on events. + +--- + dlls/ntdll/unix/fsync.c | 28 ++++++++++++++++++++++++++++ + 1 file changed, 28 insertions(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index c7b4ee1a298..e7a495be365 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -487,6 +487,34 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, + futexes[i].val = current; + break; + } ++ case FSYNC_AUTO_EVENT: ++ { ++ struct event *event = obj->shm; ++ ++ if (__sync_val_compare_and_swap( &event->signaled, 1, 0 )) ++ { ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ return i; ++ } ++ ++ futexes[i].addr = &event->signaled; ++ futexes[i].val = 0; ++ break; ++ } ++ case FSYNC_MANUAL_EVENT: ++ { ++ struct event *event = obj->shm; ++ ++ if (__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) ++ { ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ return i; ++ } ++ ++ futexes[i].addr = &event->signaled; ++ futexes[i].val = 0; ++ break; ++ } + default: + assert(0); + } +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0069-server-Add-an-object-operation-to-grab-the-fsync-shm.patch b/0007-proton-esync-fsync/0069-server-Add-an-object-operation-to-grab-the-fsync-shm.patch new file mode 100644 index 0000000..e7a45e8 --- /dev/null +++ b/0007-proton-esync-fsync/0069-server-Add-an-object-operation-to-grab-the-fsync-shm.patch @@ -0,0 +1,732 @@ +From ae25db4d519d156d24c5e78fb20ef85070b08a50 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 1 Sep 2018 16:52:01 -0500 +Subject: [PATCH 0495/2346] server: Add an object operation to grab the fsync + shm index. + +--- + server/async.c | 2 ++ + server/atom.c | 1 + + server/change.c | 1 + + server/clipboard.c | 1 + + server/completion.c | 1 + + server/console.c | 7 +++++++ + server/debugger.c | 2 ++ + server/device.c | 4 ++++ + server/directory.c | 2 ++ + server/esync.c | 1 + + server/event.c | 2 ++ + server/fd.c | 4 ++++ + server/file.c | 1 + + server/fsync.c | 1 + + server/handle.c | 1 + + server/hook.c | 1 + + server/mailslot.c | 4 ++++ + server/mapping.c | 3 +++ + server/mutex.c | 1 + + server/named_pipe.c | 5 +++++ + server/object.h | 2 ++ + server/process.c | 3 +++ + server/queue.c | 2 ++ + server/registry.c | 1 + + server/request.c | 1 + + server/semaphore.c | 1 + + server/serial.c | 1 + + server/signal.c | 1 + + server/sock.c | 3 +++ + server/symlink.c | 1 + + server/thread.c | 3 +++ + server/timer.c | 1 + + server/token.c | 1 + + server/window.c | 1 + + server/winstation.c | 2 ++ + 35 files changed, 69 insertions(+) + +diff --git a/server/async.c b/server/async.c +index 337bba8631b..91f0d87f9df 100644 +--- a/server/async.c ++++ b/server/async.c +@@ -78,6 +78,7 @@ static const struct object_ops async_ops = + remove_queue, /* remove_queue */ + async_signaled, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + async_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -678,6 +679,7 @@ static const struct object_ops iosb_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/atom.c b/server/atom.c +index d9824de8eac..6b95a546597 100644 +--- a/server/atom.c ++++ b/server/atom.c +@@ -80,6 +80,7 @@ static const struct object_ops atom_table_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/change.c b/server/change.c +index 6bd6920fdb5..8e19fc4bc2b 100644 +--- a/server/change.c ++++ b/server/change.c +@@ -113,6 +113,7 @@ static const struct object_ops dir_ops = + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ + default_fd_get_esync_fd, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + dir_get_fd, /* get_fd */ +diff --git a/server/clipboard.c b/server/clipboard.c +index 8b265f2dcea..f24924eafa5 100644 +--- a/server/clipboard.c ++++ b/server/clipboard.c +@@ -77,6 +77,7 @@ static const struct object_ops clipboard_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/completion.c b/server/completion.c +index 3d4be86a212..33266c596da 100644 +--- a/server/completion.c ++++ b/server/completion.c +@@ -76,6 +76,7 @@ static const struct object_ops completion_ops = + remove_queue, /* remove_queue */ + completion_signaled, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/console.c b/server/console.c +index dbd4a97459c..43248d359ca 100644 +--- a/server/console.c ++++ b/server/console.c +@@ -83,6 +83,7 @@ static const struct object_ops console_ops = + remove_queue, /* remove_queue */ + console_signaled, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + console_get_fd, /* get_fd */ +@@ -163,6 +164,7 @@ static const struct object_ops console_server_ops = + remove_queue, /* remove_queue */ + console_server_signaled, /* signaled */ + console_server_get_esync_fd, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + console_server_get_fd, /* get_fd */ +@@ -233,6 +235,7 @@ static const struct object_ops screen_buffer_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + screen_buffer_get_fd, /* get_fd */ +@@ -283,6 +286,7 @@ static const struct object_ops console_device_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 */ +@@ -321,6 +325,7 @@ static const struct object_ops console_input_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + console_input_get_fd, /* get_fd */ +@@ -379,6 +384,7 @@ static const struct object_ops console_output_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + console_output_get_fd, /* get_fd */ +@@ -438,6 +444,7 @@ static const struct object_ops console_connection_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + console_connection_get_fd, /* get_fd */ +diff --git a/server/debugger.c b/server/debugger.c +index d85a2000684..b0cd35604d2 100644 +--- a/server/debugger.c ++++ b/server/debugger.c +@@ -87,6 +87,7 @@ static const struct object_ops debug_event_ops = + remove_queue, /* remove_queue */ + debug_event_signaled, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -116,6 +117,7 @@ static const struct object_ops debug_obj_ops = + remove_queue, /* remove_queue */ + debug_obj_signaled, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/device.c b/server/device.c +index c45d0102a56..8613cee58af 100644 +--- a/server/device.c ++++ b/server/device.c +@@ -69,6 +69,7 @@ static const struct object_ops irp_call_ops = + NULL, /* signaled */ + NULL, /* get_esync_fd */ + NULL, /* satisfied */ ++ NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ + default_map_access, /* map_access */ +@@ -111,6 +112,7 @@ static const struct object_ops device_manager_ops = + remove_queue, /* remove_queue */ + device_manager_signaled, /* signaled */ + device_manager_get_esync_fd, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -169,6 +171,7 @@ static const struct object_ops device_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 */ +@@ -222,6 +225,7 @@ static const struct object_ops device_file_ops = + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + device_file_get_fd, /* get_fd */ +diff --git a/server/directory.c b/server/directory.c +index dc3f0cf3cf8..878941cddbf 100644 +--- a/server/directory.c ++++ b/server/directory.c +@@ -71,6 +71,7 @@ static const struct object_ops object_type_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -122,6 +123,7 @@ static const struct object_ops directory_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/esync.c b/server/esync.c +index fc8120f9449..064bdd61b25 100644 +--- a/server/esync.c ++++ b/server/esync.c +@@ -129,6 +129,7 @@ const struct object_ops esync_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + esync_get_esync_fd, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/event.c b/server/event.c +index f4ca3e48c6f..f5a25c02293 100644 +--- a/server/event.c ++++ b/server/event.c +@@ -77,6 +77,7 @@ static const struct object_ops event_ops = + remove_queue, /* remove_queue */ + event_signaled, /* signaled */ + event_get_esync_fd, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + event_satisfied, /* satisfied */ + event_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -125,6 +126,7 @@ static const struct object_ops keyed_event_ops = + remove_queue, /* remove_queue */ + keyed_event_signaled, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/fd.c b/server/fd.c +index 4149c9d4637..acd3789193a 100644 +--- a/server/fd.c ++++ b/server/fd.c +@@ -172,6 +172,7 @@ static const struct object_ops fd_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -214,6 +215,7 @@ static const struct object_ops device_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -255,6 +257,7 @@ static const struct object_ops inode_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -298,6 +301,7 @@ static const struct object_ops file_lock_ops = + remove_queue, /* remove_queue */ + file_lock_signaled, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/file.c b/server/file.c +index 26c62809d33..5be9578ce48 100644 +--- a/server/file.c ++++ b/server/file.c +@@ -95,6 +95,7 @@ static const struct object_ops file_ops = + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + file_get_fd, /* get_fd */ +diff --git a/server/fsync.c b/server/fsync.c +index 5f36e988803..55a8e709dbf 100644 +--- a/server/fsync.c ++++ b/server/fsync.c +@@ -140,6 +140,7 @@ static const struct object_ops fsync_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/handle.c b/server/handle.c +index d41c7e86454..48b5d8101bb 100644 +--- a/server/handle.c ++++ b/server/handle.c +@@ -127,6 +127,7 @@ static const struct object_ops handle_table_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/hook.c b/server/hook.c +index 95a588c843b..3a89a883c3c 100644 +--- a/server/hook.c ++++ b/server/hook.c +@@ -81,6 +81,7 @@ static const struct object_ops hook_table_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/mailslot.c b/server/mailslot.c +index 4cf9b73f784..41fb020aaf0 100644 +--- a/server/mailslot.c ++++ b/server/mailslot.c +@@ -75,6 +75,7 @@ static const struct object_ops mailslot_ops = + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + mailslot_get_fd, /* get_fd */ +@@ -135,6 +136,7 @@ static const struct object_ops mail_writer_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + mail_writer_get_fd, /* get_fd */ +@@ -199,6 +201,7 @@ static const struct object_ops mailslot_device_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 */ +@@ -230,6 +233,7 @@ static const struct object_ops mailslot_device_file_ops = + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + mailslot_device_file_get_fd, /* get_fd */ +diff --git a/server/mapping.c b/server/mapping.c +index bc971fa91c4..75f2ce4fc2b 100644 +--- a/server/mapping.c ++++ b/server/mapping.c +@@ -73,6 +73,7 @@ static const struct object_ops ranges_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -110,6 +111,7 @@ static const struct object_ops shared_map_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -185,6 +187,7 @@ static const struct object_ops mapping_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + mapping_get_fd, /* get_fd */ +diff --git a/server/mutex.c b/server/mutex.c +index 4785a830e92..2503d12057f 100644 +--- a/server/mutex.c ++++ b/server/mutex.c +@@ -74,6 +74,7 @@ static const struct object_ops mutex_ops = + remove_queue, /* remove_queue */ + mutex_signaled, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + mutex_satisfied, /* satisfied */ + mutex_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/named_pipe.c b/server/named_pipe.c +index a90ec606226..1a168f0b395 100644 +--- a/server/named_pipe.c ++++ b/server/named_pipe.c +@@ -120,6 +120,7 @@ static const struct object_ops named_pipe_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -169,6 +170,7 @@ static const struct object_ops pipe_server_ops = + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ + default_fd_get_esync_fd, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + pipe_end_get_fd, /* get_fd */ +@@ -214,6 +216,7 @@ static const struct object_ops pipe_client_ops = + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ + default_fd_get_esync_fd, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + pipe_end_get_fd, /* get_fd */ +@@ -262,6 +265,7 @@ static const struct object_ops named_pipe_device_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 */ +@@ -294,6 +298,7 @@ static const struct object_ops named_pipe_device_file_ops = + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + named_pipe_device_file_get_fd, /* get_fd */ +diff --git a/server/object.h b/server/object.h +index 51ee819415a..632b20a548c 100644 +--- a/server/object.h ++++ b/server/object.h +@@ -80,6 +80,8 @@ struct object_ops + int (*signaled)(struct object *,struct wait_queue_entry *); + /* return the esync fd for this object */ + int (*get_esync_fd)(struct object *, enum esync_type *type); ++ /* return the fsync shm idx for this object */ ++ unsigned int (*get_fsync_idx)(struct object *); + /* wait satisfied */ + void (*satisfied)(struct object *,struct wait_queue_entry *); + /* signal an object */ +diff --git a/server/process.c b/server/process.c +index f5b919cba00..1db0d52cb34 100644 +--- a/server/process.c ++++ b/server/process.c +@@ -108,6 +108,7 @@ static const struct object_ops process_ops = + remove_queue, /* remove_queue */ + process_signaled, /* signaled */ + process_get_esync_fd, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -160,6 +161,7 @@ static const struct object_ops startup_info_ops = + remove_queue, /* remove_queue */ + startup_info_signaled, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -222,6 +224,7 @@ static const struct object_ops job_ops = + remove_queue, /* remove_queue */ + job_signaled, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/queue.c b/server/queue.c +index ce818042475..ddb4122bb9d 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -171,6 +171,7 @@ static const struct object_ops msg_queue_ops = + msg_queue_remove_queue, /* remove_queue */ + msg_queue_signaled, /* signaled */ + msg_queue_get_esync_fd, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + msg_queue_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -209,6 +210,7 @@ static const struct object_ops thread_input_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/registry.c b/server/registry.c +index c071f42532b..5bd196be10d 100644 +--- a/server/registry.c ++++ b/server/registry.c +@@ -181,6 +181,7 @@ static const struct object_ops key_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/request.c b/server/request.c +index ca83fdbd2af..343e1a92e0e 100644 +--- a/server/request.c ++++ b/server/request.c +@@ -91,6 +91,7 @@ static const struct object_ops master_socket_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/semaphore.c b/server/semaphore.c +index e3889f24601..d354892c224 100644 +--- a/server/semaphore.c ++++ b/server/semaphore.c +@@ -71,6 +71,7 @@ static const struct object_ops semaphore_ops = + remove_queue, /* remove_queue */ + semaphore_signaled, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + semaphore_satisfied, /* satisfied */ + semaphore_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/serial.c b/server/serial.c +index 11e204e4419..1915d00a977 100644 +--- a/server/serial.c ++++ b/server/serial.c +@@ -86,6 +86,7 @@ static const struct object_ops serial_ops = + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + serial_get_fd, /* get_fd */ +diff --git a/server/signal.c b/server/signal.c +index 55cd6aa037e..802b7f936b9 100644 +--- a/server/signal.c ++++ b/server/signal.c +@@ -63,6 +63,7 @@ static const struct object_ops handler_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/sock.c b/server/sock.c +index 177e7e6dded..ed79d961c38 100644 +--- a/server/sock.c ++++ b/server/sock.c +@@ -454,6 +454,7 @@ static const struct object_ops sock_ops = + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + sock_get_fd, /* get_fd */ +@@ -3556,6 +3557,7 @@ static const struct object_ops ifchange_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + ifchange_get_fd, /* get_fd */ +@@ -3778,6 +3780,7 @@ static const struct object_ops socket_device_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/symlink.c b/server/symlink.c +index c7f34412317..47098fe5823 100644 +--- a/server/symlink.c ++++ b/server/symlink.c +@@ -72,6 +72,7 @@ static const struct object_ops symlink_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/thread.c b/server/thread.c +index e906e0c07c9..ce90d8cfe74 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -102,6 +102,7 @@ static const struct object_ops thread_apc_ops = + remove_queue, /* remove_queue */ + thread_apc_signaled, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -145,6 +146,7 @@ static const struct object_ops context_ops = + remove_queue, /* remove_queue */ + context_signaled, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -196,6 +198,7 @@ static const struct object_ops thread_ops = + remove_queue, /* remove_queue */ + thread_signaled, /* signaled */ + thread_get_esync_fd, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/timer.c b/server/timer.c +index 36645a2a8d2..9ec9604aa0e 100644 +--- a/server/timer.c ++++ b/server/timer.c +@@ -80,6 +80,7 @@ static const struct object_ops timer_ops = + remove_queue, /* remove_queue */ + timer_signaled, /* signaled */ + timer_get_esync_fd, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + timer_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/token.c b/server/token.c +index 8b4d2f0c1b1..0529d967b8a 100644 +--- a/server/token.c ++++ b/server/token.c +@@ -144,6 +144,7 @@ static const struct object_ops token_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/window.c b/server/window.c +index f6b9a25baa4..184d4e2e212 100644 +--- a/server/window.c ++++ b/server/window.c +@@ -108,6 +108,7 @@ static const struct object_ops window_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +diff --git a/server/winstation.c b/server/winstation.c +index ae1123c1d38..be33253d675 100644 +--- a/server/winstation.c ++++ b/server/winstation.c +@@ -77,6 +77,7 @@ static const struct object_ops winstation_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -118,6 +119,7 @@ static const struct object_ops desktop_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0070-server-Add-a-request-to-get-the-shm-index-associated.patch b/0007-proton-esync-fsync/0070-server-Add-a-request-to-get-the-shm-index-associated.patch new file mode 100644 index 0000000..be4e9cd --- /dev/null +++ b/0007-proton-esync-fsync/0070-server-Add-a-request-to-get-the-shm-index-associated.patch @@ -0,0 +1,114 @@ +From 8bd11328793276f74980fd03003fc1300c86c613 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 1 Sep 2018 16:57:08 -0500 +Subject: [PATCH 0496/2346] server: Add a request to get the shm index + associated with a waitable handle. + +--- + dlls/ntdll/unix/fsync.c | 7 ------- + server/fsync.c | 28 ++++++++++++++++++++++++++++ + server/object.h | 2 +- + server/protocol.def | 16 ++++++++++++++++ + 4 files changed, 45 insertions(+), 8 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index e7a495be365..2f680212fc0 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -95,13 +95,6 @@ int do_fsync(void) + #endif + } + +-enum fsync_type +-{ +- FSYNC_SEMAPHORE = 1, +- FSYNC_AUTO_EVENT, +- FSYNC_MANUAL_EVENT, +-}; +- + struct fsync + { + enum fsync_type type; +diff --git a/server/fsync.c b/server/fsync.c +index 55a8e709dbf..21f41f54ca1 100644 +--- a/server/fsync.c ++++ b/server/fsync.c +@@ -285,3 +285,31 @@ DECL_HANDLER(create_fsync) + + if (root) release_object( root ); + } ++ ++ ++/* Retrieve the index of a shm section which will be signaled by the server. */ ++DECL_HANDLER(get_fsync_idx) ++{ ++ struct object *obj; ++ enum fsync_type type; ++ ++ if (!(obj = get_handle_obj( current->process, req->handle, SYNCHRONIZE, NULL ))) ++ return; ++ ++ if (obj->ops->get_fsync_idx) ++ { ++ reply->shm_idx = obj->ops->get_fsync_idx( obj, &type ); ++ reply->type = type; ++ } ++ else ++ { ++ if (debug_level) ++ { ++ fprintf( stderr, "%04x: fsync: can't wait on object: ", current->id ); ++ obj->ops->dump( obj, 0 ); ++ } ++ set_error( STATUS_NOT_IMPLEMENTED ); ++ } ++ ++ release_object( obj ); ++} +diff --git a/server/object.h b/server/object.h +index 632b20a548c..c482b8ceeef 100644 +--- a/server/object.h ++++ b/server/object.h +@@ -81,7 +81,7 @@ struct object_ops + /* return the esync fd for this object */ + int (*get_esync_fd)(struct object *, enum esync_type *type); + /* return the fsync shm idx for this object */ +- unsigned int (*get_fsync_idx)(struct object *); ++ unsigned int (*get_fsync_idx)(struct object *, enum fsync_type *type); + /* wait satisfied */ + void (*satisfied)(struct object *,struct wait_queue_entry *); + /* signal an object */ +diff --git a/server/protocol.def b/server/protocol.def +index 2243d97dcfe..d32ae3a27a3 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3992,6 +3992,14 @@ enum esync_type + @REQ(get_esync_apc_fd) + @END + ++enum fsync_type ++{ ++ FSYNC_SEMAPHORE = 1, ++ FSYNC_AUTO_EVENT, ++ FSYNC_MANUAL_EVENT, ++ FSYNC_MANUAL_SERVER, ++}; ++ + /* Create a new futex-based synchronization object */ + @REQ(create_fsync) + unsigned int access; /* wanted access rights */ +@@ -4002,3 +4010,11 @@ enum esync_type + obj_handle_t handle; /* handle to the object */ + unsigned int shm_idx; /* this object's index into the shm section */ + @END ++ ++/* Retrieve the shm index for an object. */ ++@REQ(get_fsync_idx) ++ obj_handle_t handle; /* handle to the object */ ++@REPLY ++ int type; ++ unsigned int shm_idx; ++@END +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0071-server-Create-futex-sections-for-process-objects.patch b/0007-proton-esync-fsync/0071-server-Create-futex-sections-for-process-objects.patch new file mode 100644 index 0000000..1a3c2e3 --- /dev/null +++ b/0007-proton-esync-fsync/0071-server-Create-futex-sections-for-process-objects.patch @@ -0,0 +1,171 @@ +From 3958bc7081ba094c03daa995067f20c7d4b1557f Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 1 Sep 2018 17:20:36 -0500 +Subject: [PATCH 0497/2346] server: Create futex sections for process objects. + +--- + server/fsync.c | 49 +++++++++++++++++++++++++++++------------------- + server/fsync.h | 1 + + server/process.c | 15 ++++++++++++++- + server/process.h | 1 + + 4 files changed, 46 insertions(+), 20 deletions(-) + +diff --git a/server/fsync.c b/server/fsync.c +index 21f41f54ca1..ae4dc7d7318 100644 +--- a/server/fsync.c ++++ b/server/fsync.c +@@ -207,6 +207,35 @@ static void *get_shm( unsigned int idx ) + /* FIXME: This is rather inefficient... */ + static unsigned int shm_idx_counter = 1; + ++unsigned int fsync_alloc_shm( int low, int high ) ++{ ++#ifdef __linux__ ++ int shm_idx = shm_idx_counter++; ++ int *shm; ++ ++ while (shm_idx * 8 >= shm_size) ++ { ++ /* Better expand the shm section. */ ++ shm_size += pagesize; ++ if (ftruncate( shm_fd, shm_size ) == -1) ++ { ++ fprintf( stderr, "fsync: couldn't expand %s to size %jd: ", ++ shm_name, shm_size ); ++ perror( "ftruncate" ); ++ } ++ } ++ ++ shm = get_shm( shm_idx ); ++ assert(shm); ++ shm[0] = low; ++ shm[1] = high; ++ ++ return shm_idx; ++#else ++ return 0; ++#endif ++} ++ + struct fsync *create_fsync( struct object *root, const struct unicode_str *name, + unsigned int attr, int low, int high, + const struct security_descriptor *sd ) +@@ -218,32 +247,14 @@ struct fsync *create_fsync( struct object *root, const struct unicode_str *name, + { + if (get_error() != STATUS_OBJECT_NAME_EXISTS) + { +- int *shm; +- + /* initialize it if it didn't already exist */ + +- fsync->shm_idx = shm_idx_counter++; +- while (fsync->shm_idx * 8 >= shm_size) +- { +- /* Better expand the shm section. */ +- shm_size += pagesize; +- if (ftruncate( shm_fd, shm_size ) == -1) +- { +- fprintf( stderr, "fsync: couldn't expand %s to size %lld: ", +- shm_name, (long long)shm_size ); +- perror( "ftruncate" ); +- } +- } +- + /* Initialize the shared memory portion. We want to do this on the + * server side to avoid a potential though unlikely race whereby + * the same object is opened and used between the time it's created + * and the time its shared memory portion is initialized. */ + +- shm = get_shm( fsync->shm_idx ); +- assert(shm); +- shm[0] = low; +- shm[1] = high; ++ fsync->shm_idx = fsync_alloc_shm( low, high ); + } + } + +diff --git a/server/fsync.h b/server/fsync.h +index 0b7e46cdaf3..bbd104f3e16 100644 +--- a/server/fsync.h ++++ b/server/fsync.h +@@ -20,3 +20,4 @@ + + extern int do_fsync(void); + extern void fsync_init(void); ++extern unsigned int fsync_alloc_shm( int low, int high ); +diff --git a/server/process.c b/server/process.c +index 1db0d52cb34..38303e04193 100644 +--- a/server/process.c ++++ b/server/process.c +@@ -64,6 +64,7 @@ + #include "user.h" + #include "security.h" + #include "esync.h" ++#include "fsync.h" + + /* process object */ + +@@ -97,6 +98,7 @@ static void process_poll_event( struct fd *fd, int event ); + static struct list *process_get_kernel_obj_list( struct object *obj ); + static void process_destroy( struct object *obj ); + static int process_get_esync_fd( struct object *obj, enum esync_type *type ); ++static unsigned int process_get_fsync_idx( struct object *obj, enum fsync_type *type ); + static void terminate_process( struct process *process, struct thread *skip, int exit_code ); + + static const struct object_ops process_ops = +@@ -108,7 +110,7 @@ static const struct object_ops process_ops = + remove_queue, /* remove_queue */ + process_signaled, /* signaled */ + process_get_esync_fd, /* get_esync_fd */ +- NULL, /* get_fsync_idx */ ++ process_get_fsync_idx, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -692,6 +694,7 @@ struct process *create_process( int fd, struct process *parent, unsigned int fla + process->rawinput_kbd = NULL; + memset( &process->image_info, 0, sizeof(process->image_info) ); + process->esync_fd = -1; ++ process->fsync_idx = 0; + list_init( &process->rawinput_entry ); + list_init( &process->kernel_object ); + list_init( &process->thread_list ); +@@ -748,6 +751,9 @@ struct process *create_process( int fd, struct process *parent, unsigned int fla + if (!token_assign_label( process->token, &high_label_sid )) + goto error; + ++ if (do_fsync()) ++ process->fsync_idx = fsync_alloc_shm( 0, 0 ); ++ + if (do_esync()) + process->esync_fd = esync_create_fd( 0, 0 ); + +@@ -823,6 +829,13 @@ static int process_get_esync_fd( struct object *obj, enum esync_type *type ) + return process->esync_fd; + } + ++static unsigned int process_get_fsync_idx( struct object *obj, enum fsync_type *type ) ++{ ++ struct process *process = (struct process *)obj; ++ *type = FSYNC_MANUAL_SERVER; ++ return process->fsync_idx; ++} ++ + static unsigned int process_map_access( struct object *obj, unsigned int access ) + { + access = default_map_access( obj, access ); +diff --git a/server/process.h b/server/process.h +index a0a071d8f88..4b80b8863b8 100644 +--- a/server/process.h ++++ b/server/process.h +@@ -86,6 +86,7 @@ struct process + struct list kernel_object; /* list of kernel object pointers */ + pe_image_info_t image_info; /* main exe image info */ + int esync_fd; /* esync file descriptor (signaled on exit) */ ++ unsigned int fsync_idx; + }; + + /* process functions */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0072-ntdll-server-Implement-waiting-on-server-bound-objec.patch b/0007-proton-esync-fsync/0072-ntdll-server-Implement-waiting-on-server-bound-objec.patch new file mode 100644 index 0000000..da39e19 --- /dev/null +++ b/0007-proton-esync-fsync/0072-ntdll-server-Implement-waiting-on-server-bound-objec.patch @@ -0,0 +1,171 @@ +From 2bab7398c6e8c3576e11ade09602d80dc02db1cc Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 1 Sep 2018 17:30:47 -0500 +Subject: [PATCH 0498/2346] ntdll, server: Implement waiting on server-bound + objects. + +--- + dlls/ntdll/unix/fsync.c | 51 +++++++++++++++++++++++++++++++++++++++-- + server/fsync.c | 27 ++++++++++++++++++++++ + server/fsync.h | 2 ++ + server/thread.c | 4 ++++ + 4 files changed, 82 insertions(+), 2 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 2f680212fc0..ec8b3121ed1 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -205,6 +205,49 @@ static struct fsync *get_cached_object( HANDLE handle ) + return &fsync_list[entry][idx]; + } + ++/* Gets an object. This is either a proper fsync object (i.e. an event, ++ * semaphore, etc. created using create_fsync) or a generic synchronizable ++ * server-side object which the server will signal (e.g. a process, thread, ++ * message queue, etc.) */ ++static NTSTATUS get_object( HANDLE handle, struct fsync **obj ) ++{ ++ NTSTATUS ret = STATUS_SUCCESS; ++ unsigned int shm_idx = 0; ++ enum fsync_type type; ++ ++ if ((*obj = get_cached_object( handle ))) return STATUS_SUCCESS; ++ ++ if ((INT_PTR)handle < 0) ++ { ++ /* We can deal with pseudo-handles, but it's just easier this way */ ++ return STATUS_NOT_IMPLEMENTED; ++ } ++ ++ /* We need to try grabbing it from the server. */ ++ SERVER_START_REQ( get_fsync_idx ) ++ { ++ req->handle = wine_server_obj_handle( handle ); ++ if (!(ret = wine_server_call( req ))) ++ { ++ shm_idx = reply->shm_idx; ++ type = reply->type; ++ } ++ } ++ SERVER_END_REQ; ++ ++ if (ret) ++ { ++ WARN("Failed to retrieve shm index for handle %p, status %#x.\n", handle, (unsigned int)ret); ++ *obj = NULL; ++ return ret; ++ } ++ ++ TRACE("Got shm index %d for handle %p.\n", shm_idx, handle); ++ ++ *obj = add_to_list( handle, type, get_shm( shm_idx ) ); ++ return ret; ++} ++ + NTSTATUS fsync_close( HANDLE handle ) + { + UINT_PTR entry, idx = handle_to_index( handle, &entry ); +@@ -419,10 +462,13 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, + + for (i = 0; i < count; i++) + { +- if ((objs[i] = get_cached_object( handles[i] ))) ++ ret = get_object( handles[i], &objs[i] ); ++ if (ret == STATUS_SUCCESS) + has_fsync = 1; +- else ++ else if (ret == STATUS_NOT_IMPLEMENTED) + has_server = 1; ++ else ++ return ret; + } + + if (has_fsync && has_server) +@@ -495,6 +541,7 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, + break; + } + case FSYNC_MANUAL_EVENT: ++ case FSYNC_MANUAL_SERVER: + { + struct event *event = obj->shm; + +diff --git a/server/fsync.c b/server/fsync.c +index ae4dc7d7318..da30d94f1f7 100644 +--- a/server/fsync.c ++++ b/server/fsync.c +@@ -22,6 +22,7 @@ + + #include + #include ++#include + #include + #include + #include +@@ -265,6 +266,32 @@ struct fsync *create_fsync( struct object *root, const struct unicode_str *name, + #endif + } + ++static inline int futex_wake( int *addr, int val ) ++{ ++ return syscall( __NR_futex, addr, 1, val, NULL, 0, 0 ); ++} ++ ++/* shm layout for events or event-like objects. */ ++struct fsync_event ++{ ++ int signaled; ++ int unused; ++}; ++ ++void fsync_wake_up( struct object *obj ) ++{ ++ struct fsync_event *event; ++ enum fsync_type type; ++ ++ if (obj->ops->get_fsync_idx) ++ { ++ event = get_shm( obj->ops->get_fsync_idx( obj, &type ) ); ++ ++ if (!__atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST )) ++ futex_wake( &event->signaled, INT_MAX ); ++ } ++} ++ + DECL_HANDLER(create_fsync) + { + struct fsync *fsync; +diff --git a/server/fsync.h b/server/fsync.h +index bbd104f3e16..2ff98cb64cb 100644 +--- a/server/fsync.h ++++ b/server/fsync.h +@@ -21,3 +21,5 @@ + extern int do_fsync(void); + extern void fsync_init(void); + extern unsigned int fsync_alloc_shm( int low, int high ); ++extern void fsync_wake_up( struct object *obj ); ++extern void fsync_clear( struct object *obj ); +diff --git a/server/thread.c b/server/thread.c +index ce90d8cfe74..6c46fc492cf 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -55,6 +55,7 @@ + #include "security.h" + #include "unicode.h" + #include "esync.h" ++#include "fsync.h" + + + /* thread queues */ +@@ -1241,6 +1242,9 @@ void wake_up( struct object *obj, int max ) + struct list *ptr; + int ret; + ++ if (do_fsync()) ++ fsync_wake_up( obj ); ++ + if (do_esync()) + esync_wake_up( obj ); + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0073-server-Create-futexes-for-event-objects.patch b/0007-proton-esync-fsync/0073-server-Create-futexes-for-event-objects.patch new file mode 100644 index 0000000..c9861c8 --- /dev/null +++ b/0007-proton-esync-fsync/0073-server-Create-futexes-for-event-objects.patch @@ -0,0 +1,117 @@ +From c93fc0dc56069af4849c1785c1a9886a3ca3cc11 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 1 Sep 2018 17:37:55 -0500 +Subject: [PATCH 0499/2346] server: Create futexes for event objects. + +--- + server/event.c | 21 ++++++++++++++++++++- + server/fsync.c | 13 +++++++++++++ + 2 files changed, 33 insertions(+), 1 deletion(-) + +diff --git a/server/event.c b/server/event.c +index f5a25c02293..9acd7fa263c 100644 +--- a/server/event.c ++++ b/server/event.c +@@ -36,6 +36,7 @@ + #include "request.h" + #include "security.h" + #include "esync.h" ++#include "fsync.h" + + static const WCHAR event_name[] = {'E','v','e','n','t'}; + +@@ -58,12 +59,14 @@ struct event + int manual_reset; /* is it a manual reset event? */ + int signaled; /* event has been signaled */ + int esync_fd; /* esync file descriptor */ ++ unsigned int fsync_idx; + }; + + static void event_dump( struct object *obj, int verbose ); + static int event_signaled( struct object *obj, struct wait_queue_entry *entry ); + static void event_satisfied( struct object *obj, struct wait_queue_entry *entry ); + static int event_get_esync_fd( struct object *obj, enum esync_type *type ); ++static unsigned int event_get_fsync_idx( struct object *obj, enum fsync_type *type ); + static int event_signal( struct object *obj, unsigned int access); + static struct list *event_get_kernel_obj_list( struct object *obj ); + static void event_destroy( struct object *obj ); +@@ -77,7 +80,7 @@ static const struct object_ops event_ops = + remove_queue, /* remove_queue */ + event_signaled, /* signaled */ + event_get_esync_fd, /* get_esync_fd */ +- NULL, /* get_fsync_idx */ ++ event_get_fsync_idx, /* get_fsync_idx */ + event_satisfied, /* satisfied */ + event_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -159,6 +162,9 @@ struct event *create_event( struct object *root, const struct unicode_str *name, + event->manual_reset = manual_reset; + event->signaled = initial_state; + ++ if (do_fsync()) ++ event->fsync_idx = fsync_alloc_shm( initial_state, 0 ); ++ + if (do_esync()) + event->esync_fd = esync_create_fd( initial_state, 0 ); + } +@@ -181,6 +187,9 @@ static void pulse_event( struct event *event ) + /* wake up all waiters if manual reset, a single one otherwise */ + wake_up( &event->obj, !event->manual_reset ); + event->signaled = 0; ++ ++ if (do_fsync()) ++ fsync_clear( &event->obj ); + } + + void set_event( struct event *event ) +@@ -205,6 +214,9 @@ void reset_event( struct event *event ) + } + event->signaled = 0; + ++ if (do_fsync()) ++ fsync_clear( &event->obj ); ++ + if (do_esync()) + esync_clear( event->esync_fd ); + } +@@ -231,6 +243,13 @@ static int event_get_esync_fd( struct object *obj, enum esync_type *type ) + return event->esync_fd; + } + ++static unsigned int event_get_fsync_idx( struct object *obj, enum fsync_type *type ) ++{ ++ struct event *event = (struct event *)obj; ++ *type = FSYNC_MANUAL_SERVER; ++ return event->fsync_idx; ++} ++ + static void event_satisfied( struct object *obj, struct wait_queue_entry *entry ) + { + struct event *event = (struct event *)obj; +diff --git a/server/fsync.c b/server/fsync.c +index da30d94f1f7..07c0367d02c 100644 +--- a/server/fsync.c ++++ b/server/fsync.c +@@ -292,6 +292,19 @@ void fsync_wake_up( struct object *obj ) + } + } + ++void fsync_clear( struct object *obj ) ++{ ++ struct fsync_event *event; ++ enum fsync_type type; ++ ++ if (obj->ops->get_fsync_idx) ++ { ++ event = get_shm( obj->ops->get_fsync_idx( obj, &type ) ); ++ ++ __atomic_store_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); ++ } ++} ++ + DECL_HANDLER(create_fsync) + { + struct fsync *fsync; +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0074-server-Allow-re-setting-fsync-events-on-the-server-s.patch b/0007-proton-esync-fsync/0074-server-Allow-re-setting-fsync-events-on-the-server-s.patch new file mode 100644 index 0000000..10c6261 --- /dev/null +++ b/0007-proton-esync-fsync/0074-server-Allow-re-setting-fsync-events-on-the-server-s.patch @@ -0,0 +1,107 @@ +From 7fe825927c7e83008777e458304d3273df64cd6e Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 1 Sep 2018 17:44:18 -0500 +Subject: [PATCH 0500/2346] server: Allow (re)setting fsync events on the + server side. + +--- + server/event.c | 16 ++++++++++++++++ + server/fsync.c | 19 ++++++++++++++++++- + server/fsync.h | 6 ++++++ + 3 files changed, 40 insertions(+), 1 deletion(-) + +diff --git a/server/event.c b/server/event.c +index 9acd7fa263c..aa1b0a4002a 100644 +--- a/server/event.c ++++ b/server/event.c +@@ -175,6 +175,10 @@ struct event *create_event( struct object *root, const struct unicode_str *name, + struct event *get_event_obj( struct process *process, obj_handle_t handle, unsigned int access ) + { + struct object *obj; ++ ++ if (do_fsync() && (obj = get_handle_obj( process, handle, access, &fsync_ops))) ++ return (struct event *)obj; /* even though it's not an event */ ++ + if (do_esync() && (obj = get_handle_obj( process, handle, access, &esync_ops))) + return (struct event *)obj; /* even though it's not an event */ + +@@ -194,6 +198,12 @@ static void pulse_event( struct event *event ) + + void set_event( struct event *event ) + { ++ if (do_fsync() && event->obj.ops == &fsync_ops) ++ { ++ fsync_set_event( (struct fsync *)event ); ++ return; ++ } ++ + if (do_esync() && event->obj.ops == &esync_ops) + { + esync_set_event( (struct esync *)event ); +@@ -207,6 +217,12 @@ void set_event( struct event *event ) + + void reset_event( struct event *event ) + { ++ if (do_fsync() && event->obj.ops == &fsync_ops) ++ { ++ fsync_reset_event( (struct fsync *)event ); ++ return; ++ } ++ + if (do_esync() && event->obj.ops == &esync_ops) + { + esync_reset_event( (struct esync *)event ); +diff --git a/server/fsync.c b/server/fsync.c +index 07c0367d02c..1d6a49fb517 100644 +--- a/server/fsync.c ++++ b/server/fsync.c +@@ -132,7 +132,7 @@ struct fsync + static void fsync_dump( struct object *obj, int verbose ); + static void fsync_destroy( struct object *obj ); + +-static const struct object_ops fsync_ops = ++const struct object_ops fsync_ops = + { + sizeof(struct fsync), /* size */ + &no_type, /* type */ +@@ -305,6 +305,23 @@ void fsync_clear( struct object *obj ) + } + } + ++void fsync_set_event( struct fsync *fsync ) ++{ ++ struct fsync_event *event = get_shm( fsync->shm_idx ); ++ assert( fsync->obj.ops == &fsync_ops ); ++ ++ if (!__atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST )) ++ futex_wake( &event->signaled, INT_MAX ); ++} ++ ++void fsync_reset_event( struct fsync *fsync ) ++{ ++ struct fsync_event *event = get_shm( fsync->shm_idx ); ++ assert( fsync->obj.ops == &fsync_ops ); ++ ++ __atomic_store_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); ++} ++ + DECL_HANDLER(create_fsync) + { + struct fsync *fsync; +diff --git a/server/fsync.h b/server/fsync.h +index 2ff98cb64cb..087d482717b 100644 +--- a/server/fsync.h ++++ b/server/fsync.h +@@ -23,3 +23,9 @@ extern void fsync_init(void); + extern unsigned int fsync_alloc_shm( int low, int high ); + extern void fsync_wake_up( struct object *obj ); + extern void fsync_clear( struct object *obj ); ++ ++struct fsync; ++ ++extern const struct object_ops fsync_ops; ++extern void fsync_set_event( struct fsync *fsync ); ++extern void fsync_reset_event( struct fsync *fsync ); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0075-server-Create-futexes-for-thread-objects.patch b/0007-proton-esync-fsync/0075-server-Create-futexes-for-thread-objects.patch new file mode 100644 index 0000000..d2508b0 --- /dev/null +++ b/0007-proton-esync-fsync/0075-server-Create-futexes-for-thread-objects.patch @@ -0,0 +1,78 @@ +From 14397f6fccbe464df611da71d25dfec87e09dc74 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 1 Sep 2018 17:47:50 -0500 +Subject: [PATCH 0501/2346] server: Create futexes for thread objects. + +--- + server/thread.c | 14 +++++++++++++- + server/thread.h | 1 + + 2 files changed, 14 insertions(+), 1 deletion(-) + +diff --git a/server/thread.c b/server/thread.c +index 6c46fc492cf..0ca74e6a7ab 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -185,6 +185,7 @@ struct type_descr thread_type = + static void dump_thread( struct object *obj, int verbose ); + static int thread_signaled( struct object *obj, struct wait_queue_entry *entry ); + static int thread_get_esync_fd( struct object *obj, enum esync_type *type ); ++static unsigned int thread_get_fsync_idx( struct object *obj, enum fsync_type *type ); + static unsigned int thread_map_access( struct object *obj, unsigned int access ); + static void thread_poll_event( struct fd *fd, int event ); + static struct list *thread_get_kernel_obj_list( struct object *obj ); +@@ -199,7 +200,7 @@ static const struct object_ops thread_ops = + remove_queue, /* remove_queue */ + thread_signaled, /* signaled */ + thread_get_esync_fd, /* get_esync_fd */ +- NULL, /* get_fsync_idx */ ++ thread_get_fsync_idx, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -269,6 +270,7 @@ static inline void init_thread_structure( struct thread *thread ) + thread->entry_point = 0; + thread->esync_fd = -1; + thread->esync_apc_fd = -1; ++ thread->fsync_idx = 0; + thread->system_regs = 0; + thread->queue = NULL; + thread->wait = NULL; +@@ -481,6 +483,9 @@ struct thread *create_thread( int fd, struct process *process, const struct secu + } + } + ++ if (do_fsync()) ++ thread->fsync_idx = fsync_alloc_shm( 0, 0 ); ++ + if (do_esync()) + { + thread->esync_fd = esync_create_fd( 0, 0 ); +@@ -597,6 +602,13 @@ static int thread_get_esync_fd( struct object *obj, enum esync_type *type ) + return thread->esync_fd; + } + ++static unsigned int thread_get_fsync_idx( struct object *obj, enum fsync_type *type ) ++{ ++ struct thread *thread = (struct thread *)obj; ++ *type = FSYNC_MANUAL_SERVER; ++ return thread->fsync_idx; ++} ++ + static unsigned int thread_map_access( struct object *obj, unsigned int access ) + { + access = default_map_access( obj, access ); +diff --git a/server/thread.h b/server/thread.h +index a01d492361d..ec271f5cab4 100644 +--- a/server/thread.h ++++ b/server/thread.h +@@ -56,6 +56,7 @@ struct thread + struct list mutex_list; /* list of currently owned mutexes */ + int esync_fd; /* esync file descriptor (signalled on exit) */ + int esync_apc_fd; /* esync apc fd (signalled when APCs are present) */ ++ unsigned int fsync_idx; + unsigned int system_regs; /* which system regs have been set */ + struct msg_queue *queue; /* message queue */ + struct thread_wait *wait; /* current wait condition if sleeping */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0076-server-Create-futexes-for-message-queues.patch b/0007-proton-esync-fsync/0076-server-Create-futexes-for-message-queues.patch new file mode 100644 index 0000000..aa4f9ee --- /dev/null +++ b/0007-proton-esync-fsync/0076-server-Create-futexes-for-message-queues.patch @@ -0,0 +1,146 @@ +From 775d7fb3372b741c29e3721a01d60edebc560ce9 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 1 Sep 2018 17:53:59 -0500 +Subject: [PATCH 0502/2346] server: Create futexes for message queues. + +--- + server/protocol.def | 1 + + server/queue.c | 34 ++++++++++++++++++++++++++++++---- + 2 files changed, 31 insertions(+), 4 deletions(-) + +diff --git a/server/protocol.def b/server/protocol.def +index d32ae3a27a3..ac5f200122c 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3998,6 +3998,7 @@ enum fsync_type + FSYNC_AUTO_EVENT, + FSYNC_MANUAL_EVENT, + FSYNC_MANUAL_SERVER, ++ FSYNC_QUEUE, + }; + + /* Create a new futex-based synchronization object */ +diff --git a/server/queue.c b/server/queue.c +index be8526d4a74..c5c5532850b 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -45,6 +45,7 @@ + #include "request.h" + #include "user.h" + #include "esync.h" ++#include "fsync.h" + + #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE + #define WM_NCMOUSELAST (WM_NCMOUSEFIRST+(WM_MOUSELAST-WM_MOUSEFIRST)) +@@ -137,6 +138,7 @@ struct msg_queue + unsigned int ignore_post_msg; /* ignore post messages newer than this unique id */ + int esync_fd; /* esync file descriptor (signalled on message) */ + int esync_in_msgwait; /* our thread is currently waiting on us */ ++ unsigned int fsync_idx; + }; + + struct hotkey +@@ -154,6 +156,7 @@ static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *ent + static void msg_queue_remove_queue( struct object *obj, struct wait_queue_entry *entry ); + static int msg_queue_signaled( struct object *obj, struct wait_queue_entry *entry ); + static int msg_queue_get_esync_fd( struct object *obj, enum esync_type *type ); ++static unsigned int msg_queue_get_fsync_idx( struct object *obj, enum fsync_type *type ); + static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *entry ); + static void msg_queue_destroy( struct object *obj ); + static void msg_queue_poll_event( struct fd *fd, int event ); +@@ -170,7 +173,7 @@ static const struct object_ops msg_queue_ops = + msg_queue_remove_queue, /* remove_queue */ + msg_queue_signaled, /* signaled */ + msg_queue_get_esync_fd, /* get_esync_fd */ +- NULL, /* get_fsync_idx */ ++ msg_queue_get_fsync_idx, /* get_fsync_idx */ + msg_queue_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -324,12 +327,19 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ + queue->ignore_post_msg = 0; + queue->esync_fd = -1; + queue->esync_in_msgwait = 0; ++ queue->fsync_idx = 0; + list_init( &queue->send_result ); + list_init( &queue->callback_result ); + list_init( &queue->pending_timers ); + list_init( &queue->expired_timers ); + for (i = 0; i < NB_MSG_KINDS; i++) list_init( &queue->msg_list[i] ); + ++ if (do_fsync()) ++ queue->fsync_idx = fsync_alloc_shm( 0, 0 ); ++ ++ if (do_esync()) ++ queue->esync_fd = esync_create_fd( 0, 0 ); ++ + if (!(queue->shared = alloc_shared_object())) + { + release_object( queue ); +@@ -346,9 +356,6 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ + } + SHARED_WRITE_END; + +- if (do_esync()) +- queue->esync_fd = esync_create_fd( 0, 0 ); +- + thread->queue = queue; + + if ((desktop = get_thread_desktop( thread, 0 ))) +@@ -742,6 +749,9 @@ static inline void clear_queue_bits( struct msg_queue *queue, unsigned int bits + { + const queue_shm_t *queue_shm = queue->shared; + ++ if (do_fsync() && !is_signaled( queue )) ++ fsync_clear( &queue->obj ); ++ + if (do_esync() && !is_signaled( queue )) + esync_clear( queue->esync_fd ); + +@@ -1310,6 +1320,13 @@ static int msg_queue_get_esync_fd( struct object *obj, enum esync_type *type ) + return queue->esync_fd; + } + ++static unsigned int msg_queue_get_fsync_idx( struct object *obj, enum fsync_type *type ) ++{ ++ struct msg_queue *queue = (struct msg_queue *)obj; ++ *type = FSYNC_QUEUE; ++ return queue->fsync_idx; ++} ++ + static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *entry ) + { + struct msg_queue *queue = (struct msg_queue *)obj; +@@ -3154,6 +3171,9 @@ DECL_HANDLER(set_queue_mask) + else wake_up( &queue->obj, 0 ); + } + ++ if (do_fsync() && !is_signaled( queue )) ++ fsync_clear( &queue->obj ); ++ + if (do_esync() && !is_signaled( queue )) + esync_clear( queue->esync_fd ); + } +@@ -3171,6 +3191,9 @@ DECL_HANDLER(get_queue_status) + reply->wake_bits = queue_shm->wake_bits; + reply->changed_bits = queue_shm->changed_bits; + ++ if (do_fsync() && !is_signaled( queue )) ++ fsync_clear( &queue->obj ); ++ + if (do_esync() && !is_signaled( queue )) + esync_clear( queue->esync_fd ); + +@@ -3448,6 +3471,9 @@ DECL_HANDLER(get_message) + + set_error( STATUS_PENDING ); /* FIXME */ + ++ if (do_fsync() && !is_signaled( queue )) ++ fsync_clear( &queue->obj ); ++ + if (do_esync() && !is_signaled( queue )) + esync_clear( queue->esync_fd ); + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0077-server-ntdll-Implement-message-waits.patch b/0007-proton-esync-fsync/0077-server-ntdll-Implement-message-waits.patch new file mode 100644 index 0000000..0990e3b --- /dev/null +++ b/0007-proton-esync-fsync/0077-server-ntdll-Implement-message-waits.patch @@ -0,0 +1,171 @@ +From e1e1e5385bed846a11675c4186b523ef50381917 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 1 Sep 2018 19:24:15 -0500 +Subject: [PATCH 0503/2346] server, ntdll: Implement message waits. + +The approach of giving the queue fd to ntdll to wait on doesn't work here. +Fortunately, the way esync has ended up lends itself very easily to a rather +clean approach: let the server do it the normal way. +--- + dlls/ntdll/unix/fsync.c | 52 ++++++++++++++++++++++++++++++++++++++++- + server/protocol.def | 4 ++++ + server/queue.c | 20 ++++++++++++++++ + 3 files changed, 75 insertions(+), 1 deletion(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index ec8b3121ed1..edad675fa7a 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -437,12 +437,13 @@ static LONGLONG update_timeout( ULONGLONG end ) + return timeleft; + } + +-NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, ++static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) + { + struct futex_wait_block futexes[MAXIMUM_WAIT_OBJECTS]; + struct fsync *objs[MAXIMUM_WAIT_OBJECTS]; + int has_fsync = 0, has_server = 0; ++ BOOL msgwait = FALSE; + int dummy_futex = 0; + LONGLONG timeleft; + LARGE_INTEGER now; +@@ -471,6 +472,9 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, + return ret; + } + ++ if (objs[count - 1] && objs[count - 1]->type == FSYNC_QUEUE) ++ msgwait = TRUE; ++ + if (has_fsync && has_server) + FIXME("Can't wait on fsync and server objects at the same time!\n"); + else if (has_server) +@@ -482,6 +486,9 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, + for (i = 0; i < count; i++) + TRACE(" %p", handles[i]); + ++ if (msgwait) ++ TRACE(" or driver events"); ++ + if (!timeout) + TRACE(", timeout = INFINITE.\n"); + else +@@ -542,6 +549,7 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, + } + case FSYNC_MANUAL_EVENT: + case FSYNC_MANUAL_SERVER: ++ case FSYNC_QUEUE: + { + struct event *event = obj->shm; + +@@ -602,3 +610,45 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, + return STATUS_NOT_IMPLEMENTED; + } + } ++ ++/* Like esync, we need to let the server know when we are doing a message wait, ++ * and when we are done with one, so that all of the code surrounding hung ++ * queues works, and we also need this for WaitForInputIdle(). ++ * ++ * Unlike esync, we can't wait on the queue fd itself locally. Instead we let ++ * the server do that for us, the way it normally does. This could actually ++ * work for esync too, and that might be better. */ ++static void server_set_msgwait( int in_msgwait ) ++{ ++ SERVER_START_REQ( fsync_msgwait ) ++ { ++ req->in_msgwait = in_msgwait; ++ wine_server_call( req ); ++ } ++ SERVER_END_REQ; ++} ++ ++/* This is a very thin wrapper around the proper implementation above. The ++ * purpose is to make sure the server knows when we are doing a message wait. ++ * This is separated into a wrapper function since there are at least a dozen ++ * exit paths from fsync_wait_objects(). */ ++NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, ++ BOOLEAN alertable, const LARGE_INTEGER *timeout ) ++{ ++ BOOL msgwait = FALSE; ++ struct fsync *obj; ++ NTSTATUS ret; ++ ++ if (!get_object( handles[count - 1], &obj ) && obj->type == FSYNC_QUEUE) ++ { ++ msgwait = TRUE; ++ server_set_msgwait( 1 ); ++ } ++ ++ ret = __fsync_wait_objects( count, handles, wait_any, alertable, timeout ); ++ ++ if (msgwait) ++ server_set_msgwait( 0 ); ++ ++ return ret; ++} +diff --git a/server/protocol.def b/server/protocol.def +index ac5f200122c..8eb4ab0b004 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -4019,3 +4019,7 @@ enum fsync_type + int type; + unsigned int shm_idx; + @END ++ ++@REQ(fsync_msgwait) ++ int in_msgwait; /* are we in a message wait? */ ++@END +diff --git a/server/queue.c b/server/queue.c +index 50e58d31501..3526cfee3f3 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -140,6 +140,7 @@ struct msg_queue + int esync_fd; /* esync file descriptor (signalled on message) */ + int esync_in_msgwait; /* our thread is currently waiting on us */ + unsigned int fsync_idx; ++ int fsync_in_msgwait; /* our thread is currently waiting on us */ + }; + + struct hotkey +@@ -348,6 +349,7 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_ + queue->esync_fd = -1; + queue->esync_in_msgwait = 0; + queue->fsync_idx = 0; ++ queue->fsync_in_msgwait = 0; + list_init( &queue->send_result ); + list_init( &queue->callback_result ); + list_init( &queue->pending_timers ); +@@ -1234,6 +1236,9 @@ static int is_queue_hung( struct msg_queue *queue ) + return 0; /* thread is waiting on queue -> not hung */ + } + ++ if (do_fsync() && queue->fsync_in_msgwait) ++ return 0; /* thread is waiting on queue in absentia -> not hung */ ++ + if (do_esync() && queue->esync_in_msgwait) + return 0; /* thread is waiting on queue in absentia -> not hung */ + +@@ -3998,3 +4003,18 @@ DECL_HANDLER(esync_msgwait) + if (queue->fd) + set_fd_events( queue->fd, req->in_msgwait ? POLLIN : 0 ); + } ++ ++DECL_HANDLER(fsync_msgwait) ++{ ++ struct msg_queue *queue = get_current_queue(); ++ ++ if (!queue) return; ++ queue->fsync_in_msgwait = req->in_msgwait; ++ ++ if (current->process->idle_event && !(queue->wake_mask & QS_SMRESULT)) ++ set_event( current->process->idle_event ); ++ ++ /* and start/stop waiting on the driver */ ++ if (queue->fd) ++ set_fd_events( queue->fd, req->in_msgwait ? POLLIN : 0 ); ++} +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0078-server-Create-futexes-for-device-manager-objects.patch b/0007-proton-esync-fsync/0078-server-Create-futexes-for-device-manager-objects.patch new file mode 100644 index 0000000..29594a4 --- /dev/null +++ b/0007-proton-esync-fsync/0078-server-Create-futexes-for-device-manager-objects.patch @@ -0,0 +1,91 @@ +From a986d6dd884e502aa039379afda2b7e82184d0da Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 1 Sep 2018 19:29:56 -0500 +Subject: [PATCH 0504/2346] server: Create futexes for device manager objects. + +--- + server/device.c | 21 ++++++++++++++++++++- + 1 file changed, 20 insertions(+), 1 deletion(-) + +diff --git a/server/device.c b/server/device.c +index 8613cee58af..90e0a0c1fee 100644 +--- a/server/device.c ++++ b/server/device.c +@@ -39,6 +39,7 @@ + #include "request.h" + #include "process.h" + #include "esync.h" ++#include "fsync.h" + + /* IRP object */ + +@@ -96,11 +97,13 @@ struct device_manager + struct irp_call *current_call; /* call currently executed on client side */ + struct wine_rb_tree kernel_objects; /* map of objects that have client side pointer associated */ + int esync_fd; /* esync file descriptor */ ++ unsigned int fsync_idx; + }; + + static void device_manager_dump( struct object *obj, int verbose ); + static int device_manager_signaled( struct object *obj, struct wait_queue_entry *entry ); + static int device_manager_get_esync_fd( struct object *obj, enum esync_type *type ); ++static unsigned int device_manager_get_fsync_idx( struct object *obj, enum fsync_type *type ); + static void device_manager_destroy( struct object *obj ); + + static const struct object_ops device_manager_ops = +@@ -112,7 +115,7 @@ static const struct object_ops device_manager_ops = + remove_queue, /* remove_queue */ + device_manager_signaled, /* signaled */ + device_manager_get_esync_fd, /* get_esync_fd */ +- NULL, /* get_fsync_idx */ ++ device_manager_get_fsync_idx, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -758,6 +761,9 @@ static void delete_file( struct device_file *file ) + /* terminate all pending requests */ + LIST_FOR_EACH_ENTRY_SAFE( irp, next, &file->requests, struct irp_call, dev_entry ) + { ++ if (do_fsync() && file->device->manager && list_empty( &file->device->manager->requests )) ++ fsync_clear( &file->device->manager->obj ); ++ + if (do_esync() && file->device->manager && list_empty( &file->device->manager->requests )) + esync_clear( file->device->manager->esync_fd ); + +@@ -803,6 +809,13 @@ static int device_manager_get_esync_fd( struct object *obj, enum esync_type *typ + return manager->esync_fd; + } + ++static unsigned int device_manager_get_fsync_idx( struct object *obj, enum fsync_type *type ) ++{ ++ struct device_manager *manager = (struct device_manager *)obj; ++ *type = FSYNC_MANUAL_SERVER; ++ return manager->fsync_idx; ++} ++ + static void device_manager_destroy( struct object *obj ) + { + struct device_manager *manager = (struct device_manager *)obj; +@@ -853,6 +866,9 @@ static struct device_manager *create_device_manager(void) + list_init( &manager->requests ); + wine_rb_init( &manager->kernel_objects, compare_kernel_object ); + ++ if (do_fsync()) ++ manager->fsync_idx = fsync_alloc_shm( 0, 0 ); ++ + if (do_esync()) + manager->esync_fd = esync_create_fd( 0, 0 ); + } +@@ -1045,6 +1061,9 @@ DECL_HANDLER(get_next_device_request) + if (irp->file) grab_object( irp ); + manager->current_call = irp; + ++ if (do_fsync() && list_empty( &manager->requests )) ++ fsync_clear( &manager->obj ); ++ + if (do_esync() && list_empty( &manager->requests )) + esync_clear( manager->esync_fd ); + } +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0079-ntdll-Implement-NtCreateMutant.patch b/0007-proton-esync-fsync/0079-ntdll-Implement-NtCreateMutant.patch new file mode 100644 index 0000000..e865707 --- /dev/null +++ b/0007-proton-esync-fsync/0079-ntdll-Implement-NtCreateMutant.patch @@ -0,0 +1,89 @@ +From b48a1bd74a70221bf9dbe5876b45f9e23c768f28 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 1 Sep 2018 19:36:23 -0500 +Subject: [PATCH 0505/2346] ntdll: Implement NtCreateMutant(). + +--- + dlls/ntdll/unix/fsync.c | 17 +++++++++++++++++ + dlls/ntdll/unix/fsync.h | 2 ++ + dlls/ntdll/unix/sync.c | 3 +++ + server/protocol.def | 1 + + 4 files changed, 23 insertions(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index edad675fa7a..9d4d61ad389 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -115,6 +115,13 @@ struct event + }; + C_ASSERT(sizeof(struct event) == 8); + ++struct mutex ++{ ++ int tid; ++ int count; /* recursion count */ ++}; ++C_ASSERT(sizeof(struct mutex) == 8); ++ + static char shm_name[29]; + static int shm_fd; + static void **shm_addrs; +@@ -426,6 +433,16 @@ NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) + return STATUS_SUCCESS; + } + ++NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ) ++{ ++ TRACE("name %s, initial %d.\n", ++ attr ? debugstr_us(attr->ObjectName) : "", initial); ++ ++ return create_fsync( FSYNC_MUTEX, handle, access, attr, ++ initial ? GetCurrentThreadId() : 0, initial ? 1 : 0 ); ++} ++ + static LONGLONG update_timeout( ULONGLONG end ) + { + LARGE_INTEGER now; +diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h +index 56afeb1f9e8..e7cc1e87b4e 100644 +--- a/dlls/ntdll/unix/fsync.h ++++ b/dlls/ntdll/unix/fsync.h +@@ -29,6 +29,8 @@ extern NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ); + extern NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ); + extern NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ); ++extern NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ); + + extern NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, + BOOLEAN alertable, const LARGE_INTEGER *timeout ); +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index ef39b1b8b42..a21b372e0d9 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -588,6 +588,9 @@ NTSTATUS WINAPI NtCreateMutant( HANDLE *handle, ACCESS_MASK access, const OBJECT + + *handle = 0; + ++ if (do_fsync()) ++ return fsync_create_mutex( handle, access, attr, owned ); ++ + if (do_esync()) + return esync_create_mutex( handle, access, attr, owned ); + +diff --git a/server/protocol.def b/server/protocol.def +index 8eb4ab0b004..d0f9c715a54 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3997,6 +3997,7 @@ enum fsync_type + FSYNC_SEMAPHORE = 1, + FSYNC_AUTO_EVENT, + FSYNC_MANUAL_EVENT, ++ FSYNC_MUTEX, + FSYNC_MANUAL_SERVER, + FSYNC_QUEUE, + }; +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0080-ntdll-Implement-NtReleaseMutant.patch b/0007-proton-esync-fsync/0080-ntdll-Implement-NtReleaseMutant.patch new file mode 100644 index 0000000..177dd53 --- /dev/null +++ b/0007-proton-esync-fsync/0080-ntdll-Implement-NtReleaseMutant.patch @@ -0,0 +1,74 @@ +From a3324abb11bd4f89117988236ce1d5d019062fea Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 1 Sep 2018 19:42:17 -0500 +Subject: [PATCH 0506/2346] ntdll: Implement NtReleaseMutant(). + +--- + dlls/ntdll/unix/fsync.c | 23 +++++++++++++++++++++++ + dlls/ntdll/unix/fsync.h | 1 + + dlls/ntdll/unix/sync.c | 3 +++ + 3 files changed, 27 insertions(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 9d4d61ad389..22b67e5d4a4 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -443,6 +443,29 @@ NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, + initial ? GetCurrentThreadId() : 0, initial ? 1 : 0 ); + } + ++NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) ++{ ++ struct mutex *mutex; ++ struct fsync *obj; ++ ++ TRACE("%p, %p.\n", handle, prev); ++ ++ if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; ++ mutex = obj->shm; ++ ++ if (mutex->tid != GetCurrentThreadId()) return STATUS_MUTANT_NOT_OWNED; ++ ++ if (prev) *prev = mutex->count; ++ ++ if (!--mutex->count) ++ { ++ __atomic_store_n( &mutex->tid, 0, __ATOMIC_SEQ_CST ); ++ futex_wake( &mutex->tid, 1 ); ++ } ++ ++ return STATUS_SUCCESS; ++} ++ + static LONGLONG update_timeout( ULONGLONG end ) + { + LARGE_INTEGER now; +diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h +index e7cc1e87b4e..1867ba88112 100644 +--- a/dlls/ntdll/unix/fsync.h ++++ b/dlls/ntdll/unix/fsync.h +@@ -31,6 +31,7 @@ extern NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ); + extern NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ); + extern NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ); ++extern NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ); + + extern NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, + BOOLEAN alertable, const LARGE_INTEGER *timeout ); +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index a21b372e0d9..456531267e5 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -646,6 +646,9 @@ NTSTATUS WINAPI NtReleaseMutant( HANDLE handle, LONG *prev_count ) + { + unsigned int ret; + ++ if (do_fsync()) ++ return fsync_release_mutex( handle, prev_count ); ++ + if (do_esync()) + return esync_release_mutex( handle, prev_count ); + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0081-ntdll-Implement-waiting-on-mutexes.patch b/0007-proton-esync-fsync/0081-ntdll-Implement-waiting-on-mutexes.patch new file mode 100644 index 0000000..767e37d --- /dev/null +++ b/0007-proton-esync-fsync/0081-ntdll-Implement-waiting-on-mutexes.patch @@ -0,0 +1,45 @@ +From 0e61751fddda33bb1e87c00107da680f6a77afa1 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 1 Sep 2018 19:46:17 -0500 +Subject: [PATCH 0507/2346] ntdll: Implement waiting on mutexes. + +--- + dlls/ntdll/unix/fsync.c | 22 ++++++++++++++++++++++ + 1 file changed, 22 insertions(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 22b67e5d4a4..f4d3c8953cf 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -573,6 +573,28 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + futexes[i].val = current; + break; + } ++ case FSYNC_MUTEX: ++ { ++ struct mutex *mutex = obj->shm; ++ ++ if (mutex->tid == GetCurrentThreadId()) ++ { ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ mutex->count++; ++ return i; ++ } ++ ++ if (!__sync_val_compare_and_swap( &mutex->tid, 0, GetCurrentThreadId() )) ++ { ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ mutex->count = 1; ++ return i; ++ } ++ ++ futexes[i].addr = &mutex->tid; ++ futexes[i].val = mutex->tid; ++ break; ++ } + case FSYNC_AUTO_EVENT: + { + struct event *event = obj->shm; +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0082-ntdll-Implement-wait-all.patch b/0007-proton-esync-fsync/0082-ntdll-Implement-wait-all.patch new file mode 100644 index 0000000..1b1c2a1 --- /dev/null +++ b/0007-proton-esync-fsync/0082-ntdll-Implement-wait-all.patch @@ -0,0 +1,241 @@ +From 26ede2ce1e39574e153703a703654e71db8aaa59 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sat, 1 Sep 2018 20:35:44 -0500 +Subject: [PATCH 0508/2346] ntdll: Implement wait-all. + +--- + dlls/ntdll/unix/fsync.c | 204 +++++++++++++++++++++++++++++++++++++++- + 1 file changed, 201 insertions(+), 3 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index f4d3c8953cf..0c382de40ae 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -74,6 +74,11 @@ static inline int futex_wake( int *addr, int val ) + return syscall( __NR_futex, addr, 1, val, NULL, 0, 0 ); + } + ++static inline int futex_wait( int *addr, int val, struct timespec *timeout ) ++{ ++ return syscall( __NR_futex, addr, 0, val, timeout, 0, 0 ); ++} ++ + int do_fsync(void) + { + #ifdef __linux__ +@@ -477,6 +482,29 @@ static LONGLONG update_timeout( ULONGLONG end ) + return timeleft; + } + ++static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end ) ++{ ++ int ret; ++ ++ if (end) ++ { ++ LONGLONG timeleft = update_timeout( *end ); ++ struct timespec tmo_p; ++ tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; ++ tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; ++ ret = futex_wait( addr, val, &tmo_p ); ++ } ++ else ++ ret = futex_wait( addr, val, NULL ); ++ ++ if (!ret) ++ return 0; ++ else if (ret < 0 && errno == ETIMEDOUT) ++ return STATUS_TIMEOUT; ++ else ++ return STATUS_PENDING; ++} ++ + static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) + { +@@ -668,9 +696,179 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + } + else + { +- FIXME("Wait-all not implemented.\n"); +- return STATUS_NOT_IMPLEMENTED; +- } ++ /* Wait-all is a little trickier to implement correctly. Fortunately, ++ * it's not as common. ++ * ++ * The idea is basically just to wait in sequence on every object in the ++ * set. Then when we're done, try to grab them all in a tight loop. If ++ * that fails, release any resources we've grabbed (and yes, we can ++ * reliably do this—it's just mutexes and semaphores that we have to ++ * put back, and in both cases we just put back 1), and if any of that ++ * fails we start over. ++ * ++ * What makes this inherently bad is that we might temporarily grab a ++ * resource incorrectly. Hopefully it'll be quick (and hey, it won't ++ * block on wineserver) so nobody will notice. Besides, consider: if ++ * object A becomes signaled but someone grabs it before we can grab it ++ * and everything else, then they could just as well have grabbed it ++ * before it became signaled. Similarly if object A was signaled and we ++ * were blocking on object B, then B becomes available and someone grabs ++ * A before we can, then they might have grabbed A before B became ++ * signaled. In either case anyone who tries to wait on A or B will be ++ * waiting for an instant while we put things back. */ ++ ++ NTSTATUS status = STATUS_SUCCESS; ++ int current; ++ ++ while (1) ++ { ++tryagain: ++ /* First step: try to wait on each object in sequence. */ ++ ++ for (i = 0; i < count; i++) ++ { ++ struct fsync *obj = objs[i]; ++ ++ if (obj && obj->type == FSYNC_MUTEX) ++ { ++ struct mutex *mutex = obj->shm; ++ ++ if (mutex->tid == GetCurrentThreadId()) ++ continue; ++ ++ while ((current = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST ))) ++ { ++ status = do_single_wait( &mutex->tid, current, timeout ? &end : NULL ); ++ if (status != STATUS_PENDING) ++ break; ++ } ++ } ++ else if (obj) ++ { ++ /* this works for semaphores too */ ++ struct event *event = obj->shm; ++ ++ while (!__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) ++ { ++ status = do_single_wait( &event->signaled, 0, timeout ? &end : NULL ); ++ if (status != STATUS_PENDING) ++ break; ++ } ++ } ++ ++ if (status == STATUS_TIMEOUT) ++ { ++ TRACE("Wait timed out.\n"); ++ return status; ++ } ++ } ++ ++ /* If we got here and we haven't timed out, that means all of the ++ * handles were signaled. Check to make sure they still are. */ ++ for (i = 0; i < count; i++) ++ { ++ struct fsync *obj = objs[i]; ++ ++ if (obj && obj->type == FSYNC_MUTEX) ++ { ++ struct mutex *mutex = obj->shm; ++ ++ if (mutex->tid == GetCurrentThreadId()) ++ continue; /* ok */ ++ ++ if (__atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST )) ++ goto tryagain; ++ } ++ else if (obj) ++ { ++ struct event *event = obj->shm; ++ ++ if (!__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) ++ goto tryagain; ++ } ++ } ++ ++ /* Yep, still signaled. Now quick, grab everything. */ ++ for (i = 0; i < count; i++) ++ { ++ struct fsync *obj = objs[i]; ++ switch (obj->type) ++ { ++ case FSYNC_MUTEX: ++ { ++ struct mutex *mutex = obj->shm; ++ if (mutex->tid == GetCurrentThreadId()) ++ break; ++ if (__sync_val_compare_and_swap( &mutex->tid, 0, GetCurrentThreadId() )) ++ goto tooslow; ++ break; ++ } ++ case FSYNC_SEMAPHORE: ++ { ++ struct semaphore *semaphore = obj->shm; ++ if (__sync_fetch_and_sub( &semaphore->count, 1 ) <= 0) ++ goto tooslow; ++ break; ++ } ++ case FSYNC_AUTO_EVENT: ++ { ++ struct event *event = obj->shm; ++ if (!__sync_val_compare_and_swap( &event->signaled, 1, 0 )) ++ goto tooslow; ++ break; ++ } ++ default: ++ /* If a manual-reset event changed between there and ++ * here, it's shouldn't be a problem. */ ++ break; ++ } ++ } ++ ++ /* If we got here, we successfully waited on every object. ++ * Make sure to let ourselves know that we grabbed the mutexes. */ ++ for (i = 0; i < count; i++) ++ { ++ if (objs[i] && objs[i]->type == FSYNC_MUTEX) ++ { ++ struct mutex *mutex = objs[i]->shm; ++ mutex->count++; ++ } ++ } ++ ++ TRACE("Wait successful.\n"); ++ return STATUS_SUCCESS; ++ ++tooslow: ++ for (--i; i >= 0; i--) ++ { ++ struct fsync *obj = objs[i]; ++ switch (obj->type) ++ { ++ case FSYNC_MUTEX: ++ { ++ struct mutex *mutex = obj->shm; ++ __atomic_store_n( &mutex->tid, 0, __ATOMIC_SEQ_CST ); ++ break; ++ } ++ case FSYNC_SEMAPHORE: ++ { ++ struct semaphore *semaphore = obj->shm; ++ __sync_fetch_and_add( &semaphore->count, 1 ); ++ break; ++ } ++ case FSYNC_AUTO_EVENT: ++ { ++ struct event *event = obj->shm; ++ __atomic_store_n( &event->signaled, 1, __ATOMIC_SEQ_CST ); ++ break; ++ } ++ default: ++ /* doesn't need to be put back */ ++ break; ++ } ++ } ++ } /* while (1) */ ++ } /* else (wait-all) */ + } + + /* Like esync, we need to let the server know when we are doing a message wait, +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0083-ntdll-Implement-NtSignalAndWaitForSingleObject.patch b/0007-proton-esync-fsync/0083-ntdll-Implement-NtSignalAndWaitForSingleObject.patch new file mode 100644 index 0000000..3962f0a --- /dev/null +++ b/0007-proton-esync-fsync/0083-ntdll-Implement-NtSignalAndWaitForSingleObject.patch @@ -0,0 +1,74 @@ +From 54ad5ea391c97b70be1beb297b5766cd42ec6abf Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sun, 2 Sep 2018 11:41:07 -0500 +Subject: [PATCH 0509/2346] ntdll: Implement NtSignalAndWaitForSingleObject(). + +--- + dlls/ntdll/unix/fsync.c | 28 ++++++++++++++++++++++++++++ + dlls/ntdll/unix/fsync.h | 2 ++ + dlls/ntdll/unix/sync.c | 3 +++ + 3 files changed, 33 insertions(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 0c382de40ae..b5116e07920 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -912,3 +912,31 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an + + return ret; + } ++ ++NTSTATUS fsync_signal_and_wait( HANDLE signal, HANDLE wait, BOOLEAN alertable, ++ const LARGE_INTEGER *timeout ) ++{ ++ struct fsync *obj = get_cached_object( signal ); ++ NTSTATUS ret; ++ ++ if (!obj) return STATUS_INVALID_HANDLE; ++ ++ switch (obj->type) ++ { ++ case FSYNC_SEMAPHORE: ++ ret = fsync_release_semaphore( signal, 1, NULL ); ++ break; ++ case FSYNC_AUTO_EVENT: ++ case FSYNC_MANUAL_EVENT: ++ ret = fsync_set_event( signal, NULL ); ++ break; ++ case FSYNC_MUTEX: ++ ret = fsync_release_mutex( signal, NULL ); ++ break; ++ default: ++ return STATUS_OBJECT_TYPE_MISMATCH; ++ } ++ if (ret) return ret; ++ ++ return fsync_wait_objects( 1, &wait, TRUE, alertable, timeout ); ++} +diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h +index 1867ba88112..c39c3a14e59 100644 +--- a/dlls/ntdll/unix/fsync.h ++++ b/dlls/ntdll/unix/fsync.h +@@ -35,3 +35,5 @@ extern NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ); + + extern NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, + BOOLEAN alertable, const LARGE_INTEGER *timeout ); ++extern NTSTATUS fsync_signal_and_wait( HANDLE signal, HANDLE wait, ++ BOOLEAN alertable, const LARGE_INTEGER *timeout ); +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 456531267e5..cdda6307be9 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -1582,6 +1582,9 @@ NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE signal, HANDLE wait, + select_op_t select_op; + UINT flags = SELECT_INTERRUPTIBLE; + ++ if (do_fsync()) ++ return fsync_signal_and_wait( signal, wait, alertable, timeout ); ++ + if (do_esync()) + return esync_signal_and_wait( signal, wait, alertable, timeout ); + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0084-server-ntdll-Also-store-the-fsync-type-in-the-server.patch b/0007-proton-esync-fsync/0084-server-ntdll-Also-store-the-fsync-type-in-the-server.patch new file mode 100644 index 0000000..c8eeef6 --- /dev/null +++ b/0007-proton-esync-fsync/0084-server-ntdll-Also-store-the-fsync-type-in-the-server.patch @@ -0,0 +1,116 @@ +From 19824958f0adfd570070d9add90056d6d7720d51 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sun, 2 Sep 2018 11:48:26 -0500 +Subject: [PATCH 0510/2346] server, ntdll: Also store the fsync type in the + server. + +--- + dlls/ntdll/unix/fsync.c | 2 ++ + server/fsync.c | 26 +++++++++++++++++++++++--- + server/protocol.def | 2 ++ + 3 files changed, 27 insertions(+), 3 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index b5116e07920..e65abc525ed 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -290,12 +290,14 @@ static NTSTATUS create_fsync( enum fsync_type type, HANDLE *handle, + req->access = access; + req->low = low; + req->high = high; ++ req->type = type; + wine_server_add_data( req, objattr, len ); + ret = wine_server_call( req ); + if (!ret || ret == STATUS_OBJECT_NAME_EXISTS) + { + *handle = wine_server_ptr_handle( reply->handle ); + shm_idx = reply->shm_idx; ++ type = reply->type; + } + } + SERVER_END_REQ; +diff --git a/server/fsync.c b/server/fsync.c +index 1d6a49fb517..d32d5f9c689 100644 +--- a/server/fsync.c ++++ b/server/fsync.c +@@ -127,6 +127,7 @@ struct fsync + { + struct object obj; + unsigned int shm_idx; ++ enum fsync_type type; + }; + + static void fsync_dump( struct object *obj, int verbose ); +@@ -237,9 +238,16 @@ unsigned int fsync_alloc_shm( int low, int high ) + #endif + } + ++static int type_matches( enum fsync_type type1, enum fsync_type type2 ) ++{ ++ return (type1 == type2) || ++ ((type1 == FSYNC_AUTO_EVENT || type1 == FSYNC_MANUAL_EVENT) && ++ (type2 == FSYNC_AUTO_EVENT || type2 == FSYNC_MANUAL_EVENT)); ++} ++ + struct fsync *create_fsync( struct object *root, const struct unicode_str *name, +- unsigned int attr, int low, int high, +- const struct security_descriptor *sd ) ++ unsigned int attr, int low, int high, enum fsync_type type, ++ const struct security_descriptor *sd ) + { + #ifdef __linux__ + struct fsync *fsync; +@@ -256,6 +264,17 @@ struct fsync *create_fsync( struct object *root, const struct unicode_str *name, + * and the time its shared memory portion is initialized. */ + + fsync->shm_idx = fsync_alloc_shm( low, high ); ++ fsync->type = type; ++ } ++ else ++ { ++ /* validate the type */ ++ if (!type_matches( type, fsync->type )) ++ { ++ release_object( &fsync->obj ); ++ set_error( STATUS_OBJECT_TYPE_MISMATCH ); ++ return NULL; ++ } + } + } + +@@ -339,7 +358,7 @@ DECL_HANDLER(create_fsync) + if (!objattr) return; + + if ((fsync = create_fsync( root, &name, objattr->attributes, req->low, +- req->high, sd ))) ++ req->high, req->type, sd ))) + { + if (get_error() == STATUS_OBJECT_NAME_EXISTS) + reply->handle = alloc_handle( current->process, fsync, req->access, objattr->attributes ); +@@ -348,6 +367,7 @@ DECL_HANDLER(create_fsync) + req->access, objattr->attributes ); + + reply->shm_idx = fsync->shm_idx; ++ reply->type = fsync->type; + release_object( fsync ); + } + +diff --git a/server/protocol.def b/server/protocol.def +index d0f9c715a54..2b9f3bd1333 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -4007,9 +4007,11 @@ enum fsync_type + unsigned int access; /* wanted access rights */ + int low; /* initial value of low word */ + int high; /* initial value of high word */ ++ int type; /* type of fsync object */ + VARARG(objattr,object_attributes); /* object attributes */ + @REPLY + obj_handle_t handle; /* handle to the object */ ++ int type; /* type of fsync object */ + unsigned int shm_idx; /* this object's index into the shm section */ + @END + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0085-ntdll-server-Implement-NtOpenSemaphore.patch b/0007-proton-esync-fsync/0085-ntdll-server-Implement-NtOpenSemaphore.patch new file mode 100644 index 0000000..72503f6 --- /dev/null +++ b/0007-proton-esync-fsync/0085-ntdll-server-Implement-NtOpenSemaphore.patch @@ -0,0 +1,163 @@ +From 49eeda2756010fa7586494157fab48e4fecfc21c Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sun, 2 Sep 2018 12:02:39 -0500 +Subject: [PATCH 0511/2346] ntdll, server: Implement NtOpenSemaphore(). + +--- + dlls/ntdll/unix/fsync.c | 40 ++++++++++++++++++++++++++++++++++++++++ + dlls/ntdll/unix/fsync.h | 2 ++ + dlls/ntdll/unix/sync.c | 3 +++ + server/fsync.c | 27 +++++++++++++++++++++++++++ + server/protocol.def | 13 +++++++++++++ + 5 files changed, 85 insertions(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index e65abc525ed..81bd29634b1 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -312,6 +312,38 @@ static NTSTATUS create_fsync( enum fsync_type type, HANDLE *handle, + return ret; + } + ++static NTSTATUS open_fsync( enum fsync_type type, HANDLE *handle, ++ ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr ) ++{ ++ NTSTATUS ret; ++ unsigned int shm_idx; ++ ++ SERVER_START_REQ( open_fsync ) ++ { ++ req->access = access; ++ req->attributes = attr->Attributes; ++ req->rootdir = wine_server_obj_handle( attr->RootDirectory ); ++ req->type = type; ++ if (attr->ObjectName) ++ wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length ); ++ if (!(ret = wine_server_call( req ))) ++ { ++ *handle = wine_server_ptr_handle( reply->handle ); ++ type = reply->type; ++ shm_idx = reply->shm_idx; ++ } ++ } ++ SERVER_END_REQ; ++ ++ if (!ret) ++ { ++ add_to_list( *handle, type, get_shm( shm_idx ) ); ++ ++ TRACE("-> handle %p, shm index %u.\n", *handle, shm_idx); ++ } ++ return ret; ++} ++ + void fsync_init(void) + { + struct stat st; +@@ -365,6 +397,14 @@ NTSTATUS fsync_create_semaphore( HANDLE *handle, ACCESS_MASK access, + return create_fsync( FSYNC_SEMAPHORE, handle, access, attr, initial, max ); + } + ++NTSTATUS fsync_open_semaphore( HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr ) ++{ ++ TRACE("name %s.\n", debugstr_us(attr->ObjectName)); ++ ++ return open_fsync( FSYNC_SEMAPHORE, handle, access, attr ); ++} ++ + NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) + { + struct fsync *obj; +diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h +index c39c3a14e59..b70851499fe 100644 +--- a/dlls/ntdll/unix/fsync.h ++++ b/dlls/ntdll/unix/fsync.h +@@ -25,6 +25,8 @@ extern NTSTATUS fsync_close( HANDLE handle ); + extern NTSTATUS fsync_create_semaphore(HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max); + extern NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ); ++extern NTSTATUS fsync_open_semaphore( HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr ); + extern NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ); + extern NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ); +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index cdda6307be9..d8d7656ddc6 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -305,6 +305,9 @@ NTSTATUS WINAPI NtOpenSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJEC + + *handle = 0; + ++ if (do_fsync()) ++ return fsync_open_semaphore( handle, access, attr ); ++ + if (do_esync()) + return esync_open_semaphore( handle, access, attr ); + +diff --git a/server/fsync.c b/server/fsync.c +index d32d5f9c689..3fbc1734735 100644 +--- a/server/fsync.c ++++ b/server/fsync.c +@@ -374,6 +374,33 @@ DECL_HANDLER(create_fsync) + if (root) release_object( root ); + } + ++DECL_HANDLER(open_fsync) ++{ ++ struct unicode_str name = get_req_unicode_str(); ++ ++ reply->handle = open_object( current->process, req->rootdir, req->access, ++ &fsync_ops, &name, req->attributes ); ++ ++ if (reply->handle) ++ { ++ struct fsync *fsync; ++ ++ if (!(fsync = (struct fsync *)get_handle_obj( current->process, reply->handle, ++ 0, &fsync_ops ))) ++ return; ++ ++ if (!type_matches( req->type, fsync->type )) ++ { ++ set_error( STATUS_OBJECT_TYPE_MISMATCH ); ++ release_object( fsync ); ++ return; ++ } ++ ++ reply->type = fsync->type; ++ reply->shm_idx = fsync->shm_idx; ++ release_object( fsync ); ++ } ++} + + /* Retrieve the index of a shm section which will be signaled by the server. */ + DECL_HANDLER(get_fsync_idx) +diff --git a/server/protocol.def b/server/protocol.def +index 2b9f3bd1333..64734fa0457 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -4015,6 +4015,19 @@ enum fsync_type + unsigned int shm_idx; /* this object's index into the shm section */ + @END + ++/* Open an fsync object */ ++@REQ(open_fsync) ++ unsigned int access; /* wanted access rights */ ++ unsigned int attributes; /* object attributes */ ++ obj_handle_t rootdir; /* root directory */ ++ int type; /* type of fsync object */ ++ VARARG(name,unicode_str); /* object name */ ++@REPLY ++ obj_handle_t handle; /* handle to the event */ ++ int type; /* type of fsync object */ ++ unsigned int shm_idx; /* this object's index into the shm section */ ++@END ++ + /* Retrieve the shm index for an object. */ + @REQ(get_fsync_idx) + obj_handle_t handle; /* handle to the object */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0086-ntdll-Implement-NtOpenEvent.patch b/0007-proton-esync-fsync/0086-ntdll-Implement-NtOpenEvent.patch new file mode 100644 index 0000000..ace1589 --- /dev/null +++ b/0007-proton-esync-fsync/0086-ntdll-Implement-NtOpenEvent.patch @@ -0,0 +1,60 @@ +From 395a704bd29f7875bdc0b27d4886c6edb6813d68 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sun, 2 Sep 2018 12:05:37 -0500 +Subject: [PATCH 0512/2346] ntdll: Implement NtOpenEvent(). + +--- + dlls/ntdll/unix/fsync.c | 8 ++++++++ + dlls/ntdll/unix/fsync.h | 2 ++ + dlls/ntdll/unix/sync.c | 3 +++ + 3 files changed, 13 insertions(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 81bd29634b1..dfb54c667a8 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -443,6 +443,14 @@ NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, + return create_fsync( type, handle, access, attr, initial, 0xdeadbeef ); + } + ++NTSTATUS fsync_open_event( HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr ) ++{ ++ TRACE("name %s.\n", debugstr_us(attr->ObjectName)); ++ ++ return open_fsync( FSYNC_AUTO_EVENT, handle, access, attr ); ++} ++ + NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) + { + struct event *event; +diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h +index b70851499fe..9a777ef3521 100644 +--- a/dlls/ntdll/unix/fsync.h ++++ b/dlls/ntdll/unix/fsync.h +@@ -29,6 +29,8 @@ extern NTSTATUS fsync_open_semaphore( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr ); + extern NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ); ++extern NTSTATUS fsync_open_event( HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr ); + extern NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ); + extern NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ); + extern NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index d8d7656ddc6..378e2d20989 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -439,6 +439,9 @@ NTSTATUS WINAPI NtOpenEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_AT + *handle = 0; + if ((ret = validate_open_object_attributes( attr ))) return ret; + ++ if (do_fsync()) ++ return fsync_open_event( handle, access, attr ); ++ + if (do_esync()) + return esync_open_event( handle, access, attr ); + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0087-ntdll-Implement-NtOpenMutant.patch b/0007-proton-esync-fsync/0087-ntdll-Implement-NtOpenMutant.patch new file mode 100644 index 0000000..4948044 --- /dev/null +++ b/0007-proton-esync-fsync/0087-ntdll-Implement-NtOpenMutant.patch @@ -0,0 +1,60 @@ +From 8bd2c1692e803b476dc4948e76871cd708b707ad Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sun, 2 Sep 2018 12:06:40 -0500 +Subject: [PATCH 0513/2346] ntdll: Implement NtOpenMutant(). + +--- + dlls/ntdll/unix/fsync.c | 8 ++++++++ + dlls/ntdll/unix/fsync.h | 2 ++ + dlls/ntdll/unix/sync.c | 3 +++ + 3 files changed, 13 insertions(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index dfb54c667a8..383df952e4b 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -498,6 +498,14 @@ NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, + initial ? GetCurrentThreadId() : 0, initial ? 1 : 0 ); + } + ++NTSTATUS fsync_open_mutex( HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr ) ++{ ++ TRACE("name %s.\n", debugstr_us(attr->ObjectName)); ++ ++ return open_fsync( FSYNC_MUTEX, handle, access, attr ); ++} ++ + NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) + { + struct mutex *mutex; +diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h +index 9a777ef3521..0fc2305bd5c 100644 +--- a/dlls/ntdll/unix/fsync.h ++++ b/dlls/ntdll/unix/fsync.h +@@ -35,6 +35,8 @@ extern NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ); + extern NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ); + extern NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ); ++extern NTSTATUS fsync_open_mutex( HANDLE *handle, ACCESS_MASK access, ++ const OBJECT_ATTRIBUTES *attr ); + extern NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ); + + extern NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 378e2d20989..38a5cd5cbb2 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -627,6 +627,9 @@ NTSTATUS WINAPI NtOpenMutant( HANDLE *handle, ACCESS_MASK access, const OBJECT_A + *handle = 0; + if ((ret = validate_open_object_attributes( attr ))) return ret; + ++ if (do_fsync()) ++ return fsync_open_mutex( handle, access, attr ); ++ + if (do_esync()) + return esync_open_mutex( handle, access, attr ); + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0088-server-Implement-fsync_map_access.patch b/0007-proton-esync-fsync/0088-server-Implement-fsync_map_access.patch new file mode 100644 index 0000000..2a6ab52 --- /dev/null +++ b/0007-proton-esync-fsync/0088-server-Implement-fsync_map_access.patch @@ -0,0 +1,50 @@ +From 3caca34611e7f1e30110127c2564522194bc66fb Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sun, 2 Sep 2018 12:07:48 -0500 +Subject: [PATCH 0514/2346] server: Implement fsync_map_access(). + +--- + server/fsync.c | 13 ++++++++++++- + 1 file changed, 12 insertions(+), 1 deletion(-) + +diff --git a/server/fsync.c b/server/fsync.c +index 3fbc1734735..1df3aff91b6 100644 +--- a/server/fsync.c ++++ b/server/fsync.c +@@ -131,6 +131,7 @@ struct fsync + }; + + static void fsync_dump( struct object *obj, int verbose ); ++static unsigned int fsync_map_access( struct object *obj, unsigned int access ); + static void fsync_destroy( struct object *obj ); + + const struct object_ops fsync_ops = +@@ -146,7 +147,7 @@ const struct object_ops fsync_ops = + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +- default_map_access, /* map_access */ ++ fsync_map_access, /* map_access */ + default_get_sd, /* get_sd */ + default_set_sd, /* set_sd */ + default_get_full_name, /* get_full_name */ +@@ -166,6 +167,16 @@ static void fsync_dump( struct object *obj, int verbose ) + fprintf( stderr, "fsync idx=%d\n", fsync->shm_idx ); + } + ++static unsigned int fsync_map_access( struct object *obj, unsigned int access ) ++{ ++ /* Sync objects have the same flags. */ ++ if (access & GENERIC_READ) access |= STANDARD_RIGHTS_READ | EVENT_QUERY_STATE; ++ if (access & GENERIC_WRITE) access |= STANDARD_RIGHTS_WRITE | EVENT_MODIFY_STATE; ++ if (access & GENERIC_EXECUTE) access |= STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE; ++ if (access & GENERIC_ALL) access |= STANDARD_RIGHTS_ALL | EVENT_QUERY_STATE | EVENT_MODIFY_STATE; ++ return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL); ++} ++ + static void fsync_destroy( struct object *obj ) + { + } +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0089-ntdll-server-Implement-handle-duplication.patch b/0007-proton-esync-fsync/0089-ntdll-server-Implement-handle-duplication.patch new file mode 100644 index 0000000..6bc5c1f --- /dev/null +++ b/0007-proton-esync-fsync/0089-ntdll-server-Implement-handle-duplication.patch @@ -0,0 +1,117 @@ +From 13b0b7bdd287d22af1c479b810de3f21872f8b2b Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sun, 2 Sep 2018 12:12:10 -0500 +Subject: [PATCH 0515/2346] ntdll, server: Implement handle duplication. + +--- + dlls/ntdll/unix/fsync.c | 16 ++++++++++------ + server/fsync.c | 10 +++++++++- + 2 files changed, 19 insertions(+), 7 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 383df952e4b..142e3ee284b 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -410,10 +410,11 @@ NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) + struct fsync *obj; + struct semaphore *semaphore; + ULONG current; ++ NTSTATUS ret; + + TRACE("%p, %d, %p.\n", handle, (int)count, prev); + +- if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; ++ if ((ret = get_object( handle, &obj ))) return ret; + semaphore = obj->shm; + + do +@@ -456,10 +457,11 @@ NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) + struct event *event; + struct fsync *obj; + LONG current; ++ NTSTATUS ret; + + TRACE("%p.\n", handle); + +- if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; ++ if ((ret = get_object( handle, &obj ))) return ret; + event = obj->shm; + + if (!(current = __atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST ))) +@@ -475,10 +477,11 @@ NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) + struct event *event; + struct fsync *obj; + LONG current; ++ NTSTATUS ret; + + TRACE("%p.\n", handle); + +- if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; ++ if ((ret = get_object( handle, &obj ))) return ret; + event = obj->shm; + + current = __atomic_exchange_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); +@@ -510,10 +513,11 @@ NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) + { + struct mutex *mutex; + struct fsync *obj; ++ NTSTATUS ret; + + TRACE("%p, %p.\n", handle, prev); + +- if (!(obj = get_cached_object( handle ))) return STATUS_INVALID_HANDLE; ++ if ((ret = get_object( handle, &obj ))) return ret; + mutex = obj->shm; + + if (mutex->tid != GetCurrentThreadId()) return STATUS_MUTANT_NOT_OWNED; +@@ -974,10 +978,10 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an + NTSTATUS fsync_signal_and_wait( HANDLE signal, HANDLE wait, BOOLEAN alertable, + const LARGE_INTEGER *timeout ) + { +- struct fsync *obj = get_cached_object( signal ); ++ struct fsync *obj; + NTSTATUS ret; + +- if (!obj) return STATUS_INVALID_HANDLE; ++ if ((ret = get_object( signal, &obj ))) return ret; + + switch (obj->type) + { +diff --git a/server/fsync.c b/server/fsync.c +index 1df3aff91b6..73d1873759b 100644 +--- a/server/fsync.c ++++ b/server/fsync.c +@@ -131,6 +131,7 @@ struct fsync + }; + + static void fsync_dump( struct object *obj, int verbose ); ++static unsigned int fsync_get_fsync_idx( struct object *obj, enum fsync_type *type ); + static unsigned int fsync_map_access( struct object *obj, unsigned int access ); + static void fsync_destroy( struct object *obj ); + +@@ -143,7 +144,7 @@ const struct object_ops fsync_ops = + NULL, /* remove_queue */ + NULL, /* signaled */ + NULL, /* get_esync_fd */ +- NULL, /* get_fsync_idx */ ++ fsync_get_fsync_idx, /* get_fsync_idx */ + NULL, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -167,6 +168,13 @@ static void fsync_dump( struct object *obj, int verbose ) + fprintf( stderr, "fsync idx=%d\n", fsync->shm_idx ); + } + ++static unsigned int fsync_get_fsync_idx( struct object *obj, enum fsync_type *type) ++{ ++ struct fsync *fsync = (struct fsync *)obj; ++ *type = fsync->type; ++ return fsync->shm_idx; ++} ++ + static unsigned int fsync_map_access( struct object *obj, unsigned int access ) + { + /* Sync objects have the same flags. */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0090-ntdll-server-Implement-alertable-waits.patch b/0007-proton-esync-fsync/0090-ntdll-server-Implement-alertable-waits.patch new file mode 100644 index 0000000..acc555f --- /dev/null +++ b/0007-proton-esync-fsync/0090-ntdll-server-Implement-alertable-waits.patch @@ -0,0 +1,376 @@ +From ee5d96af5e16ce9e0e609a4502d7d1eb3b6198c8 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sun, 2 Sep 2018 13:19:09 -0500 +Subject: [PATCH 0516/2346] ntdll, server: Implement alertable waits. + +--- + dlls/ntdll/unix/fsync.c | 107 +++++++++++++++++++++++++++++---- + dlls/ntdll/unix/unix_private.h | 1 + + dlls/ntdll/unix/virtual.c | 1 + + server/fsync.c | 33 ++++++---- + server/fsync.h | 2 + + server/protocol.def | 5 ++ + server/thread.c | 10 +++ + server/thread.h | 1 + + 8 files changed, 135 insertions(+), 25 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 142e3ee284b..9518f1f0960 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -544,20 +544,53 @@ static LONGLONG update_timeout( ULONGLONG end ) + return timeleft; + } + +-static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end ) ++static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN alertable ) + { + int ret; + +- if (end) ++ if (alertable) + { +- LONGLONG timeleft = update_timeout( *end ); +- struct timespec tmo_p; +- tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; +- tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; +- ret = futex_wait( addr, val, &tmo_p ); ++ struct event *apc_event = get_shm( ntdll_get_thread_data()->fsync_apc_idx ); ++ struct futex_wait_block futexes[2]; ++ ++ if (__atomic_load_n( &apc_event->signaled, __ATOMIC_SEQ_CST )) ++ return STATUS_USER_APC; ++ ++ futexes[0].addr = addr; ++ futexes[0].val = val; ++ futexes[1].addr = &apc_event->signaled; ++ futexes[1].val = 0; ++#if __SIZEOF_POINTER__ == 4 ++ futexes[0].pad = futexes[1].pad = 0; ++#endif ++ ++ if (end) ++ { ++ LONGLONG timeleft = update_timeout( *end ); ++ struct timespec tmo_p; ++ tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; ++ tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; ++ ret = futex_wait_multiple( futexes, 2, &tmo_p ); ++ } ++ else ++ ret = futex_wait_multiple( futexes, 2, NULL ); ++ ++ if (__atomic_load_n( &apc_event->signaled, __ATOMIC_SEQ_CST )) ++ return STATUS_USER_APC; + } + else +- ret = futex_wait( addr, val, NULL ); ++ { ++ if (end) ++ { ++ LONGLONG timeleft = update_timeout( *end ); ++ struct timespec tmo_p; ++ tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; ++ tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; ++ ret = futex_wait( addr, val, &tmo_p ); ++ } ++ else ++ ret = futex_wait( addr, val, NULL ); ++ } + + if (!ret) + return 0; +@@ -570,16 +603,30 @@ static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end ) + static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) + { +- struct futex_wait_block futexes[MAXIMUM_WAIT_OBJECTS]; ++ static const LARGE_INTEGER zero = {0}; ++ ++ struct futex_wait_block futexes[MAXIMUM_WAIT_OBJECTS + 1]; + struct fsync *objs[MAXIMUM_WAIT_OBJECTS]; + int has_fsync = 0, has_server = 0; + BOOL msgwait = FALSE; + int dummy_futex = 0; + LONGLONG timeleft; + LARGE_INTEGER now; ++ DWORD waitcount; + ULONGLONG end; + int i, ret; + ++ /* Grab the APC futex if we don't already have it. */ ++ if (alertable && !ntdll_get_thread_data()->fsync_apc_idx) ++ { ++ SERVER_START_REQ( get_fsync_apc_idx ) ++ { ++ if (!(ret = wine_server_call( req ))) ++ ntdll_get_thread_data()->fsync_apc_idx = reply->shm_idx; ++ } ++ SERVER_END_REQ; ++ } ++ + NtQuerySystemTime( &now ); + if (timeout) + { +@@ -618,6 +665,8 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + + if (msgwait) + TRACE(" or driver events"); ++ if (alertable) ++ TRACE(", alertable"); + + if (!timeout) + TRACE(", timeout = INFINITE.\n"); +@@ -731,6 +780,21 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + #endif + } + ++ if (alertable) ++ { ++ struct event *event = get_shm( ntdll_get_thread_data()->fsync_apc_idx ); ++ if (__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) ++ goto userapc; ++ ++ futexes[i].addr = &event->signaled; ++ futexes[i].val = 0; ++#if __SIZEOF_POINTER__ == 4 ++ futexes[i].pad = 0; ++#endif ++ i++; ++ } ++ waitcount = i; ++ + /* Looks like everything is contended, so wait. */ + + if (timeout) +@@ -740,10 +804,10 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; + tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; + +- ret = futex_wait_multiple( futexes, count, &tmo_p ); ++ ret = futex_wait_multiple( futexes, waitcount, &tmo_p ); + } + else +- ret = futex_wait_multiple( futexes, count, NULL ); ++ ret = futex_wait_multiple( futexes, waitcount, NULL ); + + /* FUTEX_WAIT_MULTIPLE can succeed or return -EINTR, -EAGAIN, + * -EFAULT/-EACCES, -ETIMEDOUT. In the first three cases we need to +@@ -800,7 +864,7 @@ tryagain: + + while ((current = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST ))) + { +- status = do_single_wait( &mutex->tid, current, timeout ? &end : NULL ); ++ status = do_single_wait( &mutex->tid, current, timeout ? &end : NULL, alertable ); + if (status != STATUS_PENDING) + break; + } +@@ -812,7 +876,7 @@ tryagain: + + while (!__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) + { +- status = do_single_wait( &event->signaled, 0, timeout ? &end : NULL ); ++ status = do_single_wait( &event->signaled, 0, timeout ? &end : NULL, alertable ); + if (status != STATUS_PENDING) + break; + } +@@ -823,6 +887,8 @@ tryagain: + TRACE("Wait timed out.\n"); + return status; + } ++ else if (status == STATUS_USER_APC) ++ goto userapc; + } + + /* If we got here and we haven't timed out, that means all of the +@@ -931,6 +997,21 @@ tooslow: + } + } /* while (1) */ + } /* else (wait-all) */ ++ ++ assert(0); /* shouldn't reach here... */ ++ ++userapc: ++ TRACE("Woken up by user APC.\n"); ++ ++ /* We have to make a server call anyway to get the APC to execute, so just ++ * delegate down to server_wait(). */ ++ ret = server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, &zero ); ++ ++ /* This can happen if we received a system APC, and the APC fd was woken up ++ * before we got SIGUSR1. poll() doesn't return EINTR in that case. The ++ * right thing to do seems to be to return STATUS_USER_APC anyway. */ ++ if (ret == STATUS_TIMEOUT) ret = STATUS_USER_APC; ++ return ret; + } + + /* Like esync, we need to let the server know when we are doing a message wait, +diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h +index 48bb596df99..0cef1f0d428 100644 +--- a/dlls/ntdll/unix/unix_private.h ++++ b/dlls/ntdll/unix/unix_private.h +@@ -94,6 +94,7 @@ struct ntdll_thread_data + void *cpu_data[16]; /* reserved for CPU-specific data */ + void *kernel_stack; /* stack for thread startup and kernel syscalls */ + int esync_apc_fd; /* fd to wait on for user APCs */ ++ unsigned int fsync_apc_idx; + int request_fd; /* fd for sending server requests */ + int reply_fd; /* fd for receiving server replies */ + int wait_fd[2]; /* fd for sleeping server requests */ +diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c +index 2309f936f66..5bcfe79dcd6 100644 +--- a/dlls/ntdll/unix/virtual.c ++++ b/dlls/ntdll/unix/virtual.c +@@ -3708,6 +3708,7 @@ static TEB *init_teb( void *ptr, BOOL is_wow ) + teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); + thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch; + thread_data->esync_apc_fd = -1; ++ thread_data->fsync_apc_idx = 0; + thread_data->request_fd = -1; + thread_data->reply_fd = -1; + thread_data->wait_fd[0] = -1; +diff --git a/server/fsync.c b/server/fsync.c +index 73d1873759b..10d8eb74bc3 100644 +--- a/server/fsync.c ++++ b/server/fsync.c +@@ -316,31 +316,35 @@ struct fsync_event + int unused; + }; + ++void fsync_wake_futex( unsigned int shm_idx ) ++{ ++ struct fsync_event *event = get_shm( shm_idx ); ++ ++ if (!__atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST )) ++ futex_wake( &event->signaled, INT_MAX ); ++} ++ + void fsync_wake_up( struct object *obj ) + { +- struct fsync_event *event; + enum fsync_type type; + + if (obj->ops->get_fsync_idx) +- { +- event = get_shm( obj->ops->get_fsync_idx( obj, &type ) ); ++ fsync_wake_futex( obj->ops->get_fsync_idx( obj, &type ) ); ++} + +- if (!__atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST )) +- futex_wake( &event->signaled, INT_MAX ); +- } ++void fsync_clear_futex( unsigned int shm_idx ) ++{ ++ struct fsync_event *event = get_shm( shm_idx ); ++ ++ __atomic_store_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); + } + + void fsync_clear( struct object *obj ) + { +- struct fsync_event *event; + enum fsync_type type; + + if (obj->ops->get_fsync_idx) +- { +- event = get_shm( obj->ops->get_fsync_idx( obj, &type ) ); +- +- __atomic_store_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); +- } ++ fsync_clear_futex( obj->ops->get_fsync_idx( obj, &type ) ); + } + + void fsync_set_event( struct fsync *fsync ) +@@ -447,3 +451,8 @@ DECL_HANDLER(get_fsync_idx) + + release_object( obj ); + } ++ ++DECL_HANDLER(get_fsync_apc_idx) ++{ ++ reply->shm_idx = current->fsync_apc_idx; ++} +diff --git a/server/fsync.h b/server/fsync.h +index 087d482717b..f6f1a48b31e 100644 +--- a/server/fsync.h ++++ b/server/fsync.h +@@ -21,6 +21,8 @@ + extern int do_fsync(void); + extern void fsync_init(void); + extern unsigned int fsync_alloc_shm( int low, int high ); ++extern void fsync_wake_futex( unsigned int shm_idx ); ++extern void fsync_clear_futex( unsigned int shm_idx ); + extern void fsync_wake_up( struct object *obj ); + extern void fsync_clear( struct object *obj ); + +diff --git a/server/protocol.def b/server/protocol.def +index 64734fa0457..916d0b2e2d4 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -4039,3 +4039,8 @@ enum fsync_type + @REQ(fsync_msgwait) + int in_msgwait; /* are we in a message wait? */ + @END ++ ++@REQ(get_fsync_apc_idx) ++@REPLY ++ unsigned int shm_idx; ++@END +diff --git a/server/thread.c b/server/thread.c +index 0ca74e6a7ab..4aaab7c6f54 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -484,7 +484,10 @@ struct thread *create_thread( int fd, struct process *process, const struct secu + } + + if (do_fsync()) ++ { + thread->fsync_idx = fsync_alloc_shm( 0, 0 ); ++ thread->fsync_apc_idx = fsync_alloc_shm( 0, 0 ); ++ } + + if (do_esync()) + { +@@ -661,6 +664,7 @@ static struct thread_apc *create_apc( struct object *owner, const apc_call_t *ca + apc->result.type = APC_NONE; + if (owner) grab_object( owner ); + } ++ + return apc; + } + +@@ -1347,6 +1351,9 @@ static int queue_apc( struct process *process, struct thread *thread, struct thr + { + wake_thread( thread ); + ++ if (do_fsync() && queue == &thread->user_apc) ++ fsync_wake_futex( thread->fsync_apc_idx ); ++ + if (do_esync() && queue == &thread->user_apc) + esync_wake_fd( thread->esync_apc_fd ); + } +@@ -1397,6 +1404,9 @@ static struct thread_apc *thread_dequeue_apc( struct thread *thread, int system + list_remove( ptr ); + } + ++ if (do_fsync() && list_empty( &thread->system_apc ) && list_empty( &thread->user_apc )) ++ fsync_clear_futex( thread->fsync_apc_idx ); ++ + if (do_esync() && list_empty( &thread->system_apc ) && list_empty( &thread->user_apc )) + esync_clear( thread->esync_apc_fd ); + +diff --git a/server/thread.h b/server/thread.h +index ec271f5cab4..041eb000171 100644 +--- a/server/thread.h ++++ b/server/thread.h +@@ -57,6 +57,7 @@ struct thread + int esync_fd; /* esync file descriptor (signalled on exit) */ + int esync_apc_fd; /* esync apc fd (signalled when APCs are present) */ + unsigned int fsync_idx; ++ unsigned int fsync_apc_idx; + unsigned int system_regs; /* which system regs have been set */ + struct msg_queue *queue; /* message queue */ + struct thread_wait *wait; /* current wait condition if sleeping */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0091-ntdll-Wake-all-threads-in-futex_wake.patch b/0007-proton-esync-fsync/0091-ntdll-Wake-all-threads-in-futex_wake.patch new file mode 100644 index 0000000..e42a543 --- /dev/null +++ b/0007-proton-esync-fsync/0091-ntdll-Wake-all-threads-in-futex_wake.patch @@ -0,0 +1,45 @@ +From 45ff80baf4aec0ffa3626cfe8b137fdca01c47b1 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sun, 3 Mar 2019 10:45:10 -0600 +Subject: [PATCH 0517/2346] ntdll: Wake all threads in futex_wake(). + +Because wait-all exists, this unfortunately seems necessary. +--- + dlls/ntdll/unix/fsync.c | 7 +++---- + 1 file changed, 3 insertions(+), 4 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 9518f1f0960..690898f7eac 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -426,8 +426,7 @@ NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) + + if (prev) *prev = current; + +- if (!current) +- futex_wake( &semaphore->count, count ); ++ futex_wake( &semaphore->count, INT_MAX ); + + return STATUS_SUCCESS; + } +@@ -465,7 +464,7 @@ NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) + event = obj->shm; + + if (!(current = __atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST ))) +- futex_wake( &event->signaled, obj->type == FSYNC_AUTO_EVENT ? 1 : INT_MAX ); ++ futex_wake( &event->signaled, INT_MAX ); + + if (prev) *prev = current; + +@@ -527,7 +526,7 @@ NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) + if (!--mutex->count) + { + __atomic_store_n( &mutex->tid, 0, __ATOMIC_SEQ_CST ); +- futex_wake( &mutex->tid, 1 ); ++ futex_wake( &mutex->tid, INT_MAX ); + } + + return STATUS_SUCCESS; +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0092-server-Create-futex-sections-for-timer-objects.patch b/0007-proton-esync-fsync/0092-server-Create-futex-sections-for-timer-objects.patch new file mode 100644 index 0000000..a26ead1 --- /dev/null +++ b/0007-proton-esync-fsync/0092-server-Create-futex-sections-for-timer-objects.patch @@ -0,0 +1,123 @@ +From 80839a14ece945a6e5f69407a18333389a379e60 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sun, 3 Mar 2019 11:02:28 -0600 +Subject: [PATCH 0518/2346] server: Create futex sections for timer objects. + +--- + dlls/ntdll/unix/fsync.c | 3 +++ + server/protocol.def | 1 + + server/timer.c | 18 +++++++++++++++++- + 3 files changed, 21 insertions(+), 1 deletion(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 690898f7eac..f2ae70ee1ab 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -734,6 +734,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + break; + } + case FSYNC_AUTO_EVENT: ++ case FSYNC_AUTO_SERVER: + { + struct event *event = obj->shm; + +@@ -938,6 +939,7 @@ tryagain: + break; + } + case FSYNC_AUTO_EVENT: ++ case FSYNC_AUTO_SERVER: + { + struct event *event = obj->shm; + if (!__sync_val_compare_and_swap( &event->signaled, 1, 0 )) +@@ -984,6 +986,7 @@ tooslow: + break; + } + case FSYNC_AUTO_EVENT: ++ case FSYNC_AUTO_SERVER: + { + struct event *event = obj->shm; + __atomic_store_n( &event->signaled, 1, __ATOMIC_SEQ_CST ); +diff --git a/server/protocol.def b/server/protocol.def +index 916d0b2e2d4..2d91baf245a 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3998,6 +3998,7 @@ enum fsync_type + FSYNC_AUTO_EVENT, + FSYNC_MANUAL_EVENT, + FSYNC_MUTEX, ++ FSYNC_AUTO_SERVER, + FSYNC_MANUAL_SERVER, + FSYNC_QUEUE, + }; +diff --git a/server/timer.c b/server/timer.c +index 9ec9604aa0e..afc12ff03ad 100644 +--- a/server/timer.c ++++ b/server/timer.c +@@ -36,6 +36,7 @@ + #include "handle.h" + #include "request.h" + #include "esync.h" ++#include "fsync.h" + + static const WCHAR timer_name[] = {'T','i','m','e','r'}; + +@@ -63,11 +64,13 @@ struct timer + client_ptr_t callback; /* callback APC function */ + client_ptr_t arg; /* callback argument */ + int esync_fd; /* esync file descriptor */ ++ unsigned int fsync_idx; /* fsync shm index */ + }; + + static void timer_dump( struct object *obj, int verbose ); + static int timer_signaled( struct object *obj, struct wait_queue_entry *entry ); + static int timer_get_esync_fd( struct object *obj, enum esync_type *type ); ++static unsigned int timer_get_fsync_idx( struct object *obj, enum fsync_type *type ); + static void timer_satisfied( struct object *obj, struct wait_queue_entry *entry ); + static void timer_destroy( struct object *obj ); + +@@ -80,7 +83,7 @@ static const struct object_ops timer_ops = + remove_queue, /* remove_queue */ + timer_signaled, /* signaled */ + timer_get_esync_fd, /* get_esync_fd */ +- NULL, /* get_fsync_idx */ ++ timer_get_fsync_idx, /* get_fsync_idx */ + timer_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -117,6 +120,9 @@ static struct timer *create_timer( struct object *root, const struct unicode_str + timer->thread = NULL; + timer->esync_fd = -1; + ++ if (do_fsync()) ++ timer->fsync_idx = fsync_alloc_shm( 0, 0 ); ++ + if (do_esync()) + timer->esync_fd = esync_create_fd( 0, 0 ); + } +@@ -191,6 +197,9 @@ static int set_timer( struct timer *timer, timeout_t expire, unsigned int period + period = 0; /* period doesn't make any sense for a manual timer */ + timer->signaled = 0; + ++ if (do_fsync()) ++ fsync_clear( &timer->obj ); ++ + if (do_esync()) + esync_clear( timer->esync_fd ); + } +@@ -227,6 +236,13 @@ static int timer_get_esync_fd( struct object *obj, enum esync_type *type ) + return timer->esync_fd; + } + ++static unsigned int timer_get_fsync_idx( struct object *obj, enum fsync_type *type ) ++{ ++ struct timer *timer = (struct timer *)obj; ++ *type = timer->manual ? FSYNC_MANUAL_SERVER : FSYNC_AUTO_SERVER; ++ return timer->fsync_idx; ++} ++ + static void timer_satisfied( struct object *obj, struct wait_queue_entry *entry ) + { + struct timer *timer = (struct timer *)obj; +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0093-server-Create-futex-sections-for-console-input-event.patch b/0007-proton-esync-fsync/0093-server-Create-futex-sections-for-console-input-event.patch new file mode 100644 index 0000000..ded25e6 --- /dev/null +++ b/0007-proton-esync-fsync/0093-server-Create-futex-sections-for-console-input-event.patch @@ -0,0 +1,101 @@ +From 412e2c97a72ca36bdc449e3eae97f813591ba25a Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sun, 3 Mar 2019 11:07:55 -0600 +Subject: [PATCH 0519/2346] server: Create futex sections for console input + events objects. + +--- + server/console.c | 22 +++++++++++++++++++++- + 1 file changed, 21 insertions(+), 1 deletion(-) + +diff --git a/server/console.c b/server/console.c +index 43248d359ca..ca1ab046648 100644 +--- a/server/console.c ++++ b/server/console.c +@@ -42,6 +42,7 @@ + #include "winternl.h" + #include "wine/condrv.h" + #include "esync.h" ++#include "fsync.h" + + struct screen_buffer; + +@@ -143,12 +144,14 @@ struct console_server + int term_fd; /* UNIX terminal fd */ + struct termios termios; /* original termios */ + int esync_fd; ++ unsigned int fsync_idx; + }; + + static void console_server_dump( struct object *obj, int verbose ); + static void console_server_destroy( struct object *obj ); + static int console_server_signaled( struct object *obj, struct wait_queue_entry *entry ); + static int console_server_get_esync_fd( struct object *obj, enum esync_type *type ); ++static unsigned int console_server_get_fsync_idx( struct object *obj, enum fsync_type *type ); + static struct fd *console_server_get_fd( struct object *obj ); + static struct object *console_server_lookup_name( struct object *obj, struct unicode_str *name, + unsigned int attr, struct object *root ); +@@ -164,7 +167,7 @@ static const struct object_ops console_server_ops = + remove_queue, /* remove_queue */ + console_server_signaled, /* signaled */ + console_server_get_esync_fd, /* get_esync_fd */ +- NULL, /* get_fsync_idx */ ++ console_server_get_fsync_idx, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + console_server_get_fd, /* get_fd */ +@@ -607,6 +610,8 @@ static void disconnect_console_server( struct console_server *server ) + list_remove( &call->entry ); + console_host_ioctl_terminate( call, STATUS_CANCELLED ); + } ++ if (do_fsync()) ++ fsync_clear( &server->obj ); + if (do_esync()) + esync_clear( server->esync_fd ); + while (!list_empty( &server->read_queue )) +@@ -940,6 +945,13 @@ static int console_server_get_esync_fd( struct object *obj, enum esync_type *typ + return server->esync_fd; + } + ++static unsigned int console_server_get_fsync_idx( struct object *obj, enum fsync_type *type ) ++{ ++ struct console_server *server = (struct console_server*)obj; ++ *type = FSYNC_MANUAL_SERVER; ++ return server->fsync_idx; ++} ++ + static struct fd *console_server_get_fd( struct object* obj ) + { + struct console_server *server = (struct console_server*)obj; +@@ -972,6 +984,10 @@ static struct object *create_console_server( void ) + } + allow_fd_caching(server->fd); + server->esync_fd = -1; ++ server->fsync_idx = 0; ++ ++ if (do_fsync()) ++ server->fsync_idx = fsync_alloc_shm( 0, 0 ); + + if (do_esync()) + server->esync_fd = esync_create_fd( 0, 0 ); +@@ -1588,6 +1604,8 @@ DECL_HANDLER(get_next_console_request) + /* set result of previous ioctl */ + ioctl = LIST_ENTRY( list_head( &server->queue ), struct console_host_ioctl, entry ); + list_remove( &ioctl->entry ); ++ if (do_fsync() && list_empty( &server->queue )) ++ fsync_clear( &server->obj ); + if (do_esync() && list_empty( &server->queue )) + esync_clear( server->esync_fd ); + } +@@ -1675,6 +1693,8 @@ DECL_HANDLER(get_next_console_request) + { + set_error( STATUS_PENDING ); + } ++ if (do_fsync() && list_empty( &server->queue )) ++ fsync_clear( &server->obj ); + if (do_esync() && list_empty( &server->queue )) + esync_clear( server->esync_fd ); + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0094-ntdll-Implement-NtQuerySemaphore.patch b/0007-proton-esync-fsync/0094-ntdll-Implement-NtQuerySemaphore.patch new file mode 100644 index 0000000..6f816fb --- /dev/null +++ b/0007-proton-esync-fsync/0094-ntdll-Implement-NtQuerySemaphore.patch @@ -0,0 +1,70 @@ +From f80e4109a9ab24e921738f2206dfaa8ab786b9bd Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sun, 3 Mar 2019 11:23:23 -0600 +Subject: [PATCH 0520/2346] ntdll: Implement NtQuerySemaphore(). + +--- + dlls/ntdll/unix/fsync.c | 19 +++++++++++++++++++ + dlls/ntdll/unix/fsync.h | 1 + + dlls/ntdll/unix/sync.c | 3 +++ + 3 files changed, 23 insertions(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index f2ae70ee1ab..fb51a55aed7 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -431,6 +431,25 @@ NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) + return STATUS_SUCCESS; + } + ++NTSTATUS fsync_query_semaphore( HANDLE handle, void *info, ULONG *ret_len ) ++{ ++ struct fsync *obj; ++ struct semaphore *semaphore; ++ SEMAPHORE_BASIC_INFORMATION *out = info; ++ NTSTATUS ret; ++ ++ TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len); ++ ++ if ((ret = get_object( handle, &obj ))) return ret; ++ semaphore = obj->shm; ++ ++ out->CurrentCount = semaphore->count; ++ out->MaximumCount = semaphore->max; ++ if (ret_len) *ret_len = sizeof(*out); ++ ++ return STATUS_SUCCESS; ++} ++ + NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, EVENT_TYPE event_type, BOOLEAN initial ) + { +diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h +index 0fc2305bd5c..72a36d4517e 100644 +--- a/dlls/ntdll/unix/fsync.h ++++ b/dlls/ntdll/unix/fsync.h +@@ -27,6 +27,7 @@ extern NTSTATUS fsync_create_semaphore(HANDLE *handle, ACCESS_MASK access, + extern NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ); + extern NTSTATUS fsync_open_semaphore( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr ); ++extern NTSTATUS fsync_query_semaphore( HANDLE handle, void *info, ULONG *ret_len ); + extern NTSTATUS fsync_create_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial ); + extern NTSTATUS fsync_open_event( HANDLE *handle, ACCESS_MASK access, +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 38a5cd5cbb2..cdcb6d8ed79 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -347,6 +347,9 @@ NTSTATUS WINAPI NtQuerySemaphore( HANDLE handle, SEMAPHORE_INFORMATION_CLASS cla + + if (len != sizeof(SEMAPHORE_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH; + ++ if (do_fsync()) ++ return fsync_query_semaphore( handle, info, ret_len ); ++ + if (do_esync()) + return esync_query_semaphore( handle, info, ret_len ); + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0095-ntdll-Implement-NtQueryEvent.patch b/0007-proton-esync-fsync/0095-ntdll-Implement-NtQueryEvent.patch new file mode 100644 index 0000000..b9d39d7 --- /dev/null +++ b/0007-proton-esync-fsync/0095-ntdll-Implement-NtQueryEvent.patch @@ -0,0 +1,70 @@ +From ba93d8006d221c81b43baac7170408f7cc09d036 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 6 Jul 2020 20:11:08 -0500 +Subject: [PATCH 0521/2346] ntdll: Implement NtQueryEvent(). + +--- + dlls/ntdll/unix/fsync.c | 19 +++++++++++++++++++ + dlls/ntdll/unix/fsync.h | 1 + + dlls/ntdll/unix/sync.c | 3 +++ + 3 files changed, 23 insertions(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index fb51a55aed7..3cb8cb50d36 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -509,6 +509,25 @@ NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) + return STATUS_SUCCESS; + } + ++NTSTATUS fsync_query_event( HANDLE handle, void *info, ULONG *ret_len ) ++{ ++ struct event *event; ++ struct fsync *obj; ++ EVENT_BASIC_INFORMATION *out = info; ++ NTSTATUS ret; ++ ++ TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len); ++ ++ if ((ret = get_object( handle, &obj ))) return ret; ++ event = obj->shm; ++ ++ out->EventState = event->signaled; ++ out->EventType = (obj->type == FSYNC_AUTO_EVENT ? SynchronizationEvent : NotificationEvent); ++ if (ret_len) *ret_len = sizeof(*out); ++ ++ return STATUS_SUCCESS; ++} ++ + NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ) + { +diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h +index 72a36d4517e..388ae479eed 100644 +--- a/dlls/ntdll/unix/fsync.h ++++ b/dlls/ntdll/unix/fsync.h +@@ -34,6 +34,7 @@ extern NTSTATUS fsync_open_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr ); + extern NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ); + extern NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ); ++extern NTSTATUS fsync_query_event( HANDLE handle, void *info, ULONG *ret_len ); + extern NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ); + extern NTSTATUS fsync_open_mutex( HANDLE *handle, ACCESS_MASK access, +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index cdcb6d8ed79..355bce64cfd 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -567,6 +567,9 @@ NTSTATUS WINAPI NtQueryEvent( HANDLE handle, EVENT_INFORMATION_CLASS class, + + if (len != sizeof(EVENT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH; + ++ if (do_fsync()) ++ return fsync_query_event( handle, info, ret_len ); ++ + if (do_esync()) + return esync_query_event( handle, info, ret_len ); + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0096-ntdll-Implement-NtQueryMutant.patch b/0007-proton-esync-fsync/0096-ntdll-Implement-NtQueryMutant.patch new file mode 100644 index 0000000..5442b28 --- /dev/null +++ b/0007-proton-esync-fsync/0096-ntdll-Implement-NtQueryMutant.patch @@ -0,0 +1,71 @@ +From a8d3d0b34ce2c40e081101ce483a57e531848913 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sun, 3 Mar 2019 11:29:55 -0600 +Subject: [PATCH 0522/2346] ntdll: Implement NtQueryMutant(). + +--- + dlls/ntdll/unix/fsync.c | 20 ++++++++++++++++++++ + dlls/ntdll/unix/fsync.h | 1 + + dlls/ntdll/unix/sync.c | 3 +++ + 3 files changed, 24 insertions(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 3cb8cb50d36..522803268dc 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -570,6 +570,26 @@ NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) + return STATUS_SUCCESS; + } + ++NTSTATUS fsync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) ++{ ++ struct fsync *obj; ++ struct mutex *mutex; ++ MUTANT_BASIC_INFORMATION *out = info; ++ NTSTATUS ret; ++ ++ TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len); ++ ++ if ((ret = get_object( handle, &obj ))) return ret; ++ mutex = obj->shm; ++ ++ out->CurrentCount = 1 - mutex->count; ++ out->OwnedByCaller = (mutex->tid == GetCurrentThreadId()); ++ out->AbandonedState = FALSE; ++ if (ret_len) *ret_len = sizeof(*out); ++ ++ return STATUS_SUCCESS; ++} ++ + static LONGLONG update_timeout( ULONGLONG end ) + { + LARGE_INTEGER now; +diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h +index 388ae479eed..fe354b39dad 100644 +--- a/dlls/ntdll/unix/fsync.h ++++ b/dlls/ntdll/unix/fsync.h +@@ -40,6 +40,7 @@ extern NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, + extern NTSTATUS fsync_open_mutex( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr ); + extern NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ); ++extern NTSTATUS fsync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ); + + extern NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any, + BOOLEAN alertable, const LARGE_INTEGER *timeout ); +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 355bce64cfd..6b14b04172f 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -697,6 +697,9 @@ NTSTATUS WINAPI NtQueryMutant( HANDLE handle, MUTANT_INFORMATION_CLASS class, + + if (len != sizeof(MUTANT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH; + ++ if (do_fsync()) ++ return fsync_query_mutex( handle, info, ret_len ); ++ + if (do_esync()) + return esync_query_mutex( handle, info, ret_len ); + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0097-server-Create-futex-sections-for-pseudo-fd-objects-a.patch b/0007-proton-esync-fsync/0097-server-Create-futex-sections-for-pseudo-fd-objects-a.patch new file mode 100644 index 0000000..cb9ffea --- /dev/null +++ b/0007-proton-esync-fsync/0097-server-Create-futex-sections-for-pseudo-fd-objects-a.patch @@ -0,0 +1,108 @@ +From 84601dcff9bbb67e77b9525e0317c0a5f0bb0996 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sun, 3 Mar 2019 11:35:22 -0600 +Subject: [PATCH 0523/2346] server: Create futex sections for pseudo-fd objects + and use them for named pipes. + +--- + server/fd.c | 18 ++++++++++++++++++ + server/file.h | 1 + + server/named_pipe.c | 4 ++-- + 3 files changed, 21 insertions(+), 2 deletions(-) + +diff --git a/server/fd.c b/server/fd.c +index acd3789193a..2999e3b7395 100644 +--- a/server/fd.c ++++ b/server/fd.c +@@ -97,6 +97,7 @@ + #include "process.h" + #include "request.h" + #include "esync.h" ++#include "fsync.h" + + #include "winternl.h" + #include "winioctl.h" +@@ -158,6 +159,7 @@ struct fd + apc_param_t comp_key; /* completion key to set in completion events */ + unsigned int comp_flags; /* completion flags */ + int esync_fd; /* esync file descriptor */ ++ unsigned int fsync_idx; /* fsync shm index */ + }; + + static void fd_dump( struct object *obj, int verbose ); +@@ -1748,8 +1750,12 @@ struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *use + list_init( &fd->inode_entry ); + list_init( &fd->locks ); + ++ if (do_fsync()) ++ fd->fsync_idx = fsync_alloc_shm( 0, 0 ); ++ + if (do_esync()) + fd->esync_fd = esync_create_fd( 0, 0 ); ++ + return fd; + } + +@@ -2162,6 +2168,9 @@ void set_fd_signaled( struct fd *fd, int signaled ) + fd->signaled = signaled; + if (signaled) wake_up( fd->user, 0 ); + ++ if (do_fsync() && !signaled) ++ fsync_clear( &fd->obj ); ++ + if (do_esync() && !signaled) + esync_clear( fd->esync_fd ); + } +@@ -2198,6 +2207,15 @@ int default_fd_get_esync_fd( struct object *obj, enum esync_type *type ) + return ret; + } + ++unsigned int default_fd_get_fsync_idx( struct object *obj, enum fsync_type *type ) ++{ ++ struct fd *fd = get_obj_fd( obj ); ++ unsigned int ret = fd->fsync_idx; ++ *type = FSYNC_MANUAL_SERVER; ++ release_object( fd ); ++ return ret; ++} ++ + int default_fd_get_poll_events( struct fd *fd ) + { + int events = 0; +diff --git a/server/file.h b/server/file.h +index fadb3436add..0554ef903dc 100644 +--- a/server/file.h ++++ b/server/file.h +@@ -109,6 +109,7 @@ extern void get_nt_name( struct fd *fd, struct unicode_str *name ); + + extern int default_fd_signaled( struct object *obj, struct wait_queue_entry *entry ); + extern int default_fd_get_esync_fd( struct object *obj, enum esync_type *type ); ++extern unsigned int default_fd_get_fsync_idx( struct object *obj, enum fsync_type *type ); + extern int default_fd_get_poll_events( struct fd *fd ); + extern void default_poll_event( struct fd *fd, int event ); + extern void fd_cancel_async( struct fd *fd, struct async *async ); +diff --git a/server/named_pipe.c b/server/named_pipe.c +index 1a168f0b395..4efa51e2fec 100644 +--- a/server/named_pipe.c ++++ b/server/named_pipe.c +@@ -170,7 +170,7 @@ static const struct object_ops pipe_server_ops = + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ + default_fd_get_esync_fd, /* get_esync_fd */ +- NULL, /* get_fsync_idx */ ++ default_fd_get_fsync_idx, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + pipe_end_get_fd, /* get_fd */ +@@ -216,7 +216,7 @@ static const struct object_ops pipe_client_ops = + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ + default_fd_get_esync_fd, /* get_esync_fd */ +- NULL, /* get_fsync_idx */ ++ default_fd_get_fsync_idx, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + pipe_end_get_fd, /* get_fd */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0098-server-Create-futex-sections-for-true-file-objects-a.patch b/0007-proton-esync-fsync/0098-server-Create-futex-sections-for-true-file-objects-a.patch new file mode 100644 index 0000000..0d1fc60 --- /dev/null +++ b/0007-proton-esync-fsync/0098-server-Create-futex-sections-for-true-file-objects-a.patch @@ -0,0 +1,82 @@ +From f5c817d06cb7dac545a35c790919ef0be3dddfca Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Sun, 3 Mar 2019 11:44:00 -0600 +Subject: [PATCH 0524/2346] server: Create futex sections for true file objects + and use them for directory change notifications. + +--- + server/change.c | 2 +- + server/fd.c | 3 +++ + server/fsync.c | 13 ++++++++++++- + 3 files changed, 16 insertions(+), 2 deletions(-) + +diff --git a/server/change.c b/server/change.c +index 8e19fc4bc2b..22cf041ca80 100644 +--- a/server/change.c ++++ b/server/change.c +@@ -113,7 +113,7 @@ static const struct object_ops dir_ops = + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ + default_fd_get_esync_fd, /* get_esync_fd */ +- NULL, /* get_fsync_idx */ ++ default_fd_get_fsync_idx, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + dir_get_fd, /* get_fd */ +diff --git a/server/fd.c b/server/fd.c +index 2999e3b7395..c85d25e9566 100644 +--- a/server/fd.c ++++ b/server/fd.c +@@ -1708,6 +1708,9 @@ static struct fd *alloc_fd_object(void) + if (do_esync()) + fd->esync_fd = esync_create_fd( 1, 0 ); + ++ if (do_fsync()) ++ fd->fsync_idx = fsync_alloc_shm( 1, 0 ); ++ + if ((fd->poll_index = add_poll_user( fd )) == -1) + { + release_object( fd ); +diff --git a/server/fsync.c b/server/fsync.c +index 10d8eb74bc3..6a67d22d14e 100644 +--- a/server/fsync.c ++++ b/server/fsync.c +@@ -85,6 +85,8 @@ static void **shm_addrs; + static int shm_addrs_size; /* length of the allocated shm_addrs array */ + static long pagesize; + ++static int is_fsync_initialized; ++ + static void shm_cleanup(void) + { + close( shm_fd ); +@@ -120,6 +122,8 @@ void fsync_init(void) + if (ftruncate( shm_fd, shm_size ) == -1) + perror( "ftruncate" ); + ++ is_fsync_initialized = 1; ++ + atexit( shm_cleanup ); + } + +@@ -231,9 +235,16 @@ static unsigned int shm_idx_counter = 1; + unsigned int fsync_alloc_shm( int low, int high ) + { + #ifdef __linux__ +- int shm_idx = shm_idx_counter++; ++ int shm_idx; + int *shm; + ++ /* this is arguably a bit of a hack, but we need some way to prevent ++ * allocating shm for the master socket */ ++ if (!is_fsync_initialized) ++ return 0; ++ ++ shm_idx = shm_idx_counter++; ++ + while (shm_idx * 8 >= shm_size) + { + /* Better expand the shm section. */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0099-ntdll-Skip-zero-length-waits.patch b/0007-proton-esync-fsync/0099-ntdll-Skip-zero-length-waits.patch new file mode 100644 index 0000000..7088d0c --- /dev/null +++ b/0007-proton-esync-fsync/0099-ntdll-Skip-zero-length-waits.patch @@ -0,0 +1,33 @@ +From f4b6716fd72a585a79044d7694f74d6c9164b6a2 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Tue, 4 Jun 2019 12:29:31 -0500 +Subject: [PATCH 0525/2346] ntdll: Skip zero-length waits. + +An optimization that avoids a syscall. +--- + dlls/ntdll/unix/fsync.c | 9 ++++++++- + 1 file changed, 8 insertions(+), 1 deletion(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 522803268dc..30c996a6329 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -855,7 +855,14 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + + /* Looks like everything is contended, so wait. */ + +- if (timeout) ++ if (timeout && !timeout->QuadPart) ++ { ++ /* Unlike esync, we already know that we've timed out, so we ++ * can avoid a syscall. */ ++ TRACE("Wait timed out.\n"); ++ return STATUS_TIMEOUT; ++ } ++ else if (timeout) + { + LONGLONG timeleft = update_timeout( end ); + struct timespec tmo_p; +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0100-server-Add-a-diagnostic-message-for-fsync.patch b/0007-proton-esync-fsync/0100-server-Add-a-diagnostic-message-for-fsync.patch new file mode 100644 index 0000000..bee3603 --- /dev/null +++ b/0007-proton-esync-fsync/0100-server-Add-a-diagnostic-message-for-fsync.patch @@ -0,0 +1,25 @@ +From 4751074016f0b8c514d3d218b56da5679e3fea44 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Thu, 13 Jun 2019 12:58:27 -0500 +Subject: [PATCH 0526/2346] server: Add a diagnostic message for fsync. + +--- + server/fsync.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/server/fsync.c b/server/fsync.c +index 6a67d22d14e..d4dbd66d22a 100644 +--- a/server/fsync.c ++++ b/server/fsync.c +@@ -124,6 +124,8 @@ void fsync_init(void) + + is_fsync_initialized = 1; + ++ fprintf( stderr, "fsync: up and running.\n" ); ++ + atexit( shm_cleanup ); + } + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0101-ntdll-server-Make-extra-sure-that-esync-is-never-use.patch b/0007-proton-esync-fsync/0101-ntdll-server-Make-extra-sure-that-esync-is-never-use.patch new file mode 100644 index 0000000..2335e0c --- /dev/null +++ b/0007-proton-esync-fsync/0101-ntdll-server-Make-extra-sure-that-esync-is-never-use.patch @@ -0,0 +1,56 @@ +From 309c2b741714ef71911cc3a548e09151a662a264 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Thu, 13 Jun 2019 12:59:53 -0500 +Subject: [PATCH 0527/2346] ntdll, server: Make extra sure that esync is never + used if fsync is used. + +--- + dlls/ntdll/unix/esync.c | 3 ++- + server/esync.c | 3 ++- + 2 files changed, 4 insertions(+), 2 deletions(-) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 6eea9d3afc4..7c39f02da50 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -47,6 +47,7 @@ + + #include "unix_private.h" + #include "esync.h" ++#include "fsync.h" + + WINE_DEFAULT_DEBUG_CHANNEL(esync); + +@@ -56,7 +57,7 @@ int do_esync(void) + static int do_esync_cached = -1; + + if (do_esync_cached == -1) +- do_esync_cached = getenv("WINEESYNC") && atoi(getenv("WINEESYNC")); ++ do_esync_cached = getenv("WINEESYNC") && atoi(getenv("WINEESYNC")) && !do_fsync(); + + return do_esync_cached; + #else +diff --git a/server/esync.c b/server/esync.c +index 064bdd61b25..a5164435ed6 100644 +--- a/server/esync.c ++++ b/server/esync.c +@@ -43,6 +43,7 @@ + #include "request.h" + #include "file.h" + #include "esync.h" ++#include "fsync.h" + + int do_esync(void) + { +@@ -50,7 +51,7 @@ int do_esync(void) + static int do_esync_cached = -1; + + if (do_esync_cached == -1) +- do_esync_cached = getenv("WINEESYNC") && atoi(getenv("WINEESYNC")); ++ do_esync_cached = getenv("WINEESYNC") && atoi(getenv("WINEESYNC")) && !do_fsync(); + + return do_esync_cached; + #else +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0102-ntdll-server-Switch-to-testing-ABI.patch b/0007-proton-esync-fsync/0102-ntdll-server-Switch-to-testing-ABI.patch new file mode 100644 index 0000000..81f5b58 --- /dev/null +++ b/0007-proton-esync-fsync/0102-ntdll-server-Switch-to-testing-ABI.patch @@ -0,0 +1,70 @@ +From cdad4e7509affc0e7a098927af730c20a0e85b7d Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Wed, 17 Jul 2019 15:29:04 -0500 +Subject: [PATCH 0528/2346] ntdll, server: Switch to testing ABI. + +--- + dlls/ntdll/unix/fsync.c | 6 +++++- + server/fsync.c | 2 +- + 2 files changed, 6 insertions(+), 2 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 30c996a6329..885633296a4 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -60,13 +60,14 @@ struct futex_wait_block + int pad; + #endif + int val; ++ int bitset; + }; + #include "poppack.h" + + static inline int futex_wait_multiple( const struct futex_wait_block *futexes, + int count, const struct timespec *timeout ) + { +- return syscall( __NR_futex, futexes, 13, count, timeout, 0, 0 ); ++ return syscall( __NR_futex, futexes, 31, count, timeout, 0, 0 ); + } + + static inline int futex_wake( int *addr, int val ) +@@ -620,6 +621,7 @@ static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN aler + #if __SIZEOF_POINTER__ == 4 + futexes[0].pad = futexes[1].pad = 0; + #endif ++ futexes[0].bitset = futexes[1].bitset = ~0; + + if (end) + { +@@ -836,6 +838,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + #if __SIZEOF_POINTER__ == 4 + futexes[i].pad = 0; + #endif ++ futexes[i].bitset = ~0; + } + + if (alertable) +@@ -849,6 +852,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + #if __SIZEOF_POINTER__ == 4 + futexes[i].pad = 0; + #endif ++ futexes[i].bitset = ~0; + i++; + } + waitcount = i; +diff --git a/server/fsync.c b/server/fsync.c +index d4dbd66d22a..2cb804517dc 100644 +--- a/server/fsync.c ++++ b/server/fsync.c +@@ -57,7 +57,7 @@ struct futex_wait_block + static inline int futex_wait_multiple( const struct futex_wait_block *futexes, + int count, const struct timespec *timeout ) + { +- return syscall( __NR_futex, futexes, 13, count, timeout, 0, 0 ); ++ return syscall( __NR_futex, futexes, 31, count, timeout, 0, 0 ); + } + + int do_fsync(void) +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0103-ntdll-Check-the-APC-futex-first.patch b/0007-proton-esync-fsync/0103-ntdll-Check-the-APC-futex-first.patch new file mode 100644 index 0000000..6759011 --- /dev/null +++ b/0007-proton-esync-fsync/0103-ntdll-Check-the-APC-futex-first.patch @@ -0,0 +1,44 @@ +From 67fc77ef3db69ac3bd5fd1fd70a33a2b1dd545b5 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Tue, 23 Jul 2019 17:22:44 -0500 +Subject: [PATCH 0529/2346] ntdll: Check the APC futex first. + +--- + dlls/ntdll/unix/fsync.c | 14 +++++++++++--- + 1 file changed, 11 insertions(+), 3 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 885633296a4..92c8bb4b7ef 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -743,6 +743,16 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + { + /* Try to grab anything. */ + ++ if (alertable) ++ { ++ /* We must check this first! The server may set an event that ++ * we're waiting on, but we need to return STATUS_USER_APC. */ ++ struct event *event = get_shm( ntdll_get_thread_data()->fsync_apc_idx ); ++ TRACE("...%d\n", __atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )); ++ if (__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) ++ goto userapc; ++ } ++ + for (i = 0; i < count; i++) + { + struct fsync *obj = objs[i]; +@@ -844,9 +854,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + if (alertable) + { + struct event *event = get_shm( ntdll_get_thread_data()->fsync_apc_idx ); +- if (__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) +- goto userapc; +- ++ /* We already checked if it was signaled; don't bother doing it again. */ + futexes[i].addr = &event->signaled; + futexes[i].val = 0; + #if __SIZEOF_POINTER__ == 4 +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0104-server-Fix-an-invalid-use-of-fsync_clear.patch b/0007-proton-esync-fsync/0104-server-Fix-an-invalid-use-of-fsync_clear.patch new file mode 100644 index 0000000..e24111f --- /dev/null +++ b/0007-proton-esync-fsync/0104-server-Fix-an-invalid-use-of-fsync_clear.patch @@ -0,0 +1,26 @@ +From 3b7574de68d2479c63a13dafc9f45d0d12d39a83 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Wed, 24 Jul 2019 14:44:15 -0500 +Subject: [PATCH 0530/2346] server: Fix an invalid use of fsync_clear(). + +The fd object has no get_fsync_idx callback, so this would do nothing. +--- + server/fd.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/server/fd.c b/server/fd.c +index c85d25e9566..a5ab3c4c46c 100644 +--- a/server/fd.c ++++ b/server/fd.c +@@ -2172,7 +2172,7 @@ void set_fd_signaled( struct fd *fd, int signaled ) + if (signaled) wake_up( fd->user, 0 ); + + if (do_fsync() && !signaled) +- fsync_clear( &fd->obj ); ++ fsync_clear( fd->user ); + + if (do_esync() && !signaled) + esync_clear( fd->esync_fd ); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0105-server-Be-a-little-more-careful-about-futex-operatio.patch b/0007-proton-esync-fsync/0105-server-Be-a-little-more-careful-about-futex-operatio.patch new file mode 100644 index 0000000..f6f9ccc --- /dev/null +++ b/0007-proton-esync-fsync/0105-server-Be-a-little-more-careful-about-futex-operatio.patch @@ -0,0 +1,91 @@ +From 04f32708472f50717053efe5cb44d7750c203aae Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Wed, 24 Jul 2019 14:45:24 -0500 +Subject: [PATCH 0531/2346] server: Be a little more careful about futex + operations. + +--- + server/fd.c | 2 ++ + server/fsync.c | 24 ++++++++++++++++++++++-- + 2 files changed, 24 insertions(+), 2 deletions(-) + +diff --git a/server/fd.c b/server/fd.c +index a5ab3c4c46c..99b55e863dd 100644 +--- a/server/fd.c ++++ b/server/fd.c +@@ -1699,6 +1699,7 @@ static struct fd *alloc_fd_object(void) + fd->completion = NULL; + fd->comp_flags = 0; + fd->esync_fd = -1; ++ fd->fsync_idx = 0; + init_async_queue( &fd->read_q ); + init_async_queue( &fd->write_q ); + init_async_queue( &fd->wait_q ); +@@ -1747,6 +1748,7 @@ struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *use + fd->comp_flags = 0; + fd->no_fd_status = STATUS_BAD_DEVICE_TYPE; + fd->esync_fd = -1; ++ fd->fsync_idx = 0; + init_async_queue( &fd->read_q ); + init_async_queue( &fd->write_q ); + init_async_queue( &fd->wait_q ); +diff --git a/server/fsync.c b/server/fsync.c +index 2cb804517dc..ca57d7f9cb8 100644 +--- a/server/fsync.c ++++ b/server/fsync.c +@@ -331,8 +331,15 @@ struct fsync_event + + void fsync_wake_futex( unsigned int shm_idx ) + { +- struct fsync_event *event = get_shm( shm_idx ); ++ struct fsync_event *event; + ++ if (debug_level) ++ fprintf( stderr, "fsync_wake_futex: index %u\n", shm_idx ); ++ ++ if (!shm_idx) ++ return; ++ ++ event = get_shm( shm_idx ); + if (!__atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST )) + futex_wake( &event->signaled, INT_MAX ); + } +@@ -341,14 +348,24 @@ void fsync_wake_up( struct object *obj ) + { + enum fsync_type type; + ++ if (debug_level) ++ fprintf( stderr, "fsync_wake_up: object %p\n", obj ); ++ + if (obj->ops->get_fsync_idx) + fsync_wake_futex( obj->ops->get_fsync_idx( obj, &type ) ); + } + + void fsync_clear_futex( unsigned int shm_idx ) + { +- struct fsync_event *event = get_shm( shm_idx ); ++ struct fsync_event *event; + ++ if (debug_level) ++ fprintf( stderr, "fsync_clear_futex: index %u\n", shm_idx ); ++ ++ if (!shm_idx) ++ return; ++ ++ event = get_shm( shm_idx ); + __atomic_store_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); + } + +@@ -356,6 +373,9 @@ void fsync_clear( struct object *obj ) + { + enum fsync_type type; + ++ if (debug_level) ++ fprintf( stderr, "fsync_clear: object %p\n", obj ); ++ + if (obj->ops->get_fsync_idx) + fsync_clear_futex( obj->ops->get_fsync_idx( obj, &type ) ); + } +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0106-ntdll-Catch-closed-handles-more-gracefully.patch b/0007-proton-esync-fsync/0106-ntdll-Catch-closed-handles-more-gracefully.patch new file mode 100644 index 0000000..ea29a0d --- /dev/null +++ b/0007-proton-esync-fsync/0106-ntdll-Catch-closed-handles-more-gracefully.patch @@ -0,0 +1,38 @@ +From acb2dc4d0745f06c1afabae9ef893b988c5eabd7 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Wed, 24 Jul 2019 15:02:01 -0500 +Subject: [PATCH 0532/2346] ntdll: Catch closed handles more gracefully. + +--- + dlls/ntdll/unix/fsync.c | 8 ++++++++ + 1 file changed, 8 insertions(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 92c8bb4b7ef..af0d688b85c 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -759,6 +759,13 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + + if (obj) + { ++ if (!obj->type) /* gcc complains if we put this in the switch */ ++ { ++ /* Someone probably closed an object while waiting on it. */ ++ WARN("Handle %p has type 0; was it closed?\n", handles[i]); ++ return STATUS_INVALID_HANDLE; ++ } ++ + switch (obj->type) + { + case FSYNC_SEMAPHORE: +@@ -835,6 +842,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + break; + } + default: ++ ERR("Invalid type %#x for handle %p.\n", obj->type, handles[i]); + assert(0); + } + } +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0107-ntdll-Implement-fsync_pulse_event.patch b/0007-proton-esync-fsync/0107-ntdll-Implement-fsync_pulse_event.patch new file mode 100644 index 0000000..2330f33 --- /dev/null +++ b/0007-proton-esync-fsync/0107-ntdll-Implement-fsync_pulse_event.patch @@ -0,0 +1,80 @@ +From b7b8e5686dcb535b5667b4ad292ade24764dff70 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Wed, 24 Jul 2019 15:04:08 -0500 +Subject: [PATCH 0533/2346] ntdll: Implement fsync_pulse_event(). + +--- + dlls/ntdll/unix/fsync.c | 29 +++++++++++++++++++++++++++++ + dlls/ntdll/unix/fsync.h | 1 + + dlls/ntdll/unix/sync.c | 3 +++ + 3 files changed, 33 insertions(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index af0d688b85c..feb5fc17100 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -510,6 +510,35 @@ NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) + return STATUS_SUCCESS; + } + ++NTSTATUS fsync_pulse_event( HANDLE handle, LONG *prev ) ++{ ++ struct event *event; ++ struct fsync *obj; ++ LONG current; ++ NTSTATUS ret; ++ ++ TRACE("%p.\n", handle); ++ ++ if ((ret = get_object( handle, &obj ))) return ret; ++ event = obj->shm; ++ ++ /* This isn't really correct; an application could miss the write. ++ * Unfortunately we can't really do much better. Fortunately this is rarely ++ * used (and publicly deprecated). */ ++ if (!(current = __atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST ))) ++ futex_wake( &event->signaled, INT_MAX ); ++ ++ /* Try to give other threads a chance to wake up. Hopefully erring on this ++ * side is the better thing to do... */ ++ NtYieldExecution(); ++ ++ __atomic_store_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); ++ ++ if (prev) *prev = current; ++ ++ return STATUS_SUCCESS; ++} ++ + NTSTATUS fsync_query_event( HANDLE handle, void *info, ULONG *ret_len ) + { + struct event *event; +diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h +index fe354b39dad..763e7891ab8 100644 +--- a/dlls/ntdll/unix/fsync.h ++++ b/dlls/ntdll/unix/fsync.h +@@ -34,6 +34,7 @@ extern NTSTATUS fsync_open_event( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr ); + extern NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ); + extern NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ); ++extern NTSTATUS fsync_pulse_event( HANDLE handle, LONG *prev ); + extern NTSTATUS fsync_query_event( HANDLE handle, void *info, ULONG *ret_len ); + extern NTSTATUS fsync_create_mutex( HANDLE *handle, ACCESS_MASK access, + const OBJECT_ATTRIBUTES *attr, BOOLEAN initial ); +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 6b14b04172f..565c90bac23 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -533,6 +533,9 @@ NTSTATUS WINAPI NtPulseEvent( HANDLE handle, LONG *prev_state ) + { + unsigned int ret; + ++ if (do_fsync()) ++ return fsync_pulse_event( handle, prev_state ); ++ + if (do_esync()) + return esync_pulse_event( handle ); + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0108-server-Print-a-message-when-using-server-side-synchr.patch b/0007-proton-esync-fsync/0108-server-Print-a-message-when-using-server-side-synchr.patch new file mode 100644 index 0000000..aacc55c --- /dev/null +++ b/0007-proton-esync-fsync/0108-server-Print-a-message-when-using-server-side-synchr.patch @@ -0,0 +1,27 @@ +From 70af8770cd425bd8be5f2ddadde6774bfd3cb3e8 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Wed, 31 Jul 2019 12:18:37 -0500 +Subject: [PATCH 0534/2346] server: Print a message when using server-side + synchronization. + +--- + server/main.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/server/main.c b/server/main.c +index 457b044a36a..9559ad83584 100644 +--- a/server/main.c ++++ b/server/main.c +@@ -237,6 +237,9 @@ int main( int argc, char *argv[] ) + if (do_esync()) + esync_init(); + ++ if (!do_fsync() && !do_esync()) ++ fprintf( stderr, "wineserver: using server-side synchronization.\n" ); ++ + if (debug_level) fprintf( stderr, "wineserver: starting (pid=%ld)\n", (long) getpid() ); + set_current_time(); + init_signals(); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0109-ntdll-Store-the-fsync-APC-futex-in-the-thread-data-d.patch b/0007-proton-esync-fsync/0109-ntdll-Store-the-fsync-APC-futex-in-the-thread-data-d.patch new file mode 100644 index 0000000..2db9be9 --- /dev/null +++ b/0007-proton-esync-fsync/0109-ntdll-Store-the-fsync-APC-futex-in-the-thread-data-d.patch @@ -0,0 +1,120 @@ +From ebcf0fac198733d83d27462e05b7d5bbc54043b9 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Wed, 7 Aug 2019 17:07:15 -0500 +Subject: [PATCH 0535/2346] ntdll: Store the fsync APC futex in the thread data + directly. + +Essentially so we can take get_shm() out of any critical paths. +--- + dlls/ntdll/unix/fsync.c | 26 +++++++++++++++----------- + dlls/ntdll/unix/unix_private.h | 2 +- + dlls/ntdll/unix/virtual.c | 2 +- + 3 files changed, 17 insertions(+), 13 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index feb5fc17100..bf3581aa0cd 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -637,15 +637,15 @@ static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN aler + + if (alertable) + { +- struct event *apc_event = get_shm( ntdll_get_thread_data()->fsync_apc_idx ); ++ int *apc_futex = ntdll_get_thread_data()->fsync_apc_futex; + struct futex_wait_block futexes[2]; + +- if (__atomic_load_n( &apc_event->signaled, __ATOMIC_SEQ_CST )) ++ if (__atomic_load_n( apc_futex, __ATOMIC_SEQ_CST )) + return STATUS_USER_APC; + + futexes[0].addr = addr; + futexes[0].val = val; +- futexes[1].addr = &apc_event->signaled; ++ futexes[1].addr = apc_futex; + futexes[1].val = 0; + #if __SIZEOF_POINTER__ == 4 + futexes[0].pad = futexes[1].pad = 0; +@@ -663,7 +663,7 @@ static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN aler + else + ret = futex_wait_multiple( futexes, 2, NULL ); + +- if (__atomic_load_n( &apc_event->signaled, __ATOMIC_SEQ_CST )) ++ if (__atomic_load_n( apc_futex, __ATOMIC_SEQ_CST )) + return STATUS_USER_APC; + } + else +@@ -705,14 +705,21 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + int i, ret; + + /* Grab the APC futex if we don't already have it. */ +- if (alertable && !ntdll_get_thread_data()->fsync_apc_idx) ++ if (alertable && !ntdll_get_thread_data()->fsync_apc_futex) + { ++ unsigned int idx = 0; + SERVER_START_REQ( get_fsync_apc_idx ) + { + if (!(ret = wine_server_call( req ))) +- ntdll_get_thread_data()->fsync_apc_idx = reply->shm_idx; ++ idx = reply->shm_idx; + } + SERVER_END_REQ; ++ ++ if (idx) ++ { ++ struct event *apc_event = get_shm( idx ); ++ ntdll_get_thread_data()->fsync_apc_futex = &apc_event->signaled; ++ } + } + + NtQuerySystemTime( &now ); +@@ -776,9 +783,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + { + /* We must check this first! The server may set an event that + * we're waiting on, but we need to return STATUS_USER_APC. */ +- struct event *event = get_shm( ntdll_get_thread_data()->fsync_apc_idx ); +- TRACE("...%d\n", __atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )); +- if (__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) ++ if (__atomic_load_n( ntdll_get_thread_data()->fsync_apc_futex, __ATOMIC_SEQ_CST )) + goto userapc; + } + +@@ -890,9 +895,8 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + + if (alertable) + { +- struct event *event = get_shm( ntdll_get_thread_data()->fsync_apc_idx ); + /* We already checked if it was signaled; don't bother doing it again. */ +- futexes[i].addr = &event->signaled; ++ futexes[i].addr = ntdll_get_thread_data()->fsync_apc_futex; + futexes[i].val = 0; + #if __SIZEOF_POINTER__ == 4 + futexes[i].pad = 0; +diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h +index 0cef1f0d428..02b77ad220c 100644 +--- a/dlls/ntdll/unix/unix_private.h ++++ b/dlls/ntdll/unix/unix_private.h +@@ -94,7 +94,7 @@ struct ntdll_thread_data + void *cpu_data[16]; /* reserved for CPU-specific data */ + void *kernel_stack; /* stack for thread startup and kernel syscalls */ + int esync_apc_fd; /* fd to wait on for user APCs */ +- unsigned int fsync_apc_idx; ++ int *fsync_apc_futex; + int request_fd; /* fd for sending server requests */ + int reply_fd; /* fd for receiving server replies */ + int wait_fd[2]; /* fd for sleeping server requests */ +diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c +index 5bcfe79dcd6..a2a342e37a2 100644 +--- a/dlls/ntdll/unix/virtual.c ++++ b/dlls/ntdll/unix/virtual.c +@@ -3708,7 +3708,7 @@ static TEB *init_teb( void *ptr, BOOL is_wow ) + teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer); + thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch; + thread_data->esync_apc_fd = -1; +- thread_data->fsync_apc_idx = 0; ++ thread_data->fsync_apc_futex = NULL; + thread_data->request_fd = -1; + thread_data->reply_fd = -1; + thread_data->wait_fd[0] = -1; +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0110-ntdll-fsync-Lock-accessing-the-shm_addrs-array.patch b/0007-proton-esync-fsync/0110-ntdll-fsync-Lock-accessing-the-shm_addrs-array.patch new file mode 100644 index 0000000..6bf6ff8 --- /dev/null +++ b/0007-proton-esync-fsync/0110-ntdll-fsync-Lock-accessing-the-shm_addrs-array.patch @@ -0,0 +1,45 @@ +From 8726895ea032921e6ba8b941b6f0dc16e060140c Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Wed, 7 Aug 2019 17:14:59 -0500 +Subject: [PATCH 0536/2346] ntdll/fsync: Lock accessing the shm_addrs array. + +--- + dlls/ntdll/unix/fsync.c | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index bf3581aa0cd..b2de9354939 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -134,10 +134,15 @@ static void **shm_addrs; + static int shm_addrs_size; /* length of the allocated shm_addrs array */ + static long pagesize; + ++static pthread_mutex_t shm_addrs_mutex = PTHREAD_MUTEX_INITIALIZER; ++ + static void *get_shm( unsigned int idx ) + { + int entry = (idx * 8) / pagesize; + int offset = (idx * 8) % pagesize; ++ void *ret; ++ ++ pthread_mutex_lock( &shm_addrs_mutex ); + + if (entry >= shm_addrs_size) + { +@@ -161,7 +166,11 @@ static void *get_shm( unsigned int idx ) + munmap( addr, pagesize ); /* someone beat us to it */ + } + +- return (void *)((unsigned long)shm_addrs[entry] + offset); ++ ret = (void *)((unsigned long)shm_addrs[entry] + offset); ++ ++ pthread_mutex_unlock( &shm_addrs_mutex ); ++ ++ return ret; + } + + /* We'd like lookup to be fast. To that end, we use a static list indexed by handle. +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0111-ntdll-fsync-Fix-a-race-condition-when-waiting-on-a-m.patch b/0007-proton-esync-fsync/0111-ntdll-fsync-Fix-a-race-condition-when-waiting-on-a-m.patch new file mode 100644 index 0000000..776c516 --- /dev/null +++ b/0007-proton-esync-fsync/0111-ntdll-fsync-Fix-a-race-condition-when-waiting-on-a-m.patch @@ -0,0 +1,43 @@ +From abf1d8429bbdea0a793e23c02aae4a8d589cdc08 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Thu, 8 Aug 2019 17:12:46 -0500 +Subject: [PATCH 0537/2346] ntdll/fsync: Fix a race condition when waiting on a + mutex. + +--- + dlls/ntdll/unix/fsync.c | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index b2de9354939..d3d4a3943e7 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -834,6 +834,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + case FSYNC_MUTEX: + { + struct mutex *mutex = obj->shm; ++ int tid; + + if (mutex->tid == GetCurrentThreadId()) + { +@@ -842,7 +843,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + return i; + } + +- if (!__sync_val_compare_and_swap( &mutex->tid, 0, GetCurrentThreadId() )) ++ if (!(tid = __sync_val_compare_and_swap( &mutex->tid, 0, GetCurrentThreadId() ))) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + mutex->count = 1; +@@ -850,7 +851,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + } + + futexes[i].addr = &mutex->tid; +- futexes[i].val = mutex->tid; ++ futexes[i].val = tid; + break; + } + case FSYNC_AUTO_EVENT: +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0112-ntdll-fsync-Introduce-a-configurable-spin-count.patch b/0007-proton-esync-fsync/0112-ntdll-fsync-Introduce-a-configurable-spin-count.patch new file mode 100644 index 0000000..5f8ea74 --- /dev/null +++ b/0007-proton-esync-fsync/0112-ntdll-fsync-Introduce-a-configurable-spin-count.patch @@ -0,0 +1,147 @@ +From 147c8f0dd4294a3edf5dfe71b03f551ac5b72830 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 19 Aug 2019 18:25:42 -0500 +Subject: [PATCH 0538/2346] ntdll/fsync: Introduce a configurable spin count. + +--- + dlls/ntdll/unix/fsync.c | 68 +++++++++++++++++++++++++++++------------ + 1 file changed, 49 insertions(+), 19 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index d3d4a3943e7..2e633c51792 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -64,6 +64,15 @@ struct futex_wait_block + }; + #include "poppack.h" + ++static inline void small_pause(void) ++{ ++#if defined(__i386__) || defined(__x86_64__) ++ __asm__ __volatile__( "rep;nop" : : : "memory" ); ++#else ++ __asm__ __volatile__( "" : : : "memory" ); ++#endif ++} ++ + static inline int futex_wait_multiple( const struct futex_wait_block *futexes, + int count, const struct timespec *timeout ) + { +@@ -80,6 +89,8 @@ static inline int futex_wait( int *addr, int val, struct timespec *timeout ) + return syscall( __NR_futex, addr, 0, val, timeout, 0, 0 ); + } + ++static unsigned int spincount; ++ + int do_fsync(void) + { + #ifdef __linux__ +@@ -90,6 +101,8 @@ int do_fsync(void) + static const struct timespec zero; + futex_wait_multiple( NULL, 0, &zero ); + do_fsync_cached = getenv("WINEFSYNC") && atoi(getenv("WINEFSYNC")) && errno != ENOSYS; ++ if (getenv("WINEFSYNC_SPINCOUNT")) ++ spincount = atoi(getenv("WINEFSYNC_SPINCOUNT")); + } + + return do_fsync_cached; +@@ -707,6 +720,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + int has_fsync = 0, has_server = 0; + BOOL msgwait = FALSE; + int dummy_futex = 0; ++ unsigned int spin; + LONGLONG timeleft; + LARGE_INTEGER now; + DWORD waitcount; +@@ -816,19 +830,23 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + struct semaphore *semaphore = obj->shm; + int current; + +- do +- { +- if (!(current = semaphore->count)) break; +- } while (__sync_val_compare_and_swap( &semaphore->count, current, current - 1 ) != current); +- +- if (current) ++ /* It would be a little clearer (and less error-prone) ++ * to use a dedicated interlocked_dec_if_nonzero() ++ * helper, but nesting loops like that is probably not ++ * great for performance... */ ++ for (spin = 0; spin <= spincount || current; ++spin) + { +- TRACE("Woken up by handle %p [%d].\n", handles[i], i); +- return i; ++ if ((current = __atomic_load_n( &semaphore->count, __ATOMIC_SEQ_CST )) ++ && __sync_val_compare_and_swap( &semaphore->count, current, current - 1 ) == current) ++ { ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ return i; ++ } ++ small_pause(); + } + + futexes[i].addr = &semaphore->count; +- futexes[i].val = current; ++ futexes[i].val = 0; + break; + } + case FSYNC_MUTEX: +@@ -843,11 +861,15 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + return i; + } + +- if (!(tid = __sync_val_compare_and_swap( &mutex->tid, 0, GetCurrentThreadId() ))) ++ for (spin = 0; spin <= spincount; ++spin) + { +- TRACE("Woken up by handle %p [%d].\n", handles[i], i); +- mutex->count = 1; +- return i; ++ if (!(tid = __sync_val_compare_and_swap( &mutex->tid, 0, GetCurrentThreadId() ))) ++ { ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ mutex->count = 1; ++ return i; ++ } ++ small_pause(); + } + + futexes[i].addr = &mutex->tid; +@@ -859,10 +881,14 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + { + struct event *event = obj->shm; + +- if (__sync_val_compare_and_swap( &event->signaled, 1, 0 )) ++ for (spin = 0; spin <= spincount; ++spin) + { +- TRACE("Woken up by handle %p [%d].\n", handles[i], i); +- return i; ++ if (__sync_val_compare_and_swap( &event->signaled, 1, 0 )) ++ { ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ return i; ++ } ++ small_pause(); + } + + futexes[i].addr = &event->signaled; +@@ -875,10 +901,14 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + { + struct event *event = obj->shm; + +- if (__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) ++ for (spin = 0; spin <= spincount; ++spin) + { +- TRACE("Woken up by handle %p [%d].\n", handles[i], i); +- return i; ++ if (__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) ++ { ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ return i; ++ } ++ small_pause(); + } + + futexes[i].addr = &event->signaled; +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0113-ntdll-server-Abandon-fsync-mutexes-on-thread-exit.patch b/0007-proton-esync-fsync/0113-ntdll-server-Abandon-fsync-mutexes-on-thread-exit.patch new file mode 100644 index 0000000..a05b049 --- /dev/null +++ b/0007-proton-esync-fsync/0113-ntdll-server-Abandon-fsync-mutexes-on-thread-exit.patch @@ -0,0 +1,200 @@ +From 3c8a45c0e3d8e767b1f9b9f0664086c53b367b43 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 17 Feb 2020 11:57:40 -0600 +Subject: [PATCH 0539/2346] ntdll, server: Abandon fsync mutexes on thread + exit. + +--- + dlls/ntdll/unix/fsync.c | 35 ++++++++++++++++++++++++++++------- + server/fsync.c | 33 +++++++++++++++++++++++++++++++++ + server/fsync.h | 1 + + server/thread.c | 2 ++ + 4 files changed, 64 insertions(+), 7 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 2e633c51792..da5245f9e85 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -636,7 +636,7 @@ NTSTATUS fsync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) + + out->CurrentCount = 1 - mutex->count; + out->OwnedByCaller = (mutex->tid == GetCurrentThreadId()); +- out->AbandonedState = FALSE; ++ out->AbandonedState = (mutex->tid == ~0); + if (ret_len) *ret_len = sizeof(*out); + + return STATUS_SUCCESS; +@@ -869,6 +869,12 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + mutex->count = 1; + return i; + } ++ else if (tid == ~0 && (tid = __sync_val_compare_and_swap( &mutex->tid, ~0, GetCurrentThreadId() )) == ~0) ++ { ++ TRACE("Woken up by abandoned mutex %p [%d].\n", handles[i], i); ++ mutex->count = 1; ++ return STATUS_ABANDONED_WAIT_0 + i; ++ } + small_pause(); + } + +@@ -1006,7 +1012,11 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + + while (1) + { ++ BOOL abandoned; ++ + tryagain: ++ abandoned = FALSE; ++ + /* First step: try to wait on each object in sequence. */ + + for (i = 0; i < count; i++) +@@ -1058,11 +1068,9 @@ tryagain: + if (obj && obj->type == FSYNC_MUTEX) + { + struct mutex *mutex = obj->shm; ++ int tid = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST ); + +- if (mutex->tid == GetCurrentThreadId()) +- continue; /* ok */ +- +- if (__atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST )) ++ if (tid && tid != ~0 && tid != GetCurrentThreadId()) + goto tryagain; + } + else if (obj) +@@ -1083,10 +1091,15 @@ tryagain: + case FSYNC_MUTEX: + { + struct mutex *mutex = obj->shm; +- if (mutex->tid == GetCurrentThreadId()) ++ int tid = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST ); ++ if (tid == GetCurrentThreadId()) + break; +- if (__sync_val_compare_and_swap( &mutex->tid, 0, GetCurrentThreadId() )) ++ if (tid && tid != ~0) ++ goto tooslow; ++ if (__sync_val_compare_and_swap( &mutex->tid, tid, GetCurrentThreadId() ) != tid) + goto tooslow; ++ if (tid == ~0) ++ abandoned = TRUE; + break; + } + case FSYNC_SEMAPHORE: +@@ -1122,6 +1135,11 @@ tryagain: + } + } + ++ if (abandoned) ++ { ++ TRACE("Wait successful, but some object(s) were abandoned.\n"); ++ return STATUS_ABANDONED; ++ } + TRACE("Wait successful.\n"); + return STATUS_SUCCESS; + +@@ -1134,6 +1152,9 @@ tooslow: + case FSYNC_MUTEX: + { + struct mutex *mutex = obj->shm; ++ /* HACK: This won't do the right thing with abandoned ++ * mutexes, but fixing it is probably more trouble than ++ * it's worth. */ + __atomic_store_n( &mutex->tid, 0, __ATOMIC_SEQ_CST ); + break; + } +diff --git a/server/fsync.c b/server/fsync.c +index ca57d7f9cb8..3ad59f4735f 100644 +--- a/server/fsync.c ++++ b/server/fsync.c +@@ -129,11 +129,14 @@ void fsync_init(void) + atexit( shm_cleanup ); + } + ++static struct list mutex_list = LIST_INIT(mutex_list); ++ + struct fsync + { + struct object obj; + unsigned int shm_idx; + enum fsync_type type; ++ struct list mutex_entry; + }; + + static void fsync_dump( struct object *obj, int verbose ); +@@ -193,6 +196,9 @@ static unsigned int fsync_map_access( struct object *obj, unsigned int access ) + + static void fsync_destroy( struct object *obj ) + { ++ struct fsync *fsync = (struct fsync *)obj; ++ if (fsync->type == FSYNC_MUTEX) ++ list_remove( &fsync->mutex_entry ); + } + + static void *get_shm( unsigned int idx ) +@@ -297,6 +303,8 @@ struct fsync *create_fsync( struct object *root, const struct unicode_str *name, + + fsync->shm_idx = fsync_alloc_shm( low, high ); + fsync->type = type; ++ if (type == FSYNC_MUTEX) ++ list_add_tail( &mutex_list, &fsync->mutex_entry ); + } + else + { +@@ -397,6 +405,31 @@ void fsync_reset_event( struct fsync *fsync ) + __atomic_store_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); + } + ++struct mutex ++{ ++ int tid; ++ int count; /* recursion count */ ++}; ++ ++void fsync_abandon_mutexes( struct thread *thread ) ++{ ++ struct fsync *fsync; ++ ++ LIST_FOR_EACH_ENTRY( fsync, &mutex_list, struct fsync, mutex_entry ) ++ { ++ struct mutex *mutex = get_shm( fsync->shm_idx ); ++ ++ if (mutex->tid == thread->id) ++ { ++ if (debug_level) ++ fprintf( stderr, "fsync_abandon_mutexes() idx=%d\n", fsync->shm_idx ); ++ mutex->tid = ~0; ++ mutex->count = 0; ++ futex_wake( &mutex->tid, INT_MAX ); ++ } ++ } ++} ++ + DECL_HANDLER(create_fsync) + { + struct fsync *fsync; +diff --git a/server/fsync.h b/server/fsync.h +index f6f1a48b31e..a91939b7f0a 100644 +--- a/server/fsync.h ++++ b/server/fsync.h +@@ -31,3 +31,4 @@ struct fsync; + extern const struct object_ops fsync_ops; + extern void fsync_set_event( struct fsync *fsync ); + extern void fsync_reset_event( struct fsync *fsync ); ++extern void fsync_abandon_mutexes( struct thread *thread ); +diff --git a/server/thread.c b/server/thread.c +index 4aaab7c6f54..3f246f128bf 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -1505,6 +1505,8 @@ void kill_thread( struct thread *thread, int violent_death ) + } + kill_console_processes( thread, 0 ); + abandon_mutexes( thread ); ++ if (do_fsync()) ++ fsync_abandon_mutexes( thread ); + if (do_esync()) + esync_abandon_mutexes( thread ); + wake_up( &thread->obj, 0 ); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0114-ntdll-Default-the-spin-count-to-100.patch b/0007-proton-esync-fsync/0114-ntdll-Default-the-spin-count-to-100.patch new file mode 100644 index 0000000..217b5e0 --- /dev/null +++ b/0007-proton-esync-fsync/0114-ntdll-Default-the-spin-count-to-100.patch @@ -0,0 +1,25 @@ +From 3ed94a67cf5626372e4732b5d58faa8245c15916 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Wed, 18 Mar 2020 20:03:42 -0500 +Subject: [PATCH 0540/2346] ntdll: Default the spin count to 100. + +--- + dlls/ntdll/unix/fsync.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index da5245f9e85..c28b4e27597 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -89,7 +89,7 @@ static inline int futex_wait( int *addr, int val, struct timespec *timeout ) + return syscall( __NR_futex, addr, 0, val, timeout, 0, 0 ); + } + +-static unsigned int spincount; ++static unsigned int spincount = 100; + + int do_fsync(void) + { +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0115-ntdll-Implement-an-esync-fsync-path-for-alertable-Nt.patch b/0007-proton-esync-fsync/0115-ntdll-Implement-an-esync-fsync-path-for-alertable-Nt.patch new file mode 100644 index 0000000..e81f940 --- /dev/null +++ b/0007-proton-esync-fsync/0115-ntdll-Implement-an-esync-fsync-path-for-alertable-Nt.patch @@ -0,0 +1,98 @@ +From 101bee08d73e9c24077c57c07f5f1865f063cfd3 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Fri, 13 Mar 2020 15:52:15 -0500 +Subject: [PATCH 0541/2346] ntdll: Implement an esync/fsync path for alertable + NtDelayExecution(). + +--- + dlls/ntdll/unix/esync.c | 4 ++-- + dlls/ntdll/unix/fsync.c | 6 +++--- + dlls/ntdll/unix/sync.c | 19 ++++++++++++++++++- + 3 files changed, 23 insertions(+), 6 deletions(-) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 7c39f02da50..823e78eaf5a 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -858,7 +858,7 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA + return ret; + } + +- if (objs[count - 1] && objs[count - 1]->type == ESYNC_QUEUE) ++ if (count && objs[count - 1] && objs[count - 1]->type == ESYNC_QUEUE) + msgwait = TRUE; + + if (has_esync && has_server) +@@ -887,7 +887,7 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA + } + } + +- if (wait_any || count == 1) ++ if (wait_any || count <= 1) + { + /* Try to check objects now, so we can obviate poll() at least. */ + for (i = 0; i < count; i++) +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index c28b4e27597..f419e4b826d 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -767,7 +767,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + return ret; + } + +- if (objs[count - 1] && objs[count - 1]->type == FSYNC_QUEUE) ++ if (count && objs[count - 1] && objs[count - 1]->type == FSYNC_QUEUE) + msgwait = TRUE; + + if (has_fsync && has_server) +@@ -796,7 +796,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + } + } + +- if (wait_any || count == 1) ++ if (wait_any || count <= 1) + { + while (1) + { +@@ -1223,7 +1223,7 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an + struct fsync *obj; + NTSTATUS ret; + +- if (!get_object( handles[count - 1], &obj ) && obj->type == FSYNC_QUEUE) ++ if (count && !get_object( handles[count - 1], &obj ) && obj->type == FSYNC_QUEUE) + { + msgwait = TRUE; + server_set_msgwait( 1 ); +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 565c90bac23..388eb2508d9 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -1639,7 +1639,24 @@ NTSTATUS WINAPI NtYieldExecution(void) + NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeout ) + { + /* if alertable, we need to query the server */ +- if (alertable) return server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, timeout ); ++ if (alertable) ++ { ++ if (do_fsync()) ++ { ++ NTSTATUS ret = fsync_wait_objects( 0, NULL, TRUE, TRUE, timeout ); ++ if (ret != STATUS_NOT_IMPLEMENTED) ++ return ret; ++ } ++ ++ if (do_esync()) ++ { ++ NTSTATUS ret = esync_wait_objects( 0, NULL, TRUE, TRUE, timeout ); ++ if (ret != STATUS_NOT_IMPLEMENTED) ++ return ret; ++ } ++ ++ return server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, timeout ); ++ } + + if (!timeout || timeout->QuadPart == TIMEOUT_INFINITE) /* sleep forever */ + { +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0116-esync-fsync-Use-usleep-0-instead-of-NtYieldExecution.patch b/0007-proton-esync-fsync/0116-esync-fsync-Use-usleep-0-instead-of-NtYieldExecution.patch new file mode 100644 index 0000000..719ff87 --- /dev/null +++ b/0007-proton-esync-fsync/0116-esync-fsync-Use-usleep-0-instead-of-NtYieldExecution.patch @@ -0,0 +1,43 @@ +From ea33f2c40f333dc92f12963c98e82fe9c212cf08 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Fri, 25 Jun 2021 23:17:43 +0300 +Subject: [PATCH 0542/2346] esync, fsync: Use usleep(0) instead of + NtYieldExecution() in esync_pulse_event(). + +For Mafia III: Definitive Edition when FPS limit is set. + +CW-Bug-Id: #19024 +--- + dlls/ntdll/unix/esync.c | 2 +- + dlls/ntdll/unix/fsync.c | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 823e78eaf5a..159d25349dc 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -616,7 +616,7 @@ NTSTATUS esync_pulse_event( HANDLE handle ) + + /* Try to give other threads a chance to wake up. Hopefully erring on this + * side is the better thing to do... */ +- NtYieldExecution(); ++ usleep(0); + + read( obj->fd, &value, sizeof(value) ); + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index f419e4b826d..2ee7a1d2cb9 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -552,7 +552,7 @@ NTSTATUS fsync_pulse_event( HANDLE handle, LONG *prev ) + + /* Try to give other threads a chance to wake up. Hopefully erring on this + * side is the better thing to do... */ +- NtYieldExecution(); ++ usleep(0); + + __atomic_store_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0117-ntdll-Call-waitv-just-when-nr_futexes-1.patch b/0007-proton-esync-fsync/0117-ntdll-Call-waitv-just-when-nr_futexes-1.patch new file mode 100644 index 0000000..16edb56 --- /dev/null +++ b/0007-proton-esync-fsync/0117-ntdll-Call-waitv-just-when-nr_futexes-1.patch @@ -0,0 +1,45 @@ +From 739f2c30e002274c25547d7c9f4e782ea5853a8a Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Andr=C3=A9=20Almeida?= +Date: Fri, 27 Nov 2020 14:05:14 -0300 +Subject: [PATCH 0543/2346] ntdll: Call waitv just when nr_futexes > 1 +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +futex_waitv() needs to do an extra copy from userspace compared to +futex(), so use the latter when we are waiting in a single futex. + +Signed-off-by: André Almeida +Link: https://github.com/ValveSoftware/wine/pull/128 +--- + dlls/ntdll/unix/fsync.c | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 2ee7a1d2cb9..54e45d6471a 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -968,10 +968,18 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; + tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; + +- ret = futex_wait_multiple( futexes, waitcount, &tmo_p ); ++ if (waitcount == 1) ++ ret = futex_wait( futexes[0].addr, futexes[0].val, &tmo_p ); ++ else ++ ret = futex_wait_multiple( futexes, waitcount, &tmo_p ); + } + else +- ret = futex_wait_multiple( futexes, waitcount, NULL ); ++ { ++ if (waitcount == 1) ++ ret = futex_wait( futexes[0].addr, futexes[0].val, NULL ); ++ else ++ ret = futex_wait_multiple( futexes, waitcount, NULL ); ++ } + + /* FUTEX_WAIT_MULTIPLE can succeed or return -EINTR, -EAGAIN, + * -EFAULT/-EACCES, -ETIMEDOUT. In the first three cases we need to +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0118-ntdll-fsync-Encapsulate-timeout-conversion.patch b/0007-proton-esync-fsync/0118-ntdll-fsync-Encapsulate-timeout-conversion.patch new file mode 100644 index 0000000..ef3e02e --- /dev/null +++ b/0007-proton-esync-fsync/0118-ntdll-fsync-Encapsulate-timeout-conversion.patch @@ -0,0 +1,164 @@ +From 047de7b795e5a9a73f83ca72ba0bb959ccef9423 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Andr=C3=A9=20Almeida?= +Date: Wed, 20 Oct 2021 10:35:58 -0300 +Subject: [PATCH 0544/2346] ntdll/fsync: Encapsulate timeout conversion +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Simplify the wait path by dealing with the timeout conversion +inside of futex_wait. + +Signed-off-by: André Almeida +Link: https://github.com/ValveSoftware/wine/pull/128 +--- + dlls/ntdll/unix/fsync.c | 94 ++++++++++++++++++----------------------- + 1 file changed, 42 insertions(+), 52 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 54e45d6471a..9d09bd1555a 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -73,10 +73,32 @@ static inline void small_pause(void) + #endif + } + ++static LONGLONG update_timeout( ULONGLONG end ) ++{ ++ LARGE_INTEGER now; ++ LONGLONG timeleft; ++ ++ NtQuerySystemTime( &now ); ++ timeleft = end - now.QuadPart; ++ if (timeleft < 0) timeleft = 0; ++ return timeleft; ++} ++ + static inline int futex_wait_multiple( const struct futex_wait_block *futexes, +- int count, const struct timespec *timeout ) ++ int count, const ULONGLONG *end ) + { +- return syscall( __NR_futex, futexes, 31, count, timeout, 0, 0 ); ++ if (end) ++ { ++ LONGLONG timeleft = update_timeout( *end ); ++ struct timespec timeout; ++ timeout.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; ++ timeout.tv_nsec = (timeleft % TICKSPERSEC) * 100; ++ return syscall( __NR_futex, futexes, 31, count, timeout, 0, 0 ); ++ } ++ else ++ { ++ return syscall( __NR_futex, futexes, 31, count, NULL, 0, 0 ); ++ } + } + + static inline int futex_wake( int *addr, int val ) +@@ -84,9 +106,20 @@ static inline int futex_wake( int *addr, int val ) + return syscall( __NR_futex, addr, 1, val, NULL, 0, 0 ); + } + +-static inline int futex_wait( int *addr, int val, struct timespec *timeout ) ++static inline int futex_wait( int *addr, int val, const ULONGLONG *end ) + { +- return syscall( __NR_futex, addr, 0, val, timeout, 0, 0 ); ++ if (end) ++ { ++ LONGLONG timeleft = update_timeout( *end ); ++ struct timespec timeout; ++ timeout.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; ++ timeout.tv_nsec = (timeleft % TICKSPERSEC) * 100; ++ return syscall( __NR_futex, addr, 0, val, &timeout, 0, 0 ); ++ } ++ else ++ { ++ return syscall( __NR_futex, addr, 0, val, NULL, 0, 0 ); ++ } + } + + static unsigned int spincount = 100; +@@ -642,17 +675,6 @@ NTSTATUS fsync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) + return STATUS_SUCCESS; + } + +-static LONGLONG update_timeout( ULONGLONG end ) +-{ +- LARGE_INTEGER now; +- LONGLONG timeleft; +- +- NtQuerySystemTime( &now ); +- timeleft = end - now.QuadPart; +- if (timeleft < 0) timeleft = 0; +- return timeleft; +-} +- + static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN alertable ) + { + int ret; +@@ -674,32 +696,14 @@ static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN aler + #endif + futexes[0].bitset = futexes[1].bitset = ~0; + +- if (end) +- { +- LONGLONG timeleft = update_timeout( *end ); +- struct timespec tmo_p; +- tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; +- tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; +- ret = futex_wait_multiple( futexes, 2, &tmo_p ); +- } +- else +- ret = futex_wait_multiple( futexes, 2, NULL ); ++ ret = futex_wait_multiple( futexes, 2, end ); + + if (__atomic_load_n( apc_futex, __ATOMIC_SEQ_CST )) + return STATUS_USER_APC; + } + else + { +- if (end) +- { +- LONGLONG timeleft = update_timeout( *end ); +- struct timespec tmo_p; +- tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; +- tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; +- ret = futex_wait( addr, val, &tmo_p ); +- } +- else +- ret = futex_wait( addr, val, NULL ); ++ ret = futex_wait( addr, val, end ); + } + + if (!ret) +@@ -961,25 +965,11 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + TRACE("Wait timed out.\n"); + return STATUS_TIMEOUT; + } +- else if (timeout) +- { +- LONGLONG timeleft = update_timeout( end ); +- struct timespec tmo_p; +- tmo_p.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; +- tmo_p.tv_nsec = (timeleft % TICKSPERSEC) * 100; + +- if (waitcount == 1) +- ret = futex_wait( futexes[0].addr, futexes[0].val, &tmo_p ); +- else +- ret = futex_wait_multiple( futexes, waitcount, &tmo_p ); +- } ++ if (waitcount == 1) ++ ret = futex_wait( futexes[0].addr, futexes[0].val, timeout ? &end : NULL ); + else +- { +- if (waitcount == 1) +- ret = futex_wait( futexes[0].addr, futexes[0].val, NULL ); +- else +- ret = futex_wait_multiple( futexes, waitcount, NULL ); +- } ++ ret = futex_wait_multiple( futexes, waitcount, timeout ? &end : NULL ); + + /* FUTEX_WAIT_MULTIPLE can succeed or return -EINTR, -EAGAIN, + * -EFAULT/-EACCES, -ETIMEDOUT. In the first three cases we need to +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0119-ntdll-fsync-Support-futex_waitv-API.patch b/0007-proton-esync-fsync/0119-ntdll-fsync-Support-futex_waitv-API.patch new file mode 100644 index 0000000..ae81268 --- /dev/null +++ b/0007-proton-esync-fsync/0119-ntdll-fsync-Support-futex_waitv-API.patch @@ -0,0 +1,270 @@ +From 6887e2c14b6d549d407827e01a8ca96ec06a1311 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Andr=C3=A9=20Almeida?= +Date: Thu, 21 Oct 2021 13:36:14 -0300 +Subject: [PATCH 0545/2346] ntdll/fsync: Support futex_waitv() API +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Since an interface for wait on multiple futexes was merged, we no longer +need to support different interfaces. Drop out FUTEX_WAIT_MULTIPLE +(opcode 31) in favor of the futex_waitv() interface accepted by +upstream Linux. + +Signed-off-by: André Almeida +Link: https://github.com/ValveSoftware/wine/pull/128 +--- + dlls/ntdll/unix/fsync.c | 101 ++++++++++++++++++++-------------------- + server/fsync.c | 19 ++------ + 2 files changed, 55 insertions(+), 65 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 9d09bd1555a..c72c4be6774 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -39,6 +39,7 @@ + # include + #endif + #include ++#include + + #include "ntstatus.h" + #define WIN32_NO_STATUS +@@ -53,16 +54,30 @@ + WINE_DEFAULT_DEBUG_CHANNEL(fsync); + + #include "pshpack4.h" +-struct futex_wait_block +-{ +- int *addr; +-#if __SIZEOF_POINTER__ == 4 +- int pad; ++#include "poppack.h" ++ ++/* futex_waitv interface */ ++ ++#ifndef __NR_futex_waitv ++ ++# define __NR_futex_waitv 449 ++# define FUTEX_32 2 ++struct futex_waitv { ++ uint64_t val; ++ uint64_t uaddr; ++ uint32_t flags; ++ uint32_t __reserved; ++}; ++ + #endif +- int val; +- int bitset; ++ ++#define u64_to_ptr(x) (void *)(uintptr_t)(x) ++ ++struct timespec64 ++{ ++ long long tv_sec; ++ long long tv_nsec; + }; +-#include "poppack.h" + + static inline void small_pause(void) + { +@@ -84,20 +99,29 @@ static LONGLONG update_timeout( ULONGLONG end ) + return timeleft; + } + +-static inline int futex_wait_multiple( const struct futex_wait_block *futexes, ++static inline void futex_vector_set( struct futex_waitv *waitv, int *addr, int val ) ++{ ++ waitv->uaddr = (uintptr_t) addr; ++ waitv->val = val; ++ waitv->flags = FUTEX_32; ++ waitv->__reserved = 0; ++} ++ ++static inline int futex_wait_multiple( const struct futex_waitv *futexes, + int count, const ULONGLONG *end ) + { + if (end) + { +- LONGLONG timeleft = update_timeout( *end ); +- struct timespec timeout; +- timeout.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; +- timeout.tv_nsec = (timeleft % TICKSPERSEC) * 100; +- return syscall( __NR_futex, futexes, 31, count, timeout, 0, 0 ); ++ struct timespec64 timeout; ++ ULONGLONG tmp = *end - SECS_1601_TO_1970 * TICKSPERSEC; ++ timeout.tv_sec = tmp / (ULONGLONG)TICKSPERSEC; ++ timeout.tv_nsec = (tmp % TICKSPERSEC) * 100; ++ ++ return syscall( __NR_futex_waitv, futexes, count, 0, &timeout, CLOCK_REALTIME ); + } + else + { +- return syscall( __NR_futex, futexes, 31, count, NULL, 0, 0 ); ++ return syscall( __NR_futex_waitv, futexes, count, 0, NULL, 0 ); + } + } + +@@ -131,8 +155,7 @@ int do_fsync(void) + + if (do_fsync_cached == -1) + { +- static const struct timespec zero; +- futex_wait_multiple( NULL, 0, &zero ); ++ syscall( __NR_futex_waitv, NULL, 0, 0, NULL, 0 ); + do_fsync_cached = getenv("WINEFSYNC") && atoi(getenv("WINEFSYNC")) && errno != ENOSYS; + if (getenv("WINEFSYNC_SPINCOUNT")) + spincount = atoi(getenv("WINEFSYNC_SPINCOUNT")); +@@ -682,19 +705,13 @@ static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN aler + if (alertable) + { + int *apc_futex = ntdll_get_thread_data()->fsync_apc_futex; +- struct futex_wait_block futexes[2]; ++ struct futex_waitv futexes[2]; + + if (__atomic_load_n( apc_futex, __ATOMIC_SEQ_CST )) + return STATUS_USER_APC; + +- futexes[0].addr = addr; +- futexes[0].val = val; +- futexes[1].addr = apc_futex; +- futexes[1].val = 0; +-#if __SIZEOF_POINTER__ == 4 +- futexes[0].pad = futexes[1].pad = 0; +-#endif +- futexes[0].bitset = futexes[1].bitset = ~0; ++ futex_vector_set( &futexes[0], addr, val ); ++ futex_vector_set( &futexes[1], apc_futex, 0 ); + + ret = futex_wait_multiple( futexes, 2, end ); + +@@ -719,7 +736,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + { + static const LARGE_INTEGER zero = {0}; + +- struct futex_wait_block futexes[MAXIMUM_WAIT_OBJECTS + 1]; ++ struct futex_waitv futexes[MAXIMUM_WAIT_OBJECTS + 1]; + struct fsync *objs[MAXIMUM_WAIT_OBJECTS]; + int has_fsync = 0, has_server = 0; + BOOL msgwait = FALSE; +@@ -849,8 +866,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + small_pause(); + } + +- futexes[i].addr = &semaphore->count; +- futexes[i].val = 0; ++ futex_vector_set( &futexes[i], &semaphore->count, 0 ); + break; + } + case FSYNC_MUTEX: +@@ -882,8 +898,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + small_pause(); + } + +- futexes[i].addr = &mutex->tid; +- futexes[i].val = tid; ++ futex_vector_set( &futexes[i], &mutex->tid, tid ); + break; + } + case FSYNC_AUTO_EVENT: +@@ -901,8 +916,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + small_pause(); + } + +- futexes[i].addr = &event->signaled; +- futexes[i].val = 0; ++ futex_vector_set( &futexes[i], &event->signaled, 0 ); + break; + } + case FSYNC_MANUAL_EVENT: +@@ -921,8 +935,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + small_pause(); + } + +- futexes[i].addr = &event->signaled; +- futexes[i].val = 0; ++ futex_vector_set( &futexes[i], &event->signaled, 0 ); + break; + } + default: +@@ -933,26 +946,14 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + else + { + /* Avoid breaking things entirely. */ +- futexes[i].addr = &dummy_futex; +- futexes[i].val = dummy_futex; ++ futex_vector_set( &futexes[i], &dummy_futex, dummy_futex ); + } +- +-#if __SIZEOF_POINTER__ == 4 +- futexes[i].pad = 0; +-#endif +- futexes[i].bitset = ~0; + } + + if (alertable) + { + /* We already checked if it was signaled; don't bother doing it again. */ +- futexes[i].addr = ntdll_get_thread_data()->fsync_apc_futex; +- futexes[i].val = 0; +-#if __SIZEOF_POINTER__ == 4 +- futexes[i].pad = 0; +-#endif +- futexes[i].bitset = ~0; +- i++; ++ futex_vector_set( &futexes[i++], ntdll_get_thread_data()->fsync_apc_futex, 0 ); + } + waitcount = i; + +@@ -967,7 +968,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + } + + if (waitcount == 1) +- ret = futex_wait( futexes[0].addr, futexes[0].val, timeout ? &end : NULL ); ++ ret = futex_wait( u64_to_ptr(futexes[0].uaddr), futexes[0].val, timeout ? &end : NULL ); + else + ret = futex_wait_multiple( futexes, waitcount, timeout ? &end : NULL ); + +diff --git a/server/fsync.c b/server/fsync.c +index 3ad59f4735f..593070ad62e 100644 +--- a/server/fsync.c ++++ b/server/fsync.c +@@ -44,21 +44,11 @@ + #include "fsync.h" + + #include "pshpack4.h" +-struct futex_wait_block +-{ +- int *addr; +-#if __SIZEOF_POINTER__ == 4 +- int pad; +-#endif +- int val; +-}; + #include "poppack.h" + +-static inline int futex_wait_multiple( const struct futex_wait_block *futexes, +- int count, const struct timespec *timeout ) +-{ +- return syscall( __NR_futex, futexes, 31, count, timeout, 0, 0 ); +-} ++#ifndef __NR_futex_waitv ++#define __NR_futex_waitv 449 ++#endif + + int do_fsync(void) + { +@@ -67,8 +57,7 @@ int do_fsync(void) + + if (do_fsync_cached == -1) + { +- static const struct timespec zero; +- futex_wait_multiple( NULL, 0, &zero ); ++ syscall( __NR_futex_waitv, 0, 0, 0, 0, 0); + do_fsync_cached = getenv("WINEFSYNC") && atoi(getenv("WINEFSYNC")) && errno != ENOSYS; + } + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0120-ntdll-fsync-Use-absolute-timeouts-for-futex_wait.patch b/0007-proton-esync-fsync/0120-ntdll-fsync-Use-absolute-timeouts-for-futex_wait.patch new file mode 100644 index 0000000..06c99e9 --- /dev/null +++ b/0007-proton-esync-fsync/0120-ntdll-fsync-Use-absolute-timeouts-for-futex_wait.patch @@ -0,0 +1,54 @@ +From e269c18092ff4653bf4b00433bb22a2abab0d303 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Andr=C3=A9=20Almeida?= +Date: Thu, 21 Oct 2021 20:33:58 -0300 +Subject: [PATCH 0546/2346] ntdll/fsync: Use absolute timeouts for futex_wait +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Use the FUTEX_WAIT_BITSET operation instead of FUTEX_WAIT, that allow us +to use absolute timeouts rather than relative ones that requires an +extra syscall to update the timeout. + +Signed-off-by: André Almeida +Link: https://github.com/ValveSoftware/wine/pull/128 +--- + dlls/ntdll/unix/fsync.c | 14 ++++++++++---- + 1 file changed, 10 insertions(+), 4 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index c72c4be6774..66e2b6a6841 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -56,6 +56,10 @@ WINE_DEFAULT_DEBUG_CHANNEL(fsync); + #include "pshpack4.h" + #include "poppack.h" + ++#define FUTEX_WAIT_BITSET 9 ++#define FUTEX_CLOCK_REALTIME 256 ++#define FUTEX_BITSET_MATCH_ANY 0xffffffff ++ + /* futex_waitv interface */ + + #ifndef __NR_futex_waitv +@@ -134,11 +138,13 @@ static inline int futex_wait( int *addr, int val, const ULONGLONG *end ) + { + if (end) + { +- LONGLONG timeleft = update_timeout( *end ); + struct timespec timeout; +- timeout.tv_sec = timeleft / (ULONGLONG)TICKSPERSEC; +- timeout.tv_nsec = (timeleft % TICKSPERSEC) * 100; +- return syscall( __NR_futex, addr, 0, val, &timeout, 0, 0 ); ++ ULONGLONG tmp = *end - SECS_1601_TO_1970 * TICKSPERSEC; ++ timeout.tv_sec = tmp / (ULONGLONG)TICKSPERSEC; ++ timeout.tv_nsec = (tmp % TICKSPERSEC) * 100; ++ ++ return syscall( __NR_futex, addr, FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME, ++ val, &timeout, 0, FUTEX_BITSET_MATCH_ANY ); + } + else + { +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0121-esync-fsync-Yield-execution-before-alertable-wait-fo.patch b/0007-proton-esync-fsync/0121-esync-fsync-Yield-execution-before-alertable-wait-fo.patch new file mode 100644 index 0000000..03fbf75 --- /dev/null +++ b/0007-proton-esync-fsync/0121-esync-fsync-Yield-execution-before-alertable-wait-fo.patch @@ -0,0 +1,123 @@ +From d4710b8803f37df06ede73da5b42daa1d72600de Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Thu, 1 Apr 2021 20:19:35 +0300 +Subject: [PATCH 0547/2346] esync, fsync: Yield execution before alertable wait + for AC Odyssey. + +CW-Bug-ID: #18881 +--- + dlls/ntdll/unix/esync.c | 11 +++++++++++ + dlls/ntdll/unix/fsync.c | 9 +++++++++ + dlls/ntdll/unix/loader.c | 8 ++++++++ + dlls/ntdll/unix/unix_private.h | 2 ++ + 4 files changed, 30 insertions(+) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 159d25349dc..12d7f7e4938 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -947,6 +947,8 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA + + if (event->signaled) + { ++ if (ac_odyssey && alertable) ++ usleep( 0 ); + if ((size = read( obj->fd, &value, sizeof(value) )) == sizeof(value)) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); +@@ -962,6 +964,12 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA + + if (event->signaled) + { ++ if (ac_odyssey && alertable) ++ { ++ usleep( 0 ); ++ if (!event->signaled) ++ break; ++ } + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + return i; + } +@@ -990,6 +998,9 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA + + while (1) + { ++ if (ac_odyssey && alertable) ++ usleep( 0 ); ++ + ret = do_poll( fds, pollcount, timeout ? &end : NULL ); + if (ret > 0) + { +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 66e2b6a6841..65fc9d2ac81 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -916,6 +916,9 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + { + if (__sync_val_compare_and_swap( &event->signaled, 1, 0 )) + { ++ if (ac_odyssey && alertable) ++ usleep( 0 ); ++ + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + return i; + } +@@ -935,6 +938,9 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + { + if (__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) + { ++ if (ac_odyssey && alertable) ++ usleep( 0 ); ++ + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + return i; + } +@@ -965,6 +971,9 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + + /* Looks like everything is contended, so wait. */ + ++ if (ac_odyssey && alertable) ++ usleep( 0 ); ++ + if (timeout && !timeout->QuadPart) + { + /* Unlike esync, we already know that we've timed out, so we +diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c +index 0712ddd3fdf..f9ec5504310 100644 +--- a/dlls/ntdll/unix/loader.c ++++ b/dlls/ntdll/unix/loader.c +@@ -1920,10 +1920,18 @@ static ULONG_PTR get_image_address(void) + return 0; + } + ++BOOL ac_odyssey; ++ + static void hacks_init(void) + { + const char *sgi = getenv( "SteamGameId" ); + ++ if (main_argc > 1 && strstr(main_argv[1], "ACOdyssey.exe")) ++ { ++ ERR("HACK: AC Odyssey sync tweak on.\n"); ++ ac_odyssey = TRUE; ++ } ++ + switch (sgi ? atoi( sgi ) : -1) + { + case 25700: /* Madballs in Babo: Invasion */ +diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h +index 02b77ad220c..61d94a16edc 100644 +--- a/dlls/ntdll/unix/unix_private.h ++++ b/dlls/ntdll/unix/unix_private.h +@@ -178,6 +178,8 @@ extern SYSTEM_CPU_INFORMATION cpu_info; + extern struct ldt_copy __wine_ldt_copy; + #endif + ++extern BOOL ac_odyssey; ++ + extern void init_environment(void); + extern void init_startup_info(void); + extern void *create_startup_info( const UNICODE_STRING *nt_image, ULONG process_flags, +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0122-fsync-Add-WINE_FSYNC_SIMULATE_SCHED_QUANTUM-config-o.patch b/0007-proton-esync-fsync/0122-fsync-Add-WINE_FSYNC_SIMULATE_SCHED_QUANTUM-config-o.patch new file mode 100644 index 0000000..79d73a5 --- /dev/null +++ b/0007-proton-esync-fsync/0122-fsync-Add-WINE_FSYNC_SIMULATE_SCHED_QUANTUM-config-o.patch @@ -0,0 +1,138 @@ +From 643ba36eeb0efde55fb722c0fcfaabed4cc6330d Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Tue, 15 Feb 2022 17:20:40 +0300 +Subject: [PATCH 0549/2346] fsync: Add WINE_FSYNC_SIMULATE_SCHED_QUANTUM config + option. + +And auto enable it for Uplay laucher. + +CW-Bug-Id: #20155 +--- + dlls/ntdll/unix/fsync.c | 17 ++++++++++++++++- + dlls/ntdll/unix/loader.c | 9 +++++++++ + dlls/ntdll/unix/unix_private.h | 1 + + 3 files changed, 26 insertions(+), 1 deletion(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 65fc9d2ac81..193bd37e6b8 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -111,6 +111,15 @@ static inline void futex_vector_set( struct futex_waitv *waitv, int *addr, int v + waitv->__reserved = 0; + } + ++static void simulate_sched_quantum(void) ++{ ++ if (!fsync_simulate_sched_quantum) return; ++ /* futex wait is often very quick to resume a waiting thread when woken. ++ * That reveals synchonization bugs in some games which happen to work on ++ * Windows due to the waiting threads having some minimal delay to wake up. */ ++ usleep(0); ++} ++ + static inline int futex_wait_multiple( const struct futex_waitv *futexes, + int count, const ULONGLONG *end ) + { +@@ -744,8 +753,8 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + + struct futex_waitv futexes[MAXIMUM_WAIT_OBJECTS + 1]; + struct fsync *objs[MAXIMUM_WAIT_OBJECTS]; ++ BOOL msgwait = FALSE, waited = FALSE; + int has_fsync = 0, has_server = 0; +- BOOL msgwait = FALSE; + int dummy_futex = 0; + unsigned int spin; + LONGLONG timeleft; +@@ -867,6 +876,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + && __sync_val_compare_and_swap( &semaphore->count, current, current - 1 ) == current) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ if (waited) simulate_sched_quantum(); + return i; + } + small_pause(); +@@ -884,6 +894,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + mutex->count++; ++ if (waited) simulate_sched_quantum(); + return i; + } + +@@ -893,6 +904,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + mutex->count = 1; ++ if (waited) simulate_sched_quantum(); + return i; + } + else if (tid == ~0 && (tid = __sync_val_compare_and_swap( &mutex->tid, ~0, GetCurrentThreadId() )) == ~0) +@@ -920,6 +932,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + usleep( 0 ); + + TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ if (waited) simulate_sched_quantum(); + return i; + } + small_pause(); +@@ -942,6 +955,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + usleep( 0 ); + + TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ if (waited) simulate_sched_quantum(); + return i; + } + small_pause(); +@@ -996,6 +1010,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + TRACE("Wait timed out.\n"); + return STATUS_TIMEOUT; + } ++ else waited = TRUE; + } /* while (1) */ + } + else +diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c +index f9ec5504310..c1d7ff801d4 100644 +--- a/dlls/ntdll/unix/loader.c ++++ b/dlls/ntdll/unix/loader.c +@@ -1921,16 +1921,25 @@ static ULONG_PTR get_image_address(void) + } + + BOOL ac_odyssey; ++BOOL fsync_simulate_sched_quantum; + + static void hacks_init(void) + { + const char *sgi = getenv( "SteamGameId" ); ++ const char *env_str; + + if (main_argc > 1 && strstr(main_argv[1], "ACOdyssey.exe")) + { + ERR("HACK: AC Odyssey sync tweak on.\n"); + ac_odyssey = TRUE; + } ++ env_str = getenv("WINE_FSYNC_SIMULATE_SCHED_QUANTUM"); ++ if (env_str) ++ fsync_simulate_sched_quantum = !!atoi(env_str); ++ else if (main_argc > 1) ++ fsync_simulate_sched_quantum = !!strstr(main_argv[1], "Ubisoft Game Launcher\\upc.exe"); ++ if (fsync_simulate_sched_quantum) ++ ERR("HACK: Simulating sched quantum in fsync.\n"); + + switch (sgi ? atoi( sgi ) : -1) + { +diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h +index 61d94a16edc..cc5f1ffc9e0 100644 +--- a/dlls/ntdll/unix/unix_private.h ++++ b/dlls/ntdll/unix/unix_private.h +@@ -179,6 +179,7 @@ extern struct ldt_copy __wine_ldt_copy; + #endif + + extern BOOL ac_odyssey; ++extern BOOL fsync_simulate_sched_quantum; + + extern void init_environment(void); + extern void init_startup_info(void); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0123-esync-Type-check-HANDLE-in-esync_set_event.patch b/0007-proton-esync-fsync/0123-esync-Type-check-HANDLE-in-esync_set_event.patch new file mode 100644 index 0000000..52dd8cb --- /dev/null +++ b/0007-proton-esync-fsync/0123-esync-Type-check-HANDLE-in-esync_set_event.patch @@ -0,0 +1,27 @@ +From ed9f17f61a935059d143f6b8d9bad59328f5a608 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Wed, 2 Feb 2022 17:02:44 -0500 +Subject: [PATCH 0550/2346] esync: Type-check HANDLE in esync_set_event. + +Signed-off-by: Derek Lesho +--- + dlls/ntdll/unix/esync.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 12d7f7e4938..7b85981cd77 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -525,6 +525,9 @@ NTSTATUS esync_set_event( HANDLE handle ) + if ((ret = get_object( handle, &obj ))) return ret; + event = obj->shm; + ++ if (obj->type != ESYNC_MANUAL_EVENT && obj->type != ESYNC_AUTO_EVENT) ++ return STATUS_OBJECT_TYPE_MISMATCH; ++ + if (obj->type == ESYNC_MANUAL_EVENT) + { + /* Acquire the spinlock. */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0124-fsync-Type-check-HANDLE-in-fsync_set_event.patch b/0007-proton-esync-fsync/0124-fsync-Type-check-HANDLE-in-fsync_set_event.patch new file mode 100644 index 0000000..f7ce93c --- /dev/null +++ b/0007-proton-esync-fsync/0124-fsync-Type-check-HANDLE-in-fsync_set_event.patch @@ -0,0 +1,27 @@ +From d86b58e1f5a54a267dabfbfc75dafb93a1678b40 Mon Sep 17 00:00:00 2001 +From: Derek Lesho +Date: Mon, 14 Feb 2022 12:51:27 -0500 +Subject: [PATCH 0551/2346] fsync: Type-check HANDLE in fsync_set_event(). + +Signed-off-by: Derek Lesho +--- + dlls/ntdll/unix/fsync.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 193bd37e6b8..f9b75fd2faf 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -576,6 +576,9 @@ NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) + if ((ret = get_object( handle, &obj ))) return ret; + event = obj->shm; + ++ if (obj->type != FSYNC_MANUAL_EVENT && obj->type != FSYNC_AUTO_EVENT) ++ return STATUS_OBJECT_TYPE_MISMATCH; ++ + if (!(current = __atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST ))) + futex_wake( &event->signaled, INT_MAX ); + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0125-fsync-Fix-semaphore-grab-attempt-on-wait-all-path.patch b/0007-proton-esync-fsync/0125-fsync-Fix-semaphore-grab-attempt-on-wait-all-path.patch new file mode 100644 index 0000000..0bda42c --- /dev/null +++ b/0007-proton-esync-fsync/0125-fsync-Fix-semaphore-grab-attempt-on-wait-all-path.patch @@ -0,0 +1,29 @@ +From a1a7dae41fd7225b10eef5cbd88aebbf95293af3 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Fri, 18 Feb 2022 12:56:58 +0300 +Subject: [PATCH 0552/2346] fsync: Fix semaphore grab attempt on wait all path. + +CW-Bug-Id: #20189 +--- + dlls/ntdll/unix/fsync.c | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index f9b75fd2faf..321a6b5a79a 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -1137,7 +1137,10 @@ tryagain: + case FSYNC_SEMAPHORE: + { + struct semaphore *semaphore = obj->shm; +- if (__sync_fetch_and_sub( &semaphore->count, 1 ) <= 0) ++ int current; ++ ++ if (!(current = __atomic_load_n( &semaphore->count, __ATOMIC_SEQ_CST )) ++ || __sync_val_compare_and_swap( &semaphore->count, current, current - 1 ) != current) + goto tooslow; + break; + } +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0126-fsync-Always-check-for-NULL-object-on-wait-all-path.patch b/0007-proton-esync-fsync/0126-fsync-Always-check-for-NULL-object-on-wait-all-path.patch new file mode 100644 index 0000000..ed9c5e5 --- /dev/null +++ b/0007-proton-esync-fsync/0126-fsync-Always-check-for-NULL-object-on-wait-all-path.patch @@ -0,0 +1,34 @@ +From a96aa91aa785a90ce0a05b9b8247b180dfdfc392 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Fri, 18 Feb 2022 12:58:53 +0300 +Subject: [PATCH 0553/2346] fsync: Always check for NULL object on wait all + path. + +CW-Bug-Id: #20189 +--- + dlls/ntdll/unix/fsync.c | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 321a6b5a79a..c386b748430 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -1118,6 +1118,7 @@ tryagain: + for (i = 0; i < count; i++) + { + struct fsync *obj = objs[i]; ++ if (!obj) continue; + switch (obj->type) + { + case FSYNC_MUTEX: +@@ -1182,6 +1183,7 @@ tooslow: + for (--i; i >= 0; i--) + { + struct fsync *obj = objs[i]; ++ if (!obj) continue; + switch (obj->type) + { + case FSYNC_MUTEX: +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0127-fsync-Get-rid-of-spin-before-futex-wait.patch b/0007-proton-esync-fsync/0127-fsync-Get-rid-of-spin-before-futex-wait.patch new file mode 100644 index 0000000..0ea66aa --- /dev/null +++ b/0007-proton-esync-fsync/0127-fsync-Get-rid-of-spin-before-futex-wait.patch @@ -0,0 +1,186 @@ +From 8cbe7c2daf202e909ab8dfe3d7078668a1ec868b Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Fri, 18 Feb 2022 13:04:01 +0300 +Subject: [PATCH 0554/2346] fsync: Get rid of spin before futex wait. + +CW-Bug-Id: #20189 +--- + dlls/ntdll/unix/fsync.c | 99 +++++++++++++---------------------------- + 1 file changed, 31 insertions(+), 68 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index c386b748430..dc974a7e4d1 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -83,15 +83,6 @@ struct timespec64 + long long tv_nsec; + }; + +-static inline void small_pause(void) +-{ +-#if defined(__i386__) || defined(__x86_64__) +- __asm__ __volatile__( "rep;nop" : : : "memory" ); +-#else +- __asm__ __volatile__( "" : : : "memory" ); +-#endif +-} +- + static LONGLONG update_timeout( ULONGLONG end ) + { + LARGE_INTEGER now; +@@ -153,7 +144,7 @@ static inline int futex_wait( int *addr, int val, const ULONGLONG *end ) + timeout.tv_nsec = (tmp % TICKSPERSEC) * 100; + + return syscall( __NR_futex, addr, FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME, +- val, &timeout, 0, FUTEX_BITSET_MATCH_ANY ); ++ val, &timeout, 0, FUTEX_BITSET_MATCH_ANY ); + } + else + { +@@ -161,8 +152,6 @@ static inline int futex_wait( int *addr, int val, const ULONGLONG *end ) + } + } + +-static unsigned int spincount = 100; +- + int do_fsync(void) + { + #ifdef __linux__ +@@ -172,8 +161,6 @@ int do_fsync(void) + { + syscall( __NR_futex_waitv, NULL, 0, 0, NULL, 0 ); + do_fsync_cached = getenv("WINEFSYNC") && atoi(getenv("WINEFSYNC")) && errno != ENOSYS; +- if (getenv("WINEFSYNC_SPINCOUNT")) +- spincount = atoi(getenv("WINEFSYNC_SPINCOUNT")); + } + + return do_fsync_cached; +@@ -759,7 +746,6 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + BOOL msgwait = FALSE, waited = FALSE; + int has_fsync = 0, has_server = 0; + int dummy_futex = 0; +- unsigned int spin; + LONGLONG timeleft; + LARGE_INTEGER now; + DWORD waitcount; +@@ -869,22 +855,13 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + struct semaphore *semaphore = obj->shm; + int current; + +- /* It would be a little clearer (and less error-prone) +- * to use a dedicated interlocked_dec_if_nonzero() +- * helper, but nesting loops like that is probably not +- * great for performance... */ +- for (spin = 0; spin <= spincount || current; ++spin) ++ if ((current = __atomic_load_n( &semaphore->count, __ATOMIC_SEQ_CST )) ++ && __sync_val_compare_and_swap( &semaphore->count, current, current - 1 ) == current) + { +- if ((current = __atomic_load_n( &semaphore->count, __ATOMIC_SEQ_CST )) +- && __sync_val_compare_and_swap( &semaphore->count, current, current - 1 ) == current) +- { +- TRACE("Woken up by handle %p [%d].\n", handles[i], i); +- if (waited) simulate_sched_quantum(); +- return i; +- } +- small_pause(); ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ if (waited) simulate_sched_quantum(); ++ return i; + } +- + futex_vector_set( &futexes[i], &semaphore->count, 0 ); + break; + } +@@ -901,22 +878,18 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + return i; + } + +- for (spin = 0; spin <= spincount; ++spin) ++ if (!(tid = __sync_val_compare_and_swap( &mutex->tid, 0, GetCurrentThreadId() ))) + { +- if (!(tid = __sync_val_compare_and_swap( &mutex->tid, 0, GetCurrentThreadId() ))) +- { +- TRACE("Woken up by handle %p [%d].\n", handles[i], i); +- mutex->count = 1; +- if (waited) simulate_sched_quantum(); +- return i; +- } +- else if (tid == ~0 && (tid = __sync_val_compare_and_swap( &mutex->tid, ~0, GetCurrentThreadId() )) == ~0) +- { +- TRACE("Woken up by abandoned mutex %p [%d].\n", handles[i], i); +- mutex->count = 1; +- return STATUS_ABANDONED_WAIT_0 + i; +- } +- small_pause(); ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ mutex->count = 1; ++ if (waited) simulate_sched_quantum(); ++ return i; ++ } ++ else if (tid == ~0 && (tid = __sync_val_compare_and_swap( &mutex->tid, ~0, GetCurrentThreadId() )) == ~0) ++ { ++ TRACE("Woken up by abandoned mutex %p [%d].\n", handles[i], i); ++ mutex->count = 1; ++ return STATUS_ABANDONED_WAIT_0 + i; + } + + futex_vector_set( &futexes[i], &mutex->tid, tid ); +@@ -927,20 +900,15 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + { + struct event *event = obj->shm; + +- for (spin = 0; spin <= spincount; ++spin) ++ if (__sync_val_compare_and_swap( &event->signaled, 1, 0 )) + { +- if (__sync_val_compare_and_swap( &event->signaled, 1, 0 )) +- { +- if (ac_odyssey && alertable) +- usleep( 0 ); +- +- TRACE("Woken up by handle %p [%d].\n", handles[i], i); +- if (waited) simulate_sched_quantum(); +- return i; +- } +- small_pause(); +- } ++ if (ac_odyssey && alertable) ++ usleep( 0 ); + ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ if (waited) simulate_sched_quantum(); ++ return i; ++ } + futex_vector_set( &futexes[i], &event->signaled, 0 ); + break; + } +@@ -950,20 +918,15 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + { + struct event *event = obj->shm; + +- for (spin = 0; spin <= spincount; ++spin) ++ if (__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) + { +- if (__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) +- { +- if (ac_odyssey && alertable) +- usleep( 0 ); +- +- TRACE("Woken up by handle %p [%d].\n", handles[i], i); +- if (waited) simulate_sched_quantum(); +- return i; +- } +- small_pause(); +- } ++ if (ac_odyssey && alertable) ++ usleep( 0 ); + ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ if (waited) simulate_sched_quantum(); ++ return i; ++ } + futex_vector_set( &futexes[i], &event->signaled, 0 ); + break; + } +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0128-fsync-Always-use-futex_waitv-for-wait.patch b/0007-proton-esync-fsync/0128-fsync-Always-use-futex_waitv-for-wait.patch new file mode 100644 index 0000000..a3f31a0 --- /dev/null +++ b/0007-proton-esync-fsync/0128-fsync-Always-use-futex_waitv-for-wait.patch @@ -0,0 +1,95 @@ +From 1c16b590a1c97bce8822450d16928af7e62db4be Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Fri, 18 Feb 2022 12:46:59 +0300 +Subject: [PATCH 0555/2346] fsync: Always use futex_waitv for wait. + +CW-Bug-Id: #20189 +--- + dlls/ntdll/unix/fsync.c | 34 +++++----------------------------- + 1 file changed, 5 insertions(+), 29 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index dc974a7e4d1..64eed0c1e23 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -56,10 +56,6 @@ WINE_DEFAULT_DEBUG_CHANNEL(fsync); + #include "pshpack4.h" + #include "poppack.h" + +-#define FUTEX_WAIT_BITSET 9 +-#define FUTEX_CLOCK_REALTIME 256 +-#define FUTEX_BITSET_MATCH_ANY 0xffffffff +- + /* futex_waitv interface */ + + #ifndef __NR_futex_waitv +@@ -134,24 +130,6 @@ static inline int futex_wake( int *addr, int val ) + return syscall( __NR_futex, addr, 1, val, NULL, 0, 0 ); + } + +-static inline int futex_wait( int *addr, int val, const ULONGLONG *end ) +-{ +- if (end) +- { +- struct timespec timeout; +- ULONGLONG tmp = *end - SECS_1601_TO_1970 * TICKSPERSEC; +- timeout.tv_sec = tmp / (ULONGLONG)TICKSPERSEC; +- timeout.tv_nsec = (tmp % TICKSPERSEC) * 100; +- +- return syscall( __NR_futex, addr, FUTEX_WAIT_BITSET | FUTEX_CLOCK_REALTIME, +- val, &timeout, 0, FUTEX_BITSET_MATCH_ANY ); +- } +- else +- { +- return syscall( __NR_futex, addr, 0, val, NULL, 0, 0 ); +- } +-} +- + int do_fsync(void) + { + #ifdef __linux__ +@@ -705,17 +683,18 @@ NTSTATUS fsync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) + + static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN alertable ) + { ++ struct futex_waitv futexes[2]; + int ret; + ++ futex_vector_set( &futexes[0], addr, val ); ++ + if (alertable) + { + int *apc_futex = ntdll_get_thread_data()->fsync_apc_futex; +- struct futex_waitv futexes[2]; + + if (__atomic_load_n( apc_futex, __ATOMIC_SEQ_CST )) + return STATUS_USER_APC; + +- futex_vector_set( &futexes[0], addr, val ); + futex_vector_set( &futexes[1], apc_futex, 0 ); + + ret = futex_wait_multiple( futexes, 2, end ); +@@ -725,7 +704,7 @@ static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN aler + } + else + { +- ret = futex_wait( addr, val, end ); ++ ret = futex_wait_multiple( futexes, 1, end ); + } + + if (!ret) +@@ -962,10 +941,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + return STATUS_TIMEOUT; + } + +- if (waitcount == 1) +- ret = futex_wait( u64_to_ptr(futexes[0].uaddr), futexes[0].val, timeout ? &end : NULL ); +- else +- ret = futex_wait_multiple( futexes, waitcount, timeout ? &end : NULL ); ++ ret = futex_wait_multiple( futexes, waitcount, timeout ? &end : NULL ); + + /* FUTEX_WAIT_MULTIPLE can succeed or return -EINTR, -EAGAIN, + * -EFAULT/-EACCES, -ETIMEDOUT. In the first three cases we need to +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0129-ntdll-Include-linux-futex.h-in-fsync.c.patch b/0007-proton-esync-fsync/0129-ntdll-Include-linux-futex.h-in-fsync.c.patch new file mode 100644 index 0000000..5386984 --- /dev/null +++ b/0007-proton-esync-fsync/0129-ntdll-Include-linux-futex.h-in-fsync.c.patch @@ -0,0 +1,39 @@ +From a925f31546de8f3137a3e2711579e985c6f3bca0 Mon Sep 17 00:00:00 2001 +From: Zebediah Figura +Date: Mon, 21 Feb 2022 12:32:49 -0600 +Subject: [PATCH 0556/2346] ntdll: Include linux/futex.h in fsync.c. + +--- + configure.ac | 1 + + dlls/ntdll/unix/fsync.c | 3 +++ + 2 files changed, 4 insertions(+) + +diff --git a/configure.ac b/configure.ac +index 45ae883ddc6..c1564565c0f 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -424,6 +424,7 @@ AC_CHECK_HEADERS(\ + link.h \ + linux/cdrom.h \ + linux/filter.h \ ++ linux/futex.h \ + linux/hdreg.h \ + linux/hidraw.h \ + linux/input.h \ +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 64eed0c1e23..f620b5caff8 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -38,6 +38,9 @@ + #ifdef HAVE_SYS_SYSCALL_H + # include + #endif ++#ifdef HAVE_LINUX_FUTEX_H ++# include ++#endif + #include + #include + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0130-fsync-Reuse-shared-mem-indices.patch b/0007-proton-esync-fsync/0130-fsync-Reuse-shared-mem-indices.patch new file mode 100644 index 0000000..13f03a6 --- /dev/null +++ b/0007-proton-esync-fsync/0130-fsync-Reuse-shared-mem-indices.patch @@ -0,0 +1,290 @@ +From be971cfd3e49ec4ce2b736b7479a03f7a2f1cb3b Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Wed, 27 Apr 2022 15:52:53 -0500 +Subject: [PATCH 0557/2346] fsync: Reuse shared mem indices. + +CW-Bug-Id: #20560 +--- + server/console.c | 1 + + server/device.c | 2 ++ + server/event.c | 2 ++ + server/fd.c | 1 + + server/fsync.c | 66 +++++++++++++++++++++++++++++++++++++++++++++--- + server/fsync.h | 1 + + server/process.c | 1 + + server/queue.c | 1 + + server/thread.c | 7 +++++ + server/timer.c | 2 ++ + 10 files changed, 81 insertions(+), 3 deletions(-) + +diff --git a/server/console.c b/server/console.c +index ca1ab046648..9084e5a3828 100644 +--- a/server/console.c ++++ b/server/console.c +@@ -897,6 +897,7 @@ static void console_server_destroy( struct object *obj ) + disconnect_console_server( server ); + if (server->fd) release_object( server->fd ); + if (do_esync()) close( server->esync_fd ); ++ if (server->fsync_idx) fsync_free_shm_idx( server->fsync_idx ); + } + + static struct object *console_server_lookup_name( struct object *obj, struct unicode_str *name, +diff --git a/server/device.c b/server/device.c +index 90e0a0c1fee..7e9911efb6a 100644 +--- a/server/device.c ++++ b/server/device.c +@@ -853,6 +853,7 @@ static void device_manager_destroy( struct object *obj ) + + if (do_esync()) + close( manager->esync_fd ); ++ if (manager->fsync_idx) fsync_free_shm_idx( manager->fsync_idx ); + } + + static struct device_manager *create_device_manager(void) +@@ -865,6 +866,7 @@ static struct device_manager *create_device_manager(void) + list_init( &manager->devices ); + list_init( &manager->requests ); + wine_rb_init( &manager->kernel_objects, compare_kernel_object ); ++ manager->fsync_idx = 0; + + if (do_fsync()) + manager->fsync_idx = fsync_alloc_shm( 0, 0 ); +diff --git a/server/event.c b/server/event.c +index aa1b0a4002a..b93a9960ad2 100644 +--- a/server/event.c ++++ b/server/event.c +@@ -161,6 +161,7 @@ struct event *create_event( struct object *root, const struct unicode_str *name, + list_init( &event->kernel_object ); + event->manual_reset = manual_reset; + event->signaled = initial_state; ++ event->fsync_idx = 0; + + if (do_fsync()) + event->fsync_idx = fsync_alloc_shm( initial_state, 0 ); +@@ -300,6 +301,7 @@ static void event_destroy( struct object *obj ) + + if (do_esync()) + close( event->esync_fd ); ++ if (event->fsync_idx) fsync_free_shm_idx( event->fsync_idx ); + } + + struct keyed_event *create_keyed_event( struct object *root, const struct unicode_str *name, +diff --git a/server/fd.c b/server/fd.c +index 99b55e863dd..d18ed4fc8e4 100644 +--- a/server/fd.c ++++ b/server/fd.c +@@ -1580,6 +1580,7 @@ static void fd_destroy( struct object *obj ) + + if (do_esync()) + close( fd->esync_fd ); ++ if (fd->fsync_idx) fsync_free_shm_idx( fd->fsync_idx ); + } + + /* check if the desired access is possible without violating */ +diff --git a/server/fsync.c b/server/fsync.c +index 593070ad62e..3c1e709d7e3 100644 +--- a/server/fsync.c ++++ b/server/fsync.c +@@ -26,6 +26,7 @@ + #include + #include + #include ++#include + #ifdef HAVE_SYS_STAT_H + # include + #endif +@@ -76,6 +77,12 @@ static long pagesize; + + static int is_fsync_initialized; + ++static uint64_t *shm_idx_free_map; ++static uint32_t shm_idx_free_map_size; /* uint64_t word count */ ++static uint32_t shm_idx_free_search_start_hint; ++ ++#define BITS_IN_FREE_MAP_WORD (8 * sizeof(*shm_idx_free_map)) ++ + static void shm_cleanup(void) + { + close( shm_fd ); +@@ -115,6 +122,11 @@ void fsync_init(void) + + fprintf( stderr, "fsync: up and running.\n" ); + ++ shm_idx_free_map_size = 256; ++ shm_idx_free_map = malloc( shm_idx_free_map_size * sizeof(*shm_idx_free_map) ); ++ memset( shm_idx_free_map, 0xff, shm_idx_free_map_size * sizeof(*shm_idx_free_map) ); ++ shm_idx_free_map[0] &= ~(uint64_t)1; /* Avoid allocating shm_index 0. */ ++ + atexit( shm_cleanup ); + } + +@@ -188,6 +200,7 @@ static void fsync_destroy( struct object *obj ) + struct fsync *fsync = (struct fsync *)obj; + if (fsync->type == FSYNC_MUTEX) + list_remove( &fsync->mutex_entry ); ++ fsync_free_shm_idx( fsync->shm_idx ); + } + + static void *get_shm( unsigned int idx ) +@@ -226,12 +239,22 @@ static void *get_shm( unsigned int idx ) + return (void *)((unsigned long)shm_addrs[entry] + offset); + } + +-/* FIXME: This is rather inefficient... */ +-static unsigned int shm_idx_counter = 1; ++static int alloc_shm_idx_from_word( unsigned int word_index ) ++{ ++ int ret; ++ ++ if (!shm_idx_free_map[word_index]) return 0; ++ ++ ret = __builtin_ctzll( shm_idx_free_map[word_index] ); ++ shm_idx_free_map[word_index] &= ~((uint64_t)1 << ret); ++ shm_idx_free_search_start_hint = shm_idx_free_map[word_index] ? word_index : word_index + 1; ++ return word_index * BITS_IN_FREE_MAP_WORD + ret; ++} + + unsigned int fsync_alloc_shm( int low, int high ) + { + #ifdef __linux__ ++ unsigned int i; + int shm_idx; + int *shm; + +@@ -240,7 +263,29 @@ unsigned int fsync_alloc_shm( int low, int high ) + if (!is_fsync_initialized) + return 0; + +- shm_idx = shm_idx_counter++; ++ /* shm_idx_free_search_start_hint is always at the first word with a free index or before that. */ ++ for (i = shm_idx_free_search_start_hint; i < shm_idx_free_map_size; ++i) ++ if ((shm_idx = alloc_shm_idx_from_word( i ))) break; ++ ++ if (!shm_idx) ++ { ++ uint32_t old_size, new_size; ++ uint64_t *new_alloc; ++ ++ old_size = shm_idx_free_map_size; ++ new_size = old_size + 256; ++ new_alloc = realloc( shm_idx_free_map, new_size * sizeof(*new_alloc) ); ++ if (!new_alloc) ++ { ++ fprintf( stderr, "fsync: couldn't expand shm_idx_free_map to size %zd.", ++ new_size * sizeof(*new_alloc) ); ++ return 0; ++ } ++ memset( new_alloc + old_size, 0xff, (new_size - old_size) * sizeof(*new_alloc) ); ++ shm_idx_free_map = new_alloc; ++ shm_idx_free_map_size = new_size; ++ shm_idx = alloc_shm_idx_from_word( old_size ); ++ } + + while (shm_idx * 8 >= shm_size) + { +@@ -265,6 +310,21 @@ unsigned int fsync_alloc_shm( int low, int high ) + #endif + } + ++void fsync_free_shm_idx( int shm_idx ) ++{ ++ unsigned int idx; ++ uint64_t mask; ++ ++ assert( shm_idx ); ++ assert( shm_idx < shm_idx_free_map_size * BITS_IN_FREE_MAP_WORD ); ++ idx = shm_idx / BITS_IN_FREE_MAP_WORD; ++ mask = (uint64_t)1 << (shm_idx % BITS_IN_FREE_MAP_WORD); ++ assert( !(shm_idx_free_map[idx] & mask) ); ++ shm_idx_free_map[idx] |= mask; ++ if (idx < shm_idx_free_search_start_hint) ++ shm_idx_free_search_start_hint = idx; ++} ++ + static int type_matches( enum fsync_type type1, enum fsync_type type2 ) + { + return (type1 == type2) || +diff --git a/server/fsync.h b/server/fsync.h +index a91939b7f0a..ee1a729e77e 100644 +--- a/server/fsync.h ++++ b/server/fsync.h +@@ -21,6 +21,7 @@ + extern int do_fsync(void); + extern void fsync_init(void); + extern unsigned int fsync_alloc_shm( int low, int high ); ++extern void fsync_free_shm_idx( int shm_idx ); + extern void fsync_wake_futex( unsigned int shm_idx ); + extern void fsync_clear_futex( unsigned int shm_idx ); + extern void fsync_wake_up( struct object *obj ); +diff --git a/server/process.c b/server/process.c +index 38303e04193..d43df3d15f6 100644 +--- a/server/process.c ++++ b/server/process.c +@@ -805,6 +805,7 @@ static void process_destroy( struct object *obj ) + free( process->dir_cache ); + free( process->image ); + if (do_esync()) close( process->esync_fd ); ++ if (process->fsync_idx) fsync_free_shm_idx( process->fsync_idx ); + } + + /* dump a process on stdout for debugging purposes */ +diff --git a/server/queue.c b/server/queue.c +index de2cdd499cf..a86cee8e78c 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -1389,6 +1389,7 @@ static void msg_queue_destroy( struct object *obj ) + if (queue->fd) release_object( queue->fd ); + if (queue->shared) free_shared_object( queue->shared ); + if (do_esync()) close( queue->esync_fd ); ++ if (queue->fsync_idx) fsync_free_shm_idx( queue->fsync_idx ); + } + + static void msg_queue_poll_event( struct fd *fd, int event ) +diff --git a/server/thread.c b/server/thread.c +index 3f246f128bf..21de26a194f 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -483,6 +483,8 @@ struct thread *create_thread( int fd, struct process *process, const struct secu + } + } + ++ thread->fsync_idx = 0; ++ + if (do_fsync()) + { + thread->fsync_idx = fsync_alloc_shm( 0, 0 ); +@@ -580,6 +582,11 @@ static void destroy_thread( struct object *obj ) + + if (do_esync()) + close( thread->esync_fd ); ++ if (thread->fsync_idx) ++ { ++ fsync_free_shm_idx( thread->fsync_idx ); ++ fsync_free_shm_idx( thread->fsync_apc_idx ); ++ } + } + + /* dump a thread on stdout for debugging purposes */ +diff --git a/server/timer.c b/server/timer.c +index afc12ff03ad..884ace9376f 100644 +--- a/server/timer.c ++++ b/server/timer.c +@@ -119,6 +119,7 @@ static struct timer *create_timer( struct object *root, const struct unicode_str + timer->timeout = NULL; + timer->thread = NULL; + timer->esync_fd = -1; ++ timer->fsync_idx = 0; + + if (do_fsync()) + timer->fsync_idx = fsync_alloc_shm( 0, 0 ); +@@ -258,6 +259,7 @@ static void timer_destroy( struct object *obj ) + if (timer->timeout) remove_timeout_user( timer->timeout ); + if (timer->thread) release_object( timer->thread ); + if (do_esync()) close( timer->esync_fd ); ++ if (timer->fsync_idx) fsync_free_shm_idx( timer->fsync_idx ); + } + + /* create a timer */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0131-fsync-Use-CLOCK_MONOTONIC-for-relative-timeouts.patch b/0007-proton-esync-fsync/0131-fsync-Use-CLOCK_MONOTONIC-for-relative-timeouts.patch new file mode 100644 index 0000000..65b6577 --- /dev/null +++ b/0007-proton-esync-fsync/0131-fsync-Use-CLOCK_MONOTONIC-for-relative-timeouts.patch @@ -0,0 +1,195 @@ +From eb6a27a9dc9f965e8ebbe4a703f5e8b0e748554d Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Fri, 29 Apr 2022 16:57:13 -0500 +Subject: [PATCH 0558/2346] fsync: Use CLOCK_MONOTONIC for relative timeouts. + +CW-Bug-Id: #20548 + +Test shows that relative wait timeouts on Windows do not +include the time spent is suspend. Using CLOCK_MONOTONIC +on Linux is a closer approximation for that. +--- + dlls/ntdll/unix/fsync.c | 88 +++++++++++++++++++++++++---------------- + 1 file changed, 54 insertions(+), 34 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index f620b5caff8..f83b17d4710 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -82,13 +82,50 @@ struct timespec64 + long long tv_nsec; + }; + +-static LONGLONG update_timeout( ULONGLONG end ) ++static LONGLONG nt_time_from_ts( struct timespec *ts ) + { +- LARGE_INTEGER now; ++ return ticks_from_time_t( ts->tv_sec ) + (ts->tv_nsec + 50) / 100; ++} ++ ++static void get_wait_end_time( const LARGE_INTEGER **timeout, struct timespec64 *end, clockid_t *clock_id ) ++{ ++ ULONGLONG nt_end; ++ ++ if (!*timeout) return; ++ if ((*timeout)->QuadPart == TIMEOUT_INFINITE) ++ { ++ *timeout = NULL; ++ return; ++ } ++ ++ if ((*timeout)->QuadPart > 0) ++ { ++ nt_end = (*timeout)->QuadPart; ++ *clock_id = CLOCK_REALTIME; ++ } ++ else ++ { ++ struct timespec ts; ++ ++ clock_gettime( CLOCK_MONOTONIC, &ts ); ++ nt_end = nt_time_from_ts( &ts ) - (*timeout)->QuadPart; ++ *clock_id = CLOCK_MONOTONIC; ++ } ++ ++ nt_end -= SECS_1601_TO_1970 * TICKSPERSEC; ++ end->tv_sec = nt_end / (ULONGLONG)TICKSPERSEC; ++ end->tv_nsec = (nt_end % TICKSPERSEC) * 100; ++} ++ ++static LONGLONG update_timeout( const struct timespec64 *end, clockid_t clock_id ) ++{ ++ struct timespec end_ts, ts; + LONGLONG timeleft; + +- NtQuerySystemTime( &now ); +- timeleft = end - now.QuadPart; ++ clock_gettime( clock_id, &ts ); ++ end_ts.tv_sec = end->tv_sec; ++ end_ts.tv_nsec = end->tv_nsec; ++ timeleft = nt_time_from_ts( &end_ts ) - nt_time_from_ts( &ts ); + if (timeleft < 0) timeleft = 0; + return timeleft; + } +@@ -111,21 +148,12 @@ static void simulate_sched_quantum(void) + } + + static inline int futex_wait_multiple( const struct futex_waitv *futexes, +- int count, const ULONGLONG *end ) ++ int count, const struct timespec64 *end, clockid_t clock_id ) + { + if (end) +- { +- struct timespec64 timeout; +- ULONGLONG tmp = *end - SECS_1601_TO_1970 * TICKSPERSEC; +- timeout.tv_sec = tmp / (ULONGLONG)TICKSPERSEC; +- timeout.tv_nsec = (tmp % TICKSPERSEC) * 100; +- +- return syscall( __NR_futex_waitv, futexes, count, 0, &timeout, CLOCK_REALTIME ); +- } ++ return syscall( __NR_futex_waitv, futexes, count, 0, end, clock_id ); + else +- { + return syscall( __NR_futex_waitv, futexes, count, 0, NULL, 0 ); +- } + } + + static inline int futex_wake( int *addr, int val ) +@@ -684,7 +712,8 @@ NTSTATUS fsync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) + return STATUS_SUCCESS; + } + +-static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN alertable ) ++static NTSTATUS do_single_wait( int *addr, int val, const struct timespec64 *end, clockid_t clock_id, ++ BOOLEAN alertable ) + { + struct futex_waitv futexes[2]; + int ret; +@@ -700,14 +729,14 @@ static NTSTATUS do_single_wait( int *addr, int val, ULONGLONG *end, BOOLEAN aler + + futex_vector_set( &futexes[1], apc_futex, 0 ); + +- ret = futex_wait_multiple( futexes, 2, end ); ++ ret = futex_wait_multiple( futexes, 2, end, clock_id ); + + if (__atomic_load_n( apc_futex, __ATOMIC_SEQ_CST )) + return STATUS_USER_APC; + } + else + { +- ret = futex_wait_multiple( futexes, 1, end ); ++ ret = futex_wait_multiple( futexes, 1, end, clock_id ); + } + + if (!ret) +@@ -727,11 +756,11 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + struct fsync *objs[MAXIMUM_WAIT_OBJECTS]; + BOOL msgwait = FALSE, waited = FALSE; + int has_fsync = 0, has_server = 0; ++ clockid_t clock_id = 0; ++ struct timespec64 end; + int dummy_futex = 0; + LONGLONG timeleft; +- LARGE_INTEGER now; + DWORD waitcount; +- ULONGLONG end; + int i, ret; + + /* Grab the APC futex if we don't already have it. */ +@@ -752,16 +781,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + } + } + +- NtQuerySystemTime( &now ); +- if (timeout) +- { +- if (timeout->QuadPart == TIMEOUT_INFINITE) +- timeout = NULL; +- else if (timeout->QuadPart > 0) +- end = timeout->QuadPart; +- else +- end = now.QuadPart - timeout->QuadPart; +- } ++ get_wait_end_time( &timeout, &end, &clock_id ); + + for (i = 0; i < count; i++) + { +@@ -797,7 +817,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + TRACE(", timeout = INFINITE.\n"); + else + { +- timeleft = update_timeout( end ); ++ timeleft = update_timeout( &end, clock_id ); + TRACE(", timeout = %ld.%07ld sec.\n", + (long) (timeleft / TICKSPERSEC), (long) (timeleft % TICKSPERSEC)); + } +@@ -944,7 +964,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + return STATUS_TIMEOUT; + } + +- ret = futex_wait_multiple( futexes, waitcount, timeout ? &end : NULL ); ++ ret = futex_wait_multiple( futexes, waitcount, timeout ? &end : NULL, clock_id ); + + /* FUTEX_WAIT_MULTIPLE can succeed or return -EINTR, -EAGAIN, + * -EFAULT/-EACCES, -ETIMEDOUT. In the first three cases we need to +@@ -1006,7 +1026,7 @@ tryagain: + + while ((current = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST ))) + { +- status = do_single_wait( &mutex->tid, current, timeout ? &end : NULL, alertable ); ++ status = do_single_wait( &mutex->tid, current, timeout ? &end : NULL, clock_id, alertable ); + if (status != STATUS_PENDING) + break; + } +@@ -1018,7 +1038,7 @@ tryagain: + + while (!__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST )) + { +- status = do_single_wait( &event->signaled, 0, timeout ? &end : NULL, alertable ); ++ status = do_single_wait( &event->signaled, 0, timeout ? &end : NULL, clock_id, alertable ); + if (status != STATUS_PENDING) + break; + } +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0132-fsync-Return-a-copy-of-the-object-instead-of-cache-p.patch b/0007-proton-esync-fsync/0132-fsync-Return-a-copy-of-the-object-instead-of-cache-p.patch new file mode 100644 index 0000000..3a91c86 --- /dev/null +++ b/0007-proton-esync-fsync/0132-fsync-Return-a-copy-of-the-object-instead-of-cache-p.patch @@ -0,0 +1,407 @@ +From 5ce45b53b224d0c6e76cde7d101698c0fc35e207 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Mon, 4 Jul 2022 10:27:12 -0500 +Subject: [PATCH 0559/2346] fsync: Return a copy of the object instead of cache + pointer from get_object(). + +CW-Bug-Id: #20826 +--- + dlls/ntdll/unix/fsync.c | 123 +++++++++++++++++++++------------------- + 1 file changed, 65 insertions(+), 58 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index f83b17d4710..c397129680a 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -269,14 +269,14 @@ static inline UINT_PTR handle_to_index( HANDLE handle, UINT_PTR *entry ) + return idx % FSYNC_LIST_BLOCK_SIZE; + } + +-static struct fsync *add_to_list( HANDLE handle, enum fsync_type type, void *shm ) ++static void add_to_list( HANDLE handle, enum fsync_type type, void *shm ) + { + UINT_PTR entry, idx = handle_to_index( handle, &entry ); + + if (entry >= FSYNC_LIST_ENTRIES) + { + FIXME( "too many allocated handles, not caching %p\n", handle ); +- return FALSE; ++ return; + } + + if (!fsync_list[entry]) /* do we need to allocate a new block of entries? */ +@@ -286,38 +286,37 @@ static struct fsync *add_to_list( HANDLE handle, enum fsync_type type, void *shm + { + void *ptr = anon_mmap_alloc( FSYNC_LIST_BLOCK_SIZE * sizeof(struct fsync), + PROT_READ | PROT_WRITE ); +- if (ptr == MAP_FAILED) return FALSE; ++ if (ptr == MAP_FAILED) return; + fsync_list[entry] = ptr; + } + } + + if (!__sync_val_compare_and_swap((int *)&fsync_list[entry][idx].type, 0, type )) + fsync_list[entry][idx].shm = shm; +- +- return &fsync_list[entry][idx]; + } + +-static struct fsync *get_cached_object( HANDLE handle ) ++static BOOL get_cached_object( HANDLE handle, struct fsync *obj ) + { + UINT_PTR entry, idx = handle_to_index( handle, &entry ); + +- if (entry >= FSYNC_LIST_ENTRIES || !fsync_list[entry]) return NULL; +- if (!fsync_list[entry][idx].type) return NULL; ++ if (entry >= FSYNC_LIST_ENTRIES || !fsync_list[entry]) return FALSE; ++ if (!fsync_list[entry][idx].type) return FALSE; + +- return &fsync_list[entry][idx]; ++ *obj = fsync_list[entry][idx]; ++ return TRUE; + } + + /* Gets an object. This is either a proper fsync object (i.e. an event, + * semaphore, etc. created using create_fsync) or a generic synchronizable + * server-side object which the server will signal (e.g. a process, thread, + * message queue, etc.) */ +-static NTSTATUS get_object( HANDLE handle, struct fsync **obj ) ++static NTSTATUS get_object( HANDLE handle, struct fsync *obj ) + { + NTSTATUS ret = STATUS_SUCCESS; + unsigned int shm_idx = 0; + enum fsync_type type; + +- if ((*obj = get_cached_object( handle ))) return STATUS_SUCCESS; ++ if (get_cached_object( handle, obj )) return STATUS_SUCCESS; + + if ((INT_PTR)handle < 0) + { +@@ -340,13 +339,14 @@ static NTSTATUS get_object( HANDLE handle, struct fsync **obj ) + if (ret) + { + WARN("Failed to retrieve shm index for handle %p, status %#x.\n", handle, (unsigned int)ret); +- *obj = NULL; + return ret; + } + + TRACE("Got shm index %d for handle %p.\n", shm_idx, handle); + +- *obj = add_to_list( handle, type, get_shm( shm_idx ) ); ++ obj->type = type; ++ obj->shm = get_shm( shm_idx ); ++ add_to_list( handle, type, obj->shm ); + return ret; + } + +@@ -497,7 +497,7 @@ NTSTATUS fsync_open_semaphore( HANDLE *handle, ACCESS_MASK access, + + NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) + { +- struct fsync *obj; ++ struct fsync obj; + struct semaphore *semaphore; + ULONG current; + NTSTATUS ret; +@@ -505,7 +505,7 @@ NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) + TRACE("%p, %d, %p.\n", handle, (int)count, prev); + + if ((ret = get_object( handle, &obj ))) return ret; +- semaphore = obj->shm; ++ semaphore = obj.shm; + + do + { +@@ -523,7 +523,7 @@ NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) + + NTSTATUS fsync_query_semaphore( HANDLE handle, void *info, ULONG *ret_len ) + { +- struct fsync *obj; ++ struct fsync obj; + struct semaphore *semaphore; + SEMAPHORE_BASIC_INFORMATION *out = info; + NTSTATUS ret; +@@ -531,7 +531,7 @@ NTSTATUS fsync_query_semaphore( HANDLE handle, void *info, ULONG *ret_len ) + TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len); + + if ((ret = get_object( handle, &obj ))) return ret; +- semaphore = obj->shm; ++ semaphore = obj.shm; + + out->CurrentCount = semaphore->count; + out->MaximumCount = semaphore->max; +@@ -563,16 +563,16 @@ NTSTATUS fsync_open_event( HANDLE *handle, ACCESS_MASK access, + NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) + { + struct event *event; +- struct fsync *obj; ++ struct fsync obj; + LONG current; + NTSTATUS ret; + + TRACE("%p.\n", handle); + + if ((ret = get_object( handle, &obj ))) return ret; +- event = obj->shm; ++ event = obj.shm; + +- if (obj->type != FSYNC_MANUAL_EVENT && obj->type != FSYNC_AUTO_EVENT) ++ if (obj.type != FSYNC_MANUAL_EVENT && obj.type != FSYNC_AUTO_EVENT) + return STATUS_OBJECT_TYPE_MISMATCH; + + if (!(current = __atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST ))) +@@ -586,14 +586,14 @@ NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) + NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) + { + struct event *event; +- struct fsync *obj; ++ struct fsync obj; + LONG current; + NTSTATUS ret; + + TRACE("%p.\n", handle); + + if ((ret = get_object( handle, &obj ))) return ret; +- event = obj->shm; ++ event = obj.shm; + + current = __atomic_exchange_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); + +@@ -605,14 +605,14 @@ NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) + NTSTATUS fsync_pulse_event( HANDLE handle, LONG *prev ) + { + struct event *event; +- struct fsync *obj; ++ struct fsync obj; + LONG current; + NTSTATUS ret; + + TRACE("%p.\n", handle); + + if ((ret = get_object( handle, &obj ))) return ret; +- event = obj->shm; ++ event = obj.shm; + + /* This isn't really correct; an application could miss the write. + * Unfortunately we can't really do much better. Fortunately this is rarely +@@ -634,17 +634,17 @@ NTSTATUS fsync_pulse_event( HANDLE handle, LONG *prev ) + NTSTATUS fsync_query_event( HANDLE handle, void *info, ULONG *ret_len ) + { + struct event *event; +- struct fsync *obj; ++ struct fsync obj; + EVENT_BASIC_INFORMATION *out = info; + NTSTATUS ret; + + TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len); + + if ((ret = get_object( handle, &obj ))) return ret; +- event = obj->shm; ++ event = obj.shm; + + out->EventState = event->signaled; +- out->EventType = (obj->type == FSYNC_AUTO_EVENT ? SynchronizationEvent : NotificationEvent); ++ out->EventType = (obj.type == FSYNC_AUTO_EVENT ? SynchronizationEvent : NotificationEvent); + if (ret_len) *ret_len = sizeof(*out); + + return STATUS_SUCCESS; +@@ -671,13 +671,13 @@ NTSTATUS fsync_open_mutex( HANDLE *handle, ACCESS_MASK access, + NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) + { + struct mutex *mutex; +- struct fsync *obj; ++ struct fsync obj; + NTSTATUS ret; + + TRACE("%p, %p.\n", handle, prev); + + if ((ret = get_object( handle, &obj ))) return ret; +- mutex = obj->shm; ++ mutex = obj.shm; + + if (mutex->tid != GetCurrentThreadId()) return STATUS_MUTANT_NOT_OWNED; + +@@ -694,7 +694,7 @@ NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) + + NTSTATUS fsync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) + { +- struct fsync *obj; ++ struct fsync obj; + struct mutex *mutex; + MUTANT_BASIC_INFORMATION *out = info; + NTSTATUS ret; +@@ -702,7 +702,7 @@ NTSTATUS fsync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) + TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len); + + if ((ret = get_object( handle, &obj ))) return ret; +- mutex = obj->shm; ++ mutex = obj.shm; + + out->CurrentCount = 1 - mutex->count; + out->OwnedByCaller = (mutex->tid == GetCurrentThreadId()); +@@ -753,7 +753,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + static const LARGE_INTEGER zero = {0}; + + struct futex_waitv futexes[MAXIMUM_WAIT_OBJECTS + 1]; +- struct fsync *objs[MAXIMUM_WAIT_OBJECTS]; ++ struct fsync objs[MAXIMUM_WAIT_OBJECTS]; + BOOL msgwait = FALSE, waited = FALSE; + int has_fsync = 0, has_server = 0; + clockid_t clock_id = 0; +@@ -787,14 +787,28 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + { + ret = get_object( handles[i], &objs[i] ); + if (ret == STATUS_SUCCESS) ++ { ++ if (!objs[i].type) ++ { ++ /* Someone probably closed an object while waiting on it. */ ++ WARN("Handle %p has type 0; was it closed?\n", handles[i]); ++ return STATUS_INVALID_HANDLE; ++ } + has_fsync = 1; ++ } + else if (ret == STATUS_NOT_IMPLEMENTED) ++ { ++ objs[i].type = 0; ++ objs[i].shm = NULL; + has_server = 1; ++ } + else ++ { + return ret; ++ } + } + +- if (count && objs[count - 1] && objs[count - 1]->type == FSYNC_QUEUE) ++ if (count && objs[count - 1].type == FSYNC_QUEUE) + msgwait = TRUE; + + if (has_fsync && has_server) +@@ -839,17 +853,10 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + + for (i = 0; i < count; i++) + { +- struct fsync *obj = objs[i]; ++ struct fsync *obj = &objs[i]; + +- if (obj) ++ if (obj->type) + { +- if (!obj->type) /* gcc complains if we put this in the switch */ +- { +- /* Someone probably closed an object while waiting on it. */ +- WARN("Handle %p has type 0; was it closed?\n", handles[i]); +- return STATUS_INVALID_HANDLE; +- } +- + switch (obj->type) + { + case FSYNC_SEMAPHORE: +@@ -1015,9 +1022,9 @@ tryagain: + + for (i = 0; i < count; i++) + { +- struct fsync *obj = objs[i]; ++ struct fsync *obj = &objs[i]; + +- if (obj && obj->type == FSYNC_MUTEX) ++ if (obj->type == FSYNC_MUTEX) + { + struct mutex *mutex = obj->shm; + +@@ -1031,7 +1038,7 @@ tryagain: + break; + } + } +- else if (obj) ++ else if (obj->type) + { + /* this works for semaphores too */ + struct event *event = obj->shm; +@@ -1057,9 +1064,9 @@ tryagain: + * handles were signaled. Check to make sure they still are. */ + for (i = 0; i < count; i++) + { +- struct fsync *obj = objs[i]; ++ struct fsync *obj = &objs[i]; + +- if (obj && obj->type == FSYNC_MUTEX) ++ if (obj->type == FSYNC_MUTEX) + { + struct mutex *mutex = obj->shm; + int tid = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST ); +@@ -1067,7 +1074,7 @@ tryagain: + if (tid && tid != ~0 && tid != GetCurrentThreadId()) + goto tryagain; + } +- else if (obj) ++ else if (obj->type) + { + struct event *event = obj->shm; + +@@ -1079,8 +1086,8 @@ tryagain: + /* Yep, still signaled. Now quick, grab everything. */ + for (i = 0; i < count; i++) + { +- struct fsync *obj = objs[i]; +- if (!obj) continue; ++ struct fsync *obj = &objs[i]; ++ if (!obj->type) continue; + switch (obj->type) + { + case FSYNC_MUTEX: +@@ -1126,9 +1133,9 @@ tryagain: + * Make sure to let ourselves know that we grabbed the mutexes. */ + for (i = 0; i < count; i++) + { +- if (objs[i] && objs[i]->type == FSYNC_MUTEX) ++ if (objs[i].type == FSYNC_MUTEX) + { +- struct mutex *mutex = objs[i]->shm; ++ struct mutex *mutex = objs[i].shm; + mutex->count++; + } + } +@@ -1144,8 +1151,8 @@ tryagain: + tooslow: + for (--i; i >= 0; i--) + { +- struct fsync *obj = objs[i]; +- if (!obj) continue; ++ struct fsync *obj = &objs[i]; ++ if (!obj->type) continue; + switch (obj->type) + { + case FSYNC_MUTEX: +@@ -1219,10 +1226,10 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an + BOOLEAN alertable, const LARGE_INTEGER *timeout ) + { + BOOL msgwait = FALSE; +- struct fsync *obj; ++ struct fsync obj; + NTSTATUS ret; + +- if (count && !get_object( handles[count - 1], &obj ) && obj->type == FSYNC_QUEUE) ++ if (count && !get_object( handles[count - 1], &obj ) && obj.type == FSYNC_QUEUE) + { + msgwait = TRUE; + server_set_msgwait( 1 ); +@@ -1239,12 +1246,12 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an + NTSTATUS fsync_signal_and_wait( HANDLE signal, HANDLE wait, BOOLEAN alertable, + const LARGE_INTEGER *timeout ) + { +- struct fsync *obj; ++ struct fsync obj; + NTSTATUS ret; + + if ((ret = get_object( signal, &obj ))) return ret; + +- switch (obj->type) ++ switch (obj.type) + { + case FSYNC_SEMAPHORE: + ret = fsync_release_semaphore( signal, 1, NULL ); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0133-fsync-Synchronize-access-to-object-cache.patch b/0007-proton-esync-fsync/0133-fsync-Synchronize-access-to-object-cache.patch new file mode 100644 index 0000000..e48225c --- /dev/null +++ b/0007-proton-esync-fsync/0133-fsync-Synchronize-access-to-object-cache.patch @@ -0,0 +1,120 @@ +From ea368c961e43e6cd54cd23e628d86923bf5623b7 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Mon, 4 Jul 2022 11:40:08 -0500 +Subject: [PATCH 0560/2346] fsync: Synchronize access to object cache. + +CW-Bug-Id: #20826 +--- + dlls/ntdll/unix/fsync.c | 57 +++++++++++++++++++++++++++++++---------- + 1 file changed, 44 insertions(+), 13 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index c397129680a..d6b5dba1202 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -261,6 +261,7 @@ static void *get_shm( unsigned int idx ) + + static struct fsync *fsync_list[FSYNC_LIST_ENTRIES]; + static struct fsync fsync_list_initial_block[FSYNC_LIST_BLOCK_SIZE]; ++static int cache_locked; + + static inline UINT_PTR handle_to_index( HANDLE handle, UINT_PTR *entry ) + { +@@ -269,6 +270,26 @@ static inline UINT_PTR handle_to_index( HANDLE handle, UINT_PTR *entry ) + return idx % FSYNC_LIST_BLOCK_SIZE; + } + ++static void small_pause(void) ++{ ++#ifdef __i386__ ++ __asm__ __volatile__( "rep;nop" : : : "memory" ); ++#else ++ __asm__ __volatile__( "" : : : "memory" ); ++#endif ++} ++ ++static void lock_obj_cache(void) ++{ ++ while (__sync_val_compare_and_swap( &cache_locked, 0, 1 )) ++ small_pause(); ++} ++ ++static void unlock_obj_cache(void) ++{ ++ __atomic_store_n( &cache_locked, 0, __ATOMIC_SEQ_CST ); ++} ++ + static void add_to_list( HANDLE handle, enum fsync_type type, void *shm ) + { + UINT_PTR entry, idx = handle_to_index( handle, &entry ); +@@ -287,23 +308,29 @@ static void add_to_list( HANDLE handle, enum fsync_type type, void *shm ) + void *ptr = anon_mmap_alloc( FSYNC_LIST_BLOCK_SIZE * sizeof(struct fsync), + PROT_READ | PROT_WRITE ); + if (ptr == MAP_FAILED) return; +- fsync_list[entry] = ptr; ++ if (__sync_val_compare_and_swap( &fsync_list[entry], NULL, ptr )) ++ munmap( ptr, FSYNC_LIST_BLOCK_SIZE * sizeof(struct fsync) ); + } + } + +- if (!__sync_val_compare_and_swap((int *)&fsync_list[entry][idx].type, 0, type )) +- fsync_list[entry][idx].shm = shm; ++ lock_obj_cache(); ++ fsync_list[entry][idx].type = type; ++ fsync_list[entry][idx].shm = shm; ++ unlock_obj_cache(); + } + + static BOOL get_cached_object( HANDLE handle, struct fsync *obj ) + { ++ BOOL ret = TRUE; + UINT_PTR entry, idx = handle_to_index( handle, &entry ); + + if (entry >= FSYNC_LIST_ENTRIES || !fsync_list[entry]) return FALSE; +- if (!fsync_list[entry][idx].type) return FALSE; + +- *obj = fsync_list[entry][idx]; +- return TRUE; ++ lock_obj_cache(); ++ if (!fsync_list[entry][idx].type) ret = FALSE; ++ else *obj = fsync_list[entry][idx]; ++ unlock_obj_cache(); ++ return ret; + } + + /* Gets an object. This is either a proper fsync object (i.e. an event, +@@ -358,7 +385,16 @@ NTSTATUS fsync_close( HANDLE handle ) + + if (entry < FSYNC_LIST_ENTRIES && fsync_list[entry]) + { +- if (__atomic_exchange_n( &fsync_list[entry][idx].type, 0, __ATOMIC_SEQ_CST )) ++ enum fsync_type type; ++ ++ lock_obj_cache(); ++ if ((type = fsync_list[entry][idx].type)) ++ { ++ fsync_list[entry][idx].type = 0; ++ fsync_list[entry][idx].shm = NULL; ++ } ++ unlock_obj_cache(); ++ if (type) + return STATUS_SUCCESS; + } + +@@ -788,12 +824,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + ret = get_object( handles[i], &objs[i] ); + if (ret == STATUS_SUCCESS) + { +- if (!objs[i].type) +- { +- /* Someone probably closed an object while waiting on it. */ +- WARN("Handle %p has type 0; was it closed?\n", handles[i]); +- return STATUS_INVALID_HANDLE; +- } ++ assert( objs[i].type ); + has_fsync = 1; + } + else if (ret == STATUS_NOT_IMPLEMENTED) +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0134-fsync-Use-atomic-cache-stores-and-load-instead-of-lo.patch b/0007-proton-esync-fsync/0134-fsync-Use-atomic-cache-stores-and-load-instead-of-lo.patch new file mode 100644 index 0000000..5ad8bc0 --- /dev/null +++ b/0007-proton-esync-fsync/0134-fsync-Use-atomic-cache-stores-and-load-instead-of-lo.patch @@ -0,0 +1,177 @@ +From 9d651bf3c80fd280e4cafc5901197429d3d0a63f Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Mon, 1 Aug 2022 10:50:13 -0500 +Subject: [PATCH 0561/2346] fsync: Use atomic cache stores and load instead of + locking cache. + +CW-Bug-Id: #21050 + +(replaces "fsync: Synchronize access to object cache.") +--- + dlls/ntdll/unix/fsync.c | 91 +++++++++++++++++++---------------------- + 1 file changed, 42 insertions(+), 49 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index d6b5dba1202..0e3752421ed 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -259,9 +259,16 @@ static void *get_shm( unsigned int idx ) + #define FSYNC_LIST_BLOCK_SIZE (65536 / sizeof(struct fsync)) + #define FSYNC_LIST_ENTRIES 256 + +-static struct fsync *fsync_list[FSYNC_LIST_ENTRIES]; +-static struct fsync fsync_list_initial_block[FSYNC_LIST_BLOCK_SIZE]; +-static int cache_locked; ++struct fsync_cache ++{ ++ enum fsync_type type; ++ unsigned int shm_idx; ++}; ++ ++C_ASSERT(sizeof(struct fsync_cache) == sizeof(uint64_t)); ++ ++static struct fsync_cache *fsync_list[FSYNC_LIST_ENTRIES]; ++static struct fsync_cache fsync_list_initial_block[FSYNC_LIST_BLOCK_SIZE]; + + static inline UINT_PTR handle_to_index( HANDLE handle, UINT_PTR *entry ) + { +@@ -270,29 +277,10 @@ static inline UINT_PTR handle_to_index( HANDLE handle, UINT_PTR *entry ) + return idx % FSYNC_LIST_BLOCK_SIZE; + } + +-static void small_pause(void) +-{ +-#ifdef __i386__ +- __asm__ __volatile__( "rep;nop" : : : "memory" ); +-#else +- __asm__ __volatile__( "" : : : "memory" ); +-#endif +-} +- +-static void lock_obj_cache(void) +-{ +- while (__sync_val_compare_and_swap( &cache_locked, 0, 1 )) +- small_pause(); +-} +- +-static void unlock_obj_cache(void) +-{ +- __atomic_store_n( &cache_locked, 0, __ATOMIC_SEQ_CST ); +-} +- +-static void add_to_list( HANDLE handle, enum fsync_type type, void *shm ) ++static void add_to_list( HANDLE handle, enum fsync_type type, unsigned int shm_idx ) + { + UINT_PTR entry, idx = handle_to_index( handle, &entry ); ++ struct fsync_cache cache; + + if (entry >= FSYNC_LIST_ENTRIES) + { +@@ -305,32 +293,41 @@ static void add_to_list( HANDLE handle, enum fsync_type type, void *shm ) + if (!entry) fsync_list[0] = fsync_list_initial_block; + else + { +- void *ptr = anon_mmap_alloc( FSYNC_LIST_BLOCK_SIZE * sizeof(struct fsync), ++ void *ptr = anon_mmap_alloc( FSYNC_LIST_BLOCK_SIZE * sizeof(*fsync_list[entry]), + PROT_READ | PROT_WRITE ); + if (ptr == MAP_FAILED) return; + if (__sync_val_compare_and_swap( &fsync_list[entry], NULL, ptr )) +- munmap( ptr, FSYNC_LIST_BLOCK_SIZE * sizeof(struct fsync) ); ++ munmap( ptr, FSYNC_LIST_BLOCK_SIZE * sizeof(*fsync_list[entry]) ); + } + } + +- lock_obj_cache(); +- fsync_list[entry][idx].type = type; +- fsync_list[entry][idx].shm = shm; +- unlock_obj_cache(); ++ cache.type = type; ++ cache.shm_idx = shm_idx; ++ __atomic_store_n( (uint64_t *)&fsync_list[entry][idx], *(uint64_t *)&cache, __ATOMIC_SEQ_CST ); + } + + static BOOL get_cached_object( HANDLE handle, struct fsync *obj ) + { +- BOOL ret = TRUE; + UINT_PTR entry, idx = handle_to_index( handle, &entry ); ++ struct fsync_cache cache; + + if (entry >= FSYNC_LIST_ENTRIES || !fsync_list[entry]) return FALSE; + +- lock_obj_cache(); +- if (!fsync_list[entry][idx].type) ret = FALSE; +- else *obj = fsync_list[entry][idx]; +- unlock_obj_cache(); +- return ret; ++again: ++ *(uint64_t *)&cache = __atomic_load_n( (uint64_t *)&fsync_list[entry][idx], __ATOMIC_SEQ_CST ); ++ ++ if (!cache.type || !cache.shm_idx) return FALSE; ++ ++ obj->type = cache.type; ++ obj->shm = get_shm( cache.shm_idx ); ++ if (*(uint64_t *)&cache != __atomic_load_n( (uint64_t *)&fsync_list[entry][idx], __ATOMIC_SEQ_CST )) ++ { ++ /* This check does not strictly guarantee that we avoid the potential race but is supposed to greatly ++ * reduce the probability of that. */ ++ FIXME( "Cache changed while getting object.\n" ); ++ goto again; ++ } ++ return TRUE; + } + + /* Gets an object. This is either a proper fsync object (i.e. an event, +@@ -373,7 +370,7 @@ static NTSTATUS get_object( HANDLE handle, struct fsync *obj ) + + obj->type = type; + obj->shm = get_shm( shm_idx ); +- add_to_list( handle, type, obj->shm ); ++ add_to_list( handle, type, shm_idx ); + return ret; + } + +@@ -385,17 +382,13 @@ NTSTATUS fsync_close( HANDLE handle ) + + if (entry < FSYNC_LIST_ENTRIES && fsync_list[entry]) + { +- enum fsync_type type; ++ struct fsync_cache cache; + +- lock_obj_cache(); +- if ((type = fsync_list[entry][idx].type)) +- { +- fsync_list[entry][idx].type = 0; +- fsync_list[entry][idx].shm = NULL; +- } +- unlock_obj_cache(); +- if (type) +- return STATUS_SUCCESS; ++ cache.type = 0; ++ cache.shm_idx = 0; ++ *(uint64_t *)&cache = __atomic_exchange_n( (uint64_t *)&fsync_list[entry][idx], ++ *(uint64_t *)&cache, __ATOMIC_SEQ_CST ); ++ if (cache.type) return STATUS_SUCCESS; + } + + return STATUS_INVALID_HANDLE; +@@ -430,7 +423,7 @@ static NTSTATUS create_fsync( enum fsync_type type, HANDLE *handle, + + if (!ret || ret == STATUS_OBJECT_NAME_EXISTS) + { +- add_to_list( *handle, type, get_shm( shm_idx )); ++ add_to_list( *handle, type, shm_idx ); + TRACE("-> handle %p, shm index %d.\n", *handle, shm_idx); + } + +@@ -463,7 +456,7 @@ static NTSTATUS open_fsync( enum fsync_type type, HANDLE *handle, + + if (!ret) + { +- add_to_list( *handle, type, get_shm( shm_idx ) ); ++ add_to_list( *handle, type, shm_idx ); + + TRACE("-> handle %p, shm index %u.\n", *handle, shm_idx); + } +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0135-fsync-Implement-reference-counting-for-sync-objects-.patch b/0007-proton-esync-fsync/0135-fsync-Implement-reference-counting-for-sync-objects-.patch new file mode 100644 index 0000000..7e01d1c --- /dev/null +++ b/0007-proton-esync-fsync/0135-fsync-Implement-reference-counting-for-sync-objects-.patch @@ -0,0 +1,592 @@ +From 067fd39a1e79416d8ca96925a48b395ab551a1ec Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Mon, 4 Jul 2022 15:11:23 -0500 +Subject: [PATCH 0562/2346] fsync: Implement reference counting for sync + objects shared memory. + +CW-Bug-Id: #20826 +--- + dlls/ntdll/unix/fsync.c | 150 ++++++++++++++++++++++++++++++++++++---- + server/fsync.c | 64 ++++++++++++++++- + server/fsync.h | 1 + + server/process.c | 6 +- + server/protocol.def | 5 ++ + 5 files changed, 210 insertions(+), 16 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 0e3752421ed..309e2eb2aff 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -191,22 +191,28 @@ struct semaphore + { + int count; + int max; ++ int ref; ++ int last_pid; + }; +-C_ASSERT(sizeof(struct semaphore) == 8); ++C_ASSERT(sizeof(struct semaphore) == 16); + + struct event + { + int signaled; + int unused; ++ int ref; ++ int last_pid; + }; +-C_ASSERT(sizeof(struct event) == 8); ++C_ASSERT(sizeof(struct event) == 16); + + struct mutex + { + int tid; + int count; /* recursion count */ ++ int ref; ++ int last_pid; + }; +-C_ASSERT(sizeof(struct mutex) == 8); ++C_ASSERT(sizeof(struct mutex) == 16); + + static char shm_name[29]; + static int shm_fd; +@@ -218,8 +224,8 @@ static pthread_mutex_t shm_addrs_mutex = PTHREAD_MUTEX_INITIALIZER; + + static void *get_shm( unsigned int idx ) + { +- int entry = (idx * 8) / pagesize; +- int offset = (idx * 8) % pagesize; ++ int entry = (idx * 16) / pagesize; ++ int offset = (idx * 16) % pagesize; + void *ret; + + pthread_mutex_lock( &shm_addrs_mutex ); +@@ -306,6 +312,59 @@ static void add_to_list( HANDLE handle, enum fsync_type type, unsigned int shm_i + __atomic_store_n( (uint64_t *)&fsync_list[entry][idx], *(uint64_t *)&cache, __ATOMIC_SEQ_CST ); + } + ++static void grab_object( struct fsync *obj ) ++{ ++ int *shm = obj->shm; ++ ++ __atomic_add_fetch( &shm[2], 1, __ATOMIC_SEQ_CST ); ++} ++ ++static unsigned int shm_index_from_shm( char *shm ) ++{ ++ unsigned int count = shm_addrs_size; ++ unsigned int i, idx_offset; ++ ++ for (i = 0; i < count; ++i) ++ { ++ if (shm >= (char *)shm_addrs[i] && shm < (char *)shm_addrs[i] + pagesize) ++ { ++ idx_offset = (shm - (char *)shm_addrs[i]) / 16; ++ return i * (pagesize / 16) + idx_offset; ++ } ++ } ++ ++ ERR( "Index for shm %p not found.\n", shm ); ++ return ~0u; ++} ++ ++static void put_object( struct fsync *obj ) ++{ ++ int *shm = obj->shm; ++ ++ if (__atomic_load_n( &shm[2], __ATOMIC_SEQ_CST ) == 1) ++ { ++ /* We are holding the last reference, it should be released on server so shm idx get freed. */ ++ SERVER_START_REQ( fsync_free_shm_idx ) ++ { ++ req->shm_idx = shm_index_from_shm( obj->shm ); ++ wine_server_call( req ); ++ } ++ SERVER_END_REQ; ++ } ++ else ++ { ++ __atomic_sub_fetch( &shm[2], 1, __ATOMIC_SEQ_CST ); ++ } ++} ++ ++static void put_object_from_wait( struct fsync *obj ) ++{ ++ int *shm = obj->shm; ++ ++ __sync_val_compare_and_swap( &shm[3], GetCurrentProcessId(), 0 ); ++ put_object( obj ); ++} ++ + static BOOL get_cached_object( HANDLE handle, struct fsync *obj ) + { + UINT_PTR entry, idx = handle_to_index( handle, &entry ); +@@ -320,10 +379,13 @@ again: + + obj->type = cache.type; + obj->shm = get_shm( cache.shm_idx ); +- if (*(uint64_t *)&cache != __atomic_load_n( (uint64_t *)&fsync_list[entry][idx], __ATOMIC_SEQ_CST )) ++ grab_object( obj ); ++ if (((int *)obj->shm)[2] < 2 || ++ *(uint64_t *)&cache != __atomic_load_n( (uint64_t *)&fsync_list[entry][idx], __ATOMIC_SEQ_CST )) + { + /* This check does not strictly guarantee that we avoid the potential race but is supposed to greatly + * reduce the probability of that. */ ++ put_object( obj ); + FIXME( "Cache changed while getting object.\n" ); + goto again; + } +@@ -371,9 +433,24 @@ static NTSTATUS get_object( HANDLE handle, struct fsync *obj ) + obj->type = type; + obj->shm = get_shm( shm_idx ); + add_to_list( handle, type, shm_idx ); ++ /* get_fsync_idx server request increments shared mem refcount, so not grabbing object here. */ + return ret; + } + ++static NTSTATUS get_object_for_wait( HANDLE handle, struct fsync *obj ) ++{ ++ NTSTATUS ret; ++ int *shm; ++ ++ if ((ret = get_object( handle, obj ))) return ret; ++ ++ shm = obj->shm; ++ /* Give wineserver a chance to cleanup shm index if the process ++ * is killed while we are waiting on the object. */ ++ __atomic_store_n( &shm[3], GetCurrentProcessId(), __ATOMIC_SEQ_CST ); ++ return STATUS_SUCCESS; ++} ++ + NTSTATUS fsync_close( HANDLE handle ) + { + UINT_PTR entry, idx = handle_to_index( handle, &entry ); +@@ -540,13 +617,17 @@ NTSTATUS fsync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev ) + { + current = semaphore->count; + if (count + current > semaphore->max) ++ { ++ put_object( &obj ); + return STATUS_SEMAPHORE_LIMIT_EXCEEDED; ++ } + } while (__sync_val_compare_and_swap( &semaphore->count, current, count + current ) != current); + + if (prev) *prev = current; + + futex_wake( &semaphore->count, INT_MAX ); + ++ put_object( &obj ); + return STATUS_SUCCESS; + } + +@@ -566,6 +647,7 @@ NTSTATUS fsync_query_semaphore( HANDLE handle, void *info, ULONG *ret_len ) + out->MaximumCount = semaphore->max; + if (ret_len) *ret_len = sizeof(*out); + ++ put_object( &obj ); + return STATUS_SUCCESS; + } + +@@ -602,13 +684,17 @@ NTSTATUS fsync_set_event( HANDLE handle, LONG *prev ) + event = obj.shm; + + if (obj.type != FSYNC_MANUAL_EVENT && obj.type != FSYNC_AUTO_EVENT) ++ { ++ put_object( &obj ); + return STATUS_OBJECT_TYPE_MISMATCH; ++ } + + if (!(current = __atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST ))) + futex_wake( &event->signaled, INT_MAX ); + + if (prev) *prev = current; + ++ put_object( &obj ); + return STATUS_SUCCESS; + } + +@@ -628,6 +714,7 @@ NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) + + if (prev) *prev = current; + ++ put_object( &obj ); + return STATUS_SUCCESS; + } + +@@ -657,6 +744,7 @@ NTSTATUS fsync_pulse_event( HANDLE handle, LONG *prev ) + + if (prev) *prev = current; + ++ put_object( &obj ); + return STATUS_SUCCESS; + } + +@@ -676,6 +764,7 @@ NTSTATUS fsync_query_event( HANDLE handle, void *info, ULONG *ret_len ) + out->EventType = (obj.type == FSYNC_AUTO_EVENT ? SynchronizationEvent : NotificationEvent); + if (ret_len) *ret_len = sizeof(*out); + ++ put_object( &obj ); + return STATUS_SUCCESS; + } + +@@ -708,7 +797,11 @@ NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) + if ((ret = get_object( handle, &obj ))) return ret; + mutex = obj.shm; + +- if (mutex->tid != GetCurrentThreadId()) return STATUS_MUTANT_NOT_OWNED; ++ if (mutex->tid != GetCurrentThreadId()) ++ { ++ put_object( &obj ); ++ return STATUS_MUTANT_NOT_OWNED; ++ } + + if (prev) *prev = mutex->count; + +@@ -718,6 +811,7 @@ NTSTATUS fsync_release_mutex( HANDLE handle, LONG *prev ) + futex_wake( &mutex->tid, INT_MAX ); + } + ++ put_object( &obj ); + return STATUS_SUCCESS; + } + +@@ -738,6 +832,7 @@ NTSTATUS fsync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) + out->AbandonedState = (mutex->tid == ~0); + if (ret_len) *ret_len = sizeof(*out); + ++ put_object( &obj ); + return STATUS_SUCCESS; + } + +@@ -776,6 +871,14 @@ static NTSTATUS do_single_wait( int *addr, int val, const struct timespec64 *end + return STATUS_PENDING; + } + ++static void put_objects( struct fsync *objs, unsigned int count ) ++{ ++ unsigned int i; ++ ++ for (i = 0; i < count; ++i) ++ if (objs[i].type) put_object_from_wait( &objs[i] ); ++} ++ + static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout ) + { +@@ -814,7 +917,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + + for (i = 0; i < count; i++) + { +- ret = get_object( handles[i], &objs[i] ); ++ ret = get_object_for_wait( handles[i], &objs[i] ); + if (ret == STATUS_SUCCESS) + { + assert( objs[i].type ); +@@ -828,6 +931,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + } + else + { ++ put_objects( objs, i ); + return ret; + } + } +@@ -838,7 +942,10 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + if (has_fsync && has_server) + FIXME("Can't wait on fsync and server objects at the same time!\n"); + else if (has_server) ++ { ++ put_objects( objs, count ); + return STATUS_NOT_IMPLEMENTED; ++ } + + if (TRACE_ON(fsync)) + { +@@ -893,6 +1000,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + if (waited) simulate_sched_quantum(); ++ put_objects( objs, count ); + return i; + } + futex_vector_set( &futexes[i], &semaphore->count, 0 ); +@@ -908,6 +1016,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + mutex->count++; + if (waited) simulate_sched_quantum(); ++ put_objects( objs, count ); + return i; + } + +@@ -916,12 +1025,14 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + mutex->count = 1; + if (waited) simulate_sched_quantum(); ++ put_objects( objs, count ); + return i; + } + else if (tid == ~0 && (tid = __sync_val_compare_and_swap( &mutex->tid, ~0, GetCurrentThreadId() )) == ~0) + { + TRACE("Woken up by abandoned mutex %p [%d].\n", handles[i], i); + mutex->count = 1; ++ put_objects( objs, count ); + return STATUS_ABANDONED_WAIT_0 + i; + } + +@@ -940,6 +1051,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + if (waited) simulate_sched_quantum(); ++ put_objects( objs, count ); + return i; + } + futex_vector_set( &futexes[i], &event->signaled, 0 ); +@@ -958,6 +1070,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + if (waited) simulate_sched_quantum(); ++ put_objects( objs, count ); + return i; + } + futex_vector_set( &futexes[i], &event->signaled, 0 ); +@@ -992,6 +1105,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + /* Unlike esync, we already know that we've timed out, so we + * can avoid a syscall. */ + TRACE("Wait timed out.\n"); ++ put_objects( objs, count ); + return STATUS_TIMEOUT; + } + +@@ -1004,6 +1118,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + if (ret == -1 && errno == ETIMEDOUT) + { + TRACE("Wait timed out.\n"); ++ put_objects( objs, count ); + return STATUS_TIMEOUT; + } + else waited = TRUE; +@@ -1078,6 +1193,7 @@ tryagain: + if (status == STATUS_TIMEOUT) + { + TRACE("Wait timed out.\n"); ++ put_objects( objs, count ); + return status; + } + else if (status == STATUS_USER_APC) +@@ -1167,9 +1283,11 @@ tryagain: + if (abandoned) + { + TRACE("Wait successful, but some object(s) were abandoned.\n"); ++ put_objects( objs, count ); + return STATUS_ABANDONED; + } + TRACE("Wait successful.\n"); ++ put_objects( objs, count ); + return STATUS_SUCCESS; + + tooslow: +@@ -1214,6 +1332,8 @@ tooslow: + userapc: + TRACE("Woken up by user APC.\n"); + ++ put_objects( objs, count ); ++ + /* We have to make a server call anyway to get the APC to execute, so just + * delegate down to server_wait(). */ + ret = server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, &zero ); +@@ -1253,10 +1373,14 @@ NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_an + struct fsync obj; + NTSTATUS ret; + +- if (count && !get_object( handles[count - 1], &obj ) && obj.type == FSYNC_QUEUE) ++ if (count && !get_object( handles[count - 1], &obj )) + { +- msgwait = TRUE; +- server_set_msgwait( 1 ); ++ if (obj.type == FSYNC_QUEUE) ++ { ++ msgwait = TRUE; ++ server_set_msgwait( 1 ); ++ } ++ put_object( &obj ); + } + + ret = __fsync_wait_objects( count, handles, wait_any, alertable, timeout ); +@@ -1288,8 +1412,10 @@ NTSTATUS fsync_signal_and_wait( HANDLE signal, HANDLE wait, BOOLEAN alertable, + ret = fsync_release_mutex( signal, NULL ); + break; + default: +- return STATUS_OBJECT_TYPE_MISMATCH; ++ ret = STATUS_OBJECT_TYPE_MISMATCH; ++ break; + } ++ put_object( &obj ); + if (ret) return ret; + + return fsync_wait_objects( 1, &wait, TRUE, alertable, timeout ); +diff --git a/server/fsync.c b/server/fsync.c +index 3c1e709d7e3..0e3862389da 100644 +--- a/server/fsync.c ++++ b/server/fsync.c +@@ -205,8 +205,8 @@ static void fsync_destroy( struct object *obj ) + + static void *get_shm( unsigned int idx ) + { +- int entry = (idx * 8) / pagesize; +- int offset = (idx * 8) % pagesize; ++ int entry = (idx * 16) / pagesize; ++ int offset = (idx * 16) % pagesize; + + if (entry >= shm_addrs_size) + { +@@ -287,7 +287,7 @@ unsigned int fsync_alloc_shm( int low, int high ) + shm_idx = alloc_shm_idx_from_word( old_size ); + } + +- while (shm_idx * 8 >= shm_size) ++ while (shm_idx * 16 >= shm_size) + { + /* Better expand the shm section. */ + shm_size += pagesize; +@@ -303,6 +303,8 @@ unsigned int fsync_alloc_shm( int low, int high ) + assert(shm); + shm[0] = low; + shm[1] = high; ++ shm[2] = 1; /* Reference count. */ ++ shm[3] = 0; /* Last reference process id. */ + + return shm_idx; + #else +@@ -314,9 +316,24 @@ void fsync_free_shm_idx( int shm_idx ) + { + unsigned int idx; + uint64_t mask; ++ int *shm; + + assert( shm_idx ); + assert( shm_idx < shm_idx_free_map_size * BITS_IN_FREE_MAP_WORD ); ++ ++ shm = get_shm( shm_idx ); ++ if (shm[2] <= 0) ++ { ++ fprintf( stderr, "wineserver: fsync err: shm refcount is %d.\n", shm[2] ); ++ return; ++ } ++ ++ if (__atomic_sub_fetch( &shm[2], 1, __ATOMIC_SEQ_CST )) ++ { ++ /* Sync object is still referenced in a process. */ ++ return; ++ } ++ + idx = shm_idx / BITS_IN_FREE_MAP_WORD; + mask = (uint64_t)1 << (shm_idx % BITS_IN_FREE_MAP_WORD); + assert( !(shm_idx_free_map[idx] & mask) ); +@@ -325,6 +342,31 @@ void fsync_free_shm_idx( int shm_idx ) + shm_idx_free_search_start_hint = idx; + } + ++/* Try to cleanup the shared mem indices locked by the wait on the killed processes. ++ * This is not fully reliable but should avoid leaking the majority of indices on ++ * process kill. */ ++void fsync_cleanup_process_shm_indices( process_id_t id ) ++{ ++ uint64_t free_word; ++ unsigned int i, j; ++ void *shmbase; ++ int *shm; ++ ++ for (i = 0; i < shm_idx_free_map_size; ++i) ++ { ++ free_word = shm_idx_free_map[i]; ++ if (free_word == ~(uint64_t)0) continue; ++ shmbase = get_shm( i * BITS_IN_FREE_MAP_WORD ); ++ for (j = !i; j < BITS_IN_FREE_MAP_WORD; ++j) ++ { ++ shm = (int *)((char *)shmbase + j * 16); ++ if (!(free_word & ((uint64_t)1 << j)) && shm[3] == id ++ && __atomic_load_n( &shm[2], __ATOMIC_SEQ_CST ) == 1) ++ fsync_free_shm_idx( i * BITS_IN_FREE_MAP_WORD + j ); ++ } ++ } ++} ++ + static int type_matches( enum fsync_type type1, enum fsync_type type2 ) + { + return (type1 == type2) || +@@ -384,6 +426,8 @@ struct fsync_event + { + int signaled; + int unused; ++ int ref; ++ int last_pid; + }; + + void fsync_wake_futex( unsigned int shm_idx ) +@@ -551,8 +595,12 @@ DECL_HANDLER(get_fsync_idx) + + if (obj->ops->get_fsync_idx) + { ++ int *shm; ++ + reply->shm_idx = obj->ops->get_fsync_idx( obj, &type ); + reply->type = type; ++ shm = get_shm( reply->shm_idx ); ++ __atomic_add_fetch( &shm[2], 1, __ATOMIC_SEQ_CST ); + } + else + { +@@ -571,3 +619,13 @@ DECL_HANDLER(get_fsync_apc_idx) + { + reply->shm_idx = current->fsync_apc_idx; + } ++ ++DECL_HANDLER(fsync_free_shm_idx) ++{ ++ if (!req->shm_idx || req->shm_idx >= shm_idx_free_map_size * BITS_IN_FREE_MAP_WORD) ++ { ++ set_error( STATUS_INVALID_PARAMETER ); ++ return; ++ } ++ fsync_free_shm_idx( req->shm_idx ); ++} +diff --git a/server/fsync.h b/server/fsync.h +index ee1a729e77e..d4bd889a7f8 100644 +--- a/server/fsync.h ++++ b/server/fsync.h +@@ -33,3 +33,4 @@ extern const struct object_ops fsync_ops; + extern void fsync_set_event( struct fsync *fsync ); + extern void fsync_reset_event( struct fsync *fsync ); + extern void fsync_abandon_mutexes( struct thread *thread ); ++extern void fsync_cleanup_process_shm_indices( process_id_t id ); +diff --git a/server/process.c b/server/process.c +index d43df3d15f6..8b867a26c8a 100644 +--- a/server/process.c ++++ b/server/process.c +@@ -805,7 +805,11 @@ static void process_destroy( struct object *obj ) + free( process->dir_cache ); + free( process->image ); + if (do_esync()) close( process->esync_fd ); +- if (process->fsync_idx) fsync_free_shm_idx( process->fsync_idx ); ++ if (process->fsync_idx) ++ { ++ fsync_cleanup_process_shm_indices( process->id ); ++ fsync_free_shm_idx( process->fsync_idx ); ++ } + } + + /* dump a process on stdout for debugging purposes */ +diff --git a/server/protocol.def b/server/protocol.def +index 2d91baf245a..9d211b683eb 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -4045,3 +4045,8 @@ enum fsync_type + @REPLY + unsigned int shm_idx; + @END ++ ++@REQ(fsync_free_shm_idx) ++ unsigned int shm_idx; ++@REPLY ++@END +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0136-fsync-Increase-shm-page-size.patch b/0007-proton-esync-fsync/0136-fsync-Increase-shm-page-size.patch new file mode 100644 index 0000000..5ff041e --- /dev/null +++ b/0007-proton-esync-fsync/0136-fsync-Increase-shm-page-size.patch @@ -0,0 +1,161 @@ +From 3b2446833d393a9e5a3e9bab4a03cbb671560def Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Mon, 1 Aug 2022 10:53:28 -0500 +Subject: [PATCH 0563/2346] fsync: Increase shm page size. + +CW-Bug-Id: #21050 +--- + dlls/ntdll/unix/fsync.c | 19 +++++++++---------- + server/fsync.c | 19 +++++++++---------- + server/protocol.def | 2 ++ + 3 files changed, 20 insertions(+), 20 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 309e2eb2aff..e709f2cbc00 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -218,14 +218,13 @@ static char shm_name[29]; + static int shm_fd; + static void **shm_addrs; + static int shm_addrs_size; /* length of the allocated shm_addrs array */ +-static long pagesize; + + static pthread_mutex_t shm_addrs_mutex = PTHREAD_MUTEX_INITIALIZER; + + static void *get_shm( unsigned int idx ) + { +- int entry = (idx * 16) / pagesize; +- int offset = (idx * 16) % pagesize; ++ int entry = (idx * 16) / FSYNC_SHM_PAGE_SIZE; ++ int offset = (idx * 16) % FSYNC_SHM_PAGE_SIZE; + void *ret; + + pthread_mutex_lock( &shm_addrs_mutex ); +@@ -242,14 +241,16 @@ static void *get_shm( unsigned int idx ) + + if (!shm_addrs[entry]) + { +- void *addr = mmap( NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, entry * pagesize ); ++ void *addr = mmap( NULL, FSYNC_SHM_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, ++ (off_t)entry * FSYNC_SHM_PAGE_SIZE ); + if (addr == (void *)-1) +- ERR("Failed to map page %d (offset %#lx).\n", entry, entry * pagesize); ++ ERR("Failed to map page %d (offset %s).\n", entry, ++ wine_dbgstr_longlong((off_t)entry * FSYNC_SHM_PAGE_SIZE)); + + TRACE("Mapping page %d at %p.\n", entry, addr); + + if (__sync_val_compare_and_swap( &shm_addrs[entry], 0, addr )) +- munmap( addr, pagesize ); /* someone beat us to it */ ++ munmap( addr, FSYNC_SHM_PAGE_SIZE ); /* someone beat us to it */ + } + + ret = (void *)((unsigned long)shm_addrs[entry] + offset); +@@ -326,10 +327,10 @@ static unsigned int shm_index_from_shm( char *shm ) + + for (i = 0; i < count; ++i) + { +- if (shm >= (char *)shm_addrs[i] && shm < (char *)shm_addrs[i] + pagesize) ++ if (shm >= (char *)shm_addrs[i] && shm < (char *)shm_addrs[i] + FSYNC_SHM_PAGE_SIZE) + { + idx_offset = (shm - (char *)shm_addrs[i]) / 16; +- return i * (pagesize / 16) + idx_offset; ++ return i * (FSYNC_SHM_PAGE_SIZE / 16) + idx_offset; + } + } + +@@ -578,8 +579,6 @@ void fsync_init(void) + exit(1); + } + +- pagesize = sysconf( _SC_PAGESIZE ); +- + shm_addrs = calloc( 128, sizeof(shm_addrs[0]) ); + shm_addrs_size = 128; + } +diff --git a/server/fsync.c b/server/fsync.c +index 0e3862389da..dc50aa0a1f3 100644 +--- a/server/fsync.c ++++ b/server/fsync.c +@@ -73,7 +73,6 @@ static int shm_fd; + static off_t shm_size; + static void **shm_addrs; + static int shm_addrs_size; /* length of the allocated shm_addrs array */ +-static long pagesize; + + static int is_fsync_initialized; + +@@ -109,12 +108,10 @@ void fsync_init(void) + if (shm_fd == -1) + perror( "shm_open" ); + +- pagesize = sysconf( _SC_PAGESIZE ); +- + shm_addrs = calloc( 128, sizeof(shm_addrs[0]) ); + shm_addrs_size = 128; + +- shm_size = pagesize; ++ shm_size = FSYNC_SHM_PAGE_SIZE; + if (ftruncate( shm_fd, shm_size ) == -1) + perror( "ftruncate" ); + +@@ -205,8 +202,8 @@ static void fsync_destroy( struct object *obj ) + + static void *get_shm( unsigned int idx ) + { +- int entry = (idx * 16) / pagesize; +- int offset = (idx * 16) % pagesize; ++ int entry = (idx * 16) / FSYNC_SHM_PAGE_SIZE; ++ int offset = (idx * 16) % FSYNC_SHM_PAGE_SIZE; + + if (entry >= shm_addrs_size) + { +@@ -222,10 +219,12 @@ static void *get_shm( unsigned int idx ) + + if (!shm_addrs[entry]) + { +- void *addr = mmap( NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, entry * pagesize ); ++ void *addr = mmap( NULL, FSYNC_SHM_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, ++ (off_t)entry * FSYNC_SHM_PAGE_SIZE ); + if (addr == (void *)-1) + { +- fprintf( stderr, "fsync: failed to map page %d (offset %#lx): ", entry, entry * pagesize ); ++ fprintf( stderr, "fsync: failed to map page %d (offset %#zx): ", ++ entry, (size_t)entry * FSYNC_SHM_PAGE_SIZE ); + perror( "mmap" ); + } + +@@ -233,7 +232,7 @@ static void *get_shm( unsigned int idx ) + fprintf( stderr, "fsync: Mapping page %d at %p.\n", entry, addr ); + + if (__sync_val_compare_and_swap( &shm_addrs[entry], 0, addr )) +- munmap( addr, pagesize ); /* someone beat us to it */ ++ munmap( addr, FSYNC_SHM_PAGE_SIZE ); /* someone beat us to it */ + } + + return (void *)((unsigned long)shm_addrs[entry] + offset); +@@ -290,7 +289,7 @@ unsigned int fsync_alloc_shm( int low, int high ) + while (shm_idx * 16 >= shm_size) + { + /* Better expand the shm section. */ +- shm_size += pagesize; ++ shm_size += FSYNC_SHM_PAGE_SIZE; + if (ftruncate( shm_fd, shm_size ) == -1) + { + fprintf( stderr, "fsync: couldn't expand %s to size %jd: ", +diff --git a/server/protocol.def b/server/protocol.def +index 9d211b683eb..311265289bd 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3992,6 +3992,8 @@ enum esync_type + @REQ(get_esync_apc_fd) + @END + ++#define FSYNC_SHM_PAGE_SIZE 0x10000 ++ + enum fsync_type + { + FSYNC_SEMAPHORE = 1, +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0137-fsync-Use-static-shm_addrs-array-and-get-rid-of-lock.patch b/0007-proton-esync-fsync/0137-fsync-Use-static-shm_addrs-array-and-get-rid-of-lock.patch new file mode 100644 index 0000000..520be93 --- /dev/null +++ b/0007-proton-esync-fsync/0137-fsync-Use-static-shm_addrs-array-and-get-rid-of-lock.patch @@ -0,0 +1,86 @@ +From 75ec6162846bbcf9c0d59a6e72221c15207139e3 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Mon, 1 Aug 2022 11:01:51 -0500 +Subject: [PATCH 0564/2346] fsync: Use static shm_addrs array and get rid of + locking in get_shm(). + +CW-Bug-Id: #21050 +--- + dlls/ntdll/unix/fsync.c | 31 +++++++------------------------ + 1 file changed, 7 insertions(+), 24 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index e709f2cbc00..be27906a37c 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -216,27 +216,18 @@ C_ASSERT(sizeof(struct mutex) == 16); + + static char shm_name[29]; + static int shm_fd; +-static void **shm_addrs; +-static int shm_addrs_size; /* length of the allocated shm_addrs array */ +- +-static pthread_mutex_t shm_addrs_mutex = PTHREAD_MUTEX_INITIALIZER; ++static volatile void *shm_addrs[8192]; + + static void *get_shm( unsigned int idx ) + { + int entry = (idx * 16) / FSYNC_SHM_PAGE_SIZE; + int offset = (idx * 16) % FSYNC_SHM_PAGE_SIZE; +- void *ret; +- +- pthread_mutex_lock( &shm_addrs_mutex ); + +- if (entry >= shm_addrs_size) ++ if (entry >= ARRAY_SIZE(shm_addrs)) + { +- int new_size = max(shm_addrs_size * 2, entry + 1); +- +- if (!(shm_addrs = realloc( shm_addrs, new_size * sizeof(shm_addrs[0]) ))) +- ERR("Failed to grow shm_addrs array to size %d.\n", shm_addrs_size); +- memset( shm_addrs + shm_addrs_size, 0, (new_size - shm_addrs_size) * sizeof(shm_addrs[0]) ); +- shm_addrs_size = new_size; ++ ERR( "idx %u exceeds maximum of %u.\n", idx, ++ (unsigned int)ARRAY_SIZE(shm_addrs) * (FSYNC_SHM_PAGE_SIZE / 16) ); ++ return NULL; + } + + if (!shm_addrs[entry]) +@@ -253,11 +244,7 @@ static void *get_shm( unsigned int idx ) + munmap( addr, FSYNC_SHM_PAGE_SIZE ); /* someone beat us to it */ + } + +- ret = (void *)((unsigned long)shm_addrs[entry] + offset); +- +- pthread_mutex_unlock( &shm_addrs_mutex ); +- +- return ret; ++ return (char *)shm_addrs[entry] + offset; + } + + /* We'd like lookup to be fast. To that end, we use a static list indexed by handle. +@@ -322,10 +309,9 @@ static void grab_object( struct fsync *obj ) + + static unsigned int shm_index_from_shm( char *shm ) + { +- unsigned int count = shm_addrs_size; + unsigned int i, idx_offset; + +- for (i = 0; i < count; ++i) ++ for (i = 0; i < ARRAY_SIZE(shm_addrs); ++i) + { + if (shm >= (char *)shm_addrs[i] && shm < (char *)shm_addrs[i] + FSYNC_SHM_PAGE_SIZE) + { +@@ -578,9 +564,6 @@ void fsync_init(void) + ERR("Failed to initialize shared memory: %s\n", strerror( errno )); + exit(1); + } +- +- shm_addrs = calloc( 128, sizeof(shm_addrs[0]) ); +- shm_addrs_size = 128; + } + + NTSTATUS fsync_create_semaphore( HANDLE *handle, ACCESS_MASK access, +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0138-esync-fsync-Support-waiting-on-file-handles.patch b/0007-proton-esync-fsync/0138-esync-fsync-Support-waiting-on-file-handles.patch new file mode 100644 index 0000000..a65f237 --- /dev/null +++ b/0007-proton-esync-fsync/0138-esync-fsync-Support-waiting-on-file-handles.patch @@ -0,0 +1,28 @@ +From 7d02e2264a8595175610a058f206e7d639bf8232 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Tue, 16 Aug 2022 12:34:09 -0500 +Subject: [PATCH 0565/2346] esync, fsync: Support waiting on file handles. + +CW-Bug-Id: #21132 +--- + server/file.c | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/server/file.c b/server/file.c +index 5be9578ce48..500ffcac153 100644 +--- a/server/file.c ++++ b/server/file.c +@@ -94,8 +94,8 @@ static const struct object_ops file_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + default_fd_signaled, /* signaled */ +- NULL, /* get_esync_fd */ +- NULL, /* get_fsync_idx */ ++ default_fd_get_esync_fd, /* get_esync_fd */ ++ default_fd_get_fsync_idx, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + file_get_fd, /* get_fd */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0139-ntdll-Enable-WINE_FSYNC_SIMULATE_SCHED_QUANTUM-for-P.patch b/0007-proton-esync-fsync/0139-ntdll-Enable-WINE_FSYNC_SIMULATE_SCHED_QUANTUM-for-P.patch new file mode 100644 index 0000000..e9714b5 --- /dev/null +++ b/0007-proton-esync-fsync/0139-ntdll-Enable-WINE_FSYNC_SIMULATE_SCHED_QUANTUM-for-P.patch @@ -0,0 +1,29 @@ +From 9dd028203dc6122bd62d0005d4a46c285fb1b710 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Wed, 17 Aug 2022 18:22:35 -0500 +Subject: [PATCH 0570/2346] ntdll: Enable WINE_FSYNC_SIMULATE_SCHED_QUANTUM for + Planet Zoo. + +CW-Bug-Id: #21142 +--- + dlls/ntdll/unix/loader.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c +index c1d7ff801d4..a0b27a3dd3c 100644 +--- a/dlls/ntdll/unix/loader.c ++++ b/dlls/ntdll/unix/loader.c +@@ -1937,7 +1937,10 @@ static void hacks_init(void) + if (env_str) + fsync_simulate_sched_quantum = !!atoi(env_str); + else if (main_argc > 1) ++ { + fsync_simulate_sched_quantum = !!strstr(main_argv[1], "Ubisoft Game Launcher\\upc.exe"); ++ fsync_simulate_sched_quantum = fsync_simulate_sched_quantum || !!strstr(main_argv[1], "PlanetZoo.exe"); ++ } + if (fsync_simulate_sched_quantum) + ERR("HACK: Simulating sched quantum in fsync.\n"); + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0140-ntdll-Enable-WINE_FSYNC_SIMULATE_SCHED_QUANTUM-for-G.patch b/0007-proton-esync-fsync/0140-ntdll-Enable-WINE_FSYNC_SIMULATE_SCHED_QUANTUM-for-G.patch new file mode 100644 index 0000000..922fe78 --- /dev/null +++ b/0007-proton-esync-fsync/0140-ntdll-Enable-WINE_FSYNC_SIMULATE_SCHED_QUANTUM-for-G.patch @@ -0,0 +1,26 @@ +From cfa7ea534040f7513da90f7013433dd3969a49a8 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Fri, 9 Sep 2022 17:37:39 -0500 +Subject: [PATCH 0571/2346] ntdll: Enable WINE_FSYNC_SIMULATE_SCHED_QUANTUM for + GTA5. + +CW-Bug-Id: #21194 +--- + dlls/ntdll/unix/loader.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c +index a0b27a3dd3c..8d8c1700937 100644 +--- a/dlls/ntdll/unix/loader.c ++++ b/dlls/ntdll/unix/loader.c +@@ -1940,6 +1940,7 @@ static void hacks_init(void) + { + fsync_simulate_sched_quantum = !!strstr(main_argv[1], "Ubisoft Game Launcher\\upc.exe"); + fsync_simulate_sched_quantum = fsync_simulate_sched_quantum || !!strstr(main_argv[1], "PlanetZoo.exe"); ++ fsync_simulate_sched_quantum = fsync_simulate_sched_quantum || !!strstr(main_argv[1], "GTA5.exe"); + } + if (fsync_simulate_sched_quantum) + ERR("HACK: Simulating sched quantum in fsync.\n"); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0141-ntdll-HACK-Add-WINE_ALERT_SIMULATE_SCHED_QUANTUM-opt.patch b/0007-proton-esync-fsync/0141-ntdll-HACK-Add-WINE_ALERT_SIMULATE_SCHED_QUANTUM-opt.patch new file mode 100644 index 0000000..5d5b7c2 --- /dev/null +++ b/0007-proton-esync-fsync/0141-ntdll-HACK-Add-WINE_ALERT_SIMULATE_SCHED_QUANTUM-opt.patch @@ -0,0 +1,87 @@ +From ba766a27c3e186e1cd82ac9998a6bcd77aa0d471 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Fri, 9 Sep 2022 18:21:26 -0500 +Subject: [PATCH 0572/2346] ntdll: HACK: Add WINE_ALERT_SIMULATE_SCHED_QUANTUM + option. + +And enable it for GTA 5. + +CW-Bug-Id: #21194 +--- + dlls/ntdll/unix/loader.c | 11 +++++++++++ + dlls/ntdll/unix/sync.c | 8 ++++++++ + dlls/ntdll/unix/unix_private.h | 1 + + 3 files changed, 20 insertions(+) + +diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c +index 8d8c1700937..60488301f16 100644 +--- a/dlls/ntdll/unix/loader.c ++++ b/dlls/ntdll/unix/loader.c +@@ -1922,6 +1922,7 @@ static ULONG_PTR get_image_address(void) + + BOOL ac_odyssey; + BOOL fsync_simulate_sched_quantum; ++BOOL alert_simulate_sched_quantum; + + static void hacks_init(void) + { +@@ -1945,6 +1946,16 @@ static void hacks_init(void) + if (fsync_simulate_sched_quantum) + ERR("HACK: Simulating sched quantum in fsync.\n"); + ++ env_str = getenv("WINE_ALERT_SIMULATE_SCHED_QUANTUM"); ++ if (env_str) ++ alert_simulate_sched_quantum = !!atoi(env_str); ++ else if (main_argc > 1) ++ { ++ alert_simulate_sched_quantum = !!strstr(main_argv[1], "GTA5.exe"); ++ } ++ if (alert_simulate_sched_quantum) ++ ERR("HACK: Simulating sched quantum in NtWaitForAlertByThreadId.\n"); ++ + switch (sgi ? atoi( sgi ) : -1) + { + case 25700: /* Madballs in Babo: Invasion */ +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index f83a81afd9a..ed30388b026 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -2706,6 +2706,7 @@ NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEG + NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEGER *timeout ) + { + union tid_alert_entry *entry = get_tid_alert_entry( NtCurrentTeb()->ClientId.UniqueThread ); ++ BOOL waited = FALSE; + + TRACE( "%p %s\n", address, debugstr_timeout( timeout ) ); + +@@ -2741,8 +2742,15 @@ NTSTATUS WINAPI NtWaitForAlertByThreadId( const void *address, const LARGE_INTEG + else + ret = futex_wait( futex, 0, NULL ); + ++ if (!timeout || timeout->QuadPart) ++ waited = TRUE; ++ + if (ret == -1 && errno == ETIMEDOUT) return STATUS_TIMEOUT; + } ++ ++ if (alert_simulate_sched_quantum && waited) ++ usleep(0); ++ + return STATUS_ALERTED; + } + #endif +diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h +index cc5f1ffc9e0..92668512e90 100644 +--- a/dlls/ntdll/unix/unix_private.h ++++ b/dlls/ntdll/unix/unix_private.h +@@ -180,6 +180,7 @@ extern struct ldt_copy __wine_ldt_copy; + + extern BOOL ac_odyssey; + extern BOOL fsync_simulate_sched_quantum; ++extern BOOL alert_simulate_sched_quantum; + + extern void init_environment(void); + extern void init_startup_info(void); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0142-ntdll-HACK-Also-simulate-async-file-read-and-IO-canc.patch b/0007-proton-esync-fsync/0142-ntdll-HACK-Also-simulate-async-file-read-and-IO-canc.patch new file mode 100644 index 0000000..4c59aa3 --- /dev/null +++ b/0007-proton-esync-fsync/0142-ntdll-HACK-Also-simulate-async-file-read-and-IO-canc.patch @@ -0,0 +1,38 @@ +From ce9cde9bdc535bf820e529ee29ca17e5b2fdf9c8 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Fri, 16 Dec 2022 16:21:50 -0600 +Subject: [PATCH 0573/2346] ntdll: HACK: Also simulate async file read and IO + cancellation for Immortals Fenyx Rising. + +CW-Bug-Id: #21711 +--- + dlls/ntdll/unix/loader.c | 12 ++++++++---- + 1 file changed, 8 insertions(+), 4 deletions(-) + +diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c +index 60488301f16..9cdfed963f8 100644 +--- a/dlls/ntdll/unix/loader.c ++++ b/dlls/ntdll/unix/loader.c +@@ -1929,11 +1929,15 @@ static void hacks_init(void) + const char *sgi = getenv( "SteamGameId" ); + const char *env_str; + +- if (main_argc > 1 && strstr(main_argv[1], "ACOdyssey.exe")) +- { +- ERR("HACK: AC Odyssey sync tweak on.\n"); ++ env_str = getenv("WINE_SIMULATE_ASYNC_READ"); ++ if (env_str) ++ ac_odyssey = !!atoi(env_str); ++ else if (main_argc > 1 && (strstr(main_argv[1], "ACOdyssey.exe") || strstr(main_argv[1], "ImmortalsFenyxRising.exe"))) + ac_odyssey = TRUE; +- } ++ ++ if (ac_odyssey) ++ ERR("HACK: AC Odyssey sync tweak on.\n"); ++ + env_str = getenv("WINE_FSYNC_SIMULATE_SCHED_QUANTUM"); + if (env_str) + fsync_simulate_sched_quantum = !!atoi(env_str); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0143-fsync-Retry-grabbing-semaphore-if-count-has-changed.patch b/0007-proton-esync-fsync/0143-fsync-Retry-grabbing-semaphore-if-count-has-changed.patch new file mode 100644 index 0000000..611aac1 --- /dev/null +++ b/0007-proton-esync-fsync/0143-fsync-Retry-grabbing-semaphore-if-count-has-changed.patch @@ -0,0 +1,63 @@ +From fa2e7224e08179417d43c62bc8113685b670faf2 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Tue, 7 Mar 2023 15:54:01 -0600 +Subject: [PATCH 0575/2346] fsync: Retry grabbing semaphore if count has + changed. + +CW-Bug-Id: #21996 +--- + dlls/ntdll/unix/fsync.c | 28 ++++++++++++++++++---------- + 1 file changed, 18 insertions(+), 10 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index be27906a37c..4dade5eb27f 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -975,15 +975,18 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + case FSYNC_SEMAPHORE: + { + struct semaphore *semaphore = obj->shm; +- int current; ++ int current, new; + +- if ((current = __atomic_load_n( &semaphore->count, __ATOMIC_SEQ_CST )) +- && __sync_val_compare_and_swap( &semaphore->count, current, current - 1 ) == current) ++ new = __atomic_load_n( &semaphore->count, __ATOMIC_SEQ_CST ); ++ while ((current = new)) + { +- TRACE("Woken up by handle %p [%d].\n", handles[i], i); +- if (waited) simulate_sched_quantum(); +- put_objects( objs, count ); +- return i; ++ if ((new = __sync_val_compare_and_swap( &semaphore->count, current, current - 1 )) == current) ++ { ++ TRACE("Woken up by handle %p [%d].\n", handles[i], i); ++ if (waited) simulate_sched_quantum(); ++ put_objects( objs, count ); ++ return i; ++ } + } + futex_vector_set( &futexes[i], &semaphore->count, 0 ); + break; +@@ -1229,10 +1232,15 @@ tryagain: + case FSYNC_SEMAPHORE: + { + struct semaphore *semaphore = obj->shm; +- int current; ++ int current, new; + +- if (!(current = __atomic_load_n( &semaphore->count, __ATOMIC_SEQ_CST )) +- || __sync_val_compare_and_swap( &semaphore->count, current, current - 1 ) != current) ++ new = __atomic_load_n( &semaphore->count, __ATOMIC_SEQ_CST ); ++ while ((current = new)) ++ { ++ if ((new = __sync_val_compare_and_swap( &semaphore->count, current, current - 1 )) == current) ++ break; ++ } ++ if (!current) + goto tooslow; + break; + } +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0144-fsync-Cache-current-process-ID.patch b/0007-proton-esync-fsync/0144-fsync-Cache-current-process-ID.patch new file mode 100644 index 0000000..02ccc13 --- /dev/null +++ b/0007-proton-esync-fsync/0144-fsync-Cache-current-process-ID.patch @@ -0,0 +1,54 @@ +From 1f907e33609c14ecac945292b9f761d28bebba68 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Thu, 27 Apr 2023 16:53:17 -0600 +Subject: [PATCH 0576/2346] fsync: Cache current process ID. + +CW-Bug-Id: #22194 +--- + dlls/ntdll/unix/fsync.c | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 4dade5eb27f..c5d38754ea6 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -59,6 +59,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(fsync); + #include "pshpack4.h" + #include "poppack.h" + ++static int current_pid; ++ + /* futex_waitv interface */ + + #ifndef __NR_futex_waitv +@@ -348,7 +350,7 @@ static void put_object_from_wait( struct fsync *obj ) + { + int *shm = obj->shm; + +- __sync_val_compare_and_swap( &shm[3], GetCurrentProcessId(), 0 ); ++ __sync_val_compare_and_swap( &shm[3], current_pid, 0 ); + put_object( obj ); + } + +@@ -434,7 +436,7 @@ static NTSTATUS get_object_for_wait( HANDLE handle, struct fsync *obj ) + shm = obj->shm; + /* Give wineserver a chance to cleanup shm index if the process + * is killed while we are waiting on the object. */ +- __atomic_store_n( &shm[3], GetCurrentProcessId(), __ATOMIC_SEQ_CST ); ++ __atomic_store_n( &shm[3], current_pid, __ATOMIC_SEQ_CST ); + return STATUS_SUCCESS; + } + +@@ -564,6 +566,9 @@ void fsync_init(void) + ERR("Failed to initialize shared memory: %s\n", strerror( errno )); + exit(1); + } ++ ++ current_pid = GetCurrentProcessId(); ++ assert(current_pid); + } + + NTSTATUS fsync_create_semaphore( HANDLE *handle, ACCESS_MASK access, +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0145-fsync-Cache-current-TID-in-__fsync_wait_objects.patch b/0007-proton-esync-fsync/0145-fsync-Cache-current-TID-in-__fsync_wait_objects.patch new file mode 100644 index 0000000..ccf7ec4 --- /dev/null +++ b/0007-proton-esync-fsync/0145-fsync-Cache-current-TID-in-__fsync_wait_objects.patch @@ -0,0 +1,94 @@ +From 5fe3571986dbd70a5a6ca11f5864a4a17a2607de Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Thu, 27 Apr 2023 16:56:26 -0600 +Subject: [PATCH 0577/2346] fsync: Cache current TID in __fsync_wait_objects(). + +CW-Bug-Id: #22194 +--- + dlls/ntdll/unix/fsync.c | 18 +++++++++++------- + 1 file changed, 11 insertions(+), 7 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index c5d38754ea6..d3ad9788600 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -871,6 +871,9 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + { + static const LARGE_INTEGER zero = {0}; + ++ int current_tid = 0; ++#define CURRENT_TID (current_tid ? current_tid : (current_tid = GetCurrentThreadId())) ++ + struct futex_waitv futexes[MAXIMUM_WAIT_OBJECTS + 1]; + struct fsync objs[MAXIMUM_WAIT_OBJECTS]; + BOOL msgwait = FALSE, waited = FALSE; +@@ -1001,7 +1004,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + struct mutex *mutex = obj->shm; + int tid; + +- if (mutex->tid == GetCurrentThreadId()) ++ if (mutex->tid == CURRENT_TID) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + mutex->count++; +@@ -1010,7 +1013,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + return i; + } + +- if (!(tid = __sync_val_compare_and_swap( &mutex->tid, 0, GetCurrentThreadId() ))) ++ if (!(tid = __sync_val_compare_and_swap( &mutex->tid, 0, CURRENT_TID ))) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); + mutex->count = 1; +@@ -1018,7 +1021,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + put_objects( objs, count ); + return i; + } +- else if (tid == ~0 && (tid = __sync_val_compare_and_swap( &mutex->tid, ~0, GetCurrentThreadId() )) == ~0) ++ else if (tid == ~0 && (tid = __sync_val_compare_and_swap( &mutex->tid, ~0, CURRENT_TID )) == ~0) + { + TRACE("Woken up by abandoned mutex %p [%d].\n", handles[i], i); + mutex->count = 1; +@@ -1157,7 +1160,7 @@ tryagain: + { + struct mutex *mutex = obj->shm; + +- if (mutex->tid == GetCurrentThreadId()) ++ if (mutex->tid == CURRENT_TID) + continue; + + while ((current = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST ))) +@@ -1201,7 +1204,7 @@ tryagain: + struct mutex *mutex = obj->shm; + int tid = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST ); + +- if (tid && tid != ~0 && tid != GetCurrentThreadId()) ++ if (tid && tid != ~0 && tid != CURRENT_TID) + goto tryagain; + } + else if (obj->type) +@@ -1224,11 +1227,11 @@ tryagain: + { + struct mutex *mutex = obj->shm; + int tid = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST ); +- if (tid == GetCurrentThreadId()) ++ if (tid == CURRENT_TID) + break; + if (tid && tid != ~0) + goto tooslow; +- if (__sync_val_compare_and_swap( &mutex->tid, tid, GetCurrentThreadId() ) != tid) ++ if (__sync_val_compare_and_swap( &mutex->tid, tid, CURRENT_TID ) != tid) + goto tooslow; + if (tid == ~0) + abandoned = TRUE; +@@ -1338,6 +1341,7 @@ userapc: + * right thing to do seems to be to return STATUS_USER_APC anyway. */ + if (ret == STATUS_TIMEOUT) ret = STATUS_USER_APC; + return ret; ++#undef CURRENT_TID + } + + /* Like esync, we need to let the server know when we are doing a message wait, +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0146-fsync-Add-WINE_FSYNC_YIELD_TO_WAITERS-option.patch b/0007-proton-esync-fsync/0146-fsync-Add-WINE_FSYNC_YIELD_TO_WAITERS-option.patch new file mode 100644 index 0000000..47b458f --- /dev/null +++ b/0007-proton-esync-fsync/0146-fsync-Add-WINE_FSYNC_YIELD_TO_WAITERS-option.patch @@ -0,0 +1,149 @@ +From 2e9b6e6677fb0ae225ec5892ca3f0c0c680acf0f Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Thu, 27 Apr 2023 17:32:38 -0600 +Subject: [PATCH 0578/2346] fsync: Add WINE_FSYNC_YIELD_TO_WAITERS option. + +CW-Bug-Id: #22194 +--- + dlls/ntdll/unix/fsync.c | 37 +++++++++++++++++++++++++++++++--- + dlls/ntdll/unix/loader.c | 7 +++++++ + dlls/ntdll/unix/unix_private.h | 1 + + 3 files changed, 42 insertions(+), 3 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index d3ad9788600..0e862e5bbc2 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -426,7 +426,7 @@ static NTSTATUS get_object( HANDLE handle, struct fsync *obj ) + return ret; + } + +-static NTSTATUS get_object_for_wait( HANDLE handle, struct fsync *obj ) ++static NTSTATUS get_object_for_wait( HANDLE handle, struct fsync *obj, int *prev_pid ) + { + NTSTATUS ret; + int *shm; +@@ -436,7 +436,10 @@ static NTSTATUS get_object_for_wait( HANDLE handle, struct fsync *obj ) + shm = obj->shm; + /* Give wineserver a chance to cleanup shm index if the process + * is killed while we are waiting on the object. */ +- __atomic_store_n( &shm[3], current_pid, __ATOMIC_SEQ_CST ); ++ if (fsync_yield_to_waiters) ++ *prev_pid = __atomic_exchange_n( &shm[3], current_pid, __ATOMIC_SEQ_CST ); ++ else ++ __atomic_store_n( &shm[3], current_pid, __ATOMIC_SEQ_CST ); + return STATUS_SUCCESS; + } + +@@ -823,6 +826,24 @@ NTSTATUS fsync_query_mutex( HANDLE handle, void *info, ULONG *ret_len ) + return STATUS_SUCCESS; + } + ++static inline void try_yield_to_waiters( int prev_pid ) ++{ ++ if (!fsync_yield_to_waiters) return; ++ ++ /* On Windows singaling an object will wake the threads waiting on the object. With fsync ++ * it may happen that signaling thread (or other thread) grabs the object before the already waiting ++ * thread gets a chance. Try to workaround that for the affected apps. Non-zero 'prev_pid' indicates ++ * that the object is grabbed in __fsync_wait_objects() by some other thread. It is the same for ++ * a non-current pid, but we may currently have a stale PID on an object from a terminated process ++ * and it is probably safer to skip this workaround. This won't work great if the object is used in 'wait all' ++ * and the waiter is blocked on the other object. ++ * This check is also not entirely reliable as if multiple waiters from the same process enter ++ * __fsync_wait_objects() the first one leaving will clear 'last_pid' in the object. */ ++ ++ if (prev_pid == current_pid) ++ usleep(0); ++} ++ + static NTSTATUS do_single_wait( int *addr, int val, const struct timespec64 *end, clockid_t clock_id, + BOOLEAN alertable ) + { +@@ -877,6 +898,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + struct futex_waitv futexes[MAXIMUM_WAIT_OBJECTS + 1]; + struct fsync objs[MAXIMUM_WAIT_OBJECTS]; + BOOL msgwait = FALSE, waited = FALSE; ++ int prev_pids[MAXIMUM_WAIT_OBJECTS]; + int has_fsync = 0, has_server = 0; + clockid_t clock_id = 0; + struct timespec64 end; +@@ -907,7 +929,7 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + + for (i = 0; i < count; i++) + { +- ret = get_object_for_wait( handles[i], &objs[i] ); ++ ret = get_object_for_wait( handles[i], &objs[i], &prev_pids[i] ); + if (ret == STATUS_SUCCESS) + { + assert( objs[i].type ); +@@ -986,6 +1008,9 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + int current, new; + + new = __atomic_load_n( &semaphore->count, __ATOMIC_SEQ_CST ); ++ if (!waited && new) ++ try_yield_to_waiters(prev_pids[i]); ++ + while ((current = new)) + { + if ((new = __sync_val_compare_and_swap( &semaphore->count, current, current - 1 )) == current) +@@ -1013,6 +1038,9 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + return i; + } + ++ if (!waited && !mutex->tid) ++ try_yield_to_waiters(prev_pids[i]); ++ + if (!(tid = __sync_val_compare_and_swap( &mutex->tid, 0, CURRENT_TID ))) + { + TRACE("Woken up by handle %p [%d].\n", handles[i], i); +@@ -1037,6 +1065,9 @@ static NTSTATUS __fsync_wait_objects( DWORD count, const HANDLE *handles, + { + struct event *event = obj->shm; + ++ if (!waited && event->signaled) ++ try_yield_to_waiters(prev_pids[i]); ++ + if (__sync_val_compare_and_swap( &event->signaled, 1, 0 )) + { + if (ac_odyssey && alertable) +diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c +index 9cdfed963f8..723b033751a 100644 +--- a/dlls/ntdll/unix/loader.c ++++ b/dlls/ntdll/unix/loader.c +@@ -1923,6 +1923,7 @@ static ULONG_PTR get_image_address(void) + BOOL ac_odyssey; + BOOL fsync_simulate_sched_quantum; + BOOL alert_simulate_sched_quantum; ++BOOL fsync_yield_to_waiters; + + static void hacks_init(void) + { +@@ -1960,6 +1961,12 @@ static void hacks_init(void) + if (alert_simulate_sched_quantum) + ERR("HACK: Simulating sched quantum in NtWaitForAlertByThreadId.\n"); + ++ env_str = getenv("WINE_FSYNC_YIELD_TO_WAITERS"); ++ if (env_str) ++ fsync_yield_to_waiters = !!atoi(env_str); ++ if (fsync_yield_to_waiters) ++ ERR("HACK: fsync: yield to waiters.\n"); ++ + switch (sgi ? atoi( sgi ) : -1) + { + case 25700: /* Madballs in Babo: Invasion */ +diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h +index 92668512e90..c61187266e6 100644 +--- a/dlls/ntdll/unix/unix_private.h ++++ b/dlls/ntdll/unix/unix_private.h +@@ -181,6 +181,7 @@ extern struct ldt_copy __wine_ldt_copy; + extern BOOL ac_odyssey; + extern BOOL fsync_simulate_sched_quantum; + extern BOOL alert_simulate_sched_quantum; ++extern BOOL fsync_yield_to_waiters; + + extern void init_environment(void); + extern void init_startup_info(void); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0147-ntdll-HACK-Enable-WINE_FSYNC_YIELD_TO_WAITERS-for-FF.patch b/0007-proton-esync-fsync/0147-ntdll-HACK-Enable-WINE_FSYNC_YIELD_TO_WAITERS-for-FF.patch new file mode 100644 index 0000000..40742de --- /dev/null +++ b/0007-proton-esync-fsync/0147-ntdll-HACK-Enable-WINE_FSYNC_YIELD_TO_WAITERS-for-FF.patch @@ -0,0 +1,26 @@ +From 4d9d9f347214ba852f7cea8d033f241c1cc55fd6 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Thu, 27 Apr 2023 18:19:01 -0600 +Subject: [PATCH 0579/2346] ntdll: HACK: Enable WINE_FSYNC_YIELD_TO_WAITERS for + FFXIII. + +CW-Bug-Id: #22194 +--- + dlls/ntdll/unix/loader.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c +index 723b033751a..249aa70e01d 100644 +--- a/dlls/ntdll/unix/loader.c ++++ b/dlls/ntdll/unix/loader.c +@@ -1964,6 +1964,7 @@ static void hacks_init(void) + env_str = getenv("WINE_FSYNC_YIELD_TO_WAITERS"); + if (env_str) + fsync_yield_to_waiters = !!atoi(env_str); ++ else if (sgi) fsync_yield_to_waiters = !strcmp(sgi, "292120"); + if (fsync_yield_to_waiters) + ERR("HACK: fsync: yield to waiters.\n"); + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0148-ntdll-HACK-Enable-fsync_yield_to_waiters-for-LIGHTNI.patch b/0007-proton-esync-fsync/0148-ntdll-HACK-Enable-fsync_yield_to_waiters-for-LIGHTNI.patch new file mode 100644 index 0000000..cbc84f1 --- /dev/null +++ b/0007-proton-esync-fsync/0148-ntdll-HACK-Enable-fsync_yield_to_waiters-for-LIGHTNI.patch @@ -0,0 +1,27 @@ +From b2d168ec8aadd8c66e0556dad2467b6cac302037 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Tue, 21 Nov 2023 18:06:59 -0600 +Subject: [PATCH 0580/2346] ntdll: HACK: Enable fsync_yield_to_waiters for + LIGHTNING RETURNS: FFXIII. + +CW-Bug-Id: #23021 +--- + dlls/ntdll/unix/loader.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c +index 249aa70e01d..1bc6e147818 100644 +--- a/dlls/ntdll/unix/loader.c ++++ b/dlls/ntdll/unix/loader.c +@@ -1964,7 +1964,7 @@ static void hacks_init(void) + env_str = getenv("WINE_FSYNC_YIELD_TO_WAITERS"); + if (env_str) + fsync_yield_to_waiters = !!atoi(env_str); +- else if (sgi) fsync_yield_to_waiters = !strcmp(sgi, "292120"); ++ else if (sgi) fsync_yield_to_waiters = !strcmp(sgi, "292120") || !strcmp(sgi, "345350"); + if (fsync_yield_to_waiters) + ERR("HACK: fsync: yield to waiters.\n"); + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0149-ntdll-HACK-Enable-fsync_yield_to_waiters-for-FFXIII-.patch b/0007-proton-esync-fsync/0149-ntdll-HACK-Enable-fsync_yield_to_waiters-for-FFXIII-.patch new file mode 100644 index 0000000..5e5d5d7 --- /dev/null +++ b/0007-proton-esync-fsync/0149-ntdll-HACK-Enable-fsync_yield_to_waiters-for-FFXIII-.patch @@ -0,0 +1,27 @@ +From 5643bc14e8b79545887af6db6b76fe73b91360e8 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Wed, 6 Dec 2023 21:06:56 -0600 +Subject: [PATCH 0581/2346] ntdll: HACK: Enable fsync_yield_to_waiters for + FFXIII-2. + +CW-Bug-Id: #23021 +--- + dlls/ntdll/unix/loader.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c +index 1bc6e147818..af3055bc93b 100644 +--- a/dlls/ntdll/unix/loader.c ++++ b/dlls/ntdll/unix/loader.c +@@ -1964,7 +1964,7 @@ static void hacks_init(void) + env_str = getenv("WINE_FSYNC_YIELD_TO_WAITERS"); + if (env_str) + fsync_yield_to_waiters = !!atoi(env_str); +- else if (sgi) fsync_yield_to_waiters = !strcmp(sgi, "292120") || !strcmp(sgi, "345350"); ++ else if (sgi) fsync_yield_to_waiters = !strcmp(sgi, "292120") || !strcmp(sgi, "345350") || !strcmp(sgi, "292140"); + if (fsync_yield_to_waiters) + ERR("HACK: fsync: yield to waiters.\n"); + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0150-fsync-Avoid-race-between-NtClose-and-get_object.patch b/0007-proton-esync-fsync/0150-fsync-Avoid-race-between-NtClose-and-get_object.patch new file mode 100644 index 0000000..2001cf1 --- /dev/null +++ b/0007-proton-esync-fsync/0150-fsync-Avoid-race-between-NtClose-and-get_object.patch @@ -0,0 +1,87 @@ +From c4b4157c28e4fc1a7934a62241f10e706ae0a6e3 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Mon, 13 Mar 2023 21:39:04 -0600 +Subject: [PATCH 0582/2346] fsync: Avoid race between NtClose() and + get_object(). + +CW-Bug-Id: #22029 +--- + dlls/ntdll/unix/fsync.c | 19 ++++++++++++++++--- + dlls/ntdll/unix/fsync.h | 5 +++++ + 2 files changed, 21 insertions(+), 3 deletions(-) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 0e862e5bbc2..3aa32872a80 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -374,8 +374,9 @@ again: + { + /* This check does not strictly guarantee that we avoid the potential race but is supposed to greatly + * reduce the probability of that. */ ++ FIXME( "Cache changed while getting object, handle %p, shm_idx %d, refcount %d.\n", ++ handle, cache.shm_idx, ((int *)obj->shm)[2] ); + put_object( obj ); +- FIXME( "Cache changed while getting object.\n" ); + goto again; + } + return TRUE; +@@ -390,6 +391,7 @@ static NTSTATUS get_object( HANDLE handle, struct fsync *obj ) + NTSTATUS ret = STATUS_SUCCESS; + unsigned int shm_idx = 0; + enum fsync_type type; ++ sigset_t sigset; + + if (get_cached_object( handle, obj )) return STATUS_SUCCESS; + +@@ -399,7 +401,17 @@ static NTSTATUS get_object( HANDLE handle, struct fsync *obj ) + return STATUS_NOT_IMPLEMENTED; + } + +- /* We need to try grabbing it from the server. */ ++ ++ /* We need to try grabbing it from the server. Uninterrupted section ++ * is needed to avoid race with NtClose() which first calls fsync_close() ++ * and then closes handle on server. Without the section we might cache ++ * already closed handle back. */ ++ server_enter_uninterrupted_section( &fd_cache_mutex, &sigset ); ++ if (get_cached_object( handle, obj )) ++ { ++ server_leave_uninterrupted_section( &fd_cache_mutex, &sigset ); ++ return STATUS_SUCCESS; ++ } + SERVER_START_REQ( get_fsync_idx ) + { + req->handle = wine_server_obj_handle( handle ); +@@ -410,6 +422,8 @@ static NTSTATUS get_object( HANDLE handle, struct fsync *obj ) + } + } + SERVER_END_REQ; ++ if (!ret) add_to_list( handle, type, shm_idx ); ++ server_leave_uninterrupted_section( &fd_cache_mutex, &sigset ); + + if (ret) + { +@@ -421,7 +435,6 @@ static NTSTATUS get_object( HANDLE handle, struct fsync *obj ) + + obj->type = type; + obj->shm = get_shm( shm_idx ); +- add_to_list( handle, type, shm_idx ); + /* get_fsync_idx server request increments shared mem refcount, so not grabbing object here. */ + return ret; + } +diff --git a/dlls/ntdll/unix/fsync.h b/dlls/ntdll/unix/fsync.h +index 763e7891ab8..6005c0fa322 100644 +--- a/dlls/ntdll/unix/fsync.h ++++ b/dlls/ntdll/unix/fsync.h +@@ -47,3 +47,8 @@ extern NTSTATUS fsync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN + BOOLEAN alertable, const LARGE_INTEGER *timeout ); + extern NTSTATUS fsync_signal_and_wait( HANDLE signal, HANDLE wait, + BOOLEAN alertable, const LARGE_INTEGER *timeout ); ++ ++/* We have to synchronize on the fd cache mutex so that fsync_close(), close_handle() sequence ++ * called from NtClose() doesn't race with get_fsync_idx(), add_to_list() sequence called ++ * from get_object(). */ ++extern pthread_mutex_t fd_cache_mutex; +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0151-fsync-Check-for-NULL-handle-in-get_object.patch b/0007-proton-esync-fsync/0151-fsync-Check-for-NULL-handle-in-get_object.patch new file mode 100644 index 0000000..54a4f60 --- /dev/null +++ b/0007-proton-esync-fsync/0151-fsync-Check-for-NULL-handle-in-get_object.patch @@ -0,0 +1,25 @@ +From 4ce5048522221c7b56016d2ba6c884bbdd3b2cdf Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Mon, 3 Jul 2023 13:30:33 -0600 +Subject: [PATCH 0583/2346] fsync: Check for NULL handle in get_object(). + +CW-Bug-Id: #22395 +--- + dlls/ntdll/unix/fsync.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 3aa32872a80..8f20f7cab4a 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -401,6 +401,7 @@ static NTSTATUS get_object( HANDLE handle, struct fsync *obj ) + return STATUS_NOT_IMPLEMENTED; + } + ++ if (!handle) return STATUS_INVALID_HANDLE; + + /* We need to try grabbing it from the server. Uninterrupted section + * is needed to avoid race with NtClose() which first calls fsync_close() +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0152-fsync-Type-check-HANDLE-in-fsync_reset_event.patch b/0007-proton-esync-fsync/0152-fsync-Type-check-HANDLE-in-fsync_reset_event.patch new file mode 100644 index 0000000..0179fe3 --- /dev/null +++ b/0007-proton-esync-fsync/0152-fsync-Type-check-HANDLE-in-fsync_reset_event.patch @@ -0,0 +1,36 @@ +From 639e475a4e36bf339b63741ccda9c647ecfa83aa Mon Sep 17 00:00:00 2001 +From: Zhiyi Zhang +Date: Fri, 9 Jun 2023 15:12:31 +0800 +Subject: [PATCH 0584/2346] fsync: Type-check HANDLE in fsync_reset_event(). + +Oddworld: Stranger's Wrath HD (15750) calls ResetEvent() on a file handle and then waits for the +handle with an infinite timeout. Without esync/fsync, NtResetEvent() should return +STATUS_OBJECT_TYPE_MISMATCH because the handle is not an event handle. With esync/fsync, the file +handle is set to non-signaled successfully and causes the game to hang at start-up. The same check +should also apply to fsync_pulse_event(), esync_reset_event(), and esync_pulse_event(). + +CW-Bug-Id: #22326 +--- + dlls/ntdll/unix/fsync.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 8f20f7cab4a..3dfa7c4e035 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -714,6 +714,12 @@ NTSTATUS fsync_reset_event( HANDLE handle, LONG *prev ) + if ((ret = get_object( handle, &obj ))) return ret; + event = obj.shm; + ++ if (obj.type != FSYNC_MANUAL_EVENT && obj.type != FSYNC_AUTO_EVENT) ++ { ++ put_object( &obj ); ++ return STATUS_OBJECT_TYPE_MISMATCH; ++ } ++ + current = __atomic_exchange_n( &event->signaled, 0, __ATOMIC_SEQ_CST ); + + if (prev) *prev = current; +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0153-fsync-Type-check-HANDLE-in-fsync_pulse_event.patch b/0007-proton-esync-fsync/0153-fsync-Type-check-HANDLE-in-fsync_pulse_event.patch new file mode 100644 index 0000000..4507467 --- /dev/null +++ b/0007-proton-esync-fsync/0153-fsync-Type-check-HANDLE-in-fsync_pulse_event.patch @@ -0,0 +1,30 @@ +From 24ce12faa661000267b5c11f1ae56814f23fd3f1 Mon Sep 17 00:00:00 2001 +From: Zhiyi Zhang +Date: Fri, 9 Jun 2023 15:13:12 +0800 +Subject: [PATCH 0585/2346] fsync: Type-check HANDLE in fsync_pulse_event(). + +CW-Bug-Id: #22326 +--- + dlls/ntdll/unix/fsync.c | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/dlls/ntdll/unix/fsync.c b/dlls/ntdll/unix/fsync.c +index 3dfa7c4e035..c3da44e4f26 100644 +--- a/dlls/ntdll/unix/fsync.c ++++ b/dlls/ntdll/unix/fsync.c +@@ -740,6 +740,12 @@ NTSTATUS fsync_pulse_event( HANDLE handle, LONG *prev ) + if ((ret = get_object( handle, &obj ))) return ret; + event = obj.shm; + ++ if (obj.type != FSYNC_MANUAL_EVENT && obj.type != FSYNC_AUTO_EVENT) ++ { ++ put_object( &obj ); ++ return STATUS_OBJECT_TYPE_MISMATCH; ++ } ++ + /* This isn't really correct; an application could miss the write. + * Unfortunately we can't really do much better. Fortunately this is rarely + * used (and publicly deprecated). */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0154-esync-Type-check-HANDLE-in-esync_reset_event.patch b/0007-proton-esync-fsync/0154-esync-Type-check-HANDLE-in-esync_reset_event.patch new file mode 100644 index 0000000..76694a0 --- /dev/null +++ b/0007-proton-esync-fsync/0154-esync-Type-check-HANDLE-in-esync_reset_event.patch @@ -0,0 +1,27 @@ +From 93ffa6d39ac7f8da5cda49cc400f4ddc39de7e95 Mon Sep 17 00:00:00 2001 +From: Zhiyi Zhang +Date: Fri, 9 Jun 2023 15:14:59 +0800 +Subject: [PATCH 0586/2346] esync: Type-check HANDLE in esync_reset_event(). + +CW-Bug-Id: #22326 +--- + dlls/ntdll/unix/esync.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 7b85981cd77..8b3983151d3 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -571,6 +571,9 @@ NTSTATUS esync_reset_event( HANDLE handle ) + if ((ret = get_object( handle, &obj ))) return ret; + event = obj->shm; + ++ if (obj->type != ESYNC_MANUAL_EVENT && obj->type != ESYNC_AUTO_EVENT) ++ return STATUS_OBJECT_TYPE_MISMATCH; ++ + if (obj->type == ESYNC_MANUAL_EVENT) + { + /* Acquire the spinlock. */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0155-esync-Type-check-HANDLE-in-esync_pulse_event.patch b/0007-proton-esync-fsync/0155-esync-Type-check-HANDLE-in-esync_pulse_event.patch new file mode 100644 index 0000000..8008b75 --- /dev/null +++ b/0007-proton-esync-fsync/0155-esync-Type-check-HANDLE-in-esync_pulse_event.patch @@ -0,0 +1,27 @@ +From 98308ae11611562c73dc7e7d9f6eafa0e6c822a2 Mon Sep 17 00:00:00 2001 +From: Zhiyi Zhang +Date: Fri, 9 Jun 2023 15:15:55 +0800 +Subject: [PATCH 0587/2346] esync: Type-check HANDLE in esync_pulse_event(). + +CW-Bug-Id: #22326 +--- + dlls/ntdll/unix/esync.c | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c +index 8b3983151d3..3074f7c72ea 100644 +--- a/dlls/ntdll/unix/esync.c ++++ b/dlls/ntdll/unix/esync.c +@@ -614,6 +614,9 @@ NTSTATUS esync_pulse_event( HANDLE handle ) + + if ((ret = get_object( handle, &obj ))) return ret; + ++ if (obj->type != ESYNC_MANUAL_EVENT && obj->type != ESYNC_AUTO_EVENT) ++ return STATUS_OBJECT_TYPE_MISMATCH; ++ + /* This isn't really correct; an application could miss the write. + * Unfortunately we can't really do much better. Fortunately this is rarely + * used (and publicly deprecated). */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0156-ntdll-HACK-Add-WINE_NO_PRIV_ELEVATION-option-and-aut.patch b/0007-proton-esync-fsync/0156-ntdll-HACK-Add-WINE_NO_PRIV_ELEVATION-option-and-aut.patch new file mode 100644 index 0000000..35545d1 --- /dev/null +++ b/0007-proton-esync-fsync/0156-ntdll-HACK-Add-WINE_NO_PRIV_ELEVATION-option-and-aut.patch @@ -0,0 +1,72 @@ +From a864939a31a528eb39063dda9d843b73f2fb87ac Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Wed, 29 Jun 2022 14:09:43 -0500 +Subject: [PATCH 0734/2346] ntdll: HACK: Add WINE_NO_PRIV_ELEVATION option and + auto enable it for Aquarist - My First Job. + +CW-Bug-Id: #20846 +--- + dlls/ntdll/unix/loader.c | 5 +++++ + dlls/ntdll/unix/security.c | 3 +++ + dlls/ntdll/unix/unix_private.h | 1 + + 3 files changed, 9 insertions(+) + +diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c +index 4745cabd917..af55b0398e2 100644 +--- a/dlls/ntdll/unix/loader.c ++++ b/dlls/ntdll/unix/loader.c +@@ -1982,6 +1982,7 @@ BOOL ac_odyssey; + BOOL fsync_simulate_sched_quantum; + BOOL alert_simulate_sched_quantum; + BOOL fsync_yield_to_waiters; ++BOOL no_priv_elevation; + + static void hacks_init(void) + { +@@ -2036,6 +2037,10 @@ static void hacks_init(void) + setenv( "WINESTEAMNOEXEC", "1", 0 ); + break; + } ++ env_str = getenv("WINE_NO_PRIV_ELEVATION"); ++ if (env_str) no_priv_elevation = atoi(env_str); ++ else if (sgi) no_priv_elevation = !strcmp(sgi, "1584660"); ++ + } + + /*********************************************************************** +diff --git a/dlls/ntdll/unix/security.c b/dlls/ntdll/unix/security.c +index 3f66d959373..8226a4b14fc 100644 +--- a/dlls/ntdll/unix/security.c ++++ b/dlls/ntdll/unix/security.c +@@ -519,6 +519,8 @@ NTSTATUS WINAPI NtQueryInformationToken( HANDLE token, TOKEN_INFORMATION_CLASS c + if (!status) *type = reply->elevation; + } + SERVER_END_REQ; ++ if (!status && no_priv_elevation) ++ *(TOKEN_ELEVATION_TYPE *)info = TokenElevationTypeLimited; + break; + + case TokenElevation: +@@ -529,6 +531,7 @@ NTSTATUS WINAPI NtQueryInformationToken( HANDLE token, TOKEN_INFORMATION_CLASS c + req->handle = wine_server_obj_handle( token ); + status = wine_server_call( req ); + if (!status) elevation->TokenIsElevated = (reply->elevation == TokenElevationTypeFull); ++ if (!status && no_priv_elevation) elevation->TokenIsElevated = 0; + } + SERVER_END_REQ; + break; +diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h +index a9b434e39fa..39d0b039982 100644 +--- a/dlls/ntdll/unix/unix_private.h ++++ b/dlls/ntdll/unix/unix_private.h +@@ -182,6 +182,7 @@ extern BOOL ac_odyssey; + extern BOOL fsync_simulate_sched_quantum; + extern BOOL alert_simulate_sched_quantum; + extern BOOL fsync_yield_to_waiters; ++extern BOOL no_priv_elevation; + + extern void init_environment(void); + extern void init_startup_info(void); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0157-ntdll-Don-t-leak-objattr-allocation-in-NtCreateSemap.patch b/0007-proton-esync-fsync/0157-ntdll-Don-t-leak-objattr-allocation-in-NtCreateSemap.patch new file mode 100644 index 0000000..fbd598a --- /dev/null +++ b/0007-proton-esync-fsync/0157-ntdll-Don-t-leak-objattr-allocation-in-NtCreateSemap.patch @@ -0,0 +1,35 @@ +From f6abe139020b4d5e4ffa5dbc6f83a8d328094241 Mon Sep 17 00:00:00 2001 +From: Tatsuyuki Ishi +Date: Sat, 17 Feb 2024 22:11:43 +0900 +Subject: [PATCH 1223/2346] ntdll: Don't leak objattr allocation in + NtCreateSemaphore. + +https://github.com/ValveSoftware/wine/pull/219 +--- + dlls/ntdll/unix/sync.c | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index ed30388b026..dd08632e21c 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -272,7 +272,6 @@ NTSTATUS WINAPI NtCreateSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJ + + *handle = 0; + if (max <= 0 || initial < 0 || initial > max) return STATUS_INVALID_PARAMETER; +- if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; + + if (do_fsync()) + return fsync_create_semaphore( handle, access, attr, initial, max ); +@@ -280,6 +279,8 @@ NTSTATUS WINAPI NtCreateSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJ + if (do_esync()) + return esync_create_semaphore( handle, access, attr, initial, max ); + ++ if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret; ++ + SERVER_START_REQ( create_semaphore ) + { + req->access = access; +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0158-ntdll-Introduce-a-separate-per-thread-object-for-int.patch b/0007-proton-esync-fsync/0158-ntdll-Introduce-a-separate-per-thread-object-for-int.patch new file mode 100644 index 0000000..4aa272b --- /dev/null +++ b/0007-proton-esync-fsync/0158-ntdll-Introduce-a-separate-per-thread-object-for-int.patch @@ -0,0 +1,328 @@ +From 6e106909d6652c1eb6ad92d2df0eaee99ffc8296 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Mon, 7 Oct 2024 18:19:57 -0600 +Subject: [PATCH 2322/2346] ntdll: Introduce a separate per-thread object for + internal completion waits. + +CW-Bug-Id: #24295 +--- + dlls/ntdll/unix/sync.c | 8 ++- + server/completion.c | 120 ++++++++++++++++++++++++++++++++++++++++- + server/file.h | 1 + + server/protocol.def | 1 + + server/thread.c | 2 + + server/thread.h | 2 + + 6 files changed, 131 insertions(+), 3 deletions(-) + +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 14d4b2b9ac2..3366dc8c539 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -2027,6 +2027,7 @@ NTSTATUS WINAPI NtSetIoCompletion( HANDLE handle, ULONG_PTR key, ULONG_PTR value + NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR *value, + IO_STATUS_BLOCK *io, LARGE_INTEGER *timeout ) + { ++ HANDLE wait_handle = NULL; + unsigned int status; + + TRACE( "(%p, %p, %p, %p, %p)\n", handle, key, value, io, timeout ); +@@ -2043,10 +2044,11 @@ NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR * + io->Information = reply->information; + io->Status = reply->status; + } ++ else wait_handle = wine_server_ptr_handle( reply->wait_handle ); + } + SERVER_END_REQ; + if (status != STATUS_PENDING) return status; +- status = NtWaitForSingleObject( handle, FALSE, timeout ); ++ status = NtWaitForSingleObject( wait_handle, FALSE, timeout ); + if (status != WAIT_OBJECT_0) return status; + } + } +@@ -2058,6 +2060,7 @@ NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR * + NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORMATION *info, ULONG count, + ULONG *written, LARGE_INTEGER *timeout, BOOLEAN alertable ) + { ++ HANDLE wait_handle = NULL; + unsigned int status; + ULONG i = 0; + +@@ -2077,6 +2080,7 @@ NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORM + info[i].IoStatusBlock.Information = reply->information; + info[i].IoStatusBlock.Status = reply->status; + } ++ else wait_handle = wine_server_ptr_handle( reply->wait_handle ); + } + SERVER_END_REQ; + if (status != STATUS_SUCCESS) break; +@@ -2087,7 +2091,7 @@ NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORM + if (status == STATUS_PENDING) status = STATUS_SUCCESS; + break; + } +- status = NtWaitForSingleObject( handle, alertable, timeout ); ++ status = NtWaitForSingleObject( wait_handle, alertable, timeout ); + if (status != WAIT_OBJECT_0) break; + } + *written = i ? i : 1; +diff --git a/server/completion.c b/server/completion.c +index 33266c596da..fe84deda757 100644 +--- a/server/completion.c ++++ b/server/completion.c +@@ -56,13 +56,73 @@ struct type_descr completion_type = + }, + }; + ++struct completion_wait ++{ ++ struct object obj; ++ obj_handle_t handle; ++ struct completion *completion; ++ struct thread *thread; ++ struct list wait_queue_entry; ++}; ++ + struct completion + { + struct object obj; + struct list queue; ++ struct list wait_queue; + unsigned int depth; + }; + ++static void completion_wait_dump( struct object*, int ); ++static int completion_wait_signaled( struct object *obj, struct wait_queue_entry *entry ); ++static void completion_wait_destroy( struct object * ); ++ ++static const struct object_ops completion_wait_ops = ++{ ++ sizeof(struct completion_wait), /* size */ ++ &no_type, /* type */ ++ completion_wait_dump, /* dump */ ++ add_queue, /* add_queue */ ++ remove_queue, /* remove_queue */ ++ completion_wait_signaled, /* signaled */ ++ NULL, /* get_esync_fd */ ++ NULL, /* get_fsync_idx */ ++ no_satisfied, /* satisfied */ ++ no_signal, /* signal */ ++ no_get_fd, /* get_fd */ ++ default_map_access, /* map_access */ ++ default_get_sd, /* get_sd */ ++ default_set_sd, /* set_sd */ ++ no_get_full_name, /* get_full_name */ ++ no_lookup_name, /* lookup_name */ ++ no_link_name, /* link_name */ ++ NULL, /* unlink_name */ ++ no_open_file, /* open_file */ ++ no_kernel_obj_list, /* get_kernel_obj_list */ ++ no_close_handle, /* close_handle */ ++ completion_wait_destroy /* destroy */ ++}; ++ ++static void completion_wait_destroy( struct object *obj ) ++{ ++} ++ ++static void completion_wait_dump( struct object *obj, int verbose ) ++{ ++ struct completion_wait *wait = (struct completion_wait *)obj; ++ ++ assert( obj->ops == &completion_wait_ops ); ++ fprintf( stderr, "Completion wait completion=%p\n", wait->completion ); ++} ++ ++static int completion_wait_signaled( struct object *obj, struct wait_queue_entry *entry ) ++{ ++ struct completion_wait *wait = (struct completion_wait *)obj; ++ ++ assert( obj->ops == &completion_wait_ops ); ++ return wait->completion->depth; ++} ++ + static void completion_dump( struct object*, int ); + static int completion_signaled( struct object *obj, struct wait_queue_entry *entry ); + static void completion_destroy( struct object * ); +@@ -105,12 +165,20 @@ struct comp_msg + static void completion_destroy( struct object *obj) + { + struct completion *completion = (struct completion *) obj; ++ struct completion_wait *wait, *wait_next; + struct comp_msg *tmp, *next; + + LIST_FOR_EACH_ENTRY_SAFE( tmp, next, &completion->queue, struct comp_msg, queue_entry ) + { + free( tmp ); + } ++ ++ LIST_FOR_EACH_ENTRY_SAFE( wait, wait_next, &completion->wait_queue, struct completion_wait, wait_queue_entry ) ++ { ++ assert( wait->completion ); ++ wait->completion = NULL; ++ cleanup_thread_completion( wait->thread ); ++ } + } + + static void completion_dump( struct object *obj, int verbose ) +@@ -128,6 +196,36 @@ static int completion_signaled( struct object *obj, struct wait_queue_entry *ent + return !list_empty( &completion->queue ); + } + ++void cleanup_thread_completion( struct thread *thread ) ++{ ++ if (!thread->completion_wait) return; ++ ++ if (thread->completion_wait->handle) ++ { ++ close_handle( thread->process, thread->completion_wait->handle ); ++ thread->completion_wait->handle = 0; ++ } ++ if (thread->completion_wait->completion) list_remove( &thread->completion_wait->wait_queue_entry ); ++ release_object( &thread->completion_wait->obj ); ++ thread->completion_wait = NULL; ++} ++ ++static struct completion_wait *create_completion_wait( struct completion *completion, struct thread *thread ) ++{ ++ struct completion_wait *wait; ++ ++ if (!(wait = alloc_object( &completion_wait_ops ))) return NULL; ++ wait->completion = completion; ++ wait->thread = thread; ++ if (!(wait->handle = alloc_handle( current->process, wait, SYNCHRONIZE, 0 ))) ++ { ++ release_object( &wait->obj ); ++ return NULL; ++ } ++ list_add_head( &completion->wait_queue, &wait->wait_queue_entry ); ++ return wait; ++} ++ + static struct completion *create_completion( struct object *root, const struct unicode_str *name, + unsigned int attr, unsigned int concurrent, + const struct security_descriptor *sd ) +@@ -139,6 +237,7 @@ static struct completion *create_completion( struct object *root, const struct u + if (get_error() != STATUS_OBJECT_NAME_EXISTS) + { + list_init( &completion->queue ); ++ list_init( &completion->wait_queue ); + completion->depth = 0; + } + } +@@ -155,6 +254,7 @@ void add_completion( struct completion *completion, apc_param_t ckey, apc_param_ + unsigned int status, apc_param_t information ) + { + struct comp_msg *msg = mem_alloc( sizeof( *msg ) ); ++ struct completion_wait *wait; + + if (!msg) + return; +@@ -166,7 +266,12 @@ void add_completion( struct completion *completion, apc_param_t ckey, apc_param_ + + list_add_tail( &completion->queue, &msg->queue_entry ); + completion->depth++; +- wake_up( &completion->obj, 1 ); ++ LIST_FOR_EACH_ENTRY( wait, &completion->wait_queue, struct completion_wait, wait_queue_entry ) ++ { ++ wake_up( &wait->obj, 1 ); ++ if (list_empty( &completion->queue )) return; ++ } ++ if (!list_empty( &completion->queue )) wake_up( &completion->obj, 0 ); + } + + /* create a completion */ +@@ -221,8 +326,20 @@ DECL_HANDLER(remove_completion) + if (!completion) return; + + entry = list_head( &completion->queue ); ++ if (current->completion_wait && current->completion_wait->completion != completion) ++ cleanup_thread_completion( current ); ++ if (!current->completion_wait && !(current->completion_wait = create_completion_wait( completion, current ))) ++ { ++ release_object( completion ); ++ return; ++ } + if (!entry) ++ { ++ list_remove( ¤t->completion_wait->wait_queue_entry ); ++ list_add_head( &completion->wait_queue, ¤t->completion_wait->wait_queue_entry ); ++ reply->wait_handle = current->completion_wait->handle; + set_error( STATUS_PENDING ); ++ } + else + { + list_remove( entry ); +@@ -233,6 +350,7 @@ DECL_HANDLER(remove_completion) + reply->status = msg->status; + reply->information = msg->information; + free( msg ); ++ reply->wait_handle = 0; + } + + release_object( completion ); +diff --git a/server/file.h b/server/file.h +index 91b68ecb8ac..8f0957ec8d5 100644 +--- a/server/file.h ++++ b/server/file.h +@@ -230,6 +230,7 @@ extern struct dir *get_dir_obj( struct process *process, obj_handle_t handle, un + extern struct completion *get_completion_obj( struct process *process, obj_handle_t handle, unsigned int access ); + extern void add_completion( struct completion *completion, apc_param_t ckey, apc_param_t cvalue, + unsigned int status, apc_param_t information ); ++extern void cleanup_thread_completion( struct thread *thread ); + + /* serial port functions */ + +diff --git a/server/protocol.def b/server/protocol.def +index 3d90d7e1c0f..58f6e2ac19c 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3848,6 +3848,7 @@ typedef union + apc_param_t cvalue; /* completion value */ + apc_param_t information; /* IO_STATUS_BLOCK Information */ + unsigned int status; /* completion result */ ++ obj_handle_t wait_handle; /* handle to completion wait internal object */ + @END + + +diff --git a/server/thread.c b/server/thread.c +index ab67a7a9044..71c00fb6e35 100644 +--- a/server/thread.c ++++ b/server/thread.c +@@ -298,6 +298,7 @@ static inline void init_thread_structure( struct thread *thread ) + + thread->creation_time = current_time; + thread->exit_time = 0; ++ thread->completion_wait = NULL; + + list_init( &thread->mutex_list ); + list_init( &thread->system_apc ); +@@ -527,6 +528,7 @@ static void cleanup_thread( struct thread *thread ) + { + int i; + ++ cleanup_thread_completion( thread ); + if (thread->context) + { + thread->context->status = STATUS_ACCESS_DENIED; +diff --git a/server/thread.h b/server/thread.h +index 041eb000171..416b01db318 100644 +--- a/server/thread.h ++++ b/server/thread.h +@@ -31,6 +31,7 @@ struct thread_apc; + struct debug_obj; + struct debug_event; + struct msg_queue; ++struct completion_wait; + + enum run_state + { +@@ -98,6 +99,7 @@ struct thread + data_size_t desc_len; /* thread description length in bytes */ + WCHAR *desc; /* thread description string */ + struct timeout_user *exit_poll; /* poll if the thread/process has exited already */ ++ struct completion_wait *completion_wait; /* completion port wait object the thread is associated with */ + }; + + extern struct thread *current; +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0159-ntdll-Assign-completion-to-thread-when-wait-for-comp.patch b/0007-proton-esync-fsync/0159-ntdll-Assign-completion-to-thread-when-wait-for-comp.patch new file mode 100644 index 0000000..d37e20a --- /dev/null +++ b/0007-proton-esync-fsync/0159-ntdll-Assign-completion-to-thread-when-wait-for-comp.patch @@ -0,0 +1,298 @@ +From e9a4987627421320b94a9649ccaf54c19cded442 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Mon, 7 Oct 2024 18:41:50 -0600 +Subject: [PATCH 2323/2346] ntdll: Assign completion to thread when wait for + completion is satisfied. + +CW-Bug-Id: #24295 +--- + dlls/ntdll/unix/sync.c | 95 ++++++++++++++++++++++++++---------------- + server/completion.c | 63 +++++++++++++++++++++++----- + server/protocol.def | 10 +++++ + 3 files changed, 122 insertions(+), 46 deletions(-) + +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 3366dc8c539..8b170daa603 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -2032,25 +2032,37 @@ NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR * + + TRACE( "(%p, %p, %p, %p, %p)\n", handle, key, value, io, timeout ); + +- for (;;) ++ SERVER_START_REQ( remove_completion ) + { +- SERVER_START_REQ( remove_completion ) ++ req->handle = wine_server_obj_handle( handle ); ++ if (!(status = wine_server_call( req ))) + { +- req->handle = wine_server_obj_handle( handle ); +- if (!(status = wine_server_call( req ))) +- { +- *key = reply->ckey; +- *value = reply->cvalue; +- io->Information = reply->information; +- io->Status = reply->status; +- } +- else wait_handle = wine_server_ptr_handle( reply->wait_handle ); ++ *key = reply->ckey; ++ *value = reply->cvalue; ++ io->Information = reply->information; ++ io->Status = reply->status; + } +- SERVER_END_REQ; +- if (status != STATUS_PENDING) return status; +- status = NtWaitForSingleObject( wait_handle, FALSE, timeout ); +- if (status != WAIT_OBJECT_0) return status; ++ else wait_handle = wine_server_ptr_handle( reply->wait_handle ); + } ++ SERVER_END_REQ; ++ if (status != STATUS_PENDING) return status; ++ if (!timeout || timeout->QuadPart) status = NtWaitForSingleObject( wait_handle, FALSE, timeout ); ++ else status = STATUS_TIMEOUT; ++ if (status != WAIT_OBJECT_0) return status; ++ ++ SERVER_START_REQ( get_thread_completion ) ++ { ++ if (!(status = wine_server_call( req ))) ++ { ++ *key = reply->ckey; ++ *value = reply->cvalue; ++ io->Information = reply->information; ++ io->Status = reply->status; ++ } ++ } ++ SERVER_END_REQ; ++ ++ return status; + } + + +@@ -2066,34 +2078,47 @@ NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORM + + TRACE( "%p %p %u %p %p %u\n", handle, info, (int)count, written, timeout, alertable ); + +- for (;;) ++ while (i < count) + { +- while (i < count) ++ SERVER_START_REQ( remove_completion ) + { +- SERVER_START_REQ( remove_completion ) ++ req->handle = wine_server_obj_handle( handle ); ++ if (!(status = wine_server_call( req ))) + { +- req->handle = wine_server_obj_handle( handle ); +- if (!(status = wine_server_call( req ))) +- { +- info[i].CompletionKey = reply->ckey; +- info[i].CompletionValue = reply->cvalue; +- info[i].IoStatusBlock.Information = reply->information; +- info[i].IoStatusBlock.Status = reply->status; +- } +- else wait_handle = wine_server_ptr_handle( reply->wait_handle ); ++ info[i].CompletionKey = reply->ckey; ++ info[i].CompletionValue = reply->cvalue; ++ info[i].IoStatusBlock.Information = reply->information; ++ info[i].IoStatusBlock.Status = reply->status; + } +- SERVER_END_REQ; +- if (status != STATUS_SUCCESS) break; +- ++i; ++ else wait_handle = wine_server_ptr_handle( reply->wait_handle ); + } +- if (i || status != STATUS_PENDING) ++ SERVER_END_REQ; ++ if (status != STATUS_SUCCESS) break; ++ ++i; ++ } ++ if (i || status != STATUS_PENDING) ++ { ++ if (i) status = STATUS_SUCCESS; ++ goto done; ++ } ++ if (!timeout || timeout->QuadPart || alertable) status = NtWaitForSingleObject( wait_handle, alertable, timeout ); ++ else status = STATUS_TIMEOUT; ++ if (status != WAIT_OBJECT_0) goto done; ++ ++ SERVER_START_REQ( get_thread_completion ) ++ { ++ if (!(status = wine_server_call( req ))) + { +- if (status == STATUS_PENDING) status = STATUS_SUCCESS; +- break; ++ info[i].CompletionKey = reply->ckey; ++ info[i].CompletionValue = reply->cvalue; ++ info[i].IoStatusBlock.Information = reply->information; ++ info[i].IoStatusBlock.Status = reply->status; ++ ++i; + } +- status = NtWaitForSingleObject( wait_handle, alertable, timeout ); +- if (status != WAIT_OBJECT_0) break; + } ++ SERVER_END_REQ; ++ ++done: + *written = i ? i : 1; + return status; + } +diff --git a/server/completion.c b/server/completion.c +index fe84deda757..31e9373c725 100644 +--- a/server/completion.c ++++ b/server/completion.c +@@ -21,7 +21,6 @@ + + /* FIXMEs: + * - built-in wait queues used which means: +- * + threads are awaken FIFO and not LIFO as native does + * + "max concurrent active threads" parameter not used + * + completion handle is waitable, while native isn't + */ +@@ -56,12 +55,22 @@ struct type_descr completion_type = + }, + }; + ++struct comp_msg ++{ ++ struct list queue_entry; ++ apc_param_t ckey; ++ apc_param_t cvalue; ++ apc_param_t information; ++ unsigned int status; ++}; ++ + struct completion_wait + { + struct object obj; + obj_handle_t handle; + struct completion *completion; + struct thread *thread; ++ struct comp_msg *msg; + struct list wait_queue_entry; + }; + +@@ -75,6 +84,7 @@ struct completion + + static void completion_wait_dump( struct object*, int ); + static int completion_wait_signaled( struct object *obj, struct wait_queue_entry *entry ); ++static void completion_wait_satisfied( struct object *obj, struct wait_queue_entry *entry ); + static void completion_wait_destroy( struct object * ); + + static const struct object_ops completion_wait_ops = +@@ -87,7 +97,7 @@ static const struct object_ops completion_wait_ops = + completion_wait_signaled, /* signaled */ + NULL, /* get_esync_fd */ + NULL, /* get_fsync_idx */ +- no_satisfied, /* satisfied */ ++ completion_wait_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ + default_map_access, /* map_access */ +@@ -105,6 +115,9 @@ static const struct object_ops completion_wait_ops = + + static void completion_wait_destroy( struct object *obj ) + { ++ struct completion_wait *wait = (struct completion_wait *)obj; ++ ++ free( wait->msg ); + } + + static void completion_wait_dump( struct object *obj, int verbose ) +@@ -123,6 +136,22 @@ static int completion_wait_signaled( struct object *obj, struct wait_queue_entry + return wait->completion->depth; + } + ++static void completion_wait_satisfied( struct object *obj, struct wait_queue_entry *entry ) ++{ ++ struct completion_wait *wait = (struct completion_wait *)obj; ++ struct list *msg_entry; ++ struct comp_msg *msg; ++ ++ assert( obj->ops == &completion_wait_ops ); ++ msg_entry = list_head( &wait->completion->queue ); ++ assert( msg_entry ); ++ msg = LIST_ENTRY( msg_entry, struct comp_msg, queue_entry ); ++ --wait->completion->depth; ++ list_remove( &msg->queue_entry ); ++ if (wait->msg) free( wait->msg ); ++ wait->msg = msg; ++} ++ + static void completion_dump( struct object*, int ); + static int completion_signaled( struct object *obj, struct wait_queue_entry *entry ); + static void completion_destroy( struct object * ); +@@ -153,15 +182,6 @@ static const struct object_ops completion_ops = + completion_destroy /* destroy */ + }; + +-struct comp_msg +-{ +- struct list queue_entry; +- apc_param_t ckey; +- apc_param_t cvalue; +- apc_param_t information; +- unsigned int status; +-}; +- + static void completion_destroy( struct object *obj) + { + struct completion *completion = (struct completion *) obj; +@@ -217,6 +237,7 @@ static struct completion_wait *create_completion_wait( struct completion *comple + if (!(wait = alloc_object( &completion_wait_ops ))) return NULL; + wait->completion = completion; + wait->thread = thread; ++ wait->msg = NULL; + if (!(wait->handle = alloc_handle( current->process, wait, SYNCHRONIZE, 0 ))) + { + release_object( &wait->obj ); +@@ -356,6 +377,26 @@ DECL_HANDLER(remove_completion) + release_object( completion ); + } + ++/* get completion after successful waiting for it */ ++DECL_HANDLER(get_thread_completion) ++{ ++ struct comp_msg *msg; ++ ++ if (!current->completion_wait || !(msg = current->completion_wait->msg)) ++ { ++ set_error( STATUS_INVALID_HANDLE ); ++ return; ++ } ++ ++ reply->ckey = msg->ckey; ++ reply->cvalue = msg->cvalue; ++ reply->status = msg->status; ++ reply->information = msg->information; ++ free( msg ); ++ current->completion_wait->msg = NULL; ++ if (!current->completion_wait->completion) cleanup_thread_completion( current ); ++} ++ + /* get queue depth for completion port */ + DECL_HANDLER(query_completion) + { +diff --git a/server/protocol.def b/server/protocol.def +index 58f6e2ac19c..5f4bb53041b 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3852,6 +3852,16 @@ typedef union + @END + + ++/* get completion after successful wait */ ++@REQ(get_thread_completion) ++@REPLY ++ apc_param_t ckey; /* completion key */ ++ apc_param_t cvalue; /* completion value */ ++ apc_param_t information; /* IO_STATUS_BLOCK Information */ ++ unsigned int status; /* completion result */ ++@END ++ ++ + /* get completion queue depth */ + @REQ(query_completion) + obj_handle_t handle; /* port handle */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0160-ntdll-Handle-user-APCs-explicitly-in-NtRemoveIoCompl.patch b/0007-proton-esync-fsync/0160-ntdll-Handle-user-APCs-explicitly-in-NtRemoveIoCompl.patch new file mode 100644 index 0000000..780b722 --- /dev/null +++ b/0007-proton-esync-fsync/0160-ntdll-Handle-user-APCs-explicitly-in-NtRemoveIoCompl.patch @@ -0,0 +1,141 @@ +From 5caf0f62c6a260108a211eaa1abafc1adbb132e9 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Mon, 7 Oct 2024 19:19:02 -0600 +Subject: [PATCH 2324/2346] ntdll: Handle user APCs explicitly in + NtRemoveIoCompletionEx(). + +CW-Bug-Id: #24295 +--- + dlls/ntdll/tests/file.c | 26 ++++++++++++++++++++++++++ + dlls/ntdll/unix/sync.c | 14 +++++++++++--- + server/completion.c | 6 ++++-- + server/protocol.def | 1 + + 4 files changed, 42 insertions(+), 5 deletions(-) + +diff --git a/dlls/ntdll/tests/file.c b/dlls/ntdll/tests/file.c +index 3a585cc155f..30d30869191 100644 +--- a/dlls/ntdll/tests/file.c ++++ b/dlls/ntdll/tests/file.c +@@ -1009,6 +1009,32 @@ static void test_set_io_completion(void) + ok( res == STATUS_SUCCESS, "NtCreateIoCompletion failed: %#lx\n", res ); + ok( h && h != INVALID_HANDLE_VALUE, "got invalid handle %p\n", h ); + ++ apc_count = 0; ++ QueueUserAPC( user_apc_proc, GetCurrentThread(), (ULONG_PTR)&apc_count ); ++ res = pNtSetIoCompletion( h, 123, 456, 789, size ); ++ ok( res == STATUS_SUCCESS, "NtSetIoCompletion failed: %#lx\n", res ); ++ res = pNtRemoveIoCompletionEx( h, info, 2, &count, &timeout, TRUE ); ++ /* Before a thread is associated with completion port APC takes priority over pending completion. */ ++ ok( res == STATUS_USER_APC, "NtRemoveIoCompletionEx failed: %#lx\n", res ); ++ ok( count <= 1, "wrong count %lu\n", count ); ++ ok( apc_count == 1, "wrong apc count %u\n", apc_count ); ++ ++ res = pNtRemoveIoCompletionEx( h, info, 2, &count, &timeout, TRUE ); ++ ok( res == STATUS_SUCCESS, "NtRemoveIoCompletion failed: %#lx\n", res ); ++ ok( count == 1, "wrong count %lu\n", count ); ++ ++ apc_count = 0; ++ QueueUserAPC( user_apc_proc, GetCurrentThread(), (ULONG_PTR)&apc_count ); ++ res = pNtSetIoCompletion( h, 123, 456, 789, size ); ++ ok( res == STATUS_SUCCESS, "NtSetIoCompletion failed: %#lx\n", res ); ++ res = pNtRemoveIoCompletionEx( h, info, 2, &count, &timeout, TRUE ); ++ /* After a thread is associated with completion port existing completion is returned if APC is pending. */ ++ ok( res == STATUS_SUCCESS, "NtRemoveIoCompletionEx failed: %#lx\n", res ); ++ ok( count == 1, "wrong count %lu\n", count ); ++ ok( apc_count == 0, "wrong apc count %u\n", apc_count ); ++ SleepEx( 0, TRUE); ++ ok( apc_count == 1, "wrong apc count %u\n", apc_count ); ++ + res = pNtRemoveIoCompletion( h, &key, &value, &iosb, &timeout ); + ok( res == STATUS_TIMEOUT, "NtRemoveIoCompletion failed: %#lx\n", res ); + +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index 8b170daa603..fd3faf61997 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -2035,6 +2035,7 @@ NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR * + SERVER_START_REQ( remove_completion ) + { + req->handle = wine_server_obj_handle( handle ); ++ req->alertable = 0; + if (!(status = wine_server_call( req ))) + { + *key = reply->ckey; +@@ -2083,6 +2084,7 @@ NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORM + SERVER_START_REQ( remove_completion ) + { + req->handle = wine_server_obj_handle( handle ); ++ req->alertable = alertable; + if (!(status = wine_server_call( req ))) + { + info[i].CompletionKey = reply->ckey; +@@ -2096,13 +2098,19 @@ NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORM + if (status != STATUS_SUCCESS) break; + ++i; + } +- if (i || status != STATUS_PENDING) ++ if (i || (status != STATUS_PENDING && status != STATUS_USER_APC)) + { + if (i) status = STATUS_SUCCESS; + goto done; + } +- if (!timeout || timeout->QuadPart || alertable) status = NtWaitForSingleObject( wait_handle, alertable, timeout ); +- else status = STATUS_TIMEOUT; ++ if (status == STATUS_USER_APC) ++ { ++ status = NtDelayExecution( TRUE, NULL ); ++ assert( status == STATUS_USER_APC ); ++ goto done; ++ } ++ if (!timeout || timeout->QuadPart) status = NtWaitForSingleObject( wait_handle, alertable, timeout ); ++ else status = STATUS_TIMEOUT; + if (status != WAIT_OBJECT_0) goto done; + + SERVER_START_REQ( get_thread_completion ) +diff --git a/server/completion.c b/server/completion.c +index 31e9373c725..5077935bec2 100644 +--- a/server/completion.c ++++ b/server/completion.c +@@ -343,23 +343,25 @@ DECL_HANDLER(remove_completion) + struct completion* completion = get_completion_obj( current->process, req->handle, IO_COMPLETION_MODIFY_STATE ); + struct list *entry; + struct comp_msg *msg; ++ BOOL alerted; + + if (!completion) return; + + entry = list_head( &completion->queue ); + if (current->completion_wait && current->completion_wait->completion != completion) + cleanup_thread_completion( current ); ++ alerted = req->alertable && !list_empty( ¤t->user_apc ) && !(entry && current->completion_wait); + if (!current->completion_wait && !(current->completion_wait = create_completion_wait( completion, current ))) + { + release_object( completion ); + return; + } +- if (!entry) ++ if (alerted || !entry) + { + list_remove( ¤t->completion_wait->wait_queue_entry ); + list_add_head( &completion->wait_queue, ¤t->completion_wait->wait_queue_entry ); + reply->wait_handle = current->completion_wait->handle; +- set_error( STATUS_PENDING ); ++ set_error( alerted ? STATUS_USER_APC : STATUS_PENDING ); + } + else + { +diff --git a/server/protocol.def b/server/protocol.def +index 5f4bb53041b..f52d2cf3b49 100644 +--- a/server/protocol.def ++++ b/server/protocol.def +@@ -3843,6 +3843,7 @@ typedef union + /* get completion from completion port queue */ + @REQ(remove_completion) + obj_handle_t handle; /* port handle */ ++ int alertable; /* completion wait is alertable */ + @REPLY + apc_param_t ckey; /* completion key */ + apc_param_t cvalue; /* completion value */ +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0161-server-Signal-completion-port-waits-on-handle-close.patch b/0007-proton-esync-fsync/0161-server-Signal-completion-port-waits-on-handle-close.patch new file mode 100644 index 0000000..6f77c3f --- /dev/null +++ b/0007-proton-esync-fsync/0161-server-Signal-completion-port-waits-on-handle-close.patch @@ -0,0 +1,136 @@ +From f6b8bdd9a781557c878616bf69eee45ec2477eaa Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Mon, 7 Oct 2024 10:50:51 -0600 +Subject: [PATCH 2325/2346] server: Signal completion port waits on handle + close. + +CW-Bug-Id: #24295 +--- + server/completion.c | 50 +++++++++++++++++++++++++++++++-------------- + 1 file changed, 35 insertions(+), 15 deletions(-) + +diff --git a/server/completion.c b/server/completion.c +index 5077935bec2..49acb08a92a 100644 +--- a/server/completion.c ++++ b/server/completion.c +@@ -19,11 +19,7 @@ + * + */ + +-/* FIXMEs: +- * - built-in wait queues used which means: +- * + "max concurrent active threads" parameter not used +- * + completion handle is waitable, while native isn't +- */ ++/* FIXME: "max concurrent active threads" parameter is not used */ + + #include "config.h" + +@@ -80,6 +76,7 @@ struct completion + struct list queue; + struct list wait_queue; + unsigned int depth; ++ int closed; + }; + + static void completion_wait_dump( struct object*, int ); +@@ -133,6 +130,7 @@ static int completion_wait_signaled( struct object *obj, struct wait_queue_entry + struct completion_wait *wait = (struct completion_wait *)obj; + + assert( obj->ops == &completion_wait_ops ); ++ if (!wait->completion) return 1; + return wait->completion->depth; + } + +@@ -143,6 +141,11 @@ static void completion_wait_satisfied( struct object *obj, struct wait_queue_ent + struct comp_msg *msg; + + assert( obj->ops == &completion_wait_ops ); ++ if (!wait->completion) ++ { ++ make_wait_abandoned( entry ); ++ return; ++ } + msg_entry = list_head( &wait->completion->queue ); + assert( msg_entry ); + msg = LIST_ENTRY( msg_entry, struct comp_msg, queue_entry ); +@@ -154,6 +157,7 @@ static void completion_wait_satisfied( struct object *obj, struct wait_queue_ent + + static void completion_dump( struct object*, int ); + static int completion_signaled( struct object *obj, struct wait_queue_entry *entry ); ++static int completion_close_handle( struct object *obj, struct process *process, obj_handle_t handle ); + static void completion_destroy( struct object * ); + + static const struct object_ops completion_ops = +@@ -178,27 +182,19 @@ static const struct object_ops completion_ops = + default_unlink_name, /* unlink_name */ + no_open_file, /* open_file */ + no_kernel_obj_list, /* get_kernel_obj_list */ +- no_close_handle, /* close_handle */ ++ completion_close_handle, /* close_handle */ + completion_destroy /* destroy */ + }; + + static void completion_destroy( struct object *obj) + { + struct completion *completion = (struct completion *) obj; +- struct completion_wait *wait, *wait_next; + struct comp_msg *tmp, *next; + + LIST_FOR_EACH_ENTRY_SAFE( tmp, next, &completion->queue, struct comp_msg, queue_entry ) + { + free( tmp ); + } +- +- LIST_FOR_EACH_ENTRY_SAFE( wait, wait_next, &completion->wait_queue, struct completion_wait, wait_queue_entry ) +- { +- assert( wait->completion ); +- wait->completion = NULL; +- cleanup_thread_completion( wait->thread ); +- } + } + + static void completion_dump( struct object *obj, int verbose ) +@@ -213,7 +209,30 @@ static int completion_signaled( struct object *obj, struct wait_queue_entry *ent + { + struct completion *completion = (struct completion *)obj; + +- return !list_empty( &completion->queue ); ++ return !list_empty( &completion->queue ) || completion->closed; ++} ++ ++static int completion_close_handle( struct object *obj, struct process *process, obj_handle_t handle ) ++{ ++ struct completion *completion = (struct completion *)obj; ++ struct completion_wait *wait, *wait_next; ++ ++ if (completion->obj.handle_count != 1) return 1; ++ ++ LIST_FOR_EACH_ENTRY_SAFE( wait, wait_next, &completion->wait_queue, struct completion_wait, wait_queue_entry ) ++ { ++ assert( wait->completion ); ++ wait->completion = NULL; ++ list_remove( &wait->wait_queue_entry ); ++ if (!wait->msg) ++ { ++ wake_up( &wait->obj, 0 ); ++ cleanup_thread_completion( wait->thread ); ++ } ++ } ++ completion->closed = 1; ++ wake_up( obj, 0 ); ++ return 1; + } + + void cleanup_thread_completion( struct thread *thread ) +@@ -260,6 +279,7 @@ static struct completion *create_completion( struct object *root, const struct u + list_init( &completion->queue ); + list_init( &completion->wait_queue ); + completion->depth = 0; ++ completion->closed = 0; + } + } + +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0162-kernelbase-Set-the-proper-error-code-in-GetQueuedCom.patch b/0007-proton-esync-fsync/0162-kernelbase-Set-the-proper-error-code-in-GetQueuedCom.patch new file mode 100644 index 0000000..312f318 --- /dev/null +++ b/0007-proton-esync-fsync/0162-kernelbase-Set-the-proper-error-code-in-GetQueuedCom.patch @@ -0,0 +1,40 @@ +From 297884226263ece447ec009223603f1d928bdb17 Mon Sep 17 00:00:00 2001 +From: Alexey Prokhin +Date: Thu, 23 Apr 2020 12:29:55 +0300 +Subject: [PATCH 2326/2346] kernelbase: Set the proper error code in + GetQueuedCompletionStatus{Ex} when the handle is closed. + +CW-Bug-Id: #24295 +--- + dlls/kernelbase/sync.c | 8 +++++--- + 1 file changed, 5 insertions(+), 3 deletions(-) + +diff --git a/dlls/kernelbase/sync.c b/dlls/kernelbase/sync.c +index 8c87d56aadd..2fffd3ead79 100644 +--- a/dlls/kernelbase/sync.c ++++ b/dlls/kernelbase/sync.c +@@ -1201,7 +1201,8 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetQueuedCompletionStatus( HANDLE port, LPDWORD co + return FALSE; + } + +- if (status == STATUS_TIMEOUT) SetLastError( WAIT_TIMEOUT ); ++ if (status == STATUS_TIMEOUT) SetLastError( WAIT_TIMEOUT ); ++ else if (status == STATUS_ABANDONED) SetLastError( ERROR_ABANDONED_WAIT_0 ); + else SetLastError( RtlNtStatusToDosError(status) ); + return FALSE; + } +@@ -1221,8 +1222,9 @@ BOOL WINAPI DECLSPEC_HOTPATCH GetQueuedCompletionStatusEx( HANDLE port, OVERLAPP + ret = NtRemoveIoCompletionEx( port, (FILE_IO_COMPLETION_INFORMATION *)entries, count, + written, get_nt_timeout( &time, timeout ), alertable ); + if (ret == STATUS_SUCCESS) return TRUE; +- else if (ret == STATUS_TIMEOUT) SetLastError( WAIT_TIMEOUT ); +- else if (ret == STATUS_USER_APC) SetLastError( WAIT_IO_COMPLETION ); ++ else if (ret == STATUS_TIMEOUT) SetLastError( WAIT_TIMEOUT ); ++ else if (ret == STATUS_USER_APC) SetLastError( WAIT_IO_COMPLETION ); ++ else if (ret == STATUS_ABANDONED) SetLastError( ERROR_ABANDONED_WAIT_0 ); + else SetLastError( RtlNtStatusToDosError(ret) ); + return FALSE; + } +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0163-ntdll-tests-Add-tests-for-completion-port-signaling.patch b/0007-proton-esync-fsync/0163-ntdll-tests-Add-tests-for-completion-port-signaling.patch new file mode 100644 index 0000000..b5d338d --- /dev/null +++ b/0007-proton-esync-fsync/0163-ntdll-tests-Add-tests-for-completion-port-signaling.patch @@ -0,0 +1,224 @@ +From d771feb752feabf876e8095adc761c07ef614579 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Tue, 7 Dec 2021 12:27:17 +0300 +Subject: [PATCH 2327/2346] ntdll/tests: Add tests for completion port + signaling. + +CW-Bug-Id: #24295 +--- + dlls/ntdll/tests/sync.c | 194 ++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 194 insertions(+) + +diff --git a/dlls/ntdll/tests/sync.c b/dlls/ntdll/tests/sync.c +index f356d3ec38f..3ab89bbf361 100644 +--- a/dlls/ntdll/tests/sync.c ++++ b/dlls/ntdll/tests/sync.c +@@ -837,6 +837,199 @@ static void test_tid_alert( char **argv ) + CloseHandle( pi.hThread ); + } + ++struct test_completion_port_scheduling_param ++{ ++ HANDLE ready, test_ready; ++ HANDLE port; ++ int index; ++}; ++ ++static DWORD WINAPI test_completion_port_scheduling_thread(void *param) ++{ ++ struct test_completion_port_scheduling_param *p = param; ++ FILE_IO_COMPLETION_INFORMATION info; ++ OVERLAPPED_ENTRY overlapped_entry; ++ OVERLAPPED *overlapped; ++ IO_STATUS_BLOCK iosb; ++ ULONG_PTR key, value; ++ NTSTATUS status; ++ DWORD ret, err; ++ ULONG count; ++ BOOL bret; ++ ++ /* both threads are woken when comleption added. */ ++ ret = WaitForSingleObject( p->ready, INFINITE ); ++ ok( ret == WAIT_OBJECT_0, "got %#lx.\n", ret ); ++ ret = WaitForSingleObject( p->port, INFINITE ); ++ ok( ret == WAIT_OBJECT_0, "got %#lx.\n", ret ); ++ SetEvent( p->test_ready ); ++ ++ /* if a thread is waiting for completion which is added threads which wait on port handle are not woken. */ ++ ret = WaitForSingleObject( p->ready, INFINITE ); ++ if (p->index) ++ { ++ bret = GetQueuedCompletionStatus( p->port, &count, &key, &overlapped, INFINITE ); ++ ok( bret, "got error %lu.\n", GetLastError() ); ++ } ++ else ++ { ++ ret = WaitForSingleObject( p->port, 100 ); ++ ok( ret == WAIT_TIMEOUT || broken( !ret ) /* before Win10 1607 */, "got %#lx.\n", ret ); ++ } ++ SetEvent( p->test_ready ); ++ ++ /* Two threads in GetQueuedCompletionStatus, the second is supposed to start first. */ ++ ret = WaitForSingleObject( p->ready, INFINITE ); ++ ok( ret == WAIT_OBJECT_0, "got %#lx.\n", ret ); ++ bret = GetQueuedCompletionStatus( p->port, &count, &key, &overlapped, INFINITE ); ++ ok( bret, "got error %lu.\n", GetLastError() ); ++ ok( key == 3 + p->index || broken( p->index && key == 5 ) /* before Win10 */, "got %Iu, expected %u.\n", key, 3 + p->index ); ++ SetEvent( p->test_ready ); ++ ++ /* Port is being closed. */ ++ ret = WaitForSingleObject( p->ready, INFINITE ); ++ ret = WaitForSingleObject( p->port, INFINITE ); ++ if (ret == WAIT_FAILED) ++ skip( "Handle closed before wait started.\n" ); ++ else ++ ok( ret == WAIT_OBJECT_0, "got %#lx.\n", ret ); ++ SetEvent( p->test_ready ); ++ ++ /* Port is being closed. */ ++ ret = WaitForSingleObject( p->ready, INFINITE ); ++ ok( ret == WAIT_OBJECT_0, "got %#lx.\n", ret ); ++ SetEvent( p->test_ready ); ++ status = NtRemoveIoCompletion( p->port, &key, &value, &iosb, NULL ); ++ if (status == STATUS_INVALID_HANDLE) ++ skip( "Handle closed before wait started.\n" ); ++ else ++ ok( status == STATUS_ABANDONED_WAIT_0, "got %#lx.\n", status ); ++ ++ /* Port is being closed. */ ++ ret = WaitForSingleObject( p->ready, INFINITE ); ++ ok( ret == WAIT_OBJECT_0, "got %#lx.\n", ret ); ++ SetEvent( p->test_ready ); ++ count = 0xdeadbeef; ++ status = NtRemoveIoCompletionEx( p->port, &info, 1, &count, NULL, FALSE ); ++ ok( count <= 1, "Got unexpected count %lu.\n", count ); ++ if (status == STATUS_INVALID_HANDLE) ++ skip( "Handle closed before wait started.\n" ); ++ else ++ ok( status == STATUS_ABANDONED_WAIT_0, "got %#lx.\n", status ); ++ ++ /* Port is being closed. */ ++ ret = WaitForSingleObject( p->ready, INFINITE ); ++ ok( ret == WAIT_OBJECT_0, "got %#lx.\n", ret ); ++ SetEvent( p->test_ready ); ++ bret = GetQueuedCompletionStatus( p->port, &count, &key, &overlapped, INFINITE ); ++ err = GetLastError(); ++ ok( !bret, "got %d.\n", bret ); ++ if (err == ERROR_INVALID_HANDLE) ++ skip( "Handle closed before wait started.\n" ); ++ else ++ ok( err == ERROR_ABANDONED_WAIT_0, "got error %#lx.\n", err ); ++ ++ /* Port is being closed. */ ++ ret = WaitForSingleObject( p->ready, INFINITE ); ++ ok( ret == WAIT_OBJECT_0, "got %#lx.\n", ret ); ++ SetEvent( p->test_ready ); ++ bret = GetQueuedCompletionStatusEx( p->port, &overlapped_entry, 1, &count, INFINITE, TRUE ); ++ err = GetLastError(); ++ ok( !bret, "got %d.\n", bret ); ++ if (err == ERROR_INVALID_HANDLE) ++ skip( "Handle closed before wait started.\n" ); ++ else ++ ok( err == ERROR_ABANDONED_WAIT_0, "got error %#lx.\n", err ); ++ ++ return 0; ++} ++ ++static void test_completion_port_scheduling(void) ++{ ++ struct test_completion_port_scheduling_param p[2]; ++ HANDLE threads[2], port; ++ OVERLAPPED *overlapped; ++ unsigned int i, j; ++ DWORD ret, count; ++ NTSTATUS status; ++ ULONG_PTR key; ++ BOOL bret; ++ ++ for (i = 0; i < 2; ++i) ++ { ++ p[i].index = 0; ++ p[i].ready = CreateEventA(NULL, FALSE, FALSE, NULL); ++ p[i].test_ready = CreateEventA(NULL, FALSE, FALSE, NULL); ++ threads[i] = CreateThread( NULL, 0, test_completion_port_scheduling_thread, &p[i], 0, NULL ); ++ ok( !!threads[i], "got error %lu.\n", GetLastError() ); ++ } ++ ++ status = NtCreateIoCompletion( &port, IO_COMPLETION_ALL_ACCESS, NULL, 0 ); ++ ok( !status, "got %#lx.\n", status ); ++ /* Waking multiple threads directly waiting on port */ ++ for (i = 0; i < 2; ++i) ++ { ++ p[i].index = i; ++ p[i].port = port; ++ SetEvent( p[i].ready ); ++ } ++ PostQueuedCompletionStatus( port, 0, 1, NULL ); ++ for (i = 0; i < 2; ++i) WaitForSingleObject( p[i].test_ready, INFINITE ); ++ bret = GetQueuedCompletionStatus( port, &count, &key, &overlapped, INFINITE ); ++ ok( bret, "got error %lu.\n", GetLastError() ); ++ ++ /* One thread is waiting on port, another in GetQueuedCompletionStatus(). */ ++ SetEvent( p[1].ready ); ++ Sleep( 40 ); ++ SetEvent( p[0].ready ); ++ Sleep( 10 ); ++ PostQueuedCompletionStatus( port, 0, 2, NULL ); ++ for (i = 0; i < 2; ++i) WaitForSingleObject( p[i].test_ready, INFINITE ); ++ ++ /* Both threads are waiting in GetQueuedCompletionStatus, LIFO wake up order. */ ++ SetEvent( p[1].ready ); ++ Sleep( 40 ); ++ SetEvent( p[0].ready ); ++ Sleep( 20 ); ++ PostQueuedCompletionStatus( port, 0, 3, NULL ); ++ PostQueuedCompletionStatus( port, 0, 4, NULL ); ++ PostQueuedCompletionStatus( port, 0, 5, NULL ); ++ bret = GetQueuedCompletionStatus( p->port, &count, &key, &overlapped, INFINITE ); ++ ok( bret, "got error %lu.\n", GetLastError() ); ++ ok( key == 5 || broken( key == 4 ) /* before Win10 */, "got %Iu, expected 5.\n", key ); ++ ++ /* Close port handle while threads are waiting on it directly. */ ++ for (i = 0; i < 2; ++i) SetEvent( p[i].ready ); ++ Sleep( 20 ); ++ NtClose( port ); ++ for (i = 0; i < 2; ++i) WaitForSingleObject( p[i].test_ready, INFINITE ); ++ ++ /* Test signaling on port close. */ ++ for (i = 0; i < 4; ++i) ++ { ++ status = NtCreateIoCompletion( &port, IO_COMPLETION_ALL_ACCESS, NULL, 0 ); ++ ok( !status, "got %#lx.\n", status ); ++ for (j = 0; j < 2; ++j) ++ { ++ p[j].port = port; ++ ret = SignalObjectAndWait( p[j].ready, p[j].test_ready, ++ INFINITE, FALSE ); ++ ok( ret == WAIT_OBJECT_0, "got %#lx.\n", ret ); ++ } ++ Sleep( 20 ); ++ status = NtClose( port ); ++ ok( !status, "got %#lx.\n", status ); ++ } ++ ++ WaitForMultipleObjects( 2, threads, TRUE, INFINITE ); ++ for (i = 0; i < 2; ++i) ++ { ++ CloseHandle( threads[i] ); ++ CloseHandle( p[i].ready ); ++ CloseHandle( p[i].test_ready ); ++ } ++} ++ + START_TEST(sync) + { + HMODULE module = GetModuleHandleA("ntdll.dll"); +@@ -884,4 +1077,5 @@ START_TEST(sync) + test_keyed_events(); + test_resource(); + test_tid_alert( argv ); ++ test_completion_port_scheduling(); + } +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0164-ntdll-fsync-Introduce-explicit-server-wait-helper-an.patch b/0007-proton-esync-fsync/0164-ntdll-fsync-Introduce-explicit-server-wait-helper-an.patch new file mode 100644 index 0000000..fc89248 --- /dev/null +++ b/0007-proton-esync-fsync/0164-ntdll-fsync-Introduce-explicit-server-wait-helper-an.patch @@ -0,0 +1,75 @@ +From 6c0bf1299f53e320cb61452855dd8b77e1ed2922 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Mon, 7 Oct 2024 14:56:53 -0600 +Subject: [PATCH 2328/2346] ntdll: fsync: Introduce explicit server wait helper + and use it for some internal waits. + +CW-Bug-Id: #24295 +--- + dlls/ntdll/unix/sync.c | 14 ++++++++++++-- + dlls/ntdll/unix/unix_private.h | 3 ++- + 2 files changed, 14 insertions(+), 3 deletions(-) + +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index fd3faf61997..b2db0247b76 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -1597,6 +1597,16 @@ NTSTATUS WINAPI NtWaitForSingleObject( HANDLE handle, BOOLEAN alertable, const L + return NtWaitForMultipleObjects( 1, &handle, FALSE, alertable, timeout ); + } + ++NTSTATUS wait_internal_server( HANDLE handle, BOOLEAN alertable, const LARGE_INTEGER *timeout ) ++{ ++ select_op_t select_op; ++ UINT flags = SELECT_INTERRUPTIBLE; ++ ++ if (alertable) flags |= SELECT_ALERTABLE; ++ select_op.wait.op = SELECT_WAIT; ++ select_op.wait.handles[0] = wine_server_obj_handle( handle ); ++ return server_wait( &select_op, offsetof( select_op_t, wait.handles[1] ), flags, timeout ); ++} + + /****************************************************************** + * NtSignalAndWaitForSingleObject (NTDLL.@) +@@ -2047,7 +2057,7 @@ NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR * + } + SERVER_END_REQ; + if (status != STATUS_PENDING) return status; +- if (!timeout || timeout->QuadPart) status = NtWaitForSingleObject( wait_handle, FALSE, timeout ); ++ if (!timeout || timeout->QuadPart) status = wait_internal_server( wait_handle, FALSE, timeout ); + else status = STATUS_TIMEOUT; + if (status != WAIT_OBJECT_0) return status; + +@@ -2109,7 +2119,7 @@ NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORM + assert( status == STATUS_USER_APC ); + goto done; + } +- if (!timeout || timeout->QuadPart) status = NtWaitForSingleObject( wait_handle, alertable, timeout ); ++ if (!timeout || timeout->QuadPart) status = wait_internal_server( wait_handle, alertable, timeout ); + else status = STATUS_TIMEOUT; + if (status != WAIT_OBJECT_0) goto done; + +diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h +index 82fc9d2bc02..9dc8ea627e0 100644 +--- a/dlls/ntdll/unix/unix_private.h ++++ b/dlls/ntdll/unix/unix_private.h +@@ -214,6 +214,7 @@ extern unsigned int server_select( const select_op_t *select_op, data_size_t siz + timeout_t abs_timeout, context_t *context, user_apc_t *user_apc ); + extern unsigned int server_wait( const select_op_t *select_op, data_size_t size, UINT flags, + const LARGE_INTEGER *timeout ); ++extern NTSTATUS wait_internal_server( HANDLE handle, BOOLEAN alertable, const LARGE_INTEGER *timeout ); + extern unsigned int server_queue_process_apc( HANDLE process, const apc_call_t *call, + apc_result_t *result ); + extern int server_get_unix_fd( HANDLE handle, unsigned int wanted_access, int *unix_fd, +@@ -455,7 +456,7 @@ static inline async_data_t server_async( HANDLE handle, struct async_fileio *use + + static inline NTSTATUS wait_async( HANDLE handle, BOOL alertable ) + { +- return NtWaitForSingleObject( handle, alertable, NULL ); ++ return wait_internal_server( handle, alertable, NULL ); + } + + static inline BOOL in_wow64_call(void) +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0165-esync-fsync-Support-wait-on-completion-ports.patch b/0007-proton-esync-fsync/0165-esync-fsync-Support-wait-on-completion-ports.patch new file mode 100644 index 0000000..f0fb803 --- /dev/null +++ b/0007-proton-esync-fsync/0165-esync-fsync-Support-wait-on-completion-ports.patch @@ -0,0 +1,123 @@ +From 95b1cb1311588bf7d9ff556008bd6fd9c6bb0d90 Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Mon, 7 Oct 2024 16:26:51 -0600 +Subject: [PATCH 2329/2346] esync, fsync: Support wait on completion ports. + +CW-Bug-Id: #24295 +--- + server/completion.c | 44 +++++++++++++++++++++++++++++++++++++++++--- + 1 file changed, 41 insertions(+), 3 deletions(-) + +diff --git a/server/completion.c b/server/completion.c +index 49acb08a92a..580f83b4a82 100644 +--- a/server/completion.c ++++ b/server/completion.c +@@ -35,6 +35,8 @@ + #include "file.h" + #include "handle.h" + #include "request.h" ++#include "esync.h" ++#include "fsync.h" + + + static const WCHAR completion_name[] = {'I','o','C','o','m','p','l','e','t','i','o','n'}; +@@ -77,6 +79,8 @@ struct completion + struct list wait_queue; + unsigned int depth; + int closed; ++ int esync_fd; ++ unsigned int fsync_idx; + }; + + static void completion_wait_dump( struct object*, int ); +@@ -151,12 +155,19 @@ static void completion_wait_satisfied( struct object *obj, struct wait_queue_ent + msg = LIST_ENTRY( msg_entry, struct comp_msg, queue_entry ); + --wait->completion->depth; + list_remove( &msg->queue_entry ); ++ if (list_empty( &wait->completion->queue )) ++ { ++ if (do_esync()) esync_clear( wait->completion->esync_fd ); ++ if (do_fsync()) fsync_clear( &wait->completion->obj ); ++ } + if (wait->msg) free( wait->msg ); + wait->msg = msg; + } + + static void completion_dump( struct object*, int ); + static int completion_signaled( struct object *obj, struct wait_queue_entry *entry ); ++static int completion_get_esync_fd( struct object *obj, enum esync_type *type ); ++static unsigned int completion_get_fsync_idx( struct object *obj, enum fsync_type *type ); + static int completion_close_handle( struct object *obj, struct process *process, obj_handle_t handle ); + static void completion_destroy( struct object * ); + +@@ -168,8 +179,8 @@ static const struct object_ops completion_ops = + add_queue, /* add_queue */ + remove_queue, /* remove_queue */ + completion_signaled, /* signaled */ +- NULL, /* get_esync_fd */ +- NULL, /* get_fsync_idx */ ++ completion_get_esync_fd, /* get_esync_fd */ ++ completion_get_fsync_idx, /* get_fsync_idx */ + no_satisfied, /* satisfied */ + no_signal, /* signal */ + no_get_fd, /* get_fd */ +@@ -191,6 +202,9 @@ static void completion_destroy( struct object *obj) + struct completion *completion = (struct completion *) obj; + struct comp_msg *tmp, *next; + ++ if (do_esync()) close( completion->esync_fd ); ++ if (completion->fsync_idx) fsync_free_shm_idx( completion->fsync_idx ); ++ + LIST_FOR_EACH_ENTRY_SAFE( tmp, next, &completion->queue, struct comp_msg, queue_entry ) + { + free( tmp ); +@@ -212,6 +226,23 @@ static int completion_signaled( struct object *obj, struct wait_queue_entry *ent + return !list_empty( &completion->queue ) || completion->closed; + } + ++static int completion_get_esync_fd( struct object *obj, enum esync_type *type ) ++{ ++ struct completion *completion = (struct completion *)obj; ++ ++ *type = ESYNC_MANUAL_SERVER; ++ return completion->esync_fd; ++} ++ ++static unsigned int completion_get_fsync_idx( struct object *obj, enum fsync_type *type ) ++{ ++ struct completion *completion = (struct completion *)obj; ++ ++ assert( obj->ops == &completion_ops ); ++ *type = FSYNC_MANUAL_SERVER; ++ return completion->fsync_idx; ++} ++ + static int completion_close_handle( struct object *obj, struct process *process, obj_handle_t handle ) + { + struct completion *completion = (struct completion *)obj; +@@ -282,7 +313,9 @@ static struct completion *create_completion( struct object *root, const struct u + completion->closed = 0; + } + } +- ++ if (do_esync()) completion->esync_fd = esync_create_fd( 0, 0 ); ++ completion->fsync_idx = 0; ++ if (do_fsync()) completion->fsync_idx = fsync_alloc_shm( 0, 0 ); + return completion; + } + +@@ -394,6 +427,11 @@ DECL_HANDLER(remove_completion) + reply->information = msg->information; + free( msg ); + reply->wait_handle = 0; ++ if (list_empty( &completion->queue )) ++ { ++ if (do_esync()) esync_clear( completion->esync_fd ); ++ if (do_fsync()) fsync_clear( &completion->obj ); ++ } + } + + release_object( completion ); +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0166-ntdll-esync-fsync-Check-for-port-signal-state-for-ze.patch b/0007-proton-esync-fsync/0166-ntdll-esync-fsync-Check-for-port-signal-state-for-ze.patch new file mode 100644 index 0000000..21b91e2 --- /dev/null +++ b/0007-proton-esync-fsync/0166-ntdll-esync-fsync-Check-for-port-signal-state-for-ze.patch @@ -0,0 +1,44 @@ +From ed14565ee49bc5a60bd631ddf9e7d3b2f4034e3a Mon Sep 17 00:00:00 2001 +From: Paul Gofman +Date: Mon, 7 Oct 2024 21:11:04 -0600 +Subject: [PATCH 2330/2346] ntdll: esync, fsync: Check for port signal state + for zero timeout in NtRemoveIoCompletion[Ex]. + +CW-Bug-Id: #24295 +--- + dlls/ntdll/unix/sync.c | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c +index b2db0247b76..8361f12bb89 100644 +--- a/dlls/ntdll/unix/sync.c ++++ b/dlls/ntdll/unix/sync.c +@@ -2042,6 +2042,12 @@ NTSTATUS WINAPI NtRemoveIoCompletion( HANDLE handle, ULONG_PTR *key, ULONG_PTR * + + TRACE( "(%p, %p, %p, %p, %p)\n", handle, key, value, io, timeout ); + ++ if (timeout && !timeout->QuadPart && (do_esync() || do_fsync())) ++ { ++ status = NtWaitForSingleObject( handle, FALSE, timeout ); ++ if (status != WAIT_OBJECT_0) return status; ++ } ++ + SERVER_START_REQ( remove_completion ) + { + req->handle = wine_server_obj_handle( handle ); +@@ -2089,6 +2095,12 @@ NTSTATUS WINAPI NtRemoveIoCompletionEx( HANDLE handle, FILE_IO_COMPLETION_INFORM + + TRACE( "%p %p %u %p %p %u\n", handle, info, (int)count, written, timeout, alertable ); + ++ if (timeout && !timeout->QuadPart && (do_esync() || do_fsync())) ++ { ++ status = NtWaitForSingleObject( handle, alertable, timeout ); ++ if (status != WAIT_OBJECT_0) goto done; ++ } ++ + while (i < count) + { + SERVER_START_REQ( remove_completion ) +-- +2.47.0 + diff --git a/0007-proton-esync-fsync/0167-fixup-server-ntdll-Implement-message-waits.patch b/0007-proton-esync-fsync/0167-fixup-server-ntdll-Implement-message-waits.patch new file mode 100644 index 0000000..9061949 --- /dev/null +++ b/0007-proton-esync-fsync/0167-fixup-server-ntdll-Implement-message-waits.patch @@ -0,0 +1,34 @@ +diff --git a/server/queue.c b/server/queue.c +index a86cee8e78c..ff19298135a 100644 +--- a/server/queue.c ++++ b/server/queue.c +@@ -4287,11 +4287,13 @@ DECL_HANDLER(set_keyboard_repeat) + DECL_HANDLER(esync_msgwait) + { + struct msg_queue *queue = get_current_queue(); ++ const queue_shm_t *queue_shm; + + if (!queue) return; ++ queue_shm = queue->shared; + queue->esync_in_msgwait = req->in_msgwait; + +- if (current->process->idle_event && !(queue->wake_mask & QS_SMRESULT)) ++ if (current->process->idle_event && !(queue_shm->wake_mask & QS_SMRESULT)) + set_event( current->process->idle_event ); + + /* and start/stop waiting on the driver */ +@@ -4302,11 +4304,13 @@ DECL_HANDLER(esync_msgwait) + DECL_HANDLER(fsync_msgwait) + { + struct msg_queue *queue = get_current_queue(); ++ const queue_shm_t *queue_shm; + + if (!queue) return; ++ queue_shm = queue->shared; + queue->fsync_in_msgwait = req->in_msgwait; + +- if (current->process->idle_event && !(queue->wake_mask & QS_SMRESULT)) ++ if (current->process->idle_event && !(queue_shm->wake_mask & QS_SMRESULT)) + set_event( current->process->idle_event ); + + /* and start/stop waiting on the driver */ diff --git a/0007-proton-esync-fsync/0168-HACK-user32-Always-call-get_message-request-after-wa.patch b/0007-proton-esync-fsync/0168-HACK-user32-Always-call-get_message-request-after-wa.patch new file mode 100644 index 0000000..2ea5cc6 --- /dev/null +++ b/0007-proton-esync-fsync/0168-HACK-user32-Always-call-get_message-request-after-wa.patch @@ -0,0 +1,96 @@ +From 9ceae59cebd111f0fb06d63ad1495ea1becd714b Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?R=C3=A9mi=20Bernon?= +Date: Tue, 5 Dec 2023 15:03:25 +0100 +Subject: HACK: user32: Always call get_message request after + waiting. + +Because with esync and fsync the wait happens on the client-side, so +we need to make the request to do the server side effects. +--- + dlls/win32u/message.c | 14 +++++++------- + 1 file changed, 7 insertions(+), 7 deletions(-) + +diff --git a/dlls/win32u/message.c b/dlls/win32u/message.c +index 2eb49dd5d5c..7f2fe415c7e 100644 +--- a/dlls/win32u/message.c ++++ b/dlls/win32u/message.c +@@ -2684,7 +2684,7 @@ static BOOL check_queue_bits( UINT wake_mask, UINT changed_mask, UINT signal_bit + * available; -1 on error. + * All pending sent messages are processed before returning. + */ +-int peek_message( MSG *msg, const struct peek_message_filter *filter ) ++int peek_message( MSG *msg, const struct peek_message_filter *filter, BOOL waited ) + { + LRESULT result; + HWND hwnd = filter->hwnd; +@@ -2724,7 +2724,7 @@ int peek_message( MSG *msg, const struct peek_message_filter *filter ) + thread_info->client_info.msg_source = prev_source; + wake_mask = filter->mask & (QS_SENDMESSAGE | QS_SMRESULT); + +- if (NtGetTickCount() - thread_info->last_getmsg_time < 3000 && /* avoid hung queue */ ++ if ((!waited && (NtGetTickCount() - thread_info->last_getmsg_time < 3000)) && /* avoid hung queue */ + check_queue_bits( wake_mask, filter->mask, wake_mask | signal_bits, filter->mask | clear_bits, + &wake_bits, &changed_bits )) + res = STATUS_PENDING; +@@ -2925,7 +2925,7 @@ int peek_message( MSG *msg, const struct peek_message_filter *filter ) + .mask = filter->mask, + .internal = filter->internal, + }; +- peek_message( msg, &new_filter ); ++ peek_message( msg, &new_filter, TRUE ); + } + continue; + } +@@ -2990,7 +2990,7 @@ static void process_sent_messages(void) + { + struct peek_message_filter filter = {.flags = PM_REMOVE | PM_QS_SENDMESSAGE}; + MSG msg; +- peek_message( &msg, &filter ); ++ peek_message( &msg, &filter, FALSE ); + } + + /*********************************************************************** +@@ -3223,7 +3223,7 @@ BOOL WINAPI NtUserPeekMessage( MSG *msg_out, HWND hwnd, UINT first, UINT last, U + user_check_not_lock(); + check_for_driver_events(); + +- if ((ret = peek_message( &msg, &filter )) <= 0) ++ if ((ret = peek_message( &msg, &filter, FALSE )) <= 0) + { + if (!ret) + { +@@ -3274,7 +3274,7 @@ BOOL WINAPI NtUserGetMessage( MSG *msg, HWND hwnd, UINT first, UINT last ) + + filter.mask = mask; + filter.flags = PM_REMOVE | (mask << 16); +- while (!(ret = peek_message( msg, &filter ))) ++ while (!(ret = peek_message( msg, &filter, TRUE ))) + { + wait_objects( 1, &server_queue, INFINITE, mask & (QS_SENDMESSAGE | QS_SMRESULT), mask, 0 ); + } +diff --git a/dlls/win32u/ntuser_private.h b/dlls/win32u/ntuser_private.h +index f91056642bd..8f8f545a6eb 100644 +--- a/dlls/win32u/ntuser_private.h ++++ b/dlls/win32u/ntuser_private.h +@@ -237,7 +237,7 @@ struct peek_message_filter + BOOL internal; + }; + +-extern int peek_message( MSG *msg, const struct peek_message_filter *filter ); ++extern int peek_message( MSG *msg, const struct peek_message_filter *filter, BOOL waited ); + + /* systray.c */ + extern LRESULT system_tray_call( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, void *data ); +diff --git a/dlls/win32u/input.c b/dlls/win32u/input.c +index 2f4f0faadae..cf262e570c7 100644 +--- a/dlls/win32u/input.c ++++ b/dlls/win32u/input.c +@@ -805,7 +805,7 @@ static void check_for_events( UINT flags ) + if (!user_driver->pProcessEvents( flags )) + flush_window_surfaces( TRUE ); + +- peek_message( &msg, &filter ); ++ peek_message( &msg, &filter, FALSE ); + } + + /********************************************************************** diff --git a/0009-windowing-system-integration/0001-misc-osu-related/0000-proton-detect-WM-plus-kwin-fix.patch b/0009-windowing-system-integration/0001-misc-osu-related/0000-proton-detect-WM-plus-kwin-fix.patch index 705814a..a938c20 100644 --- a/0009-windowing-system-integration/0001-misc-osu-related/0000-proton-detect-WM-plus-kwin-fix.patch +++ b/0009-windowing-system-integration/0001-misc-osu-related/0000-proton-detect-WM-plus-kwin-fix.patch @@ -1,9 +1,9 @@ diff --git a/dlls/winex11.drv/window.c b/dlls/winex11.drv/window.c -index f975986a9d9..75d01df1009 100644 +index a693884e0c1..a7ae9799f01 100644 --- a/dlls/winex11.drv/window.c +++ b/dlls/winex11.drv/window.c -@@ -113,6 +113,97 @@ static const WCHAR clip_window_prop[] = - static pthread_mutex_t win_data_mutex = PTHREAD_MUTEX_INITIALIZER; +@@ -245,6 +245,97 @@ void host_window_set_parent( struct host_window *win, Window parent ) + } +static int handle_wm_name_badwindow_error( Display *dpy, XErrorEvent *event, void *arg ) @@ -100,38 +100,38 @@ index f975986a9d9..75d01df1009 100644 /*********************************************************************** * http://standards.freedesktop.org/startup-notification-spec */ -@@ -1413,6 +1504,7 @@ 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 ); -+ RECT original_rect = {0}; - XWindowChanges changes; - unsigned int mask = 0; - -@@ -1456,10 +1548,22 @@ 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 ); -+ /* KWin doesn't allow moving a window with _NET_WM_STATE_FULLSCREEN set. So we need to remove -+ * _NET_WM_STATE_FULLSCREEN before moving the window and restore it later */ -+ if (wm_is_kde( data->display ) && data->is_fullscreen ) -+ { -+ original_rect = data->rects.visible; -+ SetRectEmpty( &data->rects.visible ); -+ } - update_net_wm_states( data ); - - if (data->mapped) queue_pending_config( data, &data->rects.visible, NextRequest( data->display ) ); - XReconfigureWMWindow( data->display, data->whole_window, data->vis.screen, mask, &changes ); -+ if (!IsRectEmpty( &original_rect )) -+ { -+ data->rects.visible = original_rect; -+ update_net_wm_states( data ); -+ } - - TRACE( "win %p/%lx pos %d,%d,%dx%d after %lx changes=%x\n", - data->hwnd, data->whole_window, (int)data->rects.visible.left, (int)data->rects.visible.top, -@@ -2000,6 +2104,8 @@ void X11DRV_SetDesktopWindow( HWND hwnd ) +#@@ -1456,6 +1547,7 @@ 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 ); +#+ RECT original_rect = {0}; +# XWindowChanges changes; +# unsigned int mask = 0; +# +#@@ -1499,10 +1591,21 @@ 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 ); +#+ /* KWin doesn't allow moving a window with _NET_WM_STATE_FULLSCREEN set. So we need to remove +#+ * _NET_WM_STATE_FULLSCREEN before moving the window and restore it later */ +#+ if (wm_is_kde( data->display ) && data->is_fullscreen ) +#+ { +#+ original_rect = data->rects.visible; +#+ SetRectEmpty( &data->rects.visible ); +#+ } +# update_net_wm_states( data ); +# data->configure_serial = NextRequest( data->display ); +# XReconfigureWMWindow( data->display, data->whole_window, data->vis.screen, mask, &changes ); +#- +#+ if (!IsRectEmpty( &original_rect )) +#+ { +#+ data->rects.visible = original_rect; +#+ update_net_wm_states( data ); +#+ } +# TRACE( "win %p/%lx pos %d,%d,%dx%d after %lx changes=%x serial=%lu\n", +# data->hwnd, data->whole_window, (int)data->rects.visible.left, (int)data->rects.visible.top, +# (int)(data->rects.visible.right - data->rects.visible.left), +@@ -2042,6 +2145,8 @@ void X11DRV_SetDesktopWindow( HWND hwnd ) { unsigned int width, height; diff --git a/0009-windowing-system-integration/0001-misc-osu-related/0001-proton-focusin-focusout-workarounds.patch b/0009-windowing-system-integration/0001-misc-osu-related/0001-proton-focusin-focusout-workarounds.patch index 3d9c604..2d20648 100644 --- a/0009-windowing-system-integration/0001-misc-osu-related/0001-proton-focusin-focusout-workarounds.patch +++ b/0009-windowing-system-integration/0001-misc-osu-related/0001-proton-focusin-focusout-workarounds.patch @@ -129,15 +129,15 @@ index f975986a9d9..63f2861c101 100644 + /* workaround for mutter gitlab bug #649, we cannot trust the + * data->mapped flag as mapping is asynchronous. + */ -+ if (enable_mutter_workaround) -+ { -+ XWindowAttributes attr; -+ -+ mapped = data->mapped; -+ if (XGetWindowAttributes( data->display, data->whole_window, &attr )) -+ mapped = (attr.map_state != IsUnmapped); -+ } -+ ++// if (enable_mutter_workaround) ++// { ++// XWindowAttributes attr; ++// ++// mapped = data->mapped; ++// if (XGetWindowAttributes( data->display, data->whole_window, &attr )) ++// mapped = (attr.map_state != IsUnmapped); ++// } ++// + mwm_hints.flags = MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS; + mwm_hints.input_mode = 0; + mwm_hints.status = 0; @@ -146,35 +146,35 @@ index f975986a9d9..63f2861c101 100644 + x11drv_atom(_MOTIF_WM_HINTS), 32, PropModeReplace, + (unsigned char*)&mwm_hints, sizeof(mwm_hints)/sizeof(long) ); + -+ if (enable_mutter_workaround && mapped) -+ { -+ DWORD end = NtGetTickCount() + 100; -+ struct is_unmap_notify_param p; -+ struct pollfd pfd; -+ XEvent event; -+ int timeout; -+ -+ /* workaround for mutter gitlab bug #649, wait for the map notify -+ * event each time the decorations are modified before modifying -+ * them again. -+ */ -+ p.data = data; -+ p.found = FALSE; -+ TRACE("workaround mutter bug #649, waiting for UnmapNotify\n"); -+ pfd.fd = ConnectionNumber(data->display); -+ pfd.events = POLLIN; -+ for (;;) -+ { -+ XCheckIfEvent( data->display, &event, is_unmap_notify, (XPointer)&p ); -+ if (p.found) break; -+ timeout = end - NtGetTickCount(); -+ if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1) -+ { -+ WARN( "window %p/%lx unmap_notify wait timed out.\n", data->hwnd, data->whole_window ); -+ break; -+ } -+ } -+ } ++// if (enable_mutter_workaround && mapped) ++// { ++// DWORD end = NtGetTickCount() + 100; ++// struct is_unmap_notify_param p; ++// struct pollfd pfd; ++// XEvent event; ++// int timeout; ++// ++// /* workaround for mutter gitlab bug #649, wait for the map notify ++// * event each time the decorations are modified before modifying ++// * them again. ++// */ ++// p.data = data; ++// p.found = FALSE; ++// TRACE("workaround mutter bug #649, waiting for UnmapNotify\n"); ++// pfd.fd = ConnectionNumber(data->display); ++// pfd.events = POLLIN; ++// for (;;) ++// { ++// XCheckIfEvent( data->display, &event, is_unmap_notify, (XPointer)&p ); ++// if (p.found) break; ++// timeout = end - NtGetTickCount(); ++// if (timeout <= 0 || poll( &pfd, 1, timeout ) != 1) ++// { ++// WARN( "window %p/%lx unmap_notify wait timed out.\n", data->hwnd, data->whole_window ); ++// break; ++// } ++// } ++// } + + if (wm_is_mutter(data->display) && NtUserGetGUIThreadInfo( GetCurrentThreadId(), &info ) && + info.hwndFocus == data->hwnd && !!data->prev_hints.decorations != !!mwm_hints.decorations) diff --git a/0009-windowing-system-integration/0001-misc-osu-related/0021-winex11-Improved-osu-childwindow-hack.patch b/0009-windowing-system-integration/0001-misc-osu-related/0021-winex11-Improved-osu-childwindow-hack.patch index f4dc591..c527e40 100644 --- a/0009-windowing-system-integration/0001-misc-osu-related/0021-winex11-Improved-osu-childwindow-hack.patch +++ b/0009-windowing-system-integration/0001-misc-osu-related/0021-winex11-Improved-osu-childwindow-hack.patch @@ -14,24 +14,25 @@ composition-free page-flipping rendering path instead of blitting. 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c -index 4738cf6a0f8..5b96c460c71 100644 +index 126e9bd3597..a396fdb32c8 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c -@@ -1902,6 +1902,14 @@ static void hacks_init(void) - setenv( "WINESTEAMNOEXEC", "1", 0 ); - break; +@@ -1870,6 +1870,15 @@ static void hacks_init(void) + ERR( "HACK: ram_reporting_bias %lldMB.\n", ram_reporting_bias / (1024 * 1024) ); } + + if (main_argc > 1 && (strstr(main_argv[1], "osu!.exe"))) + { -+ const char* env_str = getenv("WINE_DISABLE_GLCHILD_HACK"); ++ env_str = getenv("WINE_DISABLE_GLCHILD_HACK"); + if (!(env_str && *env_str != '\0' && *env_str != '0')) + { + setenv( "OSU_HACKS_ENABLED", "1", 0 ); + } + } - } - - /*********************************************************************** ++ + env_str = getenv("WINE_SIMULATE_ASYNC_READ"); + if (env_str) + ac_odyssey = !!atoi(env_str); diff --git a/dlls/winex11.drv/init.c b/dlls/winex11.drv/init.c index 0bba9727136..5703f1ad009 100644 --- a/dlls/winex11.drv/init.c diff --git a/0009-windowing-system-integration/0004-proton/0012-winex11.drv-Call-SetForegroundWindow-instead-of-SetA.patch b/0009-windowing-system-integration/0004-proton/0012-winex11.drv-Call-SetForegroundWindow-instead-of-SetA.patch index bf2c3fe..137fc32 100644 --- a/0009-windowing-system-integration/0004-proton/0012-winex11.drv-Call-SetForegroundWindow-instead-of-SetA.patch +++ b/0009-windowing-system-integration/0004-proton/0012-winex11.drv-Call-SetForegroundWindow-instead-of-SetA.patch @@ -15,13 +15,13 @@ CW-Bug-Id: #20227 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dlls/winex11.drv/event.c b/dlls/winex11.drv/event.c -index ece04a5d..2d4fcce9 100644 +index c6729e89d42..e72aac8c8bd 100644 --- a/dlls/winex11.drv/event.c +++ b/dlls/winex11.drv/event.c -@@ -1318,7 +1318,7 @@ static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL updat +@@ -1334,7 +1334,7 @@ static void handle_wm_state_notify( HWND hwnd, XPropertyEvent *event, BOOL updat TRACE( "restoring win %p/%lx\n", data->hwnd, data->whole_window ); release_win_data( data ); - if ((style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE)) + if ((old_style & (WS_MINIMIZE | WS_VISIBLE)) == (WS_MINIMIZE | WS_VISIBLE)) - NtUserSetActiveWindow( hwnd ); + NtUserSetForegroundWindow( hwnd ); send_message( hwnd, WM_SYSCOMMAND, SC_RESTORE, 0 ); diff --git a/0013-server-optimization/0001-misc/ps0003-ucrtbase-Fix-handling-of-tab-and-non-breaking-spac.patch b/0013-server-optimization/0001-misc/ps0003-ucrtbase-Fix-handling-of-tab-and-non-breaking-spac.patch deleted file mode 100644 index b1af696..0000000 --- a/0013-server-optimization/0001-misc/ps0003-ucrtbase-Fix-handling-of-tab-and-non-breaking-spac.patch +++ /dev/null @@ -1,179 +0,0 @@ -From: Chip Davis -Subject: [PATCH v3] ucrtbase: Fix handling of tab and non-breaking space in iswctype(). -Message-Id: <20191211232355.70180-1-cdavis@codeweavers.com> -Date: Wed, 11 Dec 2019 17:23:55 -0600 - -It's just these two that are handled specially AFAICT. - -Signed-off-by: Chip Davis ---- - -Notes: - v2: Fix build. - v3: Fix sign extension bug. - - dlls/msvcr110/tests/msvcr110.c | 30 ++++++++++++++++++++++++++++++ - dlls/msvcrt/tests/string.c | 28 ++++++++++++++++++++++++++++ - dlls/ucrtbase/tests/misc.c | 29 +++++++++++++++++++++++++++++ - 3 files changed, 87 insertions(+) - -diff --git a/dlls/msvcr110/tests/msvcr110.c b/dlls/msvcr110/tests/msvcr110.c -index 11111111111..11111111111 100644 ---- a/dlls/msvcr110/tests/msvcr110.c -+++ b/dlls/msvcr110/tests/msvcr110.c -@@ -43,6 +43,7 @@ typedef struct { - - static char* (CDECL *p_setlocale)(int category, const char* locale); - static size_t (CDECL *p___strncnt)(const char *str, size_t count); -+static int (CDECL *p_iswctype)(wchar_t, wctype_t); - - static unsigned int (CDECL *p_CurrentScheduler_GetNumberOfVirtualProcessors)(void); - static unsigned int (CDECL *p__CurrentScheduler__GetNumberOfVirtualProcessors)(void); -@@ -71,6 +72,7 @@ static BOOL init(void) - - SET(p_setlocale, "setlocale"); - SET(p___strncnt, "__strncnt"); -+ SET(p_iswctype, "iswctype"); - SET(p_CurrentScheduler_GetNumberOfVirtualProcessors, "?GetNumberOfVirtualProcessors@CurrentScheduler@Concurrency@@SAIXZ"); - SET(p__CurrentScheduler__GetNumberOfVirtualProcessors, "?_GetNumberOfVirtualProcessors@_CurrentScheduler@details@Concurrency@@SAIXZ"); - SET(p_CurrentScheduler_Id, "?Id@CurrentScheduler@Concurrency@@SAIXZ"); -@@ -262,6 +264,33 @@ static void test___strncnt(void) - } - } - -+static void test_iswctype(void) -+{ -+ static const struct { -+ WCHAR c; -+ int t; -+ int r; -+ } tests[] = { -+ { '0', C1_DIGIT, C1_DIGIT }, -+ { '9', C1_DIGIT, C1_DIGIT }, -+ { 'a', C1_DIGIT, 0 }, -+ { 'a', C1_LOWER, C1_LOWER }, -+ { 0xa0, C1_BLANK, C1_BLANK }, -+ { 0xe0, _ALPHA, C1_ALPHA|C1_LOWER }, -+ { 0xff16, C1_DIGIT, C1_DIGIT }, -+ { 0x0660, C1_DIGIT, C1_DIGIT }, -+ { 0x0ce6, C1_DIGIT, C1_DIGIT } -+ }; -+ int i, r; -+ -+ p_setlocale(LC_ALL, "C"); -+ for (i = 0; i < ARRAY_SIZE(tests); i++) -+ { -+ r = p_iswctype(tests[i].c, tests[i].t); -+ ok(r == tests[i].r, "iswctype returned %x for %x\n", r, tests[i].c); -+ } -+} -+ - static void test_CurrentContext(void) - { - _Context _ctx, *ret; -@@ -313,6 +342,7 @@ START_TEST(msvcr110) - test_CurrentScheduler(); /* MUST be first (at least among Concurrency tests) */ - test_setlocale(); - test___strncnt(); -+ test_iswctype(); - test_CurrentContext(); - test_strcmp(); - } -diff --git a/dlls/msvcrt/tests/string.c b/dlls/msvcrt/tests/string.c -index 11111111111..11111111111 100644 ---- a/dlls/msvcrt/tests/string.c -+++ b/dlls/msvcrt/tests/string.c -@@ -4622,6 +4622,33 @@ static void test_wcsncpy(void) - wine_dbgstr_wn(dst, ARRAY_SIZE(dst))); - } - -+static void test_iswctype(void) -+{ -+ static const struct { -+ WCHAR c; -+ int t; -+ int r; -+ } tests[] = { -+ { '0', C1_DIGIT, C1_DIGIT }, -+ { '9', C1_DIGIT, C1_DIGIT }, -+ { 'a', C1_DIGIT, 0 }, -+ { 'a', C1_LOWER, C1_LOWER }, -+ { 0xa0, C1_BLANK, C1_BLANK }, -+ { 0xe0, _ALPHA, C1_ALPHA|C1_LOWER }, -+ { 0xff16, C1_DIGIT, C1_DIGIT }, -+ { 0x0660, C1_DIGIT, C1_DIGIT }, -+ { 0x0ce6, C1_DIGIT, C1_DIGIT } -+ }; -+ int i, r; -+ -+ setlocale(LC_ALL, "C"); -+ for (i = 0; i < ARRAY_SIZE(tests); i++) -+ { -+ r = iswctype(tests[i].c, tests[i].t); -+ ok(r == tests[i].r, "iswctype returned %x for %x\n", r, tests[i].c); -+ } -+} -+ - START_TEST(string) - { - char mem[100]; -@@ -4782,4 +4809,5 @@ START_TEST(string) - test__mbbtype(); - test_wcsncpy(); - test_mbsrev(); -+ test_iswctype(); - } -diff --git a/dlls/ucrtbase/tests/misc.c b/dlls/ucrtbase/tests/misc.c -index 11111111111..11111111111 100644 ---- a/dlls/ucrtbase/tests/misc.c -+++ b/dlls/ucrtbase/tests/misc.c -@@ -36,6 +36,7 @@ - - #include - #include -+#include - #include "wine/test.h" - - #define DEFINE_EXPECT(func) \ -@@ -574,6 +575,33 @@ static void test_isblank(void) - } - } - -+static void test_iswctype(void) -+{ -+ static const struct { -+ WCHAR c; -+ int t; -+ int r; -+ } tests[] = { -+ { '0', C1_DIGIT, C1_DIGIT }, -+ { '9', C1_DIGIT, C1_DIGIT }, -+ { 'a', C1_DIGIT, 0 }, -+ { 'a', C1_LOWER, C1_LOWER }, -+ { 0xa0, C1_BLANK, 0 }, -+ { 0xe0, _ALPHA, C1_ALPHA|C1_LOWER }, -+ { 0xff16, C1_DIGIT, C1_DIGIT }, -+ { 0x0660, C1_DIGIT, C1_DIGIT }, -+ { 0x0ce6, C1_DIGIT, C1_DIGIT } -+ }; -+ int i, r; -+ -+ _setlocale(LC_ALL, "C"); -+ for (i = 0; i < ARRAY_SIZE(tests); i++) -+ { -+ r = _iswctype(tests[i].c, tests[i].t); -+ ok(r == tests[i].r, "iswctype returned %x for %x\n", r, tests[i].c); -+ } -+} -+ - static struct _exception exception; - - static int CDECL matherr_callback(struct _exception *e) -@@ -1622,6 +1650,7 @@ START_TEST(misc) - test__sopen_s(); - test_lldiv(); - test_isblank(); -+ test_iswctype(); - test_math_errors(); - test_asctime(); - test_strftime(); diff --git a/0013-server-optimization/0001-misc/ps0023-ntoskrnl-server-Support-referencing-section-objects.patch b/0013-server-optimization/0001-misc/ps0023-ntoskrnl-server-Support-referencing-section-objects.patch deleted file mode 100644 index 603712a..0000000 --- a/0013-server-optimization/0001-misc/ps0023-ntoskrnl-server-Support-referencing-section-objects.patch +++ /dev/null @@ -1,102 +0,0 @@ -From a2efaf1d8b8a848dfe60d5c45238d48a6a653b68 Mon Sep 17 00:00:00 2001 -From: Derek Lesho -Date: Wed, 13 Jul 2022 13:08:41 -0400 -Subject: [PATCH] ntoskrnl, server: Support referencing section objects. - -Needed for the shared resource manager to track the shared memory object for shared fences. ---- - dlls/ntoskrnl.exe/ntoskrnl.c | 12 +++++++++++- - server/mapping.c | 14 +++++++++++++- - 2 files changed, 24 insertions(+), 2 deletions(-) - -diff --git a/dlls/ntoskrnl.exe/ntoskrnl.c b/dlls/ntoskrnl.exe/ntoskrnl.c -index 38a25bc5092..1802d483bbf 100644 ---- a/dlls/ntoskrnl.exe/ntoskrnl.c -+++ b/dlls/ntoskrnl.exe/ntoskrnl.c -@@ -260,6 +260,15 @@ POBJECT_TYPE WINAPI ObGetObjectType( void *object ) - return header->type; - } - -+static const WCHAR section_type_name[] = {'S','e','c','t','i','o','n',0}; -+ -+static struct _OBJECT_TYPE section_type = -+{ -+ section_type_name -+}; -+ -+static POBJECT_TYPE p_section_type = §ion_type; -+ - static const POBJECT_TYPE *known_types[] = - { - &ExEventObjectType, -@@ -269,7 +278,8 @@ static const POBJECT_TYPE *known_types[] = - &IoFileObjectType, - &PsProcessType, - &PsThreadType, -- &SeTokenObjectType -+ &SeTokenObjectType, -+ &p_section_type, - }; - - DECLARE_CRITICAL_SECTION(handle_map_cs); -diff --git a/server/mapping.c b/server/mapping.c -index 4c90673a5c5..67896165048 100644 ---- a/server/mapping.c -+++ b/server/mapping.c -@@ -160,6 +160,7 @@ struct type_descr mapping_type = - struct mapping - { - struct object obj; /* object header */ -+ struct list kernel_object; /* list of kernel object pointers */ - mem_size_t size; /* mapping size */ - unsigned int flags; /* SEC_* flags */ - struct fd *fd; /* fd for mapped file */ -@@ -171,6 +172,7 @@ struct mapping - - static void mapping_dump( struct object *obj, int verbose ); - static struct fd *mapping_get_fd( struct object *obj ); -+static struct list *mapping_get_kernel_obj_list( struct object *obj ); - static void mapping_destroy( struct object *obj ); - static enum server_fd_type mapping_get_fd_type( struct fd *fd ); - -@@ -195,7 +197,7 @@ static const struct object_ops mapping_ops = - directory_link_name, /* link_name */ - default_unlink_name, /* unlink_name */ - no_open_file, /* open_file */ -- no_kernel_obj_list, /* get_kernel_obj_list */ -+ mapping_get_kernel_obj_list, /* get_kernel_obj_list */ - no_get_fast_sync, /* get_fast_sync */ - no_close_handle, /* close_handle */ - mapping_destroy /* destroy */ -@@ -903,6 +905,8 @@ static struct mapping *create_mapping( struct object *root, const struct unicode - if (get_error() == STATUS_OBJECT_NAME_EXISTS) - return mapping; /* Nothing else to do */ - -+ list_init( &mapping->kernel_object ); -+ - mapping->size = size; - mapping->fd = NULL; - mapping->shared = NULL; -@@ -995,6 +999,8 @@ struct mapping *create_fd_mapping( struct object *root, const struct unicode_str - if (!(mapping = create_named_object( root, &mapping_ops, name, attr, sd ))) return NULL; - if (get_error() == STATUS_OBJECT_NAME_EXISTS) return mapping; /* Nothing else to do */ - -+ list_init( &mapping->kernel_object ); -+ - mapping->shared = NULL; - mapping->committed = NULL; - mapping->flags = SEC_FILE; -@@ -1101,6 +1107,12 @@ static struct fd *mapping_get_fd( struct object *obj ) - return (struct fd *)grab_object( mapping->fd ); - } - -+static struct list *mapping_get_kernel_obj_list( struct object *obj ) -+{ -+ struct mapping *mapping = (struct mapping *)obj; -+ return &mapping->kernel_object; -+} -+ - static void mapping_destroy( struct object *obj ) - { - struct mapping *mapping = (struct mapping *)obj; - diff --git a/0013-server-optimization/0005-writewatches/0004-ntdll-HACK-Add-WINE_RAM_REPORTING_BIAS-option.patch b/0013-server-optimization/0005-writewatches/0004-ntdll-HACK-Add-WINE_RAM_REPORTING_BIAS-option.patch index c117384..1ad5fa6 100644 --- a/0013-server-optimization/0005-writewatches/0004-ntdll-HACK-Add-WINE_RAM_REPORTING_BIAS-option.patch +++ b/0013-server-optimization/0005-writewatches/0004-ntdll-HACK-Add-WINE_RAM_REPORTING_BIAS-option.patch @@ -15,37 +15,24 @@ diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index 994413c1658..a8f6d3f91c0 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c -@@ -1851,8 +1851,11 @@ static ULONG_PTR get_image_address(void) - return 0; - } - +@@ -2023,11 +2023,17 @@ BOOL ac_odyssey; + BOOL alert_simulate_sched_quantum; + BOOL fsync_yield_to_waiters; + BOOL no_priv_elevation; +long long ram_reporting_bias; -+ + static void hacks_init(void) { -+ const char* env_str; const char *sgi = getenv( "SteamGameId" ); - - switch (sgi ? atoi( sgi ) : -1) -@@ -1863,12 +1866,17 @@ static void hacks_init(void) - } - if (main_argc > 1 && (strstr(main_argv[1], "osu!.exe"))) - { -- const char* env_str = getenv("WINE_DISABLE_GLCHILD_HACK"); -+ env_str = getenv("WINE_DISABLE_GLCHILD_HACK"); - if (!(env_str && *env_str != '\0' && *env_str != '0')) - { - setenv( "OSU_HACKS_ENABLED", "1", 0 ); - } - } + const char *env_str; + if ((env_str = getenv("WINE_RAM_REPORTING_BIAS"))) + { + ram_reporting_bias = atoll(env_str) * 1024 * 1024; + ERR( "HACK: ram_reporting_bias %lldMB.\n", ram_reporting_bias / (1024 * 1024) ); + } - } - /*********************************************************************** + env_str = getenv("WINE_SIMULATE_ASYNC_READ"); + if (env_str) diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c index 3dc5c704aa9..129136f675d 100644 --- a/dlls/ntdll/unix/system.c @@ -70,15 +57,14 @@ diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index bcee4508b65..e14eb43dd0d 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h -@@ -191,6 +191,8 @@ extern SYSTEM_CPU_INFORMATION cpu_info; - extern struct ldt_copy __wine_ldt_copy; - #endif - +@@ -188,6 +188,7 @@ extern BOOL fsync_simulate_sched_quantum; + extern BOOL alert_simulate_sched_quantum; + extern BOOL fsync_yield_to_waiters; + extern BOOL no_priv_elevation; +extern long long ram_reporting_bias; -+ + extern void init_environment(void); extern void init_startup_info(void); - extern void *create_startup_info( const UNICODE_STRING *nt_image, ULONG process_flags, diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c index 4953a2086ec..7ec937a478f 100644 --- a/dlls/ntdll/unix/virtual.c diff --git a/0013-server-optimization/0006-futex/0004-ntdll-Track-active-keyed-events-on-the-client-side.patch b/0013-server-optimization/0006-futex/0004-ntdll-Track-active-keyed-events-on-the-client-side.patch index fdb47d2..76c1c8d 100644 --- a/0013-server-optimization/0006-futex/0004-ntdll-Track-active-keyed-events-on-the-client-side.patch +++ b/0013-server-optimization/0006-futex/0004-ntdll-Track-active-keyed-events-on-the-client-side.patch @@ -70,7 +70,7 @@ index 11111111111..11111111111 100644 static const char *debugstr_timeout( const LARGE_INTEGER *timeout ) { if (!timeout) return "(infinite)"; -@@ -3125,18 +3177,23 @@ NTSTATUS WINAPI NtOpenKeyedEvent( HANDLE *handle, ACCESS_MASK access, const OBJE +@@ -3125,16 +3177,21 @@ NTSTATUS WINAPI NtOpenKeyedEvent( HANDLE *handle, ACCESS_MASK access, const OBJE NTSTATUS WINAPI NtWaitForKeyedEvent( HANDLE handle, const void *key, BOOLEAN alertable, const LARGE_INTEGER *timeout ) { @@ -79,8 +79,6 @@ index 11111111111..11111111111 100644 UINT flags = SELECT_INTERRUPTIBLE; + NTSTATUS status; - TRACE( "handle %p, key %p, alertable %u, timeout %s\n", handle, key, alertable, debugstr_timeout(timeout) ); - - if (!handle) handle = keyed_event; if ((ULONG_PTR)key & 1) return STATUS_INVALID_PARAMETER_1; + entry = keyed_entry_acquire( handle, wine_server_client_ptr( key ), alertable ); @@ -96,7 +94,7 @@ index 11111111111..11111111111 100644 } -@@ -3144,18 +3203,23 @@ NTSTATUS WINAPI NtWaitForKeyedEvent( HANDLE handle, const void *key, +@@ -3144,16 +3203,21 @@ NTSTATUS WINAPI NtWaitForKeyedEvent( HANDLE handle, const void *key, NTSTATUS WINAPI NtReleaseKeyedEvent( HANDLE handle, const void *key, BOOLEAN alertable, const LARGE_INTEGER *timeout ) { @@ -105,8 +103,6 @@ index 11111111111..11111111111 100644 UINT flags = SELECT_INTERRUPTIBLE; + NTSTATUS status; - TRACE( "handle %p, key %p, alertable %u, timeout %s\n", handle, key, alertable, debugstr_timeout(timeout) ); - - if (!handle) handle = keyed_event; if ((ULONG_PTR)key & 1) return STATUS_INVALID_PARAMETER_1; + entry = keyed_entry_acquire( handle, wine_server_client_ptr( key ), alertable ); diff --git a/staging-commit b/staging-commit index 9bc93cb..0c0cb62 100644 --- a/staging-commit +++ b/staging-commit @@ -1 +1 @@ -5a1b9d5093726d82b28433640f7bdecf3829c248 \ No newline at end of file +78bd3f0c6d0beb781b87dd9d54fd186e8f7628ef \ No newline at end of file diff --git a/wine-commit b/wine-commit index c2f73dd..cfc5f55 100644 --- a/wine-commit +++ b/wine-commit @@ -1 +1 @@ -3a6e9365336304b4d7eb4d66aef959f67361cc1f \ No newline at end of file +3a736901cdd588ba7fbb4318e5f5069793268a01 \ No newline at end of file