|
23 | 23 | #include "volatile.h" |
24 | 24 | #include "gcconfig.h" |
25 | 25 | #include "numasupport.h" |
| 26 | +#include <minipal/memorybarrierprocesswide.h> |
26 | 27 | #include <minipal/thread.h> |
27 | 28 | #include <minipal/time.h> |
28 | 29 |
|
29 | 30 | #if HAVE_SWAPCTL |
30 | 31 | #include <sys/swap.h> |
31 | 32 | #endif |
32 | 33 |
|
33 | | -#ifdef __linux__ |
34 | | -#include <linux/membarrier.h> |
35 | | -#include <sys/syscall.h> |
36 | | -#define membarrier(...) syscall(__NR_membarrier, __VA_ARGS__) |
37 | | -#elif HAVE_SYS_MEMBARRIER_H |
38 | | -#include <sys/membarrier.h> |
39 | | -#ifdef TARGET_BROWSER |
40 | | -#define membarrier(cmd, flags, cpu_id) 0 // browser/wasm is currently single threaded |
41 | | -#endif |
42 | | -#endif |
43 | | - |
44 | 34 | #include <sys/resource.h> |
45 | 35 |
|
46 | 36 | #undef min |
|
85 | 75 |
|
86 | 76 | #include <mach/task.h> |
87 | 77 | #include <mach/vm_map.h> |
88 | | -extern "C" |
89 | | -{ |
90 | | -# include <mach/thread_state.h> |
91 | | -} |
92 | | - |
93 | | -#define CHECK_MACH(_msg, machret) do { \ |
94 | | - if (machret != KERN_SUCCESS) \ |
95 | | - { \ |
96 | | - char _szError[1024]; \ |
97 | | - snprintf(_szError, ARRAY_SIZE(_szError), "%s: %u: %s", __FUNCTION__, __LINE__, _msg); \ |
98 | | - mach_error(_szError, machret); \ |
99 | | - abort(); \ |
100 | | - } \ |
101 | | - } while (false) |
102 | | - |
103 | 78 | #endif // __APPLE__ |
104 | 79 |
|
105 | 80 | #ifdef __HAIKU__ |
@@ -140,48 +115,6 @@ typedef cpuset_t cpu_set_t; |
140 | 115 | // The cached total number of CPUs that can be used in the OS. |
141 | 116 | static uint32_t g_totalCpuCount = 0; |
142 | 117 |
|
143 | | -bool CanFlushUsingMembarrier() |
144 | | -{ |
145 | | -#if defined(__linux__) || HAVE_SYS_MEMBARRIER_H |
146 | | - |
147 | | -#ifdef TARGET_ANDROID |
148 | | - // Avoid calling membarrier on older Android versions where membarrier |
149 | | - // may be barred by seccomp causing the process to be killed. |
150 | | - int apiLevel = android_get_device_api_level(); |
151 | | - if (apiLevel < __ANDROID_API_Q__) |
152 | | - { |
153 | | - return false; |
154 | | - } |
155 | | -#endif |
156 | | - |
157 | | - // Starting with Linux kernel 4.14, process memory barriers can be generated |
158 | | - // using MEMBARRIER_CMD_PRIVATE_EXPEDITED. |
159 | | - |
160 | | - int mask = membarrier(MEMBARRIER_CMD_QUERY, 0, 0); |
161 | | - |
162 | | - if (mask >= 0 && |
163 | | - mask & MEMBARRIER_CMD_PRIVATE_EXPEDITED && |
164 | | - // Register intent to use the private expedited command. |
165 | | - membarrier(MEMBARRIER_CMD_REGISTER_PRIVATE_EXPEDITED, 0, 0) == 0) |
166 | | - { |
167 | | - return true; |
168 | | - } |
169 | | -#endif |
170 | | - |
171 | | - return false; |
172 | | -} |
173 | | - |
174 | | -// |
175 | | -// Tracks if the OS supports FlushProcessWriteBuffers using membarrier |
176 | | -// |
177 | | -static int s_flushUsingMemBarrier = 0; |
178 | | - |
179 | | -// Helper memory page used by the FlushProcessWriteBuffers |
180 | | -static uint8_t* g_helperPage = 0; |
181 | | - |
182 | | -// Mutex to make the FlushProcessWriteBuffersMutex thread safe |
183 | | -static pthread_mutex_t g_flushProcessWriteBuffersMutex; |
184 | | - |
185 | 118 | size_t GetRestrictedPhysicalMemoryLimit(); |
186 | 119 | bool GetPhysicalMemoryUsed(size_t* val); |
187 | 120 |
|
@@ -219,50 +152,10 @@ bool GCToOSInterface::Initialize() |
219 | 152 |
|
220 | 153 | g_totalCpuCount = cpuCount; |
221 | 154 |
|
222 | | - // |
223 | | - // support for FlusProcessWriteBuffers |
224 | | - // |
225 | | -#ifndef TARGET_WASM |
226 | | - assert(s_flushUsingMemBarrier == 0); |
227 | | - |
228 | | - if (CanFlushUsingMembarrier()) |
229 | | - { |
230 | | - s_flushUsingMemBarrier = TRUE; |
231 | | - } |
232 | | -#ifndef TARGET_APPLE |
233 | | - else |
| 155 | + if (!minipal_initialize_memory_barrier_process_wide()) |
234 | 156 | { |
235 | | - assert(g_helperPage == 0); |
236 | | - |
237 | | - g_helperPage = static_cast<uint8_t*>(mmap(0, OS_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0)); |
238 | | - |
239 | | - if (g_helperPage == MAP_FAILED) |
240 | | - { |
241 | | - return false; |
242 | | - } |
243 | | - |
244 | | - // Verify that the s_helperPage is really aligned to the g_SystemInfo.dwPageSize |
245 | | - assert((((size_t)g_helperPage) & (OS_PAGE_SIZE - 1)) == 0); |
246 | | - |
247 | | - // Locking the page ensures that it stays in memory during the two mprotect |
248 | | - // calls in the FlushProcessWriteBuffers below. If the page was unmapped between |
249 | | - // those calls, they would not have the expected effect of generating IPI. |
250 | | - int status = mlock(g_helperPage, OS_PAGE_SIZE); |
251 | | - |
252 | | - if (status != 0) |
253 | | - { |
254 | | - return false; |
255 | | - } |
256 | | - |
257 | | - status = pthread_mutex_init(&g_flushProcessWriteBuffersMutex, NULL); |
258 | | - if (status != 0) |
259 | | - { |
260 | | - munlock(g_helperPage, OS_PAGE_SIZE); |
261 | | - return false; |
262 | | - } |
| 157 | + return false; |
263 | 158 | } |
264 | | -#endif // !TARGET_APPLE |
265 | | -#endif // !TARGET_WASM |
266 | 159 |
|
267 | 160 | InitializeCGroup(); |
268 | 161 |
|
@@ -354,13 +247,6 @@ bool GCToOSInterface::Initialize() |
354 | 247 | // Shutdown the interface implementation |
355 | 248 | void GCToOSInterface::Shutdown() |
356 | 249 | { |
357 | | - int ret = munlock(g_helperPage, OS_PAGE_SIZE); |
358 | | - assert(ret == 0); |
359 | | - ret = pthread_mutex_destroy(&g_flushProcessWriteBuffersMutex); |
360 | | - assert(ret == 0); |
361 | | - |
362 | | - munmap(g_helperPage, OS_PAGE_SIZE); |
363 | | - |
364 | 250 | CleanupCGroup(); |
365 | 251 | } |
366 | 252 |
|
@@ -410,91 +296,6 @@ bool GCToOSInterface::CanGetCurrentProcessorNumber() |
410 | 296 | return HAVE_SCHED_GETCPU; |
411 | 297 | } |
412 | 298 |
|
413 | | -// Flush write buffers of processors that are executing threads of the current process |
414 | | -void GCToOSInterface::FlushProcessWriteBuffers() |
415 | | -{ |
416 | | -#ifndef TARGET_WASM |
417 | | -#if defined(__linux__) || HAVE_SYS_MEMBARRIER_H |
418 | | - if (s_flushUsingMemBarrier) |
419 | | - { |
420 | | - int status = membarrier(MEMBARRIER_CMD_PRIVATE_EXPEDITED, 0, 0); |
421 | | - assert(status == 0 && "Failed to flush using membarrier"); |
422 | | - } |
423 | | - else |
424 | | -#endif |
425 | | - if (g_helperPage != 0) |
426 | | - { |
427 | | - int status = pthread_mutex_lock(&g_flushProcessWriteBuffersMutex); |
428 | | - assert(status == 0 && "Failed to lock the flushProcessWriteBuffersMutex lock"); |
429 | | - |
430 | | - // Changing a helper memory page protection from read / write to no access |
431 | | - // causes the OS to issue IPI to flush TLBs on all processors. This also |
432 | | - // results in flushing the processor buffers. |
433 | | - status = mprotect(g_helperPage, OS_PAGE_SIZE, PROT_READ | PROT_WRITE); |
434 | | - assert(status == 0 && "Failed to change helper page protection to read / write"); |
435 | | - |
436 | | - // Ensure that the page is dirty before we change the protection so that |
437 | | - // we prevent the OS from skipping the global TLB flush. |
438 | | - __sync_add_and_fetch((size_t*)g_helperPage, 1); |
439 | | - |
440 | | - status = mprotect(g_helperPage, OS_PAGE_SIZE, PROT_NONE); |
441 | | - assert(status == 0 && "Failed to change helper page protection to no access"); |
442 | | - |
443 | | - status = pthread_mutex_unlock(&g_flushProcessWriteBuffersMutex); |
444 | | - assert(status == 0 && "Failed to unlock the flushProcessWriteBuffersMutex lock"); |
445 | | - } |
446 | | -#ifdef TARGET_APPLE |
447 | | - else |
448 | | - { |
449 | | - mach_msg_type_number_t cThreads; |
450 | | - thread_act_t *pThreads; |
451 | | - kern_return_t machret = task_threads(mach_task_self(), &pThreads, &cThreads); |
452 | | - CHECK_MACH("task_threads()", machret); |
453 | | - |
454 | | - uintptr_t sp; |
455 | | - uintptr_t registerValues[128]; |
456 | | - |
457 | | - // Iterate through each of the threads in the list. |
458 | | - for (mach_msg_type_number_t i = 0; i < cThreads; i++) |
459 | | - { |
460 | | - if (__builtin_available (macOS 10.14, iOS 12, tvOS 9, *)) |
461 | | - { |
462 | | - // Request the threads pointer values to force the thread to emit a memory barrier |
463 | | - size_t registers = 128; |
464 | | - machret = thread_get_register_pointer_values(pThreads[i], &sp, ®isters, registerValues); |
465 | | - } |
466 | | - else |
467 | | - { |
468 | | - // fallback implementation for older OS versions |
469 | | -#if defined(HOST_AMD64) |
470 | | - x86_thread_state64_t threadState; |
471 | | - mach_msg_type_number_t count = x86_THREAD_STATE64_COUNT; |
472 | | - machret = thread_get_state(pThreads[i], x86_THREAD_STATE64, (thread_state_t)&threadState, &count); |
473 | | -#elif defined(HOST_ARM64) |
474 | | - arm_thread_state64_t threadState; |
475 | | - mach_msg_type_number_t count = ARM_THREAD_STATE64_COUNT; |
476 | | - machret = thread_get_state(pThreads[i], ARM_THREAD_STATE64, (thread_state_t)&threadState, &count); |
477 | | -#else |
478 | | - #error Unexpected architecture |
479 | | -#endif |
480 | | - } |
481 | | - |
482 | | - if (machret == KERN_INSUFFICIENT_BUFFER_SIZE) |
483 | | - { |
484 | | - CHECK_MACH("thread_get_register_pointer_values()", machret); |
485 | | - } |
486 | | - |
487 | | - machret = mach_port_deallocate(mach_task_self(), pThreads[i]); |
488 | | - CHECK_MACH("mach_port_deallocate()", machret); |
489 | | - } |
490 | | - // Deallocate the thread list now we're done with it. |
491 | | - machret = vm_deallocate(mach_task_self(), (vm_address_t)pThreads, cThreads * sizeof(thread_act_t)); |
492 | | - CHECK_MACH("vm_deallocate()", machret); |
493 | | - } |
494 | | -#endif // TARGET_APPLE |
495 | | -#endif // !TARGET_WASM |
496 | | -} |
497 | | - |
498 | 299 | // Break into a debugger. Uses a compiler intrinsic if one is available, |
499 | 300 | // otherwise raises a SIGTRAP. |
500 | 301 | void GCToOSInterface::DebugBreak() |
|
0 commit comments