<pre style='margin:0'>
Perry E. Metzger (pmetzger) pushed a commit to branch master
in repository macports-ports.

</pre>
<p><a href="https://github.com/macports/macports-ports/commit/052b6748c7700485487669853888841256136e20">https://github.com/macports/macports-ports/commit/052b6748c7700485487669853888841256136e20</a></p>
<pre style="white-space: pre; background: #F8F8F8">The following commit(s) were added to refs/heads/master by this push:
<span style='display:block; white-space:pre;color:#404040;'>     new 052b6748c77 wine-devel,wine-staging: Update macos_hack, add msync and rev-bump
</span>052b6748c77 is described below

<span style='display:block; white-space:pre;color:#808000;'>commit 052b6748c7700485487669853888841256136e20
</span>Author: Dean M Greer <38226388+Gcenx@users.noreply.github.com>
AuthorDate: Sun Jun 23 17:39:16 2024 -0400

<span style='display:block; white-space:pre;color:#404040;'>    wine-devel,wine-staging: Update macos_hack, add msync and rev-bump
</span>---
 emulators/wine-devel/Portfile               |   16 +-
 emulators/wine-devel/files/1001-msync.diff  | 4979 +++++++++++++++++++++++++++
 emulators/wine-devel/files/5871.diff        |   87 +
 emulators/wine-devel/files/5871.patch       |  127 -
 emulators/wine-devel/files/macos_hacks.diff |   90 +-
 5 files changed, 5160 insertions(+), 139 deletions(-)

<span style='display:block; white-space:pre;color:#808080;'>diff --git a/emulators/wine-devel/Portfile b/emulators/wine-devel/Portfile
</span><span style='display:block; white-space:pre;color:#808080;'>index de55a244f5d..b6d9351afb6 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/emulators/wine-devel/Portfile
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/emulators/wine-devel/Portfile
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -12,7 +12,7 @@ github.tarball_from         archive
</span> name                        wine-devel
 conflicts                   wine-stable wine-staging wine-crossover
 set my_name                 wine
