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
12enum 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
22struct PendingSync;
23class CRWLock;
24
25class CLREventBase
26{
27public:
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
81protected:
82 HANDLE m_handle;
83
84private:
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
125class CLREvent : public CLREventBase
126{
127public:
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.
145class CLREventStatic : public CLREventBase
146{
147};
148
149
150class CLRSemaphore {
151public:
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
176private:
177 HANDLE m_handle;
178};
179
180class CLRLifoSemaphore
181{
182private:
183 struct Counts
184 {
185 union
186 {
187 struct
188 {
189 UINT32 signalCount;
190 UINT16 waiterCount;
191 UINT8 spinnerCount;
192 UINT8 countOfWaitersSignaledToWake;
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
241public:
242 CLRLifoSemaphore() : m_handle(nullptr)
243 {
244 LIMITED_METHOD_CONTRACT;
245 }
246
247 ~CLRLifoSemaphore()
248 {
249 WRAPPER_NO_CONTRACT;
250 Close();
251 }
252
253public:
254 void Create(INT32 initialSignalCount, INT32 maximumSignalCount);
255 void Close();
256
257public:
258 BOOL IsValid() const
259 {
260 LIMITED_METHOD_CONTRACT;
261 return m_handle != nullptr;
262 }
263
264private:
265 bool WaitForSignal(DWORD timeoutMs);
266public:
267 bool Wait(DWORD timeoutMs);
268 bool Wait(DWORD timeoutMs, UINT32 spinCount, UINT32 processorCount);
269 void Release(INT32 releaseCount);
270
271private:
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
289class CLRMutex {
290public:
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
315private:
316 HANDLE m_handle;
317};
318
319BOOL CLREventWaitWithTry(CLREventBase *pEvent, DWORD timeout, BOOL fAlertable, DWORD *pStatus);
320#endif
321