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.

1911 lines
64 KiB

  1. //+-------------------------------------------------------------------
  2. //
  3. // File: RWLock.cxx
  4. //
  5. // Contents: Reader writer lock implementation that supports the
  6. // following features
  7. // 1. Cheap enough to be used in large numbers
  8. // such as per object synchronization.
  9. // 2. Supports timeout. This is a valuable feature
  10. // to detect deadlocks
  11. // 3. Supports caching of events. This allows
  12. // the events to be moved from least contentious
  13. // regions to the most contentious regions.
  14. // In other words, the number of events needed by
  15. // Reader-Writer lockls is bounded by the number
  16. // of threads in the process.
  17. // 4. Supports nested locks by readers and writers
  18. // 5. Supports spin counts for avoiding context switches
  19. // on multi processor machines.
  20. // 6. Supports functionality for upgrading to a writer
  21. // lock with a return argument that indicates
  22. // intermediate writes. Downgrading from a writer
  23. // lock restores the state of the lock.
  24. // 7. Supports functionality to Release Lock for calling
  25. // app code. RestoreLock restores the lock state and
  26. // indicates intermediate writes.
  27. // 8. Recovers from most common failures such as creation of
  28. // events. In other words, the lock mainitains consistent
  29. // internal state and remains usable
  30. //
  31. //
  32. // Classes: CRWLock
  33. // CStaticRWLock
  34. //
  35. // History: 19-Aug-98 Gopalk Created
  36. //
  37. //--------------------------------------------------------------------
  38. #include <ole2int.h>
  39. #include "RWLock.hxx"
  40. // Reader increment
  41. #define READER 0x00000001
  42. // Max number of readers
  43. #define READERS_MASK 0x000003FF
  44. // Reader being signaled
  45. #define READER_SIGNALED 0x00000400
  46. // Writer being signaled
  47. #define WRITER_SIGNALED 0x00000800
  48. #define WRITER 0x00001000
  49. // Waiting reader increment
  50. #define WAITING_READER 0x00002000
  51. // Note size of waiting readers must be less
  52. // than or equal to size of readers
  53. #define WAITING_READERS_MASK 0x007FE000
  54. #define WAITING_READERS_SHIFT 13
  55. // Waiting writer increment
  56. #define WAITING_WRITER 0x00800000
  57. // Max number of waiting writers
  58. #define WAITING_WRITERS_MASK 0xFF800000
  59. // Events are being cached
  60. #define CACHING_EVENTS (READER_SIGNALED | WRITER_SIGNALED)
  61. // Reader lock was upgraded
  62. #define INVALID_COOKIE 0x01
  63. #define UPGRADE_COOKIE 0x02
  64. #define RELEASE_COOKIE 0x04
  65. #define COOKIE_NONE 0x10
  66. #define COOKIE_WRITER 0x20
  67. #define COOKIE_READER 0x40
  68. DWORD gdwDefaultTimeout = INFINITE;
  69. DWORD gdwDefaultSpinCount = 0;
  70. DWORD gdwNumberOfProcessors = 1;
  71. DWORD gdwLockSeqNum = 0;
  72. const DWORD gdwReasonableTimeout = 120000;
  73. const DWORD gdwMaxReaders = READERS_MASK;
  74. const DWORD gdwMaxWaitingReaders = (WAITING_READERS_MASK >> WAITING_READERS_SHIFT);
  75. BOOL IsKDPresent()
  76. {
  77. return USER_SHARED_DATA->KdDebuggerEnabled;
  78. }
  79. BOOL fBreakOnErrors ()
  80. {
  81. return (IsDebuggerPresent() || IsKDPresent());
  82. }
  83. #ifdef __NOOLETLS__
  84. DWORD gLockTlsIdx = -1;
  85. #endif
  86. #define RWLOCK_FATALFAILURE 1000
  87. #define HEAP_SERIALIZE 0
  88. //+-------------------------------------------------------------------
  89. //
  90. // Method: CRWLock::InitDefaults public
  91. //
  92. // Synopsis: Reads default values from registry
  93. //
  94. // History: 21-Aug-98 Gopalk Created
  95. //
  96. //+-------------------------------------------------------------------
  97. void CRWLock::InitDefaults()
  98. {
  99. SYSTEM_INFO system;
  100. // Obtain number of processors on the system
  101. GetSystemInfo(&system);
  102. gdwNumberOfProcessors = system.dwNumberOfProcessors;
  103. gdwDefaultSpinCount = (gdwNumberOfProcessors > 1) ? 500 : 0;
  104. // Obtain system wide timeout value
  105. HKEY hKey;
  106. LONG lRetVal = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
  107. "SYSTEM\\CurrentControlSet\\Control\\Session Manager",
  108. NULL,
  109. KEY_READ,
  110. &hKey);
  111. if(lRetVal == ERROR_SUCCESS)
  112. {
  113. DWORD dwTimeout, dwSize = sizeof(dwTimeout);
  114. lRetVal = RegQueryValueExA(hKey,
  115. "CriticalSectionTimeout",
  116. NULL,
  117. NULL,
  118. (LPBYTE) &dwTimeout,
  119. &dwSize);
  120. if(lRetVal == ERROR_SUCCESS)
  121. {
  122. if (dwTimeout <= 1*24*60*60) // less than a day, usually ntstress case
  123. {
  124. gdwDefaultTimeout = dwTimeout * 20000; // 20 times the critsec timeout
  125. }
  126. // otherwise lock timeout is INFINITE.
  127. }
  128. RegCloseKey(hKey);
  129. }
  130. return;
  131. }
  132. //+-------------------------------------------------------------------
  133. //
  134. // Method: CRWLock::Cleanup public
  135. //
  136. // Synopsis: Cleansup state
  137. //
  138. // History: 21-Aug-98 Gopalk Created
  139. //
  140. //+-------------------------------------------------------------------
  141. void CRWLock::Cleanup()
  142. {
  143. #if DBG==1
  144. if (g_fDllState != DLL_STATE_PROCESS_DETACH)
  145. {
  146. // Perform sanity checks if we're not shutting down
  147. Win4Assert(_dwState == 0);
  148. Win4Assert(_dwWriterID == 0);
  149. Win4Assert(_wWriterLevel == 0);
  150. }
  151. #endif
  152. if(_hWriterEvent)
  153. CloseHandle(_hWriterEvent);
  154. if(_hReaderEvent)
  155. CloseHandle(_hReaderEvent);
  156. #if LOCK_PERF==1
  157. gLockTracker.ReportContention(this,
  158. _dwWriterEntryCount,
  159. _dwWriterContentionCount,
  160. _dwReaderEntryCount,
  161. _dwReaderContentionCount);
  162. #endif
  163. return;
  164. }
  165. //+-------------------------------------------------------------------
  166. //
  167. // Method: CRWLock::AssertWriterLockHeld public
  168. //
  169. // Synopsis: Asserts that writer lock is held
  170. //
  171. // History: 21-Aug-98 Gopalk Created
  172. //
  173. //+-------------------------------------------------------------------
  174. #if DBG==1
  175. BOOL CRWLock::AssertWriterLockHeld()
  176. {
  177. DWORD dwThreadID = GetCurrentThreadId();
  178. if(_dwWriterID != dwThreadID)
  179. Win4Assert(!"Writer lock not held by the current thread");
  180. return(_dwWriterID == dwThreadID);
  181. }
  182. #endif
  183. //+-------------------------------------------------------------------
  184. //
  185. // Method: CRWLock::AssertWriterLockNotHeld public
  186. //
  187. // Synopsis: Asserts that writer lock is not held
  188. //
  189. // History: 21-Aug-98 Gopalk Created
  190. //
  191. //+-------------------------------------------------------------------
  192. #if DBG==1
  193. BOOL CRWLock::AssertWriterLockNotHeld()
  194. {
  195. DWORD dwThreadID = GetCurrentThreadId();
  196. if(_dwWriterID == dwThreadID)
  197. Win4Assert(!"Writer lock held by the current thread");
  198. return(_dwWriterID != dwThreadID);
  199. }
  200. #endif
  201. //+-------------------------------------------------------------------
  202. //
  203. // Method: CRWLock::AssertReaderLockHeld public
  204. //
  205. // Synopsis: Asserts that reader lock is held
  206. //
  207. // History: 21-Aug-98 Gopalk Created
  208. //
  209. //+-------------------------------------------------------------------
  210. #if DBG==1
  211. BOOL CRWLock::AssertReaderLockHeld()
  212. {
  213. HRESULT hr;
  214. WORD *pwReaderLevel;
  215. BOOL fLockHeld = FALSE;
  216. hr = GetTLSLockData(&pwReaderLevel);
  217. if((hr == S_OK) && (*pwReaderLevel != 0))
  218. fLockHeld = TRUE;
  219. if(fLockHeld == FALSE)
  220. Win4Assert(!"Reader lock not held by the current thread");
  221. return(fLockHeld);
  222. }
  223. #endif
  224. //+-------------------------------------------------------------------
  225. //
  226. // Method: CRWLock::AssertReaderLockNotHeld public
  227. //
  228. // Synopsis: Asserts that writer lock is not held
  229. //
  230. // History: 21-Aug-98 Gopalk Created
  231. //
  232. //+-------------------------------------------------------------------
  233. #if DBG==1
  234. BOOL CRWLock::AssertReaderLockNotHeld()
  235. {
  236. HRESULT hr;
  237. WORD *pwReaderLevel;
  238. BOOL fLockHeld = FALSE;
  239. hr = GetTLSLockData(&pwReaderLevel);
  240. if((hr == S_OK) && (*pwReaderLevel != 0))
  241. fLockHeld = TRUE;
  242. if(fLockHeld == TRUE)
  243. Win4Assert(!"Reader lock held by the current thread");
  244. return(fLockHeld == FALSE);
  245. }
  246. #endif
  247. //+-------------------------------------------------------------------
  248. //
  249. // Method: CRWLock::AssertReaderOrWriterLockHeld public
  250. //
  251. // Synopsis: Asserts that writer lock is not held
  252. //
  253. // History: 21-Aug-98 Gopalk Created
  254. //
  255. //+-------------------------------------------------------------------
  256. #if DBG==1
  257. BOOL CRWLock::AssertReaderOrWriterLockHeld()
  258. {
  259. BOOL fLockHeld = FALSE;
  260. if(_dwWriterID == GetCurrentThreadId())
  261. {
  262. fLockHeld = TRUE;
  263. }
  264. else
  265. {
  266. HRESULT hr;
  267. WORD *pwReaderLevel;
  268. hr = GetTLSLockData(&pwReaderLevel);
  269. if((hr == S_OK) && (*pwReaderLevel != 0))
  270. fLockHeld = TRUE;
  271. }
  272. Win4Assert(fLockHeld && "Neither Reader nor Writer lock held");
  273. return(fLockHeld);
  274. }
  275. #endif
  276. //+-------------------------------------------------------------------
  277. //
  278. // Method: CRWLock::ModifyState public
  279. //
  280. // Synopsis: Helper function for updating the state inside the lock
  281. //
  282. // History: 21-Aug-98 Gopalk Created
  283. //
  284. //+-------------------------------------------------------------------
  285. inline DWORD CRWLock::ModifyState(DWORD dwModifyState)
  286. {
  287. return(InterlockedExchangeAdd((LONG *) &_dwState, dwModifyState));
  288. }
  289. //+-------------------------------------------------------------------
  290. //
  291. // Method: CRWLock::RWSetEvent public
  292. //
  293. // Synopsis: Helper function for setting an event
  294. //
  295. // History: 21-Aug-98 Gopalk Created
  296. //
  297. //+-------------------------------------------------------------------
  298. inline void CRWLock::RWSetEvent(HANDLE event)
  299. {
  300. if(!SetEvent(event))
  301. {
  302. Win4Assert(!"SetEvent failed");
  303. if(fBreakOnErrors())
  304. DebugBreak();
  305. TerminateProcess(GetCurrentProcess(), RWLOCK_FATALFAILURE);
  306. }
  307. }
  308. //+-------------------------------------------------------------------
  309. //
  310. // Method: CRWLock::RWResetEvent public
  311. //
  312. // Synopsis: Helper function for resetting an event
  313. //
  314. // History: 21-Aug-98 Gopalk Created
  315. //
  316. //+-------------------------------------------------------------------
  317. inline void CRWLock::RWResetEvent(HANDLE event)
  318. {
  319. if(!ResetEvent(event))
  320. {
  321. Win4Assert(!"ResetEvent failed");
  322. if(fBreakOnErrors())
  323. DebugBreak();
  324. TerminateProcess(GetCurrentProcess(), RWLOCK_FATALFAILURE);
  325. }
  326. }
  327. //+-------------------------------------------------------------------
  328. //
  329. // Method: CRWLock::RWSleep public
  330. //
  331. // Synopsis: Helper function for calling Sleep. Useful for debugging
  332. //
  333. // History: 21-Aug-98 Gopalk Created
  334. //
  335. //+-------------------------------------------------------------------
  336. inline void CRWLock::RWSleep(DWORD dwTime)
  337. {
  338. Sleep(dwTime);
  339. }
  340. //+-------------------------------------------------------------------
  341. //
  342. // Method: CRWLock::ReleaseEvents public
  343. //
  344. // Synopsis: Helper function for caching events
  345. //
  346. // History: 21-Aug-98 Gopalk Created
  347. //
  348. //+-------------------------------------------------------------------
  349. #ifdef RWLOCK_FULL_FUNCTIONALITY
  350. void CRWLock::ReleaseEvents()
  351. {
  352. // Sanity check
  353. Win4Assert(_wFlags & RWLOCKFLAG_CACHEEVENTS);
  354. // Ensure that reader and writers have been stalled
  355. Win4Assert((_dwState & CACHING_EVENTS) == CACHING_EVENTS);
  356. // Save writer event
  357. HANDLE hWriterEvent = _hWriterEvent;
  358. _hWriterEvent = NULL;
  359. // Save reader event
  360. HANDLE hReaderEvent = _hReaderEvent;
  361. _hReaderEvent = NULL;
  362. // Allow readers and writers to continue
  363. ModifyState(-(CACHING_EVENTS));
  364. // Cache events
  365. // REVIEW: I am closing events for now. What is needed
  366. // is an event cache to which the events are
  367. // released using InterlockedCompareExchange64
  368. if(hWriterEvent)
  369. {
  370. ComDebOut((DEB_TRACE, "Releasing writer event\n"));
  371. CloseHandle(hWriterEvent);
  372. }
  373. if(hReaderEvent)
  374. {
  375. ComDebOut((DEB_TRACE, "Releasing reader event\n"));
  376. CloseHandle(hReaderEvent);
  377. }
  378. return;
  379. }
  380. #endif
  381. //+-------------------------------------------------------------------
  382. //
  383. // Method: CRWLock::GetWriterEvent public
  384. //
  385. // Synopsis: Helper function for obtaining a auto reset event used
  386. // for serializing writers. It utilizes event cache
  387. //
  388. // History: 21-Aug-98 Gopalk Created
  389. //
  390. //+-------------------------------------------------------------------
  391. HANDLE CRWLock::GetWriterEvent()
  392. {
  393. if(_hWriterEvent == NULL)
  394. {
  395. HANDLE hWriterEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  396. if(hWriterEvent)
  397. {
  398. if(InterlockedCompareExchangePointer(&_hWriterEvent, hWriterEvent, NULL))
  399. {
  400. CloseHandle(hWriterEvent);
  401. }
  402. }
  403. }
  404. return(_hWriterEvent);
  405. }
  406. //+-------------------------------------------------------------------
  407. //
  408. // Method: CRWLock::GetReaderEvent public
  409. //
  410. // Synopsis: Helper function for obtaining a manula reset event used
  411. // by readers to wait when a writer holds the lock.
  412. // It utilizes event cache
  413. //
  414. // History: 21-Aug-98 Gopalk Created
  415. //
  416. //+-------------------------------------------------------------------
  417. HANDLE CRWLock::GetReaderEvent()
  418. {
  419. if(_hReaderEvent == NULL)
  420. {
  421. HANDLE hReaderEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  422. if(hReaderEvent)
  423. {
  424. if(InterlockedCompareExchangePointer(&_hReaderEvent, hReaderEvent, NULL))
  425. {
  426. CloseHandle(hReaderEvent);
  427. }
  428. }
  429. }
  430. return(_hReaderEvent);
  431. }
  432. //+-------------------------------------------------------------------
  433. //
  434. // Method: CRWLock::AcquireReaderLock public
  435. //
  436. // Synopsis: Makes the thread a reader. Supports nested reader locks.
  437. //
  438. // History: 21-Aug-98 Gopalk Created
  439. //
  440. //+-------------------------------------------------------------------
  441. HRESULT CRWLock::AcquireReaderLock(
  442. #ifdef RWLOCK_FULL_FUNCTIONALITY
  443. BOOL fReturnErrors,
  444. DWORD dwDesiredTimeout
  445. #if LOCK_PERF==1
  446. ,
  447. #endif
  448. #endif
  449. #if LOCK_PERF==1
  450. const char *pszFile,
  451. DWORD dwLine,
  452. const char *pszLockName
  453. #endif
  454. )
  455. {
  456. HRESULT hr;
  457. #ifndef RWLOCK_FULL_FUNCTIONALITY
  458. DWORD dwDesiredTimeout = gdwDefaultTimeout;
  459. #endif
  460. // Ensure that the lock was initialized
  461. if(!IsInitialized())
  462. Initialize();
  463. // Check if the thread already has writer lock
  464. if(_dwWriterID == GetCurrentThreadId())
  465. {
  466. hr = AcquireWriterLock();
  467. }
  468. else
  469. {
  470. WORD *pwReaderLevel;
  471. hr = GetTLSLockData(&pwReaderLevel);
  472. if(SUCCEEDED(hr))
  473. {
  474. if(*pwReaderLevel != 0)
  475. {
  476. ++(*pwReaderLevel);
  477. }
  478. else
  479. {
  480. DWORD dwCurrentState, dwKnownState;
  481. DWORD dwSpinCount;
  482. // Initialize
  483. hr = S_OK;
  484. dwSpinCount = 0;
  485. dwCurrentState = _dwState;
  486. do
  487. {
  488. dwKnownState = dwCurrentState;
  489. // Reader need not wait if there are only readers and no writer
  490. if((dwKnownState < READERS_MASK) ||
  491. (((dwKnownState & READER_SIGNALED) && ((dwKnownState & WRITER) == 0)) &&
  492. (((dwKnownState & READERS_MASK) +
  493. ((dwKnownState & WAITING_READERS_MASK) >> WAITING_READERS_SHIFT)) <=
  494. (READERS_MASK - 2))))
  495. {
  496. // Add to readers
  497. dwCurrentState = InterlockedCompareExchange((LONG *) &_dwState,
  498. (dwKnownState + READER),
  499. dwKnownState);
  500. if(dwCurrentState == dwKnownState)
  501. {
  502. // One more reader
  503. break;
  504. }
  505. }
  506. // Check for too many Readers, or waiting readers
  507. else if(((dwKnownState & READERS_MASK) == READERS_MASK) ||
  508. ((dwKnownState & WAITING_READERS_MASK) == WAITING_READERS_MASK) ||
  509. ((dwKnownState & CACHING_EVENTS) == READER_SIGNALED))
  510. {
  511. RWSleep(1000);
  512. dwSpinCount = 0;
  513. dwCurrentState = _dwState;
  514. }
  515. // Check if events are being cached
  516. #ifdef RWLOCK_FULL_FUNCTIONALITY
  517. else if((dwKnownState & CACHING_EVENTS) == CACHING_EVENTS)
  518. {
  519. if(++dwSpinCount > gdwDefaultSpinCount)
  520. {
  521. RWSleep(10);
  522. dwSpinCount = 0;
  523. }
  524. dwCurrentState = _dwState;
  525. }
  526. #endif
  527. // Check spin count
  528. else if(++dwSpinCount > gdwDefaultSpinCount)
  529. {
  530. // Add to waiting readers
  531. dwCurrentState = InterlockedCompareExchange((LONG *) &_dwState,
  532. (dwKnownState + WAITING_READER),
  533. dwKnownState);
  534. if(dwCurrentState == dwKnownState)
  535. {
  536. HANDLE hReaderEvent;
  537. DWORD dwStatus;
  538. DWORD dwModifyState;
  539. // One more waiting reader
  540. #ifdef RWLOCK_STATISTICS
  541. InterlockedIncrement((LONG *) &_dwReaderContentionCount);
  542. #endif
  543. #if LOCK_PERF==1
  544. gLockTracker.ReaderWaiting(pszFile, dwLine, pszLockName, this);
  545. #endif
  546. hReaderEvent = GetReaderEvent();
  547. if(hReaderEvent)
  548. {
  549. dwStatus = WaitForSingleObject(hReaderEvent, dwDesiredTimeout);
  550. }
  551. else
  552. {
  553. ComDebOut((DEB_WARN,
  554. "AcquireReaderLock failed to create reader "
  555. "event for RWLock 0x%x\n", this));
  556. dwStatus = WAIT_FAILED;
  557. hr = RPC_E_OUT_OF_RESOURCES;
  558. }
  559. if(dwStatus == WAIT_OBJECT_0)
  560. {
  561. Win4Assert(_dwState & READER_SIGNALED);
  562. Win4Assert((_dwState & READERS_MASK) < READERS_MASK);
  563. dwModifyState = READER - WAITING_READER;
  564. }
  565. else
  566. {
  567. dwModifyState = -WAITING_READER;
  568. if(dwStatus == WAIT_TIMEOUT)
  569. {
  570. ComDebOut((DEB_WARN,
  571. "Timed out trying to acquire reader lock "
  572. "for RWLock 0x%x\n", this));
  573. hr = RPC_E_TIMEOUT;
  574. }
  575. else if(SUCCEEDED(hr))
  576. {
  577. ComDebOut((DEB_ERROR,
  578. "WaitForSingleObject Failed for "
  579. "RWLock 0x%x\n", this));
  580. hr = HRESULT_FROM_WIN32(GetLastError());
  581. }
  582. }
  583. // One less waiting reader and he may have become a reader
  584. dwKnownState = ModifyState(dwModifyState);
  585. // Check for last signaled waiting reader
  586. if(((dwKnownState & WAITING_READERS_MASK) == WAITING_READER) &&
  587. (dwKnownState & READER_SIGNALED))
  588. {
  589. dwModifyState = -READER_SIGNALED;
  590. if(dwStatus != WAIT_OBJECT_0)
  591. {
  592. if(hReaderEvent == NULL)
  593. hReaderEvent = GetReaderEvent();
  594. Win4Assert(hReaderEvent);
  595. dwStatus = WaitForSingleObject(hReaderEvent, INFINITE);
  596. Win4Assert(dwStatus == WAIT_OBJECT_0);
  597. Win4Assert((_dwState & READERS_MASK) < READERS_MASK);
  598. dwModifyState += READER;
  599. hr = S_OK;
  600. }
  601. RWResetEvent(hReaderEvent);
  602. dwKnownState = ModifyState(dwModifyState);
  603. }
  604. // Check if the thread became a reader
  605. if(dwStatus == WAIT_OBJECT_0)
  606. {
  607. break;
  608. }
  609. }
  610. }
  611. else
  612. {
  613. dwCurrentState = _dwState;
  614. }
  615. if (RPC_E_TIMEOUT == hr)
  616. {
  617. DbgPrint("%x:%x> Timed out trying to acquire reader lock 0x%p, WriterID = %x. Switch to the WriterID thread and examine why it is blocked.\n",
  618. GetCurrentProcessId(), GetCurrentThreadId(), this, _dwWriterID);
  619. #if DBG==1
  620. _dwDeadLockCounter++;
  621. #endif
  622. hr = S_OK;
  623. if(fBreakOnErrors())
  624. DebugBreak();
  625. }
  626. #ifdef _X86_
  627. _asm { pause }
  628. #endif
  629. } while(SUCCEEDED(hr));
  630. // Sanity checks
  631. if(SUCCEEDED(hr))
  632. {
  633. Win4Assert((_dwState & WRITER) == 0);
  634. Win4Assert(_dwState & READERS_MASK);
  635. *pwReaderLevel = 1;
  636. #ifdef RWLOCK_STATISTICS
  637. InterlockedIncrement((LONG *) &_dwReaderEntryCount);
  638. #endif
  639. #if LOCK_PERF==1
  640. gLockTracker.ReaderEntered(pszFile, dwLine, pszLockName, this);
  641. #endif
  642. }
  643. }
  644. }
  645. // Check failure return
  646. #if RWLOCK_FULL_FUNCTIONALITY
  647. if(FAILED(hr) && (fReturnErrors == FALSE))
  648. #else
  649. if(FAILED(hr))
  650. #endif
  651. {
  652. Win4Assert(!"Failed to acquire reader lock");
  653. if(fBreakOnErrors())
  654. DebugBreak();
  655. TerminateProcess(GetCurrentProcess(), RWLOCK_FATALFAILURE);
  656. }
  657. }
  658. return(hr);
  659. }
  660. //+-------------------------------------------------------------------
  661. //
  662. // Method: CRWLock::AcquireWriterLock public
  663. //
  664. // Synopsis: Makes the thread a writer. Supports nested writer
  665. // locks
  666. //
  667. // History: 21-Aug-98 Gopalk Created
  668. //
  669. //+-------------------------------------------------------------------
  670. HRESULT CRWLock::AcquireWriterLock(
  671. #ifdef RWLOCK_FULL_FUNCTIONALITY
  672. BOOL fReturnErrors,
  673. DWORD dwDesiredTimeout
  674. #if LOCK_PERF==1
  675. ,
  676. #endif
  677. #endif
  678. #if LOCK_PERF==1
  679. const char *pszFile,
  680. DWORD dwLine,
  681. const char *pszLockName
  682. #endif
  683. )
  684. {
  685. HRESULT hr = S_OK;
  686. DWORD dwThreadID = GetCurrentThreadId();
  687. #ifndef RWLOCK_FULL_FUNCTIONALITY
  688. DWORD dwDesiredTimeout = gdwDefaultTimeout;
  689. #endif
  690. // Ensure that the lock was initialized
  691. if(!IsInitialized())
  692. Initialize();
  693. // Check if the thread already has writer lock
  694. if(_dwWriterID == dwThreadID)
  695. {
  696. ++_wWriterLevel;
  697. }
  698. else
  699. {
  700. DWORD dwCurrentState, dwKnownState;
  701. DWORD dwSpinCount = 0;
  702. dwCurrentState = _dwState;
  703. do
  704. {
  705. dwKnownState = dwCurrentState;
  706. // Writer need not wait if there are no readers and writer
  707. if(dwKnownState == 0)
  708. {
  709. // Can be a writer
  710. dwCurrentState = InterlockedCompareExchange((LONG *) &_dwState,
  711. WRITER,
  712. dwKnownState);
  713. if(dwCurrentState == dwKnownState)
  714. {
  715. // Only writer
  716. break;
  717. }
  718. }
  719. // Check for too many waiting writers
  720. else if(((dwKnownState & WAITING_WRITERS_MASK) == WAITING_WRITERS_MASK))
  721. {
  722. RWSleep(1000);
  723. dwSpinCount = 0;
  724. dwCurrentState = _dwState;
  725. }
  726. // Check if events are being cached
  727. #ifdef RWLOCK_FULL_FUNCTIONALITY
  728. else if((dwKnownState & CACHING_EVENTS) == CACHING_EVENTS)
  729. {
  730. if(++dwSpinCount > gdwDefaultSpinCount)
  731. {
  732. RWSleep(10);
  733. dwSpinCount = 0;
  734. }
  735. dwCurrentState = _dwState;
  736. }
  737. #endif
  738. // Check spin count
  739. else if(++dwSpinCount > gdwDefaultSpinCount)
  740. {
  741. // Add to waiting writers
  742. dwCurrentState = InterlockedCompareExchange((LONG *) &_dwState,
  743. (dwKnownState + WAITING_WRITER),
  744. dwKnownState);
  745. if(dwCurrentState == dwKnownState)
  746. {
  747. HANDLE hWriterEvent;
  748. DWORD dwStatus;
  749. DWORD dwModifyState;
  750. BOOL fLoopback;
  751. // One more waiting writer
  752. #ifdef RWLOCK_STATISTICS
  753. InterlockedIncrement((LONG *) &_dwWriterContentionCount);
  754. #endif
  755. #if LOCK_PERF==1
  756. gLockTracker.WriterWaiting(pszFile, dwLine, pszLockName, this);
  757. #endif
  758. do
  759. {
  760. fLoopback = FALSE;
  761. hr = S_OK;
  762. hWriterEvent = GetWriterEvent();
  763. if(hWriterEvent)
  764. {
  765. dwStatus = WaitForSingleObject(hWriterEvent, dwDesiredTimeout);
  766. }
  767. else
  768. {
  769. ComDebOut((DEB_WARN,
  770. "AcquireWriterLock failed to create writer "
  771. "event for RWLock 0x%x\n", this));
  772. dwStatus = WAIT_FAILED;
  773. hr = RPC_E_OUT_OF_RESOURCES;
  774. }
  775. if(dwStatus == WAIT_OBJECT_0)
  776. {
  777. Win4Assert(_dwState & WRITER_SIGNALED);
  778. dwModifyState = WRITER - WAITING_WRITER - WRITER_SIGNALED;
  779. }
  780. else
  781. {
  782. dwModifyState = -WAITING_WRITER;
  783. if(dwStatus == WAIT_TIMEOUT)
  784. {
  785. ComDebOut((DEB_WARN,
  786. "Timed out trying to acquire writer "
  787. "lock for RWLock 0x%x\n", this));
  788. hr = RPC_E_TIMEOUT;
  789. }
  790. else if(SUCCEEDED(hr))
  791. {
  792. ComDebOut((DEB_ERROR,
  793. "WaitForSingleObject Failed for "
  794. "RWLock 0x%x\n", this));
  795. hr = HRESULT_FROM_WIN32(GetLastError());
  796. }
  797. }
  798. // One less waiting writer and he may have become a writer
  799. dwKnownState = ModifyState(dwModifyState);
  800. // Check for last timing out signaled waiting writer
  801. if((dwStatus != WAIT_OBJECT_0) &&
  802. (dwKnownState & WRITER_SIGNALED) &&
  803. ((dwKnownState & WAITING_WRITERS_MASK) == WAITING_WRITER))
  804. {
  805. fLoopback = TRUE;
  806. dwCurrentState = _dwState;
  807. do
  808. {
  809. dwKnownState = dwCurrentState;
  810. if(((dwKnownState & WAITING_WRITERS_MASK) == 0) &&
  811. (dwKnownState & WRITER_SIGNALED))
  812. {
  813. dwCurrentState = InterlockedCompareExchange((LONG *) &_dwState,
  814. (dwKnownState + WAITING_WRITER),
  815. dwKnownState);
  816. }
  817. else
  818. {
  819. Win4Assert(FAILED(hr));
  820. fLoopback = FALSE;
  821. break;
  822. }
  823. #ifdef _X86_
  824. // Try to avoid pausing when we won't loop.
  825. if (dwCurrentState != dwKnownState)
  826. {
  827. _asm { pause }
  828. }
  829. #endif
  830. } while(dwCurrentState != dwKnownState);
  831. }
  832. if(fLoopback)
  833. {
  834. ComDebOut((DEB_WARN,
  835. "Retry of timing out writer for RWLock 0x%x\n",
  836. this));
  837. // Reduce the timeout value for retries
  838. dwDesiredTimeout = 100;
  839. }
  840. } while(fLoopback);
  841. // Check if the thread became a writer
  842. if(dwStatus == WAIT_OBJECT_0)
  843. break;
  844. }
  845. }
  846. else
  847. {
  848. dwCurrentState = _dwState;
  849. }
  850. if (RPC_E_TIMEOUT == hr)
  851. {
  852. DbgPrint("%x:%x> Timed out trying to acquire writer lock 0x%p, WriterID = %x. If WriterID is not zero, switch to the WriterID thread and examine why it is blocked.\n ",
  853. GetCurrentProcessId(), GetCurrentThreadId(), this, _dwWriterID);
  854. #if DBG==1
  855. _dwDeadLockCounter++;
  856. #endif
  857. hr = S_OK;
  858. if(fBreakOnErrors())
  859. DebugBreak();
  860. }
  861. #ifdef _X86_
  862. _asm { pause }
  863. #endif
  864. } while(SUCCEEDED(hr));
  865. // Sanity checks
  866. if(SUCCEEDED(hr))
  867. {
  868. Win4Assert(_dwState & WRITER);
  869. Win4Assert((_dwState & WRITER_SIGNALED) == 0);
  870. Win4Assert((_dwState & READERS_MASK) == 0);
  871. Win4Assert(_dwWriterID == 0);
  872. // Save threadid of the writer
  873. _dwWriterID = dwThreadID;
  874. _wWriterLevel = 1;
  875. ++_dwWriterSeqNum;
  876. #ifdef RWLOCK_STATISTICS
  877. ++_dwWriterEntryCount;
  878. #endif
  879. #if LOCK_PERF==1
  880. gLockTracker.WriterEntered(pszFile, dwLine, pszLockName, this);
  881. #endif
  882. }
  883. #ifdef RWLOCK_FULL_FUNCTIONALITY
  884. else if(fReturnErrors == FALSE)
  885. #else
  886. else
  887. #endif
  888. {
  889. Win4Assert(!"Failed to acquire writer lock");
  890. if(fBreakOnErrors())
  891. DebugBreak();
  892. TerminateProcess(GetCurrentProcess(), RWLOCK_FATALFAILURE);
  893. }
  894. }
  895. return(hr);
  896. }
  897. //+-------------------------------------------------------------------
  898. //
  899. // Method: CRWLock::ReleaseWriterLock public
  900. //
  901. // Synopsis: Removes the thread as a writer if not a nested
  902. // call to release the lock
  903. //
  904. // History: 21-Aug-98 Gopalk Created
  905. //
  906. //+-------------------------------------------------------------------
  907. HRESULT CRWLock::ReleaseWriterLock()
  908. {
  909. HRESULT hr = S_OK;
  910. DWORD dwThreadID = GetCurrentThreadId();
  911. // Check validity of caller
  912. if(_dwWriterID == dwThreadID)
  913. {
  914. // Sanity check
  915. Win4Assert(IsInitialized());
  916. // Check for nested release
  917. if(--_wWriterLevel == 0)
  918. {
  919. DWORD dwCurrentState, dwKnownState, dwModifyState;
  920. BOOL fCacheEvents;
  921. HANDLE hReaderEvent = NULL, hWriterEvent = NULL;
  922. // Not a writer any more
  923. #if LOCK_PERF==1
  924. gLockTracker.WriterLeaving(this);
  925. #endif
  926. _dwWriterID = 0;
  927. dwCurrentState = _dwState;
  928. do
  929. {
  930. dwKnownState = dwCurrentState;
  931. dwModifyState = -WRITER;
  932. fCacheEvents = FALSE;
  933. if(dwKnownState & WAITING_READERS_MASK)
  934. {
  935. hReaderEvent = GetReaderEvent();
  936. if(hReaderEvent == NULL)
  937. {
  938. ComDebOut((DEB_WARN,
  939. "ReleaseWriterLock failed to create "
  940. "reader event for RWLock 0x%x\n", this));
  941. RWSleep(100);
  942. dwCurrentState = _dwState;
  943. dwKnownState = 0;
  944. Win4Assert(dwCurrentState != dwKnownState);
  945. #ifdef _X86_
  946. _asm { pause }
  947. #endif
  948. continue;
  949. }
  950. dwModifyState += READER_SIGNALED;
  951. }
  952. else if(dwKnownState & WAITING_WRITERS_MASK)
  953. {
  954. hWriterEvent = GetWriterEvent();
  955. if(hWriterEvent == NULL)
  956. {
  957. ComDebOut((DEB_WARN,
  958. "ReleaseWriterLock failed to create "
  959. "writer event for RWLock 0x%x\n", this));
  960. RWSleep(100);
  961. dwCurrentState = _dwState;
  962. dwKnownState = 0;
  963. Win4Assert(dwCurrentState != dwKnownState);
  964. #ifdef _X86_
  965. _asm { pause }
  966. #endif
  967. continue;
  968. }
  969. dwModifyState += WRITER_SIGNALED;
  970. }
  971. #ifdef RWLOCK_FULL_FUNCTIONALITY
  972. else if((_wFlags & RWLOCKFLAG_CACHEEVENTS) &&
  973. (dwKnownState == WRITER) &&
  974. (_hReaderEvent || _hWriterEvent) &&
  975. ((dwKnownState & CACHING_EVENTS) == 0))
  976. {
  977. fCacheEvents = TRUE;
  978. dwModifyState += CACHING_EVENTS;
  979. }
  980. #endif
  981. // Sanity checks
  982. Win4Assert((dwKnownState & CACHING_EVENTS) == 0);
  983. Win4Assert((dwKnownState & READERS_MASK) == 0);
  984. dwCurrentState = InterlockedCompareExchange((LONG *) &_dwState,
  985. (dwKnownState + dwModifyState),
  986. dwKnownState);
  987. #ifdef _X86_
  988. _asm { pause }
  989. #endif
  990. } while(dwCurrentState != dwKnownState);
  991. // Check for waiting readers
  992. if(dwKnownState & WAITING_READERS_MASK)
  993. {
  994. Win4Assert(_dwState & READER_SIGNALED);
  995. Win4Assert(hReaderEvent);
  996. RWSetEvent(hReaderEvent);
  997. }
  998. // Check for waiting writers
  999. else if(dwKnownState & WAITING_WRITERS_MASK)
  1000. {
  1001. Win4Assert(_dwState & WRITER_SIGNALED);
  1002. Win4Assert(hWriterEvent);
  1003. RWSetEvent(hWriterEvent);
  1004. }
  1005. #ifdef RWLOCK_FULL_FUNCTIONALITY
  1006. // Check for the need to release events
  1007. else if(fCacheEvents)
  1008. {
  1009. ReleaseEvents();
  1010. }
  1011. #endif
  1012. }
  1013. }
  1014. else
  1015. {
  1016. hr = HRESULT_FROM_WIN32(ERROR_NOT_OWNER);
  1017. Win4Assert(!"Attempt to release writer lock on a wrong thread");
  1018. #ifdef RWLOCK_FULL_FUNCTIONALITY
  1019. if((_wFlags & RWLOCKFLAG_RETURNERRORS) == 0)
  1020. #endif
  1021. {
  1022. if(fBreakOnErrors())
  1023. DebugBreak();
  1024. TerminateProcess(GetCurrentProcess(), RWLOCK_FATALFAILURE);
  1025. }
  1026. }
  1027. return(hr);
  1028. }
  1029. //+-------------------------------------------------------------------
  1030. //
  1031. // Method: CRWLock::ReleaseReaderLock public
  1032. //
  1033. // Synopsis: Removes the thread as a reader
  1034. //
  1035. // History: 21-Aug-98 Gopalk Created
  1036. //
  1037. //+-------------------------------------------------------------------
  1038. HRESULT CRWLock::ReleaseReaderLock()
  1039. {
  1040. HRESULT hr = S_OK;
  1041. // Check if the thread has writer lock
  1042. if(_dwWriterID == GetCurrentThreadId())
  1043. {
  1044. hr = ReleaseWriterLock();
  1045. }
  1046. else
  1047. {
  1048. WORD *pwReaderLevel;
  1049. hr = GetTLSLockData(&pwReaderLevel);
  1050. if(SUCCEEDED(hr))
  1051. {
  1052. if(*pwReaderLevel > 1)
  1053. {
  1054. --(*pwReaderLevel);
  1055. }
  1056. else if(*pwReaderLevel == 1)
  1057. {
  1058. DWORD dwCurrentState, dwKnownState, dwModifyState;
  1059. BOOL fLastReader, fCacheEvents;
  1060. HANDLE hReaderEvent = NULL, hWriterEvent = NULL;
  1061. // Sanity checks
  1062. Win4Assert((_dwState & WRITER) == 0);
  1063. Win4Assert(_dwState & READERS_MASK);
  1064. // Not a reader any more
  1065. *pwReaderLevel = 0;
  1066. dwCurrentState = _dwState;
  1067. do
  1068. {
  1069. dwKnownState = dwCurrentState;
  1070. dwModifyState = -READER;
  1071. if((dwKnownState & (READERS_MASK | READER_SIGNALED)) == READER)
  1072. {
  1073. fLastReader = TRUE;
  1074. fCacheEvents = FALSE;
  1075. if(dwKnownState & WAITING_WRITERS_MASK)
  1076. {
  1077. hWriterEvent = GetWriterEvent();
  1078. if(hWriterEvent == NULL)
  1079. {
  1080. ComDebOut((DEB_WARN,
  1081. "ReleaseReaderLock failed to create "
  1082. "writer event for RWLock 0x%x\n", this));
  1083. RWSleep(100);
  1084. dwCurrentState = _dwState;
  1085. dwKnownState = 0;
  1086. Win4Assert(dwCurrentState != dwKnownState);
  1087. #ifdef _X86_
  1088. _asm { pause }
  1089. #endif
  1090. continue;
  1091. }
  1092. dwModifyState += WRITER_SIGNALED;
  1093. }
  1094. else if(dwKnownState & WAITING_READERS_MASK)
  1095. {
  1096. hReaderEvent = GetReaderEvent();
  1097. if(hReaderEvent == NULL)
  1098. {
  1099. ComDebOut((DEB_WARN,
  1100. "ReleaseReaderLock failed to create "
  1101. "reader event\n", this));
  1102. RWSleep(100);
  1103. dwCurrentState = _dwState;
  1104. dwKnownState = 0;
  1105. Win4Assert(dwCurrentState != dwKnownState);
  1106. #ifdef _X86_
  1107. _asm { pause }
  1108. #endif
  1109. continue;
  1110. }
  1111. dwModifyState += READER_SIGNALED;
  1112. }
  1113. #ifdef RWLOCK_FULL_FUNCTIONALITY
  1114. else if((_wFlags & RWLOCKFLAG_CACHEEVENTS) &&
  1115. (dwKnownState == READER) &&
  1116. (_hReaderEvent || _hWriterEvent))
  1117. {
  1118. fCacheEvents = TRUE;
  1119. dwModifyState += (WRITER_SIGNALED + READER_SIGNALED);
  1120. }
  1121. #endif
  1122. }
  1123. else
  1124. {
  1125. fLastReader = FALSE;
  1126. }
  1127. // Sanity checks
  1128. Win4Assert((dwKnownState & WRITER) == 0);
  1129. Win4Assert(dwKnownState & READERS_MASK);
  1130. dwCurrentState = InterlockedCompareExchange((LONG *) &_dwState,
  1131. (dwKnownState + dwModifyState),
  1132. dwKnownState);
  1133. #ifdef _X86_
  1134. // Try to avoid pausing when we won't loop.
  1135. if (dwCurrentState != dwKnownState)
  1136. {
  1137. _asm { pause }
  1138. }
  1139. #endif
  1140. } while(dwCurrentState != dwKnownState);
  1141. #if LOCK_PERF==1
  1142. gLockTracker.ReaderLeaving(this);
  1143. #endif
  1144. // Check for last reader
  1145. if(fLastReader)
  1146. {
  1147. // Check for waiting writers
  1148. if(dwKnownState & WAITING_WRITERS_MASK)
  1149. {
  1150. Win4Assert(_dwState & WRITER_SIGNALED);
  1151. Win4Assert(hWriterEvent);
  1152. RWSetEvent(hWriterEvent);
  1153. }
  1154. // Check for waiting readers
  1155. else if(dwKnownState & WAITING_READERS_MASK)
  1156. {
  1157. Win4Assert(_dwState & READER_SIGNALED);
  1158. Win4Assert(hReaderEvent);
  1159. RWSetEvent(hReaderEvent);
  1160. }
  1161. #ifdef RWLOCK_FULL_FUNCTIONALITY
  1162. // Check for the need to release events
  1163. else if(fCacheEvents)
  1164. {
  1165. ReleaseEvents();
  1166. }
  1167. #endif
  1168. }
  1169. }
  1170. else
  1171. {
  1172. hr = HRESULT_FROM_WIN32(ERROR_NOT_OWNER);
  1173. }
  1174. }
  1175. else
  1176. {
  1177. hr = HRESULT_FROM_WIN32(ERROR_NOT_OWNER);
  1178. }
  1179. if(FAILED(hr))
  1180. {
  1181. #ifdef RWLOCK_FULL_FUNCTIONALITY
  1182. if((_wFlags & RWLOCKFLAG_RETURNERRORS) == 0)
  1183. #endif
  1184. {
  1185. Win4Assert(!"Attempt to release reader lock on a wrong thread");
  1186. if(fBreakOnErrors())
  1187. DebugBreak();
  1188. TerminateProcess(GetCurrentProcess(), RWLOCK_FATALFAILURE);
  1189. }
  1190. }
  1191. }
  1192. return(hr);
  1193. }
  1194. //+-------------------------------------------------------------------
  1195. //
  1196. // Method: CRWLock::UpgradeToWriterLock public
  1197. //
  1198. // Synopsis: Upgrades to a writer lock. It returns a BOOL that
  1199. // indicates intervening writes.
  1200. //
  1201. // History: 21-Aug-98 Gopalk Created
  1202. //
  1203. //+-------------------------------------------------------------------
  1204. HRESULT CRWLock::UpgradeToWriterLock(LockCookie *pLockCookie,
  1205. BOOL *pfInterveningWrites
  1206. #ifdef RWLOCK_FULL_FUNCTIONALITY
  1207. ,
  1208. BOOL fReturnErrors,
  1209. DWORD dwDesiredTimeout
  1210. #endif
  1211. #if LOCK_PERF==1
  1212. ,
  1213. const char *pszFile,
  1214. DWORD dwLine,
  1215. const char *pszLockName
  1216. #endif
  1217. )
  1218. {
  1219. HRESULT hr;
  1220. DWORD dwThreadID;
  1221. // Initialize the cookie
  1222. memset(pLockCookie, 0, sizeof(LockCookie));
  1223. if(pfInterveningWrites)
  1224. *pfInterveningWrites = TRUE;
  1225. dwThreadID = GetCurrentThreadId();
  1226. // Check if the thread is already a writer
  1227. if(_dwWriterID == dwThreadID)
  1228. {
  1229. // Update cookie state
  1230. pLockCookie->dwFlags = UPGRADE_COOKIE | COOKIE_WRITER;
  1231. pLockCookie->wWriterLevel = _wWriterLevel;
  1232. // No intevening writes
  1233. if(pfInterveningWrites)
  1234. *pfInterveningWrites = FALSE;
  1235. // Acquire the writer lock again
  1236. hr = AcquireWriterLock();
  1237. }
  1238. else
  1239. {
  1240. WORD *pwReaderLevel;
  1241. // Ensure that the lock was initialized
  1242. if(!IsInitialized())
  1243. Initialize();
  1244. hr = GetTLSLockData(&pwReaderLevel);
  1245. if(SUCCEEDED(hr))
  1246. {
  1247. BOOL fAcquireWriterLock;
  1248. DWORD dwWriterSeqNum = 0;
  1249. // Check if the thread is a reader
  1250. if(*pwReaderLevel != 0)
  1251. {
  1252. // Sanity check
  1253. Win4Assert(_dwState & READERS_MASK);
  1254. // Save lock state in the cookie
  1255. pLockCookie->dwFlags = UPGRADE_COOKIE | COOKIE_READER;
  1256. pLockCookie->pwReaderLevel = pwReaderLevel;
  1257. pLockCookie->wReaderLevel = *pwReaderLevel;
  1258. // If there is only one reader, try to convert reader to a writer
  1259. DWORD dwKnownState = InterlockedCompareExchange((LONG *) &_dwState,
  1260. WRITER,
  1261. READER);
  1262. if(dwKnownState == READER)
  1263. {
  1264. // Thread is no longer a reader
  1265. *pwReaderLevel = 0;
  1266. // Save threadid of the writer
  1267. _dwWriterID = dwThreadID;
  1268. _wWriterLevel = 1;
  1269. ++_dwWriterSeqNum;
  1270. fAcquireWriterLock = FALSE;
  1271. // No intevening writes
  1272. if(pfInterveningWrites)
  1273. *pfInterveningWrites = FALSE;
  1274. #if RWLOCK_STATISTICS
  1275. ++_dwWriterEntryCount;
  1276. #endif
  1277. #if LOCK_PERF==1
  1278. gLockTracker.ReaderLeaving(this);
  1279. gLockTracker.WriterEntered(pszFile, dwLine, pszLockName, this);
  1280. #endif
  1281. }
  1282. else
  1283. {
  1284. // Note the current sequence number of the writer lock
  1285. dwWriterSeqNum = _dwWriterSeqNum;
  1286. // Release the reader lock
  1287. *pwReaderLevel = 1;
  1288. hr = ReleaseReaderLock();
  1289. Win4Assert(SUCCEEDED(hr));
  1290. fAcquireWriterLock = TRUE;
  1291. }
  1292. }
  1293. else
  1294. {
  1295. fAcquireWriterLock = TRUE;
  1296. pLockCookie->dwFlags = UPGRADE_COOKIE | COOKIE_NONE;
  1297. }
  1298. // Check for the need to acquire the writer lock
  1299. if(fAcquireWriterLock)
  1300. {
  1301. hr = AcquireWriterLock(
  1302. #ifdef RWLOCK_FULL_FUNCTIONALITY
  1303. TRUE, dwDesiredTimeout
  1304. #if LOCK_PERF==1
  1305. ,
  1306. #endif
  1307. #endif
  1308. #if LOCK_PERF==1
  1309. pszFile, dwLine, pszLockName
  1310. #endif
  1311. );
  1312. if(SUCCEEDED(hr))
  1313. {
  1314. // Check for intevening writes
  1315. if((_dwWriterSeqNum == (dwWriterSeqNum + 1)) &&
  1316. pfInterveningWrites)
  1317. *pfInterveningWrites = FALSE;
  1318. }
  1319. else
  1320. {
  1321. if(pLockCookie->dwFlags & COOKIE_READER)
  1322. {
  1323. #ifdef RWLOCK_FULL_FUNCTIONALITY
  1324. DWORD dwTimeout = (dwDesiredTimeout > gdwReasonableTimeout)
  1325. ? dwDesiredTimeout
  1326. : gdwReasonableTimeout;
  1327. #endif
  1328. HRESULT hr1 = AcquireReaderLock(
  1329. #ifdef RWLOCK_FULL_FUNCTIONALITY
  1330. FALSE, dwTimeout
  1331. #if LOCK_PERF==1
  1332. ,
  1333. #endif
  1334. #endif
  1335. #if LOCK_PERF==1
  1336. pszFile, dwLine, pszLockName
  1337. #endif
  1338. );
  1339. if(SUCCEEDED(hr1))
  1340. {
  1341. *pwReaderLevel = pLockCookie->wReaderLevel;
  1342. }
  1343. else
  1344. {
  1345. Win4Assert(!"Failed to reacquire reader lock");
  1346. if(fBreakOnErrors())
  1347. DebugBreak();
  1348. TerminateProcess(GetCurrentProcess(), RWLOCK_FATALFAILURE);
  1349. }
  1350. }
  1351. }
  1352. }
  1353. }
  1354. }
  1355. // Check failure return
  1356. if(FAILED(hr))
  1357. {
  1358. pLockCookie->dwFlags = INVALID_COOKIE;
  1359. #ifdef RWLOCK_FULL_FUNCTIONALITY
  1360. if(fReturnErrors == FALSE)
  1361. {
  1362. Win4Assert(!"Failed to upgrade the lock");
  1363. if(fBreakOnErrors())
  1364. DebugBreak();
  1365. TerminateProcess(GetCurrentProcess(), RWLOCK_FATALFAILURE);
  1366. }
  1367. #endif
  1368. }
  1369. return(hr);
  1370. }
  1371. //+-------------------------------------------------------------------
  1372. //
  1373. // Method: CRWLock::DowngradeFromWriterLock public
  1374. //
  1375. // Synopsis: Downgrades from a writer lock.
  1376. //
  1377. // History: 21-Aug-98 Gopalk Created
  1378. //
  1379. //+-------------------------------------------------------------------
  1380. HRESULT CRWLock::DowngradeFromWriterLock(LockCookie *pLockCookie
  1381. #if LOCK_PERF==1
  1382. ,
  1383. const char *pszFile,
  1384. DWORD dwLine,
  1385. const char *pszLockName
  1386. #endif
  1387. )
  1388. {
  1389. HRESULT hr = S_OK;
  1390. // Ensure that the cookie is valid
  1391. if(pLockCookie->dwFlags & UPGRADE_COOKIE)
  1392. {
  1393. DWORD dwThreadID = GetCurrentThreadId();
  1394. // Sanity check
  1395. Win4Assert((pLockCookie->pwReaderLevel == NULL) ||
  1396. (*pLockCookie->pwReaderLevel == 0));
  1397. // Ensure that the thread is a writer
  1398. if(_dwWriterID == dwThreadID)
  1399. {
  1400. // Release the writer lock
  1401. hr = ReleaseWriterLock();
  1402. if(SUCCEEDED(hr))
  1403. {
  1404. // Check if the thread was a writer
  1405. if(_dwWriterID == dwThreadID)
  1406. {
  1407. // Ensure that the thread was a writer and that
  1408. // nesting level was restored to the previous
  1409. // value
  1410. if(((pLockCookie->dwFlags & COOKIE_WRITER) == 0) ||
  1411. (pLockCookie->wWriterLevel != _wWriterLevel))
  1412. {
  1413. Win4Assert(!"Writer lock incorrectly nested");
  1414. hr = E_FAIL;
  1415. }
  1416. }
  1417. // Check if the thread was a reader
  1418. else if(pLockCookie->dwFlags & COOKIE_READER)
  1419. {
  1420. #ifdef RWLOCK_FULL_FUNCTIONALITY
  1421. DWORD dwTimeout = (gdwDefaultTimeout > gdwReasonableTimeout)
  1422. ? gdwDefaultTimeout
  1423. : gdwReasonableTimeout;
  1424. #endif
  1425. hr = AcquireReaderLock(
  1426. #ifdef RWLOCK_FULL_FUNCTIONALITY
  1427. TRUE, dwTimeout
  1428. #if LOCK_PERF==1
  1429. ,
  1430. #endif
  1431. #endif
  1432. #if LOCK_PERF==1
  1433. pszFile, dwLine, pszLockName
  1434. #endif
  1435. );
  1436. if(SUCCEEDED(hr))
  1437. {
  1438. *pLockCookie->pwReaderLevel = pLockCookie->wReaderLevel;
  1439. }
  1440. else
  1441. {
  1442. Win4Assert(!"Failed to reacquire reader lock");
  1443. }
  1444. }
  1445. else
  1446. {
  1447. Win4Assert(pLockCookie->dwFlags & COOKIE_NONE);
  1448. }
  1449. }
  1450. }
  1451. else
  1452. {
  1453. Win4Assert(!"Attempt to downgrade writer lock on a wrong thread");
  1454. hr = HRESULT_FROM_WIN32(ERROR_NOT_OWNER);
  1455. }
  1456. // Check failure return
  1457. if(FAILED(hr))
  1458. {
  1459. if(fBreakOnErrors())
  1460. DebugBreak();
  1461. TerminateProcess(GetCurrentProcess(), RWLOCK_FATALFAILURE);
  1462. }
  1463. }
  1464. return(hr);
  1465. }
  1466. //+-------------------------------------------------------------------
  1467. //
  1468. // Method: CRWLock::ReleaseLock public
  1469. //
  1470. // Synopsis: Releases the lock held by the current thread
  1471. //
  1472. // History: 21-Aug-98 Gopalk Created
  1473. //
  1474. //+-------------------------------------------------------------------
  1475. HRESULT CRWLock::ReleaseLock(LockCookie *pLockCookie)
  1476. {
  1477. HRESULT hr;
  1478. // Initialize the cookie
  1479. memset(pLockCookie, 0, sizeof(LockCookie));
  1480. // Check if the thread is a writer
  1481. if(_dwWriterID == GetCurrentThreadId())
  1482. {
  1483. // Save lock state in the cookie
  1484. pLockCookie->dwFlags = RELEASE_COOKIE | COOKIE_WRITER;
  1485. pLockCookie->dwWriterSeqNum = _dwWriterSeqNum;
  1486. pLockCookie->wWriterLevel = _wWriterLevel;
  1487. // Release the writer lock
  1488. _wWriterLevel = 1;
  1489. hr = ReleaseWriterLock();
  1490. Win4Assert(SUCCEEDED(hr));
  1491. }
  1492. else
  1493. {
  1494. WORD *pwReaderLevel;
  1495. // Ensure that the lock was initialized
  1496. if(!IsInitialized())
  1497. Initialize();
  1498. hr = GetTLSLockData(&pwReaderLevel);
  1499. if(SUCCEEDED(hr))
  1500. {
  1501. // Check if the thread is a reader
  1502. if(*pwReaderLevel != 0)
  1503. {
  1504. // Save lock state in the cookie
  1505. pLockCookie->dwFlags = RELEASE_COOKIE | COOKIE_READER;
  1506. pLockCookie->pwReaderLevel = pwReaderLevel;
  1507. pLockCookie->wReaderLevel = *pwReaderLevel;
  1508. pLockCookie->dwWriterSeqNum = _dwWriterSeqNum;
  1509. // Release the reader lock
  1510. *pwReaderLevel = 1;
  1511. hr = ReleaseReaderLock();
  1512. Win4Assert(SUCCEEDED(hr));
  1513. }
  1514. else
  1515. {
  1516. pLockCookie->dwFlags = RELEASE_COOKIE | COOKIE_NONE;
  1517. }
  1518. }
  1519. else
  1520. {
  1521. hr = S_OK;
  1522. pLockCookie->dwFlags = RELEASE_COOKIE | COOKIE_NONE;
  1523. }
  1524. }
  1525. return(hr);
  1526. }
  1527. //+-------------------------------------------------------------------
  1528. //
  1529. // Method: CRWLock::RestoreLock public
  1530. //
  1531. // Synopsis: Restore the lock held by the current thread
  1532. //
  1533. // History: 21-Aug-98 Gopalk Created
  1534. //
  1535. //+-------------------------------------------------------------------
  1536. HRESULT CRWLock::RestoreLock(LockCookie *pLockCookie,
  1537. BOOL *pfInterveningWrites
  1538. #if LOCK_PERF==1
  1539. ,
  1540. const char *pszFile,
  1541. DWORD dwLine,
  1542. const char *pszLockName
  1543. #endif
  1544. )
  1545. {
  1546. HRESULT hr = S_OK;
  1547. // Initialize
  1548. if(pfInterveningWrites)
  1549. *pfInterveningWrites = TRUE;
  1550. // Ensure that the cookie is valid
  1551. if(pLockCookie->dwFlags & RELEASE_COOKIE)
  1552. {
  1553. DWORD dwThreadID = GetCurrentThreadId();
  1554. #ifdef RWLOCK_FULL_FUNCTIONALITY
  1555. DWORD dwTimeout = (gdwDefaultTimeout > gdwReasonableTimeout)
  1556. ? gdwDefaultTimeout
  1557. : gdwReasonableTimeout;
  1558. #endif
  1559. // Check if the thread holds reader or writer lock
  1560. if(((pLockCookie->pwReaderLevel != NULL) && (*pLockCookie->pwReaderLevel > 0)) ||
  1561. (_dwWriterID == dwThreadID))
  1562. {
  1563. Win4Assert(!"Thread holds reader or writer lock");
  1564. if(fBreakOnErrors())
  1565. DebugBreak();
  1566. TerminateProcess(GetCurrentProcess(), RWLOCK_FATALFAILURE);
  1567. }
  1568. // Check if the thread was a writer
  1569. else if(pLockCookie->dwFlags & COOKIE_WRITER)
  1570. {
  1571. // Acquire writer lock
  1572. hr = AcquireWriterLock(
  1573. #ifdef RWLOCK_FULL_FUNCTIONALITY
  1574. FALSE, dwTimeout
  1575. #if LOCK_PERF==1
  1576. ,
  1577. #endif
  1578. #endif
  1579. #if LOCK_PERF==1
  1580. pszFile, dwLine, pszLockName
  1581. #endif
  1582. );
  1583. Win4Assert(SUCCEEDED(hr));
  1584. _wWriterLevel = pLockCookie->wWriterLevel;
  1585. if((_dwWriterSeqNum == (pLockCookie->dwWriterSeqNum + 1)) &&
  1586. pfInterveningWrites)
  1587. *pfInterveningWrites = FALSE;
  1588. }
  1589. // Check if the thread was a reader
  1590. else if(pLockCookie->dwFlags & COOKIE_READER)
  1591. {
  1592. hr = AcquireReaderLock(
  1593. #ifdef RWLOCK_FULL_FUNCTIONALITY
  1594. FALSE, dwTimeout
  1595. #if LOCK_PERF==1
  1596. ,
  1597. #endif
  1598. #endif
  1599. #if LOCK_PERF==1
  1600. pszFile, dwLine, pszLockName
  1601. #endif
  1602. );
  1603. Win4Assert(SUCCEEDED(hr));
  1604. *pLockCookie->pwReaderLevel = pLockCookie->wReaderLevel;
  1605. if((_dwWriterSeqNum == (pLockCookie->dwWriterSeqNum + 1)) &&
  1606. pfInterveningWrites)
  1607. *pfInterveningWrites = FALSE;
  1608. }
  1609. else
  1610. {
  1611. Win4Assert(pLockCookie->dwFlags & COOKIE_NONE);
  1612. }
  1613. }
  1614. return(hr);
  1615. }
  1616. //+-------------------------------------------------------------------
  1617. //
  1618. // Method: CStaticRWLock::Initialize public
  1619. //
  1620. // Synopsis: Initializes state. It is important that the
  1621. // default constructor only Zero out the memory
  1622. //
  1623. // History: 21-Aug-98 Gopalk Created
  1624. //
  1625. //+-------------------------------------------------------------------
  1626. extern CRITICAL_SECTION g_OleMutexCreationSem;
  1627. void CStaticRWLock::Initialize()
  1628. {
  1629. // Acquire lock creation critical section
  1630. EnterCriticalSection (&g_OleMutexCreationSem);
  1631. // Prevent second initialization
  1632. if(!IsInitialized())
  1633. {
  1634. _dwLockNum = gdwLockSeqNum++;
  1635. #if LOCK_PERF==1
  1636. gLockTracker.RegisterLock(this, TRUE);
  1637. #endif
  1638. // The initialization should be complete
  1639. // before delegating to the base class
  1640. CRWLock::Initialize();
  1641. }
  1642. // Release lock creation critical section
  1643. LeaveCriticalSection (&g_OleMutexCreationSem);
  1644. return;
  1645. }
  1646. LockEntry * GetLockEntryFromTLS()
  1647. {
  1648. LockEntry *pLockEntry = NULL;
  1649. #ifdef __NOOLETLS__
  1650. pLockEntry = (LockEntry *) TlsGetValue(gLockTlsIdx);
  1651. if (!pLockEntry)
  1652. {
  1653. pLockEntry = (LockEntry *) PrivMemAlloc(sizeof(LockEntry));
  1654. if (pLockEntry)
  1655. {
  1656. memset(pLockEntry, 0, sizeof(LockEntry));
  1657. TlsSetValue(gLockTlsIdx, pLockEntry);
  1658. }
  1659. }
  1660. #else
  1661. HRESULT hr;
  1662. COleTls Tls(hr);
  1663. if(SUCCEEDED(hr))
  1664. {
  1665. pLockEntry = &(Tls->lockEntry);
  1666. }
  1667. #endif
  1668. return pLockEntry;
  1669. }
  1670. //+-------------------------------------------------------------------
  1671. //
  1672. // Method: CStaticRWLock::GetTLSLockData private
  1673. //
  1674. // Synopsis: Obtains the data mainitained in TLS for the lock
  1675. //
  1676. // History: 21-Aug-98 Gopalk Created
  1677. //
  1678. //+-------------------------------------------------------------------
  1679. HRESULT CStaticRWLock::GetTLSLockData(WORD **ppwReaderLevel)
  1680. {
  1681. HRESULT hr = E_OUTOFMEMORY;
  1682. // Ensure that the lock was initialized
  1683. if(IsInitialized())
  1684. {
  1685. LockEntry *pLockEntry = GetLockEntryFromTLS();
  1686. if (pLockEntry)
  1687. {
  1688. // Compute the quotient and remainder
  1689. DWORD dwSkip = _dwLockNum / LOCKS_PER_ENTRY;
  1690. DWORD dwIndex = _dwLockNum % LOCKS_PER_ENTRY;
  1691. // Skip quotient entries
  1692. while(dwSkip && pLockEntry)
  1693. {
  1694. // Allocate the lock entries if needed
  1695. if(pLockEntry->pNext == NULL)
  1696. {
  1697. LockEntry *pEntry;
  1698. pEntry = (LockEntry *) PrivMemAlloc(sizeof(LockEntry));
  1699. if(pEntry)
  1700. {
  1701. memset(pEntry, 0 , sizeof(LockEntry));
  1702. pEntry = (LockEntry *) InterlockedCompareExchangePointer((void **) &(pLockEntry->pNext),
  1703. pEntry,
  1704. NULL);
  1705. if(pEntry)
  1706. PrivMemFree(pEntry);
  1707. }
  1708. }
  1709. // Skip to next lock entry
  1710. pLockEntry = pLockEntry->pNext;
  1711. --dwSkip;
  1712. }
  1713. // Check for OOM
  1714. if(pLockEntry)
  1715. {
  1716. *ppwReaderLevel = &(pLockEntry->wReaderLevel[dwIndex]);
  1717. hr = S_OK;
  1718. }
  1719. else
  1720. {
  1721. *ppwReaderLevel = NULL;
  1722. hr = E_OUTOFMEMORY;
  1723. }
  1724. }
  1725. }
  1726. else
  1727. {
  1728. *ppwReaderLevel = NULL;
  1729. hr = S_FALSE;
  1730. }
  1731. return(hr);
  1732. }