From: Torge Matthies <tmatthies(a)codeweavers.com>
---
dlls/ntdll/unix/virtual.c | 70 +++++++++++++++++++++++++++++++++++++++
1 file changed, 70 insertions(+)
diff --git a/dlls/ntdll/unix/virtual.c b/dlls/ntdll/unix/virtual.c
index ee2a12ecd54..7a5778a6d8c 100644
--- a/dlls/ntdll/unix/virtual.c
+++ b/dlls/ntdll/unix/virtual.c
@@ -65,6 +65,9 @@
#if defined(__APPLE__)
# include <mach/mach_init.h>
# include <mach/mach_vm.h>
+# include <mach/task.h>
+# include <mach/thread_state.h>
+# include <mach/vm_map.h>
#endif
#include "ntstatus.h"
@@ -219,6 +222,11 @@ struct range_entry
static struct range_entry *free_ranges;
static struct range_entry *free_ranges_end;
+#ifdef __APPLE__
+static kern_return_t (*p_thread_get_register_pointer_values)( thread_t, uintptr_t*,
size_t*, uintptr_t* );
+static pthread_once_t tgrpvs_init_once = PTHREAD_ONCE_INIT;
+#endif
+
#if defined(__linux__) && defined(__NR_membarrier)
static BOOL membarrier_exp_available;
static pthread_once_t membarrier_init_once = PTHREAD_ONCE_INIT;
@@ -5181,6 +5189,66 @@ NTSTATUS WINAPI NtFlushInstructionCache( HANDLE handle, const void
*addr, SIZE_T
}
+#ifdef __APPLE__
+
+static void tgrpvs_init( void )
+{
+ p_thread_get_register_pointer_values = dlsym( RTLD_DEFAULT,
"thread_get_register_pointer_values" );
+}
+
+static BOOL try_mach_tgrpvs( void )
+{
+ /* Taken from
https://github.com/dotnet/runtime/blob/7be37908e5a1cbb83b1062768c1649827eea…
*/
+ mach_msg_type_number_t count, i = 0;
+ thread_act_array_t threads;
+ kern_return_t kret;
+ BOOL success = FALSE;
+
+ pthread_once(&tgrpvs_init_once, tgrpvs_init);
+ if (!p_thread_get_register_pointer_values)
+ return FALSE;
+
+ /* Get references to all threads of this process */
+ kret = task_threads( mach_task_self(), &threads, &count );
+ if (kret)
+ return FALSE;
+
+ /* Iterate through the threads in the list */
+ while (i < count)
+ {
+ uintptr_t reg_values[128];
+ size_t reg_count = ARRAY_SIZE( reg_values );
+ uintptr_t sp;
+
+ /* Request the thread's register pointer values to force the thread to go
through a memory barrier */
+ kret = p_thread_get_register_pointer_values( threads[i], &sp, ®_count,
reg_values );
+ /* This function always fails when querying Rosetta's exception handling
thread, so we only treat
+ KERN_INSUFFICIENT_BUFFER_SIZE as an error, like .NET core does. */
+ if (kret == KERN_INSUFFICIENT_BUFFER_SIZE)
+ goto fail;
+
+ /* Deallocate thread reference once we're done with it */
+ kret = mach_port_deallocate( mach_task_self(), threads[i++] );
+ if (kret)
+ goto fail;
+ }
+ success = TRUE;
+fail:
+ /* Deallocate remaining thread references */
+ while (i < count)
+ mach_port_deallocate( mach_task_self(), threads[i++] );
+ /* Deallocate thread list */
+ vm_deallocate( mach_task_self(), (vm_address_t)threads, count * sizeof(threads[0])
);
+ return success;
+}
+
+#else /* defined(__APPLE__) */
+
+static BOOL try_mach_tgrpvs( void ) { return 0; }
+
+#endif /* defined(__APPLE__) */
+
+
#if defined(__linux__) && defined(__NR_membarrier)
#define MEMBARRIER_CMD_QUERY 0x00
@@ -5269,6 +5337,8 @@ failed:
void WINAPI NtFlushProcessWriteBuffers(void)
{
static int once = 0;
+ if (try_mach_tgrpvs())
+ return;
if (try_exp_membarrier())
return;
if (try_madvise())
--
GitLab
https://gitlab.winehq.org/wine/wine/-/merge_requests/741