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.

523 lines
14 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. CRITICAL_SECTION g_OleMutexCreationSem;
  44. //
  45. // Critical section used as the backup lock when a COleStaticMutexSem
  46. // cannot be faulted in.
  47. //
  48. CRITICAL_SECTION g_OleGlobalLock;
  49. //+---------------------------------------------------------------------------
  50. //
  51. // Member: COleStaticMutexSem::Destroy
  52. //
  53. // Synopsis: Releases a semaphore's critical section.
  54. //
  55. // History: 14-Dec-1995 Jeffe
  56. //
  57. //----------------------------------------------------------------------------
  58. void COleStaticMutexSem::Destroy()
  59. {
  60. #if LOCK_PERF==1
  61. gLockTracker.ReportContention(this, _cs.LockCount, _cs.DebugInfo->ContentionCount, 0 , 0); //entry,contention counts for writes & reads.
  62. #endif
  63. if (_fInitialized)
  64. {
  65. DeleteCriticalSection (&_cs);
  66. _fInitialized = FALSE;
  67. }
  68. }
  69. //+---------------------------------------------------------------------------
  70. //
  71. // Member: COleStaticMutexSem::FastRequest
  72. //
  73. // Synopsis: Acquire the semaphore without checking to see if it's
  74. // initialized. If another thread already has it,
  75. // wait until it is released.
  76. //
  77. // History: 14-Dec-1995 Jeffe
  78. //
  79. // Notes: You may only use this method on code paths where you're
  80. // *certain* the semaphore has already been initialized (either
  81. // by invoking Init, or by calling the Request method).
  82. // These version's of FastRequest are for debug builds. The
  83. // version's for retail builds are inline and are found in
  84. // olesem.hxx
  85. //
  86. //----------------------------------------------------------------------------
  87. #if DBG==1 || LOCK_PERF==1
  88. void COleStaticMutexSem::FastRequest(const char *pszFile, DWORD dwLine, const char *pszLockName)
  89. {
  90. Win4Assert (_fInitialized && "You must use Request here, not FastRequest");
  91. #if LOCK_PERF==1
  92. gLockTracker.WriterWaiting(pszFile, dwLine, pszLockName, this);
  93. #endif
  94. if (!_fUsingGlobal)
  95. EnterCriticalSection (&_cs);
  96. else
  97. EnterCriticalSection (&g_OleGlobalLock);
  98. #if LOCK_PERF==1
  99. gLockTracker.WriterEntered(pszFile, dwLine, pszLockName, this);
  100. #endif
  101. Win4Assert(((_dwTid == 0 && _cLocks == 0) || (_dwTid == GetCurrentThreadId() && _cLocks > 0)) && "Inconsistent state!");
  102. Win4Assert(!(_fTakeOnce && _cLocks > 1) && "Lock taken more than once on same thread.");
  103. _dwTid = GetCurrentThreadId();
  104. _cLocks++;
  105. _pszFile = pszFile;
  106. _dwLine = dwLine;
  107. }
  108. void COleStaticMutexSem::FastRequest()
  109. {
  110. FastRequest("Unknown File", 0L ,"Unknown Lock");
  111. }
  112. #endif //DBG==1 || LOCK_PERF==1
  113. //+---------------------------------------------------------------------------
  114. //
  115. // Member: COleStaticMutexSem::Request
  116. //
  117. // Synopsis: Acquire the semaphore. If another thread already has it,
  118. // wait until it is released. Initialize the semaphore if it
  119. // isn't already initialized.
  120. //
  121. // History: 14-Dec-1995 Jeffe
  122. //
  123. //----------------------------------------------------------------------------
  124. #if DBG==1 || LOCK_PERF==1
  125. void COleStaticMutexSem::Request(const char *pszFile, DWORD dwLine, const char *pszLockName)
  126. {
  127. if (!_fInitialized && !_fUsingGlobal)
  128. {
  129. EnterCriticalSection (&g_OleMutexCreationSem);
  130. if (!_fInitialized && !_fUsingGlobal) {
  131. Init();
  132. if (!_fInitialized) _fUsingGlobal = TRUE;
  133. }
  134. LeaveCriticalSection (&g_OleMutexCreationSem);
  135. }
  136. #if LOCK_PERF==1
  137. gLockTracker.WriterWaiting(pszFile, dwLine, pszLockName, this);
  138. #endif
  139. // What do we do if either of these fail?
  140. if (!_fUsingGlobal)
  141. EnterCriticalSection (&_cs);
  142. else
  143. EnterCriticalSection (&g_OleGlobalLock);
  144. #if LOCK_PERF==1
  145. gLockTracker.WriterEntered(pszFile, dwLine, pszLockName, this); //the tracker takes cares of recursive Lock calls.
  146. #endif
  147. Win4Assert((((_dwTid == 0 && _cLocks == 0) || (_dwTid == GetCurrentThreadId() && _cLocks > 0)) ||
  148. (g_fDllState == DLL_STATE_PROCESS_DETACH)) &&
  149. "Inconsistent State!");
  150. Win4Assert(!(_fTakeOnce && _cLocks > 1) && "Lock taken more than once on same thread.");
  151. if(_dwTid != GetCurrentThreadId())
  152. {
  153. _cLocks = 0;
  154. _dwTid = GetCurrentThreadId();
  155. }
  156. // only stamp the file on the
  157. // 0 -> 1 transition
  158. if (++_cLocks == 1)
  159. {
  160. _pszFile = pszFile;
  161. _dwLine = dwLine;
  162. }
  163. }
  164. #endif //DBG==1 || LOCK_PERF==1
  165. void COleStaticMutexSem::Request()
  166. {
  167. #if DBG==1 || LOCK_PERF==1
  168. Request("Unknown File", 0L,"Unknown Lock");
  169. #else
  170. if (!_fInitialized && !_fUsingGlobal)
  171. {
  172. EnterCriticalSection (&g_OleMutexCreationSem);
  173. if (!_fInitialized && !_fUsingGlobal)
  174. {
  175. Init();
  176. if (!_fInitialized) _fUsingGlobal = TRUE;
  177. }
  178. LeaveCriticalSection (&g_OleMutexCreationSem);
  179. }
  180. if (!_fUsingGlobal)
  181. EnterCriticalSection (&_cs);
  182. else
  183. EnterCriticalSection (&g_OleGlobalLock);
  184. #endif
  185. }
  186. //+---------------------------------------------------------------------------
  187. //
  188. // Member: COleStaticMutexSem::AssertHeld
  189. //
  190. // Synopsis: Check to see if this thread owns the lock, and optionally owns
  191. // cLocks amount of locks. If not raise an assertion warning.
  192. //
  193. // History: 16-Aug-1996 mattsmit
  194. //
  195. // Notes: Debug builds only
  196. //----------------------------------------------------------------------------
  197. #if DBG==1
  198. void COleStaticMutexSem::AssertHeld(DWORD cLocks)
  199. {
  200. Win4Assert(_dwTid == GetCurrentThreadId() && "Lock not held by current thread.");
  201. if (cLocks == 0)
  202. {
  203. Win4Assert(_cLocks > 0 && "Lock held by thread with a nonpositive lock count");
  204. }
  205. else
  206. {
  207. Win4Assert(_cLocks == cLocks && "Incorrect amount of locks");
  208. }
  209. }
  210. #endif
  211. //+---------------------------------------------------------------------------
  212. //
  213. // Member: COleStaticMutexSem::AssertNotHeld
  214. //
  215. // Synopsis: Check to see if this does not thread own the lock. If it does,
  216. // raise an assertion warning.
  217. //
  218. // History: 16-Aug-1996 mattsmit
  219. //
  220. // Notes: Debug builds only
  221. //----------------------------------------------------------------------------
  222. #if DBG==1
  223. void COleStaticMutexSem::AssertNotHeld()
  224. {
  225. Win4Assert(_dwTid != GetCurrentThreadId() && "Lock held by current thread.");
  226. }
  227. #endif
  228. //+---------------------------------------------------------------------------
  229. //
  230. // Member: COleStaticMutexSem::AssertTakenOnlyOnce
  231. //
  232. // Synopsis: Turn on flag to insure this lock is taken only once
  233. //
  234. // History: 16-Aug-1996 mattsmit
  235. //
  236. // Notes: Debug builds only
  237. //----------------------------------------------------------------------------
  238. #if DBG==1
  239. void COleStaticMutexSem::AssertTakenOnlyOnce()
  240. {
  241. _fTakeOnce = TRUE;
  242. }
  243. #endif
  244. //+---------------------------------------------------------------------------
  245. //
  246. // Member: COleStaticMutexSem::Init
  247. //
  248. // Synopsis: Initialize semaphore's critical section
  249. //
  250. // History: 14-Dec-1995 Jeffe
  251. //
  252. //----------------------------------------------------------------------------
  253. HRESULT COleStaticMutexSem::Init()
  254. {
  255. NTSTATUS status;
  256. if (_fInitialized)
  257. return S_OK;
  258. if (_fUseSpincount)
  259. {
  260. DWORD dwSpincount = 500;
  261. SYSTEM_BASIC_INFORMATION si = {0};
  262. status = NtQuerySystemInformation(SystemBasicInformation,&si,sizeof(si),NULL);
  263. if (NT_SUCCESS(status))
  264. dwSpincount *= si.NumberOfProcessors;
  265. status = RtlInitializeCriticalSectionAndSpinCount(&_cs, dwSpincount);
  266. }
  267. else
  268. {
  269. status = RtlInitializeCriticalSection (&_cs);
  270. }
  271. _fInitialized = NT_SUCCESS(status);
  272. if (!_fAutoDestruct)
  273. {
  274. //
  275. // We don't need to protect this list with a mutex, since it's only
  276. // manipulated during DLL attach/detach, which is single threaded by
  277. // the platform.
  278. //
  279. pNextMutex = g_pInitializedStaticMutexList;
  280. g_pInitializedStaticMutexList = this;
  281. }
  282. #if LOCK_PERF==1
  283. gLockTracker.RegisterLock(this, FALSE /*bReadWrite*/);
  284. #endif
  285. if (NT_SUCCESS(status))
  286. return S_OK;
  287. else
  288. return HRESULT_FROM_WIN32(status);
  289. }
  290. //+---------------------------------------------------------------------------
  291. //
  292. // Member: COleStaticMutexSem::Release
  293. //
  294. // Synopsis: Release the semaphore.
  295. //
  296. // History: 14-Dec-1995 Jeffe
  297. //
  298. //----------------------------------------------------------------------------
  299. #if DBG==1 || LOCK_PERF==1
  300. void COleStaticMutexSem::Release()
  301. {
  302. AssertHeld();
  303. if (--_cLocks == 0)
  304. {
  305. Win4Assert((_cContinuous == 0) ||
  306. (g_fDllState == DLL_STATE_PROCESS_DETACH));
  307. _dwTid = 0;
  308. Win4Assert(_cContinuous==0);
  309. }
  310. #if LOCK_PERF==1
  311. gLockTracker.WriterLeaving(this);
  312. #endif
  313. if (!_fUsingGlobal)
  314. LeaveCriticalSection (&_cs);
  315. else
  316. LeaveCriticalSection (&g_OleGlobalLock);
  317. }
  318. #endif // DBG==1 || LOCK_PERF==1
  319. #ifdef _CHICAGO_
  320. //+---------------------------------------------------------------------------
  321. //
  322. // Member: COleStaticMutexSem::ReleaseFn
  323. //
  324. // Synopsis: Release the semaphore(non inline version) used only by rpccall.asm
  325. //
  326. // History: 14-Dec-1995 Jeffe
  327. //
  328. //----------------------------------------------------------------------------
  329. void COleStaticMutexSem::ReleaseFn()
  330. {
  331. #if DBG==1
  332. AssertHeld();
  333. if (--_cLocks == 0)
  334. {
  335. _dwTid = 0;
  336. }
  337. #endif
  338. if (!_fUsingGlobal)
  339. LeaveCriticalSection (&_cs);
  340. else
  341. LeaveCriticalSection (&g_OleGlobalLock);
  342. }
  343. #endif
  344. #if DBG==1
  345. //+---------------------------------------------------------------------------
  346. //
  347. // Member: COleDebugMutexSem::COleDebugMutexSem
  348. //
  349. // Synopsis: Mark the mutex as dynamic...which will prevent it from being
  350. // added to the static mutex cleanup list on DLL unload.
  351. //
  352. // History: 14-Dec-1995 Jeffe
  353. //
  354. // Notes: We don't care that this has a constructor, as it won't be run
  355. // in retail builds.
  356. //
  357. //----------------------------------------------------------------------------
  358. COleDebugMutexSem::COleDebugMutexSem()
  359. {
  360. Win4Assert (g_fDllState == DLL_STATE_STATIC_CONSTRUCTING);
  361. _fAutoDestruct = TRUE;
  362. _fInitialized = FALSE;
  363. }
  364. #endif // DBG==1
  365. //+---------------------------------------------------------------------------
  366. //
  367. // Member: CMutexSem2::CMutexSem2
  368. //
  369. // Synopsis: Mutex semaphore constructor. This is a 2-phase constructed object.
  370. // You must call CMutexSem2::Init to fully initialize the object.
  371. //
  372. // Effects: Initializes the semaphores data
  373. //
  374. // History: 19-Mar-01 danroth Created.
  375. //
  376. //----------------------------------------------------------------------------
  377. CMutexSem2::CMutexSem2(void) : m_fCsInitialized(FALSE)
  378. {
  379. }
  380. BOOL CMutexSem2::FInit()
  381. {
  382. if (m_fCsInitialized == FALSE) // guard against re-entry
  383. {
  384. NTSTATUS status = RtlInitializeCriticalSection(&m_cs);
  385. if (NT_SUCCESS(status))
  386. {
  387. m_fCsInitialized = TRUE;
  388. }
  389. }
  390. return m_fCsInitialized;
  391. };
  392. //+---------------------------------------------------------------------------
  393. //
  394. // Member: CMutexSem2::~CMutexSem2, public
  395. //
  396. // Synopsis: Mutex semaphore destructor
  397. //
  398. // Effects: Releases semaphore data
  399. //
  400. // History: 19-Mar-01 danroth Created.
  401. //
  402. //----------------------------------------------------------------------------
  403. CMutexSem2::~CMutexSem2(void)
  404. {
  405. if (m_fCsInitialized == TRUE)
  406. {
  407. #ifdef _DEBUG
  408. NTSTATUS status =
  409. #endif
  410. RtlDeleteCriticalSection(&m_cs); // if RtlDeleteCriticalSection fails, tough luck--we leak.
  411. #ifdef _DEBUG // But I'm asserting for it to see if we ever really hit it.
  412. Win4Assert(NT_SUCCESS(status));
  413. #endif
  414. }
  415. }
  416. //+---------------------------------------------------------------------------
  417. //
  418. // Member: CMutexSem2::Request, public
  419. //
  420. // Synopsis: Enter critical section
  421. //
  422. // Effects: Asserts correct owner
  423. //
  424. // History: 19-Mar-01 danroth Created.
  425. //
  426. //
  427. //----------------------------------------------------------------------------
  428. void CMutexSem2::Request(void)
  429. {
  430. Win4Assert(m_fCsInitialized == TRUE);
  431. if (m_fCsInitialized == TRUE)
  432. EnterCriticalSection(&m_cs);
  433. }
  434. //+---------------------------------------------------------------------------
  435. //
  436. // Member: CMutexSem2::Release, public
  437. //
  438. // Synopsis: Release semaphore
  439. //
  440. // Effects: Leave critical section
  441. //
  442. // History: 19-Mar-01 danroth Created.
  443. //
  444. //----------------------------------------------------------------------------
  445. void CMutexSem2::Release(void)
  446. {
  447. Win4Assert(m_fCsInitialized == TRUE);
  448. if (m_fCsInitialized == TRUE)
  449. LeaveCriticalSection(&m_cs);
  450. }