Prevent compiler optimization that could cause local var values to change in multithr...
[platform/upstream/coreclr.git] / src / vm / synch.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 //
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 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
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