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 | // File: DataTest.h |
6 | // |
7 | |
8 | // |
9 | // Implement a self-test for the correct detection of when the target holds a |
10 | // lock we encounter in the DAC. |
11 | // |
12 | //***************************************************************************** |
13 | |
14 | #ifndef DATA_TEST_H |
15 | #define DATA_TEST_H |
16 | |
17 | // This class is used to test our ability to detect from the RS when the target has taken a lock. |
18 | // When the DAC executes a code path that takes a lock, we need to know if the target is holding it. |
19 | // If it is, then we assume that the locked data is in an inconsistent state. In that case, we don't |
20 | // want to report the data; we just want to throw an exception. |
21 | // This functionality in this class lets us take a lock on the LS and then signal the RS to try to |
22 | // detect whether the lock is held. The main function in this class is TestDataSafety. It deterministically |
23 | // signals the RS at key points to execute a code path that takes a lock and also passes a flag to indicate |
24 | // whether the LS actually holds the lock. With this information, we can ascertain that our lock detection |
25 | // code is working correctly. Without this special test function, it would be nearly impossible to test this |
26 | // in any kind of deterministic way. |
27 | // |
28 | // The test will run in either debug or retail builds, as long as the environment variable TestDataConsistency |
29 | // is turned on. It runs once in code:Debugger::Startup. The RS part of the test is in the cases |
30 | // DB_IPCE_TEST_CRST and DB_IPCE_TEST_RWLOCK in code:CordbProcess::RawDispatchEvent. |
31 | class DataTest |
32 | { |
33 | public: |
34 | // constructor |
35 | DataTest(): |
36 | m_crst1(CrstDataTest1), |
37 | m_crst2(CrstDataTest2), |
38 | m_rwLock(COOPERATIVE_OR_PREEMPTIVE, LOCK_TYPE_DEFAULT) {}; |
39 | |
40 | // Takes a series of locks in various ways and signals the RS to test the locks at interesting |
41 | // points to ensure we reliably detect when the LS holds a lock. |
42 | void TestDataSafety(); |
43 | private: |
44 | // Send an event to the RS to signal that it should test to determine if a crst is held. |
45 | // This is for testing purposes only. |
46 | void SendDbgCrstEvent(Crst * pCrst, bool okToTake); |
47 | |
48 | // Send an event to the RS to signal that it should test to determine if a SimpleRWLock is held. |
49 | // This is for testing purposes only. |
50 | void SendDbgRWLockEvent(SimpleRWLock * pRWLock, bool okToTake); |
51 | |
52 | private: |
53 | // The locks must be data members (rather than locals in TestDataSafety) so we can ensure that |
54 | // they are target instances. |
55 | Crst m_crst1, m_crst2; // crsts to be taken for testing |
56 | SimpleRWLock m_rwLock; // SimpleRWLock to be taken for testing |
57 | }; |
58 | #endif // DATA_TEST_H |
59 | |