1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
15 #include "gcenv.structs.h"
16 #include "gcenv.base.h"
18 #include "gcenv.unix.inl"
24 #error "sys/time.h required by GC PAL for the time being"
25 #endif // HAVE_SYS_TIME_
30 #error "sys/mman.h required by GC PAL"
31 #endif // HAVE_SYS_MMAN_H
34 #include <sys/syscall.h>
37 #include <time.h> // nanosleep
38 #include <sched.h> // sched_yield
40 #include <unistd.h> // sysconf
44 #if defined(_ARM_) || defined(_ARM64_)
45 #define SYSCONF_GET_NUMPROCS _SC_NPROCESSORS_CONF
47 #define SYSCONF_GET_NUMPROCS _SC_NPROCESSORS_ONLN
50 // The cached number of logical CPUs observed.
51 static uint32_t g_logicalCpuCount = 0;
53 // The cached number of CPUs available for the current process.
54 static uint32_t g_currentProcessCpuCount = 0;
56 // Helper memory page used by the FlushProcessWriteBuffers
57 static uint8_t* g_helperPage = 0;
59 // Mutex to make the FlushProcessWriteBuffersMutex thread safe
60 static pthread_mutex_t g_flushProcessWriteBuffersMutex;
62 size_t GetRestrictedPhysicalMemoryLimit();
63 bool GetPhysicalMemoryUsed(size_t* val);
64 bool GetCpuLimit(uint32_t* val);
66 static size_t g_RestrictedPhysicalMemoryLimit = 0;
68 uint32_t g_pageSizeUnixInl = 0;
70 AffinitySet g_processAffinitySet;
72 // Initialize the interface implementation
74 // true if it has succeeded, false if it has failed
75 bool GCToOSInterface::Initialize()
77 int pageSize = sysconf( _SC_PAGE_SIZE );
79 g_pageSizeUnixInl = uint32_t((pageSize > 0) ? pageSize : 0x1000);
81 // Calculate and cache the number of processors on this machine
82 int cpuCount = sysconf(SYSCONF_GET_NUMPROCS);
88 g_logicalCpuCount = cpuCount;
90 assert(g_helperPage == 0);
92 g_helperPage = static_cast<uint8_t*>(mmap(0, OS_PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0));
94 if(g_helperPage == MAP_FAILED)
99 // Verify that the s_helperPage is really aligned to the g_SystemInfo.dwPageSize
100 assert((((size_t)g_helperPage) & (OS_PAGE_SIZE - 1)) == 0);
102 // Locking the page ensures that it stays in memory during the two mprotect
103 // calls in the FlushProcessWriteBuffers below. If the page was unmapped between
104 // those calls, they would not have the expected effect of generating IPI.
105 int status = mlock(g_helperPage, OS_PAGE_SIZE);
112 status = pthread_mutex_init(&g_flushProcessWriteBuffersMutex, NULL);
115 munlock(g_helperPage, OS_PAGE_SIZE);
119 #if HAVE_MACH_ABSOLUTE_TIME
120 kern_return_t machRet;
121 if ((machRet = mach_timebase_info(&g_TimebaseInfo)) != KERN_SUCCESS)
125 #endif // HAVE_MACH_ABSOLUTE_TIME
129 #if HAVE_SCHED_GETAFFINITY
131 g_currentProcessCpuCount = 0;
134 int st = sched_getaffinity(0, sizeof(cpu_set_t), &cpuSet);
138 for (size_t i = 0; i < g_logicalCpuCount; i++)
140 if (CPU_ISSET(i, &cpuSet))
142 g_currentProcessCpuCount++;
143 g_processAffinitySet.Add(i);
149 // We should not get any of the errors that the sched_getaffinity can return since none
150 // of them applies for the current thread, so this is an unexpected kind of failure.
154 #else // HAVE_SCHED_GETAFFINITY
156 g_currentProcessCpuCount = g_logicalCpuCount;
158 for (size_t i = 0; i < g_logicalCpuCount; i++)
160 g_processAffinitySet.Add(i);
163 #endif // HAVE_SCHED_GETAFFINITY
168 // Shutdown the interface implementation
169 void GCToOSInterface::Shutdown()
171 int ret = munlock(g_helperPage, OS_PAGE_SIZE);
173 ret = pthread_mutex_destroy(&g_flushProcessWriteBuffersMutex);
176 munmap(g_helperPage, OS_PAGE_SIZE);
181 // Get numeric id of the current thread if possible on the
182 // current platform. It is indended for logging purposes only.
184 // Numeric id of the current thread, as best we can retrieve it.
185 uint64_t GCToOSInterface::GetCurrentThreadIdForLogging()
187 #if defined(__linux__)
188 return (uint64_t)syscall(SYS_gettid);
189 #elif HAVE_PTHREAD_GETTHREADID_NP
190 return (uint64_t)pthread_getthreadid_np();
191 #elif HAVE_PTHREAD_THREADID_NP
192 unsigned long long tid;
193 pthread_threadid_np(pthread_self(), &tid);
194 return (uint64_t)tid;
196 // Fallback in case we don't know how to get integer thread id on the current platform
197 return (uint64_t)pthread_self();
201 // Get the process ID of the process.
202 uint32_t GCToOSInterface::GetCurrentProcessId()
207 // Set ideal processor for the current thread
209 // srcProcNo - processor number the thread currently runs on
210 // dstProcNo - processor number the thread should be migrated to
212 // true if it has succeeded, false if it has failed
213 bool GCToOSInterface::SetCurrentThreadIdealAffinity(uint16_t srcProcNo, uint16_t dstProcNo)
215 return GCToOSInterface::SetThreadAffinity(dstProcNo);
218 // Get the number of the current processor
219 uint32_t GCToOSInterface::GetCurrentProcessorNumber()
221 #if HAVE_SCHED_GETCPU
222 int processorNumber = sched_getcpu();
223 assert(processorNumber != -1);
224 return processorNumber;
230 // Check if the OS supports getting current processor number
231 bool GCToOSInterface::CanGetCurrentProcessorNumber()
233 return HAVE_SCHED_GETCPU;
236 // Flush write buffers of processors that are executing threads of the current process
237 void GCToOSInterface::FlushProcessWriteBuffers()
239 int status = pthread_mutex_lock(&g_flushProcessWriteBuffersMutex);
240 assert(status == 0 && "Failed to lock the flushProcessWriteBuffersMutex lock");
242 // Changing a helper memory page protection from read / write to no access
243 // causes the OS to issue IPI to flush TLBs on all processors. This also
244 // results in flushing the processor buffers.
245 status = mprotect(g_helperPage, OS_PAGE_SIZE, PROT_READ | PROT_WRITE);
246 assert(status == 0 && "Failed to change helper page protection to read / write");
248 // Ensure that the page is dirty before we change the protection so that
249 // we prevent the OS from skipping the global TLB flush.
250 __sync_add_and_fetch((size_t*)g_helperPage, 1);
252 status = mprotect(g_helperPage, OS_PAGE_SIZE, PROT_NONE);
253 assert(status == 0 && "Failed to change helper page protection to no access");
255 status = pthread_mutex_unlock(&g_flushProcessWriteBuffersMutex);
256 assert(status == 0 && "Failed to unlock the flushProcessWriteBuffersMutex lock");
259 // Break into a debugger. Uses a compiler intrinsic if one is available,
260 // otherwise raises a SIGTRAP.
261 void GCToOSInterface::DebugBreak()
263 // __has_builtin is only defined by clang. GCC doesn't have a debug
264 // trap intrinsic anyway.
265 #ifndef __has_builtin
266 #define __has_builtin(x) 0
267 #endif // __has_builtin
269 #if __has_builtin(__builtin_debugtrap)
270 __builtin_debugtrap();
276 // Causes the calling thread to sleep for the specified number of milliseconds
278 // sleepMSec - time to sleep before switching to another thread
279 void GCToOSInterface::Sleep(uint32_t sleepMSec)
287 requested.tv_sec = sleepMSec / tccSecondsToMilliSeconds;
288 requested.tv_nsec = (sleepMSec - requested.tv_sec * tccSecondsToMilliSeconds) * tccMilliSecondsToNanoSeconds;
291 while (nanosleep(&requested, &remaining) == EINTR)
293 requested = remaining;
297 // Causes the calling thread to yield execution to another thread that is ready to run on the current processor.
299 // switchCount - number of times the YieldThread was called in a loop
300 void GCToOSInterface::YieldThread(uint32_t switchCount)
302 int ret = sched_yield();
304 // sched_yield never fails on Linux, unclear about other OSes
308 // Reserve virtual memory range.
310 // size - size of the virtual memory range
311 // alignment - requested memory alignment, 0 means no specific alignment requested
312 // flags - flags to control special settings like write watching
314 // Starting virtual address of the reserved range
315 void* GCToOSInterface::VirtualReserve(size_t size, size_t alignment, uint32_t flags)
317 assert(!(flags & VirtualReserveFlags::WriteWatch) && "WriteWatch not supported on Unix");
320 alignment = OS_PAGE_SIZE;
323 size_t alignedSize = size + (alignment - OS_PAGE_SIZE);
324 void * pRetVal = mmap(nullptr, alignedSize, PROT_NONE, MAP_ANON | MAP_PRIVATE, -1, 0);
328 void * pAlignedRetVal = (void *)(((size_t)pRetVal + (alignment - 1)) & ~(alignment - 1));
329 size_t startPadding = (size_t)pAlignedRetVal - (size_t)pRetVal;
330 if (startPadding != 0)
332 int ret = munmap(pRetVal, startPadding);
336 size_t endPadding = alignedSize - (startPadding + size);
339 int ret = munmap((void *)((size_t)pAlignedRetVal + size), endPadding);
343 pRetVal = pAlignedRetVal;
349 // Release virtual memory range previously reserved using VirtualReserve
351 // address - starting virtual address
352 // size - size of the virtual memory range
354 // true if it has succeeded, false if it has failed
355 bool GCToOSInterface::VirtualRelease(void* address, size_t size)
357 int ret = munmap(address, size);
362 // Commit virtual memory range. It must be part of a range reserved using VirtualReserve.
364 // address - starting virtual address
365 // size - size of the virtual memory range
367 // true if it has succeeded, false if it has failed
368 bool GCToOSInterface::VirtualCommit(void* address, size_t size, uint16_t node)
370 assert(node == NUMA_NODE_UNDEFINED && "Numa allocation is not ported to local GC on unix yet");
371 return mprotect(address, size, PROT_WRITE | PROT_READ) == 0;
374 // Decomit virtual memory range.
376 // address - starting virtual address
377 // size - size of the virtual memory range
379 // true if it has succeeded, false if it has failed
380 bool GCToOSInterface::VirtualDecommit(void* address, size_t size)
382 // TODO: This can fail, however the GC does not handle the failure gracefully
383 // Explicitly calling mmap instead of mprotect here makes it
384 // that much more clear to the operating system that we no
385 // longer need these pages. Also, GC depends on re-commited pages to
387 return mmap(address, size, PROT_NONE, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0) != NULL;
390 // Reset virtual memory range. Indicates that data in the memory range specified by address and size is no
391 // longer of interest, but it should not be decommitted.
393 // address - starting virtual address
394 // size - size of the virtual memory range
395 // unlock - true if the memory range should also be unlocked
397 // true if it has succeeded, false if it has failed
398 bool GCToOSInterface::VirtualReset(void * address, size_t size, bool unlock)
402 // Try to use MADV_FREE if supported. It tells the kernel that the application doesn't
403 // need the pages in the range. Freeing the pages can be delayed until a memory pressure
405 st = madvise(address, size, MADV_FREE);
409 // In case the MADV_FREE is not supported, use MADV_DONTNEED
410 st = madvise(address, size, MADV_DONTNEED);
416 // Check if the OS supports write watching
417 bool GCToOSInterface::SupportsWriteWatch()
422 // Reset the write tracking state for the specified virtual memory range.
424 // address - starting virtual address
425 // size - size of the virtual memory range
426 void GCToOSInterface::ResetWriteWatch(void* address, size_t size)
428 assert(!"should never call ResetWriteWatch on Unix");
431 // Retrieve addresses of the pages that are written to in a region of virtual memory
433 // resetState - true indicates to reset the write tracking state
434 // address - starting virtual address
435 // size - size of the virtual memory range
436 // pageAddresses - buffer that receives an array of page addresses in the memory region
437 // pageAddressesCount - on input, size of the lpAddresses array, in array elements
438 // on output, the number of page addresses that are returned in the array.
440 // true if it has succeeded, false if it has failed
441 bool GCToOSInterface::GetWriteWatch(bool resetState, void* address, size_t size, void** pageAddresses, uintptr_t* pageAddressesCount)
443 assert(!"should never call GetWriteWatch on Unix");
447 // Get size of the largest cache on the processor die
449 // trueSize - true to return true cache size, false to return scaled up size based on
450 // the processor architecture
453 size_t GCToOSInterface::GetCacheSizePerLogicalCpu(bool trueSize)
455 // TODO(segilles) processor detection
459 // Sets the calling thread's affinity to only run on the processor specified
461 // procNo - The requested processor for the calling thread.
463 // true if setting the affinity was successful, false otherwise.
464 bool GCToOSInterface::SetThreadAffinity(uint16_t procNo)
466 #if HAVE_PTHREAD_GETAFFINITY_NP
469 CPU_SET((int)procNo, &cpuSet);
471 int st = pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuSet);
475 #else // HAVE_PTHREAD_GETAFFINITY_NP
476 // There is no API to manage thread affinity, so let's ignore the request
478 #endif // HAVE_PTHREAD_GETAFFINITY_NP
481 // Boosts the calling thread's thread priority to a level higher than the default
486 // true if the priority boost was successful, false otherwise.
487 bool GCToOSInterface::BoostThreadPriority()
489 // [LOCALGC TODO] Thread priority for unix
493 // Set the set of processors enabled for GC threads for the current process based on config specified affinity mask and set
495 // configAffinityMask - mask specified by the GCHeapAffinitizeMask config
496 // configAffinitySet - affinity set specified by the GCHeapAffinitizeRanges config
498 // set of enabled processors
499 const AffinitySet* GCToOSInterface::SetGCThreadsAffinitySet(uintptr_t configAffinityMask, const AffinitySet* configAffinitySet)
501 if (!configAffinitySet->IsEmpty())
503 // Update the process affinity set using the configured set
504 for (size_t i = 0; i < MAX_SUPPORTED_CPUS; i++)
506 if (g_processAffinitySet.Contains(i) && !configAffinitySet->Contains(i))
508 g_processAffinitySet.Remove(i);
513 return &g_processAffinitySet;
516 // Get number of processors assigned to the current process
518 // The number of processors
519 uint32_t GCToOSInterface::GetCurrentProcessCpuCount()
521 return g_currentProcessCpuCount;
524 // Return the size of the user-mode portion of the virtual address space of this process.
526 // non zero if it has succeeded, 0 if it has failed
527 size_t GCToOSInterface::GetVirtualMemoryLimit()
530 // There is no API to get the total virtual address space size on
531 // Unix, so we use a constant value representing 128TB, which is
532 // the approximate size of total user virtual address space on
533 // the currently supported Unix systems.
534 static const uint64_t _128TB = (1ull << 47);
541 // Get the physical memory that this process can use.
543 // non zero if it has succeeded, 0 if it has failed
545 // If a process runs with a restricted memory limit, it returns the limit. If there's no limit
546 // specified, it returns amount of actual physical memory.
547 uint64_t GCToOSInterface::GetPhysicalMemoryLimit(bool* is_restricted)
549 size_t restricted_limit;
551 *is_restricted = false;
553 // The limit was not cached
554 if (g_RestrictedPhysicalMemoryLimit == 0)
556 restricted_limit = GetRestrictedPhysicalMemoryLimit();
557 VolatileStore(&g_RestrictedPhysicalMemoryLimit, restricted_limit);
559 restricted_limit = g_RestrictedPhysicalMemoryLimit;
561 if (restricted_limit != 0 && restricted_limit != SIZE_T_MAX)
564 *is_restricted = true;
565 return restricted_limit;
568 long pages = sysconf(_SC_PHYS_PAGES);
574 long pageSize = sysconf(_SC_PAGE_SIZE);
580 return pages * pageSize;
585 // memory_load - A number between 0 and 100 that specifies the approximate percentage of physical memory
586 // that is in use (0 indicates no memory use and 100 indicates full memory use).
587 // available_physical - The amount of physical memory currently available, in bytes.
588 // available_page_file - The maximum amount of memory the current process can commit, in bytes.
589 void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file)
591 if (memory_load != nullptr || available_physical != nullptr)
593 uint64_t total = GetPhysicalMemoryLimit();
595 uint64_t available = 0;
599 // Get the physical memory in use - from it, we can get the physical memory available.
600 // We do this only when we have the total physical memory available.
601 if (total > 0 && GetPhysicalMemoryUsed(&used))
603 available = total > used ? total-used : 0;
604 load = (uint32_t)(((float)used * 100) / (float)total);
607 if (memory_load != nullptr)
609 if (available_physical != nullptr)
610 *available_physical = available;
613 if (available_page_file != nullptr)
614 *available_page_file = 0;
617 // Get a high precision performance counter
620 int64_t GCToOSInterface::QueryPerformanceCounter()
622 // TODO: This is not a particularly efficient implementation - we certainly could
623 // do much more specific platform-dependent versions if we find that this method
624 // runs hot. However, most likely it does not.
626 if (gettimeofday(&tv, NULL) == -1)
628 assert(!"gettimeofday() failed");
629 // TODO (segilles) unconditional asserts
632 return (int64_t) tv.tv_sec * (int64_t) tccSecondsToMicroSeconds + (int64_t) tv.tv_usec;
635 // Get a frequency of the high precision performance counter
637 // The counter frequency
638 int64_t GCToOSInterface::QueryPerformanceFrequency()
640 // The counter frequency of gettimeofday is in microseconds.
641 return tccSecondsToMicroSeconds;
644 // Get a time stamp with a low precision
646 // Time stamp in milliseconds
647 uint32_t GCToOSInterface::GetLowPrecisionTimeStamp()
649 // TODO(segilles) this is pretty naive, we can do better
652 if (gettimeofday(&tv, NULL) == 0)
654 retval = (tv.tv_sec * tccSecondsToMilliSeconds) + (tv.tv_usec / tccMilliSecondsToMicroSeconds);
658 assert(!"gettimeofday() failed\n");
664 // Gets the total number of processors on the machine, not taking
665 // into account current process affinity.
667 // Number of processors on the machine
668 uint32_t GCToOSInterface::GetTotalProcessorCount()
670 // Calculated in GCToOSInterface::Initialize using
671 // sysconf(_SC_NPROCESSORS_ONLN)
672 return g_logicalCpuCount;
675 bool GCToOSInterface::CanEnableGCNumaAware()
680 bool GCToOSInterface::GetNumaProcessorNode(uint16_t proc_no, uint16_t *node_no)
682 assert(!"Numa has not been ported to local GC for unix");
686 // Get processor number and optionally its NUMA node number for the specified heap number
688 // heap_number - heap number to get the result for
689 // proc_no - set to the selected processor number
690 // node_no - set to the NUMA node of the selected processor or to NUMA_NODE_UNDEFINED
692 // true if it succeeded
693 bool GCToOSInterface::GetProcessorForHeap(uint16_t heap_number, uint16_t* proc_no, uint16_t* node_no)
695 bool success = false;
697 uint16_t availableProcNumber = 0;
698 for (size_t procNumber = 0; procNumber < g_logicalCpuCount; procNumber++)
700 if (g_processAffinitySet.Contains(procNumber))
702 if (availableProcNumber == heap_number)
704 *proc_no = procNumber;
706 if (GCToOSInterface::CanEnableGCNumaAware())
708 if (!GCToOSInterface::GetNumaProcessorNode(procNumber, node_no))
710 *node_no = NUMA_NODE_UNDEFINED;
715 *node_no = NUMA_NODE_UNDEFINED;
721 availableProcNumber++;
728 // Initialize the critical section
729 void CLRCriticalSection::Initialize()
731 int st = pthread_mutex_init(&m_cs.mutex, NULL);
735 // Destroy the critical section
736 void CLRCriticalSection::Destroy()
738 int st = pthread_mutex_destroy(&m_cs.mutex);
742 // Enter the critical section. Blocks until the section can be entered.
743 void CLRCriticalSection::Enter()
745 pthread_mutex_lock(&m_cs.mutex);
748 // Leave the critical section
749 void CLRCriticalSection::Leave()
751 pthread_mutex_unlock(&m_cs.mutex);