Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

202 lines
6.5 KiB

  1. //-----------------------------------------------------------------------------
  2. // Microsoft OLE DB Implementation For ODBC Providers
  3. // (C) Copyright 1994 - 1996 By Microsoft Corporation.
  4. //
  5. // @doc
  6. //
  7. // @module AUTOBLOC.H | CAutoBlock object implementation.
  8. //
  9. // @rev 1 | 02-27-95 | EricJ | Created
  10. // @rev 2 | 06-30-95 | EricJ | Added autoduck comments (maybe too many?)
  11. // @rev 3 | 07-02-96 | EricJ | Removed debug code; doesn't work on WIN95 or RISC.
  12. //-----------------------------------------------------------------------------
  13. #ifndef __AUTOBLOC_H_
  14. #define __AUTOBLOC_H_
  15. //-----------------------------------------------------------------------------
  16. // @class CAutoBlock | Auto blocking / synchronization.
  17. //
  18. // This C++ object allows blocking of critical sections.
  19. // The constructor/destructor automatically Enter and Leave
  20. // correctly, to ensure that each call is correctly paired.
  21. // This ensures correct operation for exception handling
  22. // and for multiple returns.
  23. //
  24. // @ex Here's example usage. |
  25. //
  26. // void test2()
  27. // {
  28. // CAutoBlock ab( &g_Crit1 );
  29. //
  30. // // Do some work here...
  31. // // Destructor cleans up
  32. // }
  33. //
  34. // void test3()
  35. // {
  36. // CAutoBlock ab( &g_Crit2 );
  37. //
  38. // //...do some work -- we are blocked here...
  39. //
  40. // ab.UnBlock();
  41. //
  42. // //...do some work -- we are not blocked here...
  43. // //...destructor does nothing...
  44. // }
  45. //
  46. // @devnote
  47. // If you want to enter the same critical section again,
  48. // just use another CAutoBlock.
  49. //
  50. // Note that since the storage is auto (not static or dynamic
  51. // via `new`), this goes onto the stack. Thus the overhead of
  52. // this class is almost exactly the same as explictly calling
  53. // EnterCriticalSection / LeaveCriticalSection.
  54. //-----------------------------------------------------------------------------
  55. class DBEXPORT CAutoBlock {
  56. public: //@access public functions
  57. CAutoBlock( CRITICAL_SECTION *pCrit ); //@cmember CTOR. Begins blocking.
  58. ~CAutoBlock(); //@cmember DTOR. Ends blocking.
  59. void UnBlock(); //@cmember Ends blocking.
  60. private: //@access private data
  61. CRITICAL_SECTION *m_pCrit; //@cmember The critical section.
  62. };
  63. //-----------------------------------------------------------------------------
  64. // Inline functions
  65. //-----------------------------------------------------------------------------
  66. //-----------------------------------------------------------------------------
  67. // @mfunc Constructor.
  68. // Begins blocking. Does EnterCriticalSection, so you can put at
  69. // beginning of function, or in the middle of the function,
  70. // or inside some scoped {}.
  71. //-----------------------------------------------------------------------------------
  72. inline CAutoBlock::CAutoBlock(
  73. CRITICAL_SECTION *pCrit ) //@parm IN | The critical section.
  74. {
  75. // It is OK to pass a NULL ptr to this routine. It is a NOOP.
  76. // Note that passing NULL to EnterCriticalSection blows up.
  77. if (0 != pCrit )
  78. ::EnterCriticalSection( pCrit );
  79. m_pCrit = pCrit;
  80. }
  81. //-----------------------------------------------------------------------------
  82. // @mfunc Destructor.
  83. // Ends blocking. Does LeaveCriticalSection, unless you called UnBlock(),
  84. // in which case it's a NOOP.
  85. //-----------------------------------------------------------------------------------
  86. inline CAutoBlock::~CAutoBlock()
  87. {
  88. if ( 0 != m_pCrit )
  89. ::LeaveCriticalSection( m_pCrit );
  90. }
  91. //-----------------------------------------------------------------------------
  92. // @mfunc
  93. // Ends blocking explicitly. Thereafter, the destructor does nothing.
  94. //-----------------------------------------------------------------------------------
  95. inline void CAutoBlock::UnBlock()
  96. {
  97. // Clear the critical-section member,
  98. // so that the destructor doesn't do anything.
  99. if ( 0 != m_pCrit )
  100. ::LeaveCriticalSection( m_pCrit );
  101. m_pCrit = 0;
  102. }
  103. //-----------------------------------------------------------------------------
  104. // @class CAutoBlock2 | Auto blocking / synchronization.
  105. // This class requires each critical section to be assigned a level.
  106. // Critical Sections can be called only in a low-to-high order, within a thread.
  107. // Otherwise the chance for deadlock exists.
  108. //-----------------------------------------------------------------------------
  109. // ifdef this out for now, so it doesn't introduce another global var.
  110. #ifdef NOTREADY
  111. class DBEXPORT CAutoBlock2 {
  112. public: //@access public functions
  113. CAutoBlock2( CRITICAL_SECTION *pCrit, DWORD dwLevel ); //@cmember CTOR. Begins blocking.
  114. ~CAutoBlock2(); //@cmember DTOR. Ends blocking.
  115. void UnBlock(); //@cmember Ends blocking.
  116. private: //@access private data
  117. CRITICAL_SECTION *m_pCriticalSection; //@cmember The critical section.
  118. DEBUGCODE( DWORD m_dwLevel; ) //@cmember Level of this critical section.
  119. };
  120. // There can be 32 levels, 0...31.
  121. // They can only be used in low --> high order.
  122. enum CritLevels {
  123. CRITLEV_DATASOURCE,
  124. CRITLEV_SESSION,
  125. CRITLEV_COMMAND,
  126. CRITLEV_ROWSET,
  127. };
  128. // We need a global var for the TLS index.
  129. // @todo EJ 2-jun-96: Fake it for now; until this is integrated.
  130. static DWORD g_dwTlsIndexCS = TLS_OUT_OF_INDEXES;
  131. inline CAutoBlock2::CAutoBlock2( CRITICAL_SECTION *pCriticalSection, DWORD dwLevel )
  132. {
  133. #ifdef DEBUG
  134. DWORD dwExistLevel;
  135. assert( 0 <= dwLevel && dwLevel <= 31);
  136. assert(g_dwTlsIndexCS != TLS_OUT_OF_INDEXES);
  137. dwExistLevel = (DWORD) TlsGetValue(g_dwTlsIndexCS);
  138. // Disallow calls to lower levels than we currently have.
  139. // Allow calls to same level.
  140. assert(dwExistLevel > (DWORD) (1<<(dwLevel+1)) - 1);
  141. dwExistLevel |= 1<<dwLevel;
  142. TlsSetValue(g_dwTlsIndexCS, (LPVOID) dwExistLevel);
  143. m_dwLevel = dwLevel;
  144. #endif
  145. m_pCriticalSection = pCriticalSection;
  146. if ( 0 != pCriticalSection )
  147. ::EnterCriticalSection( pCriticalSection );
  148. }
  149. inline CAutoBlock2::~CAutoBlock2()
  150. {
  151. #ifdef DEBUG
  152. DWORD dwExistLevel;
  153. dwExistLevel = (DWORD) TlsGetValue(g_dwTlsIndexCS);
  154. dwExistLevel &= ~ (1<<m_dwLevel);
  155. TlsSetValue(g_dwTlsIndexCS, (LPVOID) dwExistLevel);
  156. #endif
  157. if ( 0 != m_pCriticalSection )
  158. ::LeaveCriticalSection( m_pCriticalSection );
  159. }
  160. inline void CAutoBlock2::UnBlock()
  161. {
  162. // Clear the critical-section member,
  163. // so that the destructor doesn't do anything.
  164. if ( 0 != m_pCriticalSection )
  165. ::LeaveCriticalSection( m_pCriticalSection );
  166. m_pCriticalSection = 0;
  167. }
  168. #endif // NOTREADY
  169. #endif // __AUTOBLOC_H_