diff --git a/src/Native/Runtime/CMakeLists.txt b/src/Native/Runtime/CMakeLists.txt index ca3c4e4edc3..c0963fd4407 100644 --- a/src/Native/Runtime/CMakeLists.txt +++ b/src/Native/Runtime/CMakeLists.txt @@ -125,6 +125,7 @@ if(WIN32) list(APPEND COMMON_RUNTIME_SOURCES windows/PalRedhawkCommon.cpp windows/PalRedhawkMinWin.cpp + ../gc/windows/gcenv.windows.cpp eventtrace.cpp rheventtrace.cpp ) @@ -149,6 +150,12 @@ if(WIN32) else() include_directories(unix) + + include(CheckIncludeFiles) + include(CheckLibraryExists) + + include(../gc/unix/configure.cmake) + if(NOT CLR_CMAKE_PLATFORM_ARCH_WASM) include_directories(../libunwind/include) else() @@ -166,6 +173,9 @@ else() list(APPEND COMMON_RUNTIME_SOURCES unix/PalRedhawkUnix.cpp + ../gc/unix/gcenv.unix.cpp + ../gc/unix/events.cpp + ../gc/unix/cgroup.cpp ) list(APPEND FULL_RUNTIME_SOURCES diff --git a/src/Native/Runtime/PalRedhawk.h b/src/Native/Runtime/PalRedhawk.h index a13691ec11d..4993330bc52 100644 --- a/src/Native/Runtime/PalRedhawk.h +++ b/src/Native/Runtime/PalRedhawk.h @@ -661,7 +661,7 @@ EventDataDescCreate(_Out_ EVENT_DATA_DESCRIPTOR * EventDataDescriptor, _In_opt_ } #endif // _EVNTPROV_H_ -extern GCSystemInfo g_SystemInfo; +extern GCSystemInfo g_RhSystemInfo; #ifdef PLATFORM_UNIX #define REDHAWK_PALIMPORT extern "C" diff --git a/src/Native/Runtime/RWLock.cpp b/src/Native/Runtime/RWLock.cpp index a47d136536e..dee9306935b 100644 --- a/src/Native/Runtime/RWLock.cpp +++ b/src/Native/Runtime/RWLock.cpp @@ -176,7 +176,7 @@ void ReaderWriterLock::AcquireReadLockWorker() if (TryAcquireReadLock()) return; - if (g_SystemInfo.dwNumberOfProcessors <= 1) + if (g_RhSystemInfo.dwNumberOfProcessors <= 1) break; // Delay by approximately 2*i clock cycles (Pentium III). @@ -242,7 +242,7 @@ void ReaderWriterLock::AcquireWriteLock() RedhawkGCInterface::WaitForGCCompletion(); } - if (g_SystemInfo.dwNumberOfProcessors <= 1) + if (g_RhSystemInfo.dwNumberOfProcessors <= 1) { break; } diff --git a/src/Native/Runtime/gcrhenv.cpp b/src/Native/Runtime/gcrhenv.cpp index 85a44f5f3e9..e289b7bca8b 100644 --- a/src/Native/Runtime/gcrhenv.cpp +++ b/src/Native/Runtime/gcrhenv.cpp @@ -1630,209 +1630,3 @@ ProfilingScanContext::ProfilingScanContext(BOOL fProfilerPinnedParam) #endif } #endif // defined(FEATURE_EVENT_TRACE) && !defined(DACCESS_COMPILE) - -#if !defined(DACCESS_COMPILE) -// An implementatino of GCEvent that delegates to -// a CLREvent, which in turn delegates to the PAL. This event -// is also host-aware. -class GCEvent::Impl -{ -private: - CLREventStatic m_event; - -public: - Impl() = default; - - bool IsValid() - { - WRAPPER_NO_CONTRACT; - - return !!m_event.IsValid(); - } - - void CloseEvent() - { - WRAPPER_NO_CONTRACT; - - assert(m_event.IsValid()); - m_event.CloseEvent(); - } - - void Set() - { - WRAPPER_NO_CONTRACT; - - assert(m_event.IsValid()); - m_event.Set(); - } - - void Reset() - { - WRAPPER_NO_CONTRACT; - - assert(m_event.IsValid()); - m_event.Reset(); - } - - uint32_t Wait(uint32_t timeout, bool alertable) - { - WRAPPER_NO_CONTRACT; - - assert(m_event.IsValid()); - return m_event.Wait(timeout, alertable); - } - - bool CreateAutoEvent(bool initialState) - { - CONTRACTL{ - NOTHROW; - GC_NOTRIGGER; - } CONTRACTL_END; - - return !!m_event.CreateAutoEventNoThrow(initialState); - } - - bool CreateManualEvent(bool initialState) - { - CONTRACTL{ - NOTHROW; - GC_NOTRIGGER; - } CONTRACTL_END; - - return !!m_event.CreateManualEventNoThrow(initialState); - } - - bool CreateOSAutoEvent(bool initialState) - { - CONTRACTL{ - NOTHROW; - GC_NOTRIGGER; - } CONTRACTL_END; - - return !!m_event.CreateOSAutoEventNoThrow(initialState); - } - - bool CreateOSManualEvent(bool initialState) - { - CONTRACTL{ - NOTHROW; - GC_NOTRIGGER; - } CONTRACTL_END; - - return !!m_event.CreateOSManualEventNoThrow(initialState); - } -}; - -GCEvent::GCEvent() - : m_impl(nullptr) -{ -} - -void GCEvent::CloseEvent() -{ - WRAPPER_NO_CONTRACT; - - assert(m_impl != nullptr); - m_impl->CloseEvent(); -} - -void GCEvent::Set() -{ - WRAPPER_NO_CONTRACT; - - assert(m_impl != nullptr); - m_impl->Set(); -} - -void GCEvent::Reset() -{ - WRAPPER_NO_CONTRACT; - - assert(m_impl != nullptr); - m_impl->Reset(); -} - -uint32_t GCEvent::Wait(uint32_t timeout, bool alertable) -{ - WRAPPER_NO_CONTRACT; - - assert(m_impl != nullptr); - return m_impl->Wait(timeout, alertable); -} - -bool GCEvent::CreateManualEventNoThrow(bool initialState) -{ - CONTRACTL{ - NOTHROW; - GC_NOTRIGGER; - } CONTRACTL_END; - - assert(m_impl == nullptr); - NewHolder event = new (nothrow) GCEvent::Impl(); - if (!event) - { - return false; - } - - event->CreateManualEvent(initialState); - m_impl = event.Extract(); - return true; -} - -bool GCEvent::CreateAutoEventNoThrow(bool initialState) -{ - CONTRACTL{ - NOTHROW; - GC_NOTRIGGER; - } CONTRACTL_END; - - assert(m_impl == nullptr); - NewHolder event = new (nothrow) GCEvent::Impl(); - if (!event) - { - return false; - } - - event->CreateAutoEvent(initialState); - m_impl = event.Extract(); - return IsValid(); -} - -bool GCEvent::CreateOSAutoEventNoThrow(bool initialState) -{ - CONTRACTL{ - NOTHROW; - GC_NOTRIGGER; - } CONTRACTL_END; - - assert(m_impl == nullptr); - NewHolder event = new (nothrow) GCEvent::Impl(); - if (!event) - { - return false; - } - - event->CreateOSAutoEvent(initialState); - m_impl = event.Extract(); - return IsValid(); -} - -bool GCEvent::CreateOSManualEventNoThrow(bool initialState) -{ - CONTRACTL{ - NOTHROW; - GC_NOTRIGGER; - } CONTRACTL_END; - - assert(m_impl == nullptr); - NewHolder event = new (nothrow) GCEvent::Impl(); - if (!event) - { - return false; - } - - event->CreateOSManualEvent(initialState); - m_impl = event.Extract(); - return IsValid(); -} -#endif // !defined(DACCESS_COMPILE) diff --git a/src/Native/Runtime/threadstore.cpp b/src/Native/Runtime/threadstore.cpp index c940912c573..71e961b3652 100644 --- a/src/Native/Runtime/threadstore.cpp +++ b/src/Native/Runtime/threadstore.cpp @@ -276,7 +276,7 @@ void ThreadStore::SuspendAllThreads(bool waitForGCEvent, bool fireDebugEvent) if (keepWaiting) { - if (PalSwitchToThread() == 0 && g_SystemInfo.dwNumberOfProcessors > 1) + if (PalSwitchToThread() == 0 && g_RhSystemInfo.dwNumberOfProcessors > 1) { // No threads are scheduled on this processor. Perhaps we're waiting for a thread // that's scheduled on another processor. If so, let's give it a little time diff --git a/src/Native/Runtime/unix/PalRedhawkUnix.cpp b/src/Native/Runtime/unix/PalRedhawkUnix.cpp index 90d00378592..26549b1f4a7 100644 --- a/src/Native/Runtime/unix/PalRedhawkUnix.cpp +++ b/src/Native/Runtime/unix/PalRedhawkUnix.cpp @@ -1229,17 +1229,14 @@ REDHAWK_PALEXPORT Int32 PalGetModuleFileName(_Out_ const TCHAR** pModuleNameOut, #endif // defined(_WASM_) } -GCSystemInfo g_SystemInfo; - -uint32_t g_pageSizeUnixInl = 0; +GCSystemInfo g_RhSystemInfo; // Initialize the g_SystemInfo bool InitializeSystemInfo() { long pagesize = getpagesize(); - g_SystemInfo.dwPageSize = pagesize; - g_SystemInfo.dwAllocationGranularity = pagesize; - g_pageSizeUnixInl = pagesize; + g_RhSystemInfo.dwPageSize = pagesize; + g_RhSystemInfo.dwAllocationGranularity = pagesize; int nrcpus = 0; @@ -1264,7 +1261,7 @@ bool InitializeSystemInfo() } #endif // HAVE_SYSCONF - g_SystemInfo.dwNumberOfProcessors = nrcpus; + g_RhSystemInfo.dwNumberOfProcessors = nrcpus; return true; } @@ -1371,550 +1368,6 @@ extern "C" UInt64 PalGetCurrentThreadIdForLogging() #endif } -static AffinitySet g_processAffinitySet; - -static LARGE_INTEGER g_performanceFrequency; - -// Initialize the interface implementation -// Return: -// true if it has succeeded, false if it has failed -bool GCToOSInterface::Initialize() -{ - if (!::QueryPerformanceFrequency(&g_performanceFrequency)) - { - return false; - } - - for (size_t i = 0; i < g_cLogicalCpus; i++) - { - g_processAffinitySet.Add(i); - } - - return true; -} - -// Shutdown the interface implementation -void GCToOSInterface::Shutdown() -{ -} - -// Get numeric id of the current thread if possible on the -// current platform. It is indended for logging purposes only. -// Return: -// Numeric id of the current thread or 0 if the -uint64_t GCToOSInterface::GetCurrentThreadIdForLogging() -{ - return PalGetCurrentThreadIdForLogging(); -} - -// Get id of the process -uint32_t GCToOSInterface::GetCurrentProcessId() -{ - return ::GetCurrentProcessId(); -} - -// Set ideal processor for the current thread -// Parameters: -// srcProcNo - processor number the thread currently runs on -// dstProcNo - processor number the thread should be migrated to -// Return: -// true if it has succeeded, false if it has failed -bool GCToOSInterface::SetCurrentThreadIdealAffinity(uint16_t srcProcNo, uint16_t dstProcNo) -{ - // There is no way to set a thread ideal processor on Unix, so do nothing. - return true; -} - -// Get the number of the current processor -uint32_t GCToOSInterface::GetCurrentProcessorNumber() -{ - return PalGetCurrentProcessorNumber(); -} - -// Check if the OS supports getting current processor number -bool GCToOSInterface::CanGetCurrentProcessorNumber() -{ - return HAVE_SCHED_GETCPU; -} - -// Flush write buffers of processors that are executing threads of the current process -void GCToOSInterface::FlushProcessWriteBuffers() -{ - return ::FlushProcessWriteBuffers(); -} - -// Break into a debugger -void GCToOSInterface::DebugBreak() -{ - __debugbreak(); -} - -// Causes the calling thread to sleep for the specified number of milliseconds -// Parameters: -// sleepMSec - time to sleep before switching to another thread -void GCToOSInterface::Sleep(uint32_t sleepMSec) -{ - PalSleep(sleepMSec); -} - -// Causes the calling thread to yield execution to another thread that is ready to run on the current processor. -// Parameters: -// switchCount - number of times the YieldThread was called in a loop -void GCToOSInterface::YieldThread(uint32_t switchCount) -{ - PalSwitchToThread(); -} - -// Reserve virtual memory range. -// Parameters: -// size - size of the virtual memory range -// alignment - requested memory alignment, 0 means no specific alignment requested -// flags - flags to control special settings like write watching -// Return: -// Starting virtual address of the reserved range -static void* VirtualReserveInner(size_t size, size_t alignment, uint32_t flags, uint32_t hugePagesFlag = 0) -{ - ASSERT_MSG(!(flags & VirtualReserveFlags::WriteWatch), "WriteWatch not supported on Unix"); - - if (alignment == 0) - { - alignment = OS_PAGE_SIZE; - } - - size_t alignedSize = size + (alignment - OS_PAGE_SIZE); - - void* pRetVal = mmap(nullptr, alignedSize, PROT_NONE, MAP_ANON | MAP_PRIVATE | hugePagesFlag, -1, 0); - - if (pRetVal != NULL) - { - void * pAlignedRetVal = (void *)(((size_t)pRetVal + (alignment - 1)) & ~(alignment - 1)); - size_t startPadding = (size_t)pAlignedRetVal - (size_t)pRetVal; - if (startPadding != 0) - { - int ret = munmap(pRetVal, startPadding); - ASSERT(ret == 0); - } - - size_t endPadding = alignedSize - (startPadding + size); - if (endPadding != 0) - { - int ret = munmap((void *)((size_t)pAlignedRetVal + size), endPadding); - ASSERT(ret == 0); - } - - pRetVal = pAlignedRetVal; - } - - return pRetVal; -} - -// Reserve virtual memory range. -// Parameters: -// size - size of the virtual memory range -// alignment - requested memory alignment, 0 means no specific alignment requested -// flags - flags to control special settings like write watching -// Return: -// Starting virtual address of the reserved range -void* GCToOSInterface::VirtualReserve(size_t size, size_t alignment, uint32_t flags) -{ - return VirtualReserveInner(size, alignment, flags); -} - -// Release virtual memory range previously reserved using VirtualReserve -// Parameters: -// address - starting virtual address -// size - size of the virtual memory range -// Return: -// true if it has succeeded, false if it has failed -bool GCToOSInterface::VirtualRelease(void* address, size_t size) -{ - int ret = munmap(address, size); - - return (ret == 0); -} - -// Commit virtual memory range. -// Parameters: -// size - size of the virtual memory range -// Return: -// Starting virtual address of the committed range -void* GCToOSInterface::VirtualReserveAndCommitLargePages(size_t size) -{ -#if HAVE_MAP_HUGETLB - uint32_t largePagesFlag = MAP_HUGETLB; -#else - uint32_t largePagesFlag = 0; -#endif - - void* pRetVal = VirtualReserveInner(size, OS_PAGE_SIZE, 0, largePagesFlag); - if (VirtualCommit(pRetVal, size, NUMA_NODE_UNDEFINED)) - { - return pRetVal; - } - - return nullptr; -} - -// Commit virtual memory range. It must be part of a range reserved using VirtualReserve. -// Parameters: -// address - starting virtual address -// size - size of the virtual memory range -// Return: -// true if it has succeeded, false if it has failed -bool GCToOSInterface::VirtualCommit(void* address, size_t size, uint16_t node) -{ - UNREFERENCED_PARAMETER(node); // TODO: Numa support - return mprotect(address, size, PROT_WRITE | PROT_READ) == 0; -} - -// Decomit virtual memory range. -// Parameters: -// address - starting virtual address -// size - size of the virtual memory range -// Return: -// true if it has succeeded, false if it has failed -bool GCToOSInterface::VirtualDecommit(void* address, size_t size) -{ - // TODO: This can fail, however the GC does not handle the failure gracefully - // Explicitly calling mmap instead of mprotect here makes it - // that much more clear to the operating system that we no - // longer need these pages. Also, GC depends on re-commited pages to - // be zeroed-out. - return mmap(address, size, PROT_NONE, MAP_FIXED | MAP_ANON | MAP_PRIVATE, -1, 0) != NULL; -} - -// Reset virtual memory range. Indicates that data in the memory range specified by address and size is no -// longer of interest, but it should not be decommitted. -// Parameters: -// address - starting virtual address -// size - size of the virtual memory range -// unlock - true if the memory range should also be unlocked -// Return: -// true if it has succeeded, false if it has failed -bool GCToOSInterface::VirtualReset(void * address, size_t size, bool unlock) -{ - // UNIXTODO: Implement this - return true; -} - -// Check if the OS supports write watching -bool GCToOSInterface::SupportsWriteWatch() -{ - return PalHasCapability(WriteWatchCapability); -} - -// Reset the write tracking state for the specified virtual memory range. -// Parameters: -// address - starting virtual address -// size - size of the virtual memory range -void GCToOSInterface::ResetWriteWatch(void* address, size_t size) -{ -} - -// Retrieve addresses of the pages that are written to in a region of virtual memory -// Parameters: -// resetState - true indicates to reset the write tracking state -// address - starting virtual address -// size - size of the virtual memory range -// pageAddresses - buffer that receives an array of page addresses in the memory region -// pageAddressesCount - on input, size of the lpAddresses array, in array elements -// on output, the number of page addresses that are returned in the array. -// Return: -// true if it has succeeded, false if it has failed -bool GCToOSInterface::GetWriteWatch(bool resetState, void* address, size_t size, void** pageAddresses, uintptr_t* pageAddressesCount) -{ - return false; -} - -// Get size of the largest cache on the processor die -// Parameters: -// trueSize - true to return true cache size, false to return scaled up size based on -// the processor architecture -// Return: -// Size of the cache -size_t GCToOSInterface::GetCacheSizePerLogicalCpu(bool trueSize) -{ - // UNIXTODO: implement this - return 0; -} - -// Sets the calling thread's affinity to only run on the processor specified -// Parameters: -// procNo - The requested processor for the calling thread. -// Return: -// true if setting the affinity was successful, false otherwise. -bool GCToOSInterface::SetThreadAffinity(uint16_t procNo) -{ - // UNIXTODO: implement this - return false; -} - -// Boosts the calling thread's thread priority to a level higher than the default -// for new threads. -// Parameters: -// None. -// Return: -// true if the priority boost was successful, false otherwise. -bool GCToOSInterface::BoostThreadPriority() -{ - // UNIXTODO: implement this - return false; -} - -// Set the set of processors enabled for GC threads for the current process based on config specified affinity mask and set -// Parameters: -// configAffinityMask - mask specified by the GCHeapAffinitizeMask config -// configAffinitySet - affinity set specified by the GCHeapAffinitizeRanges config -// Return: -// set of enabled processors -const AffinitySet* GCToOSInterface::SetGCThreadsAffinitySet(uintptr_t configAffinityMask, const AffinitySet* configAffinitySet) -{ - if (!configAffinitySet->IsEmpty()) - { - // Update the process affinity set using the configured set - for (size_t i = 0; i < MAX_SUPPORTED_CPUS; i++) - { - if (g_processAffinitySet.Contains(i) && !configAffinitySet->Contains(i)) - { - g_processAffinitySet.Remove(i); - } - } - } - - return &g_processAffinitySet; -} - -// Get number of processors assigned to the current process -// Return: -// The number of processors -uint32_t GCToOSInterface::GetCurrentProcessCpuCount() -{ - return ::PalGetProcessCpuCount(); -} - -// Return the size of the user-mode portion of the virtual address space of this process. -// Return: -// non zero if it has succeeded, 0 if it has failed -size_t GCToOSInterface::GetVirtualMemoryLimit() -{ -#ifdef BIT64 - // There is no API to get the total virtual address space size on - // Unix, so we use a constant value representing 128TB, which is - // the approximate size of total user virtual address space on - // the currently supported Unix systems. - static const uint64_t _128TB = (1ull << 47); - return _128TB; -#else - return (size_t)-1; -#endif -} - -// Get the physical memory that this process can use. -// Return: -// non zero if it has succeeded, 0 if it has failed -// Remarks: -// If a process runs with a restricted memory limit, it returns the limit. If there's no limit -// specified, it returns amount of actual physical memory. -uint64_t GCToOSInterface::GetPhysicalMemoryLimit(bool* is_restricted) -{ - // TODO: implement is_restricted - if (is_restricted) - * is_restricted = false; - - int64_t physical_memory = 0; - - // Get the physical memory size -#if HAVE_SYSCONF && HAVE__SC_PHYS_PAGES - // Get the Physical memory size - physical_memory = sysconf(_SC_PHYS_PAGES) * sysconf(_SC_PAGE_SIZE); -#elif HAVE_SYSCTL - int mib[2]; - size_t length; - - // Get the Physical memory size - mib[0] = CTL_HW; - mib[1] = HW_MEMSIZE; - length = sizeof(int64_t); - int rc = sysctl(mib, 2, &physical_memory, &length, NULL, 0); - if (rc != 0) - { - ASSERT_UNCONDITIONALLY("sysctl failed for HW_MEMSIZE\n"); - } -#elif // HAVE_SYSINFO - // TODO: implement getting memory details via sysinfo. On Linux, it provides swap file details that - // we can use to fill in the xxxPageFile members. - -#endif // HAVE_SYSCONF - - return physical_memory; -} - -// Get memory status -// Parameters: -// memory_load - A number between 0 and 100 that specifies the approximate percentage of physical memory -// that is in use (0 indicates no memory use and 100 indicates full memory use). -// available_physical - The amount of physical memory currently available, in bytes. -// available_page_file - The maximum amount of memory the current process can commit, in bytes. -void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file) -{ - if (memory_load != nullptr || available_physical != nullptr) - { - uint64_t total = GetPhysicalMemoryLimit(); - - uint64_t available = 0; - uint32_t load = 0; - - // Get the physical memory in use - from it, we can get the physical memory available. - // We do this only when we have the total physical memory available. - if (total > 0) - { -#ifndef __APPLE__ - available = sysconf(SYSCONF_PAGES) * sysconf(_SC_PAGE_SIZE); - uint64_t used = total - available; - load = (uint32_t)((used * 100) / total); -#else - mach_port_t mach_port = mach_host_self(); - vm_size_t page_size; - if (KERN_SUCCESS == host_page_size(mach_port, &page_size)) - { - vm_statistics_data_t vm_stats; - mach_msg_type_number_t count = sizeof(vm_stats) / sizeof(natural_t); - if (KERN_SUCCESS == host_statistics(mach_port, HOST_VM_INFO, (host_info_t)&vm_stats, &count)) - { - available = (uint64_t)vm_stats.free_count * (uint64_t)page_size; - uint64_t used = ((uint64_t)vm_stats.active_count + (uint64_t)vm_stats.inactive_count + (uint64_t)vm_stats.wire_count) * (uint64_t)page_size; - load = (uint32_t)((used * 100) / total); - } - } - mach_port_deallocate(mach_task_self(), mach_port); -#endif // __APPLE__ - } - - if (memory_load != nullptr) - *memory_load = load; - if (available_physical != nullptr) - *available_physical = available; - } - - if (available_page_file != nullptr) - *available_page_file = 0; -} - -// Get a high precision performance counter -// Return: -// The counter value -int64_t GCToOSInterface::QueryPerformanceCounter() -{ - LARGE_INTEGER ts; - if (!::QueryPerformanceCounter(&ts)) - { - ASSERT_UNCONDITIONALLY("Fatal Error - cannot query performance counter."); - abort(); - } - - return ts.QuadPart; -} - -// Get a frequency of the high precision performance counter -// Return: -// The counter frequency -int64_t GCToOSInterface::QueryPerformanceFrequency() -{ - return g_performanceFrequency.QuadPart; -} - -// Get a time stamp with a low precision -// Return: -// Time stamp in milliseconds -uint32_t GCToOSInterface::GetLowPrecisionTimeStamp() -{ - return PalGetTickCount(); -} - -// Parameters of the GC thread stub -struct GCThreadStubParam -{ - GCThreadFunction GCThreadFunction; - void* GCThreadParam; -}; - -// GC thread stub to convert GC thread function to an OS specific thread function -static void* GCThreadStub(void* param) -{ - GCThreadStubParam *stubParam = (GCThreadStubParam*)param; - GCThreadFunction function = stubParam->GCThreadFunction; - void* threadParam = stubParam->GCThreadParam; - - delete stubParam; - - function(threadParam); - - return NULL; -} - -uint32_t GCToOSInterface::GetTotalProcessorCount() -{ - // TODO: CPUGroupInfo support - return g_SystemInfo.dwNumberOfProcessors; -} - -// TODO: Numa support -bool GCToOSInterface::CanEnableGCNumaAware() -{ - return false; -} - -// Get processor number and optionally its NUMA node number for the specified heap number -// Parameters: -// heap_number - heap number to get the result for -// proc_no - set to the selected processor number -// node_no - set to the NUMA node of the selected processor or to NUMA_NODE_UNDEFINED -// Return: -// true if it succeeded -bool GCToOSInterface::GetProcessorForHeap(uint16_t heap_number, uint16_t* proc_no, uint16_t* node_no) -{ - // TODO - return false; -} - -// Parse the config string describing affinitization ranges and update the passed in affinitySet accordingly -// Parameters: -// config_string - string describing the affinitization range, platform specific -// start_index - the range start index extracted from the config_string -// end_index - the range end index extracted from the config_string, equal to the start_index if only an index and not a range was passed in -// Return: -// true if the configString was successfully parsed, false if it was not correct -bool GCToOSInterface::ParseGCHeapAffinitizeRangesEntry(const char** config_string, size_t* start_index, size_t* end_index) -{ - return ParseIndexOrRange(config_string, start_index, end_index); -} - -// Initialize the critical section -void CLRCriticalSection::Initialize() -{ - int st = pthread_mutex_init(&m_cs.mutex, NULL); - ASSERT(st == 0); -} - -// Destroy the critical section -void CLRCriticalSection::Destroy() -{ - int st = pthread_mutex_destroy(&m_cs.mutex); - ASSERT(st == 0); -} - -// Enter the critical section. Blocks until the section can be entered. -void CLRCriticalSection::Enter() -{ - pthread_mutex_lock(&m_cs.mutex); -} - -// Leave the critical section -void CLRCriticalSection::Leave() -{ - pthread_mutex_unlock(&m_cs.mutex); -} - #if defined(_X86_) || defined(_AMD64_) REDHAWK_PALEXPORT uint32_t REDHAWK_PALAPI getcpuid(uint32_t arg, unsigned char result[16]) { diff --git a/src/Native/Runtime/windows/PalRedhawkMinWin.cpp b/src/Native/Runtime/windows/PalRedhawkMinWin.cpp index 1a3eb319f6d..0536cef5011 100644 --- a/src/Native/Runtime/windows/PalRedhawkMinWin.cpp +++ b/src/Native/Runtime/windows/PalRedhawkMinWin.cpp @@ -43,16 +43,16 @@ static UInt32 g_flsIndex = FLS_OUT_OF_INDEXES; static DWORD g_dwPALCapabilities; -GCSystemInfo g_SystemInfo; +GCSystemInfo g_RhSystemInfo; bool InitializeSystemInfo() { SYSTEM_INFO systemInfo; GetSystemInfo(&systemInfo); - g_SystemInfo.dwNumberOfProcessors = systemInfo.dwNumberOfProcessors; - g_SystemInfo.dwPageSize = systemInfo.dwPageSize; - g_SystemInfo.dwAllocationGranularity = systemInfo.dwAllocationGranularity; + g_RhSystemInfo.dwNumberOfProcessors = systemInfo.dwNumberOfProcessors; + g_RhSystemInfo.dwPageSize = systemInfo.dwPageSize; + g_RhSystemInfo.dwAllocationGranularity = systemInfo.dwAllocationGranularity; return true; } @@ -1358,697 +1358,3 @@ REDHAWK_PALEXPORT _Ret_maybenull_ void* REDHAWK_PALAPI PalSetWerDataBuffer(_In_ static void* pBuffer; return InterlockedExchangePointer(&pBuffer, pNewBuffer); } - -#ifndef RUNTIME_SERVICES_ONLY - -static bool g_SeLockMemoryPrivilegeAcquired = false; - -bool InitLargePagesPrivilege() -{ - TOKEN_PRIVILEGES tp; - LUID luid; - if (!LookupPrivilegeValueW(nullptr, SE_LOCK_MEMORY_NAME, &luid)) - { - return false; - } - - tp.PrivilegeCount = 1; - tp.Privileges[0].Luid = luid; - tp.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; - - HANDLE token; - if (!OpenProcessToken(::GetCurrentProcess(), TOKEN_ADJUST_PRIVILEGES, &token)) - { - return false; - } - - BOOL retVal = AdjustTokenPrivileges(token, FALSE, &tp, 0, nullptr, 0); - DWORD gls = GetLastError(); - CloseHandle(token); - - if (!retVal) - { - return false; - } - - if (gls != 0) - { - return false; - } - - return true; -} - -static AffinitySet g_processAffinitySet; - -class GroupProcNo -{ - uint16_t m_groupProc; - -public: - - static const uint16_t NoGroup = 0x3ff; - - GroupProcNo(uint16_t groupProc) : m_groupProc(groupProc) - { - } - - GroupProcNo(uint16_t group, uint16_t procIndex) : m_groupProc((group << 6) | procIndex) - { - assert(group <= 0x3ff); - assert(procIndex <= 0x3f); - } - - uint16_t GetGroup() { return m_groupProc >> 6; } - uint16_t GetProcIndex() { return m_groupProc & 0x3f; } - uint16_t GetCombinedValue() { return m_groupProc; } -}; - -static LARGE_INTEGER g_performanceFrequency; - -#ifdef PROJECTN -static bool g_roInitialized; -#endif - -// Initialize the interface implementation -// Return: -// true if it has succeeded, false if it has failed -bool GCToOSInterface::Initialize() -{ - if (!::QueryPerformanceFrequency(&g_performanceFrequency)) - { - return false; - } - -#ifdef PROJECTN - // TODO: Remove the RoInitialize call when we implement non-WinRT framework for classic apps - HRESULT hr = RoInitialize(RO_INIT_MULTITHREADED); - - // RPC_E_CHANGED_MODE indicates this thread has been already initialized with a different - // concurrency model. That is fine; we just need to skip the RoUninitialize call on shutdown. - if (SUCCEEDED(hr)) - { - g_roInitialized = true; - } - else if (hr != RPC_E_CHANGED_MODE) - { - return false; - } -#endif - - uintptr_t pmask, smask; - if (!!::GetProcessAffinityMask(::GetCurrentProcess(), (PDWORD_PTR)& pmask, (PDWORD_PTR)& smask)) - { - pmask &= smask; - - for (size_t i = 0; i < 8 * sizeof(uintptr_t); i++) - { - if ((pmask & ((uintptr_t)1 << i)) != 0) - { - g_processAffinitySet.Add(i); - } - } - } - - return true; -} - -// Shutdown the interface implementation -// Remarks: -// Must be called on the same thread as Initialize. -void GCToOSInterface::Shutdown() -{ -#ifdef PROJECTN - if (g_roInitialized) - { - RoUninitialize(); - g_roInitialized = false; - } -#endif -} - -// Get numeric id of the current thread if possible on the -// current platform. It is indended for logging purposes only. -// Return: -// Numeric id of the current thread or 0 if the -uint64_t GCToOSInterface::GetCurrentThreadIdForLogging() -{ - return ::GetCurrentThreadId(); -} - -// Get id of the process -uint32_t GCToOSInterface::GetCurrentProcessId() -{ - return ::GetCurrentProcessId(); -} - -// Set ideal processor for the current thread -// Parameters: -// srcProcNo - processor number the thread currently runs on -// dstProcNo - processor number the thread should be migrated to -// Return: -// true if it has succeeded, false if it has failed -bool GCToOSInterface::SetCurrentThreadIdealAffinity(uint16_t srcProcNo, uint16_t dstProcNo) -{ - bool success = true; - - GroupProcNo srcGroupProcNo(srcProcNo); - GroupProcNo dstGroupProcNo(dstProcNo); - - PROCESSOR_NUMBER proc; - - if (dstGroupProcNo.GetGroup() != GroupProcNo::NoGroup) - { - proc.Group = (WORD)dstGroupProcNo.GetGroup(); - proc.Number = (BYTE)dstGroupProcNo.GetProcIndex(); - proc.Reserved = 0; - - success = !!SetThreadIdealProcessorEx(GetCurrentThread(), &proc, NULL); - } - else - { - if (GetThreadIdealProcessorEx(GetCurrentThread(), &proc)) - { - proc.Number = (BYTE)dstGroupProcNo.GetProcIndex(); - success = !!SetThreadIdealProcessorEx(GetCurrentThread(), &proc, NULL); - } - } - - return success; -} - -// Get the number of the current processor -uint32_t GCToOSInterface::GetCurrentProcessorNumber() -{ - _ASSERTE(GCToOSInterface::CanGetCurrentProcessorNumber()); - return ::GetCurrentProcessorNumber(); -} - -// Check if the OS supports getting current processor number -bool GCToOSInterface::CanGetCurrentProcessorNumber() -{ - return true; -} - -// Flush write buffers of processors that are executing threads of the current process -void GCToOSInterface::FlushProcessWriteBuffers() -{ - ::FlushProcessWriteBuffers(); -} - -// Break into a debugger -void GCToOSInterface::DebugBreak() -{ - ::DebugBreak(); -} - -// Causes the calling thread to sleep for the specified number of milliseconds -// Parameters: -// sleepMSec - time to sleep before switching to another thread -void GCToOSInterface::Sleep(uint32_t sleepMSec) -{ - PalSleep(sleepMSec); -} - -// Causes the calling thread to yield execution to another thread that is ready to run on the current processor. -// Parameters: -// switchCount - number of times the YieldThread was called in a loop -void GCToOSInterface::YieldThread(uint32_t /*switchCount*/) -{ - PalSwitchToThread(); -} - -// Reserve virtual memory range. -// Parameters: -// address - starting virtual address, it can be NULL to let the function choose the starting address -// size - size of the virtual memory range -// alignment - requested memory alignment -// flags - flags to control special settings like write watching -// Return: -// Starting virtual address of the reserved range -void* GCToOSInterface::VirtualReserve(size_t size, size_t alignment, uint32_t flags) -{ - DWORD memFlags = (flags & VirtualReserveFlags::WriteWatch) ? (MEM_RESERVE | MEM_WRITE_WATCH) : MEM_RESERVE; - return ::VirtualAlloc(0, size, memFlags, PAGE_READWRITE); -} - -// Release virtual memory range previously reserved using VirtualReserve -// Parameters: -// address - starting virtual address -// size - size of the virtual memory range -// Return: -// true if it has succeeded, false if it has failed -bool GCToOSInterface::VirtualRelease(void* address, size_t size) -{ - UNREFERENCED_PARAMETER(size); - return !!::VirtualFree(address, 0, MEM_RELEASE); -} - -// Commit virtual memory range. -// Parameters: -// size - size of the virtual memory range -// Return: -// Starting virtual address of the committed range -void* GCToOSInterface::VirtualReserveAndCommitLargePages(size_t size) -{ - void* pRetVal = nullptr; - - if (!g_SeLockMemoryPrivilegeAcquired) - { - if (!InitLargePagesPrivilege()) - { - return nullptr; - } - - g_SeLockMemoryPrivilegeAcquired = true; - } - - SIZE_T largePageMinimum = GetLargePageMinimum(); - size = (size + (largePageMinimum - 1)) & ~(largePageMinimum - 1); - - return ::VirtualAlloc(nullptr, size, MEM_RESERVE | MEM_COMMIT | MEM_LARGE_PAGES, PAGE_READWRITE); -} - -// Commit virtual memory range. It must be part of a range reserved using VirtualReserve. -// Parameters: -// address - starting virtual address -// size - size of the virtual memory range -// Return: -// true if it has succeeded, false if it has failed -bool GCToOSInterface::VirtualCommit(void* address, size_t size, uint16_t node) -{ - UNREFERENCED_PARAMETER(node); // TODO: Numa support - return ::VirtualAlloc(address, size, MEM_COMMIT, PAGE_READWRITE) != NULL; -} - -// Decomit virtual memory range. -// Parameters: -// address - starting virtual address -// size - size of the virtual memory range -// Return: -// true if it has succeeded, false if it has failed -bool GCToOSInterface::VirtualDecommit(void* address, size_t size) -{ - return !!::VirtualFree(address, size, MEM_DECOMMIT); -} - -// Reset virtual memory range. Indicates that data in the memory range specified by address and size is no -// longer of interest, but it should not be decommitted. -// Parameters: -// address - starting virtual address -// size - size of the virtual memory range -// unlock - true if the memory range should also be unlocked -// Return: -// true if it has succeeded, false if it has failed -bool GCToOSInterface::VirtualReset(void * address, size_t size, bool unlock) -{ - bool success = ::VirtualAlloc(address, size, MEM_RESET, PAGE_READWRITE) != NULL; - if (success && unlock) - { - // Remove the page range from the working set - ::VirtualUnlock(address, size); - } - - return success; -} - -// Check if the OS supports write watching -bool GCToOSInterface::SupportsWriteWatch() -{ - return PalHasCapability(WriteWatchCapability); -} - -// Reset the write tracking state for the specified virtual memory range. -// Parameters: -// address - starting virtual address -// size - size of the virtual memory range -void GCToOSInterface::ResetWriteWatch(void* address, size_t size) -{ - ::ResetWriteWatch(address, size); -} - -// Retrieve addresses of the pages that are written to in a region of virtual memory -// Parameters: -// resetState - true indicates to reset the write tracking state -// address - starting virtual address -// size - size of the virtual memory range -// pageAddresses - buffer that receives an array of page addresses in the memory region -// pageAddressesCount - on input, size of the lpAddresses array, in array elements -// on output, the number of page addresses that are returned in the array. -// Return: -// true if it has succeeded, false if it has failed -bool GCToOSInterface::GetWriteWatch(bool resetState, void* address, size_t size, void** pageAddresses, uintptr_t* pageAddressesCount) -{ - uint32_t flags = resetState ? 1 : 0; - ULONG granularity; - - bool success = ::GetWriteWatch(flags, address, size, pageAddresses, (ULONG_PTR*)pageAddressesCount, &granularity) == 0; - _ASSERTE (granularity == OS_PAGE_SIZE); - - return success; -} - -// Get size of the largest cache on the processor die -// Parameters: -// trueSize - true to return true cache size, false to return scaled up size based on -// the processor architecture -// Return: -// Size of the cache -size_t GCToOSInterface::GetCacheSizePerLogicalCpu(bool trueSize) -{ - return trueSize ? g_cbLargestOnDieCache : g_cbLargestOnDieCacheAdjusted; -} - -// Sets the calling thread's affinity to only run on the processor specified -// Parameters: -// procNo - The requested processor for the calling thread. -// Return: -// true if setting the affinity was successful, false otherwise. -bool GCToOSInterface::SetThreadAffinity(uint16_t procNo) -{ - GroupProcNo groupProcNo(procNo); - - if (groupProcNo.GetGroup() != GroupProcNo::NoGroup) - { - GROUP_AFFINITY ga; - ga.Group = (WORD)groupProcNo.GetGroup(); - ga.Reserved[0] = 0; // reserve must be filled with zero - ga.Reserved[1] = 0; // otherwise call may fail - ga.Reserved[2] = 0; - ga.Mask = (size_t)1 << groupProcNo.GetProcIndex(); - return !!SetThreadGroupAffinity(GetCurrentThread(), &ga, nullptr); - } - else - { - return !!SetThreadAffinityMask(GetCurrentThread(), (DWORD_PTR)1 << groupProcNo.GetProcIndex()); - } -} - -// Boosts the calling thread's thread priority to a level higher than the default -// for new threads. -// Parameters: -// None. -// Return: -// true if the priority boost was successful, false otherwise. -bool GCToOSInterface::BoostThreadPriority() -{ - return !!SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_HIGHEST); -} - -// Set the set of processors enabled for GC threads for the current process based on config specified affinity mask and set -// Parameters: -// configAffinityMask - mask specified by the GCHeapAffinitizeMask config -// configAffinitySet - affinity set specified by the GCHeapAffinitizeRanges config -// Return: -// set of enabled processors -const AffinitySet* GCToOSInterface::SetGCThreadsAffinitySet(uintptr_t configAffinityMask, const AffinitySet* configAffinitySet) -{ - if (configAffinityMask != 0) - { - // Update the process affinity set using the configured mask - for (size_t i = 0; i < 8 * sizeof(uintptr_t); i++) - { - if (g_processAffinitySet.Contains(i) && ((configAffinityMask & ((uintptr_t)1 << i)) == 0)) - { - g_processAffinitySet.Remove(i); - } - } - } - - return &g_processAffinitySet; -} - -// Get number of processors assigned to the current process -// Return: -// The number of processors -uint32_t GCToOSInterface::GetCurrentProcessCpuCount() -{ - static int cCPUs = 0; - - if (cCPUs != 0) - return cCPUs; - - DWORD_PTR pmask, smask; - - if (!GetProcessAffinityMask(GetCurrentProcess(), &pmask, &smask)) - return 1; - - if (pmask == 1) - return 1; - - pmask &= smask; - - int count = 0; - while (pmask) - { - if (pmask & 1) - count++; - - pmask >>= 1; - } - - // GetProcessAffinityMask can return pmask=0 and smask=0 on systems with more - // than 64 processors, which would leave us with a count of 0. Since the GC - // expects there to be at least one processor to run on (and thus at least one - // heap), we'll return 64 here if count is 0, since there are likely a ton of - // processors available in that case. The GC also cannot (currently) handle - // the case where there are more than 64 processors, so we will return a - // maximum of 64 here. - if (count == 0 || count > 64) - count = 64; - - cCPUs = count; - - return count; -} - -// Return the size of the user-mode portion of the virtual address space of this process. -// Return: -// non zero if it has succeeded, 0 if it has failed -size_t GCToOSInterface::GetVirtualMemoryLimit() -{ - MEMORYSTATUSEX memStatus; - - memStatus.dwLength = sizeof(MEMORYSTATUSEX); - - BOOL fRet; - fRet = GlobalMemoryStatusEx(&memStatus); - _ASSERTE(fRet); - - return (size_t)memStatus.ullTotalVirtual; -} - -// Get the physical memory that this process can use. -// Return: -// non zero if it has succeeded, 0 if it has failed -uint64_t GCToOSInterface::GetPhysicalMemoryLimit(bool* is_restricted) -{ - // TODO: implement is_restricted - if (is_restricted) - * is_restricted = false; - - MEMORYSTATUSEX memStatus; - - memStatus.dwLength = sizeof(MEMORYSTATUSEX); - - BOOL fRet; - fRet = GlobalMemoryStatusEx(&memStatus); - _ASSERTE(fRet); - - return memStatus.ullTotalPhys; -} - -// Get memory status -// Parameters: -// memory_load - A number between 0 and 100 that specifies the approximate percentage of physical memory -// that is in use (0 indicates no memory use and 100 indicates full memory use). -// available_physical - The amount of physical memory currently available, in bytes. -// available_page_file - The maximum amount of memory the current process can commit, in bytes. -void GCToOSInterface::GetMemoryStatus(uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file) -{ - MEMORYSTATUSEX memStatus; - - memStatus.dwLength = sizeof(MEMORYSTATUSEX); - - BOOL fRet; - fRet = GlobalMemoryStatusEx(&memStatus); - _ASSERTE(fRet); - - // If the machine has more RAM than virtual address limit, let us cap it. - // The GC can never use more than virtual address limit. - if (memStatus.ullAvailPhys > memStatus.ullTotalVirtual) - { - memStatus.ullAvailPhys = memStatus.ullAvailVirtual; - } - - if (memory_load != NULL) - *memory_load = memStatus.dwMemoryLoad; - if (available_physical != NULL) - *available_physical = memStatus.ullAvailPhys; - if (available_page_file != NULL) - *available_page_file = memStatus.ullAvailPageFile; -} - -// Get a high precision performance counter -// Return: -// The counter value -int64_t GCToOSInterface::QueryPerformanceCounter() -{ - LARGE_INTEGER ts; - if (!::QueryPerformanceCounter(&ts)) - { - ASSERT_UNCONDITIONALLY("Fatal Error - cannot query performance counter."); - RhFailFast(); - } - - return ts.QuadPart; -} - -// Get a frequency of the high precision performance counter -// Return: -// The counter frequency -int64_t GCToOSInterface::QueryPerformanceFrequency() -{ - return g_performanceFrequency.QuadPart; -} - -// Get a time stamp with a low precision -// Return: -// Time stamp in milliseconds -uint32_t GCToOSInterface::GetLowPrecisionTimeStamp() -{ - return ::GetTickCount(); -} - -// Parameters of the GC thread stub -struct GCThreadStubParam -{ - GCThreadFunction GCThreadFunction; - void* GCThreadParam; -}; - -// GC thread stub to convert GC thread function to an OS specific thread function -static DWORD GCThreadStub(void* param) -{ - GCThreadStubParam *stubParam = (GCThreadStubParam*)param; - GCThreadFunction function = stubParam->GCThreadFunction; - void* threadParam = stubParam->GCThreadParam; - - delete stubParam; - - function(threadParam); - - return 0; -} - -uint32_t GCToOSInterface::GetTotalProcessorCount() -{ - // TODO: CPUGroupInfo support - return g_SystemInfo.dwNumberOfProcessors; -} - -// TODO: Numa support -bool GCToOSInterface::CanEnableGCNumaAware() -{ - return false; -} - -// Get processor number and optionally its NUMA node number for the specified heap number -// Parameters: -// heap_number - heap number to get the result for -// proc_no - set to the selected processor number -// node_no - set to the NUMA node of the selected processor or to NUMA_NODE_UNDEFINED -// Return: -// true if it succeeded -bool GCToOSInterface::GetProcessorForHeap(uint16_t heap_number, uint16_t* proc_no, uint16_t* node_no) -{ - bool success = false; - - // Locate heap_number-th available processor - uint16_t procIndex; - size_t cnt = heap_number; - for (uint16_t i = 0; i < GCToOSInterface::GetTotalProcessorCount(); i++) - { - if (g_processAffinitySet.Contains(i)) - { - if (cnt == 0) - { - procIndex = i; - success = true; - break; - } - - cnt--; - } - } - - if (success) - { - WORD gn, gpn; - gn = GroupProcNo::NoGroup; - gpn = procIndex; - - GroupProcNo groupProcNo(gn, gpn); - *proc_no = groupProcNo.GetCombinedValue(); - - PROCESSOR_NUMBER procNumber; - - // Get the current processor group - GetCurrentProcessorNumberEx(&procNumber); - - if (GCToOSInterface::CanEnableGCNumaAware()) - { - procNumber.Number = (BYTE)gpn; - procNumber.Reserved = 0; - - if (!GetNumaProcessorNodeEx(&procNumber, node_no)) - { - *node_no = NUMA_NODE_UNDEFINED; - } - } - else - { // no numa setting, each cpu group is treated as a node - *node_no = procNumber.Group; - } - } - - return success; -} - -// Parse the config string describing affinitization ranges and update the passed in affinitySet accordingly -// Parameters: -// config_string - string describing the affinitization range, platform specific -// start_index - the range start index extracted from the config_string -// end_index - the range end index extracted from the config_string, equal to the start_index if only an index and not a range was passed in -// Return: -// true if the configString was successfully parsed, false if it was not correct -bool GCToOSInterface::ParseGCHeapAffinitizeRangesEntry(const char** config_string, size_t* start_index, size_t* end_index) -{ - return ParseIndexOrRange(config_string, start_index, end_index); -} - -// Initialize the critical section -void CLRCriticalSection::Initialize() -{ - InitializeCriticalSection(&m_cs); -} - -// Destroy the critical section -void CLRCriticalSection::Destroy() -{ - DeleteCriticalSection(&m_cs); -} - -// Enter the critical section. Blocks until the section can be entered. -void CLRCriticalSection::Enter() -{ - EnterCriticalSection(&m_cs); -} - -// Leave the critical section -void CLRCriticalSection::Leave() -{ - LeaveCriticalSection(&m_cs); -} - -#endif // RUNTIME_SERVICES_ONLY diff --git a/src/Native/gc/unix/CMakeLists.txt b/src/Native/gc/unix/CMakeLists.txt index fbb94fd5130..10258108c6f 100644 --- a/src/Native/gc/unix/CMakeLists.txt +++ b/src/Native/gc/unix/CMakeLists.txt @@ -7,7 +7,6 @@ include(configure.cmake) set(GC_PAL_SOURCES gcenv.unix.cpp events.cpp - cgroup.cpp - cpuinfo.cpp) + cgroup.cpp) add_library(gc_unix STATIC ${GC_PAL_SOURCES} ${VERSION_FILE_PATH}) diff --git a/src/Native/gc/unix/config.h.in b/src/Native/gc/unix/config.gc.h.in similarity index 100% rename from src/Native/gc/unix/config.h.in rename to src/Native/gc/unix/config.gc.h.in diff --git a/src/Native/gc/unix/configure.cmake b/src/Native/gc/unix/configure.cmake index 859ffa4c482..e198a4a3507 100644 --- a/src/Native/gc/unix/configure.cmake +++ b/src/Native/gc/unix/configure.cmake @@ -95,4 +95,4 @@ endif() check_library_exists(${PTHREAD_LIBRARY} pthread_getaffinity_np "" HAVE_PTHREAD_GETAFFINITY_NP) -configure_file(${CMAKE_CURRENT_LIST_DIR}/config.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.h) +configure_file(${CMAKE_CURRENT_LIST_DIR}/config.gc.h.in ${CMAKE_CURRENT_BINARY_DIR}/config.gc.h) diff --git a/src/Native/gc/unix/events.cpp b/src/Native/gc/unix/events.cpp index b5ebc1c4dad..ad38976ecf5 100644 --- a/src/Native/gc/unix/events.cpp +++ b/src/Native/gc/unix/events.cpp @@ -9,7 +9,7 @@ #include #include #include -#include "config.h" +#include "config.gc.h" #include "common.h" #include "gcenv.structs.h" diff --git a/src/Native/gc/unix/gcenv.unix.cpp b/src/Native/gc/unix/gcenv.unix.cpp index 3d7442ada95..4407c2e7cdd 100644 --- a/src/Native/gc/unix/gcenv.unix.cpp +++ b/src/Native/gc/unix/gcenv.unix.cpp @@ -9,7 +9,7 @@ #include #include -#include "config.h" +#include "config.gc.h" #include "common.h" #include "gcenv.structs.h"