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.

222 lines
5.0 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. semphobj.c
  5. Abstract:
  6. This module implements the kernel semaphore object. Functions
  7. are provided to initialize, read, and release semaphore objects.
  8. Author:
  9. David N. Cutler (davec) 28-Feb-1989
  10. Environment:
  11. Kernel mode only.
  12. Revision History:
  13. --*/
  14. #include "ki.h"
  15. //
  16. // The following assert macro is used to check that an input semaphore is
  17. // really a ksemaphore and not something else, like deallocated pool.
  18. //
  19. #define ASSERT_SEMAPHORE(E) { \
  20. ASSERT((E)->Header.Type == SemaphoreObject); \
  21. }
  22. VOID
  23. KeInitializeSemaphore (
  24. IN PRKSEMAPHORE Semaphore,
  25. IN LONG Count,
  26. IN LONG Limit
  27. )
  28. /*++
  29. Routine Description:
  30. This function initializes a kernel semaphore object. The initial
  31. count and limit of the object are set to the specified values.
  32. Arguments:
  33. Semaphore - Supplies a pointer to a dispatcher object of type
  34. semaphore.
  35. Count - Supplies the initial count value to be assigned to the
  36. semaphore.
  37. Limit - Supplies the maximum count value that the semaphore
  38. can attain.
  39. Return Value:
  40. None.
  41. --*/
  42. {
  43. //
  44. // Initialize standard dispatcher object header and set initial
  45. // count and maximum count values.
  46. //
  47. Semaphore->Header.Type = SemaphoreObject;
  48. Semaphore->Header.Size = sizeof(KSEMAPHORE) / sizeof(LONG);
  49. Semaphore->Header.SignalState = Count;
  50. InitializeListHead(&Semaphore->Header.WaitListHead);
  51. Semaphore->Limit = Limit;
  52. return;
  53. }
  54. LONG
  55. KeReadStateSemaphore (
  56. IN PRKSEMAPHORE Semaphore
  57. )
  58. /*++
  59. Routine Description:
  60. This function reads the current signal state of a semaphore object.
  61. Arguments:
  62. Semaphore - Supplies a pointer to a dispatcher object of type
  63. semaphore.
  64. Return Value:
  65. The current signal state of the semaphore object.
  66. --*/
  67. {
  68. ASSERT_SEMAPHORE( Semaphore );
  69. //
  70. // Return current signal state of semaphore object.
  71. //
  72. return Semaphore->Header.SignalState;
  73. }
  74. LONG
  75. KeReleaseSemaphore (
  76. IN PRKSEMAPHORE Semaphore,
  77. IN KPRIORITY Increment,
  78. IN LONG Adjustment,
  79. IN BOOLEAN Wait
  80. )
  81. /*++
  82. Routine Description:
  83. This function releases a semaphore by adding the specified adjustment
  84. value to the current semaphore count and attempts to satisfy as many
  85. Waits as possible. The previous signal state of the semaphore object
  86. is returned as the function value.
  87. Arguments:
  88. Semaphore - Supplies a pointer to a dispatcher object of type
  89. semaphore.
  90. Increment - Supplies the priority increment that is to be applied
  91. if releasing the semaphore causes a Wait to be satisfied.
  92. Adjustment - Supplies value that is to be added to the current
  93. semaphore count.
  94. Wait - Supplies a boolean value that signifies whether the call to
  95. KeReleaseSemaphore will be immediately followed by a call to one
  96. of the kernel Wait functions.
  97. Return Value:
  98. The previous signal state of the semaphore object.
  99. --*/
  100. {
  101. LONG NewState;
  102. KIRQL OldIrql;
  103. LONG OldState;
  104. PRKTHREAD Thread;
  105. ASSERT_SEMAPHORE( Semaphore );
  106. ASSERT(KeGetCurrentIrql() <= DISPATCH_LEVEL);
  107. //
  108. // Raise IRQL to dispatcher level and lock dispatcher database.
  109. //
  110. KiLockDispatcherDatabase(&OldIrql);
  111. //
  112. // Capture the current signal state of the semaphore object and
  113. // compute the new count value.
  114. //
  115. OldState = Semaphore->Header.SignalState;
  116. NewState = OldState + Adjustment;
  117. //
  118. // If the new state value is greater than the limit or a carry occurs,
  119. // then unlock the dispatcher database, and raise an exception.
  120. //
  121. if ((NewState > Semaphore->Limit) || (NewState < OldState)) {
  122. KiUnlockDispatcherDatabase(OldIrql);
  123. ExRaiseStatus(STATUS_SEMAPHORE_LIMIT_EXCEEDED);
  124. }
  125. //
  126. // Set the new signal state of the semaphore object and set the wait
  127. // next value. If the previous signal state was Not-Signaled (i.e.
  128. // the count was zero), and the wait queue is not empty, then attempt
  129. // to satisfy as many Waits as possible.
  130. //
  131. Semaphore->Header.SignalState = NewState;
  132. if ((OldState == 0) && (IsListEmpty(&Semaphore->Header.WaitListHead) == FALSE)) {
  133. KiWaitTest(Semaphore, Increment);
  134. }
  135. //
  136. // If the value of the Wait argument is TRUE, then return to the
  137. // caller with IRQL raised and the dispatcher database locked. Else
  138. // release the dispatcher database lock and lower IRQL to its
  139. // previous value.
  140. //
  141. if (Wait != FALSE) {
  142. Thread = KeGetCurrentThread();
  143. Thread->WaitNext = Wait;
  144. Thread->WaitIrql = OldIrql;
  145. } else {
  146. KiUnlockDispatcherDatabase(OldIrql);
  147. }
  148. //
  149. // Return previous signal state of sempahore object.
  150. //
  151. return OldState;
  152. }