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 // GC thread function prototype
51 typedef void (*GCThreadFunction)(void* param);
52 
53 // Interface that the GC uses to invoke OS specific functionality
54 class GCToOSInterface
55 {
56 public:
57 
58     //
59     // Initialization and shutdown of the interface
60     //
61 
62     // Initialize the interface implementation
63     // Return:
64     //  true if it has succeeded, false if it has failed
65     static bool Initialize();
66 
67     // Shutdown the interface implementation
68     static void Shutdown();
69 
70     //
71     // Virtual memory management
72     //
73 
74     // Reserve virtual memory range.
75     // Parameters:
76     //  size      - size of the virtual memory range
77     //  alignment - requested memory alignment
78     //  flags     - flags to control special settings like write watching
79     // Return:
80     //  Starting virtual address of the reserved range
81     static void* VirtualReserve(size_t size, size_t alignment, uint32_t flags);
82 
83     // Release virtual memory range previously reserved using VirtualReserve
84     // Parameters:
85     //  address - starting virtual address
86     //  size    - size of the virtual memory range
87     // Return:
88     //  true if it has succeeded, false if it has failed
89     static bool VirtualRelease(void *address, size_t size);
90 
91     // Commit virtual memory range. It must be part of a range reserved using VirtualReserve.
92     // Parameters:
93     //  address - starting virtual address
94     //  size    - size of the virtual memory range
95     // Return:
96     //  true if it has succeeded, false if it has failed
97     static bool VirtualCommit(void *address, size_t size);
98 
99     // Decomit virtual memory range.
100     // Parameters:
101     //  address - starting virtual address
102     //  size    - size of the virtual memory range
103     // Return:
104     //  true if it has succeeded, false if it has failed
105     static bool VirtualDecommit(void *address, size_t size);
106 
107     // Reset virtual memory range. Indicates that data in the memory range specified by address and size is no
108     // longer of interest, but it should not be decommitted.
109     // Parameters:
110     //  address - starting virtual address
111     //  size    - size of the virtual memory range
112     //  unlock  - true if the memory range should also be unlocked
113     // Return:
114     //  true if it has succeeded, false if it has failed
115     static bool VirtualReset(void *address, size_t size, bool unlock);
116 
117     //
118     // Write watching
119     //
120 
121     // Check if the OS supports write watching
122     static bool SupportsWriteWatch();
123 
124     // Reset the write tracking state for the specified virtual memory range.
125     // Parameters:
126     //  address - starting virtual address
127     //  size    - size of the virtual memory range
128     static void ResetWriteWatch(void *address, size_t size);
129 
130     // Retrieve addresses of the pages that are written to in a region of virtual memory
131     // Parameters:
132     //  resetState         - true indicates to reset the write tracking state
133     //  address            - starting virtual address
134     //  size               - size of the virtual memory range
135     //  pageAddresses      - buffer that receives an array of page addresses in the memory region
136     //  pageAddressesCount - on input, size of the lpAddresses array, in array elements
137     //                       on output, the number of page addresses that are returned in the array.
138     // Return:
139     //  true if it has succeeded, false if it has failed
140     static bool GetWriteWatch(bool resetState, void* address, size_t size, void** pageAddresses, uintptr_t* pageAddressesCount);
141 
142     //
143     // Thread and process
144     //
145 
146     // Create a new thread
147     // Parameters:
148     //  function - the function to be executed by the thread
149     //  param    - parameters of the thread
150     //  affinity - processor affinity of the thread
151     // Return:
152     //  true if it has succeeded, false if it has failed
153     static bool CreateThread(GCThreadFunction function, void* param, GCThreadAffinity* affinity);
154 
155     // Causes the calling thread to sleep for the specified number of milliseconds
156     // Parameters:
157     //  sleepMSec   - time to sleep before switching to another thread
158     static void Sleep(uint32_t sleepMSec);
159 
160     // Causes the calling thread to yield execution to another thread that is ready to run on the current processor.
161     // Parameters:
162     //  switchCount - number of times the YieldThread was called in a loop
163     static void YieldThread(uint32_t switchCount);
164 
165     // Get the number of the current processor
166     static uint32_t GetCurrentProcessorNumber();
167 
168     // Check if the OS supports getting current processor number
169     static bool CanGetCurrentProcessorNumber();
170 
171     // Set ideal processor for the current thread
172     // Parameters:
173     //  processorIndex - index of the processor in the group
174     //  affinity - ideal processor affinity for the thread
175     // Return:
176     //  true if it has succeeded, false if it has failed
177     static bool SetCurrentThreadIdealAffinity(GCThreadAffinity* affinity);
178 
179     // Get numeric id of the current thread if possible on the
180     // current platform. It is indended for logging purposes only.
181     // Return:
182     //  Numeric id of the current thread or 0 if the
183     static uint64_t GetCurrentThreadIdForLogging();
184 
185     // Get id of the current process
186     // Return:
187     //  Id of the current process
188     static uint32_t GetCurrentProcessId();
189 
190     //
191     // Processor topology
192     //
193 
194     // Get number of logical processors
195     static uint32_t GetLogicalCpuCount();
196 
197     // Get size of the largest cache on the processor die
198     // Parameters:
199     //  trueSize - true to return true cache size, false to return scaled up size based on
200     //             the processor architecture
201     // Return:
202     //  Size of the cache
203     static size_t GetLargestOnDieCacheSize(bool trueSize = true);
204 
205     // Get number of processors assigned to the current process
206     // Return:
207     //  The number of processors
208     static uint32_t GetCurrentProcessCpuCount();
209 
210     // Get affinity mask of the current process
211     // Parameters:
212     //  processMask - affinity mask for the specified process
213     //  systemMask  - affinity mask for the system
214     // Return:
215     //  true if it has succeeded, false if it has failed
216     // Remarks:
217     //  A process affinity mask is a bit vector in which each bit represents the processors that
218     //  a process is allowed to run on. A system affinity mask is a bit vector in which each bit
219     //  represents the processors that are configured into a system.
220     //  A process affinity mask is a subset of the system affinity mask. A process is only allowed
221     //  to run on the processors configured into a system. Therefore, the process affinity mask cannot
222     //  specify a 1 bit for a processor when the system affinity mask specifies a 0 bit for that processor.
223     static bool GetCurrentProcessAffinityMask(uintptr_t *processMask, uintptr_t *systemMask);
224 
225     //
226     // Global memory info
227     //
228 
229     // Return the size of the user-mode portion of the virtual address space of this process.
230     // Return:
231     //  non zero if it has succeeded, 0 if it has failed
232     static size_t GetVirtualMemoryLimit();
233 
234     // Get the physical memory that this process can use.
235     // Return:
236     //  non zero if it has succeeded, 0 if it has failed
237     // Remarks:
238     //  If a process runs with a restricted memory limit, it returns the limit. If there's no limit
239     //  specified, it returns amount of actual physical memory.
240     static uint64_t GetPhysicalMemoryLimit();
241 
242     // Get memory status
243     // Parameters:
244     //  memory_load - A number between 0 and 100 that specifies the approximate percentage of physical memory
245     //      that is in use (0 indicates no memory use and 100 indicates full memory use).
246     //  available_physical - The amount of physical memory currently available, in bytes.
247     //  available_page_file - The maximum amount of memory the current process can commit, in bytes.
248     // Remarks:
249     //  Any parameter can be null.
250     static void GetMemoryStatus(uint32_t* memory_load, uint64_t* available_physical, uint64_t* available_page_file);
251 
252     //
253     // Misc
254     //
255 
256     // Flush write buffers of processors that are executing threads of the current process
257     static void FlushProcessWriteBuffers();
258 
259     // Break into a debugger
260     static void DebugBreak();
261 
262     //
263     // Time
264     //
265 
266     // Get a high precision performance counter
267     // Return:
268     //  The counter value
269     static int64_t QueryPerformanceCounter();
270 
271     // Get a frequency of the high precision performance counter
272     // Return:
273     //  The counter frequency
274     static int64_t QueryPerformanceFrequency();
275 
276     // Get a time stamp with a low precision
277     // Return:
278     //  Time stamp in milliseconds
279     static uint32_t GetLowPrecisionTimeStamp();
280 };
281 
282 #endif // __GCENV_OS_H__
283