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.

227 lines
5.7 KiB

  1. /*++
  2. Copyright (c) 2001-2002 Microsoft Corporation
  3. Module Name:
  4. rwlock.c
  5. Abstract:
  6. Non-inline functions for custom locks
  7. Author:
  8. George V. Reilly Jul-2001
  9. Revision History:
  10. --*/
  11. #include <precomp.h>
  12. #ifdef ALLOC_PRAGMA
  13. #endif // ALLOC_PRAGMA
  14. #if 0
  15. NOT PAGEABLE -- UlpSwitchToThread
  16. NOT PAGEABLE -- UlAcquireRWSpinLockSharedDoSpin
  17. NOT PAGEABLE -- UlAcquireRWSpinLockExclusiveDoSpin
  18. #endif
  19. // ZwYieldExecution is the actual kernel-mode implementation of SwitchToThread.
  20. NTSYSAPI
  21. NTSTATUS
  22. NTAPI
  23. ZwYieldExecution (
  24. VOID
  25. );
  26. /***************************************************************************++
  27. Routine Description:
  28. Yield the processor to another thread
  29. Arguments:
  30. None
  31. Return Value:
  32. None
  33. --***************************************************************************/
  34. VOID
  35. UlpSwitchToThread()
  36. {
  37. //
  38. // If we're running at DISPATCH_LEVEL or higher, the scheduler won't
  39. // run, so other threads can't run on this processor, and the only
  40. // appropriate action is to keep on spinning.
  41. //
  42. if (KeGetCurrentIrql() >= DISPATCH_LEVEL)
  43. return;
  44. //
  45. // Use KeDelayExecutionThread instead? ZwYieldExecution returns
  46. // immediately if there are no runnable threads on this processor.
  47. //
  48. ZwYieldExecution();
  49. }
  50. /***************************************************************************++
  51. Routine Description:
  52. Spin until we can successfully acquire the lock for shared access.
  53. Arguments:
  54. pRWSpinLock - the lock to acquire
  55. Return Value:
  56. None
  57. --***************************************************************************/
  58. VOID
  59. UlAcquireRWSpinLockSharedDoSpin(
  60. PRWSPINLOCK pRWSpinLock
  61. )
  62. {
  63. LONG OuterLoop;
  64. //
  65. // CODEWORK: add some global instrumentation to keep track of
  66. // how often we need to spin and how long we actually spin
  67. //
  68. for (OuterLoop = 1; TRUE; ++OuterLoop)
  69. {
  70. //
  71. // There's no point in spinning on a uniprocessor system because
  72. // we'll just spin and spin and spin until this thread's quantum is
  73. // exhausted. We should yield immediately after one test of the lock
  74. // so that the thread that holds the lock has a chance to proceed and
  75. // release the lock sooner. That's assuming we're running at passive
  76. // level. If we're running at dispatch level and the owning thread
  77. // isn't running, we have a biiiig problem.
  78. //
  79. // On a multiprocessor system, it's appropriate to spin for a while
  80. // before yielding the processor.
  81. //
  82. LONG Spins = (g_UlNumberOfProcessors == 1) ? 1 : 4000;
  83. while (--Spins >= 0)
  84. {
  85. volatile LONG CurrentState = pRWSpinLock->CurrentState;
  86. volatile LONG WritersWaiting = pRWSpinLock->WritersWaiting;
  87. //
  88. // If either (1) write lock is acquired (CurrentState ==
  89. // RWSL_LOCKED) or (2) there is a writer waiting for the lock
  90. // then skip it this time and retry in a tight loop
  91. //
  92. if ((CurrentState != RWSL_LOCKED) && (WritersWaiting == 0))
  93. {
  94. //
  95. // if number of readers is unchanged, increase it by 1
  96. //
  97. if (CurrentState
  98. == (LONG) InterlockedCompareExchange(
  99. (PLONG) &pRWSpinLock->CurrentState,
  100. CurrentState + 1,
  101. CurrentState)
  102. )
  103. {
  104. #if DBG
  105. ASSERT(pRWSpinLock->pExclusiveOwner == NULL);
  106. #endif
  107. return;
  108. }
  109. }
  110. //
  111. // On Jackson technology Pentium 4s, this will give the lion's
  112. // share of the cycles to the other processor on the chip.
  113. //
  114. PAUSE_PROCESSOR;
  115. }
  116. //
  117. // Couldn't acquire the lock in the inner loop. Yield the CPU
  118. // for a while in the hopes that the owning thread will release
  119. // the lock in the meantime.
  120. //
  121. UlpSwitchToThread();
  122. }
  123. } // UlAcquireRWSpinLockSharedDoSpin
  124. /***************************************************************************++
  125. Routine Description:
  126. Spin until we can successfully acquire the lock for exclusive access.
  127. Arguments:
  128. pRWSpinLock - the lock to acquire
  129. Return Value:
  130. None
  131. --***************************************************************************/
  132. VOID
  133. UlAcquireRWSpinLockExclusiveDoSpin(
  134. PRWSPINLOCK pRWSpinLock
  135. )
  136. {
  137. LONG OuterLoop;
  138. for (OuterLoop = 1; TRUE; ++OuterLoop)
  139. {
  140. LONG Spins = (g_UlNumberOfProcessors == 1) ? 1 : 4000;
  141. while (--Spins >= 0)
  142. {
  143. //
  144. // Is the lock currently free for the taking?
  145. //
  146. if (pRWSpinLock->CurrentState == RWSL_FREE)
  147. {
  148. if (RWSL_FREE == InterlockedCompareExchange(
  149. (PLONG) &pRWSpinLock->CurrentState,
  150. RWSL_LOCKED,
  151. RWSL_FREE)
  152. )
  153. {
  154. #if DBG
  155. ASSERT(pRWSpinLock->pExclusiveOwner == NULL);
  156. pRWSpinLock->pExclusiveOwner = PsGetCurrentThread();
  157. #endif
  158. return;
  159. }
  160. }
  161. PAUSE_PROCESSOR;
  162. }
  163. UlpSwitchToThread();
  164. }
  165. } // UlAcquireRWSpinLockExclusiveDoSpin