2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ke/sem.c
5 * PURPOSE: Implements kernel semaphores
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * David Welch (welch@mcmail.com)
10 /* INCLUDES *****************************************************************/
14 #include <internal/debug.h>
16 /* FUNCTIONS *****************************************************************/
23 KeInitializeSemaphore(PKSEMAPHORE Semaphore
,
27 DPRINT("KeInitializeSemaphore Sem: %x\n", Semaphore
);
29 /* Simply Initialize the Header */
30 KeInitializeDispatcherHeader(&Semaphore
->Header
,
32 sizeof(KSEMAPHORE
) / sizeof(ULONG
),
36 Semaphore
->Limit
= Limit
;
44 KeReadStateSemaphore(PKSEMAPHORE Semaphore
)
46 /* Just return the Signal State */
47 return Semaphore
->Header
.SignalState
;
53 * FUNCTION: KeReleaseSemaphore releases a given semaphore object. This
54 * routine supplies a runtime priority boost for waiting threads. If this
55 * call sets the semaphore to the Signaled state, the semaphore count is
56 * augmented by the given value. The caller can also specify whether it
57 * will call one of the KeWaitXXX routines as soon as KeReleaseSemaphore
60 * Semaphore = Points to an initialized semaphore object for which the
61 * caller provides the storage.
62 * Increment = Specifies the priority increment to be applied if
63 * releasing the semaphore causes a wait to be
65 * Adjustment = Specifies a value to be added to the current semaphore
66 * count. This value must be positive
67 * Wait = Specifies whether the call to KeReleaseSemaphore is to be
68 * followed immediately by a call to one of the KeWaitXXX.
69 * RETURNS: If the return value is zero, the previous state of the semaphore
70 * object is Not-Signaled.
74 KeReleaseSemaphore(PKSEMAPHORE Semaphore
,
79 LONG InitialState
, State
;
81 PKTHREAD CurrentThread
;
83 DPRINT("KeReleaseSemaphore(Semaphore %x, Increment %d, Adjustment %d, Wait %d)\n",
89 /* Lock the Dispatcher Database */
90 OldIrql
= KeAcquireDispatcherDatabaseLock();
92 /* Save the Old State and get new one */
93 InitialState
= Semaphore
->Header
.SignalState
;
94 State
= InitialState
+ Adjustment
;
96 /* Check if the Limit was exceeded */
97 if ((Semaphore
->Limit
< State
) || (InitialState
> State
))
99 /* Raise an error if it was exceeded */
100 KeReleaseDispatcherDatabaseLock(OldIrql
);
101 ExRaiseStatus(STATUS_SEMAPHORE_LIMIT_EXCEEDED
);
104 /* Now set the new state */
105 Semaphore
->Header
.SignalState
= State
;
107 /* Check if we should wake it */
108 if (!(InitialState
) && !(IsListEmpty(&Semaphore
->Header
.WaitListHead
)))
110 /* Wake the Semaphore */
111 KiWaitTest(&Semaphore
->Header
, Increment
);
114 /* If the Wait is true, then return with a Wait and don't unlock the Dispatcher Database */
117 /* Release the Lock */
118 KeReleaseDispatcherDatabaseLock(OldIrql
);
123 CurrentThread
= KeGetCurrentThread();
124 CurrentThread
->WaitNext
= TRUE
;
125 CurrentThread
->WaitIrql
= OldIrql
;
128 /* Return the previous state */