1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 // Interface between GC and the OS specific functionality
10 // Critical section used by the GC
11 class CLRCriticalSection
13 CRITICAL_SECTION m_cs;
16 // Initialize the critical section
19 // Destroy the critical section
22 // Enter the critical section. Blocks until the section can be entered.
25 // Leave the critical section
29 // Flags for the GCToOSInterface::VirtualReserve method
30 struct VirtualReserveFlags
39 // Affinity of a GC thread
40 struct GCThreadAffinity
42 static const int None = -1;
44 // Processor group index, None if no group is specified
46 // Processor index, None if no affinity is specified
50 // An event is a synchronization object whose state can be set and reset
51 // indicating that an event has occured. It is used pervasively throughout
54 // Note that GCEvent deliberately leaks its contents by not having a non-trivial destructor.
55 // This is by design; since all uses of GCEvent have static lifetime, their destructors
56 // are run on process exit, potentially concurrently with other threads that may still be
57 // operating on the static event. To avoid these sorts of unsafety, GCEvent chooses to
58 // not have a destructor at all. The cost of this is leaking a small amount of memory, but
59 // this is not a problem since a majority of the uses of GCEvent are static. See CoreCLR#11111
60 // for more details on the hazards of static destructors.
67 // Constructs a new uninitialized event.
70 // Closes the event. Attempting to use the event past calling CloseEvent
74 // "Sets" the event, indicating that a particular event has occured. May
75 // wake up other threads waiting on this event. Depending on whether or
76 // not this event is an auto-reset event, the state of the event may
77 // or may not be automatically reset after Set is called.
80 // Resets the event, resetting it back to a non-signalled state. Auto-reset
81 // events automatically reset once the event is set, while manual-reset
82 // events do not reset until Reset is called. It is a no-op to call Reset
83 // on an auto-reset event.
86 // Waits for some period of time for this event to be signalled. The
87 // period of time may be infinite (if the timeout argument is INFINITE) or
88 // it may be a specified period of time, in milliseconds.
90 // One of three values, depending on how why this thread was awoken:
91 // WAIT_OBJECT_0 - This event was signalled and woke up this thread.
92 // WAIT_TIMEOUT - The timeout interval expired without this event being signalled.
93 // WAIT_FAILED - The wait failed.
94 uint32_t Wait(uint32_t timeout, bool alertable);
96 // Determines whether or not this event is valid.
98 // true if this event is invalid (i.e. it has not yet been initialized or
99 // has already been closed), false otherwise
102 return m_impl != nullptr;
105 // Initializes this event to be a host-aware manual reset event with the
106 // given initial state.
108 // true if the initialization succeeded, false if it did not
109 bool CreateManualEventNoThrow(bool initialState);
111 // Initializes this event to be a host-aware auto-resetting event with the
112 // given initial state.
114 // true if the initialization succeeded, false if it did not
115 bool CreateAutoEventNoThrow(bool initialState);
117 // Initializes this event to be a host-unaware manual reset event with the
118 // given initial state.
120 // true if the initialization succeeded, false if it did not
121 bool CreateOSManualEventNoThrow(bool initialState);
123 // Initializes this event to be a host-unaware auto-resetting event with the
124 // given initial state.
126 // true if the initialization succeeded, false if it did not
127 bool CreateOSAutoEventNoThrow(bool initialState);
130 // GC thread function prototype
131 typedef void (*GCThreadFunction)(void* param);
133 // Interface that the GC uses to invoke OS specific functionality
134 class GCToOSInterface
139 // Initialization and shutdown of the interface
142 // Initialize the interface implementation
144 // true if it has succeeded, false if it has failed
145 static bool Initialize();
147 // Shutdown the interface implementation
148 static void Shutdown();
151 // Virtual memory management
154 // Reserve virtual memory range.
156 // size - size of the virtual memory range
157 // alignment - requested memory alignment
158 // flags - flags to control special settings like write watching
160 // Starting virtual address of the reserved range
161 static void* VirtualReserve(size_t size, size_t alignment, uint32_t flags);
163 // Release virtual memory range previously reserved using VirtualReserve
165 // address - starting virtual address
166 // size - size of the virtual memory range
168 // true if it has succeeded, false if it has failed
169 static bool VirtualRelease(void *address, size_t size);
171 // Commit virtual memory range. It must be part of a range reserved using VirtualReserve.
173 // address - starting virtual address
174 // size - size of the virtual memory range
176 // true if it has succeeded, false if it has failed
177 static bool VirtualCommit(void *address, size_t size);
179 // Decomit virtual memory range.
181 // address - starting virtual address
182 // size - size of the virtual memory range
184 // true if it has succeeded, false if it has failed
185 static bool VirtualDecommit(void *address, size_t size);
187 // Reset virtual memory range. Indicates that data in the memory range specified by address and size is no
188 // longer of interest, but it should not be decommitted.
190 // address - starting virtual address
191 // size - size of the virtual memory range
192 // unlock - true if the memory range should also be unlocked
194 // true if it has succeeded, false if it has failed
195 static bool VirtualReset(void *address, size_t size, bool unlock);
201 // Check if the OS supports write watching
202 static bool SupportsWriteWatch();
204 // Reset the write tracking state for the specified virtual memory range.
206 // address - starting virtual address
207 // size - size of the virtual memory range
208 static void ResetWriteWatch(void *address, size_t size);
210 // Retrieve addresses of the pages that are written to in a region of virtual memory
212 // resetState - true indicates to reset the write tracking state
213 // address - starting virtual address
214 // size - size of the virtual memory range
215 // pageAddresses - buffer that receives an array of page addresses in the memory region
216 // pageAddressesCount - on input, size of the lpAddresses array, in array elements
217 // on output, the number of page addresses that are returned in the array.
219 // true if it has succeeded, false if it has failed
220 static bool GetWriteWatch(bool resetState, void* address, size_t size, void** pageAddresses, uintptr_t* pageAddressesCount);
223 // Thread and process
226 // Create a new thread
228 // function - the function to be executed by the thread
229 // param - parameters of the thread
230 // affinity - processor affinity of the thread
232 // true if it has succeeded, false if it has failed
233 static bool CreateThread(GCThreadFunction function, void* param, GCThreadAffinity* affinity);
235 // Causes the calling thread to sleep for the specified number of milliseconds
237 // sleepMSec - time to sleep before switching to another thread
238 static void Sleep(uint32_t sleepMSec);
240 // Causes the calling thread to yield execution to another thread that is ready to run on the current processor.
242 // switchCount - number of times the YieldThread was called in a loop
243 static void YieldThread(uint32_t switchCount);
245 // Get the number of the current processor
246 static uint32_t GetCurrentProcessorNumber();
248 // Check if the OS supports getting current processor number
249 static bool CanGetCurrentProcessorNumber();
251 // Set ideal processor for the current thread
253 // processorIndex - index of the processor in the group
254 // affinity - ideal processor affinity for the thread
256 // true if it has succeeded, false if it has failed
257 static bool SetCurrentThreadIdealAffinity(GCThreadAffinity* affinity);
259 // Get numeric id of the current thread if possible on the
260 // current platform. It is indended for logging purposes only.
262 // Numeric id of the current thread or 0 if the
263 static uint64_t GetCurrentThreadIdForLogging();
265 // Get id of the current process
267 // Id of the current process
268 static uint32_t GetCurrentProcessId();
271 // Processor topology
274 // Get number of logical processors
275 static uint32_t GetLogicalCpuCount();
277 // Get size of the largest cache on the processor die
279 // trueSize - true to return true cache size, false to return scaled up size based on
280 // the processor architecture
283 static size_t GetLargestOnDieCacheSize(bool trueSize = true);
285 // Get number of processors assigned to the current process
287 // The number of processors
288 static uint32_t GetCurrentProcessCpuCount();
290 // Get affinity mask of the current process
292 // processMask - affinity mask for the specified process
293 // systemMask - affinity mask for the system
295 // true if it has succeeded, false if it has failed
297 // A process affinity mask is a bit vector in which each bit represents the processors that
298 // a process is allowed to run on. A system affinity mask is a bit vector in which each bit
299 // represents the processors that are configured into a system.
300 // A process affinity mask is a subset of the system affinity mask. A process is only allowed
301 // to run on the processors configured into a system. Therefore, the process affinity mask cannot
302 // specify a 1 bit for a processor when the system affinity mask specifies a 0 bit for that processor.
303 static bool GetCurrentProcessAffinityMask(uintptr_t *processMask, uintptr_t *systemMask);
306 // Global memory info
309 // Return the size of the user-mode portion of the virtual address space of this process.
311 // non zero if it has succeeded, 0 if it has failed
312 static size_t GetVirtualMemoryLimit();
314 // Get the physical memory that this process can use.
316 // non zero if it has succeeded, 0 if it has failed
318 // If a process runs with a restricted memory limit, it returns the limit. If there's no limit
319 // specified, it returns amount of actual physical memory.
320 static uint64_t GetPhysicalMemoryLimit();
324 // memory_load - A number between 0 and 100 that specifies the approximate percentage of physical memory
325 // that is in use (0 indicates no memory use and 100 indicates full memory use).
326 // available_physical - The amount of physical memory currently available, in bytes.
327 // available_page_file - The maximum amount of memory the current process can commit, in bytes.
329 // Any parameter can be null.
330 static void GetMemoryStatus(uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file);
336 // Flush write buffers of processors that are executing threads of the current process
337 static void FlushProcessWriteBuffers();
339 // Break into a debugger
340 static void DebugBreak();
346 // Get a high precision performance counter
349 static int64_t QueryPerformanceCounter();
351 // Get a frequency of the high precision performance counter
353 // The counter frequency
354 static int64_t QueryPerformanceFrequency();
356 // Get a time stamp with a low precision
358 // Time stamp in milliseconds
359 static uint32_t GetLowPrecisionTimeStamp();
362 #endif // __GCENV_OS_H__