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.

255 lines
5.2 KiB

  1. /*++
  2. Copyright (C) 1996-2001 Microsoft Corporation
  3. Module Name:
  4. SYNC.CPP
  5. Abstract:
  6. Synchronization
  7. History:
  8. --*/
  9. #include "precomp.h"
  10. #include "sync.h"
  11. #include <cominit.h>
  12. #include <wbemutil.h>
  13. #include <corex.h>
  14. CSimpleLock::CSimpleLock()
  15. : m_hEvent(NULL), m_dwOwningThread(0), m_bLocked(false), m_lWaiting(0)
  16. {
  17. m_hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  18. }
  19. CSimpleLock::~CSimpleLock()
  20. {
  21. CloseHandle(m_hEvent);
  22. }
  23. DWORD CSimpleLock::Enter(DWORD dwTimeout)
  24. {
  25. m_cs.Enter();
  26. if(m_bLocked || m_lWaiting > 0)
  27. {
  28. //
  29. // Locked. Make sure the unlocker sets the event
  30. //
  31. m_lWaiting++;
  32. m_cs.Leave();
  33. DWORD dwRes = WaitForSingleObject(m_hEvent, dwTimeout);
  34. if(dwRes != WAIT_OBJECT_0)
  35. {
  36. if(dwRes != WAIT_TIMEOUT)
  37. {
  38. ERRORTRACE((LOG_ESS, "FAILED TO ACQUIRE LOCK: %d\n", dwRes));
  39. }
  40. return dwRes;
  41. }
  42. m_cs.Enter();
  43. m_lWaiting--;
  44. }
  45. else
  46. {
  47. //
  48. // Nobody has the lock, and nobody is in the middle, so just grab it
  49. //
  50. }
  51. m_bLocked = true;
  52. m_cs.Leave();
  53. m_dwOwningThread = GetCurrentThreadId();
  54. return WAIT_OBJECT_0;
  55. }
  56. void CSimpleLock::Leave()
  57. {
  58. m_dwOwningThread = 0;
  59. m_cs.Enter();
  60. //
  61. // Only set the event if someone is waiting
  62. //
  63. if(m_lWaiting > 0)
  64. SetEvent(m_hEvent);
  65. m_bLocked = false;
  66. m_cs.Leave();
  67. }
  68. CHaltable::CHaltable() : m_lJustResumed(1), m_dwHaltCount(0), m_csHalt()
  69. {
  70. // This event will be signaled whenever we are not halted
  71. // ======================================================
  72. m_hReady = CreateEvent(
  73. NULL,
  74. TRUE, // manual reset
  75. TRUE, // signaled: not halted
  76. NULL);
  77. }
  78. CHaltable::~CHaltable()
  79. {
  80. CloseHandle(m_hReady);
  81. }
  82. HRESULT CHaltable::Halt()
  83. {
  84. CInCritSec ics(&m_csHalt); // in critical section
  85. m_dwHaltCount++;
  86. ResetEvent(m_hReady);
  87. return S_OK;
  88. }
  89. HRESULT CHaltable::Resume()
  90. {
  91. CInCritSec ics(&m_csHalt); // in critical section
  92. m_dwHaltCount--;
  93. if(m_dwHaltCount == 0)
  94. {
  95. SetEvent(m_hReady);
  96. m_lJustResumed = 1;
  97. }
  98. return S_OK;
  99. }
  100. HRESULT CHaltable::ResumeAll()
  101. {
  102. CInCritSec ics(&m_csHalt); // in critical section
  103. m_dwHaltCount = 1;
  104. return Resume();
  105. }
  106. HRESULT CHaltable::WaitForResumption()
  107. {
  108. while (WbemWaitForSingleObject(m_hReady, INFINITE) == WAIT_FAILED)
  109. Sleep(0);
  110. if(InterlockedDecrement(&m_lJustResumed) == 0)
  111. {
  112. // The first call after resumption
  113. return S_OK;
  114. }
  115. else
  116. {
  117. // weren't halted
  118. return S_FALSE;
  119. }
  120. }
  121. BOOL CHaltable::IsHalted()
  122. {
  123. // Approximate!
  124. return m_dwHaltCount > 0;
  125. }
  126. CWbemCriticalSection::CWbemCriticalSection( void )
  127. : m_lLock( -1 ), m_lRecursionCount( 0 ), m_dwThreadId( 0 ), m_hEvent( NULL )
  128. {
  129. m_hEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
  130. if ( NULL == m_hEvent )
  131. {
  132. throw CX_MemoryException();
  133. }
  134. }
  135. CWbemCriticalSection::~CWbemCriticalSection( void )
  136. {
  137. if ( NULL != m_hEvent )
  138. {
  139. CloseHandle( m_hEvent );
  140. m_hEvent = NULL;
  141. }
  142. }
  143. BOOL CWbemCriticalSection::Enter( DWORD dwTimeout /* = 0xFFFFFFFF */ )
  144. {
  145. BOOL fReturn = FALSE;
  146. // Only do this once
  147. DWORD dwCurrentThreadId = GetCurrentThreadId();
  148. // Check if we are the current owning thread. We can do this here because
  149. // this test will ONLY succeed in the case where we have a Nested Lock(),
  150. // AND because we are zeroing out the thread id when the lock count hits
  151. // 0.
  152. if( dwCurrentThreadId == m_dwThreadId )
  153. {
  154. // It's us - Bump the lock count
  155. // =============================
  156. InterlockedIncrement( &m_lRecursionCount );
  157. return TRUE;
  158. }
  159. // 0 means we got the lock
  160. if ( 0 == InterlockedIncrement( &m_lLock ) )
  161. {
  162. m_dwThreadId = dwCurrentThreadId;
  163. m_lRecursionCount = 1;
  164. fReturn = TRUE;
  165. }
  166. else
  167. {
  168. // We wait. If we got a signalled event, then we now own the
  169. // critical section. Otherwise, we should perform an InterlockedDecrement
  170. // to account for the Increment that got us here in the first place.
  171. if ( WaitForSingleObject( m_hEvent, dwTimeout ) == WAIT_OBJECT_0 )
  172. {
  173. m_dwThreadId = dwCurrentThreadId;
  174. m_lRecursionCount = 1;
  175. fReturn = TRUE;
  176. }
  177. else
  178. {
  179. InterlockedDecrement( &m_lLock );
  180. }
  181. }
  182. return fReturn;
  183. }
  184. void CWbemCriticalSection::Leave( void )
  185. {
  186. // We don't check the thread id, so we can lock/unlock resources
  187. // across multiple threads
  188. BOOL fReturn = FALSE;
  189. long lRecurse = InterlockedDecrement( &m_lRecursionCount );
  190. // The recursion count hit zero, so it's time to unlock the object
  191. if ( 0 == lRecurse )
  192. {
  193. // If the lock count is >= 0, threads are waiting, so we need to
  194. // signal the event
  195. m_dwThreadId = 0;
  196. if ( InterlockedDecrement( &m_lLock ) >= 0 )
  197. {
  198. SetEvent( m_hEvent );
  199. }
  200. } // If recursion count is at 0
  201. }