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 | // |
5 | |
6 | // |
7 | |
8 | |
9 | #ifndef __Synch_h__ |
10 | #define __Synch_h__ |
11 | |
12 | enum WaitMode |
13 | { |
14 | WaitMode_None =0x0, |
15 | WaitMode_Alertable = 0x1, // Can be waken by APC. May pumping message. |
16 | WaitMode_IgnoreSyncCtx = 0x2, // Dispatch to synchronization context if existed. |
17 | WaitMode_ADUnload = 0x4, // The block is to wait for AD unload start. If it is interrupted by AD Unload, we can start aborting. |
18 | WaitMode_InDeadlock = 0x8, // The wait can be terminated by host's deadlock detection |
19 | }; |
20 | |
21 | |
22 | struct PendingSync; |
23 | class CRWLock; |
24 | |
25 | class CLREventBase |
26 | { |
27 | public: |
28 | CLREventBase() |
29 | { |
30 | LIMITED_METHOD_CONTRACT; |
31 | m_handle = INVALID_HANDLE_VALUE; |
32 | m_dwFlags = 0; |
33 | } |
34 | |
35 | // Create an Event that is host aware |
36 | void CreateAutoEvent(BOOL bInitialState); |
37 | void CreateManualEvent(BOOL bInitialState); |
38 | |
39 | // Non-throwing variants of the functions above |
40 | BOOL CreateAutoEventNoThrow(BOOL bInitialState); |
41 | BOOL CreateManualEventNoThrow(BOOL bInitialState); |
42 | |
43 | void CreateMonitorEvent(SIZE_T Cookie); // robust against initialization races - for exclusive use by AwareLock |
44 | |
45 | |
46 | // Create an Event that is not host aware |
47 | void CreateOSAutoEvent (BOOL bInitialState); |
48 | void CreateOSManualEvent (BOOL bInitialState); |
49 | |
50 | // Non-throwing variants of the functions above |
51 | BOOL CreateOSAutoEventNoThrow (BOOL bInitialState); |
52 | BOOL CreateOSManualEventNoThrow (BOOL bInitialState); |
53 | |
54 | void CloseEvent(); |
55 | |
56 | BOOL IsValid() const |
57 | { |
58 | LIMITED_METHOD_CONTRACT; |
59 | return m_handle != INVALID_HANDLE_VALUE; |
60 | } |
61 | |
62 | BOOL IsMonitorEventAllocated() |
63 | { |
64 | LIMITED_METHOD_CONTRACT; |
65 | return m_dwFlags & CLREVENT_FLAGS_MONITOREVENT_ALLOCATED; |
66 | } |
67 | |
68 | #ifndef DACCESS_COMPILE |
69 | HANDLE GetHandleUNHOSTED() { |
70 | LIMITED_METHOD_CONTRACT; |
71 | return m_handle; |
72 | } |
73 | #endif // DACCESS_COMPILE |
74 | |
75 | BOOL Set(); |
76 | void SetMonitorEvent(); // robust against races - for exclusive use by AwareLock |
77 | BOOL Reset(); |
78 | DWORD Wait(DWORD dwMilliseconds, BOOL bAlertable, PendingSync *syncState=NULL); |
79 | DWORD WaitEx(DWORD dwMilliseconds, WaitMode mode, PendingSync *syncState=NULL); |
80 | |
81 | protected: |
82 | HANDLE m_handle; |
83 | |
84 | private: |
85 | enum |
86 | { |
87 | CLREVENT_FLAGS_AUTO_EVENT = 0x0001, |
88 | CLREVENT_FLAGS_OS_EVENT = 0x0002, |
89 | CLREVENT_FLAGS_IN_DEADLOCK_DETECTION = 0x0004, |
90 | |
91 | CLREVENT_FLAGS_MONITOREVENT_ALLOCATED = 0x0008, |
92 | CLREVENT_FLAGS_MONITOREVENT_SIGNALLED = 0x0010, |
93 | |
94 | CLREVENT_FLAGS_STATIC = 0x0020, |
95 | |
96 | // Several bits unused; |
97 | }; |
98 | |
99 | Volatile<DWORD> m_dwFlags; |
100 | |
101 | BOOL IsAutoEvent() { LIMITED_METHOD_CONTRACT; return m_dwFlags & CLREVENT_FLAGS_AUTO_EVENT; } |
102 | void SetAutoEvent () |
103 | { |
104 | LIMITED_METHOD_CONTRACT; |
105 | // cannot use `|=' operator on `Volatile<DWORD>' |
106 | m_dwFlags = m_dwFlags | CLREVENT_FLAGS_AUTO_EVENT; |
107 | } |
108 | BOOL IsOSEvent() { LIMITED_METHOD_CONTRACT; return m_dwFlags & CLREVENT_FLAGS_OS_EVENT; } |
109 | void SetOSEvent () |
110 | { |
111 | LIMITED_METHOD_CONTRACT; |
112 | // cannot use `|=' operator on `Volatile<DWORD>' |
113 | m_dwFlags = m_dwFlags | CLREVENT_FLAGS_OS_EVENT; |
114 | } |
115 | BOOL IsInDeadlockDetection() { LIMITED_METHOD_CONTRACT; return m_dwFlags & CLREVENT_FLAGS_IN_DEADLOCK_DETECTION; } |
116 | void SetInDeadlockDetection () |
117 | { |
118 | LIMITED_METHOD_CONTRACT; |
119 | // cannot use `|=' operator on `Volatile<DWORD>' |
120 | m_dwFlags = m_dwFlags | CLREVENT_FLAGS_IN_DEADLOCK_DETECTION; |
121 | } |
122 | }; |
123 | |
124 | |
125 | class CLREvent : public CLREventBase |
126 | { |
127 | public: |
128 | |
129 | #ifndef DACCESS_COMPILE |
130 | ~CLREvent() |
131 | { |
132 | WRAPPER_NO_CONTRACT; |
133 | |
134 | CloseEvent(); |
135 | } |
136 | #endif |
137 | }; |
138 | |
139 | |
140 | // CLREventStatic |
141 | // Same as CLREvent, but intended to be used for global variables. |
142 | // Instances may leak their handle, because of the order in which |
143 | // global destructors are run. Note that you can still explicitly |
144 | // call CloseHandle, which will indeed not leak the handle. |
145 | class CLREventStatic : public CLREventBase |
146 | { |
147 | }; |
148 | |
149 | |
150 | class CLRSemaphore { |
151 | public: |
152 | CLRSemaphore() |
153 | : m_handle(INVALID_HANDLE_VALUE) |
154 | { |
155 | LIMITED_METHOD_CONTRACT; |
156 | } |
157 | |
158 | ~CLRSemaphore() |
159 | { |
160 | WRAPPER_NO_CONTRACT; |
161 | Close (); |
162 | } |
163 | |
164 | void Create(DWORD dwInitial, DWORD dwMax); |
165 | void Close(); |
166 | |
167 | BOOL IsValid() const |
168 | { |
169 | LIMITED_METHOD_CONTRACT; |
170 | return m_handle != INVALID_HANDLE_VALUE; |
171 | } |
172 | |
173 | DWORD Wait(DWORD dwMilliseconds, BOOL bAlertable); |
174 | BOOL Release(LONG lReleaseCount, LONG* lpPreviouseCount); |
175 | |
176 | private: |
177 | HANDLE m_handle; |
178 | }; |
179 | |
180 | class CLRLifoSemaphore |
181 | { |
182 | private: |
183 | struct Counts |
184 | { |
185 | union |
186 | { |
187 | struct |
188 | { |
189 | UINT32 signalCount; |
190 | UINT16 waiterCount; |
191 | UINT8 spinnerCount; |
192 | UINT8 ; |
193 | }; |
194 | UINT64 data; |
195 | }; |
196 | |
197 | Counts(UINT64 data = 0) : data(data) |
198 | { |
199 | LIMITED_METHOD_CONTRACT; |
200 | } |
201 | |
202 | operator UINT64() const |
203 | { |
204 | LIMITED_METHOD_CONTRACT; |
205 | return data; |
206 | } |
207 | |
208 | Counts operator -() const |
209 | { |
210 | LIMITED_METHOD_CONTRACT; |
211 | return -(INT64)data; |
212 | } |
213 | |
214 | Counts &operator =(UINT64 data) |
215 | { |
216 | LIMITED_METHOD_CONTRACT; |
217 | |
218 | this->data = data; |
219 | return *this; |
220 | } |
221 | |
222 | Counts VolatileLoadWithoutBarrier() const |
223 | { |
224 | LIMITED_METHOD_CONTRACT; |
225 | return ::VolatileLoadWithoutBarrier(&data); |
226 | } |
227 | |
228 | Counts CompareExchange(Counts toCounts, Counts fromCounts) |
229 | { |
230 | LIMITED_METHOD_CONTRACT; |
231 | return (UINT64)InterlockedCompareExchange64((LONG64 *)&data, (LONG64)toCounts, (LONG64)fromCounts); |
232 | } |
233 | |
234 | Counts ExchangeAdd(Counts toAdd) |
235 | { |
236 | LIMITED_METHOD_CONTRACT; |
237 | return (UINT64)InterlockedExchangeAdd64((LONG64 *)&data, (LONG64)toAdd); |
238 | } |
239 | }; |
240 | |
241 | public: |
242 | CLRLifoSemaphore() : m_handle(nullptr) |
243 | { |
244 | LIMITED_METHOD_CONTRACT; |
245 | } |
246 | |
247 | ~CLRLifoSemaphore() |
248 | { |
249 | WRAPPER_NO_CONTRACT; |
250 | Close(); |
251 | } |
252 | |
253 | public: |
254 | void Create(INT32 initialSignalCount, INT32 maximumSignalCount); |
255 | void Close(); |
256 | |
257 | public: |
258 | BOOL IsValid() const |
259 | { |
260 | LIMITED_METHOD_CONTRACT; |
261 | return m_handle != nullptr; |
262 | } |
263 | |
264 | private: |
265 | bool WaitForSignal(DWORD timeoutMs); |
266 | public: |
267 | bool Wait(DWORD timeoutMs); |
268 | bool Wait(DWORD timeoutMs, UINT32 spinCount, UINT32 processorCount); |
269 | void Release(INT32 releaseCount); |
270 | |
271 | private: |
272 | BYTE __padding1[MAX_CACHE_LINE_SIZE]; // padding to ensure that m_counts gets its own cache line |
273 | |
274 | // Take care to use 'm_counts.VolatileLoadWithoutBarrier()` when loading this value into a local variable that will be |
275 | // reused. See AwareLock::m_lockState for details. |
276 | Counts m_counts; |
277 | |
278 | BYTE __padding2[MAX_CACHE_LINE_SIZE]; // padding to ensure that m_counts gets its own cache line |
279 | |
280 | #if defined(DEBUG) |
281 | UINT32 m_maximumSignalCount; |
282 | #endif // _DEBUG && !FEATURE_PAL |
283 | |
284 | // When FEATURE_PAL is defined, this is a handle to an instance of the PAL's LIFO semaphore. When FEATURE_PAL is not |
285 | // defined, this is a handle to an I/O completion port. |
286 | HANDLE m_handle; |
287 | }; |
288 | |
289 | class CLRMutex { |
290 | public: |
291 | CLRMutex() |
292 | : m_handle(INVALID_HANDLE_VALUE) |
293 | { |
294 | LIMITED_METHOD_CONTRACT; |
295 | } |
296 | |
297 | ~CLRMutex() |
298 | { |
299 | WRAPPER_NO_CONTRACT; |
300 | Close (); |
301 | } |
302 | |
303 | void Create(LPSECURITY_ATTRIBUTES lpMutexAttributes, BOOL bInitialOwner, LPCTSTR lpName); |
304 | void Close(); |
305 | |
306 | BOOL IsValid() const |
307 | { |
308 | LIMITED_METHOD_CONTRACT; |
309 | return m_handle != INVALID_HANDLE_VALUE; |
310 | } |
311 | |
312 | DWORD Wait(DWORD dwMilliseconds, BOOL bAlertable); |
313 | BOOL Release(); |
314 | |
315 | private: |
316 | HANDLE m_handle; |
317 | }; |
318 | |
319 | BOOL CLREventWaitWithTry(CLREventBase *pEvent, DWORD timeout, BOOL fAlertable, DWORD *pStatus); |
320 | #endif |
321 | |