update for HEAD-2003091401
[reactos.git] / ntoskrnl / ke / spinlock.c
1 /* $Id$
2  *
3  * COPYRIGHT:       See COPYING in the top level directory
4  * PROJECT:         ReactOS kernel
5  * FILE:            ntoskrnl/ke/spinlock.c
6  * PURPOSE:         Implements spinlocks
7  * PROGRAMMER:      David Welch (welch@cwcom.net)
8  * UPDATE HISTORY:
9  *                  3/6/98: Created
10  */
11
12 /*
13  * NOTE: On a uniprocessor machine spinlocks are implemented by raising
14  * the irq level
15  */
16
17 /* INCLUDES ****************************************************************/
18
19 #include <ddk/ntddk.h>
20 #include <roscfg.h>
21
22 #include <internal/debug.h>
23
24 /* FUNCTIONS ***************************************************************/
25
26 /*
27  * @implemented
28  */
29 BOOLEAN STDCALL
30 KeSynchronizeExecution (PKINTERRUPT             Interrupt,
31                         PKSYNCHRONIZE_ROUTINE   SynchronizeRoutine,
32                         PVOID                   SynchronizeContext)
33 /*
34  * FUNCTION: Synchronizes the execution of a given routine with the ISR
35  * of a given interrupt object
36  * ARGUMENTS:
37  *       Interrupt = Interrupt object to synchronize with
38  *       SynchronizeRoutine = Routine to call whose execution is 
39  *                            synchronized with the ISR
40  *       SynchronizeContext = Parameter to pass to the synchronized routine
41  * RETURNS: TRUE if the operation succeeded
42  */
43 {
44    KIRQL oldlvl;
45    BOOLEAN ret;
46    
47    KeRaiseIrql(Interrupt->SynchLevel,&oldlvl);
48    KeAcquireSpinLockAtDpcLevel(Interrupt->IrqLock);
49    
50    ret = SynchronizeRoutine(SynchronizeContext);
51    
52    KeReleaseSpinLockFromDpcLevel(Interrupt->IrqLock);
53    KeLowerIrql(oldlvl);
54    
55    return(ret);
56 }
57
58 /*
59  * @implemented
60  */
61 VOID STDCALL
62 KeInitializeSpinLock (PKSPIN_LOCK       SpinLock)
63 /*
64  * FUNCTION: Initalizes a spinlock
65  * ARGUMENTS:
66  *           SpinLock = Caller supplied storage for the spinlock
67  */
68 {
69    *SpinLock = 0;
70 }
71
72 #undef KeAcquireSpinLockAtDpcLevel
73
74 /*
75  * @implemented
76  */
77 VOID STDCALL
78 KeAcquireSpinLockAtDpcLevel (PKSPIN_LOCK        SpinLock)
79 /*
80  * FUNCTION: Acquires a spinlock when the caller is already running at 
81  * dispatch level
82  * ARGUMENTS:
83  *        SpinLock = Spinlock to acquire
84  */
85 {
86    ULONG i;
87
88    /*
89     * FIXME: This depends on gcc assembling this test to a single load from
90     * the spinlock's value.
91     */
92    if (*SpinLock >= 2)
93      {
94         DbgPrint("Lock %x has bad value %x\n", SpinLock, *SpinLock);
95         KEBUGCHECK(0);
96      }
97    
98    while ((i = InterlockedExchange((LONG *)SpinLock, 1)) == 1)
99      {
100 #ifndef MP
101        DbgPrint("Spinning on spinlock %x current value %x\n", SpinLock, i);
102        KEBUGCHECK(0);
103 #else /* not MP */
104        /* Avoid reading the value again too fast */
105 #endif /* MP */
106      }
107 }
108
109 #undef KeReleaseSpinLockFromDpcLevel
110
111 /*
112  * @implemented
113  */
114 VOID STDCALL
115 KeReleaseSpinLockFromDpcLevel (PKSPIN_LOCK      SpinLock)
116 /*
117  * FUNCTION: Releases a spinlock when the caller was running at dispatch
118  * level before acquiring it
119  * ARGUMENTS: 
120  *         SpinLock = Spinlock to release
121  */
122 {
123    if (*SpinLock != 1)
124      {
125         DbgPrint("Releasing unacquired spinlock %x\n", SpinLock);
126         KEBUGCHECK(0);
127      }
128    (void)InterlockedExchange((LONG *)SpinLock, 0);
129 }
130
131 /* EOF */