summaryrefslogtreecommitdiff
path: root/src/debug/ee/datatest.h
blob: 7715ba56210ee72a13ef53367813c4610597faf5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
//*****************************************************************************
// File: DataTest.h
//

//
// Implement a self-test for the correct detection of when the target holds a
// lock we encounter in the DAC. 
//
//*****************************************************************************

#ifndef DATA_TEST_H
#define DATA_TEST_H

// This class is used to test our ability to detect from the RS when the target has taken a lock.
// When the DAC executes a code path that takes a lock, we need to know if the target is holding it. 
// If it is, then we assume that the locked data is in an inconsistent state. In that case, we don't 
// want to report the data; we just want to throw an exception.
// This functionality in this class lets us take a lock on the LS and then signal the RS to try to 
// detect whether the lock is held. The main function in this class is TestDataSafety. It deterministically
// signals the RS at key points to execute a code path that takes a lock and also passes a flag to indicate
// whether the LS actually holds the lock. With this information, we can ascertain that our lock detection
// code is working correctly. Without this special test function, it would be nearly impossible to test this
// in any kind of deterministic way.
// 
// The test will run in either debug or retail builds, as long as the environment variable TestDataConsistency
// is turned on. It runs once in code:Debugger::Startup. The RS part of the test is in the cases
// DB_IPCE_TEST_CRST and DB_IPCE_TEST_RWLOCK in code:CordbProcess::RawDispatchEvent.
class DataTest
{
public:
    // constructor
    DataTest():
      m_crst1(CrstDataTest1),
      m_crst2(CrstDataTest2),
      m_rwLock(COOPERATIVE_OR_PREEMPTIVE, LOCK_TYPE_DEFAULT) {};

    // Takes a series of locks in various ways and signals the RS to test the locks at interesting 
    // points to ensure we reliably detect when the LS holds a lock.
      void TestDataSafety();
private:
    // Send an event to the RS to signal that it should test to determine if a crst is held.
    // This is for testing purposes only. 
    void SendDbgCrstEvent(Crst * pCrst, bool okToTake);

    // Send an event to the RS to signal that it should test to determine if a SimpleRWLock is held.
    // This is for testing purposes only. 
    void SendDbgRWLockEvent(SimpleRWLock * pRWLock, bool okToTake);

private:
    // The locks must be data members (rather than locals in TestDataSafety) so we can ensure that 
    // they are target instances. 
    Crst             m_crst1, m_crst2;  // crsts to be taken for testing
    SimpleRWLock     m_rwLock;          // SimpleRWLock to be taken for testing
};
#endif // DATA_TEST_H