Make sure compiler doesn't optimize our wait loop away. Patch by Thomas Weidenmueller
[reactos.git] / reactos / ntoskrnl / ke / spinlock.c
index 3fef79b..a5ec502 100644 (file)
-/* $Id: spinlock.c,v 1.20 2004/01/18 22:41:53 gdalsnes Exp $
- *
+/*
  * COPYRIGHT:       See COPYING in the top level directory
- * PROJECT:         ReactOS kernel
+ * PROJECT:         ReactOS Kernel
  * FILE:            ntoskrnl/ke/spinlock.c
  * PURPOSE:         Implements spinlocks
- * PROGRAMMER:      David Welch (welch@cwcom.net)
- * UPDATE HISTORY:
- *                  3/6/98: Created
- */
-
-/*
- * NOTE: On a uniprocessor machine spinlocks are implemented by raising
- * the irq level
+ * PROGRAMMERS:     Alex Ionescu (alex@relsoft.net)
+ *                  David Welch (welch@cwcom.net)
  */
 
 /* INCLUDES ****************************************************************/
 
-#include <ddk/ntddk.h>
-#include <roscfg.h>
-
+#include <ntoskrnl.h>
+#define NDEBUG
 #include <internal/debug.h>
 
+#undef KefAcquireSpinLockAtDpcLevel
+#undef KeAcquireSpinLockAtDpcLevel
+#undef KefReleaseSpinLockFromDpcLevel
+#undef KeReleaseSpinLockFromDpcLevel
+
 /* FUNCTIONS ***************************************************************/
 
 /*
  * @implemented
- */
-BOOLEAN STDCALL
-KeSynchronizeExecution (PKINTERRUPT            Interrupt,
-                       PKSYNCHRONIZE_ROUTINE   SynchronizeRoutine,
-                       PVOID                   SynchronizeContext)
-/*
+ *
  * FUNCTION: Synchronizes the execution of a given routine with the ISR
  * of a given interrupt object
  * ARGUMENTS:
  *       Interrupt = Interrupt object to synchronize with
- *       SynchronizeRoutine = Routine to call whose execution is 
+ *       SynchronizeRoutine = Routine to call whose execution is
  *                            synchronized with the ISR
  *       SynchronizeContext = Parameter to pass to the synchronized routine
  * RETURNS: TRUE if the operation succeeded
  */
+BOOLEAN
+STDCALL
+KeSynchronizeExecution(PKINTERRUPT Interrupt,
+                       PKSYNCHRONIZE_ROUTINE SynchronizeRoutine,
+                       PVOID SynchronizeContext)
 {
-   KIRQL oldlvl;
-   BOOLEAN ret;
-   
-   KeRaiseIrql(Interrupt->SynchLevel, &oldlvl);
-   KiAcquireSpinLock(Interrupt->IrqLock);
-   
-   ret = SynchronizeRoutine(SynchronizeContext);
-   
-   KiReleaseSpinLock(Interrupt->IrqLock);
-   KeLowerIrql(oldlvl);
-   
-   return(ret);
+    KIRQL OldIrql;
+    BOOLEAN Status;
+
+    /* Raise IRQL and acquire lock on MP */
+    OldIrql = KeAcquireInterruptSpinLock(Interrupt);
+
+    /* Call the routine */
+    Status = SynchronizeRoutine(SynchronizeContext);
+
+    /* Release lock and lower IRQL */
+    KeReleaseInterruptSpinLock(Interrupt, OldIrql);
+
+    /* Return routine status */
+    return Status;
 }
 
 /*
  * @implemented
  */
-VOID STDCALL
-KeInitializeSpinLock (PKSPIN_LOCK      SpinLock)
+KIRQL
+STDCALL
+KeAcquireInterruptSpinLock(IN PKINTERRUPT Interrupt)
+{
+    KIRQL OldIrql;
+
+    /* Raise IRQL */
+    KeRaiseIrql(Interrupt->SynchronizeIrql, &OldIrql);
+
+    /* Acquire spinlock on MP */
+    KiAcquireSpinLock(Interrupt->ActualLock);
+    return OldIrql;
+}
+
 /*
+ * @implemented
+ *
  * FUNCTION: Initalizes a spinlock
  * ARGUMENTS:
  *           SpinLock = Caller supplied storage for the spinlock
  */
+VOID
+STDCALL
+KeInitializeSpinLock(PKSPIN_LOCK SpinLock)
 {
-   *SpinLock = 0;
+    *SpinLock = 0;
 }
 
-#undef KefAcquireSpinLockAtDpcLevel
-
 /*
  * @implemented
  */
-VOID FASTCALL
+VOID
+FASTCALL
 KefAcquireSpinLockAtDpcLevel(PKSPIN_LOCK SpinLock)
 {
-  assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
-  KiAcquireSpinLock(SpinLock);
+    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+    KiAcquireSpinLock(SpinLock);
 }
 
