Leaked source code of windows server 2003
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.

432 lines
12 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // File: olesem.cxx
  4. //
  5. // Contents: Implementation of semaphore classes for use in OLE code
  6. //
  7. // Functions: COleStaticMutexSem::Destroy
  8. // COleStaticMutexSem::Request
  9. // COleStaticMutexSem::Init
  10. // COleDebugMutexSem::COleDebugMutexSem
  11. //
  12. // History: 14-Dec-95 Jeffe Initial entry, derived from
  13. // sem32.hxx by AlexT.
  14. //
  15. //
  16. //----------------------------------------------------------------------------
  17. #include <nt.h>
  18. #include <ntrtl.h>
  19. #include <nturtl.h>
  20. #include <ntexapi.h>
  21. #include <windows.h>
  22. #include <debnot.h>
  23. #include <olesem.hxx>
  24. //
  25. // Global state for the mutex package
  26. //
  27. //
  28. // List of initialized static mutexes (which must be destroyed
  29. // during DLL exit). We know that PROCESS_ATTACH and PROCESS_DETACH
  30. // are thread-safe, so we don't protect this list with a critical section.
  31. //
  32. COleStaticMutexSem * g_pInitializedStaticMutexList = NULL;
  33. #if DBG
  34. //
  35. // Flag used to indicate if we're past executing the C++ constructors
  36. // during DLL initialization
  37. //
  38. DLL_STATE g_fDllState = DLL_STATE_STATIC_CONSTRUCTING;
  39. #endif
  40. //
  41. // Semaphore used to protect the creation of other semaphores
  42. //
  43. BOOL gfOleMutexCreationSemOkay = FALSE;
  44. CRITICAL_SECTION g_OleMutexCreationSem;
  45. //
  46. // Critical section used as the backup lock when a COleStaticMutexSem
  47. // cannot be faulted in.
  48. //
  49. BOOL gfOleGlobalLockOkay = FALSE;
  50. CRITICAL_SECTION g_OleGlobalLock;
  51. //
  52. // Just cache the calculated spin count. Keep from calling NtQuerySystemInformation
  53. // a lot.
  54. //
  55. DWORD g_dwComSpinCount = -1;
  56. //+---------------------------------------------------------------------------
  57. //
  58. // Function: CalculateSpinCount()
  59. //
  60. // Synopsis: Calculate the spin count to use in a critical section.
  61. // We use 500 * the number of processors on the system. Note
  62. // that spin counts are ignored on single proc systems, since
  63. // it just don't help.
  64. //
  65. // History: 28-Feb-02 JohnDoty Created.
  66. //
  67. //----------------------------------------------------------------------------
  68. DWORD CalculateSpinCount()
  69. {
  70. if (g_dwComSpinCount == -1)
  71. {
  72. DWORD dwSpinCount = 500;
  73. SYSTEM_BASIC_INFORMATION si = {0};
  74. NTSTATUS status = NtQuerySystemInformation(SystemBasicInformation,&si,sizeof(si),NULL);
  75. if (NT_SUCCESS(status))
  76. dwSpinCount = 500 * si.NumberOfProcessors;
  77. g_dwComSpinCount = dwSpinCount;
  78. }
  79. return g_dwComSpinCount;
  80. }
  81. //+---------------------------------------------------------------------------
  82. //
  83. // Member: COleStaticMutexSem::Destroy
  84. //
  85. // Synopsis: Releases a semaphore's critical section.
  86. //
  87. // History: 14-Dec-1995 Jeffe
  88. //
  89. //----------------------------------------------------------------------------
  90. void COleStaticMutexSem::Destroy()
  91. {
  92. #if LOCK_PERF==1
  93. gLockTracker.ReportContention(this, _cs.LockCount, _cs.DebugInfo->ContentionCount, 0 , 0); //entry,contention counts for writes & reads.
  94. #endif
  95. if (_fInitialized)
  96. {
  97. DeleteCriticalSection (&_cs);
  98. _fInitialized = FALSE;
  99. }
  100. }
  101. //+---------------------------------------------------------------------------
  102. //
  103. // Member: COleStaticMutexSem::Request
  104. //
  105. // Synopsis: Acquire the semaphore. If another thread already has it,
  106. // wait until it is released. Initialize the semaphore if it
  107. // isn't already initialized.
  108. //
  109. // History: 14-Dec-1995 Jeffe
  110. //
  111. //----------------------------------------------------------------------------
  112. void COleStaticMutexSem::Request(const char *pszFile, DWORD dwLine, const char *pszLockName)
  113. {
  114. if (!_fInitialized && !_fUsingGlobal)
  115. {
  116. EnterCriticalSection (&g_OleMutexCreationSem);
  117. if (!_fInitialized && !_fUsingGlobal) {
  118. Init();
  119. if (!_fInitialized) _fUsingGlobal = TRUE;
  120. }
  121. LeaveCriticalSection (&g_OleMutexCreationSem);
  122. }
  123. #if LOCK_PERF==1
  124. gLockTracker.WriterWaiting(pszFile, dwLine, pszLockName, this);
  125. #endif
  126. // What do we do if either of these fail?
  127. if (!_fUsingGlobal)
  128. EnterCriticalSection (&_cs);
  129. else
  130. EnterCriticalSection (&g_OleGlobalLock);
  131. #if LOCK_PERF==1
  132. gLockTracker.WriterEntered(pszFile, dwLine, pszLockName, this); //the tracker takes cares of recursive Lock calls.
  133. #endif
  134. Win4Assert((((_dwTid == 0 && _cLocks == 0) || (_dwTid == GetCurrentThreadId() && _cLocks > 0)) ||
  135. (g_fDllState == DLL_STATE_PROCESS_DETACH)) &&
  136. "Inconsistent State!");
  137. Win4Assert(!(_fTakeOnce && _cLocks > 1) && "Lock taken more than once on same thread.");
  138. #if DBG==1 || LOCK_PERF==1
  139. if(_dwTid != GetCurrentThreadId())
  140. {
  141. if (g_fDllState != DLL_STATE_PROCESS_DETACH)
  142. {
  143. Win4Assert (_cLocks == 0);
  144. }
  145. else
  146. {
  147. _cLocks = 0;
  148. }
  149. _dwTid = GetCurrentThreadId();
  150. }
  151. #endif
  152. // only stamp the file on the
  153. // 0 -> 1 transition
  154. if (++_cLocks == 1)
  155. {
  156. _pszFile = pszFile;
  157. _dwLine = dwLine;
  158. }
  159. }
  160. //+---------------------------------------------------------------------------
  161. //
  162. // Member: COleStaticMutexSem::AssertHeld
  163. //
  164. // Synopsis: Check to see if this thread owns the lock, and optionally owns
  165. // cLocks amount of locks. If not raise an assertion warning.
  166. //
  167. // History: 16-Aug-1996 mattsmit
  168. //
  169. // Notes: Debug builds only
  170. //----------------------------------------------------------------------------
  171. #if DBG==1
  172. void COleStaticMutexSem::AssertHeld(DWORD cLocks)
  173. {
  174. Win4Assert(_dwTid == GetCurrentThreadId() && "Lock not held by current thread.");
  175. if (cLocks == 0)
  176. {
  177. Win4Assert(_cLocks > 0 && "Lock held by thread with a nonpositive lock count");
  178. }
  179. else
  180. {
  181. Win4Assert(_cLocks == cLocks && "Incorrect amount of locks");
  182. }
  183. }
  184. #endif
  185. //+---------------------------------------------------------------------------
  186. //
  187. // Member: COleStaticMutexSem::AssertNotHeld
  188. //
  189. // Synopsis: Check to see if this does not thread own the lock. If it does,
  190. // raise an assertion warning.
  191. //
  192. // History: 16-Aug-1996 mattsmit
  193. //
  194. // Notes: Debug builds only
  195. //----------------------------------------------------------------------------
  196. #if DBG==1
  197. void COleStaticMutexSem::AssertNotHeld()
  198. {
  199. Win4Assert(_dwTid != GetCurrentThreadId() && "Lock held by current thread.");
  200. }
  201. #endif
  202. //+---------------------------------------------------------------------------
  203. //
  204. // Member: COleStaticMutexSem::AssertTakenOnlyOnce
  205. //
  206. // Synopsis: Turn on flag to insure this lock is taken only once
  207. //
  208. // History: 16-Aug-1996 mattsmit
  209. //
  210. // Notes: Debug builds only
  211. //----------------------------------------------------------------------------
  212. #if DBG==1
  213. void COleStaticMutexSem::AssertTakenOnlyOnce()
  214. {
  215. _fTakeOnce = TRUE;
  216. }
  217. #endif
  218. //+---------------------------------------------------------------------------
  219. //
  220. // Member: COleStaticMutexSem::Init
  221. //
  222. // Synopsis: Initialize semaphore's critical section
  223. //
  224. // History: 14-Dec-1995 Jeffe
  225. //
  226. //----------------------------------------------------------------------------
  227. HRESULT COleStaticMutexSem::Init()
  228. {
  229. NTSTATUS status;
  230. if (_fInitialized)
  231. return S_OK;
  232. if (_fUseSpincount)
  233. {
  234. DWORD dwSpinCount = CalculateSpinCount();
  235. status = RtlInitializeCriticalSectionAndSpinCount(&_cs, dwSpinCount);
  236. }
  237. else
  238. {
  239. status = RtlInitializeCriticalSection (&_cs);
  240. }
  241. _fInitialized = NT_SUCCESS(status);
  242. if (!_fAutoDestruct)
  243. {
  244. //
  245. // We don't need to protect this list with a mutex, since it's only
  246. // manipulated during DLL attach/detach, which is single threaded by
  247. // the platform.
  248. //
  249. pNextMutex = g_pInitializedStaticMutexList;
  250. g_pInitializedStaticMutexList = this;
  251. }
  252. #if LOCK_PERF==1
  253. gLockTracker.RegisterLock(this, FALSE /*bReadWrite*/);
  254. #endif
  255. if (NT_SUCCESS(status))
  256. return S_OK;
  257. else
  258. return HRESULT_FROM_WIN32(status);
  259. }
  260. //+---------------------------------------------------------------------------
  261. //
  262. // Member: COleStaticMutexSem::Release
  263. //
  264. // Synopsis: Release the semaphore.
  265. //
  266. // History: 14-Dec-1995 Jeffe
  267. //
  268. //----------------------------------------------------------------------------
  269. void COleStaticMutexSem::Release()
  270. {
  271. AssertHeld();
  272. if (--_cLocks == 0)
  273. {
  274. Win4Assert((_cContinuous == 0) ||
  275. (g_fDllState == DLL_STATE_PROCESS_DETACH));
  276. #if DBG==1 || LOCK_PERF==1
  277. _dwTid = 0;
  278. #endif
  279. Win4Assert(_cContinuous==0);
  280. }
  281. #if LOCK_PERF==1
  282. gLockTracker.WriterLeaving(this);
  283. #endif
  284. if (!_fUsingGlobal)
  285. LeaveCriticalSection (&_cs);
  286. else
  287. LeaveCriticalSection (&g_OleGlobalLock);
  288. }
  289. //+---------------------------------------------------------------------------
  290. //
  291. // Member: CMutexSem2::CMutexSem2
  292. //
  293. // Synopsis: Mutex semaphore constructor. This is a 2-phase constructed object.
  294. // You must call CMutexSem2::Init to fully initialize the object.
  295. //
  296. // Effects: Initializes the semaphores data
  297. //
  298. // History: 19-Mar-01 danroth Created.
  299. //
  300. //----------------------------------------------------------------------------
  301. CMutexSem2::CMutexSem2(void) : m_fCsInitialized(FALSE)
  302. {
  303. }
  304. BOOL CMutexSem2::FInit()
  305. {
  306. if (m_fCsInitialized == FALSE) // guard against re-entry
  307. {
  308. NTSTATUS status = RtlInitializeCriticalSection(&m_cs);
  309. if (NT_SUCCESS(status))
  310. {
  311. m_fCsInitialized = TRUE;
  312. }
  313. }
  314. return m_fCsInitialized;
  315. };
  316. //+---------------------------------------------------------------------------
  317. //
  318. // Member: CMutexSem2::~CMutexSem2, public
  319. //
  320. // Synopsis: Mutex semaphore destructor
  321. //
  322. // Effects: Releases semaphore data
  323. //
  324. // History: 19-Mar-01 danroth Created.
  325. //
  326. //----------------------------------------------------------------------------
  327. CMutexSem2::~CMutexSem2(void)
  328. {
  329. if (m_fCsInitialized == TRUE)
  330. {
  331. #ifdef _DEBUG
  332. NTSTATUS status =
  333. #endif
  334. RtlDeleteCriticalSection(&m_cs); // if RtlDeleteCriticalSection fails, tough luck--we leak.
  335. #ifdef _DEBUG // But I'm asserting for it to see if we ever really hit it.
  336. Win4Assert(NT_SUCCESS(status));
  337. #endif
  338. }
  339. }
  340. //+---------------------------------------------------------------------------
  341. //
  342. // Member: CMutexSem2::Request, public
  343. //
  344. // Synopsis: Enter critical section
  345. //
  346. // Effects: Asserts correct owner
  347. //
  348. // History: 19-Mar-01 danroth Created.
  349. //
  350. //
  351. //----------------------------------------------------------------------------
  352. void CMutexSem2::Request(void)
  353. {
  354. Win4Assert(m_fCsInitialized == TRUE);
  355. if (m_fCsInitialized == TRUE)
  356. EnterCriticalSection(&m_cs);
  357. }
  358. //+---------------------------------------------------------------------------
  359. //
  360. // Member: CMutexSem2::Release, public
  361. //
  362. // Synopsis: Release semaphore
  363. //
  364. // Effects: Leave critical section
  365. //
  366. // History: 19-Mar-01 danroth Created.
  367. //
  368. //----------------------------------------------------------------------------
  369. void CMutexSem2::Release(void)
  370. {
  371. Win4Assert(m_fCsInitialized == TRUE);
  372. if (m_fCsInitialized == TRUE)
  373. LeaveCriticalSection(&m_cs);
  374. }