Add a fourth parameter to the DEFINE_DACVAR macro that is the actual fully qualified...
[platform/upstream/coreclr.git] / src / vm / simplerwlock.hpp
1 //
2 // Copyright (c) Microsoft. All rights reserved.
3 // Licensed under the MIT license. See LICENSE file in the project root for full license information.
4 //
5 //
6
7 // 
8
9 #ifndef _SimpleRWLock_hpp_
10 #define _SimpleRWLock_hpp_
11
12 #ifndef BINDER
13 #include "threads.h"
14 #endif
15
16 class SimpleRWLock;
17
18 //-------------------------------------------------------------------------------------------
19 // GC_MODE defines custom CONTRACTs for TryEnterRead and TryEnterWrite.
20 //
21 // Contract differs when acquiring the lock depending on its lock mode.
22 //
23 // GC/MODE
24 //     A SimpleRWLock can be one of the following modes. We only want to see the "PREEMPTIVE" 
25 //     type used in new code. Other types, kept for legacy reasons, are listed in
26 //     order from least objectionable to most objectionable.
27 //
28 //         PREEMPTIVE (equivalent to CRST's "normal")
29 //            This is the preferred type of crst. Enter() will force-switch your thread
30 //            into preemptive mode if it isn't already. Thus, the effective contract is:
31 //
32 //            MODE_ANY
33 //            GC_TRIGGERS
34 //
35 //
36 //
37 //         COOPERATIVE (equivalent to CRST_UNSAFE_COOPGC) 
38 //            You can only attempt to acquire this crst if you're already in coop mode. It is 
39 //            guaranteed no GC will occur while waiting to acquire the lock.  While you hold 
40 //            the lock, your thread is in a GCFORBID state.
41 //
42 //            MODE_COOP
43 //            GC_NOTRIGGER
44 //
45 //
46 //
47 //         COOPERATIVE_OR_PREEMPTIVE (equivalent to CRST_UNSAFE_ANYMODE) 
48 //            You can attempt to acquire this in either mode. Entering the crst will not change 
49 //            your thread mode but it will increment the GCNoTrigger count.
50 //
51 //            MODE_ANY
52 //            GC_NOTRIGGER
53 //------------------------------------------------------------------------------------------------
54 enum GC_MODE {
55     COOPERATIVE,
56     PREEMPTIVE,
57     COOPERATIVE_OR_PREEMPTIVE} ;
58
59 class SimpleRWLock
60 {
61     // Allow Module access so we can use Offsetof on this class's private members during native image creation (determinism)
62     friend class Module;
63 private:
64     BOOL IsWriterWaiting()
65     {
66         LIMITED_METHOD_CONTRACT;
67         return m_WriterWaiting != 0;
68     }
69
70     void SetWriterWaiting()
71     {
72         LIMITED_METHOD_CONTRACT;
73         m_WriterWaiting = 1;
74     }
75
76     void ResetWriterWaiting()
77     {
78         LIMITED_METHOD_CONTRACT;
79         m_WriterWaiting = 0;
80     }
81
82     BOOL TryEnterRead();
83
84     BOOL TryEnterWrite();
85
86 #ifdef ENABLE_CONTRACTS_IMPL
87     void CheckGCNoTrigger();
88 #endif  //ENABLE_CONTRACTS_IMPL
89
90     // lock used for R/W synchronization
91     Volatile<LONG>                m_RWLock;     
92
93     // Does this lock require to be taken in PreemptiveGC mode?
94     const GC_MODE          m_gcMode;
95
96     // spin count for a reader waiting for a writer to release the lock
97     LONG                m_spinCount;
98
99     // used to prevent writers from being starved by readers
100     // we currently do not prevent writers from starving readers since writers 
101     // are supposed to be rare.
102     BOOL                m_WriterWaiting;
103
104 #ifdef _DEBUG
105     // Check for dead lock situation.
106     Volatile<LONG>      m_countNoTriggerGC;
107
108 #ifdef _WIN64
109     // ensures that we are a multiple of 8-bytes
110     UINT32 pad;      
111 #endif
112
113     void                PostEnter ();
114     void                PreEnter ();
115     void                PreLeave ();
116 #endif //_DEBUG
117
118 #ifndef DACCESS_COMPILE
119     static void AcquireReadLock(SimpleRWLock *s) { LIMITED_METHOD_CONTRACT; s->EnterRead(); }
120     static void ReleaseReadLock(SimpleRWLock *s) { LIMITED_METHOD_CONTRACT; s->LeaveRead(); }
121
122     static void AcquireWriteLock(SimpleRWLock *s) { LIMITED_METHOD_CONTRACT; s->EnterWrite(); }
123     static void ReleaseWriteLock(SimpleRWLock *s) { LIMITED_METHOD_CONTRACT; s->LeaveWrite(); }
124 #else // DACCESS_COMPILE
125     // in DAC builds, we don't actually acquire the lock, we just determine whether the LS
126     // already holds it. If so, we assume the data is inconsistent and throw an exception. 
127     // Argument: 
128     //     input: s - the lock to be checked. 
129     // Note: Throws
130     static void AcquireReadLock(SimpleRWLock *s) 
131     {
132         SUPPORTS_DAC;
133         if (s->IsWriterLock()) 
134         {
135             ThrowHR(CORDBG_E_PROCESS_NOT_SYNCHRONIZED); 
136         }
137     };
138     static void ReleaseReadLock(SimpleRWLock *s) { };
139
140     static void AcquireWriteLock(SimpleRWLock *s) { SUPPORTS_DAC; ThrowHR(CORDBG_E_TARGET_READONLY); };
141     static void ReleaseWriteLock(SimpleRWLock *s) { };
142 #endif // DACCESS_COMPILE
143
144 public:
145     SimpleRWLock (GC_MODE gcMode, LOCK_TYPE locktype)
146         : m_gcMode (gcMode)
147     {
148         CONTRACTL {
149             NOTHROW;
150             GC_NOTRIGGER;
151         } CONTRACTL_END;
152
153         m_RWLock = 0;
154 #ifdef CLR_STANDALONE_BINDER
155         m_spinCount = 0;
156 #else
157         m_spinCount = (GetCurrentProcessCpuCount() == 1) ? 0 : 4000;
158 #endif
159         m_WriterWaiting = FALSE;
160
161 #ifdef _DEBUG
162         m_countNoTriggerGC = 0;
163 #endif
164     }
165
166     // Special empty CTOR for DAC. We still need to assign to const fields, but they won't actually be used.
167     SimpleRWLock()  
168         : m_gcMode(COOPERATIVE_OR_PREEMPTIVE)
169     {
170         LIMITED_METHOD_CONTRACT;
171
172 #ifdef _DEBUG
173         m_countNoTriggerGC = 0;
174 #endif //_DEBUG
175     }
176     
177 #ifndef DACCESS_COMPILE
178     // Acquire the reader lock.
179     void EnterRead();
180
181     // Acquire the writer lock.
182     void EnterWrite();
183
184 #ifdef BINDER
185     // Leave the reader lock.
186     void LeaveRead();
187     // Leave the writer lock.
188     void LeaveWrite();
189 #else // !BINDER
190     // Leave the reader lock.
191     void LeaveRead()
192     {
193         LIMITED_METHOD_CONTRACT;
194 #ifdef _DEBUG
195         PreLeave ();
196 #endif //_DEBUG
197         LONG RWLock;
198         RWLock = InterlockedDecrement(&m_RWLock);
199         _ASSERTE (RWLock >= 0);
200         DECTHREADLOCKCOUNT();
201         EE_LOCK_RELEASED(this);
202     }
203
204     // Leave the writer lock.
205     void LeaveWrite()
206     {
207         LIMITED_METHOD_CONTRACT;        
208 #ifdef _DEBUG
209         PreLeave ();
210 #endif //_DEBUG
211         LONG RWLock;
212         RWLock = InterlockedExchange (&m_RWLock, 0);
213         _ASSERTE(RWLock == -1);
214         DECTHREADLOCKCOUNT();
215         EE_LOCK_RELEASED(this);
216     }
217 #endif // !BINDER
218
219 #endif // DACCESS_COMPILE
220
221     typedef DacHolder<SimpleRWLock *, SimpleRWLock::AcquireReadLock, SimpleRWLock::ReleaseReadLock> SimpleReadLockHolder;
222     typedef DacHolder<SimpleRWLock *, SimpleRWLock::AcquireWriteLock, SimpleRWLock::ReleaseWriteLock> SimpleWriteLockHolder;
223
224 #ifdef _DEBUG
225     BOOL LockTaken ()
226     {
227         LIMITED_METHOD_CONTRACT;
228         return m_RWLock != 0;
229     }
230
231     BOOL IsReaderLock ()
232     {
233         LIMITED_METHOD_CONTRACT;
234         return m_RWLock > 0;
235     }
236
237 #endif  
238
239     BOOL IsWriterLock ()
240     {
241         LIMITED_METHOD_DAC_CONTRACT;
242         return m_RWLock < 0;
243     }
244     
245 };
246
247 typedef SimpleRWLock::SimpleReadLockHolder SimpleReadLockHolder;
248 typedef SimpleRWLock::SimpleWriteLockHolder SimpleWriteLockHolder;
249 typedef DPTR(SimpleRWLock) PTR_SimpleRWLock;
250
251 #ifdef TEST_DATA_CONSISTENCY
252 // used for test purposes. Determines if a crst is held. 
253 // Arguments:
254 //     input: pLock - the lock to test
255 // Note: Throws if the lock is held    
256
257 FORCEINLINE void DebugTryRWLock(SimpleRWLock * pLock)
258 {
259     SUPPORTS_DAC;
260
261     SimpleReadLockHolder rwLock(pLock);
262 }
263 #endif // TEST_DATA_CONSISTENCY
264 #endif