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.

559 lines
18 KiB

  1. ///+---------------------------------------------------------------------------
  2. //
  3. // File: olesem.hxx
  4. //
  5. // Contents: Semaphore classes for use in OLE code
  6. //
  7. // Classes: COleStaticMutexSem - Mutex semaphore class for statically
  8. // allocated objects
  9. // COleDebugMutexSem - Mutex semaphore class for statically
  10. // allocated objects that are not destructed
  11. // on DLL unload (and thus are leaks..used
  12. // for trace packages and such).
  13. //
  14. // History: 14-Dec-95 Jeffe Initial entry, derived from
  15. // sem32.hxx by AlexT.
  16. //
  17. // Notes: This module defines a set of classes to wrap WIN32
  18. // Critical Sections.
  19. //
  20. // Note the distinction of allocation class: the reason for this
  21. // is to avoid static constructors and destructors.
  22. //
  23. // The classes in this module *must* be used for mutex semaphores
  24. // that are statically allocated. Use the classes in sem32.hxx
  25. // for dynamically allocated (from heap or on the stack) objects.
  26. //
  27. //----------------------------------------------------------------------------
  28. #ifndef __OLESEM_HXX__
  29. #define __OLESEM_HXX__
  30. #include <windows.h>
  31. #if LOCK_PERF==1
  32. #include <lockperf.hxx>
  33. #endif
  34. //+---------------------------------------------------------------------------
  35. //
  36. // Macros for use in the code.
  37. //
  38. //----------------------------------------------------------------------------
  39. #if DBG==1
  40. #if LOCK_PERF==1
  41. #define LOCK_WRITE(mxs) mxs.AcquireWriterLock(__FILE__, __LINE__, #mxs)
  42. #define LOCK_READ(mxs) mxs.AcquireReaderLock(__FILE__, __LINE__, #mxs)
  43. #else
  44. #define LOCK_WRITE(mxs) mxs.AcquireWriterLock()
  45. #define LOCK_READ(mxs) mxs.AcquireReaderLock()
  46. #endif
  47. #define LOCK(mxs) mxs.Request(__FILE__, __LINE__, #mxs)
  48. #define FAST_LOCK(mxs) mxs.FastRequest(__FILE, __LINE__, #mxs)
  49. #define UNLOCK_WRITE(mxs) mxs.ReleaseWriterLock()
  50. #define UNLOCK_READ(mxs) mxs.ReleaseReaderLock()
  51. #define UNLOCK(mxs) mxs.Release()
  52. #if LOCK_PERF==1
  53. #define LOCK_UPGRADE(mxs, ck, f) mxs.UpgradeToWriterLock(ck, f, __FILE__, __LINE__, #mxs)
  54. #define LOCK_DOWNGRADE(mxs, ck) mxs.DowngradeFromWriterLock(ck, __FILE__, __LINE__, #mxs)
  55. #define LOCK_RESTORE(mxs, ck) mxs.RestoreLock(ck, NULL, __FILE__, __LINE__, #mxs)
  56. #else
  57. #define LOCK_UPGRADE(mxs, ck, f) mxs.UpgradeToWriterLock(ck, f)
  58. #define LOCK_DOWNGRADE(mxs, ck) mxs.DowngradeFromWriterLock(ck)
  59. #define LOCK_RESTORE(mxs, ck) mxs.RestoreLock(ck)
  60. #endif
  61. #define LOCK_RELEASE(mxs, ck) mxs.ReleaseLock(ck)
  62. #define ASSERT_LOCK_HELD(mxs) mxs.AssertHeld()
  63. #define ASSERT_LOCK_NOT_HELD(mxs) mxs.AssertNotHeld()
  64. #define ASSERT_LOCK_DONTCARE(mxs) // just exists to comment the code better
  65. #define ASSERT_LOCK_TAKEN_ONLY_ONCE(mxs) mxs.AssertTakenOnlyOnce()
  66. #define ASSERT_HELD_CONTINUOS_START(mxs) mxs.AssetHeldContinousStart()
  67. #define ASSERT_HELD_CONTINUOS_FINISH(mxs) mxs.AssetHeldContinousFinish()
  68. #define ASSERT_WRITE_LOCK_HELD(mxs) mxs.AssertWriterLockHeld()
  69. #define ASSERT_READ_LOCK_HELD(mxs) mxs.AssertReaderLockHeld()
  70. #define ASSERT_RORW_LOCK_HELD(mxs) mxs.AssertReaderOrWriterLockHeld()
  71. #define STATIC_LOCK(name, mxs) COleStaticLock name(mxs, __FILE__, __LINE__, #mxs)
  72. #define STATIC_WRITE_LOCK(name, mxs) CStaticWriteLock name(mxs, __FILE__, __LINE__, #mxs)
  73. #else // DBG!=1
  74. #if LOCK_PERF==1
  75. #define LOCK_WRITE(mxs) mxs.AcquireWriterLock(__FILE__, __LINE__, #mxs)
  76. #define LOCK_READ(mxs) mxs.AcquireReaderLock(__FILE__, __LINE__, #mxs)
  77. #define LOCK(mxs) mxs.Request(__FILE__, __LINE__, #mxs)
  78. #define FAST_LOCK(mxs) mxs.FastRequest(__FILE__, __LINE__,#mxs)
  79. #else
  80. #define LOCK_WRITE(mxs) mxs.AcquireWriterLock()
  81. #define LOCK_READ(mxs) mxs.AcquireReaderLock()
  82. #define LOCK(mxs) mxs.Request()
  83. #define FAST_LOCK(mxs) mxs.FastRequest()
  84. #endif
  85. #define UNLOCK_WRITE(mxs) mxs.ReleaseWriterLock()
  86. #define UNLOCK_READ(mxs) mxs.ReleaseReaderLock()
  87. #define UNLOCK(mxs) mxs.Release()
  88. #if LOCK_PERF==1
  89. #define LOCK_UPGRADE(mxs, ck, f) mxs.UpgradeToWriterLock(ck, f, __FILE__, __LINE__, #mxs)
  90. #define LOCK_DOWNGRADE(mxs, ck) mxs.DowngradeFromWriterLock(ck, __FILE__, __LINE__, #mxs)
  91. #define LOCK_RESTORE(mxs, ck) mxs.RestoreLock(ck, NULL, __FILE__, __LINE__, #mxs)
  92. #else
  93. #define LOCK_UPGRADE(mxs, ck, f) mxs.UpgradeToWriterLock(ck, f)
  94. #define LOCK_DOWNGRADE(mxs, ck) mxs.DowngradeFromWriterLock(ck)
  95. #define LOCK_RESTORE(mxs, ck) mxs.RestoreLock(ck)
  96. #endif
  97. #define LOCK_RELEASE(mxs, ck) mxs.ReleaseLock(ck)
  98. #define ASSERT_LOCK_HELD(mxs)
  99. #define ASSERT_LOCK_NOT_HELD(mxs)
  100. #define ASSERT_LOCK_DONTCARE(mxs)
  101. #define ASSERT_LOCK_TAKEN_ONLY_ONCE(mxs)
  102. #define ASSERT_HELD_CONTINUOS_START(mxs)
  103. #define ASSERT_HELD_CONTINUOS_FINISH(mxs)
  104. #define ASSERT_WRITE_LOCK_HELD(mxs)
  105. #define ASSERT_READ_LOCK_HELD(mxs)
  106. #define ASSERT_RORW_LOCK_HELD(mxs)
  107. #if LOCK_PERF==1
  108. #define STATIC_LOCK(name, mxs) COleStaticLock name(mxs,__FILE__, __LINE__,#mxs)
  109. #define STATIC_WRITE_LOCK(name, mxs) CStaticWriteLock name(mxs, __FILE__, __LINE__,#mxs)
  110. #else
  111. #define STATIC_LOCK(name, mxs) COleStaticLock name(mxs)
  112. #define STATIC_WRITE_LOCK(name, mxs) CStaticWriteLock name(mxs)
  113. #endif
  114. #endif // DBG!=1
  115. //
  116. // List of initialized static mutexes (which must be destroyed
  117. // during DLL exit). We know that PROCESS_ATTACH and PROCESS_DETACH
  118. // are thread-safe, so we don't protect this list with a critical section.
  119. //
  120. class COleStaticMutexSem;
  121. extern COleStaticMutexSem * g_pInitializedStaticMutexList;
  122. //
  123. // Critical section used to protect the creation of other semaphores
  124. //
  125. extern CRITICAL_SECTION g_OleMutexCreationSem;
  126. //
  127. // Critical section used as the backup lock when a COleStaticMutexSem
  128. // cannot be faulted in.
  129. //
  130. extern CRITICAL_SECTION g_OleGlobalLock;
  131. #if DBG
  132. //
  133. // DLL states used to ensure we don't use the wrong type of
  134. // semaphore at the wrong time
  135. //
  136. typedef enum _DLL_STATE_
  137. {
  138. DLL_STATE_STATIC_CONSTRUCTING = 0,
  139. DLL_STATE_NORMAL,
  140. DLL_STATE_PROCESS_DETACH,
  141. DLL_STATE_STATIC_DESTRUCTING,
  142. DLL_STATE_COUNT
  143. } DLL_STATE, * PDLL_STATE;
  144. //
  145. // Flag used to indicate if we're past executing the C++ constructors
  146. // during DLL initialization
  147. //
  148. extern DLL_STATE g_fDllState;
  149. #endif // DBG
  150. //+---------------------------------------------------------------------------
  151. //
  152. // Class: COleStaticMutexSem (mxs)
  153. //
  154. // Purpose: This class defines a mutual exclusion semaphore for use in
  155. // objects that are statically allocated (extern or static storage
  156. // class).
  157. //
  158. // Interface: FastRequest - acquire semaphore an already-initialized
  159. // semaphore
  160. // Request - acquire semaphore
  161. // Release - release semaphore
  162. // ReleaseFn - release semaphore (non inline version)
  163. //
  164. // History: 14-Dec-95 JeffE Initial entry.
  165. //
  166. // Notes: This class must NOT be used in dynamically allocated objects!
  167. //
  168. // This class uses the fact that static objects are initialized
  169. // by C++ to all zeroes.
  170. //
  171. //----------------------------------------------------------------------------
  172. class COleStaticMutexSem
  173. {
  174. public:
  175. COleStaticMutexSem(BOOLEAN fUseSpincount);
  176. COleStaticMutexSem();
  177. // This pointer *must* be the first member in this class
  178. class COleStaticMutexSem * pNextMutex;
  179. #if DBG==1 || LOCK_PERF==1
  180. private:
  181. // The following track lock usage for debugging purposes
  182. DWORD _dwTid; // Thread id of the thread currently holding the lock, 0 if free
  183. DWORD _cLocks; // Number of times the thread has taken the lock
  184. const char *_pszFile; // Filename of the code which last took the lock
  185. DWORD _dwLine; // Line number of the code which last took the lock
  186. BOOL _fTakeOnce; // Lock is to be taken only once
  187. ULONG _cContinuous;// ensure the lock is not released while count is positive
  188. public:
  189. #if DBG==1 || LOCK_PERF==1
  190. const char *_pszLockName;// Name of the lock (eg. gComLock)
  191. #endif
  192. #endif // DBG==1
  193. BOOLEAN _fInitialized;// has the lock been initialized
  194. BOOLEAN _fUsingGlobal;// are we using the global lock?
  195. BOOLEAN _fAutoDestruct;
  196. BOOLEAN _fUseSpincount;
  197. HRESULT Init();
  198. void Destroy();
  199. #if DBG==1 || LOCK_PERF==1
  200. void FastRequest(const char *pszFile, DWORD dwLine,const char *pszLockName);
  201. inline void FastRequest();
  202. void Request(const char *pszFile, DWORD dwLine, const char *pszLockName);
  203. void Release();
  204. #else // DBG!=1
  205. void FastRequest();
  206. inline void Release();
  207. #endif // DBG==1
  208. void Request();
  209. // debugging/diagnostic functions
  210. #if DBG==1
  211. void AssertHeld(DWORD cLocks=0);
  212. void AssertNotHeld();
  213. void AssertTakenOnlyOnce();
  214. void AssetHeldContinousStart() { _cContinuous++; }
  215. void AssetHeldContinousFinish() { Win4Assert(_cContinuous); _cContinuous--; }
  216. #else // DBG!=1
  217. inline void AssertHeld(DWORD cLocks=0) {;}
  218. inline void AssertNotHeld() {;}
  219. inline void AssertTakenOnlyOnce() {;}
  220. inline void AssetHeldContinousStart() {;}
  221. inline void AssetHeldContinousFinish() {;}
  222. #endif // DBG==1
  223. #ifdef _CHICAGO_
  224. // This is present for rpccall.asm which cannot use the inline version
  225. void ReleaseFn();
  226. #endif // _CHICAGO_
  227. // The following definition *should* be private...but C-10 insists on supplying
  228. // an empty constructor if we use it. Since it doesn't really matter, we just
  229. // don't use it in retail builds.
  230. #if DBG==1
  231. private:
  232. #endif // DBG
  233. CRITICAL_SECTION _cs;
  234. };
  235. #if DBG==1
  236. //+---------------------------------------------------------------------------
  237. //
  238. // Class: COleDebugMutexSem (mxs)
  239. //
  240. // Purpose: This class defines a mutual exclusion semaphore for use in
  241. // objects that are statically allocated (extern or static storage
  242. // class) but are not destructed when the DLL unloads.
  243. //
  244. // Interface: FastRequest - acquire semaphore an already-initialized
  245. // semaphore
  246. // Request - acquire semaphore
  247. // Release - release semaphore
  248. //
  249. // History: 14-Dec-95 JeffE Initial entry.
  250. //
  251. // Notes: This class must only be used in staticly allocated objects!
  252. //
  253. // This class may only be used in CHECKED builds...since it doesn't
  254. // clean up after itself on DLL unload.
  255. //
  256. //----------------------------------------------------------------------------
  257. class COleDebugMutexSem : public COleStaticMutexSem
  258. {
  259. public:
  260. COleDebugMutexSem();
  261. };
  262. #endif // DBG==1
  263. //+---------------------------------------------------------------------------
  264. //
  265. // Class: COleStaticLock (lck)
  266. //
  267. // Purpose: Lock using a static (or debug) Mutex Semaphore
  268. //
  269. // History: 02-Oct-91 BartoszM Created.
  270. //
  271. // Notes: Simple lock object to be created on the stack.
  272. // The constructor acquires the semaphor, the destructor
  273. // (called when lock is going out of scope) releases it.
  274. //
  275. //----------------------------------------------------------------------------
  276. class COleStaticLock
  277. {
  278. public:
  279. #if DBG==1 || LOCK_PERF==1
  280. COleStaticLock ( COleStaticMutexSem& mxs, const char * pszFile, DWORD dwLine, const char *pszLockName );
  281. #endif // DBG==1 || LOCK_PERF==1
  282. COleStaticLock ( COleStaticMutexSem& mxs );
  283. ~COleStaticLock ();
  284. private:
  285. COleStaticMutexSem& _mxs;
  286. };
  287. //+---------------------------------------------------------------------------
  288. //
  289. // Class: CMutexSem2 (mxs)
  290. //
  291. // Purpose: Mutex Semaphore services. Created this version because CMutexSem will
  292. // raise exceptions. CMutexSem2 uses the Rtl* functions and will not raise
  293. // exceptions.
  294. // will not throw
  295. //
  296. // Interface: Init - initializer (two-step)
  297. // Request - acquire semaphore
  298. // Release - release semaphore
  299. //
  300. // History: 19-Mar-01 danroth Created.
  301. //
  302. // Notes: This class wraps a mutex semaphore. Mutex semaphores protect
  303. // access to resources by only allowing one client through at a
  304. // time. The client Requests the semaphore before accessing the
  305. // resource and Releases the semaphore when it is done. The
  306. // same client can Request the semaphore multiple times (a nest
  307. // count is maintained).
  308. // The mutex semaphore is a wrapper around a critical section
  309. // which does not support a timeout mechanism. Therefore the
  310. // usage of any value other than INFINITE is discouraged. It
  311. // is provided merely for compatibility.
  312. //
  313. //----------------------------------------------------------------------------
  314. class CMutexSem2
  315. {
  316. public:
  317. CMutexSem2();
  318. BOOL FInit();
  319. ~CMutexSem2();
  320. void Request();
  321. void Release();
  322. BOOL FInitialized() { return m_fCsInitialized; }
  323. private:
  324. CRITICAL_SECTION m_cs;
  325. BOOL m_fCsInitialized;
  326. };
  327. //+---------------------------------------------------------------------------
  328. //
  329. // Class: CLock2(lck)
  330. //
  331. // Purpose: Lock using a Mutex Semaphore
  332. //
  333. // History: 20-Mar-01 danroth Created.
  334. //
  335. // Notes: Simple lock object to be created on the stack.
  336. // The constructor acquires the semaphor, the destructor
  337. // (called when lock is going out of scope) releases it.
  338. //
  339. //----------------------------------------------------------------------------
  340. class CLock2
  341. {
  342. public:
  343. CLock2(CMutexSem2& mxs) : m_mxs(mxs)
  344. {
  345. m_mxs.Request();
  346. }
  347. ~CLock2() { m_mxs.Release(); }
  348. private:
  349. CMutexSem2& m_mxs;
  350. };
  351. //+---------------------------------------------------------------------------
  352. //
  353. // Member: COleStaticMutexSem::FastRequest
  354. //
  355. // Synopsis: Acquire the semaphore without checking to see if it's
  356. // initialized. If another thread already has it,
  357. // wait until it is released.
  358. //
  359. // History: 14-Dec-1995 Jeffe
  360. //
  361. // Notes: You may only use this method on code paths where you're
  362. // *certain* the semaphore has already been initialized (either
  363. // by invoking Init, or by calling the Request method).
  364. //
  365. //----------------------------------------------------------------------------
  366. #if DBG!=1 && LOCK_PERF!=1
  367. inline void COleStaticMutexSem::FastRequest()
  368. {
  369. Win4Assert (_fInitialized && "You must use Request here, not FastRequest");
  370. if (!_fUsingGlobal)
  371. EnterCriticalSection (&_cs);
  372. else
  373. EnterCriticalSection (&g_OleGlobalLock);
  374. }
  375. #endif // DBG!=1
  376. //+---------------------------------------------------------------------------
  377. //
  378. // Member: COleStaticMutexSem::Release
  379. //
  380. // Synopsis: Release the semaphore.
  381. //
  382. // History: 14-Dec-1995 Jeffe
  383. //
  384. //----------------------------------------------------------------------------
  385. #if DBG!=1 && LOCK_PERF!=1
  386. inline void COleStaticMutexSem::Release()
  387. {
  388. if (!_fUsingGlobal)
  389. LeaveCriticalSection (&_cs);
  390. else
  391. LeaveCriticalSection (&g_OleGlobalLock);
  392. }
  393. #endif
  394. #if DBG==1 || LOCK_PERF==1
  395. //+---------------------------------------------------------------------------
  396. //
  397. // Member: COleStaticMutexSem::COleStaticMutexSem
  398. //
  399. // Synopsis: Debug constructor: ensure we weren't allocated dynamically.
  400. //
  401. // History: 14-Dec-1995 Jeffe
  402. //
  403. //----------------------------------------------------------------------------
  404. inline COleStaticMutexSem::COleStaticMutexSem()
  405. {
  406. Win4Assert (g_fDllState == DLL_STATE_STATIC_CONSTRUCTING);
  407. _dwTid = 0;
  408. _cLocks = 0;
  409. _dwLine = 0;
  410. _pszFile = "";
  411. _pszLockName = "";
  412. _fTakeOnce = FALSE;
  413. _cContinuous = 0;
  414. }
  415. #else
  416. inline COleStaticMutexSem::COleStaticMutexSem() {}
  417. #endif // DBG
  418. //+---------------------------------------------------------------------------
  419. //
  420. // Member: COleStaticMutexSem::COleStaticMutexSem(BOOLEAN fUseSpincount)
  421. //
  422. // Synopsis: Construct the Mutex with a spin count.
  423. //
  424. // History: 14-Apr-2000 ScottRob
  425. //
  426. //----------------------------------------------------------------------------
  427. inline COleStaticMutexSem::COleStaticMutexSem(BOOLEAN fUseSpincount)
  428. {
  429. #if DBG==1 || LOCK_PERF==1
  430. COleStaticMutexSem::COleStaticMutexSem();
  431. #endif // DBG
  432. _fUseSpincount = fUseSpincount;
  433. }
  434. //+---------------------------------------------------------------------------
  435. //
  436. // Member: COleStaticLock::COleStaticLock
  437. //
  438. // Synopsis: Acquire semaphore
  439. //
  440. // History: 02-Oct-91 BartoszM Created.
  441. //
  442. //----------------------------------------------------------------------------
  443. #if DBG==1 || LOCK_PERF==1
  444. inline COleStaticLock::COleStaticLock ( COleStaticMutexSem& mxs, const char * pszFile, DWORD dwLine, const char *pszLockName ) : _mxs ( mxs )
  445. {
  446. _mxs.Request(pszFile, dwLine, pszLockName);
  447. }
  448. #endif // DBG==1
  449. inline COleStaticLock::COleStaticLock ( COleStaticMutexSem& mxs)
  450. : _mxs ( mxs )
  451. {
  452. #if DBG==1 || LOCK_PERF==1
  453. _mxs.Request("Unknown File", 0L, "Unknown Lock");
  454. #else // DBG!=1
  455. _mxs.Request();
  456. #endif // DBG==1
  457. }
  458. //+---------------------------------------------------------------------------
  459. //
  460. // Member: COleStaticLock::~COleStaticLock
  461. //
  462. // Synopsis: Release semaphore
  463. //
  464. // History: 02-Oct-91 BartoszM Created.
  465. //
  466. //----------------------------------------------------------------------------
  467. inline COleStaticLock::~COleStaticLock ()
  468. {
  469. _mxs.Release();
  470. }
  471. // include the reader/writer lock
  472. #include <rwlock.hxx>
  473. #endif // _OLESEM_HXX