3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ke/sem.c
6 * PURPOSE: Implements kernel semaphores
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
11 /* INCLUDES *****************************************************************/
15 #include <internal/debug.h>
17 /* FUNCTIONS *****************************************************************/
24 KeInitializeSemaphore(PKSEMAPHORE Semaphore
,
29 DPRINT("KeInitializeSemaphore Sem: %x\n", Semaphore
);
31 /* Simply Initialize the Header */
32 KeInitializeDispatcherHeader(&Semaphore
->Header
,
34 sizeof(KSEMAPHORE
)/sizeof(ULONG
),
38 Semaphore
->Limit
= Limit
;
46 KeReadStateSemaphore(PKSEMAPHORE Semaphore
)
48 /* Just return the Signal State */
49 return(Semaphore
->Header
.SignalState
);
55 * FUNCTION: KeReleaseSemaphore releases a given semaphore object. This
56 * routine supplies a runtime priority boost for waiting threads. If this
57 * call sets the semaphore to the Signaled state, the semaphore count is
58 * augmented by the given value. The caller can also specify whether it
59 * will call one of the KeWaitXXX routines as soon as KeReleaseSemaphore
62 * Semaphore = Points to an initialized semaphore object for which the
63 * caller provides the storage.
64 * Increment = Specifies the priority increment to be applied if
65 * releasing the semaphore causes a wait to be
67 * Adjustment = Specifies a value to be added to the current semaphore
68 * count. This value must be positive
69 * Wait = Specifies whether the call to KeReleaseSemaphore is to be
70 * followed immediately by a call to one of the KeWaitXXX.
71 * RETURNS: If the return value is zero, the previous state of the semaphore
72 * object is Not-Signaled.
76 KeReleaseSemaphore(PKSEMAPHORE Semaphore
,
84 PKTHREAD CurrentThread
;
86 DPRINT("KeReleaseSemaphore(Semaphore %x, Increment %d, Adjustment %d, Wait %d)\n",
92 /* Lock the Dispatcher Database */
93 OldIrql
= KeAcquireDispatcherDatabaseLock();
95 /* Save the Old State */
96 InitialState
= Semaphore
->Header
.SignalState
;
98 /* Check if the Limit was exceeded */
99 if (Semaphore
->Limit
< (LONG
) InitialState
+ Adjustment
||
100 InitialState
> InitialState
+ Adjustment
) {
102 /* Raise an error if it was exceeded */
103 KeReleaseDispatcherDatabaseLock(OldIrql
);
104 ExRaiseStatus(STATUS_SEMAPHORE_LIMIT_EXCEEDED
);
107 /* Now set the new state */
108 Semaphore
->Header
.SignalState
+= Adjustment
;
110 /* Check if we should wake it */
111 if (InitialState
== 0 && !IsListEmpty(&Semaphore
->Header
.WaitListHead
)) {
113 /* Wake the Semaphore */
114 KiWaitTest(&Semaphore
->Header
, SEMAPHORE_INCREMENT
);
117 /* If the Wait is true, then return with a Wait and don't unlock the Dispatcher Database */
120 /* Release the Lock */
121 KeReleaseDispatcherDatabaseLock(OldIrql
);
126 CurrentThread
= KeGetCurrentThread();
127 CurrentThread
->WaitNext
= TRUE
;
128 CurrentThread
->WaitIrql
= OldIrql
;
131 /* Return the previous state */