<span style='display:block; white-space:pre;background:#ffe0e0;'>-revision                    0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+revision                    1
</span> platforms                   {darwin >= 19}
 set branch                  [lindex [split ${version} .] 0].x
 license                     LGPL-2.1+
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -72,7 +72,7 @@ patchfiles-append \
</span> # ntdll: Fix macOS build errors with Xcode 16.
 # https://gitlab.winehq.org/wine/wine/-/merge_requests/5871
 patchfiles-append \
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    5871.patch
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    5871.diff
</span> 
 # wine requires the program specified in INSTALL to create intermediate
 # directories; /usr/bin/install doesn't.
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -145,13 +145,16 @@ subport wine-staging {
</span>         sha256  5edfa88452afd9a52dd9c978ec9ca6a713ad3d645d08d8baa318d35583e7a975 \
         size    9460666
 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    depends_extract-append port:autoconf
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    depends_patch-append    port:autoconf
</span> 
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    # Running "patchinstall.py" before 'patchfiles' get inherited from wine-devel
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    # Applying staging after other patchfiles to avoid problems
</span>     # "winemac.drv-no-flicker-patch" gets inherited from wine-devel
<span style='display:block; white-space:pre;background:#ffe0e0;'>-    post-extract {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    # "1001-msync" needs to applied after staging
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+    post-patch {
</span>         system -W ${worksrcpath} \
             "${workpath}/wine-staging-${staging_version}/staging/patchinstall.py --all -W winemac.drv-no-flicker-patch"
<span style='display:block; white-space:pre;background:#e0ffe0;'>+        system -W ${worksrcpath} \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+            "patch -p1 < ${filespath}/1001-msync.diff"
</span>     }
 }
 
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -189,7 +192,8 @@ muniversal.arch_flag        no
</span> muniversal.arch_compiler    yes
 configure.ldflags-delete    -L${compiler.library_path}
 configure.optflags          -g -O2
<span style='display:block; white-space:pre;background:#ffe0e0;'>-configure.env-append        "CROSSCFLAGS=${configure.optflags} -Wno-incompatible-pointer-types"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+# gcc14.1 now sets -Werror-incompatible-pointer-types
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+configure.env-append        "CROSSCFLAGS=${configure.optflags} -Wno-error=incompatible-pointer-types"
</span> 
 # Were only installing wine not the development files
 destroot.target             install-lib
<span style='display:block; white-space:pre;color:#808080;'>diff --git a/emulators/wine-devel/files/1001-msync.diff b/emulators/wine-devel/files/1001-msync.diff
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 00000000000..f8f61e1c1d8
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/emulators/wine-devel/files/1001-msync.diff
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,4979 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 4629457a2ec..f169525fbff 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/dlls/ntdll/Makefile.in
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/dlls/ntdll/Makefile.in
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -50,6 +50,7 @@ SOURCES = \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   unix/env.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   unix/esync.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   unix/file.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++  unix/msync.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   unix/loader.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   unix/loadorder.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   unix/process.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/dlls/ntdll/unix/esync.c b/dlls/ntdll/unix/esync.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index edfeb03864d..71ebf6e9442 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/dlls/ntdll/unix/esync.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/dlls/ntdll/unix/esync.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -49,6 +49,7 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "unix_private.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "esync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "msync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ WINE_DEFAULT_DEBUG_CHANNEL(esync);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -58,13 +59,16 @@ int do_esync(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     static int do_esync_cached = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync_cached == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-        do_esync_cached = getenv("WINEESYNC") && atoi(getenv("WINEESYNC"));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        do_esync_cached = getenv("WINEESYNC") && atoi(getenv("WINEESYNC")) && !do_msync();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     return do_esync_cached;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     static int once;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (!once++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-        FIXME("eventfd not supported on this platform.\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (getenv("WINEESYNC") && atoi(getenv("WINEESYNC")) && !do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            FIXME("eventfd not supported on this platform.\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -569,6 +573,9 @@ NTSTATUS esync_reset_event( HANDLE handle )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if ((ret = get_object( handle, &obj ))) return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     event = obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (obj->type != ESYNC_MANUAL_EVENT && obj->type != ESYNC_AUTO_EVENT)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return STATUS_OBJECT_TYPE_MISMATCH;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (obj->type == ESYNC_MANUAL_EVENT)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         /* Acquire the spinlock. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -859,7 +866,7 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-    if (objs[count - 1] && objs[count - 1]->type == ESYNC_QUEUE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (count && objs[count - 1] && objs[count - 1]->type == ESYNC_QUEUE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         msgwait = TRUE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (has_esync && has_server)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -888,7 +895,7 @@ static NTSTATUS __esync_wait_objects( DWORD count, const HANDLE *handles, BOOLEA
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-    if (wait_any || count == 1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (wait_any || count <= 1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         /* Try to check objects now, so we can obviate poll() at least. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         for (i = 0; i < count; i++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 1f91b789c69..46680f61353 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/dlls/ntdll/unix/loader.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/dlls/ntdll/unix/loader.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -89,6 +89,7 @@ extern char **environ;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "winternl.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "unix_private.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "esync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "msync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "wine/list.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "ntsyscalls.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "wine/debug.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1867,6 +1868,7 @@ static void start_main_thread(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     signal_alloc_thread( teb );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     dbg_init();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     startup_info_size = server_init_process();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    msync_init();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     esync_init();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     virtual_map_user_shared_data();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     init_cpu_info();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/dlls/ntdll/unix/msync.c b/dlls/ntdll/unix/msync.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+new file mode 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 00000000000..90e785f6df2
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/dlls/ntdll/unix/msync.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -0,0 +1,1661 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * mach semaphore-based synchronization objects
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * Copyright (C) 2018 Zebediah Figura
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * Copyright (C) 2023 Marc-Aurel Zent
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * This library is free software; you can redistribute it and/or
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * modify it under the terms of the GNU Lesser General Public
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * License as published by the Free Software Foundation; either
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * version 2.1 of the License, or (at your option) any later version.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * This library is distributed in the hope that it will be useful,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * Lesser General Public License for more details.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * You should have received a copy of the GNU Lesser General Public
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * License along with this library; if not, write to the Free Software
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#if 0
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#pragma makedep unix
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "config.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <assert.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <fcntl.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <limits.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <stdarg.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <stdlib.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <sys/mman.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef HAVE_SYS_STAT_H
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# include <sys/stat.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef HAVE_SYS_SYSCALL_H
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# include <sys/syscall.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef __APPLE__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# include <mach/mach_init.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# include <mach/mach_port.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# include <mach/message.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# include <mach/port.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# include <mach/task.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# include <mach/semaphore.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# include <mach/mach_error.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# include <servers/bootstrap.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# include <os/lock.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <dlfcn.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <sched.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "ntstatus.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define WIN32_NO_STATUS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "windef.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "winternl.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "wine/debug.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "wine/server.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "unix_private.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "msync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++WINE_DEFAULT_DEBUG_CHANNEL(msync);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static LONGLONG update_timeout( ULONGLONG end )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    LARGE_INTEGER now;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    LONGLONG timeleft;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NtQuerySystemTime( &now );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    timeleft = end - now.QuadPart;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (timeleft < 0) timeleft = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return timeleft;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline mach_timespec_t convert_to_mach_time( LONGLONG win32_time )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_timespec_t ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    ret.tv_sec = win32_time / (ULONGLONG)TICKSPERSEC;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    ret.tv_nsec = (win32_time % TICKSPERSEC) * 100;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define UL_COMPARE_AND_WAIT_SHARED  0x3
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define ULF_WAKE_ALL                0x00000100
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define ULF_NO_ERRNO                0x01000000
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern int __ulock_wake( uint32_t operation, void *addr, uint64_t wake_value );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++typedef int (*__ulock_wait2_ptr_t)( uint32_t operation, void *addr, uint64_t value,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                                    uint64_t timeout_ns, uint64_t value2 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static __ulock_wait2_ptr_t __ulock_wait2;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * Faster to directly do the syscall and inline everything, taken and slightly adapted
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * from xnu/libsyscall/mach/mach_msg.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define LIBMACH_OPTIONS64 (MACH_SEND_INTERRUPT|MACH_RCV_INTERRUPT)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define MACH64_SEND_MQ_CALL 0x0000000400000000ull
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++typedef mach_msg_return_t (*mach_msg2_trap_ptr_t)( void *data, uint64_t options,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    uint64_t msgh_bits_and_send_size, uint64_t msgh_remote_and_local_port,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    uint64_t msgh_voucher_and_id, uint64_t desc_count_and_rcv_name,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    uint64_t rcv_size_and_priority, uint64_t timeout );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static mach_msg2_trap_ptr_t mach_msg2_trap;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline mach_msg_return_t mach_msg2_internal( void *data, uint64_t option64, uint64_t msgh_bits_and_send_size,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    uint64_t msgh_remote_and_local_port, uint64_t msgh_voucher_and_id, uint64_t desc_count_and_rcv_name,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    uint64_t rcv_size_and_priority, uint64_t timeout)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg_return_t mr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mr = mach_msg2_trap( data, option64 & ~LIBMACH_OPTIONS64, msgh_bits_and_send_size,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++             msgh_remote_and_local_port, msgh_voucher_and_id, desc_count_and_rcv_name,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++             rcv_size_and_priority, timeout );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (mr == MACH_MSG_SUCCESS)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return MACH_MSG_SUCCESS;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    while (mr == MACH_SEND_INTERRUPTED)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        mr = mach_msg2_trap( data, option64 & ~LIBMACH_OPTIONS64, msgh_bits_and_send_size,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                 msgh_remote_and_local_port, msgh_voucher_and_id, desc_count_and_rcv_name,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                 rcv_size_and_priority, timeout );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    while (mr == MACH_RCV_INTERRUPTED)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        mr = mach_msg2_trap( data, option64 & ~LIBMACH_OPTIONS64, msgh_bits_and_send_size & 0xffffffffull,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                 msgh_remote_and_local_port, msgh_voucher_and_id, desc_count_and_rcv_name,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                 rcv_size_and_priority, timeout);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return mr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/* For older versions of macOS we need to provide fallback in case there is no mach_msg2... */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern mach_msg_return_t mach_msg_trap( mach_msg_header_t *msg, mach_msg_option_t option,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        mach_msg_size_t send_size, mach_msg_size_t rcv_size, mach_port_name_t rcv_name, mach_msg_timeout_t timeout,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        mach_port_name_t notify );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline mach_msg_return_t mach_msg2( mach_msg_header_t *data, uint64_t option64,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg_size_t send_size, mach_msg_size_t rcv_size, mach_port_t rcv_name, uint64_t timeout,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    uint32_t priority)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg_base_t *base;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg_size_t descriptors;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!mach_msg2_trap)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return mach_msg_trap( data, (mach_msg_option_t)option64, send_size,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                              rcv_size, rcv_name, timeout, priority );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    base = (mach_msg_base_t *)data;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if ((option64 & MACH_SEND_MSG) &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        (base->header.msgh_bits & MACH_MSGH_BITS_COMPLEX))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        descriptors = base->body.msgh_descriptor_count;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        descriptors = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define MACH_MSG2_SHIFT_ARGS(lo, hi) ((uint64_t)hi << 32 | (uint32_t)lo)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return mach_msg2_internal(data, option64 | MACH64_SEND_MQ_CALL,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++               MACH_MSG2_SHIFT_ARGS(data->msgh_bits, send_size),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++               MACH_MSG2_SHIFT_ARGS(data->msgh_remote_port, data->msgh_local_port),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++               MACH_MSG2_SHIFT_ARGS(data->msgh_voucher_port, data->msgh_id),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++               MACH_MSG2_SHIFT_ARGS(descriptors, rcv_name),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++               MACH_MSG2_SHIFT_ARGS(rcv_size, priority), timeout);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#undef MACH_MSG2_SHIFT_ARGS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/* this is a lot, but running out cripples performance */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define MAX_POOL_SEMAPHORES 1024
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define POOL_SHRINK_THRESHOLD 30
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define POOL_SHRINK_COUNT 10
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++struct semaphore_memory_pool
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    semaphore_t semaphores[MAX_POOL_SEMAPHORES];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    semaphore_t *free_semaphores[MAX_POOL_SEMAPHORES];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int count;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int total;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    os_unfair_lock lock;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static struct semaphore_memory_pool *pool;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void semaphore_pool_init(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    pool = malloc( sizeof(struct semaphore_memory_pool) );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    pool->lock = OS_UNFAIR_LOCK_INIT;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    for (i = 0; i < MAX_POOL_SEMAPHORES; i++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        pool->free_semaphores[i] = &pool->semaphores[i];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    pool->count = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    pool->total = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline semaphore_t *semaphore_pool_alloc(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    semaphore_t *new_semaphore;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    kern_return_t kr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    os_unfair_lock_lock(&pool->lock);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (pool->count == 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (pool->total < MAX_POOL_SEMAPHORES)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            TRACE("Dynamically growing semaphore pool\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            kr = semaphore_create(mach_task_self(), &pool->semaphores[pool->total], SYNC_POLICY_FIFO, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (kr != KERN_SUCCESS)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                ERR("Cannot create dynamic semaphore: %#x %s\n", kr, mach_error_string(kr));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            new_semaphore = &pool->semaphores[pool->total];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            pool->total++;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            os_unfair_lock_unlock(&pool->lock);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            return new_semaphore;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            os_unfair_lock_unlock(&pool->lock);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            WARN("Semaphore pool exhausted, consider increasing MAX_POOL_SEMAPHORES\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            new_semaphore = malloc(sizeof(semaphore_t));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            kr = semaphore_create(mach_task_self(), new_semaphore, SYNC_POLICY_FIFO, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (kr != KERN_SUCCESS)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                ERR("Cannot create dynamic semaphore: %#x %s\n", kr, mach_error_string(kr));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            return new_semaphore;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    new_semaphore = pool->free_semaphores[pool->count - 1];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    pool->count--;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    os_unfair_lock_unlock(&pool->lock);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return new_semaphore;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline void semaphore_pool_free(semaphore_t *sem)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    os_unfair_lock_lock(&pool->lock);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (sem < pool->semaphores || sem >= pool->semaphores + MAX_POOL_SEMAPHORES)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        os_unfair_lock_unlock(&pool->lock);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        semaphore_destroy(mach_task_self(), *sem);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        free(sem);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (pool->count >= POOL_SHRINK_THRESHOLD)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        TRACE("Dynamically shrinking semaphore pool\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        for (i = 0; i < POOL_SHRINK_COUNT; i++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            semaphore_destroy(mach_task_self(), *sem);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            pool->total--;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        pool->free_semaphores[pool->count] = sem;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        pool->count++;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    os_unfair_lock_unlock(&pool->lock);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++struct msync
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    void *shm;              /* pointer to shm section */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    enum msync_type type;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++typedef struct
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg_header_t header;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg_body_t body;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg_port_descriptor_t descriptor;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++} mach_register_message_prolog_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++typedef struct
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_register_message_prolog_t prolog;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int shm_idx[MAXIMUM_WAIT_OBJECTS + 1];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++} mach_register_message_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++typedef struct
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg_header_t header;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int shm_idx[MAXIMUM_WAIT_OBJECTS + 1];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++} mach_unregister_message_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static mach_port_t server_port;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static const mach_msg_bits_t msgh_bits_complex_send = MACH_MSGH_BITS_SET(
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                MACH_MSG_TYPE_COPY_SEND, 0, 0, MACH_MSGH_BITS_COMPLEX);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static const mach_msg_bits_t msgh_bits_send = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline void server_register_wait( semaphore_t sem, unsigned int msgh_id,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                                         struct msync **wait_objs, const int count )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int i, is_mutex;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg_return_t mr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    __thread static mach_register_message_t message;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    message.prolog.header.msgh_remote_port = server_port;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    message.prolog.header.msgh_bits = msgh_bits_complex_send;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    message.prolog.header.msgh_id = msgh_id;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    message.prolog.body.msgh_descriptor_count = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    message.prolog.descriptor.name = sem;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    message.prolog.descriptor.disposition = MACH_MSG_TYPE_COPY_SEND;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    message.prolog.descriptor.type = MACH_MSG_PORT_DESCRIPTOR;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    for (i = 0; i < count; i++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        is_mutex = wait_objs[i]->type == MSYNC_MUTEX ? 1 : 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        message.shm_idx[i] = wait_objs[i]->shm_idx | (is_mutex << 28);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        __atomic_add_fetch( (int *)(wait_objs[i]->shm) + 3, 1, __ATOMIC_SEQ_CST);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    message.prolog.header.msgh_size = sizeof(mach_register_message_prolog_t) +
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                                      count * sizeof(unsigned int);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mr = mach_msg2( (mach_msg_header_t *)&message, MACH_SEND_MSG, message.prolog.header.msgh_size,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                     0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (mr != MACH_MSG_SUCCESS)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        ERR("Failed to send server register wait: %#x\n", mr);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline void server_remove_wait( semaphore_t sem, unsigned int msgh_id,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                                       struct msync **wait_objs, const int count )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg_return_t mr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    __thread static mach_unregister_message_t message;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    message.header.msgh_remote_port = server_port;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    message.header.msgh_bits = msgh_bits_send;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    message.header.msgh_id = msgh_id;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    for (i = 0; i < count; i++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        int old_val, new_val;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        do
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            old_val = __atomic_load_n( (int *)(wait_objs[i]->shm) + 3, __ATOMIC_SEQ_CST );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (old_val <= 0) break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            new_val = old_val - 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        } while (!__atomic_compare_exchange_n( (int *)(wait_objs[i]->shm) + 3, &old_val,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                                               new_val, 0, __ATOMIC_SEQ_CST, __ATOMIC_SEQ_CST ));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        message.shm_idx[i] = wait_objs[i]->shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    message.header.msgh_size = sizeof(mach_msg_header_t) +
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                               count * sizeof(unsigned int);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mr = mach_msg2( (mach_msg_header_t *)&message, MACH_SEND_MSG, message.header.msgh_size,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                     0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (mr != MACH_MSG_SUCCESS)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        ERR("Failed to send server remove wait: %#x\n", mr);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static NTSTATUS destroyed_wait( ULONGLONG *end )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (end)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        usleep( update_timeout( *end ) / 10 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return STATUS_TIMEOUT;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    pause();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return STATUS_PENDING;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline int is_destroyed( struct msync **objs, int count)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    for (i = 0; i < count; i++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (__atomic_load_n( (int *)objs[i]->shm + 2, __ATOMIC_RELAXED ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline NTSTATUS msync_wait_single( struct msync *wait_obj,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                                          ULONGLONG *end )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int ret, val = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    void *addr = wait_obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    ULONGLONG ns_timeleft = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    do 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (wait_obj->type == MSYNC_MUTEX)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            val = __atomic_load_n( (int *)addr, __ATOMIC_ACQUIRE );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (!val || val == ~0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                val = GetCurrentThreadId();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (__atomic_load_n( (int *)addr, __ATOMIC_ACQUIRE ) != val)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            return STATUS_PENDING;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (end)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            ns_timeleft = update_timeout( *end ) * 100;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (!ns_timeleft) return STATUS_TIMEOUT;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        ret = __ulock_wait2( UL_COMPARE_AND_WAIT_SHARED | ULF_NO_ERRNO, addr, val, ns_timeleft, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    } while (ret == -EINTR);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (ret == -ETIMEDOUT)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return STATUS_TIMEOUT;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (is_destroyed( &wait_obj, 1 ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return destroyed_wait( end );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return STATUS_SUCCESS;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline int resize_wait_objs( struct msync **wait_objs, struct msync **objs, int count )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int read_index, write_index = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    for (read_index = 0; read_index < count; read_index++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (wait_objs[read_index] &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            __atomic_load_n( (int *)wait_objs[read_index]->shm + 2, __ATOMIC_RELAXED ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            objs[write_index] = wait_objs[read_index];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            write_index++;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return write_index;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline int check_shm_contention( struct msync **wait_objs,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                                        int count, int tid )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int i, val;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    for (i = 0; i < count; i++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        val = __atomic_load_n((int *)wait_objs[i]->shm, __ATOMIC_SEQ_CST);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (wait_objs[i]->type == MSYNC_MUTEX)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (val == 0 || val == ~0 || val == tid) return 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (val != 0)  return 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static NTSTATUS msync_wait_multiple( struct msync **wait_objs,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                                     int count, ULONGLONG *end )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int tid;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    semaphore_t *sem;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    kern_return_t kr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int msgh_id;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    __thread static struct msync *objs[MAXIMUM_WAIT_OBJECTS + 1];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    count = resize_wait_objs( wait_objs, objs, count );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (count == 1 && __ulock_wait2) return msync_wait_single( objs[0], end );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!count) return destroyed_wait( end );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    tid = GetCurrentThreadId();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (check_shm_contention( objs, count, tid ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return STATUS_PENDING;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    sem = semaphore_pool_alloc();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    msgh_id = (tid << 8) | count;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    server_register_wait( *sem, msgh_id, objs, count );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    do
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (end)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            kr = semaphore_timedwait( *sem,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        convert_to_mach_time( update_timeout( *end ) ) );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            kr = semaphore_wait( *sem );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    } while (kr == KERN_ABORTED);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    semaphore_pool_free( sem );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (is_destroyed( objs, count ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return destroyed_wait( end );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    server_remove_wait( *sem, msgh_id, objs, count );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    switch (kr) {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        case KERN_SUCCESS:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            return STATUS_SUCCESS;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        case KERN_OPERATION_TIMED_OUT:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (check_shm_contention( objs, count, tid ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                return STATUS_PENDING;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            return STATUS_TIMEOUT;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        case KERN_TERMINATED:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            return destroyed_wait( end );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        default:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            ERR("Unexpected kernel return code: %#x %s\n", kr, mach_error_string( kr ));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            return STATUS_PENDING;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++int do_msync(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef __APPLE__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    static int do_msync_cached = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync_cached == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        do_msync_cached = getenv("WINEMSYNC") && atoi(getenv("WINEMSYNC"));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return do_msync_cached;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    static int once;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!once++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        FIXME("mach semaphores not supported on this platform.\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++struct semaphore
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int count;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int max;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT(sizeof(struct semaphore) == 8);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++struct event
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int signaled;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int unused;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT(sizeof(struct event) == 8);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++struct mutex
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int tid;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int count;  /* recursion count */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT(sizeof(struct mutex) == 8);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static char shm_name[29];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static int shm_fd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void **shm_addrs;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static int shm_addrs_size;  /* length of the allocated shm_addrs array */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static long pagesize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static os_unfair_lock shm_addrs_lock = OS_UNFAIR_LOCK_INIT;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void *get_shm( unsigned int idx )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int entry  = (idx * 16) / pagesize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int offset = (idx * 16) % pagesize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    void *ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    os_unfair_lock_lock( &shm_addrs_lock );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (entry >= shm_addrs_size)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        int new_size = max(shm_addrs_size * 2, entry + 1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (!(shm_addrs = realloc( shm_addrs, new_size * sizeof(shm_addrs[0]) )))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            ERR("Failed to grow shm_addrs array to size %d.\n", shm_addrs_size);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        memset( shm_addrs + shm_addrs_size, 0, (new_size - shm_addrs_size) * sizeof(shm_addrs[0]) );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        shm_addrs_size = new_size;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!shm_addrs[entry])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        void *addr = mmap( NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, entry * pagesize );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (addr == (void *)-1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            ERR("Failed to map page %d (offset %#lx).\n", entry, entry * pagesize);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        TRACE("Mapping page %d at %p.\n", entry, addr);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (__sync_val_compare_and_swap( &shm_addrs[entry], 0, addr ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            munmap( addr, pagesize ); /* someone beat us to it */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    ret = (void *)((unsigned long)shm_addrs[entry] + offset);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    os_unfair_lock_unlock( &shm_addrs_lock );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/* We'd like lookup to be fast. To that end, we use a static list indexed by handle.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * This is copied and adapted from the fd cache code. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define MSYNC_LIST_BLOCK_SIZE  (65536 / sizeof(struct msync))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define MSYNC_LIST_ENTRIES     256
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static struct msync *msync_list[MSYNC_LIST_ENTRIES];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static struct msync msync_list_initial_block[MSYNC_LIST_BLOCK_SIZE];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline UINT_PTR handle_to_index( HANDLE handle, UINT_PTR *entry )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    UINT_PTR idx = (((UINT_PTR)handle) >> 2) - 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    *entry = idx / MSYNC_LIST_BLOCK_SIZE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return idx % MSYNC_LIST_BLOCK_SIZE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static struct msync *add_to_list( HANDLE handle, enum msync_type type, unsigned int shm_idx )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    UINT_PTR entry, idx = handle_to_index( handle, &entry );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    void *shm = get_shm( shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (entry >= MSYNC_LIST_ENTRIES)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        FIXME( "too many allocated handles, not caching %p\n", handle );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return FALSE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!msync_list[entry])  /* do we need to allocate a new block of entries? */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (!entry) msync_list[0] = msync_list_initial_block;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            void *ptr = anon_mmap_alloc( MSYNC_LIST_BLOCK_SIZE * sizeof(struct msync),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                                         PROT_READ | PROT_WRITE );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (ptr == MAP_FAILED) return FALSE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            msync_list[entry] = ptr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!__sync_val_compare_and_swap((int *)&msync_list[entry][idx].type, 0, type ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_list[entry][idx].shm = shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_list[entry][idx].shm_idx = shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return &msync_list[entry][idx];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static struct msync *get_cached_object( HANDLE handle )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    UINT_PTR entry, idx = handle_to_index( handle, &entry );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (entry >= MSYNC_LIST_ENTRIES || !msync_list[entry]) return NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!msync_list[entry][idx].type) return NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return &msync_list[entry][idx];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/* Gets an object. This is either a proper msync object (i.e. an event,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * semaphore, etc. created using create_msync) or a generic synchronizable
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * server-side object which the server will signal (e.g. a process, thread,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * message queue, etc.) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static NTSTATUS get_object( HANDLE handle, struct msync **obj )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NTSTATUS ret = STATUS_SUCCESS;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int shm_idx = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    enum msync_type type;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if ((*obj = get_cached_object( handle ))) return STATUS_SUCCESS;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if ((INT_PTR)handle < 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        /* We can deal with pseudo-handles, but it's just easier this way */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return STATUS_NOT_IMPLEMENTED;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    /* We need to try grabbing it from the server. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    SERVER_START_REQ( get_msync_idx )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        req->handle = wine_server_obj_handle( handle );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (!(ret = wine_server_call( req )))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            shm_idx = reply->shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            type    = reply->type;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    SERVER_END_REQ;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (ret)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        WARN("Failed to retrieve shm index for handle %p, status %#x.\n", handle, ret);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        *obj = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    TRACE("Got shm index %d for handle %p.\n", shm_idx, handle);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    *obj = add_to_list( handle, type, shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++NTSTATUS msync_close( HANDLE handle )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    UINT_PTR entry, idx = handle_to_index( handle, &entry );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    TRACE("%p.\n", handle);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (entry < MSYNC_LIST_ENTRIES && msync_list[entry])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (__atomic_exchange_n( &msync_list[entry][idx].type, 0, __ATOMIC_SEQ_CST ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            return STATUS_SUCCESS;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return STATUS_INVALID_HANDLE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static NTSTATUS create_msync( enum msync_type type, HANDLE *handle,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, int low, int high )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NTSTATUS ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    data_size_t len;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct object_attributes *objattr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    SERVER_START_REQ( create_msync )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        req->access = access;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        req->low    = low;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        req->high   = high;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        req->type   = type;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        wine_server_add_data( req, objattr, len );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        ret = wine_server_call( req );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (!ret || ret == STATUS_OBJECT_NAME_EXISTS)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            *handle = wine_server_ptr_handle( reply->handle );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            shm_idx = reply->shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            type    = reply->type;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    SERVER_END_REQ;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!ret || ret == STATUS_OBJECT_NAME_EXISTS)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        add_to_list( *handle, type, shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        TRACE("-> handle %p, shm index %d.\n", *handle, shm_idx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    free( objattr );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static NTSTATUS open_msync( enum msync_type type, HANDLE *handle,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NTSTATUS ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    SERVER_START_REQ( open_msync )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        req->access     = access;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        req->attributes = attr->Attributes;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        req->rootdir    = wine_server_obj_handle( attr->RootDirectory );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        req->type       = type;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (attr->ObjectName)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            wine_server_add_data( req, attr->ObjectName->Buffer, attr->ObjectName->Length );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (!(ret = wine_server_call( req )))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            *handle = wine_server_ptr_handle( reply->handle );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            type = reply->type;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            shm_idx = reply->shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    SERVER_END_REQ;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!ret)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        add_to_list( *handle, type, shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        TRACE("-> handle %p, shm index %u.\n", *handle, shm_idx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++void msync_init(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct stat st;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_port_t bootstrap_port;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    void *dlhandle = dlopen( NULL, RTLD_NOW );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        /* make sure the server isn't running with WINEMSYNC */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        HANDLE handle;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        NTSTATUS ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        ret = create_msync( 0, &handle, 0, NULL, 0, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (ret != STATUS_NOT_IMPLEMENTED)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            ERR("Server is running with WINEMSYNC but this process is not, please enable WINEMSYNC or restart wineserver.\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            exit(1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        dlclose( dlhandle );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (stat( config_dir, &st ) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        ERR("Cannot stat %s\n", config_dir);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (st.st_ino != (unsigned long)st.st_ino)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        sprintf( shm_name, "/wine-%lx%08lx-msync", (unsigned long)((unsigned long long)st.st_ino >> 32), (unsigned long)st.st_ino );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        sprintf( shm_name, "/wine-%lx-msync", (unsigned long)st.st_ino );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if ((shm_fd = shm_open( shm_name, O_RDWR, 0644 )) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        /* probably the server isn't running with WINEMSYNC, tell the user and bail */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (errno == ENOENT)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            ERR("Failed to open msync shared memory file; make sure no stale wineserver instances are running without WINEMSYNC.\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            ERR("Failed to initialize shared memory: %s\n", strerror( errno ));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        exit(1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    pagesize = sysconf( _SC_PAGESIZE );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    shm_addrs = calloc( 128, sizeof(shm_addrs[0]) );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    shm_addrs_size = 128;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    semaphore_pool_init();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    __ulock_wait2 = (__ulock_wait2_ptr_t)dlsym( dlhandle, "__ulock_wait2" );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!__ulock_wait2)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        WARN("__ulock_wait2 not available, performance will be lower\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    /* Bootstrap mach wineserver communication */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg2_trap = (mach_msg2_trap_ptr_t)dlsym( dlhandle, "mach_msg2_trap" );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!mach_msg2_trap)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        WARN("Using mach_msg_overwrite instead of mach_msg2\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    dlclose( dlhandle );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (task_get_special_port(mach_task_self(), TASK_BOOTSTRAP_PORT, &bootstrap_port) != KERN_SUCCESS)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        ERR("Failed task_get_special_port\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        exit(1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (bootstrap_look_up(bootstrap_port, shm_name + 1, &server_port) != KERN_SUCCESS)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        ERR("Failed bootstrap_look_up for %s\n", shm_name + 1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        exit(1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++NTSTATUS msync_create_semaphore( HANDLE *handle, ACCESS_MASK access,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    TRACE("name %s, initial %d, max %d.\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        attr ? debugstr_us(attr->ObjectName) : "<no name>", initial, max);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return create_msync( MSYNC_SEMAPHORE, handle, access, attr, initial, max );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++NTSTATUS msync_open_semaphore( HANDLE *handle, ACCESS_MASK access,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    const OBJECT_ATTRIBUTES *attr )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    TRACE("name %s.\n", debugstr_us(attr->ObjectName));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return open_msync( MSYNC_SEMAPHORE, handle, access, attr );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline void signal_all( struct msync *obj )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    __thread static mach_msg_header_t send_header;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    __ulock_wake( UL_COMPARE_AND_WAIT_SHARED | ULF_WAKE_ALL, obj->shm, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!__atomic_load_n( (int *)obj->shm + 3, __ATOMIC_ACQUIRE ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    send_header.msgh_bits = msgh_bits_send;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    send_header.msgh_id = obj->shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    send_header.msgh_size = sizeof(send_header);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    send_header.msgh_remote_port = server_port;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg2( &send_header, MACH_SEND_MSG, send_header.msgh_size, 0,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++               MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++NTSTATUS msync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync *obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct semaphore *semaphore;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    ULONG current;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NTSTATUS ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    TRACE("%p, %d, %p.\n", handle, count, prev);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if ((ret = get_object( handle, &obj ))) return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    semaphore = obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    do
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        current = semaphore->count;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (count + current > semaphore->max)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            return STATUS_SEMAPHORE_LIMIT_EXCEEDED;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    } while (__sync_val_compare_and_swap( &semaphore->count, current, count + current ) != current);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (prev) *prev = current;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    signal_all( obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return STATUS_SUCCESS;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++NTSTATUS msync_query_semaphore( HANDLE handle, void *info, ULONG *ret_len )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync *obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct semaphore *semaphore;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    SEMAPHORE_BASIC_INFORMATION *out = info;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NTSTATUS ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if ((ret = get_object( handle, &obj ))) return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    semaphore = obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    out->CurrentCount = semaphore->count;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    out->MaximumCount = semaphore->max;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (ret_len) *ret_len = sizeof(*out);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return STATUS_SUCCESS;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++NTSTATUS msync_create_event( HANDLE *handle, ACCESS_MASK access,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    const OBJECT_ATTRIBUTES *attr, EVENT_TYPE event_type, BOOLEAN initial )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    enum msync_type type = (event_type == SynchronizationEvent ? MSYNC_AUTO_EVENT : MSYNC_MANUAL_EVENT);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    TRACE("name %s, %s-reset, initial %d.\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        attr ? debugstr_us(attr->ObjectName) : "<no name>",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        event_type == NotificationEvent ? "manual" : "auto", initial);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return create_msync( type, handle, access, attr, initial, 0xdeadbeef );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++NTSTATUS msync_open_event( HANDLE *handle, ACCESS_MASK access,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    const OBJECT_ATTRIBUTES *attr )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    TRACE("name %s.\n", debugstr_us(attr->ObjectName));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return open_msync( MSYNC_AUTO_EVENT, handle, access, attr );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++NTSTATUS msync_set_event( HANDLE handle, LONG *prev )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct event *event;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync *obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    LONG current;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NTSTATUS ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    TRACE("%p.\n", handle);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if ((ret = get_object( handle, &obj ))) return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    event = obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (obj->type != MSYNC_MANUAL_EVENT && obj->type != MSYNC_AUTO_EVENT)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return STATUS_OBJECT_TYPE_MISMATCH;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!(current = __atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST )))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        signal_all( obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (prev) *prev = current;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return STATUS_SUCCESS;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++NTSTATUS msync_reset_event( HANDLE handle, LONG *prev )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct event *event;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync *obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    LONG current;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NTSTATUS ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    TRACE("%p.\n", handle);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if ((ret = get_object( handle, &obj ))) return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    event = obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    current = __atomic_exchange_n( &event->signaled, 0, __ATOMIC_SEQ_CST );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (prev) *prev = current;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return STATUS_SUCCESS;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++NTSTATUS msync_pulse_event( HANDLE handle, LONG *prev )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct event *event;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync *obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    LONG current;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NTSTATUS ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    TRACE("%p.\n", handle);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if ((ret = get_object( handle, &obj ))) return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    event = obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    /* This isn't really correct; an application could miss the write.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++     * Unfortunately we can't really do much better. Fortunately this is rarely
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++     * used (and publicly deprecated). */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!(current = __atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST )))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        signal_all( obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    /* Try to give other threads a chance to wake up. Hopefully erring on this
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++     * side is the better thing to do... */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    sched_yield();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    __atomic_store_n( &event->signaled, 0, __ATOMIC_SEQ_CST );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (prev) *prev = current;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return STATUS_SUCCESS;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++NTSTATUS msync_query_event( HANDLE handle, void *info, ULONG *ret_len )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct event *event;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync *obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    EVENT_BASIC_INFORMATION *out = info;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NTSTATUS ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if ((ret = get_object( handle, &obj ))) return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    event = obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    out->EventState = event->signaled;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    out->EventType = (obj->type == MSYNC_AUTO_EVENT ? SynchronizationEvent : NotificationEvent);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (ret_len) *ret_len = sizeof(*out);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return STATUS_SUCCESS;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++NTSTATUS msync_create_mutex( HANDLE *handle, ACCESS_MASK access,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    const OBJECT_ATTRIBUTES *attr, BOOLEAN initial )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    TRACE("name %s, initial %d.\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        attr ? debugstr_us(attr->ObjectName) : "<no name>", initial);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return create_msync( MSYNC_MUTEX, handle, access, attr,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        initial ? GetCurrentThreadId() : 0, initial ? 1 : 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++NTSTATUS msync_open_mutex( HANDLE *handle, ACCESS_MASK access,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    const OBJECT_ATTRIBUTES *attr )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    TRACE("name %s.\n", debugstr_us(attr->ObjectName));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return open_msync( MSYNC_MUTEX, handle, access, attr );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++NTSTATUS msync_release_mutex( HANDLE handle, LONG *prev )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct mutex *mutex;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync *obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NTSTATUS ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    TRACE("%p, %p.\n", handle, prev);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if ((ret = get_object( handle, &obj ))) return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mutex = obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (mutex->tid != GetCurrentThreadId()) return STATUS_MUTANT_NOT_OWNED;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (prev) *prev = mutex->count;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!--mutex->count)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        __atomic_store_n( &mutex->tid, 0, __ATOMIC_SEQ_CST );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        signal_all( obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return STATUS_SUCCESS;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++NTSTATUS msync_query_mutex( HANDLE handle, void *info, ULONG *ret_len )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync *obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct mutex *mutex;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    MUTANT_BASIC_INFORMATION *out = info;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NTSTATUS ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    TRACE("handle %p, info %p, ret_len %p.\n", handle, info, ret_len);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if ((ret = get_object( handle, &obj ))) return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mutex = obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    out->CurrentCount = 1 - mutex->count;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    out->OwnedByCaller = (mutex->tid == GetCurrentThreadId());
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    out->AbandonedState = (mutex->tid == ~0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (ret_len) *ret_len = sizeof(*out);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return STATUS_SUCCESS;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static NTSTATUS do_single_wait( struct msync *obj, ULONGLONG *end, BOOLEAN alertable )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NTSTATUS status;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync *wait_objs[2];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    wait_objs[0] = obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (alertable)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        struct msync apc_obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        int *apc_addr = ntdll_get_thread_data()->msync_apc_addr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        apc_obj.type = MSYNC_AUTO_EVENT;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        apc_obj.shm = (void *)apc_addr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        apc_obj.shm_idx = ntdll_get_thread_data()->msync_apc_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (__atomic_load_n( apc_addr, __ATOMIC_SEQ_CST ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            return STATUS_USER_APC;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        wait_objs[1] = &apc_obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        status = msync_wait_multiple( wait_objs, 2, end );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (__atomic_load_n( apc_addr, __ATOMIC_SEQ_CST ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            return STATUS_USER_APC;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        status = msync_wait_multiple( wait_objs, 1, end );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return status;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static NTSTATUS __msync_wait_objects( DWORD count, const HANDLE *handles,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    BOOLEAN wait_any, BOOLEAN alertable, const LARGE_INTEGER *timeout )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    static const LARGE_INTEGER zero = {0};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    __thread static struct msync *objs[MAXIMUM_WAIT_OBJECTS + 1];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync apc_obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int has_msync = 0, has_server = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    BOOL msgwait = FALSE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    LONGLONG timeleft;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    LARGE_INTEGER now;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    DWORD waitcount;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    ULONGLONG end;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int i, ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    /* Grab the APC idx if we don't already have it. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (alertable && !ntdll_get_thread_data()->msync_apc_addr)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        unsigned int idx = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        SERVER_START_REQ( get_msync_apc_idx )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (!(ret = wine_server_call( req )))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                idx = reply->shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        SERVER_END_REQ;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (idx)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            struct event *apc_event = get_shm( idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            ntdll_get_thread_data()->msync_apc_addr = &apc_event->signaled;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            ntdll_get_thread_data()->msync_apc_idx = idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NtQuerySystemTime( &now );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (timeout)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (timeout->QuadPart == TIMEOUT_INFINITE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            timeout = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        else if (timeout->QuadPart > 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            end = timeout->QuadPart;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            end = now.QuadPart - timeout->QuadPart;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    for (i = 0; i < count; i++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        ret = get_object( handles[i], &objs[i] );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (ret == STATUS_SUCCESS)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            has_msync = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        else if (ret == STATUS_NOT_IMPLEMENTED)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            has_server = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (count && objs[count - 1] && objs[count - 1]->type == MSYNC_QUEUE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msgwait = TRUE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (has_msync && has_server)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        FIXME("Can't wait on msync and server objects at the same time!\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    else if (has_server)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return STATUS_NOT_IMPLEMENTED;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (TRACE_ON(msync))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        TRACE("Waiting for %s of %d handles:", wait_any ? "any" : "all", count);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        for (i = 0; i < count; i++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            TRACE(" %p", handles[i]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (msgwait)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            TRACE(" or driver events");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (alertable)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            TRACE(", alertable");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (!timeout)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            TRACE(", timeout = INFINITE.\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            timeleft = update_timeout( end );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            TRACE(", timeout = %ld.%07ld sec.\n",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                (long) (timeleft / TICKSPERSEC), (long) (timeleft % TICKSPERSEC));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (wait_any || count <= 1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        while (1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            /* Try to grab anything. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (alertable)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                apc_obj.type = MSYNC_AUTO_EVENT;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                /* We must check this first! The server may set an event that
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                 * we're waiting on, but we need to return STATUS_USER_APC. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                if (__atomic_load_n( ntdll_get_thread_data()->msync_apc_addr, __ATOMIC_SEQ_CST ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    goto userapc;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            for (i = 0; i < count; i++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                struct msync *obj = objs[i];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                if (obj)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    if (!obj->type) /* gcc complains if we put this in the switch */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        /* Someone probably closed an object while waiting on it. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        WARN("Handle %p has type 0; was it closed?\n", handles[i]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        return STATUS_INVALID_HANDLE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    switch (obj->type)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    case MSYNC_SEMAPHORE:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        struct semaphore *semaphore = obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        int current;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        current = __atomic_load_n(&semaphore->count, __ATOMIC_ACQUIRE);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        if (current && __atomic_compare_exchange_n(&semaphore->count, &current, current - 1, 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            TRACE("Woken up by handle %p [%d].\n", handles[i], i);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            return i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    case MSYNC_MUTEX:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        struct mutex *mutex = obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        int tid;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        if (mutex->tid == GetCurrentThreadId())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            TRACE("Woken up by handle %p [%d].\n", handles[i], i);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            mutex->count++;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            return i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        tid = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        if (__atomic_compare_exchange_n(&mutex->tid, &tid, GetCurrentThreadId(), 0, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            TRACE("Woken up by handle %p [%d].\n", handles[i], i);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            mutex->count = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            return i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        else if (tid == ~0 && __atomic_compare_exchange_n(&mutex->tid, &tid, GetCurrentThreadId(), 0, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            TRACE("Woken up by abandoned mutex %p [%d].\n", handles[i], i);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            mutex->count = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            return STATUS_ABANDONED_WAIT_0 + i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    case MSYNC_AUTO_EVENT:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    case MSYNC_AUTO_SERVER:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        struct event *event = obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        int signaled = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        if (__atomic_compare_exchange_n(&event->signaled, &signaled, 0, 0, __ATOMIC_ACQ_REL, __ATOMIC_RELAXED))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            TRACE("Woken up by handle %p [%d].\n", handles[i], i);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            return i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    case MSYNC_MANUAL_EVENT:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    case MSYNC_MANUAL_SERVER:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    case MSYNC_QUEUE:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        struct event *event = obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        if (__atomic_load_n(&event->signaled, __ATOMIC_ACQUIRE))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            TRACE("Woken up by handle %p [%d].\n", handles[i], i);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            return i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    default:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        ERR("Invalid type %#x for handle %p.\n", obj->type, handles[i]);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        assert(0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (alertable)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                /* We already checked if it was signaled; don't bother doing it again. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                apc_obj.shm = (void *)ntdll_get_thread_data()->msync_apc_addr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                apc_obj.shm_idx = ntdll_get_thread_data()->msync_apc_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                objs[i] = &apc_obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                i++;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            waitcount = i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            /* Looks like everything is contended, so wait. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (timeout && !timeout->QuadPart)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                /* Unlike esync, we already know that we've timed out, so we
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                 * can avoid a syscall. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                TRACE("Wait timed out.\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                return STATUS_TIMEOUT;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            ret = msync_wait_multiple( objs, waitcount, timeout ? &end : NULL );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (ret == STATUS_TIMEOUT)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                TRACE("Wait timed out.\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                return STATUS_TIMEOUT;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        } /* while (1) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        /* Wait-all is a little trickier to implement correctly. Fortunately,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * it's not as common.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * The idea is basically just to wait in sequence on every object in the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * set. Then when we're done, try to grab them all in a tight loop. If
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * that fails, release any resources we've grabbed (and yes, we can
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * reliably do this—it's just mutexes and semaphores that we have to
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * put back, and in both cases we just put back 1), and if any of that
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * fails we start over.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * What makes this inherently bad is that we might temporarily grab a
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * resource incorrectly. Hopefully it'll be quick (and hey, it won't
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * block on wineserver) so nobody will notice. Besides, consider: if
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * object A becomes signaled but someone grabs it before we can grab it
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * and everything else, then they could just as well have grabbed it
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * before it became signaled. Similarly if object A was signaled and we
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * were blocking on object B, then B becomes available and someone grabs
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * A before we can, then they might have grabbed A before B became
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * signaled. In either case anyone who tries to wait on A or B will be
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * waiting for an instant while we put things back. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        NTSTATUS status = STATUS_SUCCESS;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        while (1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            BOOL abandoned;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++tryagain:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            abandoned = FALSE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            /* First step: try to wait on each object in sequence. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            for (i = 0; i < count; i++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                struct msync *obj = objs[i];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                if (obj && obj->type == MSYNC_MUTEX)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    struct mutex *mutex = obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    if (mutex->tid == GetCurrentThreadId())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    while (__atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        status = do_single_wait( obj, timeout ? &end : NULL, alertable );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        if (status != STATUS_PENDING)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                else if (obj)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    /* this works for semaphores too */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    struct event *event = obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    while (!__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        status = do_single_wait( obj, timeout ? &end : NULL, alertable );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        if (status != STATUS_PENDING)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                if (status == STATUS_TIMEOUT)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    TRACE("Wait timed out.\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    return STATUS_TIMEOUT;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                else if (status == STATUS_USER_APC)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    goto userapc;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            /* If we got here and we haven't timed out, that means all of the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++             * handles were signaled. Check to make sure they still are. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            for (i = 0; i < count; i++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                struct msync *obj = objs[i];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                if (obj && obj->type == MSYNC_MUTEX)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    struct mutex *mutex = obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    int tid = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    if (tid && tid != ~0 && tid != GetCurrentThreadId())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        goto tryagain;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                else if (obj)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    struct event *event = obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    if (!__atomic_load_n( &event->signaled, __ATOMIC_SEQ_CST ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        goto tryagain;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            /* Yep, still signaled. Now quick, grab everything. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            for (i = 0; i < count; i++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                struct msync *obj = objs[i];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                if (!obj) continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                switch (obj->type)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                case MSYNC_MUTEX:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    struct mutex *mutex = obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    int tid = __atomic_load_n( &mutex->tid, __ATOMIC_SEQ_CST );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    if (tid == GetCurrentThreadId())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    if (tid && tid != ~0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        goto tooslow;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    if (__sync_val_compare_and_swap( &mutex->tid, tid, GetCurrentThreadId() ) != tid)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        goto tooslow;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    if (tid == ~0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        abandoned = TRUE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                case MSYNC_SEMAPHORE:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    struct semaphore *semaphore = obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    int current;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    if (!(current = __atomic_load_n( &semaphore->count, __ATOMIC_SEQ_CST ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            || __sync_val_compare_and_swap( &semaphore->count, current, current - 1 ) != current)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        goto tooslow;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                case MSYNC_AUTO_EVENT:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                case MSYNC_AUTO_SERVER:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    struct event *event = obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    if (!__sync_val_compare_and_swap( &event->signaled, 1, 0 ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                        goto tooslow;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                default:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    /* If a manual-reset event changed between there and
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                     * here, it's shouldn't be a problem. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            /* If we got here, we successfully waited on every object.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++             * Make sure to let ourselves know that we grabbed the mutexes. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            for (i = 0; i < count; i++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                if (objs[i] && objs[i]->type == MSYNC_MUTEX)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    struct mutex *mutex = objs[i]->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    mutex->count++;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (abandoned)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                TRACE("Wait successful, but some object(s) were abandoned.\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                return STATUS_ABANDONED;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            TRACE("Wait successful.\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            return STATUS_SUCCESS;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++tooslow:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            for (--i; i >= 0; i--)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                struct msync *obj = objs[i];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                if (!obj) continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                switch (obj->type)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                case MSYNC_MUTEX:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    struct mutex *mutex = obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    /* HACK: This won't do the right thing with abandoned
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                     * mutexes, but fixing it is probably more trouble than
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                     * it's worth. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    __atomic_store_n( &mutex->tid, 0, __ATOMIC_SEQ_CST );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                case MSYNC_SEMAPHORE:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    struct semaphore *semaphore = obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    __sync_fetch_and_add( &semaphore->count, 1 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                case MSYNC_AUTO_EVENT:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                case MSYNC_AUTO_SERVER:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    struct event *event = obj->shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    __atomic_store_n( &event->signaled, 1, __ATOMIC_SEQ_CST );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                default:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    /* doesn't need to be put back */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        } /* while (1) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    } /* else (wait-all) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    assert(0);  /* shouldn't reach here... */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++userapc:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    TRACE("Woken up by user APC.\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    /* We have to make a server call anyway to get the APC to execute, so just
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++     * delegate down to server_wait(). */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    ret = server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, &zero );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    /* This can happen if we received a system APC, and the APC fd was woken up
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++     * before we got SIGUSR1. poll() doesn't return EINTR in that case. The
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++     * right thing to do seems to be to return STATUS_USER_APC anyway. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (ret == STATUS_TIMEOUT) ret = STATUS_USER_APC;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/* Like esync, we need to let the server know when we are doing a message wait,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * and when we are done with one, so that all of the code surrounding hung
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * queues works, and we also need this for WaitForInputIdle().
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * Unlike esync, we can't wait on the queue fd itself locally. Instead we let
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * the server do that for us, the way it normally does. This could actually
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * work for esync too, and that might be better. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void server_set_msgwait( int in_msgwait )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    SERVER_START_REQ( msync_msgwait )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        req->in_msgwait = in_msgwait;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        wine_server_call( req );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    SERVER_END_REQ;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/* This is a very thin wrapper around the proper implementation above. The
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * purpose is to make sure the server knows when we are doing a message wait.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * This is separated into a wrapper function since there are at least a dozen
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * exit paths from msync_wait_objects(). */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++NTSTATUS msync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                             BOOLEAN alertable, const LARGE_INTEGER *timeout )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    BOOL msgwait = FALSE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync *obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NTSTATUS ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (count && !get_object( handles[count - 1], &obj ) && obj->type == MSYNC_QUEUE)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msgwait = TRUE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        server_set_msgwait( 1 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    ret = __msync_wait_objects( count, handles, wait_any, alertable, timeout );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (msgwait)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        server_set_msgwait( 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++NTSTATUS msync_signal_and_wait( HANDLE signal, HANDLE wait, BOOLEAN alertable,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    const LARGE_INTEGER *timeout )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync *obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NTSTATUS ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if ((ret = get_object( signal, &obj ))) return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    switch (obj->type)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    case MSYNC_SEMAPHORE:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        ret = msync_release_semaphore( signal, 1, NULL );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    case MSYNC_AUTO_EVENT:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    case MSYNC_MANUAL_EVENT:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        ret = msync_set_event( signal, NULL );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    case MSYNC_MUTEX:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        ret = msync_release_mutex( signal, NULL );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    default:
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return STATUS_OBJECT_TYPE_MISMATCH;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (ret) return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return msync_wait_objects( 1, &wait, TRUE, alertable, timeout );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/dlls/ntdll/unix/msync.h b/dlls/ntdll/unix/msync.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+new file mode 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 00000000000..3e6eb2c8b1e
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/dlls/ntdll/unix/msync.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -0,0 +1,50 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * mach semaphore-based synchronization objects
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * Copyright (C) 2018 Zebediah Figura
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * Copyright (C) 2023 Marc-Aurel Zent
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * This library is free software; you can redistribute it and/or
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * modify it under the terms of the GNU Lesser General Public
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * License as published by the Free Software Foundation; either
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * version 2.1 of the License, or (at your option) any later version.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * This library is distributed in the hope that it will be useful,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * Lesser General Public License for more details.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * You should have received a copy of the GNU Lesser General Public
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * License along with this library; if not, write to the Free Software
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern int do_msync(void);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern void msync_init(void);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern NTSTATUS msync_close( HANDLE handle );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern NTSTATUS msync_create_semaphore(HANDLE *handle, ACCESS_MASK access,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    const OBJECT_ATTRIBUTES *attr, LONG initial, LONG max);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern NTSTATUS msync_release_semaphore( HANDLE handle, ULONG count, ULONG *prev );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern NTSTATUS msync_open_semaphore( HANDLE *handle, ACCESS_MASK access,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    const OBJECT_ATTRIBUTES *attr );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern NTSTATUS msync_query_semaphore( HANDLE handle, void *info, ULONG *ret_len );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern NTSTATUS msync_create_event( HANDLE *handle, ACCESS_MASK access,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    const OBJECT_ATTRIBUTES *attr, EVENT_TYPE type, BOOLEAN initial );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern NTSTATUS msync_open_event( HANDLE *handle, ACCESS_MASK access,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    const OBJECT_ATTRIBUTES *attr );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern NTSTATUS msync_set_event( HANDLE handle, LONG *prev );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern NTSTATUS msync_reset_event( HANDLE handle, LONG *prev );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern NTSTATUS msync_pulse_event( HANDLE handle, LONG *prev );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern NTSTATUS msync_query_event( HANDLE handle, void *info, ULONG *ret_len );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern NTSTATUS msync_create_mutex( HANDLE *handle, ACCESS_MASK access,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    const OBJECT_ATTRIBUTES *attr, BOOLEAN initial );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern NTSTATUS msync_open_mutex( HANDLE *handle, ACCESS_MASK access,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    const OBJECT_ATTRIBUTES *attr );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern NTSTATUS msync_release_mutex( HANDLE handle, LONG *prev );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern NTSTATUS msync_query_mutex( HANDLE handle, void *info, ULONG *ret_len );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern NTSTATUS msync_wait_objects( DWORD count, const HANDLE *handles, BOOLEAN wait_any,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                                    BOOLEAN alertable, const LARGE_INTEGER *timeout );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern NTSTATUS msync_signal_and_wait( HANDLE signal, HANDLE wait,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    BOOLEAN alertable, const LARGE_INTEGER *timeout );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/dlls/ntdll/unix/server.c b/dlls/ntdll/unix/server.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 77aa995326c..f45db2f3090 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/dlls/ntdll/unix/server.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/dlls/ntdll/unix/server.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -84,6 +84,7 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "wine/debug.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "unix_private.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "esync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "msync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "ddk/wdm.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ WINE_DEFAULT_DEBUG_CHANNEL(server);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1882,6 +1883,9 @@ NTSTATUS WINAPI NtClose( HANDLE handle )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+      * retrieve it again */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     fd = remove_fd_from_cache( handle );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_close( handle );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         esync_close( handle );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/dlls/ntdll/unix/sync.c b/dlls/ntdll/unix/sync.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 1ddb9247fb1..641665b5ed2 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/dlls/ntdll/unix/sync.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/dlls/ntdll/unix/sync.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -67,6 +67,7 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "wine/debug.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "unix_private.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "esync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "msync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ WINE_DEFAULT_DEBUG_CHANNEL(sync);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -119,7 +120,7 @@ static inline int futex_wait( const LONG *addr, int val, struct timespec *timeou
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             long tv_nsec;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         } timeout32 = { timeout->tv_sec, timeout->tv_nsec };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-        return syscall( __NR_futex, addr, FUTEX_WAIT_PRIVATE, val, &timeout32, 0, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return syscall( __NR_futex, addr, FUTEX_WAIT_PRIVATE| futex_private, val, &timeout32, 0, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     return syscall( __NR_futex, addr, FUTEX_WAIT_PRIVATE, val, timeout, 0, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -256,6 +257,9 @@ NTSTATUS WINAPI NtCreateSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJ
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (max <= 0 || initial < 0 || initial > max) return STATUS_INVALID_PARAMETER;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if ((ret = alloc_object_attributes( attr, &objattr, &len ))) return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return msync_create_semaphore( handle, access, attr, initial, max );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         return esync_create_semaphore( handle, access, attr, initial, max );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -284,6 +288,9 @@ NTSTATUS WINAPI NtOpenSemaphore( HANDLE *handle, ACCESS_MASK access, const OBJEC
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     *handle = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return msync_open_semaphore( handle, access, attr );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         return esync_open_semaphore( handle, access, attr );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -323,6 +330,9 @@ NTSTATUS WINAPI NtQuerySemaphore( HANDLE handle, SEMAPHORE_INFORMATION_CLASS cla
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (len != sizeof(SEMAPHORE_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return msync_query_semaphore( handle, info, ret_len );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         return esync_query_semaphore( handle, info, ret_len );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -348,6 +358,9 @@ NTSTATUS WINAPI NtReleaseSemaphore( HANDLE handle, ULONG count, ULONG *previous
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     unsigned int ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return msync_release_semaphore( handle, count, previous );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         return esync_release_semaphore( handle, count, previous );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -378,6 +391,9 @@ NTSTATUS WINAPI NtCreateEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     *handle = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (type != NotificationEvent && type != SynchronizationEvent) return STATUS_INVALID_PARAMETER;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return msync_create_event( handle, access, attr, type, state );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         return esync_create_event( handle, access, attr, type, state );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -409,6 +425,9 @@ NTSTATUS WINAPI NtOpenEvent( HANDLE *handle, ACCESS_MASK access, const OBJECT_AT
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     *handle = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if ((ret = validate_open_object_attributes( attr ))) return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return msync_open_event( handle, access, attr );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         return esync_open_event( handle, access, attr );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -435,6 +454,9 @@ NTSTATUS WINAPI NtSetEvent( HANDLE handle, LONG *prev_state )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     /* This comment is a dummy to make sure this patch applies in the right place. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     unsigned int ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return msync_set_event( handle, prev_state );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         return esync_set_event( handle );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -458,6 +480,9 @@ NTSTATUS WINAPI NtResetEvent( HANDLE handle, LONG *prev_state )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     /* This comment is a dummy to make sure this patch applies in the right place. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     unsigned int ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return msync_reset_event( handle, prev_state );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         return esync_reset_event( handle );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -491,6 +516,9 @@ NTSTATUS WINAPI NtPulseEvent( HANDLE handle, LONG *prev_state )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     unsigned int ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return msync_pulse_event( handle, prev_state );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         return esync_pulse_event( handle );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -525,6 +553,9 @@ NTSTATUS WINAPI NtQueryEvent( HANDLE handle, EVENT_INFORMATION_CLASS class,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (len != sizeof(EVENT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return msync_query_event( handle, info, ret_len );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         return esync_query_event( handle, info, ret_len );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -555,6 +586,9 @@ NTSTATUS WINAPI NtCreateMutant( HANDLE *handle, ACCESS_MASK access, const OBJECT
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     *handle = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return msync_create_mutex( handle, access, attr, owned );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         return esync_create_mutex( handle, access, attr, owned );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -585,6 +619,9 @@ NTSTATUS WINAPI NtOpenMutant( HANDLE *handle, ACCESS_MASK access, const OBJECT_A
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     *handle = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if ((ret = validate_open_object_attributes( attr ))) return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return msync_open_mutex( handle, access, attr );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         return esync_open_mutex( handle, access, attr );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -610,6 +647,9 @@ NTSTATUS WINAPI NtReleaseMutant( HANDLE handle, LONG *prev_count )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     unsigned int ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return msync_release_mutex( handle, prev_count );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         return esync_release_mutex( handle, prev_count );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -643,6 +683,9 @@ NTSTATUS WINAPI NtQueryMutant( HANDLE handle, MUTANT_INFORMATION_CLASS class,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (len != sizeof(MUTANT_BASIC_INFORMATION)) return STATUS_INFO_LENGTH_MISMATCH;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return msync_query_mutex( handle, info, ret_len );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         return esync_query_mutex( handle, info, ret_len );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1566,6 +1609,13 @@ NTSTATUS WINAPI NtWaitForMultipleObjects( DWORD count, const HANDLE *handles, BO
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (!count || count > MAXIMUM_WAIT_OBJECTS) return STATUS_INVALID_PARAMETER_1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        NTSTATUS ret = msync_wait_objects( count, handles, wait_any, alertable, timeout );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (ret != STATUS_NOT_IMPLEMENTED)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         NTSTATUS ret = esync_wait_objects( count, handles, wait_any, alertable, timeout );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1598,6 +1648,9 @@ NTSTATUS WINAPI NtSignalAndWaitForSingleObject( HANDLE signal, HANDLE wait,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     select_op_t select_op;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     UINT flags = SELECT_INTERRUPTIBLE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return msync_signal_and_wait( signal, wait, alertable, timeout );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         return esync_signal_and_wait( signal, wait, alertable, timeout );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1641,7 +1694,24 @@ NTSTATUS WINAPI NtYieldExecution(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ NTSTATUS WINAPI NtDelayExecution( BOOLEAN alertable, const LARGE_INTEGER *timeout )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     /* if alertable, we need to query the server */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-    if (alertable) return server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, timeout );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (alertable)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            NTSTATUS ret = msync_wait_objects( 0, NULL, TRUE, TRUE, timeout );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (ret != STATUS_NOT_IMPLEMENTED)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            NTSTATUS ret = esync_wait_objects( 0, NULL, TRUE, TRUE, timeout );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (ret != STATUS_NOT_IMPLEMENTED)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return server_wait( NULL, 0, SELECT_INTERRUPTIBLE | SELECT_ALERTABLE, timeout );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (!timeout || timeout->QuadPart == TIMEOUT_INFINITE)  /* sleep forever */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index c3a2ac11521..6734df89f7a 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/dlls/ntdll/unix/unix_private.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/dlls/ntdll/unix/unix_private.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -94,6 +94,8 @@ struct ntdll_thread_data
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     void              *cpu_data[16];  /* reserved for CPU-specific data */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     void              *kernel_stack;  /* stack for thread startup and kernel syscalls */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     int                esync_apc_fd;  /* fd to wait on for user APCs */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int               *msync_apc_addr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int       msync_apc_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     int                request_fd;    /* fd for sending server requests */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     int                reply_fd;      /* fd for receiving server replies */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     int                wait_fd[2];    /* fd for sleeping server requests */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 7e386a41858..f6163e51734 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/dlls/ntdll/unix/virtual.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/dlls/ntdll/unix/virtual.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -3693,6 +3693,8 @@ static TEB *init_teb( void *ptr, BOOL is_wow )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     thread_data->esync_apc_fd = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    thread_data->msync_apc_addr = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    thread_data->msync_apc_idx = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     thread_data->request_fd = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     thread_data->reply_fd   = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     thread_data->wait_fd[0] = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/include/wine/server_protocol.h b/include/wine/server_protocol.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 8bedd7d2bbe..a26d6ce6ef7 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/include/wine/server_protocol.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/include/wine/server_protocol.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -5781,6 +5781,92 @@ struct get_esync_apc_fd_reply
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     struct reply_header __header;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++enum msync_type
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    MSYNC_SEMAPHORE = 1,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    MSYNC_AUTO_EVENT,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    MSYNC_MANUAL_EVENT,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    MSYNC_MUTEX,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    MSYNC_AUTO_SERVER,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    MSYNC_MANUAL_SERVER,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    MSYNC_QUEUE,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++struct create_msync_request
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct request_header __header;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int access;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int low;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int high;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int type;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    /* VARARG(objattr,object_attributes); */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    char __pad_28[4];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++struct create_msync_reply
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct reply_header __header;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    obj_handle_t handle;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int type;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    char __pad_20[4];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++struct open_msync_request
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct request_header __header;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int access;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int attributes;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    obj_handle_t rootdir;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int          type;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    /* VARARG(name,unicode_str); */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    char __pad_28[4];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++struct open_msync_reply
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct reply_header __header;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    obj_handle_t handle;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int          type;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    char __pad_20[4];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++struct get_msync_idx_request
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct request_header __header;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    obj_handle_t handle;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++struct get_msync_idx_reply
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct reply_header __header;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int          type;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++struct msync_msgwait_request
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct request_header __header;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int          in_msgwait;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++struct msync_msgwait_reply
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct reply_header __header;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++struct get_msync_apc_idx_request
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct request_header __header;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    char __pad_12[4];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++struct get_msync_apc_idx_reply
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct reply_header __header;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    char __pad_12[4];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ enum request
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -6076,6 +6162,11 @@ enum request
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     REQ_esync_msgwait,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     REQ_set_keyboard_repeat,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     REQ_get_esync_apc_fd,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    REQ_create_msync,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    REQ_open_msync,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    REQ_get_msync_idx,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    REQ_msync_msgwait,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    REQ_get_msync_apc_idx,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     REQ_NB_REQUESTS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -6375,6 +6466,11 @@ union generic_request
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     struct esync_msgwait_request esync_msgwait_request;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     struct set_keyboard_repeat_request set_keyboard_repeat_request;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     struct get_esync_apc_fd_request get_esync_apc_fd_request;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct create_msync_request create_msync_request;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct open_msync_request open_msync_request;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct get_msync_idx_request get_msync_idx_request;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync_msgwait_request msync_msgwait_request;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct get_msync_apc_idx_request get_msync_apc_idx_request;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ union generic_reply
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -6672,11 +6768,16 @@ union generic_reply
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     struct esync_msgwait_reply esync_msgwait_reply;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     struct set_keyboard_repeat_reply set_keyboard_repeat_reply;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     struct get_esync_apc_fd_reply get_esync_apc_fd_reply;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct create_msync_reply create_msync_reply;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct open_msync_reply open_msync_reply;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct get_msync_idx_reply get_msync_idx_reply;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync_msgwait_reply msync_msgwait_reply;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct get_msync_apc_idx_reply get_msync_apc_idx_reply;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* ### protocol_version begin ### */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-#define SERVER_PROTOCOL_VERSION 807
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define SERVER_PROTOCOL_VERSION 808
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* ### protocol_version end ### */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/Makefile.in b/server/Makefile.in
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index b164193ef20..937f8b14953 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/Makefile.in
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/Makefile.in
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -15,6 +15,7 @@ SOURCES = \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   event.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   fd.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   file.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++  msync.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   handle.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   hook.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+   mach.c \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/async.c b/server/async.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index b0f9fe42ad1..b7270394579 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/async.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/async.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -78,6 +78,7 @@ static const struct object_ops async_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,              /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     async_signaled,            /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                      /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                      /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     async_satisfied,           /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                 /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                 /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -688,6 +689,7 @@ static const struct object_ops iosb_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                     /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/atom.c b/server/atom.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index d9824de8eac..d99f10d6f19 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/atom.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/atom.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -80,6 +80,7 @@ static const struct object_ops atom_table_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                         /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                    /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                    /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/change.c b/server/change.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 17a29c02867..84d4b25252b 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/change.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/change.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -113,6 +113,7 @@ static const struct object_ops dir_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,             /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     default_fd_signaled,      /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     default_fd_get_esync_fd,  /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    default_fd_get_msync_idx, /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,             /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     dir_get_fd,               /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/clipboard.c b/server/clipboard.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 8b265f2dcea..e7149f20488 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/clipboard.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/clipboard.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -77,6 +77,7 @@ static const struct object_ops clipboard_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                         /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                    /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                    /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/completion.c b/server/completion.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 3d4be86a212..d761d372314 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/completion.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/completion.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -76,6 +76,7 @@ static const struct object_ops completion_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,              /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     completion_signaled,       /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                      /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                      /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,              /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                 /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                 /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/console.c b/server/console.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index dbd4a97459c..2b023546907 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/console.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/console.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -42,6 +42,7 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "winternl.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "wine/condrv.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "esync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "msync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ struct screen_buffer;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -83,6 +84,7 @@ static const struct object_ops console_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,                     /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     console_signaled,                 /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                             /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                     /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                        /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     console_get_fd,                   /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -142,12 +144,14 @@ struct console_server
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     int                   term_fd;     /* UNIX terminal fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     struct termios        termios;     /* original termios */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     int                   esync_fd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int          msync_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void console_server_dump( struct object *obj, int verbose );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void console_server_destroy( struct object *obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static int console_server_signaled( struct object *obj, struct wait_queue_entry *entry );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static int console_server_get_esync_fd( struct object *obj, enum esync_type *type );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static unsigned int console_server_get_msync_idx( struct object *obj, enum msync_type *type );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static struct fd *console_server_get_fd( struct object *obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static struct object *console_server_lookup_name( struct object *obj, struct unicode_str *name,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                                                 unsigned int attr, struct object *root );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -163,6 +167,7 @@ static const struct object_ops console_server_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,                     /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     console_server_signaled,          /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     console_server_get_esync_fd,      /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    console_server_get_msync_idx,     /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                     /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                        /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     console_server_get_fd,            /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -233,6 +238,7 @@ static const struct object_ops screen_buffer_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                             /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                        /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     screen_buffer_get_fd,             /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -283,6 +289,7 @@ static const struct object_ops console_device_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                             /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                     /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                        /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                        /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -321,6 +328,7 @@ static const struct object_ops console_input_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                             /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                     /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                        /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     console_input_get_fd,             /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -379,6 +387,7 @@ static const struct object_ops console_output_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                             /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                     /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                        /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     console_output_get_fd,            /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -438,6 +447,7 @@ static const struct object_ops console_connection_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                             /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                     /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                        /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     console_connection_get_fd,        /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -600,8 +610,13 @@ static void disconnect_console_server( struct console_server *server )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         list_remove( &call->entry );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         console_host_ioctl_terminate( call, STATUS_CANCELLED );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_clear_shm( server->msync_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         esync_clear( server->esync_fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     while (!list_empty( &server->read_queue ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         struct console_host_ioctl *call = LIST_ENTRY( list_head( &server->read_queue ), struct console_host_ioctl, entry );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -885,6 +900,7 @@ static void console_server_destroy( struct object *obj )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     disconnect_console_server( server );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (server->fd) release_object( server->fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync()) close( server->esync_fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync()) msync_destroy_semaphore( server->msync_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static struct object *console_server_lookup_name( struct object *obj, struct unicode_str *name,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -933,6 +949,13 @@ static int console_server_get_esync_fd( struct object *obj, enum esync_type *typ
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     return server->esync_fd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static unsigned int console_server_get_msync_idx( struct object *obj, enum msync_type *type )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct console_server *server = (struct console_server*)obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    *type = MSYNC_MANUAL_SERVER;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return server->msync_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static struct fd *console_server_get_fd( struct object* obj )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     struct console_server *server = (struct console_server*)obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -966,6 +989,9 @@ static struct object *create_console_server( void )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     allow_fd_caching(server->fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     server->esync_fd = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        server->msync_idx = msync_alloc_shm( 0, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         server->esync_fd = esync_create_fd( 0, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1581,6 +1607,10 @@ DECL_HANDLER(get_next_console_request)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         /* set result of previous ioctl */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         ioctl = LIST_ENTRY( list_head( &server->queue ), struct console_host_ioctl, entry );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         list_remove( &ioctl->entry );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (do_msync() && list_empty( &server->queue ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            msync_clear_shm( server->msync_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         if (do_esync() && list_empty( &server->queue ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             esync_clear( server->esync_fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1668,6 +1698,10 @@ DECL_HANDLER(get_next_console_request)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         set_error( STATUS_PENDING );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync() && list_empty( &server->queue ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_clear_shm( server->msync_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync() && list_empty( &server->queue ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         esync_clear( server->esync_fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/debugger.c b/server/debugger.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index ca04d4c71ce..946dc7b04b5 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/debugger.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/debugger.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -87,6 +87,7 @@ static const struct object_ops debug_event_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,                  /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     debug_event_signaled,          /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                          /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                          /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                  /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                     /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                     /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -116,6 +117,7 @@ static const struct object_ops debug_obj_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,                  /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     debug_obj_signaled,            /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                          /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                          /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                  /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                     /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                     /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/device.c b/server/device.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index c45d0102a56..93e22bbd78a 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/device.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/device.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -39,6 +39,7 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "request.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "process.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "esync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "msync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* IRP object */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -68,6 +69,7 @@ static const struct object_ops irp_call_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                             /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                        /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                        /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -95,11 +97,13 @@ struct device_manager
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     struct irp_call       *current_call;   /* call currently executed on client side */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     struct wine_rb_tree    kernel_objects; /* map of objects that have client side pointer associated */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     int                    esync_fd;       /* esync file descriptor */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int           msync_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void device_manager_dump( struct object *obj, int verbose );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static int device_manager_signaled( struct object *obj, struct wait_queue_entry *entry );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static int device_manager_get_esync_fd( struct object *obj, enum esync_type *type );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static unsigned int device_manager_get_msync_idx( struct object *obj, enum msync_type *type );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void device_manager_destroy( struct object *obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static const struct object_ops device_manager_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -111,6 +115,7 @@ static const struct object_ops device_manager_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,                     /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     device_manager_signaled,          /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     device_manager_get_esync_fd,      /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    device_manager_get_msync_idx,     /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                     /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                        /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                        /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -169,6 +174,7 @@ static const struct object_ops device_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                             /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                     /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                        /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                        /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -222,6 +228,7 @@ static const struct object_ops device_file_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,                     /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     default_fd_signaled,              /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                             /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                     /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                        /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     device_file_get_fd,               /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -754,6 +761,9 @@ static void delete_file( struct device_file *file )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     /* terminate all pending requests */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     LIST_FOR_EACH_ENTRY_SAFE( irp, next, &file->requests, struct irp_call, dev_entry )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (do_msync() && file->device->manager && list_empty( &file->device->manager->requests ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            msync_clear( &file->device->manager->obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         if (do_esync() && file->device->manager && list_empty( &file->device->manager->requests ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             esync_clear( file->device->manager->esync_fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -799,6 +809,13 @@ static int device_manager_get_esync_fd( struct object *obj, enum esync_type *typ
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     return manager->esync_fd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static unsigned int device_manager_get_msync_idx( struct object *obj, enum msync_type *type )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct device_manager *manager = (struct device_manager *)obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    *type = MSYNC_MANUAL_SERVER;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return manager->msync_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void device_manager_destroy( struct object *obj )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     struct device_manager *manager = (struct device_manager *)obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -834,6 +851,9 @@ static void device_manager_destroy( struct object *obj )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         release_object( irp );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_destroy_semaphore( manager->msync_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         close( manager->esync_fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -849,6 +869,9 @@ static struct device_manager *create_device_manager(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         list_init( &manager->requests );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         wine_rb_init( &manager->kernel_objects, compare_kernel_object );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            manager->msync_idx = msync_alloc_shm( 0, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             manager->esync_fd = esync_create_fd( 0, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1041,6 +1064,9 @@ DECL_HANDLER(get_next_device_request)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                 if (irp->file) grab_object( irp );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                 manager->current_call = irp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                if (do_msync() && list_empty( &manager->requests ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                    msync_clear( &manager->obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                 if (do_esync() && list_empty( &manager->requests ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                     esync_clear( manager->esync_fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/directory.c b/server/directory.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index f2b4b409ef6..4d910998cd3 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/directory.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/directory.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -70,6 +70,7 @@ static const struct object_ops object_type_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                         /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                    /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                    /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -121,6 +122,7 @@ static const struct object_ops directory_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                         /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                    /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                    /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/esync.c b/server/esync.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index e193f61b3a7..06e17c01874 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/esync.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/esync.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -49,7 +49,7 @@ int do_esync(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     static int do_esync_cached = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync_cached == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-        do_esync_cached = getenv("WINEESYNC") && atoi(getenv("WINEESYNC"));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        do_esync_cached = getenv("WINEESYNC") && atoi(getenv("WINEESYNC")) && !do_msync();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     return do_esync_cached;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -128,6 +128,7 @@ const struct object_ops esync_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                      /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                      /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     esync_get_esync_fd,        /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                      /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                      /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                 /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                 /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/event.c b/server/event.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index f4ca3e48c6f..2770d83e6d6 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/event.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/event.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -36,6 +36,7 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "request.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "security.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "esync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "msync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static const WCHAR event_name[] = {'E','v','e','n','t'};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -58,12 +59,14 @@ struct event
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     int            manual_reset;    /* is it a manual reset event? */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     int            signaled;        /* event has been signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     int            esync_fd;        /* esync file descriptor */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int   msync_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void event_dump( struct object *obj, int verbose );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static int event_signaled( struct object *obj, struct wait_queue_entry *entry );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void event_satisfied( struct object *obj, struct wait_queue_entry *entry );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static int event_get_esync_fd( struct object *obj, enum esync_type *type );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static unsigned int event_get_msync_idx( struct object *obj, enum msync_type *type );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static int event_signal( struct object *obj, unsigned int access);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static struct list *event_get_kernel_obj_list( struct object *obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void event_destroy( struct object *obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -77,6 +80,7 @@ static const struct object_ops event_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,              /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     event_signaled,            /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     event_get_esync_fd,        /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    event_get_msync_idx,       /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     event_satisfied,           /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     event_signal,              /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                 /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -125,6 +129,7 @@ static const struct object_ops keyed_event_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,                /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     keyed_event_signaled,        /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                        /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                        /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                   /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                   /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -157,6 +162,9 @@ struct event *create_event( struct object *root, const struct unicode_str *name,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             event->manual_reset = manual_reset;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             event->signaled     = initial_state;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                event->msync_idx = msync_alloc_shm( initial_state, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                 event->esync_fd = esync_create_fd( initial_state, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -167,6 +175,10 @@ struct event *create_event( struct object *root, const struct unicode_str *name,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ struct event *get_event_obj( struct process *process, obj_handle_t handle, unsigned int access )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     struct object *obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync() && (obj = get_handle_obj( process, handle, access, &msync_ops)))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return (struct event *)obj; /* even though it's not an event */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync() && (obj = get_handle_obj( process, handle, access, &esync_ops)))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         return (struct event *)obj; /* even though it's not an event */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -179,10 +191,19 @@ static void pulse_event( struct event *event )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     /* wake up all waiters if manual reset, a single one otherwise */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     wake_up( &event->obj, !event->manual_reset );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     event->signaled = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_clear( &event->obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ void set_event( struct event *event )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync() && event->obj.ops == &msync_ops)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_set_event( (struct msync *)event );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync() && event->obj.ops == &esync_ops)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         esync_set_event( (struct esync *)event );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -196,6 +217,12 @@ void set_event( struct event *event )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ void reset_event( struct event *event )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync() && event->obj.ops == &msync_ops)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_reset_event( (struct msync *)event );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync() && event->obj.ops == &esync_ops)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         esync_reset_event( (struct esync *)event );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -203,6 +230,9 @@ void reset_event( struct event *event )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     event->signaled = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_clear( &event->obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         esync_clear( event->esync_fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -229,6 +259,13 @@ static int event_get_esync_fd( struct object *obj, enum esync_type *type )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     return event->esync_fd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static unsigned int event_get_msync_idx( struct object *obj, enum msync_type *type )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct event *event = (struct event *)obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    *type = MSYNC_MANUAL_SERVER;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return event->msync_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void event_satisfied( struct object *obj, struct wait_queue_entry *entry )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     struct event *event = (struct event *)obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -261,6 +298,9 @@ static void event_destroy( struct object *obj )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     struct event *event = (struct event *)obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_destroy_semaphore( event->msync_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         close( event->esync_fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/fd.c b/server/fd.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index b90999aae3c..17132109b8e 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/fd.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/fd.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -98,6 +98,7 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "process.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "request.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "esync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "msync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "winternl.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "winioctl.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -163,6 +164,7 @@ struct fd
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     apc_param_t          comp_key;    /* completion key to set in completion events */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     unsigned int         comp_flags;  /* completion flags */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     int                  esync_fd;    /* esync file descriptor */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int         msync_idx;   /* msync shm index */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void fd_dump( struct object *obj, int verbose );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -177,6 +179,7 @@ static const struct object_ops fd_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                     /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -219,6 +222,7 @@ static const struct object_ops device_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                     /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -260,6 +264,7 @@ static const struct object_ops inode_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                     /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -303,6 +308,7 @@ static const struct object_ops file_lock_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,               /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     file_lock_signaled,         /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                       /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                       /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,               /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                  /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                  /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1652,6 +1658,9 @@ static void fd_destroy( struct object *obj )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         free( fd->unix_name );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_destroy_semaphore( fd->msync_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         close( fd->esync_fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1773,6 +1782,7 @@ static struct fd *alloc_fd_object(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     fd->completion = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     fd->comp_flags = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     fd->esync_fd   = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fd->msync_idx  = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     init_async_queue( &fd->read_q );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     init_async_queue( &fd->write_q );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     init_async_queue( &fd->wait_q );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1782,6 +1792,9 @@ static struct fd *alloc_fd_object(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         fd->esync_fd = esync_create_fd( 1, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        fd->msync_idx = msync_alloc_shm( 1, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if ((fd->poll_index = add_poll_user( fd )) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         release_object( fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1818,14 +1831,19 @@ struct fd *alloc_pseudo_fd( const struct fd_ops *fd_user_ops, struct object *use
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     fd->comp_flags = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     fd->no_fd_status = STATUS_BAD_DEVICE_TYPE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     fd->esync_fd   = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fd->msync_idx  = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     init_async_queue( &fd->read_q );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     init_async_queue( &fd->write_q );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     init_async_queue( &fd->wait_q );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     list_init( &fd->inode_entry );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     list_init( &fd->locks );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        fd->msync_idx = msync_alloc_shm( 0, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         fd->esync_fd = esync_create_fd( 0, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     return fd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -2284,6 +2302,9 @@ void set_fd_signaled( struct fd *fd, int signaled )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     fd->signaled = signaled;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (signaled) wake_up( fd->user, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync() && !signaled)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_clear( fd->user );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync() && !signaled)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         esync_clear( fd->esync_fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -2320,6 +2341,15 @@ int default_fd_get_esync_fd( struct object *obj, enum esync_type *type )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++unsigned int default_fd_get_msync_idx( struct object *obj, enum msync_type *type )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct fd *fd = get_obj_fd( obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int ret = fd->msync_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    *type = MSYNC_MANUAL_SERVER;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    release_object( fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int default_fd_get_poll_events( struct fd *fd )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     int events = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/file.c b/server/file.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 828a21c08c6..017c89bf025 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/file.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/file.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -124,6 +124,7 @@ static const struct object_ops file_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,                 /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     default_fd_signaled,          /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                         /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                 /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                    /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     file_get_fd,                  /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/file.h b/server/file.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index abad355679f..fed41271832 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/file.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/file.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -109,6 +109,7 @@ extern void get_nt_name( struct fd *fd, struct unicode_str *name );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ extern int default_fd_signaled( struct object *obj, struct wait_queue_entry *entry );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ extern int default_fd_get_esync_fd( struct object *obj, enum esync_type *type );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern unsigned int default_fd_get_msync_idx( struct object *obj, enum msync_type *type );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ extern int default_fd_get_poll_events( struct fd *fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ extern void default_poll_event( struct fd *fd, int event );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ extern void fd_cancel_async( struct fd *fd, struct async *async );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/handle.c b/server/handle.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 7fc24d12a34..0d3e1f74655 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/handle.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/handle.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -127,6 +127,7 @@ static const struct object_ops handle_table_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                            /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                            /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                            /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                            /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                            /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                       /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                       /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/hook.c b/server/hook.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 260d59fa8d2..b17813c4df6 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/hook.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/hook.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -81,6 +81,7 @@ static const struct object_ops hook_table_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                         /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                    /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                    /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/mailslot.c b/server/mailslot.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 4cf9b73f784..d04fc2f4edc 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/mailslot.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/mailslot.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -75,6 +75,7 @@ static const struct object_ops mailslot_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,              /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     default_fd_signaled,       /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                      /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                      /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,              /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                 /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     mailslot_get_fd,           /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -135,6 +136,7 @@ static const struct object_ops mail_writer_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                       /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                       /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                       /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                       /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                       /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                  /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     mail_writer_get_fd,         /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -199,6 +201,7 @@ static const struct object_ops mailslot_device_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                           /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                           /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                           /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                           /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                   /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                      /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                      /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -230,6 +233,7 @@ static const struct object_ops mailslot_device_file_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,                           /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     default_fd_signaled,                    /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                                   /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                                   /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                           /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                              /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     mailslot_device_file_get_fd,            /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/main.c b/server/main.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 5062d0999fa..d5a8c05cb86 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/main.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/main.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -35,6 +35,7 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "request.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "unicode.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "esync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "msync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* command-line options */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ int debug_level = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -230,9 +231,15 @@ int main( int argc, char *argv[] )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     sock_init();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     open_master_socket();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_init();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         esync_init();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!do_msync() && !do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        fprintf( stderr, "wineserver: using server-side synchronization.\n" );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (debug_level) fprintf( stderr, "wineserver: starting (pid=%ld)\n", (long) getpid() );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     set_current_time();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     init_scheduler();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/mapping.c b/server/mapping.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 2681475173b..b2c5a2b4196 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/mapping.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/mapping.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -68,6 +68,7 @@ static const struct object_ops ranges_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                      /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                      /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                      /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                      /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                      /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                 /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                 /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -105,6 +106,7 @@ static const struct object_ops shared_map_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                      /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                      /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                      /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                      /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                      /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                 /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                 /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -179,6 +181,7 @@ static const struct object_ops mapping_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                        /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                        /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                        /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                        /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                        /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                   /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     mapping_get_fd,              /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/msync.c b/server/msync.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+new file mode 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 00000000000..b6e98cbffbe
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/msync.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -0,0 +1,992 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * mach semaphore-based synchronization objects
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * Copyright (C) 2018 Zebediah Figura
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * Copyright (C) 2023 Marc-Aurel Zent
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * This library is free software; you can redistribute it and/or
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * modify it under the terms of the GNU Lesser General Public
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * License as published by the Free Software Foundation; either
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * version 2.1 of the License, or (at your option) any later version.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * This library is distributed in the hope that it will be useful,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * Lesser General Public License for more details.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * You should have received a copy of the GNU Lesser General Public
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * License along with this library; if not, write to the Free Software
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "config.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <errno.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <fcntl.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <limits.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <stdio.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <stdarg.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <sys/mman.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef HAVE_SYS_STAT_H
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# include <sys/stat.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef __APPLE__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# include <mach/mach_init.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# include <mach/mach_port.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# include <mach/message.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# include <mach/port.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# include <mach/task.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# include <mach/semaphore.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# include <mach/mach_error.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# include <mach/thread_act.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# include <servers/bootstrap.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <sched.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <dlfcn.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <signal.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <pthread.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include <unistd.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "ntstatus.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define WIN32_NO_STATUS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "windef.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "winternl.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "handle.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "request.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "msync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * We need to set the maximum allowed shared memory size early, since on
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * XNU it is not possible to call ftruncate() more than once...
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * This isn't a problem in practice since it is lazily allocated.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define MAX_INDEX 0x100000
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef __APPLE__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define UL_COMPARE_AND_WAIT_SHARED  0x3
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define ULF_WAKE_ALL                0x00000100
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern int __ulock_wake( uint32_t operation, void *addr, uint64_t wake_value );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define MACH_CHECK_ERROR(ret, operation) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (ret != KERN_SUCCESS) \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        fprintf(stderr, "msync: error: %s failed with %d: %s\n", \
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            operation, ret, mach_error_string(ret));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/* Private API to register a mach port with the bootstrap server */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern kern_return_t bootstrap_register2( mach_port_t bp, name_t service_name, mach_port_t sp, int flags );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * Faster to directly do the syscall and inline everything, taken and slightly adapted
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * from xnu/libsyscall/mach/mach_msg.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define LIBMACH_OPTIONS64 (MACH_SEND_INTERRUPT|MACH_RCV_INTERRUPT)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define MACH64_SEND_MQ_CALL 0x0000000400000000ull
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++typedef mach_msg_return_t (*mach_msg2_trap_ptr_t)( void *data, uint64_t options,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    uint64_t msgh_bits_and_send_size, uint64_t msgh_remote_and_local_port,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    uint64_t msgh_voucher_and_id, uint64_t desc_count_and_rcv_name,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    uint64_t rcv_size_and_priority, uint64_t timeout );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static mach_msg2_trap_ptr_t mach_msg2_trap;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline mach_msg_return_t mach_msg2_internal( void *data, uint64_t option64, uint64_t msgh_bits_and_send_size,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    uint64_t msgh_remote_and_local_port, uint64_t msgh_voucher_and_id, uint64_t desc_count_and_rcv_name,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    uint64_t rcv_size_and_priority, uint64_t timeout)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg_return_t mr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mr = mach_msg2_trap( data, option64 & ~LIBMACH_OPTIONS64, msgh_bits_and_send_size,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++             msgh_remote_and_local_port, msgh_voucher_and_id, desc_count_and_rcv_name,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++             rcv_size_and_priority, timeout );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (mr == MACH_MSG_SUCCESS)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return MACH_MSG_SUCCESS;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    while (mr == MACH_SEND_INTERRUPTED)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        mr = mach_msg2_trap( data, option64 & ~LIBMACH_OPTIONS64, msgh_bits_and_send_size,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                 msgh_remote_and_local_port, msgh_voucher_and_id, desc_count_and_rcv_name,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                 rcv_size_and_priority, timeout );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    while (mr == MACH_RCV_INTERRUPTED)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        mr = mach_msg2_trap( data, option64 & ~LIBMACH_OPTIONS64, msgh_bits_and_send_size & 0xffffffffull,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                 msgh_remote_and_local_port, msgh_voucher_and_id, desc_count_and_rcv_name,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                 rcv_size_and_priority, timeout);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return mr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/* For older versions of macOS we need to provide fallback in case there is no mach_msg2... */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern mach_msg_return_t mach_msg_trap( mach_msg_header_t *msg, mach_msg_option_t option,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        mach_msg_size_t send_size, mach_msg_size_t rcv_size, mach_port_name_t rcv_name, mach_msg_timeout_t timeout,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        mach_port_name_t notify );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline mach_msg_return_t mach_msg2( mach_msg_header_t *data, uint64_t option64,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg_size_t send_size, mach_msg_size_t rcv_size, mach_port_t rcv_name, uint64_t timeout,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    uint32_t priority)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg_base_t *base;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg_size_t descriptors;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!mach_msg2_trap)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return mach_msg_trap( data, (mach_msg_option_t)option64, send_size,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                              rcv_size, rcv_name, timeout, priority );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    base = (mach_msg_base_t *)data;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if ((option64 & MACH_SEND_MSG) &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        (base->header.msgh_bits & MACH_MSGH_BITS_COMPLEX))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        descriptors = base->body.msgh_descriptor_count;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        descriptors = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define MACH_MSG2_SHIFT_ARGS(lo, hi) ((uint64_t)hi << 32 | (uint32_t)lo)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return mach_msg2_internal(data, option64 | MACH64_SEND_MQ_CALL,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++               MACH_MSG2_SHIFT_ARGS(data->msgh_bits, send_size),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++               MACH_MSG2_SHIFT_ARGS(data->msgh_remote_port, data->msgh_local_port),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++               MACH_MSG2_SHIFT_ARGS(data->msgh_voucher_port, data->msgh_id),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++               MACH_MSG2_SHIFT_ARGS(descriptors, rcv_name),
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++               MACH_MSG2_SHIFT_ARGS(rcv_size, priority), timeout);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#undef MACH_MSG2_SHIFT_ARGS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static mach_port_name_t receive_port;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++struct sem_node
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct sem_node *next;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    semaphore_t sem;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int tid;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#define MAX_POOL_NODES 0x80000
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++struct node_memory_pool
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct sem_node *nodes;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct sem_node **free_nodes;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int count;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static struct node_memory_pool *pool;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void pool_init(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int i;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    pool = malloc( sizeof(struct node_memory_pool) );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    pool->nodes = malloc( MAX_POOL_NODES * sizeof(struct sem_node) );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    pool->free_nodes = malloc( MAX_POOL_NODES * sizeof(struct sem_node *) );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    pool->count = MAX_POOL_NODES;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    for (i = 0; i < MAX_POOL_NODES; i++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        pool->free_nodes[i] = &pool->nodes[i];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline struct sem_node *pool_alloc(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (pool->count == 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        fprintf( stderr, "msync: warn: node memory pool exhausted\n" );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return malloc( sizeof(struct sem_node) );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return pool->free_nodes[--pool->count];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline void pool_free( struct sem_node *node )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (node < pool->nodes || node >= pool->nodes + MAX_POOL_NODES)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        free(node);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    pool->free_nodes[pool->count++] = node;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++struct sem_list
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct sem_node *head;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static struct sem_list mach_semaphore_map[MAX_INDEX];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline void add_sem( unsigned int shm_idx, semaphore_t sem, int tid )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct sem_node *new_node;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct sem_list *list = mach_semaphore_map + shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    new_node = pool_alloc();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    new_node->sem = sem;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    new_node->tid = tid;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    new_node->next = list->head;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    list->head = new_node;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline void remove_sem( unsigned int shm_idx, int tid )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct sem_node *current, *prev = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct sem_list *list = mach_semaphore_map + shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    current = list->head;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    while (current != NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (current->tid == tid)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (prev == NULL)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                list->head = current->next;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                prev->next = current->next;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            pool_free(current);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        prev = current;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        current = current->next;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void *get_shm( unsigned int idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline void destroy_all_internal( unsigned int shm_idx )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct sem_node *current, *temp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct sem_list *list = mach_semaphore_map + shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int *shm = get_shm( shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    __atomic_store_n( shm + 2, 0, __ATOMIC_SEQ_CST );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    __atomic_store_n( shm + 3, 0, __ATOMIC_SEQ_CST );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    __ulock_wake( UL_COMPARE_AND_WAIT_SHARED | ULF_WAKE_ALL, (void *)shm, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    current = list->head;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    list->head = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    while (current)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        semaphore_destroy( mach_task_self(), current->sem );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        temp = current;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        current = current->next;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        pool_free(temp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline void signal_all_internal( unsigned int shm_idx )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct sem_node *current, *temp;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct sem_list *list = mach_semaphore_map + shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    current = list->head;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    list->head = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    while (current)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        semaphore_signal( current->sem );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        semaphore_destroy( mach_task_self(), current->sem );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        temp = current;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        current = current->next;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        pool_free(temp);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * thread-safe sequentially consistent guarantees relative to register/unregister
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * client-side are made by the mach messaging queue
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline mach_msg_return_t destroy_all( unsigned int shm_idx )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    static mach_msg_header_t send_header;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    send_header.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    send_header.msgh_id = shm_idx | (1 << 28);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    send_header.msgh_size = sizeof(send_header);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    send_header.msgh_remote_port = receive_port;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return mach_msg2( &send_header, MACH_SEND_MSG, send_header.msgh_size,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, 0);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline mach_msg_return_t signal_all( unsigned int shm_idx, int *shm )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    static mach_msg_header_t send_header;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    __ulock_wake( UL_COMPARE_AND_WAIT_SHARED | ULF_WAKE_ALL, (void *)shm, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!__atomic_load_n( shm + 3, __ATOMIC_ACQUIRE ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return MACH_MSG_SUCCESS;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    send_header.msgh_bits = MACH_MSGH_BITS_REMOTE(MACH_MSG_TYPE_COPY_SEND);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    send_header.msgh_id = shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    send_header.msgh_size = sizeof(send_header);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    send_header.msgh_remote_port = receive_port;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return mach_msg2( &send_header, MACH_SEND_MSG, send_header.msgh_size,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                0, MACH_PORT_NULL, MACH_MSG_TIMEOUT_NONE, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++typedef struct
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg_header_t header;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg_body_t body;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg_port_descriptor_t descriptor;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int shm_idx[MAXIMUM_WAIT_OBJECTS + 1];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg_trailer_t trailer;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++} mach_register_message_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++typedef struct
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg_header_t header;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int shm_idx[MAXIMUM_WAIT_OBJECTS + 1];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg_trailer_t trailer;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++} mach_unregister_message_t;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline mach_msg_return_t receive_mach_msg( mach_register_message_t *buffer )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return mach_msg2( (mach_msg_header_t *)buffer, MACH_RCV_MSG, 0,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            sizeof(*buffer), receive_port, MACH_MSG_TIMEOUT_NONE, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline void decode_msgh_id( unsigned int msgh_id, unsigned int *tid, unsigned int *count )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    *tid = msgh_id >> 8;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    *count = msgh_id & 0xFF;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static inline unsigned int check_bit_29( unsigned int *shm_idx )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int bit_29 = (*shm_idx >> 28) & 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    *shm_idx &= ~(1 << 28);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return bit_29;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void *mach_message_pump( void *args )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int i, val;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int tid, count, is_mutex;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int *addr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg_return_t mr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    semaphore_t sem;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_register_message_t receive_message = { 0 };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_unregister_message_t *mach_unregister_message;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    sigset_t set;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    sigfillset( &set );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    pthread_sigmask( SIG_BLOCK, &set, NULL );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    for (;;)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        mr = receive_mach_msg( &receive_message );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (mr != MACH_MSG_SUCCESS)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            fprintf( stderr, "msync: failed to receive message\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * A message with no body is a signal_all or destroy_all operation where the shm_idx
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * is the msgh_id and the type of operation is decided by the 20th bit.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * (The shared memory index is only a 28-bit integer at max)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * See signal_all( unsigned int shm_idx ) and destroy_all( unsigned int shm_idx )above.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (receive_message.header.msgh_size == sizeof(mach_msg_header_t))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (check_bit_29( (unsigned int *)&receive_message.header.msgh_id ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                destroy_all_internal( receive_message.header.msgh_id );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                signal_all_internal( receive_message.header.msgh_id );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * A message with a body which is not complex means this is a
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * server_remove_wait operation
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        decode_msgh_id( receive_message.header.msgh_id, &tid, &count );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (!MACH_MSGH_BITS_IS_COMPLEX(receive_message.header.msgh_bits))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            mach_unregister_message = (mach_unregister_message_t *)&receive_message;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            for (i = 0; i < count; i++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                remove_sem( mach_unregister_message->shm_idx[i], tid );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        /*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         * Finally server_register_wait
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++         */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        sem = receive_message.descriptor.name;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        for (i = 0; i < count; i++)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            is_mutex = check_bit_29( receive_message.shm_idx + i );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            addr = (int *)get_shm( receive_message.shm_idx[i] );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            val = __atomic_load_n( addr, __ATOMIC_SEQ_CST );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if ((is_mutex && (val == 0 || val == ~0 || val == tid)) || (!is_mutex && val != 0)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                || !__atomic_load_n( addr + 2, __ATOMIC_SEQ_CST ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                /* The client had a TOCTTOU we need to fix */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                semaphore_signal( sem );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                semaphore_destroy( mach_task_self(), sem );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                continue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            add_sem( receive_message.shm_idx[i], sem, tid );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++int do_msync(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef __APPLE__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    static int do_msync_cached = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync_cached == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        do_msync_cached = getenv("WINEMSYNC") && atoi(getenv("WINEMSYNC"));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return do_msync_cached;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static char shm_name[29];
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static int shm_fd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static const off_t shm_size = MAX_INDEX * 16;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void **shm_addrs;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static int shm_addrs_size;  /* length of the allocated shm_addrs array */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static long pagesize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static pthread_t message_thread;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static int is_msync_initialized;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void cleanup(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    close( shm_fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (shm_unlink( shm_name ) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        perror( "shm_unlink" );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void set_thread_policy_qos( mach_port_t mach_thread_id )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    thread_extended_policy_data_t extended_policy;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    thread_precedence_policy_data_t precedence_policy;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int throughput_qos, latency_qos;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    kern_return_t kr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    latency_qos = LATENCY_QOS_TIER_0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    kr = thread_policy_set( mach_thread_id, THREAD_LATENCY_QOS_POLICY,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            (thread_policy_t)&latency_qos,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            THREAD_LATENCY_QOS_POLICY_COUNT);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (kr != KERN_SUCCESS)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        fprintf( stderr, "msync: error setting thread latency QoS.\n" );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    throughput_qos = THROUGHPUT_QOS_TIER_0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    kr = thread_policy_set( mach_thread_id, THREAD_THROUGHPUT_QOS_POLICY,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            (thread_policy_t)&throughput_qos,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            THREAD_THROUGHPUT_QOS_POLICY_COUNT);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (kr != KERN_SUCCESS)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        fprintf( stderr, "msync: error setting thread throughput QoS.\n" );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    extended_policy.timeshare = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    kr = thread_policy_set( mach_thread_id, THREAD_EXTENDED_POLICY,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            (thread_policy_t)&extended_policy,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            THREAD_EXTENDED_POLICY_COUNT );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (kr != KERN_SUCCESS)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        fprintf( stderr, "msync: error setting extended policy\n" );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    precedence_policy.importance = 63;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    kr = thread_policy_set( mach_thread_id, THREAD_PRECEDENCE_POLICY,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            (thread_policy_t)&precedence_policy,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                            THREAD_PRECEDENCE_POLICY_COUNT );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (kr != KERN_SUCCESS)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        fprintf( stderr, "msync: error setting precedence policy\n" );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++void msync_init(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef __APPLE__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct stat st;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_port_t bootstrap_port;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_port_limits_t limits;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    void *dlhandle = dlopen( NULL, RTLD_NOW );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int *shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (fstat( config_dir_fd, &st ) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        fatal_error( "cannot stat config dir\n" );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (st.st_ino != (unsigned long)st.st_ino)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        sprintf( shm_name, "/wine-%lx%08lx-msync", (unsigned long)((unsigned long long)st.st_ino >> 32), (unsigned long)st.st_ino );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        sprintf( shm_name, "/wine-%lx-msync", (unsigned long)st.st_ino );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!shm_unlink( shm_name ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        fprintf( stderr, "msync: warning: a previous shm file %s was not properly removed\n", shm_name );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    shm_fd = shm_open( shm_name, O_RDWR | O_CREAT | O_EXCL, 0644 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (shm_fd == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        perror( "shm_open" );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    pagesize = sysconf( _SC_PAGESIZE );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    shm_addrs = calloc( 128, sizeof(shm_addrs[0]) );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    shm_addrs_size = 128;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (ftruncate( shm_fd, shm_size ) == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        perror( "ftruncate" );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        fatal_error( "could not initialize shared memory\n" );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    shm = get_shm( 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    __atomic_store_n( shm + 2, 1, __ATOMIC_SEQ_CST );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    /* Bootstrap mach server message pump */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    mach_msg2_trap = (mach_msg2_trap_ptr_t)dlsym( dlhandle, "mach_msg2_trap" );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!mach_msg2_trap)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        fprintf( stderr, "msync: warning: using mach_msg_overwrite instead of mach_msg2\n");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    dlclose( dlhandle );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    MACH_CHECK_ERROR(mach_port_allocate(mach_task_self(), MACH_PORT_RIGHT_RECEIVE, &receive_port), "mach_port_allocate");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    MACH_CHECK_ERROR(mach_port_insert_right(mach_task_self(), receive_port, receive_port, MACH_MSG_TYPE_MAKE_SEND), "mach_port_insert_right");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    limits.mpl_qlimit = 50;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (getenv("WINEMSYNC_QLIMIT"))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        limits.mpl_qlimit = atoi(getenv("WINEMSYNC_QLIMIT"));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    MACH_CHECK_ERROR(mach_port_set_attributes( mach_task_self(), receive_port, MACH_PORT_LIMITS_INFO,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                                        (mach_port_info_t)&limits, MACH_PORT_LIMITS_INFO_COUNT), "mach_port_set_attributes");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    MACH_CHECK_ERROR(task_get_special_port(mach_task_self(), TASK_BOOTSTRAP_PORT, &bootstrap_port), "task_get_special_port");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    MACH_CHECK_ERROR(bootstrap_register2(bootstrap_port, shm_name + 1, receive_port, 0), "bootstrap_register2");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    pool_init();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (pthread_create( &message_thread, NULL, mach_message_pump, NULL ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        perror("pthread_create");
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        fatal_error( "could not create mach message pump thread\n" );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    set_thread_policy_qos( pthread_mach_thread_np( message_thread )) ;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fprintf( stderr, "msync: bootstrapped mach port on %s.\n", shm_name + 1 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    is_msync_initialized = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fprintf( stderr, "msync: up and running.\n" );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    atexit( cleanup );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static struct list mutex_list = LIST_INIT(mutex_list);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++struct msync
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct object  obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int   shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    enum msync_type type;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct list     mutex_entry;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void msync_dump( struct object *obj, int verbose );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static unsigned int msync_get_msync_idx( struct object *obj, enum msync_type *type );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static unsigned int msync_map_access( struct object *obj, unsigned int access );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void msync_destroy( struct object *obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++const struct object_ops msync_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    sizeof(struct msync),      /* size */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    &no_type,                  /* type */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    msync_dump,                /* dump */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    no_add_queue,              /* add_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                      /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                      /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                      /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    msync_get_msync_idx,       /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                      /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    no_signal,                 /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    no_get_fd,                 /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    msync_map_access,          /* map_access */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    default_get_sd,            /* get_sd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    default_set_sd,            /* set_sd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    no_get_full_name,          /* get_full_name */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    no_lookup_name,            /* lookup_name */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    directory_link_name,       /* link_name */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    default_unlink_name,       /* unlink_name */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    no_open_file,              /* open_file */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    no_kernel_obj_list,        /* get_kernel_obj_list */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    no_close_handle,           /* close_handle */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    msync_destroy              /* destroy */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void msync_dump( struct object *obj, int verbose )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync *msync = (struct msync *)obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    assert( obj->ops == &msync_ops );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fprintf( stderr, "msync idx=%d\n", msync->shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static unsigned int msync_get_msync_idx( struct object *obj, enum msync_type *type)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync *msync = (struct msync *)obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    *type = msync->type;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return msync->shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static unsigned int msync_map_access( struct object *obj, unsigned int access )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    /* Sync objects have the same flags. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (access & GENERIC_READ)    access |= STANDARD_RIGHTS_READ | EVENT_QUERY_STATE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (access & GENERIC_WRITE)   access |= STANDARD_RIGHTS_WRITE | EVENT_MODIFY_STATE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (access & GENERIC_EXECUTE) access |= STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (access & GENERIC_ALL)     access |= STANDARD_RIGHTS_ALL | EVENT_QUERY_STATE | EVENT_MODIFY_STATE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return access & ~(GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void msync_destroy( struct object *obj )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync *msync = (struct msync *)obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (msync->type == MSYNC_MUTEX)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        list_remove( &msync->mutex_entry );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef __APPLE__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    msync_destroy_semaphore( msync->shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void *get_shm( unsigned int idx )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int entry  = (idx * 16) / pagesize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int offset = (idx * 16) % pagesize;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (entry >= shm_addrs_size)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        int new_size = max(shm_addrs_size * 2, entry + 1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (!(shm_addrs = realloc( shm_addrs, new_size * sizeof(shm_addrs[0]) )))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            fprintf( stderr, "msync: couldn't expand shm_addrs array to size %d\n", entry + 1 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        memset( shm_addrs + shm_addrs_size, 0, (new_size - shm_addrs_size) * sizeof(shm_addrs[0]) );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        shm_addrs_size = new_size;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!shm_addrs[entry])
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        void *addr = mmap( NULL, pagesize, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, entry * pagesize );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (addr == (void *)-1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            fprintf( stderr, "msync: failed to map page %d (offset %#lx): ", entry, entry * pagesize );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            perror( "mmap" );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (debug_level)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            fprintf( stderr, "msync: Mapping page %d at %p.\n", entry, addr );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (__sync_val_compare_and_swap( &shm_addrs[entry], 0, addr ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            munmap( addr, pagesize ); /* someone beat us to it */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            memset( addr, 0, pagesize );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return (void *)((unsigned long)shm_addrs[entry] + offset);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static unsigned int shm_idx_counter = 1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++unsigned int msync_alloc_shm( int low, int high )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef __APPLE__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int shm_idx, tries = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int *shm;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    /* this is arguably a bit of a hack, but we need some way to prevent
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++     * allocating shm for the master socket */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!is_msync_initialized)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    shm_idx = shm_idx_counter;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    for(;;)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        shm = get_shm( shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (!__atomic_load_n( shm + 2, __ATOMIC_SEQ_CST ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            break;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        shm_idx = (shm_idx + 1) % MAX_INDEX;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (tries++ > MAX_INDEX)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            /* The ftruncate call can only be successfully done with a non-zero length
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++             * once per shared memory region with XNU. We need to terminate now.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++             * Also, we initialized with more than what is reasonable anyways... */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            fatal_error( "too many msync objects\n" );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    __atomic_store_n( shm + 2, 1, __ATOMIC_SEQ_CST );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    assert(mach_semaphore_map[shm_idx].head == NULL);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    shm_idx_counter = (shm_idx + 1) % MAX_INDEX;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    assert(shm);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    shm[0] = low;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    shm[1] = high;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static int type_matches( enum msync_type type1, enum msync_type type2 )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return (type1 == type2) ||
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++           ((type1 == MSYNC_AUTO_EVENT || type1 == MSYNC_MANUAL_EVENT) &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            (type2 == MSYNC_AUTO_EVENT || type2 == MSYNC_MANUAL_EVENT));
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++struct msync *create_msync( struct object *root, const struct unicode_str *name,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int attr, int low, int high, enum msync_type type,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    const struct security_descriptor *sd )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef __APPLE__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync *msync;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if ((msync = create_named_object( root, &msync_ops, name, attr, sd )))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (get_error() != STATUS_OBJECT_NAME_EXISTS)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            /* initialize it if it didn't already exist */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            /* Initialize the shared memory portion. We want to do this on the
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++             * server side to avoid a potential though unlikely race whereby
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++             * the same object is opened and used between the time it's created
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++             * and the time its shared memory portion is initialized. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            msync->shm_idx = msync_alloc_shm( low, high );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            msync->type = type;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (type == MSYNC_MUTEX)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                list_add_tail( &mutex_list, &msync->mutex_entry );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            /* validate the type */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (!type_matches( type, msync->type ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                release_object( &msync->obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                set_error( STATUS_OBJECT_TYPE_MISMATCH );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                return NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return msync;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    set_error( STATUS_NOT_IMPLEMENTED );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/* shm layout for events or event-like objects. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++struct msync_event
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int signaled;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int unused;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++void msync_signal_all( unsigned int shm_idx )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync_event *event;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (debug_level)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        fprintf( stderr, "msync_signal_all: index %u\n", shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!shm_idx)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    event = get_shm( shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!__atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        signal_all( shm_idx, (int *)event );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++void msync_wake_up( struct object *obj )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    enum msync_type type;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (debug_level)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        fprintf( stderr, "msync_wake_up: object %p\n", obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (obj->ops->get_msync_idx)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_signal_all( obj->ops->get_msync_idx( obj, &type ) );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++void msync_destroy_semaphore( unsigned int shm_idx )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!shm_idx) return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    destroy_all( shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++void msync_clear_shm( unsigned int shm_idx )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync_event *event;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (debug_level)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        fprintf( stderr, "msync_clear_shm: index %u\n", shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!shm_idx)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    event = get_shm( shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    __atomic_store_n( &event->signaled, 0, __ATOMIC_SEQ_CST );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++void msync_clear( struct object *obj )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    enum msync_type type;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (debug_level)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        fprintf( stderr, "msync_clear: object %p\n", obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (obj->ops->get_msync_idx)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_clear_shm( obj->ops->get_msync_idx( obj, &type ) );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++void msync_set_event( struct msync *msync )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync_event *event = get_shm( msync->shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    assert( msync->obj.ops == &msync_ops );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!__atomic_exchange_n( &event->signaled, 1, __ATOMIC_SEQ_CST ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        signal_all( msync->shm_idx, (int *)event );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++void msync_reset_event( struct msync *msync )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync_event *event = get_shm( msync->shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    assert( msync->obj.ops == &msync_ops );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    __atomic_store_n( &event->signaled, 0, __ATOMIC_SEQ_CST );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++struct mutex
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int tid;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int count;  /* recursion count */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++void msync_abandon_mutexes( struct thread *thread )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync *msync;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    LIST_FOR_EACH_ENTRY( msync, &mutex_list, struct msync, mutex_entry )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        struct mutex *mutex = get_shm( msync->shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (mutex->tid == thread->id)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (debug_level)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                fprintf( stderr, "msync_abandon_mutexes() idx=%d\n", msync->shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            mutex->tid = ~0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            mutex->count = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            signal_all ( msync->shm_idx, (int *)mutex );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++DECL_HANDLER(create_msync)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msync *msync;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct unicode_str name;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct object *root;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    const struct security_descriptor *sd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    const struct object_attributes *objattr = get_req_object_attributes( &sd, &name, &root );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        set_error( STATUS_NOT_IMPLEMENTED );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!objattr) return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if ((msync = create_msync( root, &name, objattr->attributes, req->low,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                               req->high, req->type, sd )))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (get_error() == STATUS_OBJECT_NAME_EXISTS)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            reply->handle = alloc_handle( current->process, msync, req->access, objattr->attributes );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            reply->handle = alloc_handle_no_access_check( current->process, msync,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                                                          req->access, objattr->attributes );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        reply->shm_idx = msync->shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        reply->type = msync->type;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        release_object( msync );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (root) release_object( root );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++DECL_HANDLER(open_msync)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct unicode_str name = get_req_unicode_str();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    reply->handle = open_object( current->process, req->rootdir, req->access,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                                 &msync_ops, &name, req->attributes );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (reply->handle)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        struct msync *msync;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (!(msync = (struct msync *)get_handle_obj( current->process, reply->handle,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                                                      0, &msync_ops )))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (!type_matches( req->type, msync->type ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            set_error( STATUS_OBJECT_TYPE_MISMATCH );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            release_object( msync );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        reply->type = msync->type;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        reply->shm_idx = msync->shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        release_object( msync );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/* Retrieve the index of a shm section which will be signaled by the server. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++DECL_HANDLER(get_msync_idx)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct object *obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    enum msync_type type;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!(obj = get_handle_obj( current->process, req->handle, SYNCHRONIZE, NULL )))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (obj->ops->get_msync_idx)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        reply->shm_idx = obj->ops->get_msync_idx( obj, &type );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        reply->type = type;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (debug_level)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            fprintf( stderr, "%04x: msync: can't wait on object: ", current->id );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            obj->ops->dump( obj, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        set_error( STATUS_NOT_IMPLEMENTED );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    release_object( obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++DECL_HANDLER(get_msync_apc_idx)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    reply->shm_idx = current->msync_apc_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/msync.h b/server/msync.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+new file mode 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 00000000000..000aa48c53d
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/msync.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -0,0 +1,36 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/*
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * mach semaphore-based synchronization objects
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * Copyright (C) 2018 Zebediah Figura
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * Copyright (C) 2023 Marc-Aurel Zent
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * This library is free software; you can redistribute it and/or
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * modify it under the terms of the GNU Lesser General Public
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * License as published by the Free Software Foundation; either
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * version 2.1 of the License, or (at your option) any later version.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * This library is distributed in the hope that it will be useful,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * Lesser General Public License for more details.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ *
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * You should have received a copy of the GNU Lesser General Public
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * License along with this library; if not, write to the Free Software
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++ */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern int do_msync(void);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern void msync_init(void);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern unsigned int msync_alloc_shm( int low, int high );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern void msync_signal_all( unsigned int shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern void msync_clear_shm( unsigned int shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern void msync_destroy_semaphore( unsigned int shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern void msync_wake_up( struct object *obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern void msync_clear( struct object *obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++struct msync;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern const struct object_ops msync_ops;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern void msync_set_event( struct msync *msync );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern void msync_reset_event( struct msync *msync );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++extern void msync_abandon_mutexes( struct thread *thread );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/mutex.c b/server/mutex.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 4785a830e92..6a60adee0bd 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/mutex.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/mutex.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -74,6 +74,7 @@ static const struct object_ops mutex_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,              /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     mutex_signaled,            /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                      /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                      /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     mutex_satisfied,           /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     mutex_signal,              /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                 /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/named_pipe.c b/server/named_pipe.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index a90ec606226..d8d17fa95f7 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/named_pipe.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/named_pipe.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -120,6 +120,7 @@ static const struct object_ops named_pipe_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                         /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                    /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                    /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -169,6 +170,7 @@ static const struct object_ops pipe_server_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,                 /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     default_fd_signaled,          /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     default_fd_get_esync_fd,      /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    default_fd_get_msync_idx,     /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                 /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                    /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     pipe_end_get_fd,              /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -214,6 +216,7 @@ static const struct object_ops pipe_client_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,                 /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     default_fd_signaled,          /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     default_fd_get_esync_fd,      /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    default_fd_get_msync_idx,     /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                 /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                    /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     pipe_end_get_fd,              /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -262,6 +265,7 @@ static const struct object_ops named_pipe_device_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                             /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                             /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                     /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                        /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                        /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -294,6 +298,7 @@ static const struct object_ops named_pipe_device_file_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,                            /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     default_fd_signaled,                     /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                                    /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                                    /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                            /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                               /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     named_pipe_device_file_get_fd,           /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/object.h b/server/object.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 6f4bca834d2..3e535d01344 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/object.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/object.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -80,6 +80,8 @@ struct object_ops
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     int  (*signaled)(struct object *,struct wait_queue_entry *);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     /* return the esync fd for this object */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     int (*get_esync_fd)(struct object *, enum esync_type *type);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    /* return the msync shm idx for this object */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int (*get_msync_idx)(struct object *, enum msync_type *type);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     /* wait satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     void (*satisfied)(struct object *,struct wait_queue_entry *);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     /* signal an object */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/process.c b/server/process.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index ce34f46166a..93bcd822b38 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/process.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/process.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -64,6 +64,7 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "user.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "security.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "esync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "msync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* process object */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -97,6 +98,7 @@ static void process_poll_event( struct fd *fd, int event );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static struct list *process_get_kernel_obj_list( struct object *obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void process_destroy( struct object *obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static int process_get_esync_fd( struct object *obj, enum esync_type *type );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static unsigned int process_get_msync_idx( struct object *obj, enum msync_type *type );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void terminate_process( struct process *process, struct thread *skip, int exit_code );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static const struct object_ops process_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -108,6 +110,7 @@ static const struct object_ops process_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,                /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     process_signaled,            /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     process_get_esync_fd,        /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    process_get_msync_idx,       /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                   /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                   /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -160,6 +163,7 @@ static const struct object_ops startup_info_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,                  /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     startup_info_signaled,         /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                          /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                          /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                  /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                     /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                     /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -222,6 +226,7 @@ static const struct object_ops job_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,                  /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     job_signaled,                  /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                          /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                          /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                  /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                     /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                     /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -691,6 +696,7 @@ struct process *create_process( int fd, struct process *parent, unsigned int fla
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     memset( &process->image_info, 0, sizeof(process->image_info) );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     list_init( &process->rawinput_entry );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     process->esync_fd        = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    process->msync_idx       = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     list_init( &process->kernel_object );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     list_init( &process->thread_list );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     list_init( &process->locks );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -741,6 +747,9 @@ struct process *create_process( int fd, struct process *parent, unsigned int fla
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (!process->handles || !process->token) goto error;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     process->session_id = token_get_session_id( process->token );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        process->msync_idx = msync_alloc_shm( 0, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         process->esync_fd = esync_create_fd( 0, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -793,6 +802,7 @@ static void process_destroy( struct object *obj )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     free( process->dir_cache );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     free( process->image );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync()) close( process->esync_fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync()) msync_destroy_semaphore( process->msync_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* dump a process on stdout for debugging purposes */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -817,6 +827,13 @@ static int process_get_esync_fd( struct object *obj, enum esync_type *type )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     return process->esync_fd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static unsigned int process_get_msync_idx( struct object *obj, enum msync_type *type )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct process *process = (struct process *)obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    *type = MSYNC_MANUAL_SERVER;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return process->msync_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static unsigned int process_map_access( struct object *obj, unsigned int access )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     access = default_map_access( obj, access );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/process.h b/server/process.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index bedd8bb4586..24276142a63 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/process.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/process.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -87,6 +87,7 @@ struct process
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     struct list          kernel_object;   /* list of kernel object pointers */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     pe_image_info_t      image_info;      /* main exe image info */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     int                  esync_fd;        /* esync file descriptor (signaled on exit) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int         msync_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* process functions */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/protocol.def b/server/protocol.def
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 44f0751e77a..4f26c6bbad5 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/protocol.def
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/protocol.def
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -3972,3 +3972,57 @@ enum esync_type
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* Retrieve the fd to wait on for user APCs. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ @REQ(get_esync_apc_fd)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ @END
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++enum msync_type
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    MSYNC_SEMAPHORE = 1,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    MSYNC_AUTO_EVENT,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    MSYNC_MANUAL_EVENT,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    MSYNC_MUTEX,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    MSYNC_AUTO_SERVER,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    MSYNC_MANUAL_SERVER,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    MSYNC_QUEUE,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/* Create a new mach-based synchronization object */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++@REQ(create_msync)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int access;        /* wanted access rights */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int low;                    /* initial value of low word */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int high;                   /* initial value of high word */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int type;                   /* type of msync object */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    VARARG(objattr,object_attributes); /* object attributes */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++@REPLY
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    obj_handle_t handle;        /* handle to the object */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int type;                   /* type of msync object */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int shm_idx;       /* this object's index into the shm section */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++@END
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/* Open an msync object */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++@REQ(open_msync)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int access;        /* wanted access rights */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int attributes;    /* object attributes */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    obj_handle_t rootdir;       /* root directory */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int          type;          /* type of msync object */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    VARARG(name,unicode_str);   /* object name */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++@REPLY
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    obj_handle_t handle;        /* handle to the event */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int          type;          /* type of msync object */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int shm_idx;       /* this object's index into the shm section */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++@END
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++/* Retrieve the shm index for an object. */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++@REQ(get_msync_idx)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    obj_handle_t handle;        /* handle to the object */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++@REPLY
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int          type;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++@END
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++@REQ(msync_msgwait)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int          in_msgwait;    /* are we in a message wait? */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++@END
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++@REQ(get_msync_apc_idx)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++@REPLY
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int shm_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++@END
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/queue.c b/server/queue.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index a220baa1f92..6c62d9076db 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/queue.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/queue.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -45,6 +45,7 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "request.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "user.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "esync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "msync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #define WM_NCMOUSEFIRST WM_NCMOUSEMOVE
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #define WM_NCMOUSELAST  (WM_NCMOUSEFIRST+(WM_MOUSELAST-WM_MOUSEFIRST))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -150,6 +151,8 @@ struct msg_queue
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     unsigned int           ignore_post_msg; /* ignore post messages newer than this unique id */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     int                    esync_fd;        /* esync file descriptor (signalled on message) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     int                    esync_in_msgwait; /* our thread is currently waiting on us */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int           msync_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    int                    msync_in_msgwait; /* our thread is currently waiting on us */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ struct hotkey
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -167,6 +170,7 @@ static int msg_queue_add_queue( struct object *obj, struct wait_queue_entry *ent
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void msg_queue_remove_queue( struct object *obj, struct wait_queue_entry *entry );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static int msg_queue_signaled( struct object *obj, struct wait_queue_entry *entry );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static int msg_queue_get_esync_fd( struct object *obj, enum esync_type *type );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static unsigned int msg_queue_get_msync_idx( struct object *obj, enum msync_type *type );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *entry );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void msg_queue_destroy( struct object *obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void msg_queue_poll_event( struct fd *fd, int event );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -183,6 +187,7 @@ static const struct object_ops msg_queue_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     msg_queue_remove_queue,    /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     msg_queue_signaled,        /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     msg_queue_get_esync_fd,    /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    msg_queue_get_msync_idx,   /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     msg_queue_satisfied,       /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                 /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                 /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -221,6 +226,7 @@ static const struct object_ops thread_input_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                         /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                    /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                    /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -324,6 +330,8 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         queue->ignore_post_msg = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         queue->esync_fd        = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         queue->esync_in_msgwait = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        queue->msync_idx       = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        queue->msync_in_msgwait = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         list_init( &queue->send_result );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         list_init( &queue->callback_result );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         list_init( &queue->pending_timers );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -333,6 +341,9 @@ static struct msg_queue *create_msg_queue( struct thread *thread, struct thread_
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             queue->esync_fd = esync_create_fd( 0, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            queue->msync_idx = msync_alloc_shm( 0, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         thread->queue = queue;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (new_input) release_object( new_input );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -627,6 +638,9 @@ static inline void clear_queue_bits( struct msg_queue *queue, unsigned int bits
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         queue->keystate_lock = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync() && !is_signaled( queue ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_clear( &queue->obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync() && !is_signaled( queue ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         esync_clear( queue->esync_fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1118,6 +1132,9 @@ static int is_queue_hung( struct msg_queue *queue )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             return 0;  /* thread is waiting on queue -> not hung */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync() && queue->msync_in_msgwait)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return 0;   /* thread is waiting on queue in absentia -> not hung */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync() && queue->esync_in_msgwait)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         return 0;   /* thread is waiting on queue in absentia -> not hung */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1181,6 +1198,13 @@ static int msg_queue_get_esync_fd( struct object *obj, enum esync_type *type )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     return queue->esync_fd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static unsigned int msg_queue_get_msync_idx( struct object *obj, enum msync_type *type )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msg_queue *queue = (struct msg_queue *)obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    *type = MSYNC_QUEUE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return queue->msync_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void msg_queue_satisfied( struct object *obj, struct wait_queue_entry *entry )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     struct msg_queue *queue = (struct msg_queue *)obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1226,6 +1250,8 @@ static void msg_queue_destroy( struct object *obj )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (queue->hooks) release_object( queue->hooks );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (queue->fd) release_object( queue->fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync()) close( queue->esync_fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_destroy_semaphore( queue->msync_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void msg_queue_poll_event( struct fd *fd, int event )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -2905,6 +2931,8 @@ DECL_HANDLER(set_queue_mask)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             if (req->skip_wait) queue->wake_mask = queue->changed_mask = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             else wake_up( &queue->obj, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (do_msync() && !is_signaled( queue ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            msync_clear( &queue->obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         if (do_esync() && !is_signaled( queue ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             esync_clear( queue->esync_fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -2922,6 +2950,9 @@ DECL_HANDLER(get_queue_status)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         reply->changed_bits = queue->changed_bits;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         queue->changed_bits &= ~req->clear_bits;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (do_msync() && !is_signaled( queue ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            msync_clear( &queue->obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         if (do_esync() && !is_signaled( queue ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             esync_clear( queue->esync_fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -3179,6 +3210,9 @@ DECL_HANDLER(get_message)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     queue->changed_mask = req->changed_mask;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     set_error( STATUS_PENDING );  /* FIXME */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync() && !is_signaled( queue ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_clear( &queue->obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync() && !is_signaled( queue ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         esync_clear( queue->esync_fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -3950,6 +3984,21 @@ DECL_HANDLER(esync_msgwait)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         set_fd_events( queue->fd, req->in_msgwait ? POLLIN : 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++DECL_HANDLER(msync_msgwait)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct msg_queue *queue = get_current_queue();
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!queue) return;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    queue->msync_in_msgwait = req->in_msgwait;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (current->process->idle_event && !(queue->wake_mask & QS_SMRESULT))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        set_event( current->process->idle_event );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    /* and start/stop waiting on the driver */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (queue->fd)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        set_fd_events( queue->fd, req->in_msgwait ? POLLIN : 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ DECL_HANDLER(set_keyboard_repeat)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     struct desktop *desktop;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/registry.c b/server/registry.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 1cca1acfe6b..eb54495208c 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/registry.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/registry.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -181,6 +181,7 @@ static const struct object_ops key_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                    /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                    /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                    /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                    /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                    /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,               /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,               /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/request.c b/server/request.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 8e7d88a0d4c..3287b16170d 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/request.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/request.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -91,6 +91,7 @@ static const struct object_ops master_socket_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                          /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                          /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                          /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                          /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                          /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                     /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                     /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/request.h b/server/request.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 8df304f9a8f..2261a2bbfca 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/request.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/request.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -411,6 +411,11 @@ DECL_HANDLER(get_esync_fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ DECL_HANDLER(esync_msgwait);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ DECL_HANDLER(set_keyboard_repeat);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ DECL_HANDLER(get_esync_apc_fd);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++DECL_HANDLER(create_msync);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++DECL_HANDLER(open_msync);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++DECL_HANDLER(get_msync_idx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++DECL_HANDLER(msync_msgwait);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++DECL_HANDLER(get_msync_apc_idx);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #ifdef WANT_REQUEST_HANDLERS
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -709,6 +714,11 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     (req_handler)req_esync_msgwait,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     (req_handler)req_set_keyboard_repeat,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     (req_handler)req_get_esync_apc_fd,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    (req_handler)req_create_msync,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    (req_handler)req_open_msync,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    (req_handler)req_get_msync_idx,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    (req_handler)req_msync_msgwait,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    (req_handler)req_get_msync_apc_idx,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ C_ASSERT( sizeof(abstime_t) == 8 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -2394,6 +2404,34 @@ C_ASSERT( sizeof(struct set_keyboard_repeat_request) == 24 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ C_ASSERT( FIELD_OFFSET(struct set_keyboard_repeat_reply, enable) == 8 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ C_ASSERT( sizeof(struct set_keyboard_repeat_reply) == 16 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ C_ASSERT( sizeof(struct get_esync_apc_fd_request) == 16 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( FIELD_OFFSET(struct create_msync_request, access) == 12 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( FIELD_OFFSET(struct create_msync_request, low) == 16 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( FIELD_OFFSET(struct create_msync_request, high) == 20 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( FIELD_OFFSET(struct create_msync_request, type) == 24 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( sizeof(struct create_msync_request) == 32 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( FIELD_OFFSET(struct create_msync_reply, handle) == 8 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( FIELD_OFFSET(struct create_msync_reply, type) == 12 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( FIELD_OFFSET(struct create_msync_reply, shm_idx) == 16 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( sizeof(struct create_msync_reply) == 24 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( FIELD_OFFSET(struct open_msync_request, access) == 12 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( FIELD_OFFSET(struct open_msync_request, attributes) == 16 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( FIELD_OFFSET(struct open_msync_request, rootdir) == 20 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( FIELD_OFFSET(struct open_msync_request, type) == 24 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( sizeof(struct open_msync_request) == 32 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( FIELD_OFFSET(struct open_msync_reply, handle) == 8 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( FIELD_OFFSET(struct open_msync_reply, type) == 12 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( FIELD_OFFSET(struct open_msync_reply, shm_idx) == 16 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( sizeof(struct open_msync_reply) == 24 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( FIELD_OFFSET(struct get_msync_idx_request, handle) == 12 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( sizeof(struct get_msync_idx_request) == 16 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( FIELD_OFFSET(struct get_msync_idx_reply, type) == 8 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( FIELD_OFFSET(struct get_msync_idx_reply, shm_idx) == 12 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( sizeof(struct get_msync_idx_reply) == 16 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( FIELD_OFFSET(struct msync_msgwait_request, in_msgwait) == 12 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( sizeof(struct msync_msgwait_request) == 16 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( sizeof(struct get_msync_apc_idx_request) == 16 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( FIELD_OFFSET(struct get_msync_apc_idx_reply, shm_idx) == 8 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++C_ASSERT( sizeof(struct get_msync_apc_idx_reply) == 16 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #endif  /* WANT_REQUEST_HANDLERS */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/semaphore.c b/server/semaphore.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index e3889f24601..8d3c325c0b3 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/semaphore.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/semaphore.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -71,6 +71,7 @@ static const struct object_ops semaphore_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,                  /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     semaphore_signaled,            /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                          /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                          /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     semaphore_satisfied,           /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     semaphore_signal,              /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                     /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/serial.c b/server/serial.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index ecb19936281..3dd44bd7322 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/serial.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/serial.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -94,6 +94,7 @@ static const struct object_ops serial_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,                 /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     default_fd_signaled,          /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                         /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                 /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                    /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     serial_get_fd,                /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/signal.c b/server/signal.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 55cd6aa037e..e86ad49df8e 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/signal.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/signal.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -63,6 +63,7 @@ static const struct object_ops handler_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                     /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/sock.c b/server/sock.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 7be912b3b50..af92f134538 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/sock.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/sock.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -454,6 +454,7 @@ static const struct object_ops sock_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,                 /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     default_fd_signaled,          /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                         /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,                 /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                    /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     sock_get_fd,                  /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -3562,6 +3563,7 @@ static const struct object_ops ifchange_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                    /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                    /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                    /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                    /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,            /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,               /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     ifchange_get_fd,         /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -3784,6 +3786,7 @@ static const struct object_ops socket_device_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                       /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                       /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                       /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                       /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,               /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                  /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                  /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/symlink.c b/server/symlink.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index c7f34412317..d40d060492b 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/symlink.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/symlink.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -72,6 +72,7 @@ static const struct object_ops symlink_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                         /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                    /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                    /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/thread.c b/server/thread.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index dac5c43e3bd..5003898e822 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/thread.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/thread.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -51,6 +51,7 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "user.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "security.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "esync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "msync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* thread queues */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -98,6 +99,7 @@ static const struct object_ops thread_apc_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,               /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     thread_apc_signaled,        /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                       /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                       /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,               /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                  /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                  /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -141,6 +143,7 @@ static const struct object_ops context_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,               /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     context_signaled,           /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                       /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                       /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,               /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                  /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                  /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -178,6 +181,7 @@ struct type_descr thread_type =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void dump_thread( struct object *obj, int verbose );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static int thread_signaled( struct object *obj, struct wait_queue_entry *entry );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static int thread_get_esync_fd( struct object *obj, enum esync_type *type );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static unsigned int thread_get_msync_idx( struct object *obj, enum msync_type *type );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static unsigned int thread_map_access( struct object *obj, unsigned int access );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void thread_poll_event( struct fd *fd, int event );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static struct list *thread_get_kernel_obj_list( struct object *obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -192,6 +196,7 @@ static const struct object_ops thread_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,               /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     thread_signaled,            /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     thread_get_esync_fd,        /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    thread_get_msync_idx,       /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_satisfied,               /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                  /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                  /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -233,6 +238,8 @@ static inline void init_thread_structure( struct thread *thread )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     thread->entry_point     = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     thread->esync_fd        = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     thread->esync_apc_fd    = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    thread->msync_idx       = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    thread->msync_apc_idx   = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     thread->system_regs     = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     thread->queue           = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     thread->wait            = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -380,6 +387,12 @@ struct thread *create_thread( int fd, struct process *process, const struct secu
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        thread->msync_idx = msync_alloc_shm( 0, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        thread->msync_apc_idx = msync_alloc_shm( 0, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         thread->esync_fd = esync_create_fd( 0, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -468,6 +481,12 @@ static void destroy_thread( struct object *obj )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         close( thread->esync_fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_destroy_semaphore( thread->msync_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_destroy_semaphore( thread->msync_apc_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* dump a thread on stdout for debugging purposes */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -493,6 +512,13 @@ static int thread_get_esync_fd( struct object *obj, enum esync_type *type )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     return thread->esync_fd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static unsigned int thread_get_msync_idx( struct object *obj, enum msync_type *type )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct thread *thread = (struct thread *)obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    *type = MSYNC_MANUAL_SERVER;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return thread->msync_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static unsigned int thread_map_access( struct object *obj, unsigned int access )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     access = default_map_access( obj, access );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -545,6 +571,7 @@ static struct thread_apc *create_apc( struct object *owner, const apc_call_t *ca
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         apc->result.type = APC_NONE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         if (owner) grab_object( owner );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     return apc;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1091,6 +1118,9 @@ void wake_up( struct object *obj, int max )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     struct list *ptr;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     int ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_wake_up( obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         esync_wake_up( obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1181,6 +1211,9 @@ static int queue_apc( struct process *process, struct thread *thread, struct thr
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         wake_thread( thread );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (do_msync() && queue == &thread->user_apc)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            msync_signal_all( thread->msync_apc_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         if (do_esync() && queue == &thread->user_apc)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             esync_wake_fd( thread->esync_apc_fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1231,6 +1264,9 @@ static struct thread_apc *thread_dequeue_apc( struct thread *thread, int system
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         list_remove( ptr );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync() && list_empty( &thread->system_apc ) && list_empty( &thread->user_apc ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_clear_shm( thread->msync_apc_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync() && list_empty( &thread->system_apc ) && list_empty( &thread->user_apc ))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         esync_clear( thread->esync_apc_fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1349,6 +1385,8 @@ void kill_thread( struct thread *thread, int violent_death )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     kill_console_processes( thread, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     abandon_mutexes( thread );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_abandon_mutexes( thread );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         esync_abandon_mutexes( thread );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (violent_death)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/thread.h b/server/thread.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 10e9e28b432..26b41745261 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/thread.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/thread.h
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -57,6 +57,8 @@ struct thread
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     struct list            mutex_list;    /* list of currently owned mutexes */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     int                    esync_fd;      /* esync file descriptor (signalled on exit) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     int                    esync_apc_fd;  /* esync apc fd (signalled when APCs are present) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int           msync_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int           msync_apc_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     unsigned int           system_regs;   /* which system regs have been set */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     struct msg_queue      *queue;         /* message queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     struct thread_wait    *wait;          /* current wait condition if sleeping */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/timer.c b/server/timer.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 36645a2a8d2..d57a5536eb3 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/timer.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/timer.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -36,6 +36,7 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "handle.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "request.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "esync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#include "msync.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static const WCHAR timer_name[] = {'T','i','m','e','r'};
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -63,11 +64,13 @@ struct timer
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     client_ptr_t         callback;  /* callback APC function */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     client_ptr_t         arg;       /* callback argument */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     int                  esync_fd;  /* esync file descriptor */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned int         msync_idx; /* msync shm index */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void timer_dump( struct object *obj, int verbose );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static int timer_signaled( struct object *obj, struct wait_queue_entry *entry );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static int timer_get_esync_fd( struct object *obj, enum esync_type *type );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static unsigned int timer_get_msync_idx( struct object *obj, enum msync_type *type );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void timer_satisfied( struct object *obj, struct wait_queue_entry *entry );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void timer_destroy( struct object *obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -80,6 +83,7 @@ static const struct object_ops timer_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     remove_queue,              /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     timer_signaled,            /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     timer_get_esync_fd,        /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    timer_get_msync_idx,       /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     timer_satisfied,           /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                 /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                 /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -116,6 +120,9 @@ static struct timer *create_timer( struct object *root, const struct unicode_str
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             timer->thread   = NULL;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             timer->esync_fd = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                timer->msync_idx = msync_alloc_shm( 0, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                 timer->esync_fd = esync_create_fd( 0, 0 );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -190,6 +197,9 @@ static int set_timer( struct timer *timer, timeout_t expire, unsigned int period
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         period = 0;  /* period doesn't make any sense for a manual timer */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         timer->signaled = 0;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            msync_clear( &timer->obj );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         if (do_esync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             esync_clear( timer->esync_fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -226,6 +236,13 @@ static int timer_get_esync_fd( struct object *obj, enum esync_type *type )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     return timer->esync_fd;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static unsigned int timer_get_msync_idx( struct object *obj, enum msync_type *type )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct timer *timer = (struct timer *)obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    *type = timer->manual ? MSYNC_MANUAL_SERVER : MSYNC_AUTO_SERVER;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return timer->msync_idx;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static void timer_satisfied( struct object *obj, struct wait_queue_entry *entry )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     struct timer *timer = (struct timer *)obj;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -241,6 +258,8 @@ static void timer_destroy( struct object *obj )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (timer->timeout) remove_timeout_user( timer->timeout );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (timer->thread) release_object( timer->thread );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (do_esync()) close( timer->esync_fd );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (do_msync())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        msync_destroy_semaphore( timer->msync_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /* create a timer */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/token.c b/server/token.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index e40ba10f9aa..1101c7224b9 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/token.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/token.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -146,6 +146,7 @@ static const struct object_ops token_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                      /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                      /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                      /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                      /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                      /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                 /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                 /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/trace.c b/server/trace.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 574a971b24e..42e89eed4a3 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/trace.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/trace.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -4713,6 +4713,63 @@ static void dump_get_esync_apc_fd_request( const struct get_esync_apc_fd_request
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void dump_create_msync_request( const struct create_msync_request *req )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fprintf( stderr, " access=%08x", req->access );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fprintf( stderr, ", low=%d", req->low );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fprintf( stderr, ", high=%d", req->high );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fprintf( stderr, ", type=%d", req->type );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    dump_varargs_object_attributes( ", objattr=", cur_size );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void dump_create_msync_reply( const struct create_msync_reply *req )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fprintf( stderr, " handle=%04x", req->handle );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fprintf( stderr, ", type=%d", req->type );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fprintf( stderr, ", shm_idx=%08x", req->shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void dump_open_msync_request( const struct open_msync_request *req )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fprintf( stderr, " access=%08x", req->access );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fprintf( stderr, ", attributes=%08x", req->attributes );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fprintf( stderr, ", rootdir=%04x", req->rootdir );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fprintf( stderr, ", type=%d", req->type );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    dump_varargs_unicode_str( ", name=", cur_size );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void dump_open_msync_reply( const struct open_msync_reply *req )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fprintf( stderr, " handle=%04x", req->handle );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fprintf( stderr, ", type=%d", req->type );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fprintf( stderr, ", shm_idx=%08x", req->shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void dump_get_msync_idx_request( const struct get_msync_idx_request *req )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fprintf( stderr, " handle=%04x", req->handle );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void dump_get_msync_idx_reply( const struct get_msync_idx_reply *req )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fprintf( stderr, " type=%d", req->type );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fprintf( stderr, ", shm_idx=%08x", req->shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void dump_msync_msgwait_request( const struct msync_msgwait_request *req )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fprintf( stderr, " in_msgwait=%d", req->in_msgwait );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void dump_get_msync_apc_idx_request( const struct get_msync_apc_idx_request *req )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void dump_get_msync_apc_idx_reply( const struct get_msync_apc_idx_reply *req )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    fprintf( stderr, " shm_idx=%08x", req->shm_idx );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     (dump_func)dump_new_process_request,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     (dump_func)dump_get_new_process_info_request,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -5006,6 +5063,11 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     (dump_func)dump_esync_msgwait_request,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     (dump_func)dump_set_keyboard_repeat_request,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     (dump_func)dump_get_esync_apc_fd_request,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    (dump_func)dump_create_msync_request,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    (dump_func)dump_open_msync_request,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    (dump_func)dump_get_msync_idx_request,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    (dump_func)dump_msync_msgwait_request,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    (dump_func)dump_get_msync_apc_idx_request,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -5301,6 +5363,11 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     (dump_func)dump_set_keyboard_repeat_reply,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    (dump_func)dump_create_msync_reply,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    (dump_func)dump_open_msync_reply,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    (dump_func)dump_get_msync_idx_reply,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    (dump_func)dump_get_msync_apc_idx_reply,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static const char * const req_names[REQ_NB_REQUESTS] = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -5596,6 +5663,11 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     "esync_msgwait",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     "set_keyboard_repeat",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     "get_esync_apc_fd",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    "create_msync",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    "open_msync",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    "get_msync_idx",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    "msync_msgwait",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    "get_msync_apc_idx",
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ };
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ static const struct
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/window.c b/server/window.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index bfde133fe9b..4ab444bbdbe 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/window.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/window.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -108,6 +108,7 @@ static const struct object_ops window_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                     /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                     /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/server/winstation.c b/server/winstation.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index d3d4995949d..fd60a44953c 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/server/winstation.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/server/winstation.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -77,6 +77,7 @@ static const struct object_ops winstation_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                         /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                    /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                    /* get_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -118,6 +119,7 @@ static const struct object_ops desktop_ops =
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* remove_queue */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* signaled */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* get_esync_fd */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    NULL,                         /* get_msync_idx */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     NULL,                         /* satisfied */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_signal,                    /* signal */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     no_get_fd,                    /* get_fd */
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/emulators/wine-devel/files/5871.diff b/emulators/wine-devel/files/5871.diff
</span>new file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index 00000000000..3ebd7f60411
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/emulators/wine-devel/files/5871.diff
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -0,0 +1,87 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+From 802a52cb1b9825a8baa63276b0e6620d7f4edc83 Mon Sep 17 00:00:00 2001
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+From: Brendan Shanks <bshanks@codeweavers.com>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+Date: Wed, 19 Jun 2024 15:36:27 -0700
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+Subject: [PATCH] ntdll: Make __wine_syscall_dispatcher_return a separate
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ function to fix Xcode 16 build errors.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+LLVM no longer allows non-private labels to appear between
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+.cfi_startproc/endproc when targeting Mach-O.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+For consistency, also modify ARM and i386.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+---
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ dlls/ntdll/unix/signal_arm.c    | 6 +++---
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ dlls/ntdll/unix/signal_arm64.c  | 6 +++---
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ dlls/ntdll/unix/signal_i386.c   | 5 ++---
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ dlls/ntdll/unix/signal_x86_64.c | 6 +++---
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 4 files changed, 11 insertions(+), 12 deletions(-)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/dlls/ntdll/unix/signal_arm.c b/dlls/ntdll/unix/signal_arm.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index a477d8d2ed8..77d66909135 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/dlls/ntdll/unix/signal_arm.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/dlls/ntdll/unix/signal_arm.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1252,9 +1252,9 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    "5:\tmovw r0, #0x000d\n\t" /* STATUS_INVALID_PARAMETER */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    "movt r0, #0xc000\n\t"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-                   "b " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") "\n\t"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-                   ".globl " __ASM_NAME("__wine_syscall_dispatcher_return") "\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-                   __ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                   "b " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++__ASM_GLOBAL_FUNC( __wine_syscall_dispatcher_return,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    "mov r8, r0\n\t"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    "mov r0, r1\n\t"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    "b " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 58911d9b1f2..667bc1108cf 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/dlls/ntdll/unix/signal_arm64.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/dlls/ntdll/unix/signal_arm64.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1607,9 +1607,9 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    "ret x16\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    "4:\tmov x0, #0xc0000000\n\t" /* STATUS_INVALID_PARAMETER */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    "movk x0, #0x000d\n\t"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-                   "b " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") "\n\t"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-                   ".globl " __ASM_NAME("__wine_syscall_dispatcher_return") "\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-                   __ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                   "b " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++__ASM_GLOBAL_FUNC( __wine_syscall_dispatcher_return,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    "mov sp, x0\n\t"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    "mov x0, x1\n\t"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    "b " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/dlls/ntdll/unix/signal_i386.c b/dlls/ntdll/unix/signal_i386.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 6457f0221bd..61d41ec3589 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/dlls/ntdll/unix/signal_i386.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/dlls/ntdll/unix/signal_i386.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -2768,10 +2768,9 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    __ASM_CFI("\t.cfi_restore_state\n")
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    "6:\tmovl $0xc000000d,%eax\n\t" /* STATUS_INVALID_PARAMETER */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-                   "jmp " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") "\n\t"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                   "jmp " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-                   ".globl " __ASM_NAME("__wine_syscall_dispatcher_return") "\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-                   __ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++__ASM_GLOBAL_FUNC( __wine_syscall_dispatcher_return,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    "movl 8(%esp),%eax\n\t"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    "movl 4(%esp),%esp\n\t"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    "jmp " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index a163d5d0b33..e84044fa805 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+--- a/dlls/ntdll/unix/signal_x86_64.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++++ b/dlls/ntdll/unix/signal_x86_64.c
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -2876,9 +2876,9 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    __ASM_CFI("\t.cfi_restore_state\n")
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    "5:\tmovl $0xc000000d,%eax\n\t" /* STATUS_INVALID_PARAMETER */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    "movq %rsp,%rcx\n\t"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-                   "jmp " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") "\n\t"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-                   ".globl " __ASM_NAME("__wine_syscall_dispatcher_return") "\n"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-                   __ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                   "jmp " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++__ASM_GLOBAL_FUNC( __wine_syscall_dispatcher_return,
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    "movq %rdi,%rcx\n\t"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    "movl 0xb0(%rcx),%r14d\n\t"     /* frame->syscall_flags */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+                    "movq %rsi,%rax\n\t"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-- 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+GitLab
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/emulators/wine-devel/files/5871.patch b/emulators/wine-devel/files/5871.patch
</span>deleted file mode 100644
<span style='display:block; white-space:pre;color:#808080;'>index d6e2934f42b..00000000000
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/emulators/wine-devel/files/5871.patch
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ /dev/null
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -1,127 +0,0 @@
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-From 306e8d2c145b678d117174dbc3cd3b0b1761f271 Mon Sep 17 00:00:00 2001
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-From: Brendan Shanks <bshanks@codeweavers.com>
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-Date: Tue, 18 Jun 2024 10:35:03 -0700
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-Subject: [PATCH] ntdll: Fix macOS build errors with Xcode 16.
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-LLVM no longer allows non-private labels to appear between
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-.cfi_startproc/endproc when targeting Mach-O.
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-Similar fixes as in commit 295d521b11644fb76c36854336b13c2155bb7d79.
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>----
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- dlls/ntdll/unix/signal_arm64.c  | 16 ++++++++++++----
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- dlls/ntdll/unix/signal_x86_64.c | 13 +++++++++----
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- 2 files changed, 21 insertions(+), 8 deletions(-)
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-diff --git a/dlls/ntdll/unix/signal_arm64.c b/dlls/ntdll/unix/signal_arm64.c
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-index 58911d9b1f2..49d54b11f91 100644
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>---- a/dlls/ntdll/unix/signal_arm64.c
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-+++ b/dlls/ntdll/unix/signal_arm64.c
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-@@ -1017,10 +1017,12 @@ static BOOL handle_syscall_fault( ucontext_t *context, EXCEPTION_RECORD *rec )
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-     }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-     else
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-     {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-+        extern typeof(__wine_syscall_dispatcher_return) *__wine_syscall_dispatcher_return_ptr;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-+
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-         TRACE( "returning to user mode ip=%p ret=%08x\n", (void *)frame->pc, rec->ExceptionCode );
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-         REGn_sig(0, context) = (ULONG_PTR)frame;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-         REGn_sig(1, context) = rec->ExceptionCode;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--        PC_sig(context)      = (ULONG_PTR)__wine_syscall_dispatcher_return;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-+        PC_sig(context)      = (ULONG_PTR)__wine_syscall_dispatcher_return_ptr;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-     }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-     return TRUE;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-@@ -1381,6 +1383,7 @@ void call_init_thunk( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend, TEB
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-     CONTEXT *ctx, context = { CONTEXT_ALL };
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-     I386_CONTEXT *i386_context;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-     ARM_CONTEXT *arm_context;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-+    extern typeof(__wine_syscall_dispatcher_return) *__wine_syscall_dispatcher_return_ptr;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- 
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-     thread_data->syscall_table = KeServiceDescriptorTable;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- 
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-@@ -1440,7 +1443,7 @@ void call_init_thunk( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend, TEB
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-     syscall_frame_fixup_for_fastpath( frame );
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- 
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-     pthread_sigmask( SIG_UNBLOCK, &server_block_set, NULL );
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--    __wine_syscall_dispatcher_return( frame, 0 );
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-+    __wine_syscall_dispatcher_return_ptr( frame, 0 );
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- 
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- 
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-@@ -1608,12 +1611,17 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    "4:\tmov x0, #0xc0000000\n\t" /* STATUS_INVALID_PARAMETER */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    "movk x0, #0x000d\n\t"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    "b " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") "\n\t"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--                   ".globl " __ASM_NAME("__wine_syscall_dispatcher_return") "\n"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--                   __ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-+                   __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return_label") ":\n\t"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    "mov sp, x0\n\t"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    "mov x0, x1\n\t"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    "b " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") )
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- 
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-+asm( ".data\n\t"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-+     ".align 4\n\t"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-+     ".globl " __ASM_NAME("__wine_syscall_dispatcher_return_ptr") "\n"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-+     __ASM_NAME("__wine_syscall_dispatcher_return_ptr") ":\n\t"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-+     ".quad " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return_label") "\n\t"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-+     ".text\n\t" );
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- 
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- /***********************************************************************
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-  *           __wine_unix_call_dispatcher
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-diff --git a/dlls/ntdll/unix/signal_x86_64.c b/dlls/ntdll/unix/signal_x86_64.c
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-index a163d5d0b33..894ddee9348 100644
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>---- a/dlls/ntdll/unix/signal_x86_64.c
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-+++ b/dlls/ntdll/unix/signal_x86_64.c
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-@@ -1880,10 +1880,12 @@ static BOOL handle_syscall_fault( ucontext_t *sigcontext, EXCEPTION_RECORD *rec,
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-     }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-     else
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-     {
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-+        extern typeof(__wine_syscall_dispatcher_return) *__wine_syscall_dispatcher_return_ptr;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-+
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-         TRACE_(seh)( "returning to user mode ip=%016lx ret=%08x\n", frame->rip, rec->ExceptionCode );
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-         RDI_sig(sigcontext) = (ULONG_PTR)frame;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-         RSI_sig(sigcontext) = rec->ExceptionCode;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--        RIP_sig(sigcontext) = (ULONG_PTR)__wine_syscall_dispatcher_return;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-+        RIP_sig(sigcontext) = (ULONG_PTR)__wine_syscall_dispatcher_return_ptr;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-     }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-     return TRUE;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-@@ -2513,6 +2515,7 @@ void call_init_thunk( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend, TEB
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-     struct amd64_thread_data *thread_data = (struct amd64_thread_data *)&teb->GdiTebBatch;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-     CONTEXT *ctx, context = { 0 };
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-     I386_CONTEXT *wow_context;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-+    extern typeof(__wine_syscall_dispatcher_return) *__wine_syscall_dispatcher_return_ptr;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- 
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-     thread_data->syscall_table = KeServiceDescriptorTable;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-     thread_data->xstate_features_mask = xstate_supported_features_mask;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-@@ -2592,7 +2595,7 @@ void call_init_thunk( LPTHREAD_START_ROUTINE entry, void *arg, BOOL suspend, TEB
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-     frame->syscall_cfa   = syscall_cfa;
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- 
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-     pthread_sigmask( SIG_UNBLOCK, &server_block_set, NULL );
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--    __wine_syscall_dispatcher_return( frame, 0 );
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-+    __wine_syscall_dispatcher_return_ptr( frame, 0 );
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- }
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- 
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- 
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-@@ -2877,8 +2880,7 @@ __ASM_GLOBAL_FUNC( __wine_syscall_dispatcher,
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    "5:\tmovl $0xc000000d,%eax\n\t" /* STATUS_INVALID_PARAMETER */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    "movq %rsp,%rcx\n\t"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    "jmp " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return") "\n\t"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--                   ".globl " __ASM_NAME("__wine_syscall_dispatcher_return") "\n"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--                   __ASM_NAME("__wine_syscall_dispatcher_return") ":\n\t"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-+                   __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return_label") ":\n\t"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    "movq %rdi,%rcx\n\t"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    "movl 0xb0(%rcx),%r14d\n\t"     /* frame->syscall_flags */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-                    "movq %rsi,%rax\n\t"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-@@ -2994,6 +2996,9 @@ asm( ".data\n\t"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-      ".globl " __ASM_NAME("__wine_unix_call_dispatcher_prolog_end_ptr") "\n"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-      __ASM_NAME("__wine_unix_call_dispatcher_prolog_end_ptr") ":\n\t"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-      ".quad " __ASM_LOCAL_LABEL("__wine_unix_call_dispatcher_prolog_end") "\n\t"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-+     ".globl " __ASM_NAME("__wine_syscall_dispatcher_return_ptr") "\n"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-+     __ASM_NAME("__wine_syscall_dispatcher_return_ptr") ":\n\t"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-+     ".quad " __ASM_LOCAL_LABEL("__wine_syscall_dispatcher_return_label") "\n\t"
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-      ".text\n\t" );
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- 
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>- #endif  /* __x86_64__ */
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>--- 
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-GitLab
</span><span style='display:block; white-space:pre;background:#ffe0e0;'>-
</span><span style='display:block; white-space:pre;color:#808080;'>diff --git a/emulators/wine-devel/files/macos_hacks.diff b/emulators/wine-devel/files/macos_hacks.diff
</span><span style='display:block; white-space:pre;color:#808080;'>index 267b46526b4..31a3d5e8c3c 100644
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>--- a/emulators/wine-devel/files/macos_hacks.diff
</span><span style='display:block; white-space:pre;background:#e0e0ff;'>+++ b/emulators/wine-devel/files/macos_hacks.diff
</span><span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -470,10 +470,10 @@ index 5c59d102dd9..08df8328080 100644
</span>      if (NtCurrentTeb()->WowTebOffset) init_wow64( context );
  #endif
 diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c
<span style='display:block; white-space:pre;background:#ffe0e0;'>-index 9d866fa70f5..992db125965 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 8cf6abed3da..2509cde21c6 100644
</span> --- a/dlls/ntdll/unix/loader.c
 +++ b/dlls/ntdll/unix/loader.c
<span style='display:block; white-space:pre;background:#ffe0e0;'>-@@ -1809,6 +1809,48 @@ static ULONG_PTR get_image_address(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1813,6 +1813,48 @@ static ULONG_PTR get_image_address(void)
</span>      return 0;
  }
  
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -522,7 +522,7 @@ index 9d866fa70f5..992db125965 100644
</span>  /***********************************************************************
   *           start_main_thread
   */
<span style='display:block; white-space:pre;background:#ffe0e0;'>-@@ -1831,6 +1873,13 @@ static void start_main_thread(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1835,6 +1877,13 @@ static void start_main_thread(void)
</span>      load_ntdll();
      load_wow64_ntdll( main_image_info.Machine );
      load_apiset_dll();
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -750,10 +750,88 @@ index 3d151e7b2b8..03d1516fc03 100644
</span>  }
  
 diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
<span style='display:block; white-space:pre;background:#ffe0e0;'>-index 4b23d9954df..9e59ee46785 100644
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+index 4b23d9954df..44e341ece56 100644
</span> --- a/dlls/ntdll/unix/virtual.c
 +++ b/dlls/ntdll/unix/virtual.c
<span style='display:block; white-space:pre;background:#ffe0e0;'>-@@ -5924,6 +5924,56 @@ NTSTATUS WINAPI NtReadVirtualMemory( HANDLE process, const void *addr, void *buf
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -62,6 +62,7 @@
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #if defined(__APPLE__)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # include <mach/mach_init.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ # include <mach/mach_vm.h>
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++# include <sys/utsname.h> /* CrossOver Hack #22011 */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ #include "ntstatus.h"
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -1714,6 +1715,42 @@ static void mprotect_range( void *base, size_t size, BYTE set, BYTE clear )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (count) mprotect_exec( addr, count << page_shift, prot );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static BOOL is_catalina_or_later(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#ifdef __APPLE__
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    static int result = -1;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    struct utsname name;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    unsigned major, minor;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (result == -1)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        result = (uname(&name) == 0 &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                  sscanf(name.release, "%u.%u", &major, &minor) == 2 &&
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++                  major >= 19 /* macOS 10.15 Catalina */);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return (result == 1) ? TRUE : FALSE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#else
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return FALSE;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++static void *wine_mmap(void *addr, size_t len, int prot, int flags, int fd, off_t offset)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++{
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#if defined(__APPLE__) && defined(__x86_64__)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    // In Catalina-and-later, mapping files with execute permissions can make
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    // Gatekeeper prompt the user, or just fail outright.
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    if (!(flags & MAP_ANON) && fd >= 0 && prot & PROT_EXEC && is_catalina_or_later())
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        void *ret = mmap(addr, len, prot & ~PROT_EXEC, flags, fd, offset);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (ret != MAP_FAILED && mprotect(ret, len, prot))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++            WARN("failed to mprotect region: %d\n", errno);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        return ret;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++#endif
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++    return mmap(addr, len, prot, flags, fd, offset);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++}
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ /***********************************************************************
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+  *           set_vprot
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -2085,7 +2122,7 @@ static NTSTATUS map_file_into_view( struct file_view *view, int fd, size_t start
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     /* only try mmap if media is not removable (or if we require write access) */
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (!removable || (flags & MAP_SHARED))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-        if (mmap( (char *)view->base + start, size, prot, flags, fd, offset ) != MAP_FAILED)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (wine_mmap( (char *)view->base + start, size, prot, flags, fd, offset ) != MAP_FAILED)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             goto done;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         switch (errno)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -2413,7 +2450,7 @@ static NTSTATUS map_pe_header( void *ptr, size_t size, int fd, BOOL *removable )
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if (!*removable)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-        if (mmap( ptr, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, fd, 0 ) != MAP_FAILED)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        if (wine_mmap( ptr, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, fd, 0 ) != MAP_FAILED)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+             return STATUS_SUCCESS;
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+ 
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         switch (errno)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -3904,7 +3941,7 @@ void virtual_map_user_shared_data(void)
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         exit(1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     }
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     if ((res = server_get_unix_fd( section, 0, &fd, &needs_close, NULL, NULL )) ||
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+-        (user_shared_data != mmap( user_shared_data, page_size, PROT_READ, MAP_SHARED|MAP_FIXED, fd, 0 )))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>++        (user_shared_data != wine_mmap( user_shared_data, page_size, PROT_READ, MAP_SHARED|MAP_FIXED, fd, 0 )))
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+     {
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         ERR( "failed to remap the process USD: %d\n", res );
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+         exit(1);
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -5924,6 +5961,56 @@ NTSTATUS WINAPI NtReadVirtualMemory( HANDLE process, const void *addr, void *buf
</span>      return status;
  }
  
<span style='display:block; white-space:pre;background:#e0e0e0;'>@@ -810,7 +888,7 @@ index 4b23d9954df..9e59ee46785 100644
</span>  
  /***********************************************************************
   *             NtWriteVirtualMemory   (NTDLL.@)
<span style='display:block; white-space:pre;background:#ffe0e0;'>-@@ -5944,6 +5994,10 @@ NTSTATUS WINAPI NtWriteVirtualMemory( HANDLE process, void *addr, const void *bu
</span><span style='display:block; white-space:pre;background:#e0ffe0;'>+@@ -5944,6 +6031,10 @@ NTSTATUS WINAPI NtWriteVirtualMemory( HANDLE process, void *addr, const void *bu
</span>              if ((status = wine_server_call( req ))) size = 0;
          }
          SERVER_END_REQ;
</pre><pre style='margin:0'>

</pre>