-/*
- * ReactOS kernel
- * Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-/* $Id: sem.c,v 1.10 2002/09/07 15:12:57 chorns Exp $
+/* $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 <ntoskrnl.h>
-
#define NDEBUG
#include <internal/debug.h>
-
/* FUNCTIONS *****************************************************************/
-VOID STDCALL
-KeInitializeSemaphore (PKSEMAPHORE Semaphore,
- LONG Count,
- LONG Limit)
+/*
+ * @implemented
+ */
+VOID
+STDCALL
+KeInitializeSemaphore(PKSEMAPHORE Semaphore,
+ LONG Count,
+ LONG Limit)
{
- KeInitializeDispatcherHeader(&Semaphore->Header,
- InternalSemaphoreType,
- 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 STDCALL
-KeReadStateSemaphore (PKSEMAPHORE Semaphore)
+/*
+ * @implemented
+ */
+LONG
+STDCALL
+KeReadStateSemaphore(PKSEMAPHORE Semaphore)
{
- return(Semaphore->Header.SignalState);
+ /* Just return the Signal State */
+ return(Semaphore->Header.SignalState);
}
-LONG STDCALL
-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
* 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 InitialState;
-
- DPRINT("KeReleaseSemaphore(Semaphore %x, Increment %d, Adjustment %d, "
- "Wait %d)\n", Semaphore, Increment, Adjustment, Wait);
-
- KeAcquireDispatcherDatabaseLock(Wait);
-
- InitialState = Semaphore->Header.SignalState;
- if (Semaphore->Limit < InitialState + Adjustment ||
- InitialState > InitialState + Adjustment)
- {
- ExRaiseStatus(STATUS_SEMAPHORE_LIMIT_EXCEEDED);
- }
-
- Semaphore->Header.SignalState += Adjustment;
- if (InitialState == 0)
- {
- KeDispatcherObjectWake(&Semaphore->Header);
- }
-
- KeReleaseDispatcherDatabaseLock(Wait);
- return(InitialState);
+ 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 */