From 262d44875080ff7421b314f7c6f580a92e471701 Mon Sep 17 00:00:00 2001 From: Steve MacLean Date: Thu, 17 Dec 2020 16:01:46 -0500 Subject: [PATCH] Implement FlushProcessWriteBuffers for macos-arm64 (#44670) --- src/coreclr/gc/unix/gcenv.unix.cpp | 51 +++++++++++++++++++++++++++++++- src/coreclr/pal/src/thread/process.cpp | 54 ++++++++++++++++++++++++++++++++-- 2 files changed, 102 insertions(+), 3 deletions(-) diff --git a/src/coreclr/gc/unix/gcenv.unix.cpp b/src/coreclr/gc/unix/gcenv.unix.cpp index e6b4fc7..4a3c583 100644 --- a/src/coreclr/gc/unix/gcenv.unix.cpp +++ b/src/coreclr/gc/unix/gcenv.unix.cpp @@ -66,6 +66,26 @@ #include #include #include + +#if defined(HOST_ARM64) +#include +#include +extern "C" +{ +# include +} + +#define CHECK_MACH(_msg, machret) do { \ + if (machret != KERN_SUCCESS) \ + { \ + char _szError[1024]; \ + snprintf(_szError, _countof(_szError), "%s: %u: %s", __FUNCTION__, __LINE__, _msg); \ + mach_error(_szError, machret); \ + abort(); \ + } \ + } while (false) +#endif // defined(HOST_ARM64) + #endif // __APPLE__ #ifdef __linux__ @@ -340,6 +360,7 @@ bool GCToOSInterface::Initialize() { s_flushUsingMemBarrier = TRUE; } +#if !(defined(TARGET_OSX) && defined(HOST_ARM64)) else { assert(g_helperPage == 0); @@ -371,6 +392,7 @@ bool GCToOSInterface::Initialize() return false; } } +#endif // !(defined(TARGET_OSX) && defined(HOST_ARM64)) InitializeCGroup(); @@ -500,7 +522,7 @@ void GCToOSInterface::FlushProcessWriteBuffers() int status = membarrier(MEMBARRIER_CMD_PRIVATE_EXPEDITED, 0); assert(status == 0 && "Failed to flush using membarrier"); } - else + else if (g_helperPage != 0) { int status = pthread_mutex_lock(&g_flushProcessWriteBuffersMutex); assert(status == 0 && "Failed to lock the flushProcessWriteBuffersMutex lock"); @@ -521,6 +543,33 @@ void GCToOSInterface::FlushProcessWriteBuffers() status = pthread_mutex_unlock(&g_flushProcessWriteBuffersMutex); assert(status == 0 && "Failed to unlock the flushProcessWriteBuffersMutex lock"); } +#if defined(TARGET_OSX) && defined(HOST_ARM64) + else + { + mach_msg_type_number_t cThreads; + thread_act_t *pThreads; + kern_return_t machret = task_threads(mach_task_self(), &pThreads, &cThreads); + CHECK_MACH("task_threads()", machret); + + uintptr_t sp; + uintptr_t registerValues[128]; + + // Iterate through each of the threads in the list. + for (mach_msg_type_number_t i = 0; i < cThreads; i++) + { + // Request the threads pointer values to force the thread to emit a memory barrier + size_t registers = 128; + machret = thread_get_register_pointer_values(pThreads[i], &sp, ®isters, registerValues); + if (machret == KERN_INSUFFICIENT_BUFFER_SIZE) + { + CHECK_MACH("thread_get_register_pointer_values()", machret); + } + } + // Deallocate the thread list now we're done with it. + machret = vm_deallocate(mach_task_self(), (vm_address_t)pThreads, cThreads * sizeof(thread_act_t)); + CHECK_MACH("vm_deallocate()", machret); + } +#endif // defined(TARGET_OSX) && defined(HOST_ARM64) } // Break into a debugger. Uses a compiler intrinsic if one is available, diff --git a/src/coreclr/pal/src/thread/process.cpp b/src/coreclr/pal/src/thread/process.cpp index a5253ca..1628fd5 100644 --- a/src/coreclr/pal/src/thread/process.cpp +++ b/src/coreclr/pal/src/thread/process.cpp @@ -83,7 +83,26 @@ SET_DEFAULT_DEBUG_CHANNEL(PROCESS); // some headers have code with asserts, so d #include #include #include -#endif +#if defined(HOST_ARM64) +#include +#include +extern "C" +{ +# include +} + +#define CHECK_MACH(_msg, machret) do { \ + if (machret != KERN_SUCCESS) \ + { \ + char _szError[1024]; \ + snprintf(_szError, _countof(_szError), "%s: %u: %s", __FUNCTION__, __LINE__, _msg); \ + mach_error(_szError, machret); \ + abort(); \ + } \ + } while (false) + +#endif // defined(HOST_ARM64) +#endif // __APPLE__ #ifdef __NetBSD__ #include @@ -3348,6 +3367,9 @@ InitializeFlushProcessWriteBuffers() } } +#if defined(TARGET_OSX) && defined(HOST_ARM64) + return TRUE; +#else s_helperPage = static_cast(mmap(0, GetVirtualPageSize(), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)); if(s_helperPage == MAP_FAILED) @@ -3375,6 +3397,7 @@ InitializeFlushProcessWriteBuffers() } return status == 0; +#endif // defined(TARGET_OSX) && defined(HOST_ARM64) } #define FATAL_ASSERT(e, msg) \ @@ -3403,7 +3426,7 @@ FlushProcessWriteBuffers() int status = membarrier(MEMBARRIER_CMD_PRIVATE_EXPEDITED, 0); FATAL_ASSERT(status == 0, "Failed to flush using membarrier"); } - else + else if (s_helperPage != 0) { int status = pthread_mutex_lock(&flushProcessWriteBuffersMutex); FATAL_ASSERT(status == 0, "Failed to lock the flushProcessWriteBuffersMutex lock"); @@ -3424,6 +3447,33 @@ FlushProcessWriteBuffers() status = pthread_mutex_unlock(&flushProcessWriteBuffersMutex); FATAL_ASSERT(status == 0, "Failed to unlock the flushProcessWriteBuffersMutex lock"); } +#if defined(TARGET_OSX) && defined(HOST_ARM64) + else + { + mach_msg_type_number_t cThreads; + thread_act_t *pThreads; + kern_return_t machret = task_threads(mach_task_self(), &pThreads, &cThreads); + CHECK_MACH("task_threads()", machret); + + uintptr_t sp; + uintptr_t registerValues[128]; + + // Iterate through each of the threads in the list. + for (mach_msg_type_number_t i = 0; i < cThreads; i++) + { + // Request the threads pointer values to force the thread to emit a memory barrier + size_t registers = 128; + machret = thread_get_register_pointer_values(pThreads[i], &sp, ®isters, registerValues); + if (machret == KERN_INSUFFICIENT_BUFFER_SIZE) + { + CHECK_MACH("thread_get_register_pointer_values()", machret); + } + } + // Deallocate the thread list now we're done with it. + machret = vm_deallocate(mach_task_self(), (vm_address_t)pThreads, cThreads * sizeof(thread_act_t)); + CHECK_MACH("vm_deallocate()", machret); + } +#endif // defined(TARGET_OSX) && defined(HOST_ARM64) } /*++ -- 2.7.4