-/*
+/* $Id$
+ *
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/ke/sem.c
* PURPOSE: Implements kernel semaphores
- * PROGRAMMER: David Welch (welch@mcmail.com)
- * UPDATE HISTORY:
- * Created 22/05/98
+ *
+ * PROGRAMMERS: David Welch (welch@mcmail.com)
*/
/* INCLUDES *****************************************************************/
-#include <ddk/ntddk.h>
-#include <internal/ke.h>
-
+#include <ntoskrnl.h>
+#define NDEBUG
#include <internal/debug.h>
/* FUNCTIONS *****************************************************************/
-VOID KeInitializeSemaphore(PKSEMAPHORE Semaphore,
- LONG Count,
- LONG Limit)
+/*
+ * @implemented
+ */
+VOID
+STDCALL
+KeInitializeSemaphore(PKSEMAPHORE Semaphore,
+ LONG Count,
+ LONG Limit)
{
- KeInitializeDispatcherHeader(&Semaphore->Header,SemaphoreType,
- sizeof(KSEMAPHORE)/sizeof(ULONG),
- Count);
- Semaphore->Limit=Limit;
+
+ DPRINT("KeInitializeSemaphore Sem: %x\n", Semaphore);
+
+ /* Simply Initialize the Header */
+ KeInitializeDispatcherHeader(&Semaphore->Header,
+ SemaphoreObject,
+ sizeof(KSEMAPHORE)/sizeof(ULONG),
+ Count);
+
+ /* Set the Limit */
+ Semaphore->Limit = Limit;
}
-LONG KeReadStateSemaphore(PKSEMAPHORE Semaphore)
+/*
+ * @implemented
+ */
+LONG
+STDCALL
+KeReadStateSemaphore(PKSEMAPHORE Semaphore)
{
- return(Semaphore->Header.SignalState);
+ /* Just return the Signal State */
+ return(Semaphore->Header.SignalState);
}
-LONG KeReleaseSemaphore(PKSEMAPHORE Semaphore,
- KPRIORITY Increment,
- LONG Adjustment,
- BOOLEAN Wait)
+/*
+ * @implemented
+ *
+ * FUNCTION: KeReleaseSemaphore releases a given semaphore object. This
+ * routine supplies a runtime priority boost for waiting threads. If this
+ * call sets the semaphore to the Signaled state, the semaphore count is
+ * augmented by the given value. The caller can also specify whether it
+ * will call one of the KeWaitXXX routines as soon as KeReleaseSemaphore
+ * returns control.
+ * ARGUMENTS:
+ * Semaphore = Points to an initialized semaphore object for which the
+ * caller provides the storage.
+ * Increment = Specifies the priority increment to be applied if
+ * releasing the semaphore causes a wait to be
+ * satisfied.
+ * Adjustment = Specifies a value to be added to the current semaphore
+ * count. This value must be positive
+ * Wait = Specifies whether the call to KeReleaseSemaphore is to be
+ * followed immediately by a call to one of the KeWaitXXX.
+ * RETURNS: If the return value is zero, the previous state of the semaphore
+ * object is Not-Signaled.
+ */
+LONG
+STDCALL
+KeReleaseSemaphore(PKSEMAPHORE Semaphore,
+ KPRIORITY Increment,
+ LONG Adjustment,
+ BOOLEAN Wait)
+
{
- ULONG initState = Semaphore->Header.SignalState;
- KeAcquireDispatcherDatabaseLock(Wait);
- if(Semaphore->Limit < initState+Adjustment
- || initState > initState+Adjustment)
- ExRaiseStatus(STATUS_SEMAPHORE_LIMIT_EXCEEDED);
- Semaphore->Header.SignalState+=Adjustment;
- if(initState == 0)
- {
- // wake up SignalState waiters
- KeDispatcherObjectWake(&Semaphore->Header) ;
- }
- KeReleaseDispatcherDatabaseLock(Wait);
- return initState;
+ ULONG InitialState;
+ KIRQL OldIrql;
+ PKTHREAD CurrentThread;
+
+ DPRINT("KeReleaseSemaphore(Semaphore %x, Increment %d, Adjustment %d, Wait %d)\n",
+ Semaphore,
+ Increment,
+ Adjustment,
+ Wait);
+
+ /* Lock the Dispatcher Database */
+ OldIrql = KeAcquireDispatcherDatabaseLock();
+
+ /* Save the Old State */
+ InitialState = Semaphore->Header.SignalState;
+
+ /* Check if the Limit was exceeded */
+ if (Semaphore->Limit < (LONG) InitialState + Adjustment ||
+ InitialState > InitialState + Adjustment) {
+
+ /* Raise an error if it was exceeded */
+ KeReleaseDispatcherDatabaseLock(OldIrql);
+ ExRaiseStatus(STATUS_SEMAPHORE_LIMIT_EXCEEDED);
+ }
+
+ /* Now set the new state */
+ Semaphore->Header.SignalState += Adjustment;
+
+ /* Check if we should wake it */
+ if (InitialState == 0 && !IsListEmpty(&Semaphore->Header.WaitListHead)) {
+
+ /* Wake the Semaphore */
+ KiWaitTest(&Semaphore->Header, Increment);
+ }
+
+ /* If the Wait is true, then return with a Wait and don't unlock the Dispatcher Database */
+ if (Wait == FALSE) {
+
+ /* Release the Lock */
+ KeReleaseDispatcherDatabaseLock(OldIrql);
+
+ } else {
+
+ /* Set a wait */
+ CurrentThread = KeGetCurrentThread();
+ CurrentThread->WaitNext = TRUE;
+ CurrentThread->WaitIrql = OldIrql;
+ }
+
+ /* Return the previous state */
+ return InitialState;
}
+/* EOF */