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.

820 lines
17 KiB

  1. // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2. //
  3. // SYNCHRO.H
  4. //
  5. // Header for DAV synchronization classes.
  6. //
  7. // Copyright 1986-1998 Microsoft Corporation, All Rights Reserved
  8. //
  9. #ifndef _EX_SYNCHRO_H_
  10. #define _EX_SYNCHRO_H_
  11. #include <caldbg.h> // for Assert/DebugTrace/etc
  12. // ========================================================================
  13. //
  14. // CLASS CCriticalSection
  15. //
  16. // Implements a critical section around a Win32 CRITICAL_SECTION.
  17. //
  18. // Adds safety by explicitly disallowing copying (copying a raw
  19. // CRITICAL_SECTION can cause very unpredictable and hard to debug
  20. // behavior -- trust me).
  21. //
  22. // Automatically cleans up the CRITICAL_SECTION resource when done.
  23. //
  24. class CCriticalSection
  25. {
  26. // The critical section
  27. //
  28. CRITICAL_SECTION m_cs;
  29. // NOT IMPLEMENTED
  30. //
  31. CCriticalSection& operator=( const CCriticalSection& );
  32. CCriticalSection( const CCriticalSection& );
  33. public:
  34. // CREATORS
  35. //
  36. CCriticalSection()
  37. {
  38. InitializeCriticalSection(&m_cs);
  39. #ifdef DBG
  40. m_cLockRefs = 0;
  41. m_dwLockOwnerThreadId = 0;
  42. #endif
  43. }
  44. ~CCriticalSection()
  45. {
  46. DeleteCriticalSection(&m_cs);
  47. }
  48. BOOL FTryEnter()
  49. {
  50. if ( TryEnterCriticalSection (&m_cs) ) {
  51. #ifdef DBG
  52. Assert (
  53. m_dwLockOwnerThreadId == GetCurrentThreadId() ||
  54. ( m_cLockRefs == 0 && m_dwLockOwnerThreadId == 0 )
  55. );
  56. m_dwLockOwnerThreadId = GetCurrentThreadId ();
  57. m_cLockRefs++;
  58. #endif
  59. return TRUE;
  60. }
  61. else
  62. return FALSE;
  63. }
  64. void Enter()
  65. {
  66. EnterCriticalSection(&m_cs);
  67. #ifdef DBG
  68. Assert (
  69. m_dwLockOwnerThreadId == GetCurrentThreadId() ||
  70. ( m_cLockRefs == 0 && m_dwLockOwnerThreadId == 0 )
  71. );
  72. m_dwLockOwnerThreadId = GetCurrentThreadId ();
  73. m_cLockRefs++;
  74. #endif
  75. }
  76. void Leave()
  77. {
  78. #ifdef DBG
  79. Assert ( m_cLockRefs > 0 );
  80. Assert ( m_dwLockOwnerThreadId != 0 );
  81. m_cLockRefs--;
  82. if ( m_cLockRefs == 0 ) {
  83. m_dwLockOwnerThreadId = 0;
  84. }
  85. #endif
  86. LeaveCriticalSection(&m_cs);
  87. }
  88. void AssertLocked ( ) const
  89. {
  90. #ifdef DBG
  91. // This routine allows us to verify our correctness even when
  92. // running in the single-threaded case.
  93. //
  94. // If this assert fires, it means that nobody has the lock:
  95. AssertSz ( m_cLockRefs > 0, "Calling method without the lock." );
  96. // If this assert fires, it means that somebody else has the lock:
  97. AssertSz ( m_dwLockOwnerThreadId == GetCurrentThreadId(),
  98. "Calling method, but another thread owns the lock!" );
  99. #endif
  100. }
  101. private:
  102. #ifdef DBG
  103. // # of Lock() calls - # of Unlock() calls. Used by AssertInLock()
  104. DWORD m_cLockRefs;
  105. // Thread ID of the current lock owner (or 0 if unowned).
  106. DWORD m_dwLockOwnerThreadId;
  107. #endif
  108. };
  109. // ========================================================================
  110. //
  111. // CLASS CSynchronizedBlock
  112. //
  113. // Synchronizes (serializes) any block of code in which an instance of
  114. // this class is declared on the critical section with which it
  115. // is initialized.
  116. //
  117. // To use, just declare one of these in the block you want synchronized:
  118. //
  119. // ...
  120. // {
  121. // CSynchronizedBlock sb(critsec);
  122. //
  123. // //
  124. // // Do some stuff that must be synchronized
  125. // //
  126. // ...
  127. //
  128. // //
  129. // // Do more synchronized stuff
  130. // //
  131. // ...
  132. // }
  133. //
  134. // //
  135. // // Do stuff that doesn't have to be synchronized
  136. // //
  137. // ...
  138. //
  139. // and the block is automatically synchronized. Why bother? Because
  140. // you don't need to have any cleanup code; the critical section is
  141. // automatically released when execution leaves the block, even if via
  142. // an exception thrown from any of the synchronized stuff.
  143. //
  144. class CSynchronizedBlock
  145. {
  146. // The critical section
  147. //
  148. CCriticalSection& m_cs;
  149. // NOT IMPLEMENTED
  150. //
  151. CSynchronizedBlock& operator=( const CSynchronizedBlock& );
  152. CSynchronizedBlock( const CSynchronizedBlock& );
  153. public:
  154. // CREATORS
  155. //
  156. CSynchronizedBlock( CCriticalSection& cs ) :
  157. m_cs(cs)
  158. {
  159. m_cs.Enter();
  160. }
  161. ~CSynchronizedBlock()
  162. {
  163. m_cs.Leave();
  164. }
  165. };
  166. #include <except.h>
  167. // ========================================================================
  168. //
  169. // CLASS CEvent
  170. //
  171. // Implements an event around a Win32 event handle resource.
  172. //
  173. class CEvent
  174. {
  175. // NOT IMPLEMENTED
  176. //
  177. CEvent& operator=(const CEvent&);
  178. CEvent(const CEvent&);
  179. protected:
  180. HANDLE m_hevt;
  181. public:
  182. CEvent() : m_hevt(NULL) {}
  183. BOOL FInitialized() const
  184. {
  185. return m_hevt && m_hevt != INVALID_HANDLE_VALUE;
  186. }
  187. ~CEvent()
  188. {
  189. if ( FInitialized() )
  190. {
  191. CloseHandle( m_hevt );
  192. }
  193. }
  194. BOOL FCreate( LPSECURITY_ATTRIBUTES lpsa,
  195. BOOL fManualReset,
  196. BOOL fSignalled,
  197. LPCWSTR lpwszEventName,
  198. BOOL fDontMungeTheEventName = FALSE)
  199. {
  200. Assert( !FInitialized() );
  201. // create event does not take backslashes. so replace
  202. // them with ? which won't be part of URI at this point.
  203. //
  204. //$HACK
  205. // ARGH! Who put this slash-munging hack in here? Modifying a
  206. // const parameter and munging the name. Most events are smart
  207. // enough not to use backward slashes in their names since they
  208. // aren't allowed by the underlying Win32 API, CreateEvent()....
  209. //
  210. // At any rate, this is not good in the Terminal Server case which
  211. // must prefix event names with either "Global\" or "Local\" (note
  212. // the backslash!)
  213. //
  214. // So the hack upon a hack here (fDontMungeTheEventName) is for
  215. // callers who really can be trusted to know what they are doing.
  216. // Unfortunately, short of grepping a lot of sources, there is
  217. // no way of knowing who can and can't be trusted, so we have to
  218. // assume the worst.
  219. //
  220. if (!fDontMungeTheEventName)
  221. {
  222. LPWSTR lpwszTemp = const_cast<LPWSTR>(lpwszEventName);
  223. if (lpwszTemp)
  224. {
  225. while( NULL != (lpwszTemp = wcschr (lpwszTemp, L'\\')) )
  226. {
  227. lpwszTemp[0] = L'?';
  228. }
  229. }
  230. }
  231. m_hevt = CreateEventW( lpsa,
  232. fManualReset,
  233. fSignalled,
  234. lpwszEventName );
  235. // According to MSDN, if the creation fails, CreateEvent returns NULL, not
  236. // INVALID_HANDLE_VALUE. We'll just do a quick DBG check to make sure we never
  237. // see INVALID_HANDLE_VALUE here.
  238. //
  239. Assert(INVALID_HANDLE_VALUE != m_hevt);
  240. if ( !m_hevt )
  241. return FALSE;
  242. return TRUE;
  243. }
  244. void Set()
  245. {
  246. Assert( FInitialized() );
  247. SideAssert( SetEvent(m_hevt) );
  248. }
  249. void Reset()
  250. {
  251. Assert( FInitialized() );
  252. SideAssert( ResetEvent(m_hevt) );
  253. }
  254. void Wait()
  255. {
  256. Assert( FInitialized() );
  257. SideAssert( WaitForSingleObject( m_hevt, INFINITE ) == WAIT_OBJECT_0 );
  258. }
  259. void AlertableWait()
  260. {
  261. Assert( FInitialized() );
  262. DWORD dwResult;
  263. do
  264. {
  265. dwResult = WaitForSingleObjectEx( m_hevt, INFINITE, TRUE );
  266. Assert( dwResult != 0xFFFFFFFF );
  267. }
  268. while ( dwResult == WAIT_IO_COMPLETION );
  269. Assert( dwResult == WAIT_OBJECT_0 );
  270. }
  271. };
  272. // ========================================================================
  273. //
  274. // CLASS CMRWLock
  275. //
  276. // Implements a multi-reader, single writer-with-promote lock for
  277. // efficient, thread-safe access of a per-process resource.
  278. //
  279. class CMRWLock
  280. {
  281. //
  282. // The implementation uses a really clever trick where
  283. // the high bit of the reader count is reserved for use
  284. // as a one-bit flag that it set whenever there is a
  285. // writer in the lock or waiting to enter it.
  286. //
  287. // Combining the reader count and a writer flag into
  288. // a single DWORD allows InterlockedXXX() calls to
  289. // be used to manipulate the two pieces of information
  290. // atomically as part of a spinlock which eliminates
  291. // the need for an entering reader to pass through
  292. // a critical section.
  293. //
  294. // Entering a critical section, even for the short amount
  295. // of time necessary to get a reader into the lock,
  296. // drastically impacts the performance of heavily used
  297. // process-wide locks.
  298. //
  299. //
  300. // The write lock bit
  301. //
  302. enum { WRITE_LOCKED = 0x80000000 };
  303. //
  304. // Critical section to allow only one writer at a time.
  305. //
  306. CCriticalSection m_csWriter;
  307. //
  308. // ThreadID of the thread that owns the write lock.
  309. // This value is 0 when no one owns the write lock.
  310. //
  311. DWORD m_dwWriteLockOwner;
  312. //
  313. // Promoter recursion count used to allow a single thread
  314. // which holds the promote/write lock to reenter the lock.
  315. //
  316. DWORD m_dwPromoterRecursion;
  317. //
  318. // Event signalled when a writer leaves the lock to
  319. // allow blocked readers to enter.
  320. //
  321. CEvent m_evtEnableReaders;
  322. //
  323. // Event signalled when the last reader leaves the lock
  324. // to allow a blocked writer to enter.
  325. //
  326. CEvent m_evtEnableWriter;
  327. //
  328. // Count of readers plus a flag bit (WRITE_LOCKED)
  329. // indicating whether a writer owns the lock or is
  330. // waiting to enter it.
  331. //
  332. LONG m_lcReaders;
  333. BOOL FAcquireReadLock(BOOL fAllowCallToBlock);
  334. // NOT IMPLEMENTED
  335. //
  336. CMRWLock& operator=(const CMRWLock&);
  337. CMRWLock(const CMRWLock&);
  338. public:
  339. // CREATORS
  340. //
  341. CMRWLock();
  342. BOOL FInitialize();
  343. ~CMRWLock() {};
  344. // MANIPULATORS
  345. //
  346. void EnterRead();
  347. BOOL FTryEnterRead();
  348. void LeaveRead();
  349. void EnterWrite();
  350. BOOL FTryEnterWrite();
  351. void LeaveWrite();
  352. void EnterPromote();
  353. BOOL FTryEnterPromote();
  354. void LeavePromote();
  355. void Promote();
  356. };
  357. // ========================================================================
  358. //
  359. // CLASS CCrossThreadLock
  360. //
  361. // Implements a simple mutual exclusion lock to guard access to objects.
  362. // This object can be locked and unlocked from different threads (difference
  363. // from critsec-style locks).
  364. //
  365. // ONLY USE THIS LOCK IF YOU _REALLY_ _REALLY_ NEED CROSS-THREAD
  366. // LOCK/UNLOCK CAPABILITY.
  367. //
  368. // Possible future plans for improvement:
  369. // o This object currently sets NULL for lpSemaphoreAttributes. This will
  370. // not allow the lock to be used cross-process or from a different
  371. // user security context.
  372. // o This object always specifies an INFINITE timeout. In the future, there
  373. // could be an optional parameter to FEnter that allows you to set
  374. // something other than INFINITE.
  375. //
  376. class
  377. CCrossThreadLock
  378. {
  379. HANDLE m_hSemaphore;
  380. // NOT IMPLEMENTED
  381. //
  382. CCrossThreadLock& operator=(const CCrossThreadLock&);
  383. CCrossThreadLock(const CCrossThreadLock&);
  384. public:
  385. CCrossThreadLock() :
  386. m_hSemaphore(NULL)
  387. { }
  388. ~CCrossThreadLock()
  389. {
  390. if (NULL != m_hSemaphore)
  391. CloseHandle(m_hSemaphore);
  392. }
  393. BOOL FInitialize()
  394. {
  395. BOOL fSuccess = FALSE;
  396. m_hSemaphore = CreateSemaphore(NULL, // lpSemaphoreAttributes
  397. 1, // lInitialCount
  398. 1, // lMaximumCount
  399. NULL); // lpName
  400. // According to MSDN, if the creation fails, CreateSemaphore returns NULL, not
  401. // INVALID_HANDLE_VALUE. We'll just do a quick DBG check to make sure we never
  402. // see INVALID_HANDLE_VALUE here.
  403. //
  404. Assert(INVALID_HANDLE_VALUE != m_hSemaphore);
  405. if (NULL == m_hSemaphore)
  406. goto Exit;
  407. fSuccess = TRUE;
  408. Exit:
  409. return fSuccess;
  410. }
  411. BOOL FEnter(DWORD dwTimeOut = INFINITE)
  412. {
  413. Assert(NULL != m_hSemaphore);
  414. if (WAIT_OBJECT_0 == WaitForSingleObject(m_hSemaphore,
  415. dwTimeOut))
  416. return TRUE;
  417. return FALSE;
  418. }
  419. VOID Leave()
  420. {
  421. Assert(NULL != m_hSemaphore);
  422. if (!ReleaseSemaphore(m_hSemaphore,
  423. 1,
  424. NULL))
  425. {
  426. DebugTrace("CCrossThreadLock::Leave(): Failed to release semaphore, last error 0x%08lX.\n",
  427. GetLastError());
  428. TrapSz("CCrossThreadLock::Leave(): Failed to release semaphore!\n");
  429. }
  430. }
  431. };
  432. // ========================================================================
  433. //
  434. // CLASS CGate
  435. //
  436. // Implements gating mechanism, that alows to close the EXECUTION PATH and
  437. // push out all the threads using it. Very usefull on shutdown scenarios.
  438. //
  439. // Here is a sketch of the gate usage:
  440. //
  441. // ...
  442. //
  443. // {
  444. // CGatedBlock gb(gate);
  445. //
  446. // if (gb.FIsGateOpen())
  447. // {
  448. // ...
  449. // EXECUTION PATH that is to be gated
  450. // ...
  451. // }
  452. // else
  453. // {
  454. // ...
  455. // Do whatever has to be done if EXECUTION PATH
  456. // is not to be executed any more
  457. // ...
  458. // }
  459. // }
  460. // ...
  461. //
  462. class CGate
  463. {
  464. // Number of users in the zone framed by this gate
  465. //
  466. LONG m_lcUsers;
  467. // Flag indicating if the gate is open
  468. //
  469. BOOL m_fClosed;
  470. // NOT IMPLEMENTED
  471. //
  472. CGate& operator=(const CGate&);
  473. CGate(const CGate&);
  474. public:
  475. // The fact that all member variables of the class are
  476. // 0 on creation, allows to use it as a static variable
  477. // without additional burden of explicit initialization
  478. //
  479. CGate() : m_lcUsers(0),
  480. m_fClosed(FALSE) {};
  481. // INITIALIZER
  482. //
  483. inline
  484. VOID Init()
  485. {
  486. m_lcUsers = 0;
  487. m_fClosed = FALSE;
  488. }
  489. // MANIPULATORS
  490. //
  491. inline
  492. VOID Enter()
  493. {
  494. InterlockedIncrement(&m_lcUsers);
  495. }
  496. inline
  497. VOID Leave()
  498. {
  499. InterlockedDecrement(&m_lcUsers);
  500. }
  501. inline
  502. VOID Close()
  503. {
  504. // Mark the gate as closed
  505. //
  506. m_fClosed = TRUE;
  507. // Wait until all the threads that use execution
  508. // path framed by this gate will leave the zone
  509. // it is framing. As FIsOpen() call is allowed only
  510. // inside the gated zone, we will know that after
  511. // this call returns there is no thread thinking
  512. // that the gate is still open
  513. //
  514. while (0 != m_lcUsers)
  515. {
  516. Sleep(200);
  517. }
  518. }
  519. // ACCESSORS
  520. //
  521. inline
  522. BOOL FIsOpen()
  523. {
  524. // We must be in the gated zone in order
  525. // to be able to determine if the gate is
  526. // open.
  527. //
  528. Assert(m_lcUsers > 0);
  529. return !m_fClosed;
  530. }
  531. };
  532. // ========================================================================
  533. //
  534. // TEMPLATE CLASS SynchronizedReadBlock
  535. //
  536. template<class _Lock>
  537. class SynchronizedReadBlock
  538. {
  539. // The read/write lock
  540. //
  541. _Lock& m_lock;
  542. // NOT IMPLEMENTED
  543. //
  544. SynchronizedReadBlock& operator=( const SynchronizedReadBlock& );
  545. SynchronizedReadBlock( const SynchronizedReadBlock& );
  546. public:
  547. SynchronizedReadBlock (_Lock& mrw)
  548. : m_lock(mrw)
  549. {
  550. m_lock.EnterRead();
  551. }
  552. ~SynchronizedReadBlock()
  553. {
  554. m_lock.LeaveRead();
  555. }
  556. };
  557. typedef SynchronizedReadBlock<CMRWLock> CSynchronizedReadBlock;
  558. // ========================================================================
  559. //
  560. // TEMPLATE CLASS CSynchronizedWriteBlock
  561. //
  562. template<class _Lock>
  563. class SynchronizedWriteBlock
  564. {
  565. // The read/write lock
  566. //
  567. _Lock& m_lock;
  568. // NOT IMPLEMENTED
  569. //
  570. SynchronizedWriteBlock& operator=( const SynchronizedWriteBlock& );
  571. SynchronizedWriteBlock( const SynchronizedWriteBlock& );
  572. public:
  573. SynchronizedWriteBlock (_Lock& mrw)
  574. : m_lock(mrw)
  575. {
  576. m_lock.EnterWrite();
  577. }
  578. ~SynchronizedWriteBlock()
  579. {
  580. m_lock.LeaveWrite();
  581. }
  582. };
  583. typedef SynchronizedWriteBlock<CMRWLock> CSynchronizedWriteBlock;
  584. // ========================================================================
  585. //
  586. // TEMPLATE CLASS TryWriteBlock
  587. //
  588. // Like SynchronizedWriteBlock except that the block must be
  589. // entered via the FTryEnter() method. A return value of TRUE
  590. // from FTryEnter() indicates the lock is entered.
  591. //
  592. template<class _Lock>
  593. class TryWriteBlock
  594. {
  595. // The read/write lock
  596. //
  597. _Lock& m_lock;
  598. // TRUE if write lock entered
  599. //
  600. BOOL m_fLocked;
  601. // NOT IMPLEMENTED
  602. //
  603. TryWriteBlock& operator=( const TryWriteBlock& );
  604. TryWriteBlock( const TryWriteBlock& );
  605. public:
  606. TryWriteBlock (_Lock& mrw) :
  607. m_lock(mrw),
  608. m_fLocked(FALSE)
  609. {
  610. }
  611. BOOL FTryEnter()
  612. {
  613. return m_fLocked = m_lock.FTryEnterWrite();
  614. }
  615. ~TryWriteBlock()
  616. {
  617. if ( m_fLocked )
  618. m_lock.LeaveWrite();
  619. }
  620. };
  621. typedef TryWriteBlock<CMRWLock> CTryWriteBlock;
  622. // ========================================================================
  623. //
  624. // TEMPLATE CLASS SynchronizedPromoteBlock
  625. //
  626. template<class _Lock>
  627. class SynchronizedPromoteBlock
  628. {
  629. // The read/write lock
  630. //
  631. _Lock& m_lock;
  632. // NOT IMPLEMENTED
  633. //
  634. SynchronizedPromoteBlock& operator=( const SynchronizedPromoteBlock& );
  635. SynchronizedPromoteBlock( const SynchronizedPromoteBlock& );
  636. public:
  637. SynchronizedPromoteBlock (_Lock& mrw)
  638. : m_lock(mrw)
  639. {
  640. m_lock.EnterPromote();
  641. }
  642. ~SynchronizedPromoteBlock()
  643. {
  644. m_lock.LeavePromote();
  645. }
  646. void Promote()
  647. {
  648. m_lock.Promote();
  649. }
  650. };
  651. typedef SynchronizedPromoteBlock<CMRWLock> CSynchronizedPromoteBlock;
  652. // ========================================================================
  653. //
  654. // TEMPLATE CLASS GatedBlock
  655. //
  656. template<class _Gate>
  657. class GatedBlock
  658. {
  659. // The gate
  660. //
  661. _Gate& m_gate;
  662. // NOT IMPLEMENTED
  663. //
  664. GatedBlock& operator=( const GatedBlock& );
  665. GatedBlock( const GatedBlock& );
  666. public:
  667. GatedBlock (_Gate& gate)
  668. : m_gate(gate)
  669. {
  670. m_gate.Enter();
  671. }
  672. BOOL FGateIsOpen()
  673. {
  674. return m_gate.FIsOpen();
  675. }
  676. ~GatedBlock()
  677. {
  678. m_gate.Leave();
  679. }
  680. };
  681. typedef GatedBlock<CGate> CGatedBlock;
  682. // ========================================================================
  683. //
  684. // InterlockedExchangeOr - A multithread safe way to OR bits into a LONG
  685. //
  686. LONG InterlockedExchangeOr( LONG * plVariable, LONG lOrBits );
  687. #endif // !_EX_SYNCHRO_H_