<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, ¤t, 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>