| 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 | |