-#undef KeAcquireSpinLockAtDpcLevel
-
 /*
  * @implemented
- */
-VOID STDCALL
-KeAcquireSpinLockAtDpcLevel (PKSPIN_LOCK       SpinLock)
-/*
- * FUNCTION: Acquires a spinlock when the caller is already running at 
+ *
+ * FUNCTION: Acquires a spinlock when the caller is already running at
  * dispatch level
  * ARGUMENTS:
  *        SpinLock = Spinlock to acquire
  */
+VOID
+STDCALL
+KeAcquireSpinLockAtDpcLevel (PKSPIN_LOCK SpinLock)
 {
-  KefAcquireSpinLockAtDpcLevel(SpinLock);
+    KefAcquireSpinLockAtDpcLevel(SpinLock);
 }
 
-#undef KefReleaseSpinLockFromDpcLevel
-
 /*
  * @implemented
  */
-VOID FASTCALL
+VOID
+FASTCALL
 KefReleaseSpinLockFromDpcLevel(PKSPIN_LOCK SpinLock)
 {
-  assert(KeGetCurrentIrql() == DISPATCH_LEVEL);
-  KiReleaseSpinLock(SpinLock);  
+    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
+    KiReleaseSpinLock(SpinLock);
 }
 
-#undef KeReleaseSpinLockFromDpcLevel
-
 /*
  * @implemented
- */
-VOID STDCALL
-KeReleaseSpinLockFromDpcLevel (PKSPIN_LOCK     SpinLock)
-/*
+ *
  * FUNCTION: Releases a spinlock when the caller was running at dispatch
  * level before acquiring it
- * ARGUMENTS: 
+ * ARGUMENTS:
  *         SpinLock = Spinlock to release
  */
+VOID
+STDCALL
+KeReleaseSpinLockFromDpcLevel (PKSPIN_LOCK SpinLock)
 {
-  KefReleaseSpinLockFromDpcLevel(SpinLock);
+    KefReleaseSpinLockFromDpcLevel(SpinLock);
 }
 
-
 /*
  * @implemented
  */
-VOID FASTCALL
+VOID
+FASTCALL
 KiAcquireSpinLock(PKSPIN_LOCK SpinLock)
 {
-  ULONG i;
-
-  /*
-   * FIXME: This depends on gcc assembling this test to a single load from
-   * the spinlock's value.
-   */
-  if (*SpinLock >= 2)
-  {
-    DbgPrint("Lock %x has bad value %x\n", SpinLock, *SpinLock);
-    KEBUGCHECK(0);
-  }
-   
-  while ((i = InterlockedExchange((LONG *)SpinLock, 1)) == 1)
-  {
-#ifndef MP
-    DbgPrint("Spinning on spinlock %x current value %x\n", SpinLock, i);
-    KEBUGCHECK(0);
-#else /* not MP */
-       /* Avoid reading the value again too fast */
-#endif /* MP */
-  }
+#ifdef CONFIG_SMP
+    for (;;)
+    {
+        /* Try to acquire it */
+        if (InterlockedBitTestAndSet((PLONG)SpinLock, 0))
+        {
+            /* Value changed... wait until it's locked */
+            while (*(volatile KSPIN_LOCK *)SpinLock == 1) YieldProcessor();
+        }
+        else
+        {
+            /* All is well, break out */
+            break;
+        }
+    }
+#endif /* CONFIG_SMP */
 }
 
+/*
+ * @implemented
+ */
+VOID
+STDCALL
+KeReleaseInterruptSpinLock(IN PKINTERRUPT Interrupt,
+                           IN KIRQL OldIrql)
+{
+    /* Release lock on MP */
+    KiReleaseSpinLock(Interrupt->ActualLock);
+
+    /* Lower IRQL */
+    KeLowerIrql(OldIrql);
+}
 
 /*
  * @implemented
  */
-VOID FASTCALL
+VOID
+FASTCALL
 KiReleaseSpinLock(PKSPIN_LOCK SpinLock)
 {
-  if (*SpinLock != 1)
-  {
-    DbgPrint("Releasing unacquired spinlock %x\n", SpinLock);
-    KEBUGCHECK(0);
-  }
-  (void)InterlockedExchange((LONG *)SpinLock, 0);
+#ifdef CONFIG_SMP
+    /* Simply clear it */
+    *SpinLock = 0;
+#endif
+}
+
+/*
+ * @unimplemented
+ */
+VOID
+FASTCALL
+KeAcquireInStackQueuedSpinLockAtDpcLevel(IN PKSPIN_LOCK SpinLock,
+                                         IN PKLOCK_QUEUE_HANDLE LockHandle)
+{
+    UNIMPLEMENTED;
+}
+
+/*
+ * @unimplemented
+ */
+VOID
+FASTCALL
+KeReleaseInStackQueuedSpinLockFromDpcLevel(IN PKLOCK_QUEUE_HANDLE LockHandle)
+{
+    UNIMPLEMENTED;
 }
 
 /* EOF */