Remove destructor from GCEvent and instead rely on the OS to clean up (#11132)
[platform/upstream/coreclr.git] / src / gc / env / gcenv.os.h
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
5 //
6
7 #ifndef __GCENV_OS_H__
8 #define __GCENV_OS_H__
9
10 // Critical section used by the GC
11 class CLRCriticalSection
12 {
13     CRITICAL_SECTION m_cs;
14
15 public:
16     // Initialize the critical section
17     void Initialize();
18
19     // Destroy the critical section
20     void Destroy();
21
22     // Enter the critical section. Blocks until the section can be entered.
23     void Enter();
24
25     // Leave the critical section
26     void Leave();
27 };
28
29 // Flags for the GCToOSInterface::VirtualReserve method
30 struct VirtualReserveFlags
31 {
32     enum
33     {
34         None = 0,
35         WriteWatch = 1,
36     };
37 };
38
39 // Affinity of a GC thread
40 struct GCThreadAffinity
41 {
42     static const int None = -1;
43
44     // Processor group index, None if no group is specified
45     int Group;
46     // Processor index, None if no affinity is specified
47     int Processor;
48 };
49
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
52 // the GC.
53 //
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.
61 class GCEvent {
62 private:
63     class Impl;
64     Impl *m_impl;
65
66 public:
67     // Constructs a new uninitialized event.
68     GCEvent();
69
70     // Closes the event. Attempting to use the event past calling CloseEvent
71     // is a logic error.
72     void CloseEvent();
73
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.
78     void Set();
79
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.
84     void Reset();
85
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.
89     // Returns:
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);
95
96     // Determines whether or not this event is valid.
97     // Returns:
98     //  true if this event is invalid (i.e. it has not yet been initialized or
99     //  has already been closed), false otherwise
100     bool IsValid() const
101     {
102         return m_impl != nullptr;
103     }
104
105     // Initializes this event to be a host-aware manual reset event with the
106     // given initial state.
107     // Returns:
108     //   true if the initialization succeeded, false if it did not
109     bool CreateManualEventNoThrow(bool initialState);
110
111     // Initializes this event to be a host-aware auto-resetting event with the
112     // given initial state.
113     // Returns:
114     //   true if the initialization succeeded, false if it did not
115     bool CreateAutoEventNoThrow(bool initialState);
116
117     // Initializes this event to be a host-unaware manual reset event with the
118     // given initial state.
119     // Returns:
120     //   true if the initialization succeeded, false if it did not
121     bool CreateOSManualEventNoThrow(bool initialState);
122
123     // Initializes this event to be a host-unaware auto-resetting event with the
124     // given initial state.
125     // Returns:
126     //   true if the initialization succeeded, false if it did not
127     bool CreateOSAutoEventNoThrow(bool initialState);
128 };
129
130 // GC thread function prototype
131 typedef void (*GCThreadFunction)(void* param);
132
133 // Interface that the GC uses to invoke OS specific functionality
134 class GCToOSInterface
135 {
136 public:
137
138     //
139     // Initialization and shutdown of the interface
140     //
141
142     // Initialize the interface implementation
143     // Return:
144     //  true if it has succeeded, false if it has failed
145     static bool Initialize();
146
147     // Shutdown the interface implementation
148     static void Shutdown();
149
150     //
151     // Virtual memory management
152     //
153
154     // Reserve virtual memory range.
155     // Parameters:
156     //  size      - size of the virtual memory range
157     //  alignment - requested memory alignment
158     //  flags     - flags to control special settings like write watching
159     // Return:
160     //  Starting virtual address of the reserved range
161     static void* VirtualReserve(size_t size, size_t alignment, uint32_t flags);
162
163     // Release virtual memory range previously reserved using VirtualReserve
164     // Parameters:
165     //  address - starting virtual address
166     //  size    - size of the virtual memory range
167     // Return:
168     //  true if it has succeeded, false if it has failed
169     static bool VirtualRelease(void *address, size_t size);
170
171     // Commit virtual memory range. It must be part of a range reserved using VirtualReserve.
172     // Parameters:
173     //  address - starting virtual address
174     //  size    - size of the virtual memory range
175     // Return:
176     //  true if it has succeeded, false if it has failed
177     static bool VirtualCommit(void *address, size_t size);
178
179     // Decomit virtual memory range.
180     // Parameters:
181     //  address - starting virtual address
182     //  size    - size of the virtual memory range
183     // Return:
184     //  true if it has succeeded, false if it has failed
185     static bool VirtualDecommit(void *address, size_t size);
186
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.
189     // Parameters:
190     //  address - starting virtual address
191     //  size    - size of the virtual memory range
192     //  unlock  - true if the memory range should also be unlocked
193     // Return:
194     //  true if it has succeeded, false if it has failed
195     static bool VirtualReset(void *address, size_t size, bool unlock);
196
197     //
198     // Write watching
199     //
200
201     // Check if the OS supports write watching
202     static bool SupportsWriteWatch();
203
204     // Reset the write tracking state for the specified virtual memory range.
205     // Parameters:
206     //  address - starting virtual address
207     //  size    - size of the virtual memory range
208     static void ResetWriteWatch(void *address, size_t size);
209
210     // Retrieve addresses of the pages that are written to in a region of virtual memory
211     // Parameters:
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.
218     // Return:
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);
221
222     //
223     // Thread and process
224     //
225
226     // Create a new thread
227     // Parameters:
228     //  function - the function to be executed by the thread
229     //  param    - parameters of the thread
230     //  affinity - processor affinity of the thread
231     // Return:
232     //  true if it has succeeded, false if it has failed
233     static bool CreateThread(GCThreadFunction function, void* param, GCThreadAffinity* affinity);
234
235     // Causes the calling thread to sleep for the specified number of milliseconds
236     // Parameters:
237     //  sleepMSec   - time to sleep before switching to another thread
238     static void Sleep(uint32_t sleepMSec);
239
240     // Causes the calling thread to yield execution to another thread that is ready to run on the current processor.
241     // Parameters:
242     //  switchCount - number of times the YieldThread was called in a loop
243     static void YieldThread(uint32_t switchCount);
244
245     // Get the number of the current processor
246     static uint32_t GetCurrentProcessorNumber();
247
248     // Check if the OS supports getting current processor number
249     static bool CanGetCurrentProcessorNumber();
250
251     // Set ideal processor for the current thread
252     // Parameters:
253     //  processorIndex - index of the processor in the group
254     //  affinity - ideal processor affinity for the thread
255     // Return:
256     //  true if it has succeeded, false if it has failed
257     static bool SetCurrentThreadIdealAffinity(GCThreadAffinity* affinity);
258
259     // Get numeric id of the current thread if possible on the
260     // current platform. It is indended for logging purposes only.
261     // Return:
262     //  Numeric id of the current thread or 0 if the 
263     static uint64_t GetCurrentThreadIdForLogging();
264
265     // Get id of the current process
266     // Return:
267     //  Id of the current process
268     static uint32_t GetCurrentProcessId();
269
270     //
271     // Processor topology
272     //
273
274     // Get number of logical processors
275     static uint32_t GetLogicalCpuCount();
276
277     // Get size of the largest cache on the processor die
278     // Parameters:
279     //  trueSize - true to return true cache size, false to return scaled up size based on
280     //             the processor architecture
281     // Return:
282     //  Size of the cache
283     static size_t GetLargestOnDieCacheSize(bool trueSize = true);
284
285     // Get number of processors assigned to the current process
286     // Return:
287     //  The number of processors
288     static uint32_t GetCurrentProcessCpuCount();
289
290     // Get affinity mask of the current process
291     // Parameters:
292     //  processMask - affinity mask for the specified process
293     //  systemMask  - affinity mask for the system
294     // Return:
295     //  true if it has succeeded, false if it has failed
296     // Remarks:
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);
304
305     //
306     // Global memory info
307     //
308
309     // Return the size of the user-mode portion of the virtual address space of this process.
310     // Return:
311     //  non zero if it has succeeded, 0 if it has failed
312     static size_t GetVirtualMemoryLimit();
313
314     // Get the physical memory that this process can use.
315     // Return:
316     //  non zero if it has succeeded, 0 if it has failed
317     // Remarks:
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();
321
322     // Get memory status
323     // Parameters:
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.
328     // Remarks:
329     //  Any parameter can be null.
330     static void GetMemoryStatus(uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file);
331
332     //
333     // Misc
334     //
335
336     // Flush write buffers of processors that are executing threads of the current process
337     static void FlushProcessWriteBuffers();
338
339     // Break into a debugger
340     static void DebugBreak();
341
342     //
343     // Time
344     //
345
346     // Get a high precision performance counter
347     // Return:
348     //  The counter value
349     static int64_t QueryPerformanceCounter();
350
351     // Get a frequency of the high precision performance counter
352     // Return:
353     //  The counter frequency
354     static int64_t QueryPerformanceFrequency();
355
356     // Get a time stamp with a low precision
357     // Return:
358     //  Time stamp in milliseconds
359     static uint32_t GetLowPrecisionTimeStamp();
360 };
361
362 #endif // __GCENV_OS_H__