diff options
Diffstat (limited to 'src/gc/env')
-rw-r--r-- | src/gc/env/common.h | 2 | ||||
-rw-r--r-- | src/gc/env/gcenv.base.h | 380 | ||||
-rw-r--r-- | src/gc/env/gcenv.ee.h | 85 | ||||
-rw-r--r-- | src/gc/env/gcenv.interlocked.h | 102 | ||||
-rw-r--r-- | src/gc/env/gcenv.interlocked.inl | 200 | ||||
-rw-r--r-- | src/gc/env/gcenv.object.h | 4 | ||||
-rw-r--r-- | src/gc/env/gcenv.os.h | 274 | ||||
-rw-r--r-- | src/gc/env/gcenv.structs.h | 70 | ||||
-rw-r--r-- | src/gc/env/gcenv.sync.h | 31 | ||||
-rw-r--r-- | src/gc/env/gcenv.unix.cpp | 569 | ||||
-rw-r--r-- | src/gc/env/gcenv.windows.cpp | 268 |
11 files changed, 806 insertions, 1179 deletions
diff --git a/src/gc/env/common.h b/src/gc/env/common.h index 3e982f8f6c..39e97b3e7a 100644 --- a/src/gc/env/common.h +++ b/src/gc/env/common.h @@ -22,7 +22,7 @@ #include <new> -#ifndef WIN32 +#ifdef PLATFORM_UNIX #include <pthread.h> #endif diff --git a/src/gc/env/gcenv.base.h b/src/gc/env/gcenv.base.h index 5b8f5f7dd3..628a90cc88 100644 --- a/src/gc/env/gcenv.base.h +++ b/src/gc/env/gcenv.base.h @@ -16,11 +16,17 @@ #define REDHAWK_PALIMPORT extern "C" #define REDHAWK_PALAPI __stdcall - #ifndef _MSC_VER #define __stdcall +#ifdef __clang__ +#define __forceinline __attribute__((always_inline)) +#else // __clang__ #define __forceinline inline -#endif +#endif // __clang__ +#endif // !_MSC_VER + +#define SIZE_T_MAX ((size_t)-1) +#define SSIZE_T_MAX ((ptrdiff_t)(SIZE_T_MAX / 2)) #ifndef _INC_WINDOWS // ----------------------------------------------------------------------------------------------------------- @@ -44,17 +50,14 @@ typedef size_t SIZE_T; typedef void * HANDLE; -#define SIZE_T_MAX ((size_t)-1) -#define SSIZE_T_MAX ((ptrdiff_t)(SIZE_T_MAX / 2)) - // ----------------------------------------------------------------------------------------------------------- // HRESULT subset. -#ifdef WIN32 +#ifdef PLATFORM_UNIX +typedef int32_t HRESULT; +#else // this must exactly match the typedef used by windows.h typedef long HRESULT; -#else -typedef int32_t HRESULT; #endif #define SUCCEEDED(_hr) ((HRESULT)(_hr) >= 0) @@ -104,122 +107,20 @@ inline HRESULT HRESULT_FROM_WIN32(unsigned long x) #define INVALID_HANDLE_VALUE ((HANDLE)-1) -#ifndef WIN32 +#ifdef PLATFORM_UNIX #define _vsnprintf vsnprintf #define sprintf_s snprintf +#define swprintf_s swprintf #endif -#define WINBASEAPI extern "C" #define WINAPI __stdcall typedef DWORD (WINAPI *PTHREAD_START_ROUTINE)(void* lpThreadParameter); -WINBASEAPI -void -WINAPI -DebugBreak(); - -WINBASEAPI -BOOL -WINAPI -VirtualUnlock( - LPVOID lpAddress, - SIZE_T dwSize - ); - -WINBASEAPI -DWORD -WINAPI -GetLastError(); - -WINBASEAPI -UINT -WINAPI -GetWriteWatch( - DWORD dwFlags, - PVOID lpBaseAddress, - SIZE_T dwRegionSize, - PVOID *lpAddresses, - ULONG_PTR * lpdwCount, - DWORD * lpdwGranularity -); - -WINBASEAPI -UINT -WINAPI -ResetWriteWatch( - LPVOID lpBaseAddress, - SIZE_T dwRegionSize -); - -WINBASEAPI -VOID -WINAPI -FlushProcessWriteBuffers(); - -WINBASEAPI -DWORD -WINAPI -GetTickCount(); - -WINBASEAPI -BOOL -WINAPI -QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount); - -WINBASEAPI -BOOL -WINAPI -QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency); - -WINBASEAPI -DWORD -WINAPI -GetCurrentThreadId( - VOID); - -WINBASEAPI -BOOL -WINAPI -CloseHandle( - HANDLE hObject); - #define WAIT_OBJECT_0 0 #define WAIT_TIMEOUT 258 #define WAIT_FAILED 0xFFFFFFFF -#define GENERIC_WRITE 0x40000000 -#define FILE_SHARE_READ 0x00000001 -#define CREATE_ALWAYS 2 -#define FILE_ATTRIBUTE_NORMAL 0x00000080 - -WINBASEAPI -BOOL -WINAPI -WriteFile( - HANDLE hFile, - LPCVOID lpBuffer, - DWORD nNumberOfBytesToWrite, - DWORD * lpNumberOfBytesWritten, - PVOID lpOverlapped); - -#define FILE_BEGIN 0 - -WINBASEAPI -DWORD -WINAPI -SetFilePointer( - HANDLE hFile, - int32_t lDistanceToMove, - int32_t * lpDistanceToMoveHigh, - DWORD dwMoveMethod); - -WINBASEAPI -BOOL -WINAPI -FlushFileBuffers( - HANDLE hFile); - #if defined(_MSC_VER) #if defined(_ARM_) @@ -263,24 +164,8 @@ FlushFileBuffers( #endif #else // _MSC_VER -WINBASEAPI -VOID -WINAPI -YieldProcessor(); - -WINBASEAPI -VOID -WINAPI -MemoryBarrier(); - #endif // _MSC_VER -typedef struct _GUID { - unsigned long Data1; - unsigned short Data2; - unsigned short Data3; - unsigned char Data4[8]; -} GUID; #endif // _INC_WINDOWS // ----------------------------------------------------------------------------------------------------------- @@ -410,56 +295,6 @@ typedef DPTR(uint8_t) PTR_uint8_t; #define UI64(_literal) _literal##ULL -int32_t FastInterlockIncrement(int32_t volatile *lpAddend); -int32_t FastInterlockDecrement(int32_t volatile *lpAddend); -int32_t FastInterlockExchange(int32_t volatile *Target, int32_t Value); -int32_t FastInterlockCompareExchange(int32_t volatile *Destination, int32_t Exchange, int32_t Comperand); -int32_t FastInterlockExchangeAdd(int32_t volatile *Addend, int32_t Value); - -void * _FastInterlockExchangePointer(void * volatile *Target, void * Value); -void * _FastInterlockCompareExchangePointer(void * volatile *Destination, void * Exchange, void * Comperand); - -template <typename T> -inline T FastInterlockExchangePointer( - T volatile * target, - T value) -{ - return (T)((TADDR)_FastInterlockExchangePointer((void **)target, value)); -} - -template <typename T> -inline T FastInterlockExchangePointer( - T volatile * target, - nullptr_t value) -{ - return (T)((TADDR)_FastInterlockExchangePointer((void **)target, value)); -} - -template <typename T> -inline T FastInterlockCompareExchangePointer( - T volatile * destination, - T exchange, - T comparand) -{ - return (T)((TADDR)_FastInterlockCompareExchangePointer((void **)destination, exchange, comparand)); -} - -template <typename T> -inline T FastInterlockCompareExchangePointer( - T volatile * destination, - T exchange, - nullptr_t comparand) -{ - return (T)((TADDR)_FastInterlockCompareExchangePointer((void **)destination, exchange, comparand)); -} - - -void FastInterlockOr(uint32_t volatile *p, uint32_t msk); -void FastInterlockAnd(uint32_t volatile *p, uint32_t msk); - -#define CALLER_LIMITS_SPINNING 0 -bool __SwitchToThread (uint32_t dwSleepMSec, uint32_t dwSwitchCount); - class ObjHeader; class MethodTable; class Object; @@ -493,7 +328,51 @@ typedef TADDR OBJECTHANDLE; #define VOLATILE(T) T volatile +// +// This code is extremely compiler- and CPU-specific, and will need to be altered to +// support new compilers and/or CPUs. Here we enforce that we can only compile using +// VC++, or Clang on x86, AMD64, ARM and ARM64. +// +#if !defined(_MSC_VER) && !defined(__clang__) +#error The Volatile type is currently only defined for Visual C++ and Clang +#endif + +#if defined(__clang__) && !defined(_X86_) && !defined(_AMD64_) && !defined(_ARM_) && !defined(_ARM64_) +#error The Volatile type is currently only defined for Clang when targeting x86, AMD64, ARM or ARM64 CPUs +#endif + +#if defined(__clang__) +#if defined(_ARM_) || defined(_ARM64_) +// This is functionally equivalent to the MemoryBarrier() macro used on ARM on Windows. +#define VOLATILE_MEMORY_BARRIER() asm volatile ("dmb sy" : : : "memory") +#else +// +// For Clang, we prevent reordering by the compiler by inserting the following after a volatile +// load (to prevent subsequent operations from moving before the read), and before a volatile +// write (to prevent prior operations from moving past the write). We don't need to do anything +// special to prevent CPU reorderings, because the x86 and AMD64 architectures are already +// sufficiently constrained for our purposes. If we ever need to run on weaker CPU architectures +// (such as PowerPC), then we will need to do more work. +// +// Please do not use this macro outside of this file. It is subject to change or removal without +// notice. +// +#define VOLATILE_MEMORY_BARRIER() asm volatile ("" : : : "memory") +#endif // !_ARM_ +#elif defined(_ARM_) && _ISO_VOLATILE +// ARM has a very weak memory model and very few tools to control that model. We're forced to perform a full +// memory barrier to preserve the volatile semantics. Technically this is only necessary on MP systems but we +// currently don't have a cheap way to determine the number of CPUs from this header file. Revisit this if it +// turns out to be a performance issue for the uni-proc case. +#define VOLATILE_MEMORY_BARRIER() MemoryBarrier() +#else +// +// On VC++, reorderings at the compiler and machine level are prevented by the use of the +// "volatile" keyword in VolatileLoad and VolatileStore. This should work on any CPU architecture +// targeted by VC++ with /iso_volatile-. +// #define VOLATILE_MEMORY_BARRIER() +#endif // // VolatileLoad loads a T from a pointer to T. It is guaranteed that this load will not be optimized @@ -539,11 +418,6 @@ void VolatileStore(T* pt, T val) } extern GCSystemInfo g_SystemInfo; -void InitializeSystemInfo(); - -void -GetProcessMemoryLoad( - GCMemoryStatus* lpBuffer); extern MethodTable * g_pFreeObjectMethodTable; @@ -552,43 +426,6 @@ extern int32_t g_TrapReturningThreads; extern bool g_fFinalizerRunOnShutDown; // -// Memory allocation -// -#define MEM_COMMIT 0x1000 -#define MEM_RESERVE 0x2000 -#define MEM_DECOMMIT 0x4000 -#define MEM_RELEASE 0x8000 -#define MEM_RESET 0x80000 - -#define PAGE_NOACCESS 0x01 -#define PAGE_READWRITE 0x04 - -void * ClrVirtualAlloc( - void * lpAddress, - size_t dwSize, - uint32_t flAllocationType, - uint32_t flProtect); - -void * ClrVirtualAllocAligned( - void * lpAddress, - size_t dwSize, - uint32_t flAllocationType, - uint32_t flProtect, - size_t dwAlignment); - -bool ClrVirtualFree( - void * lpAddress, - size_t dwSize, - uint32_t dwFreeType); - -bool -ClrVirtualProtect( - void * lpAddress, - size_t dwSize, - uint32_t flNewProtect, - uint32_t * lpflOldProtect); - -// // Locks // @@ -597,71 +434,8 @@ class Thread; Thread * GetThread(); -struct ScanContext; -typedef void promote_func(PTR_PTR_Object, ScanContext*, uint32_t); - typedef void (CALLBACK *HANDLESCANPROC)(PTR_UNCHECKED_OBJECTREF pref, uintptr_t *pExtraInfo, uintptr_t param1, uintptr_t param2); -typedef void enum_alloc_context_func(alloc_context*, void*); - -class GCToEEInterface -{ -public: - // - // Suspend/Resume callbacks - // - typedef enum - { - SUSPEND_FOR_GC, - SUSPEND_FOR_GC_PREP - } SUSPEND_REASON; - - static void SuspendEE(SUSPEND_REASON reason); - static void RestartEE(bool bFinishedGC); //resume threads. - - // - // The stack roots enumeration callback - // - static void GcScanRoots(promote_func* fn, int condemned, int max_gen, ScanContext* sc); - - // - // Callbacks issues during GC that the execution engine can do its own bookeeping - // - - // start of GC call back - single threaded - static void GcStartWork(int condemned, int max_gen); - - //EE can perform post stack scanning action, while the - // user threads are still suspended - static void AfterGcScanRoots(int condemned, int max_gen, ScanContext* sc); - - // Called before BGC starts sweeping, the heap is walkable - static void GcBeforeBGCSweepWork(); - - // post-gc callback. - static void GcDone(int condemned); - - // Promote refcounted handle callback - static bool RefCountedHandleCallbacks(Object * pObject); - - // Sync block cache management - static void SyncBlockCacheWeakPtrScan(HANDLESCANPROC scanProc, uintptr_t lp1, uintptr_t lp2); - static void SyncBlockCacheDemote(int max_gen); - static void SyncBlockCachePromotionsGranted(int max_gen); - - // Thread functions - static bool IsPreemptiveGCDisabled(Thread * pThread); - static void EnablePreemptiveGC(Thread * pThread); - static void DisablePreemptiveGC(Thread * pThread); - static void SetGCSpecial(Thread * pThread); - static bool CatchAtSafePoint(Thread * pThread); - static alloc_context * GetAllocContext(Thread * pThread); - - // ThreadStore functions - static void AttachCurrentThread(); // does not acquire thread store lock - static void GcEnumAllocContexts (enum_alloc_context_func* fn, void* param); -}; - class FinalizerThread { public: @@ -678,9 +452,20 @@ public: static HANDLE GetFinalizerEvent(); }; +#ifdef FEATURE_REDHAWK typedef uint32_t (__stdcall *BackgroundCallback)(void* pCallbackContext); REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalStartBackgroundGCThread(BackgroundCallback callback, void* pCallbackContext); +enum PalCapability +{ + WriteWatchCapability = 0x00000001, // GetWriteWatch() and friends + LowMemoryNotificationCapability = 0x00000002, // CreateMemoryResourceNotification() and friends + GetCurrentProcessorNumberCapability = 0x00000004, // GetCurrentProcessorNumber() +}; + +REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalHasCapability(PalCapability capability); +#endif // FEATURE_REDHAWK + void DestroyThread(Thread * pThread); bool IsGCSpecialThread(); @@ -692,12 +477,6 @@ inline bool dbgOnly_IsSpecialEEThread() #define ClrFlsSetThreadType(type) -void UnsafeInitializeCriticalSection(CRITICAL_SECTION * lpCriticalSection); -void UnsafeEEEnterCriticalSection(CRITICAL_SECTION *lpCriticalSection); -void UnsafeEELeaveCriticalSection(CRITICAL_SECTION * lpCriticalSection); -void UnsafeDeleteCriticalSection(CRITICAL_SECTION *lpCriticalSection); - - // // Performance logging // @@ -763,29 +542,10 @@ VOID LogSpewAlways(const char *fmt, ...); #define STRESS_LOG_RESERVE_MEM(numChunks) do {} while (0) #define STRESS_LOG_GC_STACK -typedef void* CLR_MUTEX_ATTRIBUTES; -typedef void* CLR_MUTEX_COOKIE; - -CLR_MUTEX_COOKIE ClrCreateMutex(CLR_MUTEX_ATTRIBUTES lpMutexAttributes, bool bInitialOwner, LPCWSTR lpName); -void ClrCloseMutex(CLR_MUTEX_COOKIE mutex); -bool ClrReleaseMutex(CLR_MUTEX_COOKIE mutex); -uint32_t ClrWaitForMutex(CLR_MUTEX_COOKIE mutex, uint32_t dwMilliseconds, bool bAlertable); - -REDHAWK_PALIMPORT HANDLE REDHAWK_PALAPI PalCreateFileW(_In_z_ LPCWSTR pFileName, uint32_t desiredAccess, uint32_t shareMode, _In_opt_ void* pSecurityAttributes, uint32_t creationDisposition, uint32_t flagsAndAttributes, HANDLE hTemplateFile); - #define DEFAULT_GC_PRN_LVL 3 // ----------------------------------------------------------------------------------------------------------- -enum PalCapability -{ - WriteWatchCapability = 0x00000001, // GetWriteWatch() and friends - LowMemoryNotificationCapability = 0x00000002, // CreateMemoryResourceNotification() and friends - GetCurrentProcessorNumberCapability = 0x00000004, // GetCurrentProcessorNumber() -}; - -REDHAWK_PALIMPORT bool REDHAWK_PALAPI PalHasCapability(PalCapability capability); - void StompWriteBarrierEphemeral(); void StompWriteBarrierResize(bool bReqUpperBoundsCheck); @@ -862,8 +622,8 @@ namespace GCStressPolicy static volatile int32_t s_cGcStressDisables; inline bool IsEnabled() { return s_cGcStressDisables == 0; } - inline void GlobalDisable() { FastInterlockIncrement(&s_cGcStressDisables); } - inline void GlobalEnable() { FastInterlockDecrement(&s_cGcStressDisables); } + inline void GlobalDisable() { Interlocked::Increment(&s_cGcStressDisables); } + inline void GlobalEnable() { Interlocked::Decrement(&s_cGcStressDisables); } } enum gcs_trigger_points diff --git a/src/gc/env/gcenv.ee.h b/src/gc/env/gcenv.ee.h new file mode 100644 index 0000000000..741337fbbf --- /dev/null +++ b/src/gc/env/gcenv.ee.h @@ -0,0 +1,85 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +// Interface between the GC and EE +// + +#ifndef __GCENV_EE_H__ +#define __GCENV_EE_H__ + +struct ScanContext; +class CrawlFrame; + +typedef void promote_func(PTR_PTR_Object, ScanContext*, uint32_t); + +typedef void enum_alloc_context_func(alloc_context*, void*); + +typedef struct +{ + promote_func* f; + ScanContext* sc; + CrawlFrame * cf; +} GCCONTEXT; + + +class GCToEEInterface +{ +public: + // + // Suspend/Resume callbacks + // + typedef enum + { + SUSPEND_FOR_GC = 1, + SUSPEND_FOR_GC_PREP = 6 + } SUSPEND_REASON; + + static void SuspendEE(SUSPEND_REASON reason); + static void RestartEE(bool bFinishedGC); //resume threads. + + // + // The GC roots enumeration callback + // + static void GcScanRoots(promote_func* fn, int condemned, int max_gen, ScanContext* sc); + + // + // Callbacks issues during GC that the execution engine can do its own bookeeping + // + + // start of GC call back - single threaded + static void GcStartWork(int condemned, int max_gen); + + //EE can perform post stack scanning action, while the + // user threads are still suspended + static void AfterGcScanRoots(int condemned, int max_gen, ScanContext* sc); + + // Called before BGC starts sweeping, the heap is walkable + static void GcBeforeBGCSweepWork(); + + // post-gc callback. + static void GcDone(int condemned); + + // Promote refcounted handle callback + static bool RefCountedHandleCallbacks(Object * pObject); + + // Sync block cache management + static void SyncBlockCacheWeakPtrScan(HANDLESCANPROC scanProc, uintptr_t lp1, uintptr_t lp2); + static void SyncBlockCacheDemote(int max_gen); + static void SyncBlockCachePromotionsGranted(int max_gen); + + // Thread functions + static bool IsPreemptiveGCDisabled(Thread * pThread); + static void EnablePreemptiveGC(Thread * pThread); + static void DisablePreemptiveGC(Thread * pThread); + + static void SetGCSpecial(Thread * pThread); + static alloc_context * GetAllocContext(Thread * pThread); + static bool CatchAtSafePoint(Thread * pThread); + + static void GcEnumAllocContexts(enum_alloc_context_func* fn, void* param); + + static void AttachCurrentThread(); // does not acquire thread store lock +}; + +#endif // __GCENV_EE_H__ diff --git a/src/gc/env/gcenv.interlocked.h b/src/gc/env/gcenv.interlocked.h new file mode 100644 index 0000000000..1d6cc8424f --- /dev/null +++ b/src/gc/env/gcenv.interlocked.h @@ -0,0 +1,102 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +// Interlocked operations +// + +#ifndef __GCENV_INTERLOCKED_H__ +#define __GCENV_INTERLOCKED_H__ + +// Interlocked operations +class Interlocked +{ +public: + + // Increment the value of the specified 32-bit variable as an atomic operation. + // Parameters: + // addend - variable to be incremented + // Return: + // The resulting incremented value + template<typename T> + static T Increment(T volatile *addend); + + // Decrement the value of the specified 32-bit variable as an atomic operation. + // Parameters: + // addend - variable to be decremented + // Return: + // The resulting decremented value + template<typename T> + static T Decrement(T volatile *addend); + + // Perform an atomic AND operation on the specified values values + // Parameters: + // destination - the first operand and the destination + // value - second operand + template<typename T> + static void And(T volatile *destination, T value); + + // Perform an atomic OR operation on the specified values values + // Parameters: + // destination - the first operand and the destination + // value - second operand + template<typename T> + static void Or(T volatile *destination, T value); + + // Set a 32-bit variable to the specified value as an atomic operation. + // Parameters: + // destination - value to be exchanged + // value - value to set the destination to + // Return: + // The previous value of the destination + template<typename T> + static T Exchange(T volatile *destination, T value); + + // Set a pointer variable to the specified value as an atomic operation. + // Parameters: + // destination - value to be exchanged + // value - value to set the destination to + // Return: + // The previous value of the destination + template <typename T> + static T ExchangePointer(T volatile * destination, T value); + + template <typename T> + static T ExchangePointer(T volatile * destination, std::nullptr_t value); + + // Perform an atomic addition of two 32-bit values and return the original value of the addend. + // Parameters: + // addend - variable to be added to + // value - value to add + // Return: + // The previous value of the addend + template<typename T> + static T ExchangeAdd(T volatile *addend, T value); + + // Performs an atomic compare-and-exchange operation on the specified values. + // Parameters: + // destination - value to be exchanged + // exchange - value to set the destination to + // comparand - value to compare the destination to before setting it to the exchange. + // The destination is set only if the destination is equal to the comparand. + // Return: + // The original value of the destination + template<typename T> + static T CompareExchange(T volatile *destination, T exchange, T comparand); + + // Performs an atomic compare-and-exchange operation on the specified pointers. + // Parameters: + // destination - value to be exchanged + // exchange - value to set the destination to + // comparand - value to compare the destination to before setting it to the exchange. + // The destination is set only if the destination is equal to the comparand. + // Return: + // The original value of the destination + template <typename T> + static T CompareExchangePointer(T volatile *destination, T exchange, T comparand); + + template <typename T> + static T CompareExchangePointer(T volatile *destination, T exchange, std::nullptr_t comparand); +}; + +#endif // __GCENV_INTERLOCKED_H__ diff --git a/src/gc/env/gcenv.interlocked.inl b/src/gc/env/gcenv.interlocked.inl new file mode 100644 index 0000000000..62e171cadf --- /dev/null +++ b/src/gc/env/gcenv.interlocked.inl @@ -0,0 +1,200 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +// __forceinline implementation of the Interlocked class methods +// + +#ifndef __GCENV_INTERLOCKED_INL__ +#define __GCENV_INTERLOCKED_INL__ + +#ifdef _MSC_VER +#include <intrin.h> +#endif // _MSC_VER + +// Increment the value of the specified 32-bit variable as an atomic operation. +// Parameters: +// addend - variable to be incremented +// Return: +// The resulting incremented value +template <typename T> +__forceinline T Interlocked::Increment(T volatile *addend) +{ +#ifdef _MSC_VER + static_assert(sizeof(long) == sizeof(T), "Size of long must be the same as size of T"); + return _InterlockedIncrement((long*)addend); +#else + return __sync_add_and_fetch(addend, 1); +#endif +} + +// Decrement the value of the specified 32-bit variable as an atomic operation. +// Parameters: +// addend - variable to be decremented +// Return: +// The resulting decremented value +template <typename T> +__forceinline T Interlocked::Decrement(T volatile *addend) +{ +#ifdef _MSC_VER + static_assert(sizeof(long) == sizeof(T), "Size of long must be the same as size of T"); + return _InterlockedDecrement((long*)addend); +#else + return __sync_sub_and_fetch(addend, 1); +#endif +} + +// Set a 32-bit variable to the specified value as an atomic operation. +// Parameters: +// destination - value to be exchanged +// value - value to set the destination to +// Return: +// The previous value of the destination +template <typename T> +__forceinline T Interlocked::Exchange(T volatile *destination, T value) +{ +#ifdef _MSC_VER + static_assert(sizeof(long) == sizeof(T), "Size of long must be the same as size of T"); + return _InterlockedExchange((long*)destination, value); +#else + return __sync_swap(destination, value); +#endif +} + +// Performs an atomic compare-and-exchange operation on the specified values. +// Parameters: +// destination - value to be exchanged +// exchange - value to set the destinaton to +// comparand - value to compare the destination to before setting it to the exchange. +// The destination is set only if the destination is equal to the comparand. +// Return: +// The original value of the destination +template <typename T> +__forceinline T Interlocked::CompareExchange(T volatile *destination, T exchange, T comparand) +{ +#ifdef _MSC_VER + static_assert(sizeof(long) == sizeof(T), "Size of long must be the same as size of T"); + return _InterlockedCompareExchange((long*)destination, exchange, comparand); +#else + return __sync_val_compare_and_swap(destination, comparand, exchange); +#endif +} + +// Perform an atomic addition of two 32-bit values and return the original value of the addend. +// Parameters: +// addend - variable to be added to +// value - value to add +// Return: +// The previous value of the addend +template <typename T> +__forceinline T Interlocked::ExchangeAdd(T volatile *addend, T value) +{ +#ifdef _MSC_VER + static_assert(sizeof(long) == sizeof(T), "Size of long must be the same as size of T"); + return _InterlockedExchangeAdd((long*)addend, value); +#else + return __sync_fetch_and_add(addend, value); +#endif +} + +// Perform an atomic AND operation on the specified values values +// Parameters: +// destination - the first operand and the destination +// value - second operand +template <typename T> +__forceinline void Interlocked::And(T volatile *destination, T value) +{ +#ifdef _MSC_VER + static_assert(sizeof(long) == sizeof(T), "Size of long must be the same as size of T"); + _InterlockedAnd((long*)destination, value); +#else + __sync_and_and_fetch(destination, value); +#endif +} + +// Perform an atomic OR operation on the specified values values +// Parameters: +// destination - the first operand and the destination +// value - second operand +template <typename T> +__forceinline void Interlocked::Or(T volatile *destination, T value) +{ +#ifdef _MSC_VER + static_assert(sizeof(long) == sizeof(T), "Size of long must be the same as size of T"); + _InterlockedOr((long*)destination, value); +#else + __sync_or_and_fetch(destination, value); +#endif +} + +// Set a pointer variable to the specified value as an atomic operation. +// Parameters: +// destination - value to be exchanged +// value - value to set the destination to +// Return: +// The previous value of the destination +template <typename T> +__forceinline T Interlocked::ExchangePointer(T volatile * destination, T value) +{ +#ifdef _MSC_VER +#ifdef BIT64 + return (T)(TADDR)_InterlockedExchangePointer((void* volatile *)destination, value); +#else + return (T)(TADDR)_InterlockedExchange((long volatile *)(void* volatile *)destination, (long)(void*)value); +#endif +#else + return (T)(TADDR)__sync_swap((void* volatile *)destination, value); +#endif +} + +template <typename T> +__forceinline T Interlocked::ExchangePointer(T volatile * destination, std::nullptr_t value) +{ +#ifdef _MSC_VER +#ifdef BIT64 + return (T)(TADDR)_InterlockedExchangePointer((void* volatile *)destination, value); +#else + return (T)(TADDR)_InterlockedExchange((long volatile *)(void* volatile *)destination, (long)(void*)value); +#endif +#else + return (T)(TADDR)__sync_swap((void* volatile *)destination, value); +#endif +} + +// Performs an atomic compare-and-exchange operation on the specified pointers. +// Parameters: +// destination - value to be exchanged +// exchange - value to set the destinaton to +// comparand - value to compare the destination to before setting it to the exchange. +// The destination is set only if the destination is equal to the comparand. +// Return: +// The original value of the destination +template <typename T> +__forceinline T Interlocked::CompareExchangePointer(T volatile *destination, T exchange, T comparand) +{ +#ifdef _MSC_VER +#ifdef BIT64 + return (T)(TADDR)_InterlockedCompareExchangePointer((void* volatile *)destination, exchange, comparand); +#else + return (T)(TADDR)_InterlockedCompareExchange((long volatile *)(void* volatile *)destination, (long)(void*)exchange, (long)(void*)comparand); +#endif +#else + return (T)(TADDR)__sync_val_compare_and_swap((void* volatile *)destination, comparand, exchange); +#endif +} + +template <typename T> +__forceinline T Interlocked::CompareExchangePointer(T volatile *destination, T exchange, std::nullptr_t comparand) +{ +#ifdef _MSC_VER +#ifdef BIT64 + return (T)(TADDR)_InterlockedCompareExchangePointer((void* volatile *)destination, exchange, comparand); +#else + return (T)(TADDR)_InterlockedCompareExchange((long volatile *)(void* volatile *)destination, (long)(void*)exchange, (long)(void*)comparand); +#endif +#else + return (T)(TADDR)__sync_val_compare_and_swap((void* volatile *)destination, comparand, exchange); +#endif +} + +#endif // __GCENV_INTERLOCKED_INL__ diff --git a/src/gc/env/gcenv.object.h b/src/gc/env/gcenv.object.h index 31dfe838dd..d3660173ce 100644 --- a/src/gc/env/gcenv.object.h +++ b/src/gc/env/gcenv.object.h @@ -26,8 +26,8 @@ private: public: uint32_t GetBits() { return m_uSyncBlockValue; } - void SetBit(uint32_t uBit) { FastInterlockOr(&m_uSyncBlockValue, uBit); } - void ClrBit(uint32_t uBit) { FastInterlockAnd(&m_uSyncBlockValue, ~uBit); } + void SetBit(uint32_t uBit) { Interlocked::Or(&m_uSyncBlockValue, uBit); } + void ClrBit(uint32_t uBit) { Interlocked::And(&m_uSyncBlockValue, ~uBit); } void SetGCBit() { m_uSyncBlockValue |= BIT_SBLK_GC_RESERVE; } void ClrGCBit() { m_uSyncBlockValue &= ~BIT_SBLK_GC_RESERVE; } }; diff --git a/src/gc/env/gcenv.os.h b/src/gc/env/gcenv.os.h new file mode 100644 index 0000000000..c1ae87a042 --- /dev/null +++ b/src/gc/env/gcenv.os.h @@ -0,0 +1,274 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// +// Interface between GC and the OS specific functionality +// + +#ifndef __GCENV_OS_H__ +#define __GCENV_OS_H__ + +// Critical section used by the GC +class CLRCriticalSection +{ + CRITICAL_SECTION m_cs; + +public: + // Initialize the critical section + void Initialize(); + + // Destroy the critical section + void Destroy(); + + // Enter the critical section. Blocks until the section can be entered. + void Enter(); + + // Leave the critical section + void Leave(); +}; + +// Flags for the GCToOSInterface::VirtualReserve method +struct VirtualReserveFlags +{ + enum + { + None = 0, + WriteWatch = 1, + }; +}; + +// Affinity of a GC thread +struct GCThreadAffinity +{ + static const int None = -1; + + // Processor group index, None if no group is specified + int Group; + // Processor index, None if no affinity is specified + int Processor; +}; + +// GC thread function prototype +typedef void (*GCThreadFunction)(void* param); + +// Interface that the GC uses to invoke OS specific functionality +class GCToOSInterface +{ +public: + + // + // Initialization and shutdown of the interface + // + + // Initialize the interface implementation + // Return: + // true if it has succeeded, false if it has failed + static bool Initialize(); + + // Shutdown the interface implementation + static void Shutdown(); + + // + // Virtual memory management + // + + // 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 + static void* VirtualReserve(void *address, size_t size, size_t alignment, uint32_t 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 + static bool VirtualRelease(void *address, size_t size); + + // 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 + static bool VirtualCommit(void *address, size_t size); + + // 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 + static bool VirtualDecommit(void *address, size_t size); + + // 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 + static bool VirtualReset(void *address, size_t size, bool unlock); + + // + // Write watching + // + + // Check if the OS supports write watching + static bool SupportsWriteWatch(); + + // Reset the write tracking state for the specified virtual memory range. + // Parameters: + // address - starting virtual address + // size - size of the virtual memory range + static void 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 + static bool GetWriteWatch(bool resetState, void* address, size_t size, void** pageAddresses, uintptr_t* pageAddressesCount); + + // + // Thread and process + // + + // Create a new thread + // Parameters: + // function - the function to be executed by the thread + // param - parameters of the thread + // affinity - processor affinity of the thread + // Return: + // true if it has succeeded, false if it has failed + static bool CreateThread(GCThreadFunction function, void* param, GCThreadAffinity* affinity); + + // Causes the calling thread to sleep for the specified number of milliseconds + // Parameters: + // sleepMSec - time to sleep before switching to another thread + static void Sleep(uint32_t 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 + static void YieldThread(uint32_t switchCount); + + // Get the number of the current processor + static uint32_t GetCurrentProcessorNumber(); + + // Check if the OS supports getting current processor number + static bool CanGetCurrentProcessorNumber(); + + // Set ideal processor for the current thread + // Parameters: + // processorIndex - index of the processor in the group + // affinity - ideal processor affinity for the thread + // Return: + // true if it has succeeded, false if it has failed + static bool SetCurrentThreadIdealAffinity(GCThreadAffinity* affinity); + + // 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 + static uint32_t GetCurrentThreadIdForLogging(); + + // Get id of the current process + // Return: + // Id of the current process + static uint32_t GetCurrentProcessId(); + + // + // Processor topology + // + + // Get number of logical processors + static uint32_t GetLogicalCpuCount(); + + // 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 + static size_t GetLargestOnDieCacheSize(bool trueSize = true); + + // Get number of processors assigned to the current process + // Return: + // The number of processors + static uint32_t GetCurrentProcessCpuCount(); + + // Get affinity mask of the current process + // Parameters: + // processMask - affinity mask for the specified process + // systemMask - affinity mask for the system + // Return: + // true if it has succeeded, false if it has failed + // Remarks: + // A process affinity mask is a bit vector in which each bit represents the processors that + // a process is allowed to run on. A system affinity mask is a bit vector in which each bit + // represents the processors that are configured into a system. + // A process affinity mask is a subset of the system affinity mask. A process is only allowed + // to run on the processors configured into a system. Therefore, the process affinity mask cannot + // specify a 1 bit for a processor when the system affinity mask specifies a 0 bit for that processor. + static bool GetCurrentProcessAffinityMask(uintptr_t *processMask, uintptr_t *systemMask); + + // + // Misc + // + + // Get global memory status + // Parameters: + // ms - pointer to the structure that will be filled in with the memory status + static void GetMemoryStatus(GCMemoryStatus* ms); + + // Flush write buffers of processors that are executing threads of the current process + static void FlushProcessWriteBuffers(); + + // Break into a debugger + static void DebugBreak(); + + // + // Time + // + + // Get a high precision performance counter + // Return: + // The counter value + static int64_t QueryPerformanceCounter(); + + // Get a frequency of the high precision performance counter + // Return: + // The counter frequency + static int64_t QueryPerformanceFrequency(); + + // Get a time stamp with a low precision + // Return: + // Time stamp in milliseconds + static uint32_t GetLowPrecisionTimeStamp(); + + // + // File + // + + // Open a file + // Parameters: + // filename - name of the file to open + // mode - mode to open the file in (like in the CRT fopen) + // Return: + // FILE* of the opened file + static FILE* OpenFile(const WCHAR* filename, const WCHAR* mode); +}; + +#endif // __GCENV_OS_H__ diff --git a/src/gc/env/gcenv.structs.h b/src/gc/env/gcenv.structs.h index e3bfb17f56..7c576a5928 100644 --- a/src/gc/env/gcenv.structs.h +++ b/src/gc/env/gcenv.structs.h @@ -31,6 +31,62 @@ struct GCMemoryStatus typedef void * HANDLE; +#ifdef PLATFORM_UNIX + +class EEThreadId +{ + pthread_t m_id; + // Indicates whether the m_id is valid or not. pthread_t doesn't have any + // portable "invalid" value. + bool m_isValid; + +public: + bool IsCurrentThread() + { + return m_isValid && pthread_equal(m_id, pthread_self()); + } + + void SetToCurrentThread() + { + m_id = pthread_self(); + m_isValid = true; + } + + void Clear() + { + m_isValid = false; + } +}; + +#else // PLATFORM_UNIX + +#ifndef _INC_WINDOWS +extern "C" uint32_t __stdcall GetCurrentThreadId(); +#endif + +class EEThreadId +{ + uint32_t m_uiId; +public: + + bool IsCurrentThread() + { + return m_uiId == ::GetCurrentThreadId(); + } + + void SetToCurrentThread() + { + m_uiId = ::GetCurrentThreadId(); + } + + void Clear() + { + m_uiId = 0; + } +}; + +#endif // PLATFORM_UNIX + #ifndef _INC_WINDOWS typedef union _LARGE_INTEGER { @@ -46,7 +102,13 @@ typedef union _LARGE_INTEGER { int64_t QuadPart; } LARGE_INTEGER, *PLARGE_INTEGER; -#ifdef WIN32 +#ifdef PLATFORM_UNIX + +typedef struct _RTL_CRITICAL_SECTION { + pthread_mutex_t mutex; +} CRITICAL_SECTION, RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION; + +#else #pragma pack(push, 8) @@ -67,12 +129,6 @@ typedef struct _RTL_CRITICAL_SECTION { #pragma pack(pop) -#else - -typedef struct _RTL_CRITICAL_SECTION { - pthread_mutex_t mutex; -} CRITICAL_SECTION, RTL_CRITICAL_SECTION, *PRTL_CRITICAL_SECTION; - #endif #endif // _INC_WINDOWS diff --git a/src/gc/env/gcenv.sync.h b/src/gc/env/gcenv.sync.h index c3aea23fde..fe619cc696 100644 --- a/src/gc/env/gcenv.sync.h +++ b/src/gc/env/gcenv.sync.h @@ -7,19 +7,6 @@ // // Helper classes expected by the GC // -class EEThreadId -{ -public: - EEThreadId(uint32_t uiId) : m_uiId(uiId) {} - bool IsSameThread() - { - return m_uiId == GetCurrentThreadId(); - } - -private: - uint32_t m_uiId; -}; - #define CRST_REENTRANCY 0 #define CRST_UNSAFE_SAMELEVEL 0 #define CRST_UNSAFE_ANYMODE 0 @@ -33,37 +20,37 @@ typedef int CrstType; class CrstStatic { - CRITICAL_SECTION m_cs; + CLRCriticalSection m_cs; #ifdef _DEBUG - uint32_t m_holderThreadId; + EEThreadId m_holderThreadId; #endif public: bool InitNoThrow(CrstType eType, CrstFlags eFlags = CRST_DEFAULT) { - UnsafeInitializeCriticalSection(&m_cs); + m_cs.Initialize(); return true; } void Destroy() { - UnsafeDeleteCriticalSection(&m_cs); + m_cs.Destroy(); } void Enter() { - UnsafeEEEnterCriticalSection(&m_cs); + m_cs.Enter(); #ifdef _DEBUG - m_holderThreadId = GetCurrentThreadId(); + m_holderThreadId.SetToCurrentThread(); #endif } void Leave() { #ifdef _DEBUG - m_holderThreadId = 0; + m_holderThreadId.Clear(); #endif - UnsafeEELeaveCriticalSection(&m_cs); + m_cs.Leave(); } #ifdef _DEBUG @@ -74,7 +61,7 @@ public: bool OwnedByCurrentThread() { - return GetHolderThreadId().IsSameThread(); + return GetHolderThreadId().IsCurrentThread(); } #endif }; diff --git a/src/gc/env/gcenv.unix.cpp b/src/gc/env/gcenv.unix.cpp deleted file mode 100644 index c9186d5d43..0000000000 --- a/src/gc/env/gcenv.unix.cpp +++ /dev/null @@ -1,569 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -// -// Implementation of the GC environment -// - -#include "common.h" - -#include "gcenv.h" -#include "gc.h" - -#include <sys/mman.h> -#include <sys/time.h> - -int32_t FastInterlockIncrement(int32_t volatile *lpAddend) -{ - return __sync_add_and_fetch(lpAddend, 1); -} - -int32_t FastInterlockDecrement(int32_t volatile *lpAddend) -{ - return __sync_sub_and_fetch(lpAddend, 1); -} - -int32_t FastInterlockExchange(int32_t volatile *Target, int32_t Value) -{ - return __sync_swap(Target, Value); -} - -int32_t FastInterlockCompareExchange(int32_t volatile *Destination, int32_t Exchange, int32_t Comperand) -{ - return __sync_val_compare_and_swap(Destination, Comperand, Exchange); -} - -int32_t FastInterlockExchangeAdd(int32_t volatile *Addend, int32_t Value) -{ - return __sync_fetch_and_add(Addend, Value); -} - -void * _FastInterlockExchangePointer(void * volatile *Target, void * Value) -{ - return __sync_swap(Target, Value); -} - -void * _FastInterlockCompareExchangePointer(void * volatile *Destination, void * Exchange, void * Comperand) -{ - return __sync_val_compare_and_swap(Destination, Comperand, Exchange); -} - -void FastInterlockOr(uint32_t volatile *p, uint32_t msk) -{ - __sync_fetch_and_or(p, msk); -} - -void FastInterlockAnd(uint32_t volatile *p, uint32_t msk) -{ - __sync_fetch_and_and(p, msk); -} - - -void UnsafeInitializeCriticalSection(CRITICAL_SECTION * lpCriticalSection) -{ - pthread_mutex_init(&lpCriticalSection->mutex, NULL); -} - -void UnsafeEEEnterCriticalSection(CRITICAL_SECTION *lpCriticalSection) -{ - pthread_mutex_lock(&lpCriticalSection->mutex); -} - -void UnsafeEELeaveCriticalSection(CRITICAL_SECTION * lpCriticalSection) -{ - pthread_mutex_unlock(&lpCriticalSection->mutex); -} - -void UnsafeDeleteCriticalSection(CRITICAL_SECTION *lpCriticalSection) -{ - pthread_mutex_destroy(&lpCriticalSection->mutex); -} - - -void GetProcessMemoryLoad(GCMemoryStatus* pGCMemStatus) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; - - pGCMemStatus->dwMemoryLoad = 0; - pGCMemStatus->ullTotalPageFile = 0; - pGCMemStatus->ullAvailPageFile = 0; - - // 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); - pGCMemStatus->ullTotalVirtual = _128TB; - pGCMemStatus->ullAvailVirtual = _128TB; - - // TODO: Implement - pGCMemStatus->ullTotalPhys = _128TB; - pGCMemStatus->ullAvailPhys = _128TB; - - // If the machine has more RAM than virtual address limit, let us cap it. - // Our GC can never use more than virtual address limit. - if (pGCMemStatus->ullAvailPhys > pGCMemStatus->ullTotalVirtual) - { - pGCMemStatus->ullAvailPhys = pGCMemStatus->ullAvailVirtual; - } -} - -void CLREventStatic::CreateManualEvent(bool bInitialState) -{ - // TODO: Implement - m_fInitialized = true; -} - -void CLREventStatic::CreateAutoEvent(bool bInitialState) -{ - // TODO: Implement - m_fInitialized = true; -} - -void CLREventStatic::CreateOSManualEvent(bool bInitialState) -{ - CreateManualEvent(bInitialState); -} - -void CLREventStatic::CreateOSAutoEvent (bool bInitialState) -{ - CreateAutoEvent(bInitialState); -} - -void CLREventStatic::CloseEvent() -{ - if (m_fInitialized) - { - // TODO: Implement - m_fInitialized = false; - } -} - -bool CLREventStatic::IsValid() const -{ - return m_fInitialized; -} - -bool CLREventStatic::Set() -{ - if (!m_fInitialized) - return false; - // TODO: Implement - return true; -} - -bool CLREventStatic::Reset() -{ - if (!m_fInitialized) - return false; - // TODO: Implement - return true; -} - -uint32_t CLREventStatic::Wait(uint32_t dwMilliseconds, bool bAlertable) -{ - DWORD result = WAIT_FAILED; - - if (m_fInitialized) - { - bool disablePreemptive = false; - Thread * pCurThread = GetThread(); - - if (NULL != pCurThread) - { - if (pCurThread->PreemptiveGCDisabled()) - { - pCurThread->EnablePreemptiveGC(); - disablePreemptive = true; - } - } - - // TODO: Implement - result = WAIT_OBJECT_0; - - if (disablePreemptive) - { - pCurThread->DisablePreemptiveGC(); - } - } - - return result; -} - -bool __SwitchToThread(uint32_t dwSleepMSec, uint32_t dwSwitchCount) -{ - return sched_yield() == 0; -} - -void * ClrVirtualAlloc( - void * lpAddress, - size_t dwSize, - uint32_t flAllocationType, - uint32_t flProtect) -{ - return ClrVirtualAllocAligned(lpAddress, dwSize, flAllocationType, flProtect, OS_PAGE_SIZE); -} - -static int W32toUnixAccessControl(uint32_t flProtect) -{ - int prot = 0; - - switch (flProtect & 0xff) - { - case PAGE_NOACCESS: - prot = PROT_NONE; - break; - case PAGE_READWRITE: - prot = PROT_READ | PROT_WRITE; - break; - default: - _ASSERTE(false); - break; - } - return prot; -} - -void * ClrVirtualAllocAligned( - void * lpAddress, - size_t dwSize, - uint32_t flAllocationType, - uint32_t flProtect, - size_t dwAlignment) -{ - if ((flAllocationType & ~(MEM_RESERVE | MEM_COMMIT)) != 0) - { - // TODO: Implement - return NULL; - } - - _ASSERTE(((size_t)lpAddress & (OS_PAGE_SIZE - 1)) == 0); - - // Align size to whole pages - dwSize = (dwSize + (OS_PAGE_SIZE - 1)) & ~(OS_PAGE_SIZE - 1); - - if (flAllocationType & MEM_RESERVE) - { - size_t alignedSize = dwSize; - - if (dwAlignment > OS_PAGE_SIZE) - alignedSize += (dwAlignment - OS_PAGE_SIZE); - - void * pRetVal = mmap(lpAddress, alignedSize, W32toUnixAccessControl(flProtect), - MAP_ANON | MAP_PRIVATE, -1, 0); - - if (dwAlignment > OS_PAGE_SIZE && pRetVal != NULL) - { - void * pAlignedRetVal = (void *)(((size_t)pRetVal + (dwAlignment - 1)) & ~(dwAlignment - 1)); - - size_t startPadding = (size_t)pAlignedRetVal - (size_t)pRetVal; - if (startPadding != 0) - { - int ret = munmap(pRetVal, startPadding); - _ASSERTE(ret == 0); - } - - size_t endPadding = alignedSize - (startPadding + dwSize); - if (endPadding != 0) - { - int ret = munmap((void *)((size_t)pAlignedRetVal + dwSize), endPadding); - _ASSERTE(ret == 0); - } - - pRetVal = pAlignedRetVal; - } - - return pRetVal; - } - - if (flAllocationType & MEM_COMMIT) - { - int ret = mprotect(lpAddress, dwSize, W32toUnixAccessControl(flProtect)); - return (ret == 0) ? lpAddress : NULL; - } - - return NULL; -} - -bool ClrVirtualFree( - void * lpAddress, - size_t dwSize, - uint32_t dwFreeType) -{ - // TODO: Implement - return false; -} - -bool -ClrVirtualProtect( - void * lpAddress, - size_t dwSize, - uint32_t flNewProtect, - uint32_t * lpflOldProtect) -{ - // TODO: Implement, not currently used - return false; -} - -MethodTable * g_pFreeObjectMethodTable; - -GCSystemInfo g_SystemInfo; - -void InitializeSystemInfo() -{ - // TODO: Implement - g_SystemInfo.dwNumberOfProcessors = 4; - - g_SystemInfo.dwPageSize = OS_PAGE_SIZE; - g_SystemInfo.dwAllocationGranularity = OS_PAGE_SIZE; -} - -int32_t g_TrapReturningThreads; - -bool g_fFinalizerRunOnShutDown; - -#ifdef _MSC_VER -__declspec(thread) -#else -__thread -#endif -Thread * pCurrentThread; - -Thread * GetThread() -{ - return pCurrentThread; -} - -Thread * g_pThreadList = NULL; - -Thread * ThreadStore::GetThreadList(Thread * pThread) -{ - if (pThread == NULL) - return g_pThreadList; - - return pThread->m_pNext; -} - -void ThreadStore::AttachCurrentThread(bool fAcquireThreadStoreLock) -{ - // TODO: Locks - - Thread * pThread = new Thread(); - pThread->GetAllocContext()->init(); - pCurrentThread = pThread; - - pThread->m_pNext = g_pThreadList; - g_pThreadList = pThread; -} - -void DestroyThread(Thread * pThread) -{ - // TODO: Implement -} - -void FinalizerThread::EnableFinalization() -{ - // Signal to finalizer thread that there are objects to finalize - // TODO: Implement for finalization -} - -bool PalHasCapability(PalCapability capability) -{ - // TODO: Implement for background GC - return false; -} - -WINBASEAPI -UINT -WINAPI -GetWriteWatch( - DWORD dwFlags, - PVOID lpBaseAddress, - SIZE_T dwRegionSize, - PVOID *lpAddresses, - uintptr_t * lpdwCount, - uint32_t * lpdwGranularity - ) -{ - // TODO: Implement for background GC - *lpAddresses = NULL; - *lpdwCount = 0; - // Until it is implemented, return non-zero value as an indicator of failure - return 1; -} - -WINBASEAPI -UINT -WINAPI -ResetWriteWatch( - LPVOID lpBaseAddress, - SIZE_T dwRegionSize - ) -{ - // TODO: Implement for background GC - // Until it is implemented, return non-zero value as an indicator of failure - return 1; -} - -WINBASEAPI -BOOL -WINAPI -VirtualUnlock( - LPVOID lpAddress, - SIZE_T dwSize - ) -{ - // TODO: Implement - return false; -} - - -WINBASEAPI -VOID -WINAPI -FlushProcessWriteBuffers() -{ - // TODO: Implement -} - -const int tccSecondsToMillieSeconds = 1000; -const int tccSecondsToMicroSeconds = 1000000; -const int tccMillieSecondsToMicroSeconds = 1000; // 10^3 - -WINBASEAPI -DWORD -WINAPI -GetTickCount() -{ - // TODO: More efficient, platform-specific implementation - struct timeval tv; - if (gettimeofday(&tv, NULL) == -1) - { - _ASSERTE(!"gettimeofday() failed"); - return 0; - } - return (tv.tv_sec * tccSecondsToMillieSeconds) + (tv.tv_usec / tccMillieSecondsToMicroSeconds); -} - -WINBASEAPI -BOOL -WINAPI -QueryPerformanceCounter(LARGE_INTEGER *lpPerformanceCount) -{ - // TODO: More efficient, platform-specific implementation - struct timeval tv; - if (gettimeofday(&tv, NULL) == -1) - { - _ASSERTE(!"gettimeofday() failed"); - return FALSE; - } - lpPerformanceCount->QuadPart = - (int64_t) tv.tv_sec * (int64_t) tccSecondsToMicroSeconds + (int64_t) tv.tv_usec; - return TRUE; -} - -WINBASEAPI -BOOL -WINAPI -QueryPerformanceFrequency(LARGE_INTEGER *lpFrequency) -{ - lpFrequency->QuadPart = (int64_t) tccSecondsToMicroSeconds; - return TRUE; -} - -WINBASEAPI -DWORD -WINAPI -GetCurrentThreadId( - VOID) -{ - // TODO: Implement - return 1; -} - -WINBASEAPI -VOID -WINAPI -YieldProcessor() -{ - // TODO: Implement -} - -WINBASEAPI -void -WINAPI -DebugBreak() -{ - // TODO: Implement -} - -WINBASEAPI -VOID -WINAPI -MemoryBarrier() -{ - // TODO: Implement -} - -// File I/O - Used for tracking only - -WINBASEAPI -DWORD -WINAPI -SetFilePointer( - HANDLE hFile, - int32_t lDistanceToMove, - int32_t * lpDistanceToMoveHigh, - DWORD dwMoveMethod) -{ - // TODO: Reimplement callers using CRT - return 0; -} - -WINBASEAPI -BOOL -WINAPI -FlushFileBuffers( - HANDLE hFile) -{ - // TODO: Reimplement callers using CRT - return FALSE; -} - -WINBASEAPI -BOOL -WINAPI -WriteFile( - HANDLE hFile, - LPCVOID lpBuffer, - DWORD nNumberOfBytesToWrite, - DWORD * lpNumberOfBytesWritten, - PVOID lpOverlapped) -{ - // TODO: Reimplement callers using CRT - return FALSE; -} - -WINBASEAPI -BOOL -WINAPI -CloseHandle( - HANDLE hObject) -{ - // TODO: Reimplement callers using CRT - return FALSE; -} - -WINBASEAPI -DWORD -WINAPI -GetLastError() -{ - return 1; -} diff --git a/src/gc/env/gcenv.windows.cpp b/src/gc/env/gcenv.windows.cpp deleted file mode 100644 index 1059e5e6a2..0000000000 --- a/src/gc/env/gcenv.windows.cpp +++ /dev/null @@ -1,268 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -// -// Implementation of the GC environment -// - -#include "common.h" - -#include "windows.h" - -#include "gcenv.h" -#include "gc.h" - -int32_t FastInterlockIncrement(int32_t volatile *lpAddend) -{ - return InterlockedIncrement((LONG *)lpAddend); -} - -int32_t FastInterlockDecrement(int32_t volatile *lpAddend) -{ - return InterlockedDecrement((LONG *)lpAddend); -} - -int32_t FastInterlockExchange(int32_t volatile *Target, int32_t Value) -{ - return InterlockedExchange((LONG *)Target, Value); -} - -int32_t FastInterlockCompareExchange(int32_t volatile *Destination, int32_t Exchange, int32_t Comperand) -{ - return InterlockedCompareExchange((LONG *)Destination, Exchange, Comperand); -} - -int32_t FastInterlockExchangeAdd(int32_t volatile *Addend, int32_t Value) -{ - return InterlockedExchangeAdd((LONG *)Addend, Value); -} - -void * _FastInterlockExchangePointer(void * volatile *Target, void * Value) -{ - return InterlockedExchangePointer(Target, Value); -} - -void * _FastInterlockCompareExchangePointer(void * volatile *Destination, void * Exchange, void * Comperand) -{ - return InterlockedCompareExchangePointer(Destination, Exchange, Comperand); -} - -void FastInterlockOr(uint32_t volatile *p, uint32_t msk) -{ - InterlockedOr((LONG volatile *)p, msk); -} - -void FastInterlockAnd(uint32_t volatile *p, uint32_t msk) -{ - InterlockedAnd((LONG volatile *)p, msk); -} - - -void UnsafeInitializeCriticalSection(CRITICAL_SECTION * lpCriticalSection) -{ - InitializeCriticalSection(lpCriticalSection); -} - -void UnsafeEEEnterCriticalSection(CRITICAL_SECTION *lpCriticalSection) -{ - EnterCriticalSection(lpCriticalSection); -} - -void UnsafeEELeaveCriticalSection(CRITICAL_SECTION * lpCriticalSection) -{ - LeaveCriticalSection(lpCriticalSection); -} - -void UnsafeDeleteCriticalSection(CRITICAL_SECTION *lpCriticalSection) -{ - DeleteCriticalSection(lpCriticalSection); -} - - -void GetProcessMemoryLoad(GCMemoryStatus* pGCMemStatus) -{ - CONTRACTL - { - NOTHROW; - GC_NOTRIGGER; - } - CONTRACTL_END; - - MEMORYSTATUSEX memStatus; - - memStatus.dwLength = sizeof(MEMORYSTATUSEX); - BOOL fRet = GlobalMemoryStatusEx(&memStatus); - _ASSERTE (fRet); - - // If the machine has more RAM than virtual address limit, let us cap it. - // Our GC can never use more than virtual address limit. - if (memStatus.ullAvailPhys > memStatus.ullTotalVirtual) - { - memStatus.ullAvailPhys = memStatus.ullAvailVirtual; - } - - // Convert Windows struct to abstract struct - pGCMemStatus->dwMemoryLoad = memStatus.dwMemoryLoad ; - pGCMemStatus->ullTotalPhys = memStatus.ullTotalPhys ; - pGCMemStatus->ullAvailPhys = memStatus.ullAvailPhys ; - pGCMemStatus->ullTotalPageFile = memStatus.ullTotalPageFile ; - pGCMemStatus->ullAvailPageFile = memStatus.ullAvailPageFile ; - pGCMemStatus->ullTotalVirtual = memStatus.ullTotalVirtual ; - pGCMemStatus->ullAvailVirtual = memStatus.ullAvailVirtual ; -} - -void CLREventStatic::CreateManualEvent(bool bInitialState) -{ - m_hEvent = CreateEventW(NULL, TRUE, bInitialState, NULL); - m_fInitialized = true; -} - -void CLREventStatic::CreateAutoEvent(bool bInitialState) -{ - m_hEvent = CreateEventW(NULL, FALSE, bInitialState, NULL); - m_fInitialized = true; -} - -void CLREventStatic::CreateOSManualEvent(bool bInitialState) -{ - m_hEvent = CreateEventW(NULL, TRUE, bInitialState, NULL); - m_fInitialized = true; -} - -void CLREventStatic::CreateOSAutoEvent(bool bInitialState) -{ - m_hEvent = CreateEventW(NULL, FALSE, bInitialState, NULL); - m_fInitialized = true; -} - -void CLREventStatic::CloseEvent() -{ - if (m_fInitialized && m_hEvent != INVALID_HANDLE_VALUE) - { - CloseHandle(m_hEvent); - m_hEvent = INVALID_HANDLE_VALUE; - } -} - -bool CLREventStatic::IsValid() const -{ - return m_fInitialized && m_hEvent != INVALID_HANDLE_VALUE; -} - -bool CLREventStatic::Set() -{ - if (!m_fInitialized) - return false; - return !!SetEvent(m_hEvent); -} - -bool CLREventStatic::Reset() -{ - if (!m_fInitialized) - return false; - return !!ResetEvent(m_hEvent); -} - -uint32_t CLREventStatic::Wait(uint32_t dwMilliseconds, bool bAlertable) -{ - DWORD result = WAIT_FAILED; - - if (m_fInitialized) - { - bool disablePreemptive = false; - Thread * pCurThread = GetThread(); - - if (NULL != pCurThread) - { - if (pCurThread->PreemptiveGCDisabled()) - { - pCurThread->EnablePreemptiveGC(); - disablePreemptive = true; - } - } - - result = WaitForSingleObjectEx(m_hEvent, dwMilliseconds, bAlertable); - - if (disablePreemptive) - { - pCurThread->DisablePreemptiveGC(); - } - } - - return result; -} - -bool __SwitchToThread(uint32_t dwSleepMSec, uint32_t dwSwitchCount) -{ - SwitchToThread(); - return true; -} - -void * ClrVirtualAlloc( - void * lpAddress, - size_t dwSize, - uint32_t flAllocationType, - uint32_t flProtect) -{ - return VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect); -} - -void * ClrVirtualAllocAligned( - void * lpAddress, - size_t dwSize, - uint32_t flAllocationType, - uint32_t flProtect, - size_t dwAlignment) -{ - return VirtualAlloc(lpAddress, dwSize, flAllocationType, flProtect); -} - -bool ClrVirtualFree( - void * lpAddress, - size_t dwSize, - uint32_t dwFreeType) -{ - return !!VirtualFree(lpAddress, dwSize, dwFreeType); -} - -bool -ClrVirtualProtect( - void * lpAddress, - size_t dwSize, - uint32_t flNewProtect, - uint32_t * lpflOldProtect) -{ - return !!VirtualProtect(lpAddress, dwSize, flNewProtect, (DWORD *)lpflOldProtect); -} - -MethodTable * g_pFreeObjectMethodTable; - -GCSystemInfo g_SystemInfo; - -void InitializeSystemInfo() -{ - SYSTEM_INFO systemInfo; - GetSystemInfo(&systemInfo); - - g_SystemInfo.dwNumberOfProcessors = systemInfo.dwNumberOfProcessors; - g_SystemInfo.dwPageSize = systemInfo.dwPageSize; - g_SystemInfo.dwAllocationGranularity = systemInfo.dwAllocationGranularity; -} - -int32_t g_TrapReturningThreads; - -bool g_fFinalizerRunOnShutDown; - -void DestroyThread(Thread * pThread) -{ - // TODO: Implement -} - -bool PalHasCapability(PalCapability capability) -{ - // TODO: Implement for background GC - return false; -} - |