From 54990d90fcffbae79d72cfb2e37bb4cac4e0660c Mon Sep 17 00:00:00 2001 From: Jan Vorlicek Date: Wed, 14 Oct 2015 03:01:25 +0200 Subject: [PATCH] GC OS interface refactoring This change replaces all calls of OS specific functions in the GC by a call to a platform agnostic interface. Critical sections were abstracted too. The logging file access was changed to use CRT functions instead of Windows specific APIs. A "size" member was added to the card_table_info so that we can pass the right size to the VirtualRelease method when destroying the card table. I have also fixed a bug in the gc_heap::make_card_table error path where when VirtualCommit failed, it called VirtualRelease with size that was not the reserved size, but the committed size. Other related changes - All interlocked operations moved to Interlocked class as static methods - Removed unused function prototypes - Shuffled stuff in the root CMakeLists.txt to enable building the GC sample using the settings inherited from the root CMakeLists.txt and to clean up some things that have rotted over time, like the FEATURE_xxx macros not being in one alphabetically ordered block - Fixed the VOLATILE_MEMORY_BARRIER macro in the gcenv.base.h - Replaced uint32_t thread id by EEThreadId - Removed thread handles storage (g_gc_thread) from the GC. The thread handle is closed right after the thread is launched. That allowed me to get rid of the GCThreadHandle - Renamed the methods of the EEThreadId to be easier to understand - Moved the gcenv.windows.cpp and gcenv.unix.cpp to the sample folder --- CMakeLists.txt | 520 +++++++------- .../System.Globalization.Native/CMakeLists.txt | 1 + src/debug/ee/rcthread.cpp | 4 +- src/dlls/mscoree/coreclr/CMakeLists.txt | 1 - src/gc/env/common.h | 2 +- src/gc/env/gcenv.base.h | 380 ++-------- src/gc/env/gcenv.ee.h | 85 +++ src/gc/env/gcenv.interlocked.h | 102 +++ src/gc/env/gcenv.interlocked.inl | 184 +++++ src/gc/env/gcenv.object.h | 4 +- src/gc/env/gcenv.os.h | 274 ++++++++ src/gc/env/gcenv.structs.h | 70 +- src/gc/env/gcenv.sync.h | 31 +- src/gc/env/gcenv.windows.cpp | 268 ------- src/gc/gc.cpp | 769 +++++++++------------ src/gc/gcee.cpp | 10 +- src/gc/gcpriv.h | 93 +-- src/gc/gcscan.cpp | 4 +- src/gc/handletable.cpp | 2 +- src/gc/handletable.inl | 4 +- src/gc/handletablecache.cpp | 26 +- src/gc/handletablecore.cpp | 12 +- src/gc/objecthandle.cpp | 8 +- src/gc/sample/CMakeLists.txt | 41 +- src/gc/sample/GCSample.cpp | 9 +- src/gc/sample/GCSample.vcxproj | 4 +- src/gc/sample/GCSample.vcxproj.filters | 6 +- src/gc/sample/gcenv.cpp | 156 ----- src/gc/sample/gcenv.ee.cpp | 289 ++++++++ src/gc/sample/gcenv.h | 9 + src/gc/{env => sample}/gcenv.unix.cpp | 68 +- src/gc/sample/gcenv.windows.cpp | 446 ++++++++++++ src/pal/inc/pal.h | 1 + src/pal/src/exception/seh.cpp | 8 +- src/pal/src/misc/time.cpp | 10 +- src/pal/src/thread/context.cpp | 1 - .../tests/palsuite/eventprovider/CMakeLists.txt | 3 +- src/strongname/api/api.props | 3 +- src/strongname/api/common.h | 3 + src/vm/CMakeLists.txt | 3 +- src/vm/appdomain.cpp | 1 - src/vm/common.h | 4 +- src/vm/crst.cpp | 14 +- src/vm/crst.h | 2 +- src/vm/eehash.inl | 4 +- src/vm/{gcenv.cpp => gcenv.ee.cpp} | 24 +- src/vm/gcenv.ee.h | 6 + src/vm/gcenv.h | 94 +-- src/vm/gcenv.interlocked.h | 6 + src/vm/gcenv.interlocked.inl | 6 + src/vm/gcenv.os.cpp | 520 ++++++++++++++ src/vm/gcenv.os.h | 6 + src/vm/hash.cpp | 4 +- src/vm/spinlock.cpp | 6 +- src/vm/syncblk.cpp | 2 +- src/vm/syncblk.h | 2 +- src/vm/threads.cpp | 12 +- src/vm/threadsuspend.cpp | 8 +- src/vm/util.hpp | 8 +- src/vm/wks/wks.targets | 3 +- 60 files changed, 2854 insertions(+), 1792 deletions(-) create mode 100644 src/gc/env/gcenv.ee.h create mode 100644 src/gc/env/gcenv.interlocked.h create mode 100644 src/gc/env/gcenv.interlocked.inl create mode 100644 src/gc/env/gcenv.os.h delete mode 100644 src/gc/env/gcenv.windows.cpp delete mode 100644 src/gc/sample/gcenv.cpp create mode 100644 src/gc/sample/gcenv.ee.cpp rename src/gc/{env => sample}/gcenv.unix.cpp (91%) create mode 100644 src/gc/sample/gcenv.windows.cpp rename src/vm/{gcenv.cpp => gcenv.ee.cpp} (97%) create mode 100644 src/vm/gcenv.ee.h create mode 100644 src/vm/gcenv.interlocked.h create mode 100644 src/vm/gcenv.interlocked.inl create mode 100644 src/vm/gcenv.os.cpp create mode 100644 src/vm/gcenv.os.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 4bdc49f..15bed4d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,6 +104,17 @@ elseif(WIN32) endif() endif() +if(CLR_CMAKE_PLATFORM_UNIX) + # Set flag to indicate if this will be a 64bit build + # CMAKE_SYSTEM_PROCESSOR returns the value of `uname -p`. + # For the AMD/Intel 64bit architecure two different strings are common. + # Linux and Darwin identify it as "x86_64" while FreeBSD uses the + # "amd64" string. Accept either of the two here. + if(CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL amd64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64) + set(IS_64BIT_BUILD 1) + endif (CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL amd64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64) +endif(CLR_CMAKE_PLATFORM_UNIX) + if(WIN32) enable_language(ASM_MASM) else() @@ -248,13 +259,6 @@ elseif (CLR_CMAKE_PLATFORM_UNIX) endif(WIN32) -if (WIN32 OR CLR_CMAKE_PLATFORM_LINUX) - add_definitions(-DFEATURE_EVENT_TRACE=1) -endif (WIN32 OR CLR_CMAKE_PLATFORM_LINUX) - -if (CLR_CMAKE_PLATFORM_LINUX) - add_definitions(-DFEATURE_EVENTSOURCE_XPLAT=1) -endif (CLR_CMAKE_PLATFORM_LINUX) if (CLR_CMAKE_PLATFORM_UNIX) add_definitions(-DPLATFORM_UNIX=1) @@ -325,125 +329,111 @@ if (CLR_CMAKE_PLATFORM_UNIX) endif () endif(UPPERCASE_CMAKE_BUILD_TYPE STREQUAL DEBUG OR UPPERCASE_CMAKE_BUILD_TYPE STREQUAL CHECKED) - add_subdirectory(src/ToolBox/SOS/lldbplugin) - add_subdirectory(src/pal) - add_subdirectory(src/corefx) - add_subdirectory(src/coreclr/hosts/unixcoreruncommon) - add_subdirectory(src/coreclr/hosts/unixcorerun) - add_subdirectory(src/coreclr/hosts/unixcoreconsole) - add_subdirectory(src/ildasm/unixcoreclrloader) -endif(CLR_CMAKE_PLATFORM_UNIX) - -if(CLR_CMAKE_PLATFORM_DARWIN) - add_subdirectory(src/coreclr/hosts/osxbundlerun) -endif(CLR_CMAKE_PLATFORM_DARWIN) - -# Add this subdir. We install the headers for the jit. -add_subdirectory(src/pal/prebuilt/inc) - -# Set to 1 if you want to clear the CMAKE initial compiler flags and set all the flags explicitly -# or to 0 if the CMake generated flags should be used + add_definitions(-DDISABLE_CONTRACTS) + # The -ferror-limit is helpful during the porting, it makes sure the compiler doesn't stop + # after hitting just about 20 errors. + add_compile_options(-ferror-limit=4096) + + # All warnings that are not explicitly disabled are reported as errors + add_compile_options(-Werror) + + # Disabled warnings + add_compile_options(-Wno-unused-private-field) + add_compile_options(-Wno-unused-variable) + # Explicit constructor calls are not supported by clang (this->ClassName::ClassName()) + add_compile_options(-Wno-microsoft) + # This warning is caused by comparing 'this' to NULL + add_compile_options(-Wno-tautological-compare) + # There are constants of type BOOL used in a condition. But BOOL is defined as int + # and so the compiler thinks that there is a mistake. + add_compile_options(-Wno-constant-logical-operand) + + add_compile_options(-Wno-unknown-warning-option) + + #These seem to indicate real issues + add_compile_options(-Wno-invalid-offsetof) + # The following warning indicates that an attribute __attribute__((__ms_struct__)) was applied + # to a struct or a class that has virtual members or a base class. In that case, clang + # may not generate the same object layout as MSVC. + add_compile_options(-Wno-incompatible-ms-struct) -# Enable for UNIX altjit on Windows - set(CLR_CMAKE_PLATFORM_UNIX_TARGET_AMD64 1) -# Enable for UNIX altjit on Windows - add_definitions(-DCLR_CMAKE_PLATFORM_UNIX=1) - -if (WIN32) - set(OVERRIDE_CMAKE_CXX_FLAGS 1) -elseif (CLR_CMAKE_PLATFORM_UNIX) - # Set flag to indicate if this will be a 64bit build - # CMAKE_SYSTEM_PROCESSOR returns the value of `uname -p`. - # For the AMD/Intel 64bit architecure two different strings are common. - # Linux and Darwin identify it as "x86_64" while FreeBSD uses the - # "amd64" string. Accept either of the two here. - if(CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL amd64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64) - set(IS_64BIT_BUILD 1) - endif (CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL amd64 OR CMAKE_SYSTEM_PROCESSOR STREQUAL aarch64) -endif(WIN32) - -if (OVERRIDE_CMAKE_CXX_FLAGS) +endif(CLR_CMAKE_PLATFORM_UNIX) -# Compile options for targeting windows if (WIN32) - -# The following options are set by the razzle build -add_compile_options(/TP) # compile all files as C++ -add_compile_options(/FIWarningControl.h) # force include of WarningControl.h -add_compile_options(/d2Zi+) # make optimized builds debugging easier -add_compile_options(/nologo) # Suppress Startup Banner -add_compile_options(/W3) # set warning level to 3 -add_compile_options(/WX) # treat warnings as errors -add_compile_options(/Oi) # enable intrinsics -add_compile_options(/Oy-) # disable suppressing of the creation of frame pointers on the call stack for quicker function calls -add_compile_options(/U_MT) # undefine the predefined _MT macro -add_compile_options(/GF) # enable read-only string pooling -add_compile_options(/Gm-) # disable minimal rebuild -add_compile_options(/EHa) # enable C++ EH (w/ SEH exceptions) -add_compile_options(/Zp8) # pack structs on 8-byte boundary -add_compile_options(/GS) # enable security checks -add_compile_options(/Gy) # separate functions for linker -add_compile_options(/Zc:wchar_t-) # C++ language conformance: wchar_t is NOT the native type, but a typedef -add_compile_options(/Zc:forScope) # C++ language conformance: enforce Standard C++ for scoping rules -add_compile_options(/GR-) # disable C++ RTTI -add_compile_options(/FC) # use full pathnames in diagnostics -add_compile_options(/Zl) # omit default library name in .OBJ -add_compile_options(/MP) # Build with Multiple Processes (number of processes equal to the number of processors) -add_compile_options(/GS) # Buffer Security Check -add_compile_options(/Zm200) # Specify Precompiled Header Memory Allocation Limit of 150MB -add_compile_options(/wd4960 /wd4961 /wd4603 /wd4627 /wd4838 /wd4456 /wd4457 /wd4458 /wd4459 /wd4091 /we4640) -add_compile_options(/Zi) # enable debugging information - -if (CLR_CMAKE_PLATFORM_ARCH_I386) - add_compile_options(/Gz) -endif (CLR_CMAKE_PLATFORM_ARCH_I386) - -add_compile_options($<$,$>:/GL>) -add_compile_options($<$,$>,$>:/O1>) - -if (IS_64BIT_BUILD EQUAL 1) -# The generator expression in the following command means that the /homeparams option is added only for debug builds -add_compile_options($<$:/homeparams>) # Force parameters passed in registers to be written to the stack -endif (IS_64BIT_BUILD EQUAL 1) - -# Disable the following line for UNIX altjit on Windows -set(CMAKE_CXX_STANDARD_LIBRARIES "") # do not link against standard win32 libs i.e. kernel32, uuid, user32, etc. - -# Linker flags -# -# Disable the following line for UNIX altjit on Windows -set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /MANIFEST:NO") #Do not create Side-by-Side Assembly Manifest -set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SUBSYSTEM:WINDOWS,6.00") #windows subsystem -set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /LARGEADDRESSAWARE") # can handle addresses larger than 2 gigabytes -set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /RELEASE") #sets the checksum in the header -set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /NXCOMPAT") #Compatible with Data Execution Prevention -set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DYNAMICBASE") #Use address space layout randomization -set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DEBUGTYPE:cv,fixup") #debugging format -set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /PDBCOMPRESS") #shrink pdb size -set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DEBUG") -set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /IGNORE:4197,4013,4254,4070") -set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /INCREMENTAL:NO") - -set(CMAKE_STATIC_LINKER_FLAGS "${CMAKE_STATIC_LINKER_FLAGS} /IGNORE:4221") - -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DEBUG /PDBCOMPRESS") -set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:1572864") - -# Debug build specific flags -set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "/NOVCFEATURE") - -# Checked build specific flags -set(CMAKE_SHARED_LINKER_FLAGS_CHECKED "${CMAKE_SHARED_LINKER_FLAGS_CHECKED} /OPT:REF /OPT:NOICF /NOVCFEATURE") -set(CMAKE_STATIC_LINKER_FLAGS_CHECKED "${CMAKE_STATIC_LINKER_FLAGS_CHECKED} /OPT:REF /OPT:NOICF") -set(CMAKE_EXE_LINKER_FLAGS_CHECKED "${CMAKE_EXE_LINKER_FLAGS_CHECKED} /OPT:REF /OPT:NOICF") - -# Release build specific flags -set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF /OPT:ICF") -set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG") -set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF /OPT:ICF") - -# ReleaseWithDebugInfo build specific flags -set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} /LTCG /OPT:REF /OPT:ICF") -set(CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO} /LTCG") -set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /LTCG /OPT:REF /OPT:ICF") + # Compile options for targeting windows + + # The following options are set by the razzle build + add_compile_options(/TP) # compile all files as C++ + add_compile_options(/d2Zi+) # make optimized builds debugging easier + add_compile_options(/nologo) # Suppress Startup Banner + add_compile_options(/W3) # set warning level to 3 + add_compile_options(/WX) # treat warnings as errors + add_compile_options(/Oi) # enable intrinsics + add_compile_options(/Oy-) # disable suppressing of the creation of frame pointers on the call stack for quicker function calls + add_compile_options(/U_MT) # undefine the predefined _MT macro + add_compile_options(/GF) # enable read-only string pooling + add_compile_options(/Gm-) # disable minimal rebuild + add_compile_options(/EHa) # enable C++ EH (w/ SEH exceptions) + add_compile_options(/Zp8) # pack structs on 8-byte boundary + add_compile_options(/GS) # enable security checks + add_compile_options(/Gy) # separate functions for linker + add_compile_options(/Zc:wchar_t-) # C++ language conformance: wchar_t is NOT the native type, but a typedef + add_compile_options(/Zc:forScope) # C++ language conformance: enforce Standard C++ for scoping rules + add_compile_options(/GR-) # disable C++ RTTI + add_compile_options(/FC) # use full pathnames in diagnostics + add_compile_options(/MP) # Build with Multiple Processes (number of processes equal to the number of processors) + add_compile_options(/GS) # Buffer Security Check + add_compile_options(/Zm200) # Specify Precompiled Header Memory Allocation Limit of 150MB + add_compile_options(/wd4960 /wd4961 /wd4603 /wd4627 /wd4838 /wd4456 /wd4457 /wd4458 /wd4459 /wd4091 /we4640) + add_compile_options(/Zi) # enable debugging information + + if (CLR_CMAKE_PLATFORM_ARCH_I386) + add_compile_options(/Gz) + endif (CLR_CMAKE_PLATFORM_ARCH_I386) + + add_compile_options($<$,$>:/GL>) + add_compile_options($<$,$>,$>:/O1>) + + if (IS_64BIT_BUILD EQUAL 1) + # The generator expression in the following command means that the /homeparams option is added only for debug builds + add_compile_options($<$:/homeparams>) # Force parameters passed in registers to be written to the stack + endif (IS_64BIT_BUILD EQUAL 1) + + # Linker flags + # + # Disable the following line for UNIX altjit on Windows + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /MANIFEST:NO") #Do not create Side-by-Side Assembly Manifest + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /SUBSYSTEM:WINDOWS,6.00") #windows subsystem + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /LARGEADDRESSAWARE") # can handle addresses larger than 2 gigabytes + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /RELEASE") #sets the checksum in the header + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /NXCOMPAT") #Compatible with Data Execution Prevention + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DYNAMICBASE") #Use address space layout randomization + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DEBUGTYPE:cv,fixup") #debugging format + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /PDBCOMPRESS") #shrink pdb size + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /DEBUG") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /IGNORE:4197,4013,4254,4070,4221") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} /INCREMENTAL:NO") + + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /DEBUG /PDBCOMPRESS") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /STACK:1572864") + + # Debug build specific flags + set(CMAKE_SHARED_LINKER_FLAGS_DEBUG "/NOVCFEATURE") + + # Checked build specific flags + set(CMAKE_SHARED_LINKER_FLAGS_CHECKED "${CMAKE_SHARED_LINKER_FLAGS_CHECKED} /OPT:REF /OPT:NOICF /NOVCFEATURE") + set(CMAKE_STATIC_LINKER_FLAGS_CHECKED "${CMAKE_STATIC_LINKER_FLAGS_CHECKED} /OPT:REF /OPT:NOICF") + set(CMAKE_EXE_LINKER_FLAGS_CHECKED "${CMAKE_EXE_LINKER_FLAGS_CHECKED} /OPT:REF /OPT:NOICF") + + # Release build specific flags + set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF /OPT:ICF") + set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF /OPT:ICF") + set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG /OPT:REF /OPT:ICF") + + # ReleaseWithDebugInfo build specific flags + set(CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_SHARED_LINKER_FLAGS_RELWITHDEBINFO} /LTCG /OPT:REF /OPT:ICF") + set(CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_STATIC_LINKER_FLAGS_RELWITHDEBINFO} /LTCG /OPT:REF /OPT:ICF") + set(CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO "${CMAKE_EXE_LINKER_FLAGS_RELWITHDEBINFO} /LTCG /OPT:REF /OPT:ICF") # Temporary until cmake has VS generators for arm64 if(CLR_CMAKE_PLATFORM_ARCH_ARM64) @@ -454,13 +444,6 @@ endif(CLR_CMAKE_PLATFORM_ARCH_ARM64) endif (WIN32) -endif (OVERRIDE_CMAKE_CXX_FLAGS) - -if(CLR_CMAKE_PLATFORM_UNIX_TARGET_AMD64) -add_definitions(-DFEATURE_UNIX_AMD64_STRUCT_PASSING_ITF) -add_definitions(-DFEATURE_UNIX_AMD64_STRUCT_PASSING) -endif (CLR_CMAKE_PLATFORM_UNIX_TARGET_AMD64) - OPTION(CMAKE_ENABLE_CODE_COVERAGE "Enable code coverage" OFF) if(CMAKE_ENABLE_CODE_COVERAGE) @@ -482,39 +465,90 @@ if(CMAKE_ENABLE_CODE_COVERAGE) endif(CMAKE_ENABLE_CODE_COVERAGE) +# Start of projects that require usage of platform include files + if(CLR_CMAKE_PLATFORM_UNIX) -add_definitions(-DDISABLE_CONTRACTS) -# The -ferror-limit is helpful during the porting, it makes sure the compiler doesn't stop -# after hitting just about 20 errors. -add_compile_options(-ferror-limit=4096) - -# All warnings that are not explicitly disabled are reported as errors -add_compile_options(-Werror) - -# Disabled warnings -add_compile_options(-Wno-unused-private-field) -add_compile_options(-Wno-unused-variable) -# Explicit constructor calls are not supported by clang (this->ClassName::ClassName()) -add_compile_options(-Wno-microsoft) -# This warning is caused by comparing 'this' to NULL -add_compile_options(-Wno-tautological-compare) -# There are constants of type BOOL used in a condition. But BOOL is defined as int -# and so the compiler thinks that there is a mistake. -add_compile_options(-Wno-constant-logical-operand) - -add_compile_options(-Wno-unknown-warning-option) - -#These seem to indicate real issues -add_compile_options(-Wno-invalid-offsetof) -# The following warning indicates that an attribute __attribute__((__ms_struct__)) was applied -# to a struct or a class that has virtual members or a base class. In that case, clang -# may not generate the same object layout as MSVC. -add_compile_options(-Wno-incompatible-ms-struct) + add_subdirectory(src/corefx) +endif(CLR_CMAKE_PLATFORM_UNIX) + +if(IS_64BIT_BUILD) + add_definitions(-DBIT64=1) +endif(IS_64BIT_BUILD) +if (CLR_CMAKE_PLATFORM_ARCH_AMD64) + if (CLR_CMAKE_PLATFORM_UNIX_TARGET_AMD64) + add_definitions(-DDBG_TARGET_AMD64_UNIX) + endif() + add_definitions(-D_TARGET_AMD64_=1) + add_definitions(-DDBG_TARGET_AMD64) +elseif (CLR_CMAKE_PLATFORM_ARCH_ARM64) + if (CLR_CMAKE_PLATFORM_UNIX_TARGET_ARM64) + add_definitions(-DDBG_TARGET_ARM64_UNIX) + endif() + add_definitions(-D_TARGET_ARM64_=1) + add_definitions(-DDBG_TARGET_ARM64) +elseif (CLR_CMAKE_PLATFORM_ARCH_ARM) + if (CLR_CMAKE_PLATFORM_UNIX_TARGET_ARM) + add_definitions(-DDBG_TARGET_ARM_UNIX) + endif (CLR_CMAKE_PLATFORM_UNIX_TARGET_ARM) + add_definitions(-D_TARGET_ARM_=1) + add_definitions(-DDBG_TARGET_ARM) +elseif (CLR_CMAKE_PLATFORM_ARCH_I386) + add_definitions(-D_TARGET_X86_=1) + add_definitions(-DDBG_TARGET_X86) +else () + clr_unknown_arch() +endif (CLR_CMAKE_PLATFORM_ARCH_AMD64) + +if (CLR_CMAKE_PLATFORM_ARCH_AMD64) + add_definitions(-D_AMD64_) + add_definitions(-D_WIN64) + add_definitions(-DAMD64) +elseif (CLR_CMAKE_PLATFORM_ARCH_I386) + add_definitions(-D_WIN32) + add_definitions(-D_X86_) +elseif (CLR_CMAKE_PLATFORM_ARCH_ARM) + add_definitions(-D_ARM_) + add_definitions(-DARM) + add_definitions(-D_WIN32) +elseif (CLR_CMAKE_PLATFORM_ARCH_ARM64) + add_definitions(-D_ARM64_) + add_definitions(-DARM64) + add_definitions(-D_WIN64) +else () + clr_unknown_arch() +endif () + +if(CLR_CMAKE_PLATFORM_UNIX) + add_subdirectory(src/ToolBox/SOS/lldbplugin) + add_subdirectory(src/pal) + add_subdirectory(src/coreclr/hosts/unixcoreruncommon) + add_subdirectory(src/coreclr/hosts/unixcorerun) + add_subdirectory(src/coreclr/hosts/unixcoreconsole) + add_subdirectory(src/ildasm/unixcoreclrloader) endif(CLR_CMAKE_PLATFORM_UNIX) +if(CLR_CMAKE_PLATFORM_DARWIN) + add_subdirectory(src/coreclr/hosts/osxbundlerun) +endif(CLR_CMAKE_PLATFORM_DARWIN) + +# Add this subdir. We install the headers for the jit. +add_subdirectory(src/pal/prebuilt/inc) + add_subdirectory(src/debug/debug-pal) +if(WIN32) + add_subdirectory(src/gc/sample) +endif() + +# End of projects that require usage of platform include files + +# Enable for UNIX altjit on Windows - set(CLR_CMAKE_PLATFORM_UNIX_TARGET_AMD64 1) +# Enable for UNIX altjit on Windows - add_definitions(-DCLR_CMAKE_PLATFORM_UNIX=1) + +# Disable the following line for UNIX altjit on Windows +set(CMAKE_CXX_STANDARD_LIBRARIES "") # do not link against standard win32 libs i.e. kernel32, uuid, user32, etc. + # Include directory directives # Include the basic prebuilt headers - required for getting fileversion resource details. @@ -532,23 +566,22 @@ if (WIN32) set(STATIC_MT_CRT_LIB "libcmt$<$,$>:d>.lib") set(STATIC_MT_CPP_LIB "libcpmt$<$,$>:d>.lib") endif(WIN32) -# Definition directives - if(IS_64BIT_BUILD) - add_definitions(-DBIT64=1) - endif(IS_64BIT_BUILD) +# Definition directives if (CLR_CMAKE_PLATFORM_UNIX) - add_definitions(-DFEATURE_PAL_SXS) - add_definitions(-DFEATURE_COREFX_GLOBALIZATION) - add_definitions(-DFEATURE_PAL) if(CLR_CMAKE_PLATFORM_DARWIN) add_definitions(-D_XOPEN_SOURCE) endif(CLR_CMAKE_PLATFORM_DARWIN) -endif(CLR_CMAKE_PLATFORM_UNIX) + if (CLR_CMAKE_PLATFORM_UNIX_TARGET_AMD64) + add_definitions(-DUNIX_AMD64_ABI) + elseif (CLR_CMAKE_PLATFORM_UNIX_TARGET_ARM) + add_definitions(-DUNIX_ARM_ABI) + endif() +endif(CLR_CMAKE_PLATFORM_UNIX) add_definitions(-D_CRT_STDIO_ARBITRARY_WIDE_SPECIFIERS) add_definitions(-DDEV10) @@ -560,86 +593,63 @@ add_definitions(-DWINNT=1) add_definitions(-DNT_INST=0) add_definitions(-DCONDITION_HANDLING=1) add_definitions(-DNTDDI_VERSION=NTDDI_WIN8) - -if (CLR_CMAKE_PLATFORM_ARCH_AMD64) - if (CLR_CMAKE_PLATFORM_UNIX_TARGET_AMD64) - add_definitions(-DDBG_TARGET_AMD64_UNIX) - endif() - add_definitions(-D_TARGET_AMD64_=1) - add_definitions(-DDBG_TARGET_AMD64) -elseif(CLR_CMAKE_PLATFORM_ARCH_ARM64) - if (CLR_CMAKE_PLATFORM_UNIX_TARGET_ARM64) - add_definitions(-DDBG_TARGET_ARM64_UNIX) - endif() - add_definitions(-D_TARGET_ARM64_=1) - add_definitions(-DDBG_TARGET_ARM64) -elseif (CLR_CMAKE_PLATFORM_ARCH_ARM) - if (CLR_CMAKE_PLATFORM_UNIX_TARGET_ARM) - add_definitions(-DDBG_TARGET_ARM_UNIX) - endif (CLR_CMAKE_PLATFORM_UNIX_TARGET_ARM) - add_definitions(-D_TARGET_ARM_=1) - add_definitions(-DDBG_TARGET_ARM) -elseif (CLR_CMAKE_PLATFORM_ARCH_I386) - add_definitions(-D_TARGET_X86_=1) - add_definitions(-DDBG_TARGET_X86) -else () - clr_unknown_arch() -endif (CLR_CMAKE_PLATFORM_ARCH_AMD64) - -if(WIN32) - add_definitions(-D_CRT_SECURE_NO_WARNINGS) -endif(WIN32) add_definitions(-DNTMAKEENV) add_definitions(-D_BLD_CLR) add_definitions(-DWINVER=0x0602) add_definitions(-DWIN32_LEAN_AND_MEAN=1) add_definitions(-DDEBUGGING_SUPPORTED) + if(WIN32) if(CLR_CMAKE_PLATFORM_ARCH_AMD64 OR CLR_CMAKE_PLATFORM_ARCH_I386) - # Only enable edit and continue on windows x86 and x64 - # exclude Linux, arm & arm64 - add_definitions(-DEnC_SUPPORTED) + add_definitions(-D_CRT_SECURE_NO_WARNINGS) + # Only enable edit and continue on windows x86 and x64 + # exclude Linux, arm & arm64 + add_definitions(-DEnC_SUPPORTED) endif(CLR_CMAKE_PLATFORM_ARCH_AMD64 OR CLR_CMAKE_PLATFORM_ARCH_I386) + add_definitions(-DPROFILING_SUPPORTED) endif(WIN32) + +# Features - please keep them alphabetically sorted + add_definitions(-DFEATURE_APPDOMAIN_RESOURCE_MONITORING) +if(WIN32) + add_definitions(-DFEATURE_APPX) +endif(WIN32) if(CLR_CMAKE_PLATFORM_ARCH_AMD64 OR CLR_CMAKE_PLATFORM_ARCH_ARM OR CLR_CMAKE_PLATFORM_ARCH_ARM64) add_definitions(-DFEATURE_ARRAYSTUB_AS_IL) endif() -if (CLR_CMAKE_PLATFORM_UNIX OR CLR_CMAKE_PLATFORM_ARCH_ARM64) - add_definitions(-DFEATURE_STUBS_AS_IL) - add_definitions(-DFEATURE_IMPLICIT_TLS) - set(FEATURE_IMPLICIT_TLS 1) -endif() - -if (CLR_CMAKE_PLATFORM_UNIX) - if (CLR_CMAKE_PLATFORM_UNIX_TARGET_AMD64) - add_definitions(-DUNIX_AMD64_ABI) - elseif (CLR_CMAKE_PLATFORM_UNIX_TARGET_ARM) - add_definitions(-DUNIX_ARM_ABI) - endif() -endif(CLR_CMAKE_PLATFORM_UNIX) add_definitions(-DFEATURE_ASYNC_IO) add_definitions(-DFEATURE_BCL_FORMATTING) add_definitions(-DFEATURE_COLLECTIBLE_TYPES) if(WIN32) add_definitions(-DFEATURE_CLASSIC_COMINTEROP) - add_definitions(-DFEATURE_APPX) add_definitions(-DFEATURE_COMINTEROP) add_definitions(-DFEATURE_COMINTEROP_APARTMENT_SUPPORT) add_definitions(-DFEATURE_COMINTEROP_UNMANAGED_ACTIVATION) add_definitions(-DFEATURE_COMINTEROP_WINRT_MANAGED_ACTIVATION) endif(WIN32) -add_definitions(-DFEATURE_ICASTABLE) - add_definitions(-DFEATURE_CORECLR) +if (CLR_CMAKE_PLATFORM_UNIX) + add_definitions(-DFEATURE_COREFX_GLOBALIZATION) +endif(CLR_CMAKE_PLATFORM_UNIX) add_definitions(-DFEATURE_CORESYSTEM) add_definitions(-DFEATURE_CORRUPTING_EXCEPTIONS) if(WIN32) add_definitions(-DFEATURE_CRYPTO) endif(WIN32) +if(CLR_CMAKE_PLATFORM_UNIX) + add_definitions(-DFEATURE_DBGIPC_TRANSPORT_DI) + add_definitions(-DFEATURE_DBGIPC_TRANSPORT_VM) +endif(CLR_CMAKE_PLATFORM_UNIX) +if (WIN32 OR CLR_CMAKE_PLATFORM_LINUX) + add_definitions(-DFEATURE_EVENT_TRACE=1) +endif (WIN32 OR CLR_CMAKE_PLATFORM_LINUX) +if (CLR_CMAKE_PLATFORM_LINUX) + add_definitions(-DFEATURE_EVENTSOURCE_XPLAT=1) +endif (CLR_CMAKE_PLATFORM_LINUX) add_definitions(-DFEATURE_EXCEPTIONDISPATCHINFO) add_definitions(-DFEATURE_FRAMEWORK_INTERNAL) if(NOT CLR_CMAKE_PLATFORM_UNIX_TARGET_ARM) @@ -647,6 +657,11 @@ if(NOT CLR_CMAKE_PLATFORM_UNIX_TARGET_ARM) endif(NOT CLR_CMAKE_PLATFORM_UNIX_TARGET_ARM) add_definitions(-DFEATURE_HOST_ASSEMBLY_RESOLVER) add_definitions(-DFEATURE_HOSTED_BINDER) +add_definitions(-DFEATURE_ICASTABLE) +if (CLR_CMAKE_PLATFORM_UNIX OR CLR_CMAKE_PLATFORM_ARCH_ARM64) + add_definitions(-DFEATURE_IMPLICIT_TLS) + set(FEATURE_IMPLICIT_TLS 1) +endif(CLR_CMAKE_PLATFORM_UNIX OR CLR_CMAKE_PLATFORM_ARCH_ARM64) if(WIN32) add_definitions(-DFEATURE_ISOSTORE) add_definitions(-DFEATURE_ISOSTORE_LIGHT) @@ -670,7 +685,15 @@ if(WIN32) # Disable the following or UNIX altjit on Windows add_definitions(-DFEATURE_MERGE_JIT_AND_ENGINE) endif(WIN32) +add_definitions(-DFEATURE_MULTICOREJIT) add_definitions(-DFEATURE_NORM_IDNA_ONLY) +if(CLR_CMAKE_PLATFORM_UNIX) + add_definitions(-DFEATURE_PAL) + add_definitions(-DFEATURE_PAL_SXS) +endif(CLR_CMAKE_PLATFORM_UNIX) +if(CLR_CMAKE_PLATFORM_LINUX) + add_definitions(-DFEATURE_PERFMAP) +endif(CLR_CMAKE_PLATFORM_LINUX) add_definitions(-DFEATURE_PREJIT) add_definitions(-DFEATURE_RANDOMIZED_STRING_HASHING) if(NOT DEFINED CLR_CMAKE_PLATFORM_ARCH_ARM64) @@ -683,11 +706,17 @@ add_definitions(-DFEATURE_STRONGNAME_MIGRATION) if(WIN32) add_definitions(-DFEATURE_STRONGNAME_TESTKEY_ALLOWED) endif(WIN32) +if (CLR_CMAKE_PLATFORM_UNIX OR CLR_CMAKE_PLATFORM_ARCH_ARM64) + add_definitions(-DFEATURE_STUBS_AS_IL) +endif(CLR_CMAKE_PLATFORM_UNIX OR CLR_CMAKE_PLATFORM_ARCH_ARM64) add_definitions(-DFEATURE_SVR_GC) -if(CLR_CMAKE_PLATFORM_LINUX) - add_definitions(-DFEATURE_PERFMAP) -endif(CLR_CMAKE_PLATFORM_LINUX) +add_definitions(-DFEATURE_SYMDIFF) add_definitions(-DFEATURE_SYNTHETIC_CULTURES) +if(CLR_CMAKE_PLATFORM_UNIX_TARGET_AMD64) + add_definitions(-DFEATURE_UNIX_AMD64_STRUCT_PASSING) + add_definitions(-DFEATURE_UNIX_AMD64_STRUCT_PASSING_ITF) +endif (CLR_CMAKE_PLATFORM_UNIX_TARGET_AMD64) +add_definitions(-DFEATURE_USE_ASM_GC_WRITE_BARRIERS) add_definitions(-DFEATURE_VERSIONING) if(WIN32) add_definitions(-DFEATURE_VERSIONING_LOG) @@ -698,55 +727,12 @@ add_definitions(-DFEATURE_WINMD_RESILIENT) if(WIN32) add_definitions(-DFEATURE_X509) add_definitions(-DFEATURE_X509_SECURESTRINGS) - add_definitions(-DPROFILING_SUPPORTED) - if (CLR_CMAKE_PLATFORM_ARCH_I386 OR CLR_CMAKE_PLATFORM_ARCH_ARM) - add_definitions(-DFEATURE_LAZY_COW_PAGES) - endif() endif(WIN32) -add_definitions(-DFEATURE_MULTICOREJIT) -add_definitions(-DFEATURE_USE_ASM_GC_WRITE_BARRIERS) -add_definitions(-DFEATURE_SYMDIFF) - -if(CLR_CMAKE_PLATFORM_UNIX) - add_definitions(-DFEATURE_DBGIPC_TRANSPORT_DI) - add_definitions(-DFEATURE_DBGIPC_TRANSPORT_VM) -endif(CLR_CMAKE_PLATFORM_UNIX) - -if (CLR_CMAKE_PLATFORM_ARCH_AMD64) - add_definitions(-D_AMD64_) - add_definitions(-D_AMD64_SIMULATOR_) - add_definitions(-D_AMD64_SIMULATOR_PERF_) - add_definitions(-D_AMD64_WORKAROUND_) - add_definitions(-D_WIN64) - add_definitions(-DAMD64) -elseif (CLR_CMAKE_PLATFORM_ARCH_I386) - add_definitions(-D_WIN32) - add_definitions(-D_X86_) -elseif (CLR_CMAKE_PLATFORM_ARCH_ARM) - add_definitions(-D_ARM_) - add_definitions(-DARM) - add_definitions(-D_WIN32) -elseif (CLR_CMAKE_PLATFORM_ARCH_ARM64) - add_definitions(-D_ARM64_) - add_definitions(-DARM64) - add_definitions(-D_WIN64) -else () - clr_unknown_arch() -endif () if(CLR_CMAKE_BUILD_TESTS) add_subdirectory(tests) endif(CLR_CMAKE_BUILD_TESTS) -add_definitions(-D_SKIP_IF_SIMULATOR_) -add_definitions(-D_SECURE_SCL=0) -add_definitions(-D_NEW_SDK=1) -add_definitions(-DOFFICIAL_BUILD=0) -add_definitions(-DBETA=0) -add_definitions(-DFX_BRANCH_SYNC_COUNTER_VALUE=0) -add_definitions(-DUNICODE) -add_definitions(-D_UNICODE) - if (CLR_CMAKE_PLATFORM_ARCH_AMD64) set(ARCH_SOURCES_DIR amd64) elseif (CLR_CMAKE_PLATFORM_ARCH_ARM64) @@ -759,4 +745,20 @@ else () clr_unknown_arch() endif () +add_definitions(-D_SKIP_IF_SIMULATOR_) +add_definitions(-D_SECURE_SCL=0) +add_definitions(-D_NEW_SDK=1) +add_definitions(-DOFFICIAL_BUILD=0) +add_definitions(-DBETA=0) +add_definitions(-DFX_BRANCH_SYNC_COUNTER_VALUE=0) +add_definitions(-DUNICODE) +add_definitions(-D_UNICODE) + +# Compiler options + +if(WIN32) + add_compile_options(/FIWarningControl.h) # force include of WarningControl.h + add_compile_options(/Zl) # omit default library name in .OBJ +endif(WIN32) + add_subdirectory(src) diff --git a/src/corefx/System.Globalization.Native/CMakeLists.txt b/src/corefx/System.Globalization.Native/CMakeLists.txt index 08d35a0..71b5c03 100644 --- a/src/corefx/System.Globalization.Native/CMakeLists.txt +++ b/src/corefx/System.Globalization.Native/CMakeLists.txt @@ -1,5 +1,6 @@ project(System.Globalization.Native) +include(CheckCXXSourceCompiles) set(CMAKE_INCLUDE_CURRENT_DIR ON) diff --git a/src/debug/ee/rcthread.cpp b/src/debug/ee/rcthread.cpp index 442c074..d4b8a61 100644 --- a/src/debug/ee/rcthread.cpp +++ b/src/debug/ee/rcthread.cpp @@ -882,7 +882,7 @@ void AssertAllocationAllowed() // Can't call IsDbgHelperSpecialThread() here b/c that changes program state. // So we use our - if (DebuggerRCThread::s_DbgHelperThreadId.IsSameThread()) + if (DebuggerRCThread::s_DbgHelperThreadId.IsCurrentThread()) { // In case assert allocates, bump up the 'OK' counter to avoid an infinite recursion. SUPPRESS_ALLOCATION_ASSERTS_IN_THIS_SCOPE; @@ -935,7 +935,7 @@ void DebuggerRCThread::ThreadProc(void) #ifdef _DEBUG // Track the helper thread. - s_DbgHelperThreadId.SetThreadId(); + s_DbgHelperThreadId.SetToCurrentThread(); #endif CantAllocHolder caHolder; diff --git a/src/dlls/mscoree/coreclr/CMakeLists.txt b/src/dlls/mscoree/coreclr/CMakeLists.txt index 98af591..792a9aa 100644 --- a/src/dlls/mscoree/coreclr/CMakeLists.txt +++ b/src/dlls/mscoree/coreclr/CMakeLists.txt @@ -177,4 +177,3 @@ install (TARGETS coreclr DESTINATION .) if(WIN32) install (FILES ${CMAKE_CURRENT_BINARY_DIR}/$/coreclr.pdb DESTINATION PDB) endif(WIN32) - diff --git a/src/gc/env/common.h b/src/gc/env/common.h index 3e982f8..39e97b3 100644 --- a/src/gc/env/common.h +++ b/src/gc/env/common.h @@ -22,7 +22,7 @@ #include -#ifndef WIN32 +#ifdef PLATFORM_UNIX #include #endif diff --git a/src/gc/env/gcenv.base.h b/src/gc/env/gcenv.base.h index 5b8f5f7..628a90c 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 -inline T FastInterlockExchangePointer( - T volatile * target, - T value) -{ - return (T)((TADDR)_FastInterlockExchangePointer((void **)target, value)); -} - -template -inline T FastInterlockExchangePointer( - T volatile * target, - nullptr_t value) -{ - return (T)((TADDR)_FastInterlockExchangePointer((void **)target, value)); -} - -template -inline T FastInterlockCompareExchangePointer( - T volatile * destination, - T exchange, - T comparand) -{ - return (T)((TADDR)_FastInterlockCompareExchangePointer((void **)destination, exchange, comparand)); -} - -template -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 0000000..741337f --- /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 0000000..1d6cc84 --- /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 + 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 + 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 + 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 + 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 + 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 + static T ExchangePointer(T volatile * destination, T value); + + template + 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 + 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 + 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 + static T CompareExchangePointer(T volatile *destination, T exchange, T comparand); + + template + 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 0000000..943bc2e --- /dev/null +++ b/src/gc/env/gcenv.interlocked.inl @@ -0,0 +1,184 @@ +// +// 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 +#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 +__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 +__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 +__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 +__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 +__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 +__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 +__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 +__forceinline T Interlocked::ExchangePointer(T volatile * destination, T value) +{ +#ifdef _MSC_VER + return (T)(TADDR)_InterlockedExchangePointer((void* volatile *)destination, value); +#else + return (T)(TADDR)__sync_swap((void* volatile *)destination, value); +#endif +} + +template +__forceinline T Interlocked::ExchangePointer(T volatile * destination, std::nullptr_t value) +{ +#ifdef _MSC_VER + return (T)(TADDR)_InterlockedExchangePointer((void* volatile *)destination, value); +#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 +__forceinline T Interlocked::CompareExchangePointer(T volatile *destination, T exchange, T comparand) +{ +#ifdef _MSC_VER + return (T)(TADDR)_InterlockedCompareExchangePointer((void* volatile *)destination, exchange, comparand); +#else + return (T)(TADDR)__sync_val_compare_and_swap((void* volatile *)destination, comparand, exchange); +#endif +} + +template +__forceinline T Interlocked::CompareExchangePointer(T volatile *destination, T exchange, std::nullptr_t comparand) +{ +#ifdef _MSC_VER + return (T)(TADDR)_InterlockedCompareExchangePointer((void* volatile *)destination, exchange, comparand); +#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 31dfe83..d366017 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 0000000..c1ae87a --- /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 e3bfb17..7c576a5 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 c3aea23..fe619cc 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.windows.cpp b/src/gc/env/gcenv.windows.cpp deleted file mode 100644 index 1059e5e..0000000 --- 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; -} - diff --git a/src/gc/gc.cpp b/src/gc/gc.cpp index f89ecbb..4baf08f 100644 --- a/src/gc/gc.cpp +++ b/src/gc/gc.cpp @@ -149,6 +149,17 @@ BOOL is_induced_blocking (gc_reason reason) (reason == reason_induced_compacting)); } +#ifndef DACCESS_COMPILE +int64_t qpf; + +size_t GetHighPrecisionTimeStamp() +{ + int64_t ts = GCToOSInterface::QueryPerformanceCounter(); + + return (size_t)(ts / (qpf / 1000)); +} +#endif + #ifdef GC_STATS // There is a current and a prior copy of the statistics. This allows us to display deltas per reporting // interval, as well as running totals. The 'min' and 'max' values require special treatment. They are @@ -296,15 +307,7 @@ uint32_t bgc_alloc_spin = 2; inline void c_write (uint32_t& place, uint32_t value) { - FastInterlockExchange (&(LONG&)place, value); - //place = value; -} - -// TODO - can't make it work with the syntax for Volatile -inline -void c_write_volatile (BOOL* place, uint32_t value) -{ - FastInterlockExchange ((LONG*)place, value); + Interlocked::Exchange (&place, value); //place = value; } @@ -368,15 +371,15 @@ void gc_heap::add_to_history() #endif //DACCESS_COMPILE #endif //BACKGROUND_GC -#ifdef TRACE_GC +#if defined(TRACE_GC) && !defined(DACCESS_COMPILE) BOOL gc_log_on = TRUE; -HANDLE gc_log = INVALID_HANDLE_VALUE; +FILE* gc_log = NULL; size_t gc_log_file_size = 0; size_t gc_buffer_index = 0; size_t max_gc_buffers = 0; -static CLR_MUTEX_COOKIE gc_log_lock = 0; +static CLRCriticalSection gc_log_lock; // we keep this much in a buffer and only flush when the buffer is full #define gc_log_buffer_size (1024*1024) @@ -385,8 +388,7 @@ size_t gc_log_buffer_offset = 0; void log_va_msg(const char *fmt, va_list args) { - uint32_t status = ClrWaitForMutex(gc_log_lock, INFINITE, FALSE); - assert (WAIT_OBJECT_0 == status); + gc_log_lock.Enter(); const int BUFFERSIZE = 512; static char rgchBuffer[BUFFERSIZE]; @@ -395,7 +397,7 @@ void log_va_msg(const char *fmt, va_list args) pBuffer[0] = '\r'; pBuffer[1] = '\n'; int buffer_start = 2; - int pid_len = sprintf_s (&pBuffer[buffer_start], BUFFERSIZE - buffer_start, "[%5d]", GetCurrentThreadId()); + int pid_len = sprintf_s (&pBuffer[buffer_start], BUFFERSIZE - buffer_start, "[%5d]", GCToOSInterface::GetCurrentThreadIdForLogging()); buffer_start += pid_len; memset(&pBuffer[buffer_start], '-', BUFFERSIZE - buffer_start); int msg_len = _vsnprintf(&pBuffer[buffer_start], BUFFERSIZE - buffer_start, fmt, args ); @@ -418,12 +420,11 @@ void log_va_msg(const char *fmt, va_list args) gc_buffer_index++; if (gc_buffer_index > max_gc_buffers) { - SetFilePointer (gc_log, 0, NULL, FILE_BEGIN); + fseek (gc_log, 0, SEEK_SET); gc_buffer_index = 0; } - uint32_t written_to_log = 0; - WriteFile (gc_log, gc_log_buffer, (uint32_t)gc_log_buffer_size, (DWORD*)&written_to_log, NULL); - FlushFileBuffers (gc_log); + fwrite(gc_log_buffer, gc_log_buffer_size, 1, gc_log); + fflush(gc_log); memset (gc_log_buffer, '*', gc_log_buffer_size); gc_log_buffer_offset = 0; } @@ -431,13 +432,12 @@ void log_va_msg(const char *fmt, va_list args) memcpy (gc_log_buffer + gc_log_buffer_offset, pBuffer, msg_len); gc_log_buffer_offset += msg_len; - status = ClrReleaseMutex(gc_log_lock); - assert (status); + gc_log_lock.Leave(); } void GCLog (const char *fmt, ... ) { - if (gc_log_on && (gc_log != INVALID_HANDLE_VALUE)) + if (gc_log_on && (gc_log != NULL)) { va_list args; va_start(args, fmt); @@ -445,11 +445,12 @@ void GCLog (const char *fmt, ... ) va_end(args); } } -#endif //TRACE_GC +#endif // TRACE_GC && !DACCESS_COMPILE + +#if defined(GC_CONFIG_DRIVEN) && !defined(DACCESS_COMPILE) -#ifdef GC_CONFIG_DRIVEN BOOL gc_config_log_on = FALSE; -HANDLE gc_config_log = INVALID_HANDLE_VALUE; +FILE* gc_config_log = NULL; // we keep this much in a buffer and only flush when the buffer is full #define gc_config_log_buffer_size (1*1024) // TEMP @@ -473,9 +474,8 @@ void log_va_msg_config(const char *fmt, va_list args) if ((gc_config_log_buffer_offset + msg_len) > gc_config_log_buffer_size) { - uint32_t written_to_log = 0; - WriteFile (gc_config_log, gc_config_log_buffer, (uint32_t)gc_config_log_buffer_offset, (DWORD*)&written_to_log, NULL); - FlushFileBuffers (gc_config_log); + fwrite(gc_config_log_buffer, gc_config_log_buffer_offset, 1, gc_config_log); + fflush(gc_config_log); gc_config_log_buffer_offset = 0; } @@ -485,14 +485,14 @@ void log_va_msg_config(const char *fmt, va_list args) void GCLogConfig (const char *fmt, ... ) { - if (gc_config_log_on && (gc_config_log != INVALID_HANDLE_VALUE)) + if (gc_config_log_on && (gc_config_log != NULL)) { va_list args; va_start( args, fmt ); log_va_msg_config (fmt, args); } } -#endif //GC_CONFIG_DRIVEN +#endif // GC_CONFIG_DRIVEN && !DACCESS_COMPILE #ifdef SYNCHRONIZATION_STATS @@ -523,7 +523,7 @@ init_sync_log_stats() gc_during_log = 0; gc_lock_contended = 0; - log_start_tick = GetTickCount(); + log_start_tick = GCToOSInterface::GetLowPrecisionTimeStamp(); } gc_count_during_log++; #endif //SYNCHRONIZATION_STATS @@ -534,7 +534,7 @@ process_sync_log_stats() { #ifdef SYNCHRONIZATION_STATS - unsigned int log_elapsed = GetTickCount() - log_start_tick; + unsigned int log_elapsed = GCToOSInterface::GetLowPrecisionTimeStamp() - log_start_tick; if (log_elapsed > log_interval) { @@ -700,7 +700,7 @@ public: flavor = f; #ifdef JOIN_STATS - start_tick = GetTickCount(); + start_tick = GCToOSInterface::GetLowPrecisionTimeStamp(); #endif //JOIN_STATS return TRUE; @@ -731,7 +731,7 @@ public: assert (!join_struct.joined_p); int color = join_struct.lock_color; - if (FastInterlockDecrement((LONG*)&join_struct.join_lock) != 0) + if (Interlocked::Decrement(&join_struct.join_lock) != 0) { dprintf (JOIN_LOG, ("join%d(%d): Join() Waiting...join_lock is now %d", flavor, join_id, (int32_t)(join_struct.join_lock))); @@ -783,7 +783,7 @@ respin: fire_event (gch->heap_number, time_end, type_join, join_id); // last thread out should reset event - if (FastInterlockDecrement((LONG*)&join_struct.join_restart) == 0) + if (Interlocked::Decrement(&join_struct.join_restart) == 0) { // the joined event must be set at this point, because the restarting must have done this join_struct.join_restart = join_struct.n_threads - 1; @@ -793,7 +793,7 @@ respin: #ifdef JOIN_STATS // parallel execution starts here start[gch->heap_number] = GetCycleCount32(); - FastInterlockExchangeAdd((int*)&in_join_total[join_id], (start[gch->heap_number] - end[gch->heap_number])/1000); + Interlocked::ExchangeAdd(&in_join_total[join_id], (start[gch->heap_number] - end[gch->heap_number])/1000); #endif //JOIN_STATS } else @@ -810,7 +810,7 @@ respin: // and keep track of the cycles spent waiting in the join thd = gch->heap_number; start_seq = GetCycleCount32(); - FastInterlockExchangeAdd((int*)&in_join_total[join_id], (start_seq - end[gch->heap_number])/1000); + Interlocked::ExchangeAdd(&in_join_total[join_id], (start_seq - end[gch->heap_number])/1000); #endif //JOIN_STATS } } @@ -831,7 +831,7 @@ respin: return TRUE; } - if (FastInterlockDecrement((LONG*)&join_struct.r_join_lock) != (join_struct.n_threads - 1)) + if (Interlocked::Decrement(&join_struct.r_join_lock) != (join_struct.n_threads - 1)) { if (!join_struct.wait_done) { @@ -879,7 +879,7 @@ respin: #ifdef JOIN_STATS // parallel execution starts here start[gch->heap_number] = GetCycleCount32(); - FastInterlockExchangeAdd((volatile int *)&in_join_total[join_id], (start[gch->heap_number] - end[gch->heap_number])/1000); + Interlocked::ExchangeAdd(&in_join_total[join_id], (start[gch->heap_number] - end[gch->heap_number])/1000); #endif //JOIN_STATS } @@ -918,7 +918,7 @@ respin: par_loss_total[join_id] += par_loss/1000; // every 10 seconds, print a summary of the time spent in each type of join, in 1000's of clock cycles - if (GetTickCount() - start_tick > 10*1000) + if (GCToOSInterface::GetLowPrecisionTimeStamp() - start_tick > 10*1000) { printf("**** summary *****\n"); for (int i = 0; i < 16; i++) @@ -926,7 +926,7 @@ respin: printf("join #%3d seq_loss = %8u par_loss = %8u in_join_total = %8u\n", i, seq_loss_total[i], par_loss_total[i], in_join_total[i]); elapsed_total[i] = seq_loss_total[i] = par_loss_total[i] = in_join_total[i] = 0; } - start_tick = GetTickCount(); + start_tick = GCToOSInterface::GetLowPrecisionTimeStamp(); } #endif //JOIN_STATS @@ -998,7 +998,7 @@ t_join bgc_t_join; } \ if (!(expr)) \ { \ - __SwitchToThread(0, CALLER_LIMITS_SPINNING); \ + GCToOSInterface::YieldThread(0); \ } \ } @@ -1051,7 +1051,7 @@ public: { if (alloc_objects [i] != (uint8_t*)0) { - DebugBreak(); + GCToOSInterface::DebugBreak(); } } } @@ -1060,7 +1060,7 @@ public: { dprintf (3, ("cm: probing %Ix", obj)); retry: - if (FastInterlockExchange ((LONG*)&needs_checking, 1) == 0) + if (Interlocked::Exchange (&needs_checking, 1) == 0) { // If we spend too much time spending all the allocs, // consider adding a high water mark and scan up @@ -1099,7 +1099,7 @@ retry: retry: dprintf (3, ("loh alloc: probing %Ix", obj)); - if (FastInterlockExchange ((LONG*)&needs_checking, 1) == 0) + if (Interlocked::Exchange (&needs_checking, 1) == 0) { if (obj == rwp_object) { @@ -1117,7 +1117,7 @@ retry: needs_checking = 0; //if (cookie >= 4) //{ - // DebugBreak(); + // GCToOSInterface::DebugBreak(); //} dprintf (3, ("loh alloc: set %Ix at %d", obj, cookie)); @@ -1273,7 +1273,7 @@ void recursive_gc_sync::begin_foreground() try_again_top: - FastInterlockIncrement ((LONG*)&foreground_request_count); + Interlocked::Increment (&foreground_request_count); try_again_no_inc: dprintf(2, ("Waiting sync gc point")); @@ -1291,7 +1291,7 @@ try_again_no_inc: if (foreground_gate) { - FastInterlockIncrement ((LONG*)&foreground_count); + Interlocked::Increment (&foreground_count); dprintf (2, ("foreground_count: %d", (int32_t)foreground_count)); if (foreground_gate) { @@ -1316,11 +1316,11 @@ void recursive_gc_sync::end_foreground() dprintf (2, ("end_foreground")); if (gc_background_running) { - FastInterlockDecrement ((LONG*)&foreground_request_count); + Interlocked::Decrement (&foreground_request_count); dprintf (2, ("foreground_count before decrement: %d", (int32_t)foreground_count)); - if (FastInterlockDecrement ((LONG*)&foreground_count) == 0) + if (Interlocked::Decrement (&foreground_count) == 0) { - //c_write_volatile ((BOOL*)&foreground_gate, 0); + //c_write ((BOOL*)&foreground_gate, 0); // TODO - couldn't make the syntax work with Volatile foreground_gate = 0; if (foreground_count == 0) @@ -1350,7 +1350,7 @@ BOOL recursive_gc_sync::allow_foreground() //background and foreground // gc_heap::disallow_new_allocation (0); - //__SwitchToThread(0, CALLER_LIMITS_SPINNING); + //GCToOSInterface::YieldThread(0); //END of TODO if (foreground_request_count != 0) @@ -1362,7 +1362,7 @@ BOOL recursive_gc_sync::allow_foreground() do { did_fgc = TRUE; - //c_write_volatile ((BOOL*)&foreground_gate, 1); + //c_write ((BOOL*)&foreground_gate, 1); // TODO - couldn't make the syntax work with Volatile foreground_gate = 1; foreground_allowed.Set (); @@ -1411,9 +1411,6 @@ __asm pop EDX #endif //COUNT_CYCLES || JOIN_STATS || SYNCHRONIZATION_STATS -LARGE_INTEGER qpf; - - #ifdef TIME_GC int mark_time, plan_time, sweep_time, reloc_time, compact_time; #endif //TIME_GC @@ -1438,13 +1435,9 @@ void reset_memory (uint8_t* o, size_t sizeo); #ifdef WRITE_WATCH -#define MEM_WRITE_WATCH 0x200000 +static bool virtual_alloc_write_watch = false; -static uint32_t mem_reserve = MEM_RESERVE; - -#ifndef FEATURE_REDHAWK -BOOL write_watch_capability = FALSE; -#endif +static bool write_watch_capability = false; #ifndef DACCESS_COMPILE @@ -1452,34 +1445,22 @@ BOOL write_watch_capability = FALSE; void write_watch_api_supported() { -#ifndef FEATURE_REDHAWK - // check if the OS will accept the MEM_WRITE_WATCH flag at runtime. - // Drawbridge does not support write-watch so we still need to do the runtime detection for them. - // Otherwise, all currently supported OSes do support write-watch. - void* mem = VirtualAlloc (0, g_SystemInfo.dwAllocationGranularity, MEM_WRITE_WATCH|MEM_RESERVE, - PAGE_READWRITE); - if (mem == 0) + if (GCToOSInterface::SupportsWriteWatch()) { - dprintf (2,("WriteWatch not supported")); + write_watch_capability = true; + dprintf (2, ("WriteWatch supported")); } else { - write_watch_capability = TRUE; - dprintf (2, ("WriteWatch supported")); - VirtualFree (mem, 0, MEM_RELEASE); + dprintf (2,("WriteWatch not supported")); } -#endif //FEATURE_REDHAWK } #endif //!DACCESS_COMPILE -inline BOOL can_use_write_watch() +inline bool can_use_write_watch() { -#ifdef FEATURE_REDHAWK - return PalHasCapability(WriteWatchCapability); -#else //FEATURE_REDHAWK return write_watch_capability; -#endif //FEATURE_REDHAWK } #else @@ -1509,12 +1490,12 @@ void WaitLongerNoInstru (int i) { YieldProcessor(); // indicate to the processor that we are spining if (i & 0x01f) - __SwitchToThread (0, CALLER_LIMITS_SPINNING); + GCToOSInterface::YieldThread (0); else - __SwitchToThread (5, CALLER_LIMITS_SPINNING); + GCToOSInterface::Sleep (5); } else - __SwitchToThread (5, CALLER_LIMITS_SPINNING); + GCToOSInterface::Sleep (5); } // If CLR is hosted, a thread may reach here while it is in preemptive GC mode, @@ -1544,7 +1525,7 @@ static void safe_switch_to_thread() Thread* current_thread = GetThread(); BOOL cooperative_mode = gc_heap::enable_preemptive(current_thread); - __SwitchToThread(0, CALLER_LIMITS_SPINNING); + GCToOSInterface::YieldThread(0); gc_heap::disable_preemptive(current_thread, cooperative_mode); } @@ -1558,7 +1539,7 @@ static void enter_spin_lock_noinstru (RAW_KEYWORD(volatile) int32_t* lock) { retry: - if (FastInterlockExchange ((LONG*)lock, 0) >= 0) + if (Interlocked::Exchange (lock, 0) >= 0) { unsigned int i = 0; while (VolatileLoad(lock) >= 0) @@ -1600,7 +1581,7 @@ retry: inline static BOOL try_enter_spin_lock_noinstru(RAW_KEYWORD(volatile) int32_t* lock) { - return (FastInterlockExchange ((LONG*)&*lock, 0) < 0); + return (Interlocked::Exchange (&*lock, 0) < 0); } inline @@ -1685,12 +1666,12 @@ void WaitLonger (int i { YieldProcessor(); // indicate to the processor that we are spining if (i & 0x01f) - __SwitchToThread (0, CALLER_LIMITS_SPINNING); + GCToOSInterface::YieldThread (0); else - __SwitchToThread (5, CALLER_LIMITS_SPINNING); + GCToOSInterface::Sleep (5); } else - __SwitchToThread (5, CALLER_LIMITS_SPINNING); + GCToOSInterface::Sleep (5); } // If CLR is hosted, a thread may reach here while it is in preemptive GC mode, @@ -1719,7 +1700,7 @@ static void enter_spin_lock (GCSpinLock* spin_lock) { retry: - if (FastInterlockExchange ((LONG*)&spin_lock->lock, 0) >= 0) + if (Interlocked::Exchange (&spin_lock->lock, 0) >= 0) { unsigned int i = 0; while (spin_lock->lock >= 0) @@ -1747,13 +1728,13 @@ retry: Thread* current_thread = GetThread(); BOOL cooperative_mode = gc_heap::enable_preemptive (current_thread); - __SwitchToThread(0, CALLER_LIMITS_SPINNING); + GCToOSInterface::YieldThread(0); gc_heap::disable_preemptive (current_thread, cooperative_mode); } } else - __SwitchToThread(0, CALLER_LIMITS_SPINNING); + GCToOSInterface::YieldThread(0); } else { @@ -1770,7 +1751,7 @@ retry: inline BOOL try_enter_spin_lock(GCSpinLock* spin_lock) { - return (FastInterlockExchange ((LONG*)&spin_lock->lock, 0) < 0); + return (Interlocked::Exchange (&spin_lock->lock, 0) < 0); } inline @@ -1783,8 +1764,6 @@ static void leave_spin_lock (GCSpinLock * spin_lock) #endif //_DEBUG -#endif // !DACCESS_COMPILE - BOOL gc_heap::enable_preemptive (Thread* current_thread) { bool cooperative_mode = false; @@ -1811,6 +1790,8 @@ void gc_heap::disable_preemptive (Thread* current_thread, BOOL restore_cooperati } } +#endif // !DACCESS_COMPILE + typedef void ** PTR_PTR; //This function clears a piece of memory // size has to be Dword aligned @@ -2256,8 +2237,6 @@ CLREvent gc_heap::gc_start_event; SVAL_IMPL_NS(int, SVR, gc_heap, n_heaps); SPTR_IMPL_NS(PTR_gc_heap, SVR, gc_heap, g_heaps); -HANDLE* gc_heap::g_gc_threads; - size_t* gc_heap::g_promoted; #ifdef MH_SC_MARK @@ -2460,7 +2439,7 @@ BOOL gc_heap::loh_compacted_p = FALSE; #ifdef BACKGROUND_GC -uint32_t gc_heap::bgc_thread_id = 0; +EEThreadId gc_heap::bgc_thread_id; uint8_t* gc_heap::background_written_addresses [array_size+2]; @@ -2518,7 +2497,7 @@ BOOL gc_heap::bgc_thread_running; CLREvent gc_heap::background_gc_create_event; -CRITICAL_SECTION gc_heap::bgc_threads_timeout_cs; +CLRCriticalSection gc_heap::bgc_threads_timeout_cs; CLREvent gc_heap::gc_lh_block_event; @@ -4262,7 +4241,8 @@ void* virtual_alloc (size_t size) } } - void* prgmem = ClrVirtualAllocAligned (0, requested_size, mem_reserve, PAGE_READWRITE, card_size * card_word_width); + uint32_t flags = virtual_alloc_write_watch ? VirtualReserveFlags::WriteWatch : VirtualReserveFlags::None; + void* prgmem = GCToOSInterface::VirtualReserve (0, requested_size, card_size * card_word_width, flags); void *aligned_mem = prgmem; // We don't want (prgmem + size) to be right at the end of the address space @@ -4276,7 +4256,7 @@ void* virtual_alloc (size_t size) if ((end_mem == 0) || ((size_t)(MAX_PTR - end_mem) <= END_SPACE_AFTER_GC)) { - VirtualFree (prgmem, 0, MEM_RELEASE); + GCToOSInterface::VirtualRelease (prgmem, requested_size); dprintf (2, ("Virtual Alloc size %Id returned memory right against 4GB [%Ix, %Ix[ - discarding", requested_size, (size_t)prgmem, (size_t)((uint8_t*)prgmem+requested_size))); prgmem = 0; @@ -4297,7 +4277,7 @@ void* virtual_alloc (size_t size) void virtual_free (void* add, size_t size) { - VirtualFree (add, 0, MEM_RELEASE); + GCToOSInterface::VirtualRelease (add, size); gc_heap::reserved_memory -= size; dprintf (2, ("Virtual Free size %Id: [%Ix, %Ix[", size, (size_t)add, (size_t)((uint8_t*)add+size))); @@ -4757,6 +4737,7 @@ gc_heap::get_large_segment (size_t size, BOOL* did_full_compact_gc) return res; } +#if 0 BOOL gc_heap::unprotect_segment (heap_segment* seg) { uint8_t* start = align_lower_page (heap_segment_mem (seg)); @@ -4764,16 +4745,15 @@ BOOL gc_heap::unprotect_segment (heap_segment* seg) if (region_size != 0 ) { - uint32_t old_protection; dprintf (3, ("unprotecting segment %Ix:", (size_t)seg)); - BOOL status = VirtualProtect (start, region_size, - PAGE_READWRITE, (DWORD*)&old_protection); + BOOL status = GCToOSInterface::VirtualUnprotect (start, region_size); assert (status); return status; } return FALSE; } +#endif #ifdef MULTIPLE_HEAPS #ifdef _X86_ @@ -4836,10 +4816,6 @@ extern "C" uint64_t __rdtsc(); #error NYI platform: get_cycle_count #endif //_TARGET_X86_ -// The purpose of this whole class is to guess the right heap to use for a given thread. -typedef -uint32_t (WINAPI *GetCurrentProcessorNumber_t)(void); - class heap_select { heap_select() {} @@ -4865,31 +4841,11 @@ class heap_select return (int) elapsed_cycles; } - static - GetCurrentProcessorNumber_t GCGetCurrentProcessorNumber; - - //check if the new APIs are supported. - static - BOOL api_supported() - { -#ifdef FEATURE_REDHAWK - BOOL fSupported = PalHasCapability(GetCurrentProcessorNumberCapability); - GCGetCurrentProcessorNumber = fSupported ? PalGetCurrentProcessorNumber : NULL; - return fSupported; -#elif !defined(FEATURE_PAL) - // on all platforms we support this API exists. - GCGetCurrentProcessorNumber = (GetCurrentProcessorNumber_t)&GetCurrentProcessorNumber; - return TRUE; -#else - return FALSE; -#endif //FEATURE_REDHAWK - } - public: static BOOL init(int n_heaps) { assert (sniff_buffer == NULL && n_sniff_buffers == 0); - if (!api_supported()) + if (!GCToOSInterface::CanGetCurrentProcessorNumber()) { n_sniff_buffers = n_heaps*2+1; size_t sniff_buf_size = 0; @@ -4921,10 +4877,10 @@ public: static void init_cpu_mapping(gc_heap *heap, int heap_number) { - if (GCGetCurrentProcessorNumber != 0) + if (GCToOSInterface::CanGetCurrentProcessorNumber()) { - uint32_t proc_no = GCGetCurrentProcessorNumber() % gc_heap::n_heaps; - // We can safely cast heap_number to a uint8_t 'cause GetCurrentProcessCpuCount + uint32_t proc_no = GCToOSInterface::GetCurrentProcessorNumber() % gc_heap::n_heaps; + // We can safely cast heap_number to a BYTE 'cause GetCurrentProcessCpuCount // only returns up to MAX_SUPPORTED_CPUS procs right now. We only ever create at most // MAX_SUPPORTED_CPUS GC threads. proc_no_to_heap_no[proc_no] = (uint8_t)heap_number; @@ -4933,7 +4889,7 @@ public: static void mark_heap(int heap_number) { - if (GCGetCurrentProcessorNumber != 0) + if (GCToOSInterface::CanGetCurrentProcessorNumber()) return; for (unsigned sniff_index = 0; sniff_index < n_sniff_buffers; sniff_index++) @@ -4942,10 +4898,10 @@ public: static int select_heap(alloc_context* acontext, int hint) { - if (GCGetCurrentProcessorNumber) - return proc_no_to_heap_no[GCGetCurrentProcessorNumber() % gc_heap::n_heaps]; + if (GCToOSInterface::CanGetCurrentProcessorNumber()) + return proc_no_to_heap_no[GCToOSInterface::GetCurrentProcessorNumber() % gc_heap::n_heaps]; - unsigned sniff_index = FastInterlockIncrement((LONG *)&cur_sniff_index); + unsigned sniff_index = Interlocked::Increment(&cur_sniff_index); sniff_index %= n_sniff_buffers; int best_heap = 0; @@ -4983,12 +4939,9 @@ public: return best_heap; } - static BOOL can_find_heap_fast() + static bool can_find_heap_fast() { - if (GCGetCurrentProcessorNumber) - return TRUE; - else - return FALSE; + return GCToOSInterface::CanGetCurrentProcessorNumber(); } static uint8_t find_proc_no_from_heap_no(int heap_number) @@ -5057,7 +5010,6 @@ public: uint8_t* heap_select::sniff_buffer; unsigned heap_select::n_sniff_buffers; unsigned heap_select::cur_sniff_index; -GetCurrentProcessorNumber_t heap_select::GCGetCurrentProcessorNumber; uint8_t heap_select::proc_no_to_heap_no[MAX_SUPPORTED_CPUS]; uint8_t heap_select::heap_no_to_proc_no[MAX_SUPPORTED_CPUS]; uint8_t heap_select::heap_no_to_numa_node[MAX_SUPPORTED_CPUS]; @@ -5107,17 +5059,15 @@ void gc_heap::destroy_thread_support () } } -void set_thread_group_affinity_for_heap(HANDLE gc_thread, int heap_number) -{ #if !defined(FEATURE_REDHAWK) && !defined(FEATURE_CORECLR) +void set_thread_group_affinity_for_heap(int heap_number, GCThreadAffinity* affinity) +{ + affinity->Group = GCThreadAffinity::None; + affinity->Processor = GCThreadAffinity::None; GROUP_AFFINITY ga; uint16_t gn, gpn; CPUGroupInfo::GetGroupForProcessor((uint16_t)heap_number, &gn, &gpn); - ga.Group = gn; - ga.Reserved[0] = 0; // reserve must be filled with zero - ga.Reserved[1] = 0; // otherwise call may fail - ga.Reserved[2] = 0; int bit_number = 0; for (uintptr_t mask = 1; mask !=0; mask <<=1) @@ -5125,8 +5075,8 @@ void set_thread_group_affinity_for_heap(HANDLE gc_thread, int heap_number) if (bit_number == gpn) { dprintf(3, ("using processor group %d, mask %x%Ix for heap %d\n", gn, mask, heap_number)); - ga.Mask = mask; - CPUGroupInfo::SetThreadGroupAffinity(gc_thread, &ga, NULL); + *affinity->Processor = gpn; + *affinity->Group = gn; heap_select::set_cpu_group_for_heap(heap_number, (uint8_t)gn); heap_select::set_group_proc_for_heap(heap_number, (uint8_t)gpn); if (NumaNodeInfo::CanEnableGCNumaAware()) @@ -5148,15 +5098,15 @@ void set_thread_group_affinity_for_heap(HANDLE gc_thread, int heap_number) } bit_number++; } -#endif } -void set_thread_affinity_mask_for_heap(HANDLE gc_thread, int heap_number) +void set_thread_affinity_mask_for_heap(int heap_number, GCThreadAffinity* affinity) { -#if !defined(FEATURE_REDHAWK) && !defined(FEATURE_CORECLR) + affinity->Group = GCThreadAffinity::None; + affinity->Processor = GCThreadAffinity::None; DWORD_PTR pmask, smask; - if (GetProcessAffinityMask(GetCurrentProcess(), &pmask, &smask)) + if (GCToOSInterface::GetCurrentProcessAffinityMask(&pmask, &smask)) { pmask &= smask; int bit_number = 0; @@ -5167,7 +5117,8 @@ void set_thread_affinity_mask_for_heap(HANDLE gc_thread, int heap_number) { if (bit_number == heap_number) { - dprintf (3, ("Using processor mask 0x%Ix for heap %d\n", mask, heap_number)); + dprintf (3, ("Using processor %d for heap %d\n", proc_number, heap_number)); + affinity->Processor = proc_number; SetThreadAffinityMask(gc_thread, mask); heap_select::set_proc_no_for_heap(heap_number, proc_number); if (NumaNodeInfo::CanEnableGCNumaAware()) @@ -5198,42 +5149,35 @@ void set_thread_affinity_mask_for_heap(HANDLE gc_thread, int heap_number) proc_number++; } } -#endif } +#endif // !FEATURE_REDHAWK && !FEATURE_CORECLR -HANDLE gc_heap::create_gc_thread () +bool gc_heap::create_gc_thread () { - uint32_t thread_id; dprintf (3, ("Creating gc thread\n")); -#ifdef FEATURE_REDHAWK - HANDLE gc_thread = CreateThread(0, 4096, gc_thread_stub,this, CREATE_SUSPENDED, &thread_id); -#else //FEATURE_REDHAWK - HANDLE gc_thread = Thread::CreateUtilityThread(Thread::StackSize_Medium, (DWORD (*)(void*))gc_thread_stub, this, CREATE_SUSPENDED, (DWORD*)&thread_id); -#endif //FEATURE_REDHAWK - - if (!gc_thread) - { - return 0;; - } - SetThreadPriority(gc_thread, /* THREAD_PRIORITY_ABOVE_NORMAL );*/ THREAD_PRIORITY_HIGHEST ); + GCThreadAffinity affinity; + affinity.Group = GCThreadAffinity::None; + affinity.Processor = GCThreadAffinity::None; +#if !defined(FEATURE_REDHAWK) && !defined(FEATURE_CORECLR) //We are about to set affinity for GC threads, it is a good place to setup NUMA and //CPU groups, because the process mask, processor number, group number are all //readyly available. if (CPUGroupInfo::CanEnableGCCPUGroups()) - set_thread_group_affinity_for_heap(gc_thread, heap_number); + set_thread_group_affinity_for_heap(heap_number, &affinity); else - set_thread_affinity_mask_for_heap(gc_thread, heap_number); + set_thread_affinity_mask_for_heap(heap_number, &affinity); - ResumeThread(gc_thread); - return gc_thread; +#endif // !FEATURE_REDHAWK && !FEATURE_CORECLR + + return GCToOSInterface::CreateThread(gc_thread_stub, this, &affinity); } #ifdef _MSC_VER #pragma warning(disable:4715) //IA64 xcompiler recognizes that without the 'break;' the while(1) will never end and therefore not return a value for that code path #endif //_MSC_VER -uint32_t gc_heap::gc_thread_function () +void gc_heap::gc_thread_function () { assert (gc_done_event.IsValid()); assert (gc_start_event.IsValid()); @@ -5321,7 +5265,6 @@ uint32_t gc_heap::gc_thread_function () set_gc_done(); } } - return 0; } #ifdef _MSC_VER #pragma warning(default:4715) //IA64 xcompiler recognizes that without the 'break;' the while(1) will never end and therefore not return a value for that code path @@ -5329,8 +5272,7 @@ uint32_t gc_heap::gc_thread_function () #endif //MULTIPLE_HEAPS -void* virtual_alloc_commit_for_heap(void* addr, size_t size, uint32_t type, - uint32_t prot, int h_number) +bool virtual_alloc_commit_for_heap(void* addr, size_t size, int h_number) { #if defined(MULTIPLE_HEAPS) && !defined(FEATURE_REDHAWK) && !defined(FEATURE_PAL) // Currently there is no way for us to specific the numa node to allocate on via hosting interfaces to @@ -5341,17 +5283,17 @@ void* virtual_alloc_commit_for_heap(void* addr, size_t size, uint32_t type, { uint32_t numa_node = heap_select::find_numa_node_from_heap_no(h_number); void * ret = NumaNodeInfo::VirtualAllocExNuma(GetCurrentProcess(), addr, size, - type, prot, numa_node); + MEM_COMMIT, PAGE_READWRITE, numa_node); if (ret != NULL) - return ret; + return true; } } #else UNREFERENCED_PARAMETER(h_number); #endif - //numa aware not enabled, or call failed --> fallback to VirtualAlloc() - return VirtualAlloc(addr, size, type, prot); + //numa aware not enabled, or call failed --> fallback to VirtualCommit() + return GCToOSInterface::VirtualCommit(addr, size); } #ifndef SEG_MAPPING_TABLE @@ -5972,7 +5914,7 @@ bool gc_heap::new_allocation_allowed (int gen_number) if ((allocation_running_amount - dd_new_allocation (dd0)) > dd_min_gc_size (dd0)) { - uint32_t ctime = GetTickCount(); + uint32_t ctime = GCToOSInterface::GetLowPrecisionTimeStamp(); if ((ctime - allocation_running_time) > 1000) { dprintf (2, (">1s since last gen0 gc")); @@ -6558,21 +6500,22 @@ class card_table_info { public: unsigned recount; - uint8_t* lowest_address; - uint8_t* highest_address; + uint8_t* lowest_address; + uint8_t* highest_address; short* brick_table; #ifdef CARD_BUNDLE - uint32_t* card_bundle_table; + uint32_t* card_bundle_table; #endif //CARD_BUNDLE // mark_array is always at the end of the data structure because we // want to be able to make one commit call for everything before it. #ifdef MARK_ARRAY - uint32_t* mark_array; + uint32_t* mark_array; #endif //MARK_ARRAY - uint32_t* next_card_table; + size_t size; + uint32_t* next_card_table; }; //These are accessors on untranslated cardtable @@ -6718,7 +6661,7 @@ void gc_heap::mark_array_set_marked (uint8_t* add) size_t index = mark_word_of (add); uint32_t val = (1 << mark_bit_bit_of (add)); #ifdef MULTIPLE_HEAPS - InterlockedOr ((LONG*)&(mark_array [index]), val); + Interlocked::Or (&(mark_array [index]), val); #else mark_array [index] |= val; #endif @@ -6829,6 +6772,12 @@ uint32_t*& card_table_next (uint32_t* c_table) return ((card_table_info*)((uint8_t*)c_table - sizeof (card_table_info)))->next_card_table; } +inline +size_t& card_table_size (uint32_t* c_table) +{ + return ((card_table_info*)((uint8_t*)c_table - sizeof (card_table_info)))->size; +} + void own_card_table (uint32_t* c_table) { card_table_refcount (c_table) += 1; @@ -6880,7 +6829,8 @@ void release_card_table (uint32_t* c_table) void destroy_card_table (uint32_t* c_table) { // delete (uint32_t*)&card_table_refcount(c_table); - VirtualFree (&card_table_refcount(c_table), 0, MEM_RELEASE); + + GCToOSInterface::VirtualRelease (&card_table_refcount(c_table), card_table_size(c_table)); dprintf (2, ("Table Virtual Free : %Ix", (size_t)&card_table_refcount(c_table))); } @@ -6889,7 +6839,7 @@ uint32_t* gc_heap::make_card_table (uint8_t* start, uint8_t* end) assert (g_lowest_address == start); assert (g_highest_address == end); - uint32_t mem_flags = MEM_RESERVE; + uint32_t virtual_reserve_flags = VirtualReserveFlags::None; size_t bs = size_brick_of (start, end); size_t cs = size_card_of (start, end); @@ -6906,7 +6856,7 @@ uint32_t* gc_heap::make_card_table (uint8_t* start, uint8_t* end) #ifdef CARD_BUNDLE if (can_use_write_watch()) { - mem_flags |= MEM_WRITE_WATCH; + virtual_reserve_flags |= VirtualReserveFlags::WriteWatch; cb = size_card_bundle_of (g_lowest_address, g_highest_address); } #endif //CARD_BUNDLE @@ -6922,8 +6872,7 @@ uint32_t* gc_heap::make_card_table (uint8_t* start, uint8_t* end) size_t alloc_size = sizeof (uint8_t)*(bs + cs + cb + ms + st + sizeof (card_table_info)); size_t alloc_size_aligned = Align (alloc_size, g_SystemInfo.dwAllocationGranularity-1); - uint32_t* ct = (uint32_t*)VirtualAlloc (0, alloc_size_aligned, - mem_flags, PAGE_READWRITE); + uint32_t* ct = (uint32_t*)GCToOSInterface::VirtualReserve (0, alloc_size_aligned, 0, virtual_reserve_flags); if (!ct) return 0; @@ -6933,11 +6882,11 @@ uint32_t* gc_heap::make_card_table (uint8_t* start, uint8_t* end) // mark array will be committed separately (per segment). size_t commit_size = alloc_size - ms; - - if (!VirtualAlloc ((uint8_t*)ct, commit_size, MEM_COMMIT, PAGE_READWRITE)) + + if (!GCToOSInterface::VirtualCommit ((uint8_t*)ct, commit_size)) { - dprintf (2, ("Table commit failed: %d", GetLastError())); - VirtualFree ((uint8_t*)ct, 0, MEM_RELEASE); + dprintf (2, ("Table commit failed")); + GCToOSInterface::VirtualRelease ((uint8_t*)ct, alloc_size_aligned); return 0; } @@ -6947,6 +6896,7 @@ uint32_t* gc_heap::make_card_table (uint8_t* start, uint8_t* end) card_table_lowest_address (ct) = start; card_table_highest_address (ct) = end; card_table_brick_table (ct) = (short*)((uint8_t*)ct + cs); + card_table_size (ct) = alloc_size_aligned; card_table_next (ct) = 0; #ifdef CARD_BUNDLE @@ -7012,7 +6962,7 @@ int gc_heap::grow_brick_card_tables (uint8_t* start, //modify the higest address so the span covered //is twice the previous one. GCMemoryStatus st; - GetProcessMemoryLoad (&st); + GCToOSInterface::GetMemoryStatus (&st); uint8_t* top = (uint8_t*)0 + Align ((size_t)(st.ullTotalVirtual)); // On non-Windows systems, we get only an approximate ullTotalVirtual // value that can possibly be slightly lower than the saved_g_highest_address. @@ -7052,7 +7002,7 @@ int gc_heap::grow_brick_card_tables (uint8_t* start, (size_t)saved_g_lowest_address, (size_t)saved_g_highest_address)); - uint32_t mem_flags = MEM_RESERVE; + uint32_t virtual_reserve_flags = VirtualReserveFlags::None; uint32_t* saved_g_card_table = g_card_table; uint32_t* ct = 0; short* bt = 0; @@ -7073,7 +7023,7 @@ int gc_heap::grow_brick_card_tables (uint8_t* start, #ifdef CARD_BUNDLE if (can_use_write_watch()) { - mem_flags |= MEM_WRITE_WATCH; + virtual_reserve_flags = VirtualReserveFlags::WriteWatch; cb = size_card_bundle_of (saved_g_lowest_address, saved_g_highest_address); } #endif //CARD_BUNDLE @@ -7091,7 +7041,7 @@ int gc_heap::grow_brick_card_tables (uint8_t* start, dprintf (GC_TABLE_LOG, ("brick table: %Id; card table: %Id; mark array: %Id, card bundle: %Id, seg table: %Id", bs, cs, ms, cb, st)); - uint8_t* mem = (uint8_t*)VirtualAlloc (0, alloc_size_aligned, mem_flags, PAGE_READWRITE); + uint8_t* mem = (uint8_t*)GCToOSInterface::VirtualReserve (0, alloc_size_aligned, 0, virtual_reserve_flags); if (!mem) { @@ -7106,7 +7056,7 @@ int gc_heap::grow_brick_card_tables (uint8_t* start, // mark array will be committed separately (per segment). size_t commit_size = alloc_size - ms; - if (!VirtualAlloc (mem, commit_size, MEM_COMMIT, PAGE_READWRITE)) + if (!GCToOSInterface::VirtualCommit (mem, commit_size)) { dprintf (GC_TABLE_LOG, ("Table commit failed")); set_fgm_result (fgm_commit_table, commit_size, loh_p); @@ -7205,7 +7155,7 @@ int gc_heap::grow_brick_card_tables (uint8_t* start, // with address that it does not cover. Write barriers access card table // without memory barriers for performance reasons, so we need to flush // the store buffers here. - FlushProcessWriteBuffers(); + GCToOSInterface::FlushProcessWriteBuffers(); g_lowest_address = saved_g_lowest_address; VolatileStore(&g_highest_address, saved_g_highest_address); @@ -7223,9 +7173,9 @@ fail: } //delete (uint32_t*)((uint8_t*)ct - sizeof(card_table_info)); - if (!VirtualFree (mem, 0, MEM_RELEASE)) + if (!GCToOSInterface::VirtualRelease (mem, alloc_size_aligned)) { - dprintf (GC_TABLE_LOG, ("VirtualFree failed: %d", GetLastError())); + dprintf (GC_TABLE_LOG, ("GCToOSInterface::VirtualRelease failed")); assert (!"release failed"); } } @@ -8950,12 +8900,10 @@ int gc_heap::object_gennum_plan (uint8_t* o) heap_segment* gc_heap::make_heap_segment (uint8_t* new_pages, size_t size, int h_number) { - void * res; size_t initial_commit = SEGMENT_INITIAL_COMMIT; //Commit the first page - if ((res = virtual_alloc_commit_for_heap (new_pages, initial_commit, - MEM_COMMIT, PAGE_READWRITE, h_number)) == 0) + if (!virtual_alloc_commit_for_heap (new_pages, initial_commit, h_number)) { return 0; } @@ -9062,7 +9010,7 @@ void gc_heap::reset_heap_segment_pages (heap_segment* seg) size_t page_start = align_on_page ((size_t)heap_segment_allocated (seg)); size_t size = (size_t)heap_segment_committed (seg) - page_start; if (size != 0) - VirtualAlloc ((char*)page_start, size, MEM_RESET, PAGE_READWRITE); + GCToOSInterface::VirtualReset((void*)page_start, size, false /* unlock */); #endif //!FEATURE_PAL } @@ -9077,7 +9025,7 @@ void gc_heap::decommit_heap_segment_pages (heap_segment* seg, page_start += max(extra_space, 32*OS_PAGE_SIZE); size -= max (extra_space, 32*OS_PAGE_SIZE); - VirtualFree (page_start, size, MEM_DECOMMIT); + GCToOSInterface::VirtualDecommit (page_start, size); dprintf (3, ("Decommitting heap segment [%Ix, %Ix[(%d)", (size_t)page_start, (size_t)(page_start + size), @@ -9102,7 +9050,7 @@ void gc_heap::decommit_heap_segment (heap_segment* seg) #endif //BACKGROUND_GC size_t size = heap_segment_committed (seg) - page_start; - VirtualFree (page_start, size, MEM_DECOMMIT); + GCToOSInterface::VirtualDecommit (page_start, size); //re-init the segment object heap_segment_committed (seg) = page_start; @@ -9239,7 +9187,6 @@ void gc_heap::update_card_table_bundle() uint8_t* base_address = (uint8_t*)(&card_table[card_word (card_of (lowest_address))]); uint8_t* saved_base_address = base_address; uintptr_t bcount = array_size; - uint32_t granularity = 0; uint8_t* high_address = (uint8_t*)(&card_table[card_word (card_of (highest_address))]); size_t saved_region_size = align_on_page (high_address) - saved_base_address; @@ -9247,16 +9194,15 @@ void gc_heap::update_card_table_bundle() { size_t region_size = align_on_page (high_address) - base_address; dprintf (3,("Probing card table pages [%Ix, %Ix[", (size_t)base_address, (size_t)base_address+region_size)); - uint32_t status = GetWriteWatch (0, base_address, region_size, - (void**)g_addresses, - (ULONG_PTR*)&bcount, (DWORD*)&granularity); - assert (status == 0); - assert (granularity == OS_PAGE_SIZE); + bool success = GCToOSInterface::GetWriteWatch (false /* resetState */ , base_address, region_size, + (void**)g_addresses, + &bcount); + assert (success); dprintf (3,("Found %d pages written", bcount)); for (unsigned i = 0; i < bcount; i++) { size_t bcardw = (uint32_t*)(max(g_addresses[i],base_address)) - &card_table[0]; - size_t ecardw = (uint32_t*)(min(g_addresses[i]+granularity, high_address)) - &card_table[0]; + size_t ecardw = (uint32_t*)(min(g_addresses[i]+OS_PAGE_SIZE, high_address)) - &card_table[0]; assert (bcardw >= card_word (card_of (g_lowest_address))); card_bundles_set (cardw_card_bundle (bcardw), @@ -9283,7 +9229,7 @@ void gc_heap::update_card_table_bundle() } } while ((bcount >= array_size) && (base_address < high_address)); - ResetWriteWatch (saved_base_address, saved_region_size); + GCToOSInterface::ResetWriteWatch (saved_base_address, saved_region_size); #ifdef _DEBUG @@ -9328,7 +9274,7 @@ void gc_heap::switch_one_quantum() { Thread* current_thread = GetThread(); enable_preemptive (current_thread); - __SwitchToThread (1, CALLER_LIMITS_SPINNING); + GCToOSInterface::Sleep (1); disable_preemptive (current_thread, TRUE); } @@ -9344,7 +9290,7 @@ void gc_heap::reset_ww_by_chunk (uint8_t* start_address, size_t total_reset_size next_reset_size = ((remaining_reset_size >= ww_reset_quantum) ? ww_reset_quantum : remaining_reset_size); if (next_reset_size) { - ResetWriteWatch (start_address, next_reset_size); + GCToOSInterface::ResetWriteWatch (start_address, next_reset_size); reset_size += next_reset_size; switch_one_quantum(); @@ -9354,7 +9300,7 @@ void gc_heap::reset_ww_by_chunk (uint8_t* start_address, size_t total_reset_size assert (reset_size == total_reset_size); } -// This does a __SwitchToThread for every reset ww_reset_quantum bytes of reset +// This does a Sleep(1) for every reset ww_reset_quantum bytes of reset // we do concurrently. void gc_heap::switch_on_reset (BOOL concurrent_p, size_t* current_total_reset_size, size_t last_reset_size) { @@ -9413,7 +9359,7 @@ void gc_heap::reset_write_watch (BOOL concurrent_p) #endif //TIME_WRITE_WATCH dprintf (3, ("h%d: soh ww: [%Ix(%Id)", heap_number, (size_t)base_address, region_size)); //reset_ww_by_chunk (base_address, region_size); - ResetWriteWatch (base_address, region_size); + GCToOSInterface::ResetWriteWatch (base_address, region_size); #ifdef TIME_WRITE_WATCH unsigned int time_stop = GetCycleCount32(); @@ -9456,7 +9402,7 @@ void gc_heap::reset_write_watch (BOOL concurrent_p) #endif //TIME_WRITE_WATCH dprintf (3, ("h%d: loh ww: [%Ix(%Id)", heap_number, (size_t)base_address, region_size)); //reset_ww_by_chunk (base_address, region_size); - ResetWriteWatch (base_address, region_size); + GCToOSInterface::ResetWriteWatch (base_address, region_size); #ifdef TIME_WRITE_WATCH unsigned int time_stop = GetCycleCount32(); @@ -9560,45 +9506,28 @@ void gc_heap::adjust_ephemeral_limits () } #if defined(TRACE_GC) || defined(GC_CONFIG_DRIVEN) -HANDLE CreateLogFile(const CLRConfig::ConfigStringInfo & info, BOOL is_config) +FILE* CreateLogFile(const CLRConfig::ConfigStringInfo & info, BOOL is_config) { + FILE* logFile; LPWSTR temp_logfile_name = NULL; CLRConfig::GetConfigValue(info, &temp_logfile_name); -#ifdef FEATURE_REDHAWK - UNREFERENCED_PARAMETER(is_config); - return PalCreateFileW( - temp_logfile_name, - GENERIC_WRITE, - FILE_SHARE_READ, - NULL, - CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL); -#else // FEATURE_REDHAWK - char logfile_name[MAX_PATH+1]; + WCHAR logfile_name[MAX_LONGPATH+1]; if (temp_logfile_name != 0) { - int ret; - ret = WszWideCharToMultiByte(CP_ACP, 0, temp_logfile_name, -1, logfile_name, sizeof(logfile_name)-1, NULL, NULL); - _ASSERTE(ret != 0); - delete temp_logfile_name; - } - - char szPid[20]; - sprintf_s(szPid, _countof(szPid), ".%d", GetCurrentProcessId()); - strcat_s(logfile_name, _countof(logfile_name), szPid); - strcat_s(logfile_name, _countof(logfile_name), (is_config ? ".config.log" : ".log")); - - return CreateFileA( - logfile_name, - GENERIC_WRITE, - FILE_SHARE_READ, - NULL, - CREATE_ALWAYS, - FILE_ATTRIBUTE_NORMAL, - NULL); -#endif //FEATURE_REDHAWK + wcscpy(logfile_name, temp_logfile_name); + } + + size_t logfile_name_len = wcslen(logfile_name); + WCHAR* szPid = logfile_name + logfile_name_len; + size_t remaining_space = MAX_LONGPATH + 1 - logfile_name_len; + swprintf_s(szPid, remaining_space, W(".%d%s"), GCToOSInterface::GetCurrentProcessId(), (is_config ? W(".config.log") : W(".log"))); + + logFile = GCToOSInterface::OpenFile(logfile_name, W("wb")); + + delete temp_logfile_name; + + return logFile; } #endif //TRACE_GC || GC_CONFIG_DRIVEN @@ -9615,7 +9544,7 @@ HRESULT gc_heap::initialize_gc (size_t segment_size, { gc_log = CreateLogFile(CLRConfig::UNSUPPORTED_GCLogFile, FALSE); - if (gc_log == INVALID_HANDLE_VALUE) + if (gc_log == NULL) return E_FAIL; // GCLogFileSize in MBs. @@ -9623,15 +9552,15 @@ HRESULT gc_heap::initialize_gc (size_t segment_size, if (gc_log_file_size > 500) { - CloseHandle (gc_log); + fclose (gc_log); return E_FAIL; } - gc_log_lock = ClrCreateMutex(NULL, FALSE, NULL); + gc_log_lock.Initialize(); gc_log_buffer = new (nothrow) uint8_t [gc_log_buffer_size]; if (!gc_log_buffer) { - CloseHandle(gc_log); + fclose(gc_log); return E_FAIL; } @@ -9647,13 +9576,13 @@ HRESULT gc_heap::initialize_gc (size_t segment_size, { gc_config_log = CreateLogFile(CLRConfig::UNSUPPORTED_GCConfigLogFile, TRUE); - if (gc_config_log == INVALID_HANDLE_VALUE) + if (gc_config_log == NULL) return E_FAIL; gc_config_log_buffer = new (nothrow) uint8_t [gc_config_log_buffer_size]; if (!gc_config_log_buffer) { - CloseHandle(gc_config_log); + fclose(gc_config_log); return E_FAIL; } @@ -9687,7 +9616,7 @@ HRESULT gc_heap::initialize_gc (size_t segment_size, GCStatistics::logFileName = CLRConfig::GetConfigValue(CLRConfig::UNSUPPORTED_GCMixLog); if (GCStatistics::logFileName != NULL) { - GCStatistics::logFile = _wfopen((LPCWSTR)GCStatistics::logFileName, W("a")); + GCStatistics::logFile = GCToOSInterface::OpenFile((LPCWSTR)GCStatistics::logFileName, W("a")); } #endif // GC_STATS @@ -9700,7 +9629,7 @@ HRESULT gc_heap::initialize_gc (size_t segment_size, if (can_use_write_watch () && g_pConfig->GetGCconcurrent()!=0) { gc_can_use_concurrent = true; - mem_reserve = MEM_WRITE_WATCH | MEM_RESERVE; + virtual_alloc_write_watch = true; } else { @@ -9777,10 +9706,6 @@ HRESULT gc_heap::initialize_gc (size_t segment_size, return E_OUTOFMEMORY; #endif //MH_SC_MARK - g_gc_threads = new (nothrow) HANDLE [number_of_heaps]; - if (!g_gc_threads) - return E_OUTOFMEMORY; - if (!create_thread_support (number_of_heaps)) return E_OUTOFMEMORY; @@ -10053,7 +9978,7 @@ gc_heap::enter_gc_done_event_lock() uint32_t dwSwitchCount = 0; retry: - if (FastInterlockExchange ((LONG*)&gc_done_event_lock, 0) >= 0) + if (Interlocked::Exchange (&gc_done_event_lock, 0) >= 0) { while (gc_done_event_lock >= 0) { @@ -10067,10 +9992,10 @@ retry: YieldProcessor(); // indicate to the processor that we are spining } if (gc_done_event_lock >= 0) - __SwitchToThread(0, ++dwSwitchCount); + GCToOSInterface::YieldThread(++dwSwitchCount); } else - __SwitchToThread(0, ++dwSwitchCount); + GCToOSInterface::YieldThread(++dwSwitchCount); } goto retry; } @@ -10105,7 +10030,7 @@ void gc_heap::add_saved_spinlock_info ( current->enter_state = enter_state; current->take_state = take_state; - current->thread_id = GetCurrentThreadId(); + current->thread_id.SetToCurrentThread(); spinlock_info_index++; @@ -10388,8 +10313,7 @@ gc_heap::init_gc_heap (int h_number) #ifdef MULTIPLE_HEAPS //register the heap in the heaps array - g_gc_threads [heap_number] = create_gc_thread (); - if (!g_gc_threads [heap_number]) + if (!create_gc_thread ()) return 0; g_heaps [heap_number] = this; @@ -10439,7 +10363,7 @@ gc_heap::init_gc_heap (int h_number) #endif // MULTIPLE_HEAPS #ifdef BACKGROUND_GC - bgc_thread_id = 0; + bgc_thread_id.Clear(); if (!create_bgc_thread_support()) { @@ -10462,7 +10386,7 @@ gc_heap::init_gc_heap (int h_number) bgc_thread_running = 0; bgc_thread = 0; - InitializeCriticalSection (&bgc_threads_timeout_cs); + bgc_threads_timeout_cs.Initialize(); expanded_in_fgc = 0; current_bgc_state = bgc_not_in_process; background_soh_alloc_count = 0; @@ -10570,17 +10494,14 @@ void gc_heap::shutdown_gc() #ifdef MULTIPLE_HEAPS //delete the heaps array delete g_heaps; - for (int i = 0; i < n_heaps; i++) - { - CloseHandle (g_gc_threads [i]); - } - delete g_gc_threads; destroy_thread_support(); n_heaps = 0; #endif //MULTIPLE_HEAPS //destroy seg_manager destroy_initial_memory(); + + GCToOSInterface::Shutdown(); } inline @@ -10667,8 +10588,7 @@ BOOL gc_heap::grow_heap_segment (heap_segment* seg, uint8_t* high_address) dprintf(3, ("Growing segment allocation %Ix %Ix", (size_t)heap_segment_committed(seg),c_size)); - if (!virtual_alloc_commit_for_heap(heap_segment_committed (seg), c_size, - MEM_COMMIT, PAGE_READWRITE, heap_number)) + if (!virtual_alloc_commit_for_heap(heap_segment_committed (seg), c_size, heap_number)) { dprintf(3, ("Cannot grow heap segment")); return FALSE; @@ -11319,7 +11239,7 @@ void gc_heap::handle_oom (int heap_num, oom_reason reason, size_t alloc_size, // could have allocated on the same heap when OOM happened. if (g_pConfig->IsGCBreakOnOOMEnabled()) { - DebugBreak(); + GCToOSInterface::DebugBreak(); } } @@ -11999,7 +11919,7 @@ void gc_heap::wait_for_bgc_high_memory (alloc_wait_reason awr) { GCMemoryStatus ms; memset (&ms, 0, sizeof(ms)); - GetProcessMemoryLoad(&ms); + GCToOSInterface::GetMemoryStatus(&ms); if (ms.dwMemoryLoad >= 95) { dprintf (GTC_LOG, ("high mem - wait for BGC to finish, wait reason: %d", awr)); @@ -12089,7 +12009,7 @@ BOOL gc_heap::allocate_small (int gen_number, dprintf (SPINLOCK_LOG, ("[%d]spin Lmsl", heap_number)); leave_spin_lock (&more_space_lock); BOOL cooperative_mode = enable_preemptive (current_thread); - __SwitchToThread (bgc_alloc_spin, CALLER_LIMITS_SPINNING); + GCToOSInterface::Sleep (bgc_alloc_spin); disable_preemptive (current_thread, cooperative_mode); enter_spin_lock (&more_space_lock); add_saved_spinlock_info (me_acquire, mt_alloc_small); @@ -12097,7 +12017,7 @@ BOOL gc_heap::allocate_small (int gen_number, } else { - //__SwitchToThread (0, CALLER_LIMITS_SPINNING); + //GCToOSInterface::YieldThread (0); } } #endif //BACKGROUND_GC && !MULTIPLE_HEAPS @@ -12577,7 +12497,7 @@ exit: } #ifdef RECORD_LOH_STATE -void gc_heap::add_saved_loh_state (allocation_state loh_state_to_save, uint32_t thread_id) +void gc_heap::add_saved_loh_state (allocation_state loh_state_to_save, EEThreadId thread_id) { // When the state is can_allocate we already have released the more // space lock. So we are not logging states here since this code @@ -12618,7 +12538,7 @@ BOOL gc_heap::allocate_large (int gen_number, dprintf (SPINLOCK_LOG, ("[%d]spin Lmsl loh", heap_number)); leave_spin_lock (&more_space_lock); BOOL cooperative_mode = enable_preemptive (current_thread); - __SwitchToThread (bgc_alloc_spin_loh, CALLER_LIMITS_SPINNING); + GCToOSInterface::YieldThread (bgc_alloc_spin_loh); disable_preemptive (current_thread, cooperative_mode); enter_spin_lock (&more_space_lock); add_saved_spinlock_info (me_acquire, mt_alloc_large); @@ -12642,7 +12562,8 @@ BOOL gc_heap::allocate_large (int gen_number, // That's why there are local variable for each state allocation_state loh_alloc_state = a_state_start; #ifdef RECORD_LOH_STATE - uint32_t current_thread_id = GetCurrentThreadId(); + EEThreadId current_thread_id; + current_thread_id.SetToCurrentThread(); #endif //RECORD_LOH_STATE // If we can get a new seg it means allocation will succeed. @@ -13126,41 +13047,29 @@ try_again: { uint8_t group_proc_no = heap_select::find_group_proc_from_heap_no(max_hp->heap_number); -#if !defined(FEATURE_CORESYSTEM) - SetThreadIdealProcessor(GetCurrentThread(), (uint32_t)group_proc_no); -#else - PROCESSOR_NUMBER proc; - proc.Group = org_gn; - proc.Number = group_proc_no; - proc.Reserved = 0; - - if(!SetThreadIdealProcessorEx(GetCurrentThread(), &proc, NULL)) + GCThreadAffinity affinity; + affinity.Processor = group_proc_no; + affinity.Group = org_gn; + if (!GCToOSInterface::SetCurrentThreadIdealAffinity(&affinity)) { dprintf (3, ("Failed to set the ideal processor and group for heap %d.", org_hp->heap_number)); } -#endif } } else { uint8_t proc_no = heap_select::find_proc_no_from_heap_no(max_hp->heap_number); -#if !defined(FEATURE_CORESYSTEM) - SetThreadIdealProcessor(GetCurrentThread(), (uint32_t)proc_no); -#else - PROCESSOR_NUMBER proc; - if(GetThreadIdealProcessorEx(GetCurrentThread(), &proc)) + GCThreadAffinity affinity; + affinity.Processor = proc_no; + affinity.Group = GCThreadAffinity::None; + + if (!GCToOSInterface::SetCurrentThreadIdealAffinity(&affinity)) { - proc.Number = proc_no; - BOOL result; - if(!SetThreadIdealProcessorEx(GetCurrentThread(), &proc, NULL)) - { - dprintf (3, ("Failed to set the ideal processor for heap %d.", - org_hp->heap_number)); - } + dprintf (3, ("Failed to set the ideal processor for heap %d.", + org_hp->heap_number)); } -#endif } #endif // !FEATURE_REDHAWK && !FEATURE_PAL dprintf (3, ("Switching context %p (home heap %d) ", @@ -14532,11 +14441,7 @@ int gc_heap::generation_to_condemn (int n_initial, (local_settings->pause_mode == pause_sustained_low_latency)) { dynamic_data* dd0 = dynamic_data_of (0); - LARGE_INTEGER ts; - if (!QueryPerformanceCounter(&ts)) - FATAL_GC_ERROR(); - - size_t now = (size_t) (ts.QuadPart/(qpf.QuadPart/1000)); + size_t now = GetHighPrecisionTimeStamp(); temp_gen = n; for (i = (temp_gen+1); i <= n_time_max; i++) { @@ -14655,7 +14560,7 @@ int gc_heap::generation_to_condemn (int n_initial, if (check_memory) { //find out if we are short on memory - GetProcessMemoryLoad(&ms); + GCToOSInterface::GetMemoryStatus(&ms); if (heap_number == 0) { dprintf (GTC_LOG, ("ml: %d", ms.dwMemoryLoad)); @@ -14955,7 +14860,7 @@ size_t gc_heap::min_reclaim_fragmentation_threshold (uint32_t num_heaps) size_t min_mem_based_on_available = (500 - (settings.entry_memory_load - high_memory_load_th) * 40) * 1024 * 1024 / num_heaps; size_t ten_percent_size = (size_t)((float)generation_size (max_generation) * 0.10); - ULONGLONG three_percent_mem = mem_one_percent * 3 / num_heaps; + uint64_t three_percent_mem = mem_one_percent * 3 / num_heaps; #ifdef SIMPLE_DPRINTF dprintf (GTC_LOG, ("min av: %Id, 10%% gen2: %Id, 3%% mem: %I64d", @@ -15036,10 +14941,7 @@ void fire_overflow_event (uint8_t* overflow_min, void gc_heap::concurrent_print_time_delta (const char* msg) { #ifdef TRACE_GC - LARGE_INTEGER ts; - QueryPerformanceCounter (&ts); - - size_t current_time = (size_t) (ts.QuadPart/(qpf.QuadPart/1000)); + size_t current_time = GetHighPrecisionTimeStamp(); size_t elapsed_time = current_time - time_bgc_last; time_bgc_last = current_time; @@ -15113,7 +15015,7 @@ BOOL gc_heap::should_proceed_with_gc() void gc_heap::gc1() { #ifdef BACKGROUND_GC - assert (settings.concurrent == (uint32_t)(GetCurrentThreadId() == bgc_thread_id)); + assert (settings.concurrent == (uint32_t)(bgc_thread_id.IsCurrentThread())); #endif //BACKGROUND_GC #ifdef TIME_GC @@ -15151,10 +15053,7 @@ void gc_heap::gc1() if (settings.concurrent) { #ifdef TRACE_GC - LARGE_INTEGER ts; - QueryPerformanceCounter (&ts); - - time_bgc_last = (size_t)(ts.QuadPart/(qpf.QuadPart/1000)); + time_bgc_last = GetHighPrecisionTimeStamp(); #endif //TRACE_GC fire_bgc_event (BGCBegin); @@ -15183,17 +15082,7 @@ void gc_heap::gc1() } } - LARGE_INTEGER ts; - if (!QueryPerformanceCounter(&ts)) - FATAL_GC_ERROR(); - - size_t end_gc_time = (size_t) (ts.QuadPart/(qpf.QuadPart/1000)); - -#ifdef GC_CONFIG_DRIVEN - if (heap_number == 0) - time_since_init = end_gc_time - time_init; -#endif //GC_CONFIG_DRIVEN - + size_t end_gc_time = GetHighPrecisionTimeStamp(); // printf ("generation: %d, elapsed time: %Id\n", n, end_gc_time - dd_time_clock (dynamic_data_of (0))); //adjust the allocation size from the pinned quantities. @@ -15393,7 +15282,7 @@ void gc_heap::gc1() #endif //TIME_GC #ifdef BACKGROUND_GC - assert (settings.concurrent == (uint32_t)(GetCurrentThreadId() == bgc_thread_id)); + assert (settings.concurrent == (uint32_t)(bgc_thread_id.IsCurrentThread())); #endif //BACKGROUND_GC #if defined(VERIFY_HEAP) || (defined (FEATURE_EVENT_TRACE) && defined(BACKGROUND_GC)) @@ -15443,7 +15332,7 @@ void gc_heap::gc1() #endif //BACKGROUND_GC #ifdef BACKGROUND_GC - assert (settings.concurrent == (uint32_t)(GetCurrentThreadId() == bgc_thread_id)); + assert (settings.concurrent == (uint32_t)(bgc_thread_id.IsCurrentThread())); #ifdef FEATURE_EVENT_TRACE if (ETW::GCLog::ShouldTrackMovementForEtw() && settings.concurrent) { @@ -15547,7 +15436,7 @@ void gc_heap::gc1() size_t min_gc_size = dd_min_gc_size(dd); // if min GC size larger than true on die cache, then don't bother // limiting the desired size - if ((min_gc_size <= GetLargestOnDieCacheSize(TRUE) / GetLogicalCpuCount()) && + if ((min_gc_size <= GCToOSInterface::GetLargestOnDieCacheSize(TRUE) / GCToOSInterface::GetLogicalCpuCount()) && desired_per_heap <= 2*min_gc_size) { desired_per_heap = min_gc_size; @@ -16063,11 +15952,7 @@ void gc_heap::update_collection_counts () dynamic_data* dd0 = dynamic_data_of (0); dd_gc_clock (dd0) += 1; - LARGE_INTEGER ts; - if (!QueryPerformanceCounter (&ts)) - FATAL_GC_ERROR(); - - size_t now = (size_t)(ts.QuadPart/(qpf.QuadPart/1000)); + size_t now = GetHighPrecisionTimeStamp(); for (int i = 0; i <= settings.condemned_generation;i++) { @@ -16719,7 +16604,7 @@ int gc_heap::garbage_collect (int n) gc1(); } #ifndef MULTIPLE_HEAPS - allocation_running_time = (size_t)GetTickCount(); + allocation_running_time = (size_t)GCToOSInterface::GetLowPrecisionTimeStamp(); allocation_running_amount = dd_new_allocation (dynamic_data_of (0)); fgn_last_alloc = dd_new_allocation (dynamic_data_of (0)); #endif //MULTIPLE_HEAPS @@ -17721,7 +17606,7 @@ gc_heap::mark_steal() #ifdef SNOOP_STATS dprintf (SNOOP_LOG, ("(GC%d)heap%d: start snooping %d", settings.gc_index, heap_number, (heap_number+1)%n_heaps)); - uint32_t begin_tick = GetTickCount(); + uint32_t begin_tick = GCToOSInterface::GetLowPrecisionTimeStamp(); #endif //SNOOP_STATS int idle_loop_count = 0; @@ -17822,8 +17707,8 @@ gc_heap::mark_steal() #ifdef SNOOP_STATS dprintf (SNOOP_LOG, ("heap%d: marking %Ix from %d [%d] tl:%dms", heap_number, (size_t)o, (heap_number+1)%n_heaps, level, - (GetTickCount()-begin_tick))); - uint32_t start_tick = GetTickCount(); + (GCToOSInterface::GetLowPrecisionTimeStamp()-begin_tick))); + uint32_t start_tick = GCToOSInterface::GetLowPrecisionTimeStamp(); #endif //SNOOP_STATS mark_object_simple1 (o, start, heap_number); @@ -17831,7 +17716,7 @@ gc_heap::mark_steal() #ifdef SNOOP_STATS dprintf (SNOOP_LOG, ("heap%d: done marking %Ix from %d [%d] %dms tl:%dms", heap_number, (size_t)o, (heap_number+1)%n_heaps, level, - (GetTickCount()-start_tick),(GetTickCount()-begin_tick))); + (GCToOSInterface::GetLowPrecisionTimeStamp()-start_tick),(GCToOSInterface::GetLowPrecisionTimeStamp()-begin_tick))); #endif //SNOOP_STATS mark_stack_busy() = 0; @@ -17872,7 +17757,7 @@ gc_heap::mark_steal() #ifdef SNOOP_STATS snoop_stat.switch_to_thread_count++; #endif //SNOOP_STATS - __SwitchToThread(1,0); + GCToOSInterface::Sleep(1); } int free_count = 1; #ifdef SNOOP_STATS @@ -17985,7 +17870,7 @@ gc_heap::ha_mark_object_simple (uint8_t** po THREAD_NUMBER_DCL) size_t new_size = 2*internal_root_array_length; GCMemoryStatus statex; - GetProcessMemoryLoad(&statex); + GCToOSInterface::GetMemoryStatus(&statex); if (new_size > (size_t)(statex.ullAvailPhys / 10)) { heap_analyze_success = FALSE; @@ -18510,11 +18395,10 @@ void gc_heap::fix_card_table () PREFIX_ASSUME(seg != NULL); - uint32_t granularity; #ifdef BACKGROUND_GC - uint32_t mode = settings.concurrent ? 1 : 0; + bool reset_watch_state = !!settings.concurrent; #else //BACKGROUND_GC - uint32_t mode = 0; + bool reset_watch_state = false; #endif //BACKGROUND_GC BOOL small_object_segments = TRUE; while (1) @@ -18554,10 +18438,10 @@ void gc_heap::fix_card_table () #ifdef TIME_WRITE_WATCH unsigned int time_start = GetCycleCount32(); #endif //TIME_WRITE_WATCH - uint32_t status = GetWriteWatch (mode, base_address, region_size, - (void**)g_addresses, - (ULONG_PTR*)&bcount, (DWORD*)&granularity); - assert (status == 0); + bool success = GCToOSInterface::GetWriteWatch(reset_watch_state, base_address, region_size, + (void**)g_addresses, + &bcount); + assert (success); #ifdef TIME_WRITE_WATCH unsigned int time_stop = GetCycleCount32(); @@ -18567,7 +18451,6 @@ void gc_heap::fix_card_table () #endif //TIME_WRITE_WATCH assert( ((card_size * card_word_width)&(OS_PAGE_SIZE-1))==0 ); - assert (granularity == OS_PAGE_SIZE); //printf ("%Ix written into\n", bcount); dprintf (3,("Found %Id pages written", bcount)); for (unsigned i = 0; i < bcount; i++) @@ -18595,7 +18478,7 @@ void gc_heap::fix_card_table () align_on_page (generation_allocation_start (generation_of (0))); size_t region_size = heap_segment_allocated (ephemeral_heap_segment) - base_address; - ResetWriteWatch (base_address, region_size); + GCToOSInterface::ResetWriteWatch (base_address, region_size); } #endif //BACKGROUND_GC #endif //WRITE_WATCH @@ -21137,7 +21020,7 @@ void gc_heap::store_plug_gap_info (uint8_t* plug_start, //if (last_plug_len == Align (min_obj_size)) //{ // dprintf (3, ("debugging only - last npinned plug is min, check to see if it's correct")); - // DebugBreak(); + // GCToOSInterface::DebugBreak(); //} save_pre_plug_info_p = TRUE; } @@ -21170,7 +21053,7 @@ void gc_heap::store_plug_gap_info (uint8_t* plug_start, //if (Align (last_plug_len) < min_pre_pin_obj_size) //{ // dprintf (3, ("debugging only - last pinned plug is min, check to see if it's correct")); - // DebugBreak(); + // GCToOSInterface::DebugBreak(); //} save_post_plug_info (last_pinned_plug, last_object_in_last_plug, plug_start); @@ -23486,7 +23369,7 @@ void gc_heap::relocate_shortened_obj_helper (uint8_t* x, size_t s, uint8_t* end, //{ // dprintf (3, ("obj %Ix needed padding: end %Ix is %d bytes from pinned obj %Ix", // x, (x + s), (plug- (x + s)), plug)); - // DebugBreak(); + // GCToOSInterface::DebugBreak(); //} relocate_pre_plug_info (pinned_plug_entry); @@ -24770,7 +24653,7 @@ inline int32_t GCUnhandledExceptionFilter(EXCEPTION_POINTERS* pExceptionPointers #pragma warning(push) #pragma warning(disable:4702) // C4702: unreachable code: gc_thread_function may not return #endif //_MSC_VER -uint32_t __stdcall gc_heap::gc_thread_stub (void* arg) +void __stdcall gc_heap::gc_thread_stub (void* arg) { ClrFlsSetThreadType (ThreadType_GC); STRESS_LOG_RESERVE_MEM (GC_STRESSLOG_MULTIPLY); @@ -24783,7 +24666,7 @@ uint32_t __stdcall gc_heap::gc_thread_stub (void* arg) { #ifdef BACKGROUND_GC // For background GC we revert to doing a blocking GC. - return 0; + return; #else STRESS_LOG0(LF_GC, LL_ALWAYS, "Thread::CommitThreadStack failed."); _ASSERTE(!"Thread::CommitThreadStack failed."); @@ -24797,7 +24680,7 @@ uint32_t __stdcall gc_heap::gc_thread_stub (void* arg) #endif // NO_CATCH_HANDLERS gc_heap* heap = (gc_heap*)arg; _alloca (256*heap->heap_number); - return heap->gc_thread_function(); + heap->gc_thread_function(); #ifndef NO_CATCH_HANDLERS } @@ -25229,7 +25112,7 @@ BOOL gc_heap::commit_mark_array_by_range (uint8_t* begin, uint8_t* end, uint32_t size)); #endif //SIMPLE_DPRINTF - if (VirtualAlloc (commit_start, size, MEM_COMMIT, PAGE_READWRITE)) + if (GCToOSInterface::VirtualCommit (commit_start, size)) { // We can only verify the mark array is cleared from begin to end, the first and the last // page aren't necessarily all cleared 'cause they could be used by other segments or @@ -25474,10 +25357,10 @@ void gc_heap::decommit_mark_array_by_seg (heap_segment* seg) if (decommit_start < decommit_end) { - if (!VirtualFree (decommit_start, size, MEM_DECOMMIT)) + if (!GCToOSInterface::VirtualDecommit (decommit_start, size)) { - dprintf (GC_TABLE_LOG, ("VirtualFree on %Ix for %Id bytes failed: %d", - decommit_start, size, GetLastError())); + dprintf (GC_TABLE_LOG, ("GCToOSInterface::VirtualDecommit on %Ix for %Id bytes failed", + decommit_start, size)); assert (!"decommit failed"); } } @@ -25603,7 +25486,7 @@ void gc_heap::background_mark_phase () dont_restart_ee_p = FALSE; restart_vm(); - __SwitchToThread (0, CALLER_LIMITS_SPINNING); + GCToOSInterface::YieldThread (0); #ifdef MULTIPLE_HEAPS dprintf(3, ("Starting all gc threads for gc")); bgc_t_join.restart(); @@ -26242,8 +26125,7 @@ void gc_heap::revisit_written_pages (BOOL concurrent_p, BOOL reset_only_p) PREFIX_ASSUME(seg != NULL); - uint32_t granularity; - int mode = concurrent_p ? 1 : 0; + bool reset_watch_state = !!concurrent_p; BOOL small_object_segments = TRUE; int align_const = get_alignment_constant (small_object_segments); @@ -26348,19 +26230,18 @@ void gc_heap::revisit_written_pages (BOOL concurrent_p, BOOL reset_only_p) ptrdiff_t region_size = high_address - base_address; dprintf (3, ("h%d: gw: [%Ix(%Id)", heap_number, (size_t)base_address, (size_t)region_size)); - uint32_t status = GetWriteWatch (mode, base_address, region_size, - (void**)background_written_addresses, - (ULONG_PTR*)&bcount, (DWORD*)&granularity); + bool success = GCToOSInterface::GetWriteWatch (reset_watch_state, base_address, region_size, + (void**)background_written_addresses, + &bcount); //#ifdef _DEBUG - if (status != 0) + if (!success) { printf ("GetWriteWatch Error "); printf ("Probing pages [%Ix, %Ix[\n", (size_t)base_address, (size_t)high_address); } //#endif - assert (status == 0); - assert (granularity == OS_PAGE_SIZE); + assert (success); if (bcount != 0) { @@ -26540,7 +26421,7 @@ BOOL gc_heap::prepare_bgc_thread(gc_heap* gh) BOOL thread_created = FALSE; dprintf (2, ("Preparing gc thread")); - EnterCriticalSection (&(gh->bgc_threads_timeout_cs)); + gh->bgc_threads_timeout_cs.Enter(); if (!(gh->bgc_thread_running)) { dprintf (2, ("GC thread not runnning")); @@ -26555,7 +26436,7 @@ BOOL gc_heap::prepare_bgc_thread(gc_heap* gh) dprintf (3, ("GC thread already running")); success = TRUE; } - LeaveCriticalSection (&(gh->bgc_threads_timeout_cs)); + gh->bgc_threads_timeout_cs.Leave(); if(thread_created) FireEtwGCCreateConcurrentThread_V1(GetClrInstanceId()); @@ -26581,7 +26462,7 @@ BOOL gc_heap::create_bgc_thread(gc_heap* gh) // finished the event wait below. rh_bgc_thread_ctx sContext; - sContext.m_pRealStartRoutine = gh->bgc_thread_stub; + sContext.m_pRealStartRoutine = (PTHREAD_START_ROUTINE)gh->bgc_thread_stub; sContext.m_pRealContext = gh; if (!PalStartBackgroundGCThread(gh->rh_bgc_thread_stub, &sContext)) @@ -26833,7 +26714,7 @@ void gc_heap::kill_gc_thread() background_gc_done_event.CloseEvent(); gc_lh_block_event.CloseEvent(); bgc_start_event.CloseEvent(); - DeleteCriticalSection (&bgc_threads_timeout_cs); + bgc_threads_timeout_cs.Destroy(); bgc_thread = 0; recursive_gc_sync::shutdown(); } @@ -26864,8 +26745,8 @@ uint32_t gc_heap::bgc_thread_function() bgc_thread_running = TRUE; Thread* current_thread = GetThread(); BOOL cooperative_mode = TRUE; - bgc_thread_id = GetCurrentThreadId(); - dprintf (1, ("bgc_thread_id is set to %Ix", bgc_thread_id)); + bgc_thread_id.SetToCurrentThread(); + dprintf (1, ("bgc_thread_id is set to %Ix", GCToOSInterface::GetCurrentThreadIdForLogging())); //this also indicates that the thread is ready. background_gc_create_event.Set(); while (1) @@ -26902,7 +26783,7 @@ uint32_t gc_heap::bgc_thread_function() // Should join the bgc threads and terminate all of them // at once. dprintf (1, ("GC thread timeout")); - EnterCriticalSection (&bgc_threads_timeout_cs); + bgc_threads_timeout_cs.Enter(); if (!keep_bgc_threads_p) { dprintf (2, ("GC thread exiting")); @@ -26912,10 +26793,10 @@ uint32_t gc_heap::bgc_thread_function() // assert if the lock count is not 0. thread_to_destroy = bgc_thread; bgc_thread = 0; - bgc_thread_id = 0; + bgc_thread_id.Clear(); do_exit = TRUE; } - LeaveCriticalSection (&bgc_threads_timeout_cs); + bgc_threads_timeout_cs.Leave(); if (do_exit) break; else @@ -29403,18 +29284,9 @@ generation* gc_heap::expand_heap (int condemned_generation, bool gc_heap::init_dynamic_data() { - LARGE_INTEGER ts; - if (!QueryPerformanceFrequency(&qpf)) - { - FATAL_GC_ERROR(); - } - - if (!QueryPerformanceCounter(&ts)) - { - FATAL_GC_ERROR(); - } + qpf = GCToOSInterface::QueryPerformanceFrequency(); - uint32_t now = (uint32_t)(ts.QuadPart/(qpf.QuadPart/1000)); + uint32_t now = (uint32_t)GetHighPrecisionTimeStamp(); //clear some fields for (int i = 0; i < max_generation+1; i++) @@ -29536,17 +29408,6 @@ bool gc_heap::init_dynamic_data() return true; } -// This returns a time stamp in milliseconds that is used throughout GC. -// TODO: Replace all calls to QueryPerformanceCounter with this function. -size_t gc_heap::get_time_now() -{ - LARGE_INTEGER ts; - if (!QueryPerformanceCounter(&ts)) - FATAL_GC_ERROR(); - - return (size_t)(ts.QuadPart/(qpf.QuadPart/1000)); -} - float gc_heap::surv_to_growth (float cst, float limit, float max_limit) { if (cst < ((max_limit - limit ) / (limit * (max_limit-1.0f)))) @@ -29643,7 +29504,7 @@ size_t gc_heap::desired_new_allocation (dynamic_data* dd, else //large object heap { GCMemoryStatus ms; - GetProcessMemoryLoad (&ms); + GCToOSInterface::GetMemoryStatus (&ms); uint64_t available_ram = ms.ullAvailPhys; if (ms.ullAvailPhys > 1024*1024) @@ -29879,7 +29740,7 @@ size_t gc_heap::joined_youngest_desired (size_t new_allocation) { uint32_t dwMemoryLoad = 0; GCMemoryStatus ms; - GetProcessMemoryLoad(&ms); + GCToOSInterface::GetMemoryStatus(&ms); dprintf (2, ("Current memory load: %d", ms.dwMemoryLoad)); dwMemoryLoad = ms.dwMemoryLoad; @@ -30573,7 +30434,7 @@ CObjectHeader* gc_heap::allocate_large_object (size_t jsize, int64_t& alloc_byte { if (g_pConfig->IsGCBreakOnOOMEnabled()) { - DebugBreak(); + GCToOSInterface::DebugBreak(); } #ifndef FEATURE_REDHAWK @@ -30666,10 +30527,7 @@ void reset_memory (uint8_t* o, size_t sizeo) // on write watched memory. if (reset_mm_p) { - if (VirtualAlloc ((char*)page_start, size, MEM_RESET, PAGE_READWRITE)) - VirtualUnlock ((char*)page_start, size); - else - reset_mm_p = FALSE; + reset_mm_p = GCToOSInterface::VirtualReset((void*)page_start, size, true /* unlock */); } } #endif //!FEATURE_PAL @@ -32524,11 +32382,7 @@ void gc_heap::clear_all_mark_array() { #ifdef MARK_ARRAY //size_t num_dwords_written = 0; - //LARGE_INTEGER ts; - //if (!QueryPerformanceCounter(&ts)) - // FATAL_GC_ERROR(); - // - //size_t begin_time = (size_t) (ts.QuadPart/(qpf.QuadPart/1000)); + //size_t begin_time = GetHighPrecisionTimeStamp(); generation* gen = generation_of (max_generation); heap_segment* seg = heap_segment_rw (generation_start_segment (gen)); @@ -32589,10 +32443,7 @@ void gc_heap::clear_all_mark_array() seg = heap_segment_next_rw (seg); } - //if (!QueryPerformanceCounter(&ts)) - // FATAL_GC_ERROR(); - // - //size_t end_time = (size_t) (ts.QuadPart/(qpf.QuadPart/1000)) - begin_time; + //size_t end_time = GetHighPrecisionTimeStamp() - begin_time; //printf ("took %Id ms to clear %Id bytes\n", end_time, num_dwords_written*sizeof(uint32_t)); @@ -32932,7 +32783,7 @@ gc_heap::verify_heap (BOOL begin_gc_p) #ifdef MULTIPLE_HEAPS t_join* current_join = &gc_t_join; #ifdef BACKGROUND_GC - if (settings.concurrent && (GetCurrentThreadId() == bgc_thread_id)) + if (settings.concurrent && (bgc_thread_id.IsCurrentThread())) { // We always call verify_heap on entry of GC on the SVR GC threads. current_join = &bgc_t_join; @@ -33559,6 +33410,11 @@ HRESULT GCHeap::Initialize () HRESULT hr = S_OK; + if (!GCToOSInterface::Initialize()) + { + return E_FAIL; + } + //Initialize the static members. #ifdef TRACE_GC GcDuration = 0; @@ -33572,7 +33428,7 @@ HRESULT GCHeap::Initialize () #ifdef MULTIPLE_HEAPS // GetGCProcessCpuCount only returns up to 64 procs. unsigned nhp = CPUGroupInfo::CanEnableGCCPUGroups() ? CPUGroupInfo::GetNumActiveProcessors(): - GetCurrentProcessCpuCount(); + GCToOSInterface::GetCurrentProcessCpuCount(); hr = gc_heap::initialize_gc (seg_size, large_seg_size /*LHEAP_ALLOC*/, nhp); #else hr = gc_heap::initialize_gc (seg_size, large_seg_size /*LHEAP_ALLOC*/); @@ -33582,7 +33438,7 @@ HRESULT GCHeap::Initialize () return hr; GCMemoryStatus ms; - GetProcessMemoryLoad (&ms); + GCToOSInterface::GetMemoryStatus (&ms); gc_heap::total_physical_mem = ms.ullTotalPhys; gc_heap::mem_one_percent = gc_heap::total_physical_mem / 100; #ifndef MULTIPLE_HEAPS @@ -33596,7 +33452,7 @@ HRESULT GCHeap::Initialize () // I am assuming 47 processes using WKS GC and 3 using SVR GC. // I am assuming 3 in part due to the "very high memory load" is 97%. int available_mem_th = 10; - if (gc_heap::total_physical_mem >= ((ULONGLONG)80 * 1024 * 1024 * 1024)) + if (gc_heap::total_physical_mem >= ((uint64_t)80 * 1024 * 1024 * 1024)) { int adjusted_available_mem_th = 3 + (int)((float)47 / (float)(g_SystemInfo.dwNumberOfProcessors)); available_mem_th = min (available_mem_th, adjusted_available_mem_th); @@ -34056,7 +33912,7 @@ BOOL GCHeap::StressHeap(alloc_context * acontext) // Allow programmer to skip the first N Stress GCs so that you can // get to the interesting ones faster. - FastInterlockIncrement((LONG*)&GCStressCurCount); + Interlocked::Increment(&GCStressCurCount); if (GCStressCurCount < GCStressStartCount) return FALSE; @@ -34102,7 +33958,7 @@ BOOL GCHeap::StressHeap(alloc_context * acontext) // at a time. A secondary advantage is that we release part of our StressObjs // buffer sparingly but just as effectively. - if (FastInterlockIncrement((LONG *) &OneAtATime) == 0 && + if (Interlocked::Increment(&OneAtATime) == 0 && !TrackAllocations()) // Messing with object sizes can confuse the profiler (see ICorProfilerInfo::GetObjectSize) { StringObject* str; @@ -34164,7 +34020,7 @@ BOOL GCHeap::StressHeap(alloc_context * acontext) } } } - FastInterlockDecrement((LONG *) &OneAtATime); + Interlocked::Decrement(&OneAtATime); #endif // !MULTIPLE_HEAPS if (IsConcurrentGCEnabled()) { @@ -35747,18 +35603,18 @@ size_t GCHeap::GetValidGen0MaxSize(size_t seg_size) #ifdef SERVER_GC // performance data seems to indicate halving the size results // in optimal perf. Ask for adjusted gen0 size. - gen0size = max(GetLargestOnDieCacheSize(FALSE)/GetLogicalCpuCount(),(256*1024)); + gen0size = max(GCToOSInterface::GetLargestOnDieCacheSize(FALSE)/GCToOSInterface::GetLogicalCpuCount(),(256*1024)); #if (defined(_TARGET_AMD64_)) // if gen0 size is too large given the available memory, reduce it. // Get true cache size, as we don't want to reduce below this. - size_t trueSize = max(GetLargestOnDieCacheSize(TRUE)/GetLogicalCpuCount(),(256*1024)); + size_t trueSize = max(GCToOSInterface::GetLargestOnDieCacheSize(TRUE)/GCToOSInterface::GetLogicalCpuCount(),(256*1024)); dprintf (2, ("cache: %Id-%Id, cpu: %Id", - GetLargestOnDieCacheSize(FALSE), - GetLargestOnDieCacheSize(TRUE), - GetLogicalCpuCount())); + GCToOSInterface::GetLargestOnDieCacheSize(FALSE), + GCToOSInterface::GetLargestOnDieCacheSize(TRUE), + GCToOSInterface::GetLogicalCpuCount())); GCMemoryStatus ms; - GetProcessMemoryLoad (&ms); + GCToOSInterface::GetMemoryStatus (&ms); // if the total min GC across heaps will exceed 1/6th of available memory, // then reduce the min GC size until it either fits or has been reduced to cache size. while ((gen0size * gc_heap::n_heaps) > (ms.ullAvailPhys / 6)) @@ -35773,7 +35629,7 @@ size_t GCHeap::GetValidGen0MaxSize(size_t seg_size) #endif //_TARGET_AMD64_ #else //SERVER_GC - gen0size = max((4*GetLargestOnDieCacheSize(TRUE)/5),(256*1024)); + gen0size = max((4*GCToOSInterface::GetLargestOnDieCacheSize(TRUE)/5),(256*1024)); #endif //SERVER_GC #else //!FEATURE_REDHAWK gen0size = (256*1024); @@ -35982,8 +35838,7 @@ GCHeap::SetCardsAfterBulkCopy( Object **StartPoint, size_t len ) // Set Bit For Card and advance to next card size_t card = gcard_of ((uint8_t*)rover); - FastInterlockOr ((DWORD RAW_KEYWORD(volatile) *)&g_card_table[card/card_word_width], - (1 << (uint32_t)(card % card_word_width))); + Interlocked::Or (&g_card_table[card/card_word_width], (1U << (card % card_word_width))); // Skip to next card for the object rover = (Object**)align_on_card ((uint8_t*)(rover+1)); } @@ -36029,7 +35884,7 @@ bool CFinalize::Initialize() STRESS_LOG_OOM_STACK(sizeof(Object*[100])); if (g_pConfig->IsGCBreakOnOOMEnabled()) { - DebugBreak(); + GCToOSInterface::DebugBreak(); } return false; } @@ -36042,7 +35897,7 @@ bool CFinalize::Initialize() m_PromotedCount = 0; lock = -1; #ifdef _DEBUG - lockowner_threadid = (uint32_t) -1; + lockowner_threadid.Clear(); #endif // _DEBUG return true; @@ -36066,22 +35921,22 @@ void CFinalize::EnterFinalizeLock() GCToEEInterface::IsPreemptiveGCDisabled(GetThread())); retry: - if (FastInterlockExchange ((LONG*)&lock, 0) >= 0) + if (Interlocked::Exchange (&lock, 0) >= 0) { unsigned int i = 0; while (lock >= 0) { YieldProcessor(); // indicate to the processor that we are spining if (++i & 7) - __SwitchToThread (0, CALLER_LIMITS_SPINNING); + GCToOSInterface::YieldThread (0); else - __SwitchToThread (5, CALLER_LIMITS_SPINNING); + GCToOSInterface::Sleep (5); } goto retry; } #ifdef _DEBUG - lockowner_threadid = ::GetCurrentThreadId(); + lockowner_threadid.SetToCurrentThread(); #endif // _DEBUG } @@ -36093,7 +35948,7 @@ void CFinalize::LeaveFinalizeLock() GCToEEInterface::IsPreemptiveGCDisabled(GetThread())); #ifdef _DEBUG - lockowner_threadid = (uint32_t) -1; + lockowner_threadid.Clear(); #endif // _DEBUG lock = -1; } @@ -36143,7 +35998,7 @@ CFinalize::RegisterForFinalization (int gen, Object* obj, size_t size) STRESS_LOG_OOM_STACK(0); if (g_pConfig->IsGCBreakOnOOMEnabled()) { - DebugBreak(); + GCToOSInterface::DebugBreak(); } #ifdef FEATURE_REDHAWK return false; @@ -36795,7 +36650,7 @@ void TouchPages(LPVOID pStart, uint32_t cb) void deleteGCShadow() { if (g_GCShadow != 0) - VirtualFree (g_GCShadow, 0, MEM_RELEASE); + GCToOSInterface::VirtualRelease (g_GCShadow, g_GCShadowEnd - g_GCShadow); g_GCShadow = 0; g_GCShadowEnd = 0; } @@ -36810,7 +36665,7 @@ void initGCShadow() if (len > (size_t)(g_GCShadowEnd - g_GCShadow)) { deleteGCShadow(); - g_GCShadowEnd = g_GCShadow = (uint8_t*) VirtualAlloc(0, len, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE); + g_GCShadowEnd = g_GCShadow = (uint8_t*) GCToOSInterface::VirtualCommit(0, len); if (g_GCShadow) { g_GCShadowEnd += len; diff --git a/src/gc/gcee.cpp b/src/gc/gcee.cpp index 7a9bb18..8e4e448 100644 --- a/src/gc/gcee.cpp +++ b/src/gc/gcee.cpp @@ -379,15 +379,11 @@ size_t GCHeap::GetLastGCDuration(int generation) return dd_gc_elapsed_time (hp->dynamic_data_of (generation)); } +size_t GetHighPrecisionTimeStamp(); + size_t GCHeap::GetNow() { -#ifdef MULTIPLE_HEAPS - gc_heap* hp = gc_heap::g_heaps[0]; -#else - gc_heap* hp = pGenGCHeap; -#endif //MULTIPLE_HEAPS - - return hp->get_time_now(); + return GetHighPrecisionTimeStamp(); } #if defined(GC_PROFILING) //UNIXTODO: Enable this for FEATURE_EVENT_TRACE diff --git a/src/gc/gcpriv.h b/src/gc/gcpriv.h index 14bea15..fe40c0c 100644 --- a/src/gc/gcpriv.h +++ b/src/gc/gcpriv.h @@ -25,7 +25,7 @@ inline void FATAL_GC_ERROR() { - DebugBreak(); + GCToOSInterface::DebugBreak(); _ASSERTE(!"Fatal Error in GC."); EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE); } @@ -143,12 +143,12 @@ inline void FATAL_GC_ERROR() #if defined (SYNCHRONIZATION_STATS) || defined (STAGE_STATS) #define BEGIN_TIMING(x) \ LARGE_INTEGER x##_start; \ - QueryPerformanceCounter (&x##_start) + x##_start = GCToOSInterface::QueryPerformanceCounter () #define END_TIMING(x) \ LARGE_INTEGER x##_end; \ - QueryPerformanceCounter (&x##_end); \ - x += x##_end.QuadPart - x##_start.QuadPart + x##_end = GCToOSInterface::QueryPerformanceCounter (); \ + x += x##_end - x##_start #else #define BEGIN_TIMING(x) @@ -204,70 +204,7 @@ void GCLogConfig (const char *fmt, ... ); #define CLREvent CLREventStatic -#ifdef CreateFileMapping - -#undef CreateFileMapping - -#endif //CreateFileMapping - -#define CreateFileMapping WszCreateFileMapping - // hosted api -#ifdef InitializeCriticalSection -#undef InitializeCriticalSection -#endif //ifdef InitializeCriticalSection -#define InitializeCriticalSection UnsafeInitializeCriticalSection - -#ifdef DeleteCriticalSection -#undef DeleteCriticalSection -#endif //ifdef DeleteCriticalSection -#define DeleteCriticalSection UnsafeDeleteCriticalSection - -#ifdef EnterCriticalSection -#undef EnterCriticalSection -#endif //ifdef EnterCriticalSection -#define EnterCriticalSection UnsafeEEEnterCriticalSection - -#ifdef LeaveCriticalSection -#undef LeaveCriticalSection -#endif //ifdef LeaveCriticalSection -#define LeaveCriticalSection UnsafeEELeaveCriticalSection - -#ifdef TryEnterCriticalSection -#undef TryEnterCriticalSection -#endif //ifdef TryEnterCriticalSection -#define TryEnterCriticalSection UnsafeEETryEnterCriticalSection - -#ifdef CreateSemaphore -#undef CreateSemaphore -#endif //CreateSemaphore -#define CreateSemaphore UnsafeCreateSemaphore - -#ifdef CreateEvent -#undef CreateEvent -#endif //ifdef CreateEvent -#define CreateEvent UnsafeCreateEvent - -#ifdef VirtualAlloc -#undef VirtualAlloc -#endif //ifdef VirtualAlloc -#define VirtualAlloc ClrVirtualAlloc - -#ifdef VirtualFree -#undef VirtualFree -#endif //ifdef VirtualFree -#define VirtualFree ClrVirtualFree - -#ifdef VirtualQuery -#undef VirtualQuery -#endif //ifdef VirtualQuery -#define VirtualQuery ClrVirtualQuery - -#ifdef VirtualProtect -#undef VirtualProtect -#endif //ifdef VirtualProtect -#define VirtualProtect ClrVirtualProtect - #ifdef memcpy #undef memcpy #endif //memcpy @@ -1045,7 +982,7 @@ struct spinlock_info { msl_enter_state enter_state; msl_take_state take_state; - uint32_t thread_id; + EEThreadId thread_id; }; const unsigned HS_CACHE_LINE_SIZE = 128; @@ -1293,7 +1230,7 @@ public: static gc_heap* balance_heaps_loh (alloc_context* acontext, size_t size); static - uint32_t __stdcall gc_thread_stub (void* arg); + void __stdcall gc_thread_stub (void* arg); #endif //MULTIPLE_HEAPS CObjectHeader* try_fast_alloc (size_t jsize); @@ -1621,13 +1558,13 @@ protected: struct loh_state_info { allocation_state alloc_state; - uint32_t thread_id; + EEThreadId thread_id; }; PER_HEAP loh_state_info last_loh_states[max_saved_loh_states]; PER_HEAP - void add_saved_loh_state (allocation_state loh_state_to_save, uint32_t thread_id); + void add_saved_loh_state (allocation_state loh_state_to_save, EEThreadId thread_id); #endif //RECORD_LOH_STATE PER_HEAP BOOL allocate_large (int gen_number, @@ -2517,8 +2454,6 @@ protected: PER_HEAP void save_ephemeral_generation_starts(); - static size_t get_time_now(); - PER_HEAP bool init_dynamic_data (); PER_HEAP @@ -2612,9 +2547,9 @@ protected: PER_HEAP_ISOLATED void destroy_thread_support (); PER_HEAP - HANDLE create_gc_thread(); + bool create_gc_thread(); PER_HEAP - uint32_t gc_thread_function(); + void gc_thread_function(); #ifdef MARK_LIST #ifdef PARALLEL_MARK_LIST_SORT PER_HEAP @@ -3109,7 +3044,7 @@ protected: #ifdef BACKGROUND_GC PER_HEAP - uint32_t bgc_thread_id; + EEThreadId bgc_thread_id; #ifdef WRITE_WATCH PER_HEAP @@ -3152,7 +3087,7 @@ protected: Thread* bgc_thread; PER_HEAP - CRITICAL_SECTION bgc_threads_timeout_cs; + CLRCriticalSection bgc_threads_timeout_cs; PER_HEAP_ISOLATED CLREvent background_gc_done_event; @@ -3728,8 +3663,6 @@ public: SPTR_DECL(PTR_gc_heap, g_heaps); static - HANDLE* g_gc_threads; // keep all of the gc threads. - static size_t* g_promoted; #ifdef BACKGROUND_GC static @@ -3784,7 +3717,7 @@ private: VOLATILE(int32_t) lock; #ifdef _DEBUG - uint32_t lockowner_threadid; + EEThreadId lockowner_threadid; #endif // _DEBUG BOOL GrowArray(); diff --git a/src/gc/gcscan.cpp b/src/gc/gcscan.cpp index 621ffad..78e0dd6 100644 --- a/src/gc/gcscan.cpp +++ b/src/gc/gcscan.cpp @@ -270,13 +270,13 @@ void GCScan::GcRuntimeStructuresValid (BOOL bValid) if (!bValid) { int32_t result; - result = FastInterlockIncrement ((LONG*)&m_GcStructuresInvalidCnt); + result = Interlocked::Increment (&m_GcStructuresInvalidCnt); _ASSERTE (result > 0); } else { int32_t result; - result = FastInterlockDecrement ((LONG*)&m_GcStructuresInvalidCnt); + result = Interlocked::Decrement (&m_GcStructuresInvalidCnt); _ASSERTE (result >= 0); } } diff --git a/src/gc/handletable.cpp b/src/gc/handletable.cpp index e14316b..7f855bb 100644 --- a/src/gc/handletable.cpp +++ b/src/gc/handletable.cpp @@ -688,7 +688,7 @@ uintptr_t HndCompareExchangeHandleExtraInfo(OBJECTHANDLE handle, uint32_t uType, if (pUserData) { // yes - attempt to store the info - return (uintptr_t)FastInterlockCompareExchangePointer((void**)pUserData, (void*)lNewExtraInfo, (void*)lOldExtraInfo); + return (uintptr_t)Interlocked::CompareExchangePointer((void**)pUserData, (void*)lNewExtraInfo, (void*)lOldExtraInfo); } _ASSERTE(!"Shouldn't be trying to call HndCompareExchangeHandleExtraInfo on handle types without extra info"); diff --git a/src/gc/handletable.inl b/src/gc/handletable.inl index 29594d0..15c38fd 100644 --- a/src/gc/handletable.inl +++ b/src/gc/handletable.inl @@ -67,7 +67,7 @@ inline void* HndInterlockedCompareExchangeHandle(OBJECTHANDLE handle, OBJECTREF // store the pointer - void* ret = FastInterlockCompareExchangePointer(reinterpret_cast<_UNCHECKED_OBJECTREF volatile*>(handle), value, oldValue); + void* ret = Interlocked::CompareExchangePointer(reinterpret_cast<_UNCHECKED_OBJECTREF volatile*>(handle), value, oldValue); if (ret == oldValue) HndLogSetEvent(handle, value); @@ -101,7 +101,7 @@ inline BOOL HndFirstAssignHandle(OBJECTHANDLE handle, OBJECTREF objref) _UNCHECKED_OBJECTREF null = NULL; // store the pointer if we are the first ones here - BOOL success = (NULL == FastInterlockCompareExchangePointer(reinterpret_cast<_UNCHECKED_OBJECTREF volatile*>(handle), + BOOL success = (NULL == Interlocked::CompareExchangePointer(reinterpret_cast<_UNCHECKED_OBJECTREF volatile*>(handle), value, null)); diff --git a/src/gc/handletablecache.cpp b/src/gc/handletablecache.cpp index 717348f..33cc08e 100644 --- a/src/gc/handletablecache.cpp +++ b/src/gc/handletablecache.cpp @@ -86,7 +86,7 @@ void SpinUntil(void *pCond, BOOL fNonZero) #endif //_DEBUG // sleep for a little while - __SwitchToThread(dwThisSleepPeriod, CALLER_LIMITS_SPINNING); + GCToOSInterface::Sleep(dwThisSleepPeriod); // now update our sleep period dwThisSleepPeriod = dwNextSleepPeriod; @@ -471,7 +471,7 @@ void TableFullRebalanceCache(HandleTable *pTable, // update the write index for the free bank // NOTE: we use an interlocked exchange here to guarantee relative store order on MP // AFTER THIS POINT THE FREE BANK IS LIVE AND COULD RECEIVE NEW HANDLES - FastInterlockExchange((LONG*)&pCache->lFreeIndex, lMinFreeIndex); + Interlocked::Exchange(&pCache->lFreeIndex, lMinFreeIndex); // now if we have any handles left, store them in the reserve bank if (uHandleCount) @@ -488,7 +488,7 @@ void TableFullRebalanceCache(HandleTable *pTable, // update the read index for the reserve bank // NOTE: we use an interlocked exchange here to guarantee relative store order on MP // AT THIS POINT THE RESERVE BANK IS LIVE AND HANDLES COULD BE ALLOCATED FROM IT - FastInterlockExchange((LONG*)&pCache->lReserveIndex, lMinReserveIndex); + Interlocked::Exchange(&pCache->lReserveIndex, lMinReserveIndex); } @@ -599,12 +599,12 @@ void TableQuickRebalanceCache(HandleTable *pTable, // update the write index for the free bank // NOTE: we use an interlocked exchange here to guarantee relative store order on MP // AFTER THIS POINT THE FREE BANK IS LIVE AND COULD RECEIVE NEW HANDLES - FastInterlockExchange((LONG*)&pCache->lFreeIndex, lMinFreeIndex); + Interlocked::Exchange(&pCache->lFreeIndex, lMinFreeIndex); // update the read index for the reserve bank // NOTE: we use an interlocked exchange here to guarantee relative store order on MP // AT THIS POINT THE RESERVE BANK IS LIVE AND HANDLES COULD BE ALLOCATED FROM IT - FastInterlockExchange((LONG*)&pCache->lReserveIndex, lMinReserveIndex); + Interlocked::Exchange(&pCache->lReserveIndex, lMinReserveIndex); } @@ -630,13 +630,13 @@ OBJECTHANDLE TableCacheMissOnAlloc(HandleTable *pTable, HandleTypeCache *pCache, CrstHolder ch(&pTable->Lock); // try again to take a handle (somebody else may have rebalanced) - int32_t lReserveIndex = FastInterlockDecrement((LONG*)&pCache->lReserveIndex); + int32_t lReserveIndex = Interlocked::Decrement(&pCache->lReserveIndex); // are we still waiting for handles? if (lReserveIndex < 0) { // yup, suspend free list usage... - int32_t lFreeIndex = FastInterlockExchange((LONG*)&pCache->lFreeIndex, 0L); + int32_t lFreeIndex = Interlocked::Exchange(&pCache->lFreeIndex, 0); // ...and rebalance the cache... TableQuickRebalanceCache(pTable, pCache, uType, lReserveIndex, lFreeIndex, &handle, NULL); @@ -680,13 +680,13 @@ void TableCacheMissOnFree(HandleTable *pTable, HandleTypeCache *pCache, uint32_t CrstHolder ch(&pTable->Lock); // try again to take a slot (somebody else may have rebalanced) - int32_t lFreeIndex = FastInterlockDecrement((LONG*)&pCache->lFreeIndex); + int32_t lFreeIndex = Interlocked::Decrement(&pCache->lFreeIndex); // are we still waiting for free slots? if (lFreeIndex < 0) { // yup, suspend reserve list usage... - int32_t lReserveIndex = FastInterlockExchange((LONG*)&pCache->lReserveIndex, 0L); + int32_t lReserveIndex = Interlocked::Exchange(&pCache->lReserveIndex, 0); // ...and rebalance the cache... TableQuickRebalanceCache(pTable, pCache, uType, lReserveIndex, lFreeIndex, NULL, handle); @@ -718,7 +718,7 @@ OBJECTHANDLE TableAllocSingleHandleFromCache(HandleTable *pTable, uint32_t uType if (pTable->rgQuickCache[uType]) { // try to grab the handle we saw - handle = FastInterlockExchangePointer(pTable->rgQuickCache + uType, (OBJECTHANDLE)NULL); + handle = Interlocked::ExchangePointer(pTable->rgQuickCache + uType, (OBJECTHANDLE)NULL); // if it worked then we're done if (handle) @@ -729,7 +729,7 @@ OBJECTHANDLE TableAllocSingleHandleFromCache(HandleTable *pTable, uint32_t uType HandleTypeCache *pCache = pTable->rgMainCache + uType; // try to take a handle from the main cache - int32_t lReserveIndex = FastInterlockDecrement((LONG*)&pCache->lReserveIndex); + int32_t lReserveIndex = Interlocked::Decrement(&pCache->lReserveIndex); // did we underflow? if (lReserveIndex < 0) @@ -787,7 +787,7 @@ void TableFreeSingleHandleToCache(HandleTable *pTable, uint32_t uType, OBJECTHAN if (!pTable->rgQuickCache[uType]) { // yup - try to stuff our handle in the slot we saw - handle = FastInterlockExchangePointer(&pTable->rgQuickCache[uType], handle); + handle = Interlocked::ExchangePointer(&pTable->rgQuickCache[uType], handle); // if we didn't end up with another handle then we're done if (!handle) @@ -798,7 +798,7 @@ void TableFreeSingleHandleToCache(HandleTable *pTable, uint32_t uType, OBJECTHAN HandleTypeCache *pCache = pTable->rgMainCache + uType; // try to take a free slot from the main cache - int32_t lFreeIndex = FastInterlockDecrement((LONG*)&pCache->lFreeIndex); + int32_t lFreeIndex = Interlocked::Decrement(&pCache->lFreeIndex); // did we underflow? if (lFreeIndex < 0) diff --git a/src/gc/handletablecore.cpp b/src/gc/handletablecore.cpp index 8435f94..d302087 100644 --- a/src/gc/handletablecore.cpp +++ b/src/gc/handletablecore.cpp @@ -239,7 +239,7 @@ BOOL TableCanFreeSegmentNow(HandleTable *pTable, TableSegment *pSegment) // fail but by the time a dump was created the lock was unowned so // there was no way to tell who the previous owner was. EEThreadId threadId = pTable->Lock.GetHolderThreadId(); - _ASSERTE(threadId.IsSameThread()); + _ASSERTE(threadId.IsCurrentThread()); #endif // _DEBUG // deterine if any segment is currently being scanned asynchronously @@ -526,7 +526,7 @@ BOOL SegmentInitialize(TableSegment *pSegment, HandleTable *pTable) dwCommit &= ~(g_SystemInfo.dwPageSize - 1); // commit the header - if (!ClrVirtualAlloc(pSegment, dwCommit, MEM_COMMIT, PAGE_READWRITE)) + if (!GCToOSInterface::VirtualCommit(pSegment, dwCommit)) { //_ASSERTE(FALSE); return FALSE; @@ -581,7 +581,7 @@ void SegmentFree(TableSegment *pSegment) */ // free the segment's memory - ClrVirtualFree(pSegment, 0, MEM_RELEASE); + GCToOSInterface::VirtualRelease(pSegment, HANDLE_SEGMENT_SIZE); } @@ -611,7 +611,7 @@ TableSegment *SegmentAlloc(HandleTable *pTable) _ASSERTE(HANDLE_SEGMENT_ALIGNMENT >= HANDLE_SEGMENT_SIZE); _ASSERTE(HANDLE_SEGMENT_ALIGNMENT == 0x10000); - pSegment = (TableSegment *)ClrVirtualAllocAligned(NULL, HANDLE_SEGMENT_SIZE, MEM_RESERVE, PAGE_NOACCESS, HANDLE_SEGMENT_ALIGNMENT); + pSegment = (TableSegment *)GCToOSInterface::VirtualReserve(NULL, HANDLE_SEGMENT_SIZE, HANDLE_SEGMENT_ALIGNMENT, VirtualReserveFlags::None); _ASSERTE(((size_t)pSegment % HANDLE_SEGMENT_ALIGNMENT) == 0); // bail out if we couldn't get any memory @@ -1440,7 +1440,7 @@ uint32_t SegmentInsertBlockFromFreeListWorker(TableSegment *pSegment, uint32_t u uint32_t dwCommit = g_SystemInfo.dwPageSize; // commit the memory - if (!ClrVirtualAlloc(pvCommit, dwCommit, MEM_COMMIT, PAGE_READWRITE)) + if (!GCToOSInterface::VirtualCommit(pvCommit, dwCommit)) return BLOCK_INVALID; // use the previous commit line as the new decommit line @@ -1844,7 +1844,7 @@ void SegmentTrimExcessPages(TableSegment *pSegment) if (dwHi > dwLo) { // decommit the memory - ClrVirtualFree((LPVOID)dwLo, dwHi - dwLo, MEM_DECOMMIT); + GCToOSInterface::VirtualDecommit((LPVOID)dwLo, dwHi - dwLo); // update the commit line pSegment->bCommitLine = (uint8_t)((dwLo - (size_t)pSegment->rgValue) / HANDLE_BYTES_PER_BLOCK); diff --git a/src/gc/objecthandle.cpp b/src/gc/objecthandle.cpp index 8b72d0d..1654cf9 100644 --- a/src/gc/objecthandle.cpp +++ b/src/gc/objecthandle.cpp @@ -787,7 +787,7 @@ HandleTableBucket *Ref_CreateHandleTableBucket(ADIndex uADIndex) HndSetHandleTableIndex(result->pTable[uCPUindex], i+offset); result->HandleTableIndex = i+offset; - if (FastInterlockCompareExchangePointer(&walk->pBuckets[i], result, NULL) == 0) { + if (Interlocked::CompareExchangePointer(&walk->pBuckets[i], result, NULL) == 0) { // Get a free slot. bucketHolder.SuppressRelease(); return result; @@ -812,7 +812,7 @@ HandleTableBucket *Ref_CreateHandleTableBucket(ADIndex uADIndex) ZeroMemory(newMap->pBuckets, INITIAL_HANDLE_TABLE_ARRAY_SIZE * sizeof (HandleTableBucket *)); - if (FastInterlockCompareExchangePointer(&last->pNext, newMap.GetValue(), NULL) != NULL) + if (Interlocked::CompareExchangePointer(&last->pNext, newMap.GetValue(), NULL) != NULL) { // This thread loses. delete [] newMap->pBuckets; @@ -1575,8 +1575,8 @@ void Ref_UpdatePointers(uint32_t condemned, uint32_t maxgen, ScanContext* sc, Re if (GCHeap::IsServerHeap()) { - bDo = (FastInterlockIncrement((LONG*)&uCount) == 1); - FastInterlockCompareExchange ((LONG*)&uCount, 0, GCHeap::GetGCHeap()->GetNumberOfHeaps()); + bDo = (Interlocked::Increment(&uCount) == 1); + Interlocked::CompareExchange (&uCount, 0, GCHeap::GetGCHeap()->GetNumberOfHeaps()); _ASSERTE (uCount <= GCHeap::GetGCHeap()->GetNumberOfHeaps()); } diff --git a/src/gc/sample/CMakeLists.txt b/src/gc/sample/CMakeLists.txt index 8bed3ad..a46f9ae 100644 --- a/src/gc/sample/CMakeLists.txt +++ b/src/gc/sample/CMakeLists.txt @@ -1,11 +1,13 @@ project(clrgcsample) +set(CMAKE_INCLUDE_CURRENT_DIR ON) + include_directories(..) include_directories(../env) set(SOURCES GCSample.cpp - gcenv.cpp + gcenv.ee.cpp ../gccommon.cpp ../gceewks.cpp ../gcscan.cpp @@ -19,45 +21,12 @@ set(SOURCES if(WIN32) list(APPEND SOURCES - ../env/gcenv.windows.cpp) + gcenv.windows.cpp) else() list(APPEND SOURCES - ../env/gcenv.unix.cpp) -endif() - -if(CLR_CMAKE_PLATFORM_UNIX) - add_compile_options(-Wno-format) - add_compile_options(-Wno-unused-variable) - add_compile_options(-Wno-unused-private-field) - add_compile_options(-Wno-tautological-undefined-compare) + gcenv.unix.cpp) endif() -if(CLR_CMAKE_PLATFORM_ARCH_AMD64) - add_definitions(-D_TARGET_AMD64_=1) - set(IS_64BIT_BUILD 1) -elseif(CLR_CMAKE_PLATFORM_ARCH_I386) - add_definitions(-D_TARGET_X86_=1) -elseif(CLR_CMAKE_PLATFORM_ARCH_ARM) - add_definitions(-D_TARGET_ARM_=1) -elseif(CLR_CMAKE_PLATFORM_ARCH_ARM64) - add_definitions(-D_TARGET_ARM64_=1) - set(IS_64BIT_BUILD 1) -else() - clr_unknown_arch() -endif() - -if(IS_64BIT_BUILD) - add_definitions(-DBIT64=1) -endif(IS_64BIT_BUILD) - -if(WIN32) - add_definitions(-DWIN32) - add_definitions(-D_WIN32=1) - if(IS_64BIT_BUILD) - add_definitions(-D_WIN64=1) - endif() -endif(WIN32) - add_executable(gcsample ${SOURCES} ) diff --git a/src/gc/sample/GCSample.cpp b/src/gc/sample/GCSample.cpp index 4469561..eb2c9aa 100644 --- a/src/gc/sample/GCSample.cpp +++ b/src/gc/sample/GCSample.cpp @@ -111,12 +111,15 @@ void WriteBarrier(Object ** dst, Object * ref) ErectWriteBarrier(dst, ref); } -int main(int argc, char* argv[]) +int __cdecl main(int argc, char* argv[]) { // // Initialize system info // - InitializeSystemInfo(); + if (!GCToOSInterface::Initialize()) + { + return -1; + } // // Initialize free object methodtable. The GC uses a special array-like methodtable as placeholder @@ -170,7 +173,7 @@ int main(int argc, char* argv[]) My_MethodTable; // 'My' contains the MethodTable* - size_t baseSize = sizeof(My); + uint32_t baseSize = sizeof(My); // GC expects the size of ObjHeader (extra void*) to be included in the size. baseSize = baseSize + sizeof(ObjHeader); // Add padding as necessary. GC requires the object size to be at least MIN_OBJECT_SIZE. diff --git a/src/gc/sample/GCSample.vcxproj b/src/gc/sample/GCSample.vcxproj index a0a79c5..eefca17 100644 --- a/src/gc/sample/GCSample.vcxproj +++ b/src/gc/sample/GCSample.vcxproj @@ -83,7 +83,8 @@ - + + @@ -94,7 +95,6 @@ - Create Create diff --git a/src/gc/sample/GCSample.vcxproj.filters b/src/gc/sample/GCSample.vcxproj.filters index 1e9facd..e46c054 100644 --- a/src/gc/sample/GCSample.vcxproj.filters +++ b/src/gc/sample/GCSample.vcxproj.filters @@ -53,13 +53,13 @@ Source Files - + Source Files - + Source Files - + Source Files diff --git a/src/gc/sample/gcenv.cpp b/src/gc/sample/gcenv.cpp deleted file mode 100644 index 2164fb0..0000000 --- a/src/gc/sample/gcenv.cpp +++ /dev/null @@ -1,156 +0,0 @@ -// -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. -// - -#include "common.h" - -#include "windows.h" - -#include "gcenv.h" -#include "gc.h" - -EEConfig * g_pConfig; - -#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() -{ - // TODO: Locks - - Thread * pThread = new Thread(); - pThread->GetAllocContext()->init(); - pCurrentThread = pThread; - - pThread->m_pNext = g_pThreadList; - g_pThreadList = pThread; -} - -void GCToEEInterface::SuspendEE(GCToEEInterface::SUSPEND_REASON reason) -{ - GCHeap::GetGCHeap()->SetGCInProgress(TRUE); - - // TODO: Implement -} - -void GCToEEInterface::RestartEE(bool bFinishedGC) -{ - // TODO: Implement - - GCHeap::GetGCHeap()->SetGCInProgress(FALSE); -} - -void GCToEEInterface::GcScanRoots(promote_func* fn, int condemned, int max_gen, ScanContext* sc) -{ - // TODO: Implement - Scan stack roots on given thread -} - -void GCToEEInterface::GcStartWork(int condemned, int max_gen) -{ -} - -void GCToEEInterface::AfterGcScanRoots(int condemned, int max_gen, ScanContext* sc) -{ -} - -void GCToEEInterface::GcBeforeBGCSweepWork() -{ -} - -void GCToEEInterface::GcDone(int condemned) -{ -} - -bool GCToEEInterface::RefCountedHandleCallbacks(Object * pObject) -{ - return false; -} - -bool GCToEEInterface::IsPreemptiveGCDisabled(Thread * pThread) -{ - return pThread->PreemptiveGCDisabled(); -} - -void GCToEEInterface::EnablePreemptiveGC(Thread * pThread) -{ - return pThread->EnablePreemptiveGC(); -} - -void GCToEEInterface::DisablePreemptiveGC(Thread * pThread) -{ - pThread->DisablePreemptiveGC(); -} - -void GCToEEInterface::SetGCSpecial(Thread * pThread) -{ - pThread->SetGCSpecial(true); -} - -alloc_context * GCToEEInterface::GetAllocContext(Thread * pThread) -{ - return pThread->GetAllocContext(); -} - -bool GCToEEInterface::CatchAtSafePoint(Thread * pThread) -{ - return pThread->CatchAtSafePoint(); -} - -// does not acquire thread store lock -void GCToEEInterface::AttachCurrentThread() -{ - ThreadStore::AttachCurrentThread(); -} - -void GCToEEInterface::GcEnumAllocContexts (enum_alloc_context_func* fn, void* param) -{ - Thread * pThread = NULL; - while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL) - { - fn(pThread->GetAllocContext(), param); - } -} - - -void FinalizerThread::EnableFinalization() -{ - // Signal to finalizer thread that there are objects to finalize - // TODO: Implement for finalization -} - -bool FinalizerThread::HaveExtraWorkForFinalizer() -{ - return false; -} - -bool PalStartBackgroundGCThread(BackgroundCallback callback, void* pCallbackContext) -{ - // TODO: Implement for background GC - return false; -} - -bool IsGCSpecialThread() -{ - // TODO: Implement for background GC - return false; -} diff --git a/src/gc/sample/gcenv.ee.cpp b/src/gc/sample/gcenv.ee.cpp new file mode 100644 index 0000000..a1a0360 --- /dev/null +++ b/src/gc/sample/gcenv.ee.cpp @@ -0,0 +1,289 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "common.h" + +#include "windows.h" + +#include "gcenv.h" +#include "gc.h" + +EEConfig * g_pConfig; + +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 (GCToEEInterface::IsPreemptiveGCDisabled(pCurThread)) + { + GCToEEInterface::EnablePreemptiveGC(pCurThread); + disablePreemptive = true; + } + } + + result = WaitForSingleObjectEx(m_hEvent, dwMilliseconds, bAlertable); + + if (disablePreemptive) + { + GCToEEInterface::DisablePreemptiveGC(pCurThread); + } + } + + return result; +} + +__declspec(thread) 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() +{ + // TODO: Locks + + Thread * pThread = new Thread(); + pThread->GetAllocContext()->init(); + pCurrentThread = pThread; + + pThread->m_pNext = g_pThreadList; + g_pThreadList = pThread; +} + +void GCToEEInterface::SuspendEE(GCToEEInterface::SUSPEND_REASON reason) +{ + GCHeap::GetGCHeap()->SetGCInProgress(TRUE); + + // TODO: Implement +} + +void GCToEEInterface::RestartEE(bool bFinishedGC) +{ + // TODO: Implement + + GCHeap::GetGCHeap()->SetGCInProgress(FALSE); +} + +void GCToEEInterface::GcScanRoots(promote_func* fn, int condemned, int max_gen, ScanContext* sc) +{ + // TODO: Implement - Scan stack roots on given thread +} + +void GCToEEInterface::GcStartWork(int condemned, int max_gen) +{ +} + +void GCToEEInterface::AfterGcScanRoots(int condemned, int max_gen, ScanContext* sc) +{ +} + +void GCToEEInterface::GcBeforeBGCSweepWork() +{ +} + +void GCToEEInterface::GcDone(int condemned) +{ +} + +bool GCToEEInterface::RefCountedHandleCallbacks(Object * pObject) +{ + return false; +} + +bool GCToEEInterface::IsPreemptiveGCDisabled(Thread * pThread) +{ + return pThread->PreemptiveGCDisabled(); +} + +void GCToEEInterface::EnablePreemptiveGC(Thread * pThread) +{ + return pThread->EnablePreemptiveGC(); +} + +void GCToEEInterface::DisablePreemptiveGC(Thread * pThread) +{ + pThread->DisablePreemptiveGC(); +} + +void GCToEEInterface::SetGCSpecial(Thread * pThread) +{ + pThread->SetGCSpecial(true); +} + +alloc_context * GCToEEInterface::GetAllocContext(Thread * pThread) +{ + return pThread->GetAllocContext(); +} + +bool GCToEEInterface::CatchAtSafePoint(Thread * pThread) +{ + return pThread->CatchAtSafePoint(); +} + +// does not acquire thread store lock +void GCToEEInterface::AttachCurrentThread() +{ + ThreadStore::AttachCurrentThread(); +} + +void GCToEEInterface::GcEnumAllocContexts (enum_alloc_context_func* fn, void* param) +{ + Thread * pThread = NULL; + while ((pThread = ThreadStore::GetThreadList(pThread)) != NULL) + { + fn(pThread->GetAllocContext(), param); + } +} + +void GCToEEInterface::SyncBlockCacheWeakPtrScan(HANDLESCANPROC /*scanProc*/, uintptr_t /*lp1*/, uintptr_t /*lp2*/) +{ +} + +void GCToEEInterface::SyncBlockCacheDemote(int /*max_gen*/) +{ +} + +void GCToEEInterface::SyncBlockCachePromotionsGranted(int /*max_gen*/) +{ +} + +void FinalizerThread::EnableFinalization() +{ + // Signal to finalizer thread that there are objects to finalize + // TODO: Implement for finalization +} + +bool FinalizerThread::HaveExtraWorkForFinalizer() +{ + return false; +} + +bool PalStartBackgroundGCThread(BackgroundCallback callback, void* pCallbackContext) +{ + // TODO: Implement for background GC + return false; +} + +bool IsGCSpecialThread() +{ + // TODO: Implement for background GC + return false; +} + +void StompWriteBarrierEphemeral() +{ +} + +void StompWriteBarrierResize(bool /*bReqUpperBoundsCheck*/) +{ +} + +VOID LogSpewAlways(const char * /*fmt*/, ...) +{ +} + +uint32_t CLRConfig::GetConfigValue(ConfigDWORDInfo eType) +{ + switch (eType) + { + case UNSUPPORTED_BGCSpinCount: + return 140; + + case UNSUPPORTED_BGCSpin: + return 2; + + case UNSUPPORTED_GCLogEnabled: + case UNSUPPORTED_GCLogFile: + case UNSUPPORTED_GCLogFileSize: + case EXTERNAL_GCStressStart: + case INTERNAL_GCStressStartAtJit: + case INTERNAL_DbgDACSkipVerifyDlls: + return 0; + + case Config_COUNT: + default: +#ifdef _MSC_VER +#pragma warning(suppress:4127) // Constant conditional expression in ASSERT below +#endif + ASSERT(!"Unknown config value type"); + return 0; + } +} + +HRESULT CLRConfig::GetConfigValue(ConfigStringInfo /*eType*/, wchar_t * * outVal) +{ + *outVal = NULL; + return 0; +} diff --git a/src/gc/sample/gcenv.h b/src/gc/sample/gcenv.h index 1e391ab..c09d012 100644 --- a/src/gc/sample/gcenv.h +++ b/src/gc/sample/gcenv.h @@ -16,11 +16,20 @@ #define _ASSERTE(_expr) ASSERT(_expr) #endif +typedef wchar_t WCHAR; +#define W(s) L##s + #include "gcenv.structs.h" #include "gcenv.base.h" +#include "gcenv.ee.h" +#include "gcenv.os.h" +#include "gcenv.interlocked.h" +#include "gcenv.interlocked.inl" #include "gcenv.object.h" #include "gcenv.sync.h" +#define MAX_LONGPATH 1024 + // // Thread // diff --git a/src/gc/env/gcenv.unix.cpp b/src/gc/sample/gcenv.unix.cpp similarity index 91% rename from src/gc/env/gcenv.unix.cpp rename to src/gc/sample/gcenv.unix.cpp index c9186d5..33d9bd6 100644 --- a/src/gc/env/gcenv.unix.cpp +++ b/src/gc/sample/gcenv.unix.cpp @@ -115,6 +115,7 @@ void GetProcessMemoryLoad(GCMemoryStatus* pGCMemStatus) } } +#if 0 void CLREventStatic::CreateManualEvent(bool bInitialState) { // TODO: Implement @@ -196,6 +197,12 @@ uint32_t CLREventStatic::Wait(uint32_t dwMilliseconds, bool bAlertable) return result; } +#endif // 0 + +void DestroyThread(Thread * pThread) +{ + // TODO: implement +} bool __SwitchToThread(uint32_t dwSleepMSec, uint32_t dwSwitchCount) { @@ -328,6 +335,7 @@ int32_t g_TrapReturningThreads; bool g_fFinalizerRunOnShutDown; +#if 0 #ifdef _MSC_VER __declspec(thread) #else @@ -361,18 +369,68 @@ void ThreadStore::AttachCurrentThread(bool fAcquireThreadStoreLock) pThread->m_pNext = g_pThreadList; g_pThreadList = pThread; } - +#endif // 0 void DestroyThread(Thread * pThread) { // TODO: Implement } +#if 0 +void GCToEEInterface::SuspendEE(GCToEEInterface::SUSPEND_REASON reason) +{ + GCHeap::GetGCHeap()->SetGCInProgress(TRUE); + + // TODO: Implement +} + +void GCToEEInterface::RestartEE(bool bFinishedGC) +{ + // TODO: Implement + + GCHeap::GetGCHeap()->SetGCInProgress(FALSE); +} + +void GCToEEInterface::GcScanRoots(promote_func* fn, int condemned, int max_gen, ScanContext* sc) +{ + // TODO: Implement - Scan stack roots +} + +void GCToEEInterface::GcStartWork(int condemned, int max_gen) +{ +} + +void GCToEEInterface::AfterGcScanRoots(int condemned, int max_gen, ScanContext* sc) +{ +} + +void GCToEEInterface::GcBeforeBGCSweepWork() +{ +} + +void GCToEEInterface::GcDone(int condemned) +{ +} + void FinalizerThread::EnableFinalization() { // Signal to finalizer thread that there are objects to finalize // TODO: Implement for finalization } +bool PalStartBackgroundGCThread(BackgroundCallback callback, void* pCallbackContext) +{ + // TODO: Implement for background GC + return false; +} + +bool IsGCSpecialThread() +{ + // TODO: Implement for background GC + return false; +} + +#endif // 0 + bool PalHasCapability(PalCapability capability) { // TODO: Implement for background GC @@ -424,14 +482,6 @@ VirtualUnlock( } -WINBASEAPI -VOID -WINAPI -FlushProcessWriteBuffers() -{ - // TODO: Implement -} - const int tccSecondsToMillieSeconds = 1000; const int tccSecondsToMicroSeconds = 1000000; const int tccMillieSecondsToMicroSeconds = 1000; // 10^3 diff --git a/src/gc/sample/gcenv.windows.cpp b/src/gc/sample/gcenv.windows.cpp new file mode 100644 index 0000000..c9f0edb --- /dev/null +++ b/src/gc/sample/gcenv.windows.cpp @@ -0,0 +1,446 @@ +// +// 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" + +static LARGE_INTEGER performanceFrequency; + +MethodTable * g_pFreeObjectMethodTable; + +int32_t g_TrapReturningThreads; + +bool g_fFinalizerRunOnShutDown; + +GCSystemInfo g_SystemInfo; + +// Initialize the interface implementation +// Return: +// true if it has succeeded, false if it has failed +bool GCToOSInterface::Initialize() +{ + if (!::QueryPerformanceFrequency(&performanceFrequency)) + { + return false; + } + + SYSTEM_INFO systemInfo; + GetSystemInfo(&systemInfo); + + g_SystemInfo.dwNumberOfProcessors = systemInfo.dwNumberOfProcessors; + g_SystemInfo.dwPageSize = systemInfo.dwPageSize; + g_SystemInfo.dwAllocationGranularity = systemInfo.dwAllocationGranularity; + + 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 +uint32_t GCToOSInterface::GetCurrentThreadIdForLogging() +{ + return ::GetCurrentThreadId(); +} + +// Get id of the process +// Return: +// Id of the current process +uint32_t GCToOSInterface::GetCurrentProcessId() +{ + return ::GetCurrentProcessId(); +} + +// Set ideal affinity for the current thread +// Parameters: +// affinity - ideal processor affinity for the thread +// Return: +// true if it has succeeded, false if it has failed +bool GCToOSInterface::SetCurrentThreadIdealAffinity(GCThreadAffinity* affinity) +{ + bool success = true; + +#if !defined(FEATURE_CORESYSTEM) + SetThreadIdealProcessor(GetCurrentThread(), (DWORD)affinity->Processor); +#elif !defined(FEATURE_PAL) + PROCESSOR_NUMBER proc; + + if (affinity->Group != -1) + { + proc.Group = (WORD)affinity->Group; + proc.Number = (BYTE)affinity->Processor; + proc.Reserved = 0; + + success = !!SetThreadIdealProcessorEx(GetCurrentThread(), &proc, NULL); + } + else + { + if (GetThreadIdealProcessorEx(GetCurrentThread(), &proc)) + { + proc.Number = affinity->Processor; + success = !!SetThreadIdealProcessorEx(GetCurrentThread(), &proc, NULL); + } + } +#endif + + 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(); +} + +// Get number of logical processors +uint32_t GCToOSInterface::GetLogicalCpuCount() +{ + return g_SystemInfo.dwNumberOfProcessors; +} + +// 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) +{ + ::Sleep(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) +{ + SwitchToThread(); +} + +// 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(void* address, 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. 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) +{ + 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; +#ifndef FEATURE_PAL + if (success && unlock) + { + // Remove the page range from the working set + ::VirtualUnlock(address, size); + } +#endif // FEATURE_PAL + + return success; +} + +// Check if the OS supports write watching +bool GCToOSInterface::SupportsWriteWatch() +{ + return false; +} + +// 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::GetLargestOnDieCacheSize(bool trueSize) +{ + // TODO: implement + return 0; +} + +// 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. +bool GCToOSInterface::GetCurrentProcessAffinityMask(uintptr_t* processMask, uintptr_t* systemMask) +{ + return false; +} + +// Get number of processors assigned to the current process +// Return: +// The number of processors +uint32_t GCToOSInterface::GetCurrentProcessCpuCount() +{ + return g_SystemInfo.dwNumberOfProcessors; +} + +// Get global memory status +// Parameters: +// ms - pointer to the structure that will be filled in with the memory status +void GCToOSInterface::GetMemoryStatus(GCMemoryStatus* ms) +{ + 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 + ms->dwMemoryLoad = memStatus.dwMemoryLoad ; + ms->ullTotalPhys = memStatus.ullTotalPhys ; + ms->ullAvailPhys = memStatus.ullAvailPhys ; + ms->ullTotalPageFile = memStatus.ullTotalPageFile ; + ms->ullAvailPageFile = memStatus.ullAvailPageFile ; + ms->ullTotalVirtual = memStatus.ullTotalVirtual ; + ms->ullAvailVirtual = memStatus.ullAvailVirtual ; +} + +// Get a high precision performance counter +// Return: +// The counter value +int64_t GCToOSInterface::QueryPerformanceCounter() +{ + LARGE_INTEGER ts; + if (!::QueryPerformanceCounter(&ts)) + { + _ASSERTE(!"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() +{ + LARGE_INTEGER frequency; + if (!::QueryPerformanceFrequency(&frequency)) + { + _ASSERTE(!"Fatal Error - cannot query performance counter."); + abort(); + } + + return frequency.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; + stubParam->GCThreadFunction(stubParam->GCThreadParam); + + return 0; +} + +// 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 +bool GCToOSInterface::CreateThread(GCThreadFunction function, void* param, GCThreadAffinity* affinity) +{ + DWORD thread_id; + GCThreadStubParam stubParam; + + stubParam.GCThreadFunction = function; + stubParam.GCThreadParam = param; + + HANDLE gc_thread = ::CreateThread(NULL, 0, GCThreadStub, &stubParam, CREATE_SUSPENDED, &thread_id); + + if (!gc_thread) + { + return false; + } + + SetThreadPriority(gc_thread, /* THREAD_PRIORITY_ABOVE_NORMAL );*/ THREAD_PRIORITY_HIGHEST ); + + ResumeThread(gc_thread); + + CloseHandle(gc_thread); + + return true; +} + +// 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 +FILE* GCToOSInterface::OpenFile(const WCHAR* filename, const WCHAR* mode) +{ + return _wfopen(filename, mode); +} + +// 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); +} + +void DestroyThread(Thread * pThread) +{ + // TODO: implement +} diff --git a/src/pal/inc/pal.h b/src/pal/inc/pal.h index cec19c2..c139efc 100644 --- a/src/pal/inc/pal.h +++ b/src/pal/inc/pal.h @@ -3547,6 +3547,7 @@ SetErrorMode( #define MEM_RESERVE 0x2000 #define MEM_DECOMMIT 0x4000 #define MEM_RELEASE 0x8000 +#define MEM_RESET 0x80000 #define MEM_FREE 0x10000 #define MEM_PRIVATE 0x20000 #define MEM_MAPPED 0x40000 diff --git a/src/pal/src/exception/seh.cpp b/src/pal/src/exception/seh.cpp index 87bc677..7acb3dc 100644 --- a/src/pal/src/exception/seh.cpp +++ b/src/pal/src/exception/seh.cpp @@ -77,20 +77,16 @@ Return value : BOOL SEHInitialize (CPalThread *pthrCurrent, DWORD flags) { - BOOL bRet = FALSE; - #if !HAVE_MACH_EXCEPTIONS if (!SEHInitializeSignals()) { ERROR("SEHInitializeSignals failed!\n"); SEHCleanup(); - goto SEHInitializeExit; + return FALSE; } #endif - bRet = TRUE; -SEHInitializeExit: - return bRet; + return TRUE; } /*++ diff --git a/src/pal/src/misc/time.cpp b/src/pal/src/misc/time.cpp index 939c869..17fe037 100644 --- a/src/pal/src/misc/time.cpp +++ b/src/pal/src/misc/time.cpp @@ -202,6 +202,7 @@ QueryPerformanceCounter( PERF_ENTRY(QueryPerformanceCounter); ENTRY("QueryPerformanceCounter()\n"); + do #if HAVE_CLOCK_MONOTONIC { struct timespec ts; @@ -209,7 +210,7 @@ QueryPerformanceCounter( { ASSERT("clock_gettime(CLOCK_MONOTONIC) failed; errno is %d (%s)\n", errno, strerror(errno)); retval = FALSE; - goto EXIT; + break; } lpPerformanceCount->QuadPart = (LONGLONG)ts.tv_sec * (LONGLONG)tccSecondsToNanoSeconds + (LONGLONG)ts.tv_nsec; @@ -230,7 +231,7 @@ QueryPerformanceCounter( { ASSERT("time_base_to_time() failed; errno is %d (%s)\n", errno, strerror(errno)); retval = FALSE; - goto EXIT; + break; } lpPerformanceCount->QuadPart = (LONGLONG)tb.tb_high * (LONGLONG)tccSecondsToNanoSeconds + (LONGLONG)tb.tb_low; @@ -242,13 +243,14 @@ QueryPerformanceCounter( { ASSERT("gettimeofday() failed; errno is %d (%s)\n", errno, strerror(errno)); retval = FALSE; - goto EXIT; + break; } lpPerformanceCount->QuadPart = (LONGLONG)tv.tv_sec * (LONGLONG)tccSecondsToMicroSeconds + (LONGLONG)tv.tv_usec; } #endif // HAVE_CLOCK_MONOTONIC -EXIT: + while (false); + LOGEXIT("QueryPerformanceCounter\n"); PERF_EXIT(QueryPerformanceCounter); return retval; diff --git a/src/pal/src/thread/context.cpp b/src/pal/src/thread/context.cpp index ebd4383..dfb1c4b 100644 --- a/src/pal/src/thread/context.cpp +++ b/src/pal/src/thread/context.cpp @@ -220,7 +220,6 @@ BOOL CONTEXT_GetRegisters(DWORD processId, LPCONTEXT lpContext) bRet = TRUE; #if HAVE_BSD_REGS_T -EXIT : if (regFd != -1) { close(regFd); diff --git a/src/pal/tests/palsuite/eventprovider/CMakeLists.txt b/src/pal/tests/palsuite/eventprovider/CMakeLists.txt index 32b5959..41289f9 100644 --- a/src/pal/tests/palsuite/eventprovider/CMakeLists.txt +++ b/src/pal/tests/palsuite/eventprovider/CMakeLists.txt @@ -10,7 +10,6 @@ set(SOURCES include_directories(${COREPAL_SOURCE_DIR}/prebuilt/inc) include_directories(${COREPAL_SOURCE_DIR}/inc/rt) - add_executable(eventprovidertest ${SOURCES} ) @@ -18,6 +17,8 @@ set(EVENT_PROVIDER_DEPENDENCIES "") set(EVENT_PROVIDER_LINKER_OTPTIONS "") if(CMAKE_SYSTEM_NAME STREQUAL Linux) + add_definitions(-DFEATURE_EVENT_TRACE=1) + list(APPEND EVENT_PROVIDER_DEPENDENCIES eventprovider ) diff --git a/src/strongname/api/api.props b/src/strongname/api/api.props index 2c4c278..cba2811 100644 --- a/src/strongname/api/api.props +++ b/src/strongname/api/api.props @@ -7,7 +7,8 @@ $(Clrbase)\src\inc; $(Clrbase)\src\md\inc; $(Clrbase)\src\md\compiler; - $(Clrbase)\src\vm + $(Clrbase)\src\vm; + $(Clrbase)\src\gc\env diff --git a/src/strongname/api/common.h b/src/strongname/api/common.h index 45f14a8..ea315e4 100644 --- a/src/strongname/api/common.h +++ b/src/strongname/api/common.h @@ -270,6 +270,9 @@ namespace Loader #if STRONGNAME_IN_VM // src/vm +#include "gcenv.interlocked.h" +#include "gcenv.interlocked.inl" + #include "util.hpp" #include "ibclogger.h" #include "eepolicy.h" diff --git a/src/vm/CMakeLists.txt b/src/vm/CMakeLists.txt index e6238ed..964c987 100644 --- a/src/vm/CMakeLists.txt +++ b/src/vm/CMakeLists.txt @@ -195,7 +195,8 @@ set(VM_SOURCES_WKS finalizerthread.cpp frameworkexceptionloader.cpp gccover.cpp - gcenv.cpp + gcenv.ee.cpp + gcenv.os.cpp gchelpers.cpp genmeth.cpp ../gc/gceesvr.cpp diff --git a/src/vm/appdomain.cpp b/src/vm/appdomain.cpp index d89146d..c9f6588 100644 --- a/src/vm/appdomain.cpp +++ b/src/vm/appdomain.cpp @@ -14,7 +14,6 @@ #include "excep.h" #include "eeconfig.h" #include "gc.h" -#include "gcenv.h" #include "eventtrace.h" #ifdef FEATURE_FUSION #include "assemblysink.h" diff --git a/src/vm/common.h b/src/vm/common.h index e323333..2d23f8c 100644 --- a/src/vm/common.h +++ b/src/vm/common.h @@ -288,7 +288,6 @@ namespace Loader } LoadFlag; } - // src/inc #include "utilcode.h" #include "log.h" @@ -297,6 +296,9 @@ namespace Loader #include "lazycow.h" // src/vm +#include "gcenv.interlocked.h" +#include "gcenv.interlocked.inl" + #include "util.hpp" #include "ibclogger.h" #include "eepolicy.h" diff --git a/src/vm/crst.cpp b/src/vm/crst.cpp index 7266549..9ecdee7 100644 --- a/src/vm/crst.cpp +++ b/src/vm/crst.cpp @@ -653,9 +653,9 @@ void CrstBase::PostEnter() } _ASSERTE((m_entercount == 0 && m_holderthreadid.IsUnknown()) || - m_holderthreadid.IsSameThread() || + m_holderthreadid.IsCurrentThread() || IsAtProcessExit()); - m_holderthreadid.SetThreadId(); + m_holderthreadid.SetToCurrentThread(); m_entercount++; if (m_entercount == 1) @@ -715,7 +715,7 @@ void CrstBase::PreLeave() _ASSERTE(m_entercount > 0); m_entercount--; if (!m_entercount) { - m_holderthreadid.ResetThreadId(); + m_holderthreadid.Clear(); // Delink it from the Thread's chain of OwnedChain if (m_prev) @@ -796,7 +796,7 @@ void CrstBase::DebugInit(CrstType crstType, CrstFlags flags) m_crstType = crstType; m_tag = GetCrstName(crstType); m_crstlevel = GetCrstLevel(crstType); - m_holderthreadid.ResetThreadId(); + m_holderthreadid.Clear(); m_entercount = 0; m_next = NULL; m_prev = NULL; @@ -868,7 +868,7 @@ void CrstBase::DebugDestroy() } FillMemory(&m_criticalsection, sizeof(m_criticalsection), 0xcc); - m_holderthreadid.ResetThreadId(); + m_holderthreadid.Clear(); m_entercount = 0xcccccccc; m_next = (CrstBase*)POISONC; @@ -914,7 +914,7 @@ BOOL CrstBase::IsSafeToTake() (GCHeap::IsGCInProgress() && pThread == ThreadSuspend::GetSuspensionThread())); END_GETTHREAD_ALLOWED; - if (m_holderthreadid.IsSameThread()) + if (m_holderthreadid.IsCurrentThread()) { // If we already hold it, we can't violate level order. // Check if client wanted to allow reentrancy. @@ -949,7 +949,7 @@ BOOL CrstBase::IsSafeToTake() for (CrstBase *pcrst = GetThreadsOwnedCrsts(); pcrst != NULL; pcrst = pcrst->m_next) { fSafe = - !pcrst->m_holderthreadid.IsSameThread() + !pcrst->m_holderthreadid.IsCurrentThread() || (pcrst->m_crstlevel == CRSTUNORDERED) || (pcrst->m_crstlevel > m_crstlevel) || (pcrst->m_crstlevel == m_crstlevel && (m_dwFlags & CRST_UNSAFE_SAMELEVEL) != 0); diff --git a/src/vm/crst.h b/src/vm/crst.h index 010cb5f..730327e 100644 --- a/src/vm/crst.h +++ b/src/vm/crst.h @@ -261,7 +261,7 @@ public: #ifdef CROSSGEN_COMPILE return TRUE; #else - return m_holderthreadid.IsSameThread(); + return m_holderthreadid.IsCurrentThread(); #endif } diff --git a/src/vm/eehash.inl b/src/vm/eehash.inl index 6a09b29..9910b55 100644 --- a/src/vm/eehash.inl +++ b/src/vm/eehash.inl @@ -17,7 +17,7 @@ BOOL EEHashTableBase::OwnLock() return TRUE; if (m_pfnLockOwner == NULL) { - return m_writerThreadId.IsSameThread(); + return m_writerThreadId.IsCurrentThread(); } else { BOOL ret = m_pfnLockOwner(m_lockData); @@ -211,7 +211,7 @@ BOOL EEHashTableBase::Init(DWORD dwNumBucke } if (m_pfnLockOwner == NULL) { - m_writerThreadId.SetThreadId(); + m_writerThreadId.SetToCurrentThread(); } m_CheckThreadSafety = CheckThreadSafety; #endif diff --git a/src/vm/gcenv.cpp b/src/vm/gcenv.ee.cpp similarity index 97% rename from src/vm/gcenv.cpp rename to src/vm/gcenv.ee.cpp index 99880b5..ab1d66f 100644 --- a/src/vm/gcenv.cpp +++ b/src/vm/gcenv.ee.cpp @@ -4,7 +4,7 @@ // /* - * GCENV.CPP + * GCENV.EE.CPP * * GCToEEInterface implementation * @@ -36,7 +36,7 @@ void GCToEEInterface::SuspendEE(SUSPEND_REASON reason) ThreadSuspend::SuspendEE((ThreadSuspend::SUSPEND_REASON)reason); } -void GCToEEInterface::RestartEE(BOOL bFinishedGC) +void GCToEEInterface::RestartEE(bool bFinishedGC) { WRAPPER_NO_CONTRACT; @@ -428,7 +428,7 @@ StackWalkAction GcStackCrawlCallBack(CrawlFrame* pCF, VOID* pData) return SWA_CONTINUE; } -VOID GCToEEInterface::SyncBlockCacheWeakPtrScan(HANDLESCANPROC scanProc, LPARAM lp1, LPARAM lp2) +VOID GCToEEInterface::SyncBlockCacheWeakPtrScan(HANDLESCANPROC scanProc, uintptr_t lp1, uintptr_t lp2) { CONTRACTL { @@ -726,3 +726,21 @@ void GCToEEInterface::GcEnumAllocContexts(enum_alloc_context_func* fn, void* par fn(pThread->GetAllocContext(), param); } } + +bool GCToEEInterface::IsPreemptiveGCDisabled(Thread * pThread) +{ + WRAPPER_NO_CONTRACT; + return !!pThread->PreemptiveGCDisabled(); +} + +void GCToEEInterface::EnablePreemptiveGC(Thread * pThread) +{ + WRAPPER_NO_CONTRACT; + pThread->EnablePreemptiveGC(); +} + +void GCToEEInterface::DisablePreemptiveGC(Thread * pThread) +{ + WRAPPER_NO_CONTRACT; + pThread->DisablePreemptiveGC(); +} diff --git a/src/vm/gcenv.ee.h b/src/vm/gcenv.ee.h new file mode 100644 index 0000000..2baf24c --- /dev/null +++ b/src/vm/gcenv.ee.h @@ -0,0 +1,6 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "../gc/env/gcenv.ee.h" diff --git a/src/vm/gcenv.h b/src/vm/gcenv.h index 73e6585..7ddbe5e 100644 --- a/src/vm/gcenv.h +++ b/src/vm/gcenv.h @@ -45,96 +45,14 @@ #include #endif // FEATURE_UEF_CHAINMANAGER - -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, LPARAM lp1, LPARAM lp2); - static void SyncBlockCacheDemote(int max_gen); - static void SyncBlockCachePromotionsGranted(int max_gen); - - // Thread functions - static bool IsPreemptiveGCDisabled(Thread * pThread) - { - WRAPPER_NO_CONTRACT; - return !!pThread->PreemptiveGCDisabled(); - } - - static void EnablePreemptiveGC(Thread * pThread) - { - WRAPPER_NO_CONTRACT; - pThread->EnablePreemptiveGC(); - } - - static void DisablePreemptiveGC(Thread * pThread) - { - WRAPPER_NO_CONTRACT; - pThread->DisablePreemptiveGC(); - } - - 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); -}; - #define GCMemoryStatus MEMORYSTATUSEX -#define CLR_MUTEX_COOKIE MUTEX_COOKIE +#include "util.hpp" + +#include "gcenv.ee.h" +#include "gcenv.os.h" +#include "gcenv.interlocked.h" +#include "gcenv.interlocked.inl" namespace ETW { diff --git a/src/vm/gcenv.interlocked.h b/src/vm/gcenv.interlocked.h new file mode 100644 index 0000000..39c6ad3 --- /dev/null +++ b/src/vm/gcenv.interlocked.h @@ -0,0 +1,6 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "../gc/env/gcenv.interlocked.h" diff --git a/src/vm/gcenv.interlocked.inl b/src/vm/gcenv.interlocked.inl new file mode 100644 index 0000000..8d33416 --- /dev/null +++ b/src/vm/gcenv.interlocked.inl @@ -0,0 +1,6 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "../gc/env/gcenv.interlocked.inl" diff --git a/src/vm/gcenv.os.cpp b/src/vm/gcenv.os.cpp new file mode 100644 index 0000000..4fdd34e --- /dev/null +++ b/src/vm/gcenv.os.cpp @@ -0,0 +1,520 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +/* + * gcenv.os.cpp + * + * GCToOSInterface implementation + * + + * + */ + +#include "common.h" +#include "gcenv.h" + +// Initialize the interface implementation +// Return: +// true if it has succeeded, false if it has failed +bool GCToOSInterface::Initialize() +{ + LIMITED_METHOD_CONTRACT; + return true; +} + +// Shutdown the interface implementation +void GCToOSInterface::Shutdown() +{ + LIMITED_METHOD_CONTRACT; +} + +// 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 +uint32_t GCToOSInterface::GetCurrentThreadIdForLogging() +{ + LIMITED_METHOD_CONTRACT; + return ::GetCurrentThreadId(); +} + +// Get id of the process +// Return: +// Id of the current process +uint32_t GCToOSInterface::GetCurrentProcessId() +{ + LIMITED_METHOD_CONTRACT; + return ::GetCurrentProcessId(); +} + +// Set ideal affinity for the current thread +// Parameters: +// affinity - ideal processor affinity for the thread +// Return: +// true if it has succeeded, false if it has failed +bool GCToOSInterface::SetCurrentThreadIdealAffinity(GCThreadAffinity* affinity) +{ + LIMITED_METHOD_CONTRACT; + + bool success = true; + +#if !defined(FEATURE_CORESYSTEM) + SetThreadIdealProcessor(GetCurrentThread(), (DWORD)affinity->Processor); +#elif !defined(FEATURE_PAL) + PROCESSOR_NUMBER proc; + + if (affinity->Group != -1) + { + proc.Group = (WORD)affinity->Group; + proc.Number = (BYTE)affinity->Processor; + proc.Reserved = 0; + + success = !!SetThreadIdealProcessorEx(GetCurrentThread(), &proc, NULL); + } + else + { + if (GetThreadIdealProcessorEx(GetCurrentThread(), &proc)) + { + proc.Number = affinity->Processor; + success = !!SetThreadIdealProcessorEx(GetCurrentThread(), &proc, NULL); + } + } +#endif + + return success; +} + +// Get the number of the current processor +uint32_t GCToOSInterface::GetCurrentProcessorNumber() +{ + LIMITED_METHOD_CONTRACT; + + _ASSERTE(CanGetCurrentProcessorNumber()); + return ::GetCurrentProcessorNumber(); +} + +// Check if the OS supports getting current processor number +bool GCToOSInterface::CanGetCurrentProcessorNumber() +{ + LIMITED_METHOD_CONTRACT; + +#ifdef FEATURE_PAL + return PAL_HasGetCurrentProcessorNumber(); +#else + // on all Windows platforms we support this API exists + return true; +#endif +} + +// Flush write buffers of processors that are executing threads of the current process +void GCToOSInterface::FlushProcessWriteBuffers() +{ + LIMITED_METHOD_CONTRACT; + ::FlushProcessWriteBuffers(); +} + +// Break into a debugger +void GCToOSInterface::DebugBreak() +{ + LIMITED_METHOD_CONTRACT; + ::DebugBreak(); +} + +// Get number of logical processors +uint32_t GCToOSInterface::GetLogicalCpuCount() +{ + LIMITED_METHOD_CONTRACT; + return ::GetLogicalCpuCount(); +} + +// 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) +{ + LIMITED_METHOD_CONTRACT; + __SwitchToThread(sleepMSec, 0); +} + +// 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) +{ + LIMITED_METHOD_CONTRACT; + __SwitchToThread(0, switchCount); +} + +// 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(void* address, size_t size, size_t alignment, uint32_t flags) +{ + LIMITED_METHOD_CONTRACT; + + DWORD memFlags = (flags & VirtualReserveFlags::WriteWatch) ? (MEM_RESERVE | MEM_WRITE_WATCH) : MEM_RESERVE; + if (alignment == 0) + { + return ::ClrVirtualAlloc(0, size, memFlags, PAGE_READWRITE); + } + else + { + return ::ClrVirtualAllocAligned(0, size, memFlags, PAGE_READWRITE, alignment); + } +} + +// 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) +{ + LIMITED_METHOD_CONTRACT; + + UNREFERENCED_PARAMETER(size); + return !!::ClrVirtualFree(address, 0, MEM_RELEASE); +} + +// 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) +{ + LIMITED_METHOD_CONTRACT; + + return ::ClrVirtualAlloc(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) +{ + LIMITED_METHOD_CONTRACT; + + return !!::ClrVirtualFree(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) +{ + LIMITED_METHOD_CONTRACT; + + bool success = ::ClrVirtualAlloc(address, size, MEM_RESET, PAGE_READWRITE) != NULL; +#ifndef FEATURE_PAL + if (success && unlock) + { + // Remove the page range from the working set + ::VirtualUnlock(address, size); + } +#endif // FEATURE_PAL + + return success; +} + +// Check if the OS supports write watching +bool GCToOSInterface::SupportsWriteWatch() +{ + LIMITED_METHOD_CONTRACT; + + bool writeWatchSupported = false; + + // check if the OS supports write-watch. + // Drawbridge does not support write-watch so we still need to do the runtime detection for them. + // Otherwise, all currently supported OSes do support write-watch. + void* mem = VirtualReserve (0, g_SystemInfo.dwAllocationGranularity, 0, VirtualReserveFlags::WriteWatch); + if (mem != NULL) + { + VirtualRelease (mem, g_SystemInfo.dwAllocationGranularity); + writeWatchSupported = true; + } + + return writeWatchSupported; +} + +// 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) +{ + LIMITED_METHOD_CONTRACT; + + ::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) +{ + LIMITED_METHOD_CONTRACT; + + 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::GetLargestOnDieCacheSize(bool trueSize) +{ + LIMITED_METHOD_CONTRACT; + + return ::GetLargestOnDieCacheSize(trueSize); +} + +// 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. +bool GCToOSInterface::GetCurrentProcessAffinityMask(uintptr_t* processMask, uintptr_t* systemMask) +{ + LIMITED_METHOD_CONTRACT; + +#ifndef FEATURE_CORECLR + return !!::GetProcessAffinityMask(GetCurrentProcess(), (PDWORD_PTR)processMask, (PDWORD_PTR)systemMask); +#else + return false; +#endif +} + +// Get number of processors assigned to the current process +// Return: +// The number of processors +uint32_t GCToOSInterface::GetCurrentProcessCpuCount() +{ + LIMITED_METHOD_CONTRACT; + + return ::GetCurrentProcessCpuCount(); +} + +// Get global memory status +// Parameters: +// ms - pointer to the structure that will be filled in with the memory status +void GCToOSInterface::GetMemoryStatus(GCMemoryStatus* ms) +{ + LIMITED_METHOD_CONTRACT; + + MEMORYSTATUSEX msEx; + msEx.dwLength = sizeof(MEMORYSTATUSEX); + + ::GetProcessMemoryLoad(&msEx); + + // Convert Windows struct to abstract struct + ms->dwMemoryLoad = msEx.dwMemoryLoad; + ms->ullTotalPhys = msEx.ullTotalPhys; + ms->ullAvailPhys = msEx.ullAvailPhys; + ms->ullTotalPageFile = msEx.ullTotalPageFile; + ms->ullAvailPageFile = msEx.ullAvailPageFile; + ms->ullTotalVirtual = msEx.ullTotalVirtual; + ms->ullAvailVirtual = msEx.ullAvailVirtual; +} + +// Get a high precision performance counter +// Return: +// The counter value +int64_t GCToOSInterface::QueryPerformanceCounter() +{ + LIMITED_METHOD_CONTRACT; + + LARGE_INTEGER ts; + if (!::QueryPerformanceCounter(&ts)) + { + DebugBreak(); + _ASSERTE(!"Fatal Error - cannot query performance counter."); + EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE); // TODO: fatal error + } + + return ts.QuadPart; +} + +// Get a frequency of the high precision performance counter +// Return: +// The counter frequency +int64_t GCToOSInterface::QueryPerformanceFrequency() +{ + LIMITED_METHOD_CONTRACT; + + LARGE_INTEGER frequency; + if (!::QueryPerformanceFrequency(&frequency)) + { + DebugBreak(); + _ASSERTE(!"Fatal Error - cannot query performance counter."); + EEPOLICY_HANDLE_FATAL_ERROR(COR_E_EXECUTIONENGINE); // TODO: fatal error + } + + return frequency.QuadPart; +} + +// Get a time stamp with a low precision +// Return: +// Time stamp in milliseconds +uint32_t GCToOSInterface::GetLowPrecisionTimeStamp() +{ + LIMITED_METHOD_CONTRACT; + + 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) +{ + WRAPPER_NO_CONTRACT; + + GCThreadStubParam *stubParam = (GCThreadStubParam*)param; + GCThreadFunction function = stubParam->GCThreadFunction; + void* threadParam = stubParam->GCThreadParam; + + delete stubParam; + + function(threadParam); + + return 0; +} + +// 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 +bool GCToOSInterface::CreateThread(GCThreadFunction function, void* param, GCThreadAffinity* affinity) +{ + LIMITED_METHOD_CONTRACT; + + uint32_t thread_id; + + GCThreadStubParam* stubParam = new (nothrow) GCThreadStubParam(); + stubParam->GCThreadFunction = function; + stubParam->GCThreadParam = param; + + HANDLE gc_thread = Thread::CreateUtilityThread(Thread::StackSize_Medium, GCThreadStub, stubParam, CREATE_SUSPENDED, (DWORD*)&thread_id); + + if (!gc_thread) + { + return false; + } + + SetThreadPriority(gc_thread, /* THREAD_PRIORITY_ABOVE_NORMAL );*/ THREAD_PRIORITY_HIGHEST ); + +#ifndef FEATURE_CORECLR + if (affinity->Group != -1) + { + _ASSERTE(affinity->Processor != -1); + GROUP_AFFINITY ga; + ga.Group = (WORD)affinity->Group; + ga.Reserved[0] = 0; // reserve must be filled with zero + ga.Reserved[1] = 0; // otherwise call may fail + ga.Reserved[2] = 0; + ga.Mask = 1 << affinity->Processor; + + CPUGroupInfo::SetThreadGroupAffinity(gc_thread, &ga, NULL); + } + else if (affinity->Processor != -1) + { + SetThreadAffinityMask(gc_thread, 1 << affinity->Processor); + } +#endif // !FEATURE_CORECLR + + ResumeThread(gc_thread); + CloseHandle(gc_thread); + + return true; +} + +// 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 +FILE* GCToOSInterface::OpenFile(const WCHAR* filename, const WCHAR* mode) +{ + LIMITED_METHOD_CONTRACT; + + return _wfopen(filename, mode); +} + +// Initialize the critical section +void CLRCriticalSection::Initialize() +{ + WRAPPER_NO_CONTRACT; + UnsafeInitializeCriticalSection(&m_cs); +} + +// Destroy the critical section +void CLRCriticalSection::Destroy() +{ + WRAPPER_NO_CONTRACT; + UnsafeDeleteCriticalSection(&m_cs); +} + +// Enter the critical section. Blocks until the section can be entered. +void CLRCriticalSection::Enter() +{ + WRAPPER_NO_CONTRACT; + UnsafeEnterCriticalSection(&m_cs); +} + +// Leave the critical section +void CLRCriticalSection::Leave() +{ + WRAPPER_NO_CONTRACT; + UnsafeLeaveCriticalSection(&m_cs); +} + diff --git a/src/vm/gcenv.os.h b/src/vm/gcenv.os.h new file mode 100644 index 0000000..b6897ae --- /dev/null +++ b/src/vm/gcenv.os.h @@ -0,0 +1,6 @@ +// +// Copyright (c) Microsoft. All rights reserved. +// Licensed under the MIT license. See LICENSE file in the project root for full license information. +// + +#include "../gc/env/gcenv.os.h" diff --git a/src/vm/hash.cpp b/src/vm/hash.cpp index 8a0ab28..8e8408c 100644 --- a/src/vm/hash.cpp +++ b/src/vm/hash.cpp @@ -298,7 +298,7 @@ void HashMap::Init(DWORD cbInitialSize, Compare* pCompare, BOOL fAsyncMode, Lock m_pfnLockOwner = pLock->lockOwnerFunc; } if (m_pfnLockOwner == NULL) { - m_writerThreadId.SetThreadId(); + m_writerThreadId.SetToCurrentThread(); } #endif // _DEBUG } @@ -1079,7 +1079,7 @@ BOOL HashMap::OwnLock() DEBUG_ONLY_FUNCTION; if (m_pfnLockOwner == NULL) { - return m_writerThreadId.IsSameThread(); + return m_writerThreadId.IsCurrentThread(); } else { BOOL ret = m_pfnLockOwner(m_lockData); diff --git a/src/vm/spinlock.cpp b/src/vm/spinlock.cpp index 2360d5c..68b9150 100644 --- a/src/vm/spinlock.cpp +++ b/src/vm/spinlock.cpp @@ -160,7 +160,7 @@ BOOL SpinLock::OwnedByCurrentThread() } CONTRACTL_END; - return m_holdingThreadId.IsSameThread(); + return m_holdingThreadId.IsCurrentThread(); } #endif @@ -222,7 +222,7 @@ void SpinLock::GetLock(Thread* pThread) INCTHREADLOCKCOUNTTHREAD(pThread); #ifdef _DEBUG - m_holdingThreadId.SetThreadId(); + m_holdingThreadId.SetToCurrentThread(); dbg_EnterLock(); #endif } @@ -289,7 +289,7 @@ void SpinLock::FreeLock(Thread* pThread) #ifdef _DEBUG _ASSERTE(OwnedByCurrentThread()); - m_holdingThreadId.ResetThreadId(); + m_holdingThreadId.Clear(); dbg_LeaveLock(); #endif diff --git a/src/vm/syncblk.cpp b/src/vm/syncblk.cpp index 7163658..9e8dec4 100644 --- a/src/vm/syncblk.cpp +++ b/src/vm/syncblk.cpp @@ -1348,7 +1348,7 @@ void SyncBlockCache::GCDeleteSyncBlock(SyncBlock *psb) m_FreeBlockList = &psb->m_Link; } -void SyncBlockCache::GCWeakPtrScan(HANDLESCANPROC scanProc, LPARAM lp1, LPARAM lp2) +void SyncBlockCache::GCWeakPtrScan(HANDLESCANPROC scanProc, uintptr_t lp1, uintptr_t lp2) { CONTRACTL { diff --git a/src/vm/syncblk.h b/src/vm/syncblk.h index ad527b9..60f0fa2 100644 --- a/src/vm/syncblk.h +++ b/src/vm/syncblk.h @@ -1008,7 +1008,7 @@ class SyncBlockCache // return sync block to cache or delete, called from GC void GCDeleteSyncBlock(SyncBlock *sb); - void GCWeakPtrScan(HANDLESCANPROC scanProc, LPARAM lp1, LPARAM lp2); + void GCWeakPtrScan(HANDLESCANPROC scanProc, uintptr_t lp1, uintptr_t lp2); void GCDone(BOOL demoting, int max_gen); diff --git a/src/vm/threads.cpp b/src/vm/threads.cpp index a614ddb..22e3b88 100644 --- a/src/vm/threads.cpp +++ b/src/vm/threads.cpp @@ -680,8 +680,8 @@ DWORD Thread::StartThread() DWORD dwRetVal = (DWORD) -1; #ifdef _DEBUG - _ASSERTE (m_Creater.IsSameThread()); - m_Creater.ResetThreadId(); + _ASSERTE (m_Creater.IsCurrentThread()); + m_Creater.Clear(); #endif #ifdef FEATURE_INCLUDE_ALL_INTERFACES HostComHolder pHostTask(GetHostTaskWithAddRef()); @@ -1922,7 +1922,7 @@ Thread::Thread() #ifdef _DEBUG dbg_m_cSuspendedThreads = 0; dbg_m_cSuspendedThreadsWithoutOSLock = 0; - m_Creater.ResetThreadId(); + m_Creater.Clear(); m_dwUnbreakableLockCount = 0; #endif @@ -3132,7 +3132,7 @@ BOOL Thread::CreateNewOSThread(SIZE_T sizeToCommitOrReserve, LPTHREAD_START_ROUT FastInterlockIncrement(&ThreadStore::s_pThreadStore->m_PendingThreadCount); #ifdef _DEBUG - m_Creater.SetThreadId(); + m_Creater.SetToCurrentThread(); #endif return TRUE; @@ -3188,7 +3188,7 @@ BOOL Thread::CreateNewHostTask(SIZE_T stackSize, LPTHREAD_START_ROUTINE start, v FastInterlockIncrement(&ThreadStore::s_pThreadStore->m_PendingThreadCount); #ifdef _DEBUG - m_Creater.SetThreadId(); + m_Creater.SetToCurrentThread(); #endif return TRUE; @@ -11202,7 +11202,7 @@ BOOL ThreadStore::HoldingThreadStore(Thread *pThread) } else { - return (s_pThreadStore->m_holderthreadid.IsSameThread()); + return (s_pThreadStore->m_holderthreadid.IsCurrentThread()); } } diff --git a/src/vm/threadsuspend.cpp b/src/vm/threadsuspend.cpp index 0d823dd..705ae83 100644 --- a/src/vm/threadsuspend.cpp +++ b/src/vm/threadsuspend.cpp @@ -480,7 +480,7 @@ DWORD Thread::ResumeThread() DWORD res = ::ResumeThread(m_ThreadHandleForResume); _ASSERTE (res != 0 && "Thread is not previously suspended"); #ifdef _DEBUG_IMPL - _ASSERTE (!m_Creater.IsSameThread()); + _ASSERTE (!m_Creater.IsCurrentThread()); if ((res != (DWORD)-1) && (res != 0)) { Thread * pCurThread = GetThread(); @@ -3102,7 +3102,7 @@ void ThreadSuspend::LockThreadStore(ThreadSuspend::SUSPEND_REASON reason) _ASSERTE(ThreadStore::s_pThreadStore->m_holderthreadid.IsUnknown()); - ThreadStore::s_pThreadStore->m_holderthreadid.SetThreadId(); + ThreadStore::s_pThreadStore->m_holderthreadid.SetToCurrentThread(); LOG((LF_SYNC, INFO3, "Locked thread store\n")); @@ -3147,12 +3147,12 @@ void ThreadSuspend::UnlockThreadStore(BOOL bThreadDestroyed, ThreadSuspend::SUSP // If Thread object has been destroyed, we need to reset the ownership info in Crst. _ASSERTE(!bThreadDestroyed || GetThread() == NULL); if (bThreadDestroyed) { - ThreadStore::s_pThreadStore->m_Crst.m_holderthreadid.SetThreadId(); + ThreadStore::s_pThreadStore->m_Crst.m_holderthreadid.SetToCurrentThread(); } #endif ThreadStore::s_pThreadStore->m_HoldingThread = NULL; - ThreadStore::s_pThreadStore->m_holderthreadid.ResetThreadId(); + ThreadStore::s_pThreadStore->m_holderthreadid.Clear(); ThreadStore::s_pThreadStore->Leave(); Thread::EndThreadAffinity(); diff --git a/src/vm/util.hpp b/src/vm/util.hpp index b444357..62508bc 100644 --- a/src/vm/util.hpp +++ b/src/vm/util.hpp @@ -652,14 +652,14 @@ public: } #endif - void SetThreadId() + void SetToCurrentThread() { WRAPPER_NO_CONTRACT; m_FiberPtrId = ClrTeb::GetFiberPtrId(); } - BOOL IsSameThread() const + bool IsCurrentThread() const { WRAPPER_NO_CONTRACT; @@ -668,13 +668,13 @@ public: #ifdef _DEBUG - BOOL IsUnknown() const + bool IsUnknown() const { LIMITED_METHOD_CONTRACT; return m_FiberPtrId == NULL; } #endif - void ResetThreadId() + void Clear() { LIMITED_METHOD_CONTRACT; m_FiberPtrId = NULL; diff --git a/src/vm/wks/wks.targets b/src/vm/wks/wks.targets index 5f2770b..5e5f18b 100644 --- a/src/vm/wks/wks.targets +++ b/src/vm/wks/wks.targets @@ -103,7 +103,8 @@ - + + -- 2.7.4