Don't use the OldIrql value from fmutex after releasing it.
[reactos.git] / reactos / ntoskrnl / ex / fmutex.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Kernel
4 * FILE: ntoskrnl/ex/fmutex.c
5 * PURPOSE: Implements fast mutexes
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 */
8
9 /* INCLUDES *****************************************************************/
10
11 #include <ntoskrnl.h>
12 #include <internal/debug.h>
13
14 VOID
15 FASTCALL
16 KiAcquireFastMutex(IN PFAST_MUTEX FastMutex);
17
18 /* FUNCTIONS *****************************************************************/
19
20 /*
21 * @implemented
22 */
23 VOID
24 FASTCALL
25 ExEnterCriticalRegionAndAcquireFastMutexUnsafe(PFAST_MUTEX FastMutex)
26 {
27 PKTHREAD Thread = KeGetCurrentThread();
28
29 /* Enter the Critical Region */
30 KeEnterCriticalRegion();
31 ASSERT((KeGetCurrentIrql() == APC_LEVEL) ||
32 (Thread == NULL) ||
33 (Thread->CombinedApcDisable != 0) ||
34 (Thread->Teb == NULL) ||
35 (Thread->Teb >= (PTEB)MM_SYSTEM_RANGE_START));
36 ASSERT((Thread == NULL) || (FastMutex->Owner != Thread));
37
38 /* Decrease the count */
39 if (InterlockedDecrement(&FastMutex->Count))
40 {
41 /* Someone is still holding it, use slow path */
42 KiAcquireFastMutex(FastMutex);
43 }
44
45 /* Set the owner */
46 FastMutex->Owner = Thread;
47 }
48
49 /*
50 * @implemented
51 */
52 VOID
53 FASTCALL
54 ExReleaseFastMutexUnsafeAndLeaveCriticalRegion(PFAST_MUTEX FastMutex)
55 {
56 ASSERT((KeGetCurrentIrql() == APC_LEVEL) ||
57 (KeGetCurrentThread() == NULL) ||
58 (KeGetCurrentThread()->CombinedApcDisable != 0) ||
59 (KeGetCurrentThread()->Teb == NULL) ||
60 (KeGetCurrentThread()->Teb >= (PTEB)MM_SYSTEM_RANGE_START));
61 ASSERT(FastMutex->Owner == KeGetCurrentThread());
62
63 /* Erase the owner */
64 FastMutex->Owner = NULL;
65
66 /* Increase the count */
67 if (InterlockedIncrement(&FastMutex->Count) <= 0)
68 {
69 /* Someone was waiting for it, signal the waiter */
70 KeSetEventBoostPriority(&FastMutex->Gate, IO_NO_INCREMENT);
71 }
72
73 /* Leave the critical region */
74 KeLeaveCriticalRegion();
75 }
76
77 /*
78 * @implemented
79 */
80 VOID
81 FASTCALL
82 ExAcquireFastMutex(PFAST_MUTEX FastMutex)
83 {
84 KIRQL OldIrql;
85 ASSERT_IRQL_LESS_OR_EQUAL(APC_LEVEL);
86
87 /* Raise IRQL to APC */
88 OldIrql = KfRaiseIrql(APC_LEVEL);
89
90 /* Decrease the count */
91 if (InterlockedDecrement(&FastMutex->Count))
92 {
93 /* Someone is still holding it, use slow path */
94 KiAcquireFastMutex(FastMutex);
95 }
96
97 /* Set the owner and IRQL */
98 FastMutex->Owner = KeGetCurrentThread();
99 FastMutex->OldIrql = OldIrql;
100 }
101
102 /*
103 * @implemented
104 */
105 VOID
106 FASTCALL
107 ExReleaseFastMutex (PFAST_MUTEX FastMutex)
108 {
109 KIRQL oldIrql;
110 ASSERT_IRQL(APC_LEVEL);
111
112 /* Erase the owner */
113 FastMutex->Owner = NULL;
114 OldIrql = FastMutex->OldIrql;
115
116 /* Increase the count */
117 if (InterlockedIncrement(&FastMutex->Count) <= 0)
118 {
119 /* Someone was waiting for it, signal the waiter */
120 KeSetEventBoostPriority(&FastMutex->Gate, IO_NO_INCREMENT);
121 }
122
123 /* Lower IRQL back */
124 KfLowerIrql(OldIrql);
125 }
126
127 /*
128 * @implemented
129 */
130 VOID
131 FASTCALL
132 ExAcquireFastMutexUnsafe(PFAST_MUTEX FastMutex)
133 {
134 PKTHREAD Thread = KeGetCurrentThread();
135 ASSERT((KeGetCurrentIrql() == APC_LEVEL) ||
136 (Thread == NULL) ||
137 (Thread->CombinedApcDisable != 0) ||
138 (Thread->Teb == NULL) ||
139 (Thread->Teb >= (PTEB)MM_SYSTEM_RANGE_START));
140 ASSERT((Thread == NULL) || (FastMutex->Owner != Thread));
141
142 /* Decrease the count */
143 if (InterlockedDecrement(&FastMutex->Count))
144 {
145 /* Someone is still holding it, use slow path */
146 KiAcquireFastMutex(FastMutex);
147 }
148
149 /* Set the owner */
150 FastMutex->Owner = Thread;
151 }
152
153 /*
154 * @implemented
155 */
156 VOID
157 FASTCALL
158 ExReleaseFastMutexUnsafe(PFAST_MUTEX FastMutex)
159 {
160 ASSERT((KeGetCurrentIrql() == APC_LEVEL) ||
161 (KeGetCurrentThread() == NULL) ||
162 (KeGetCurrentThread()->CombinedApcDisable != 0) ||
163 (KeGetCurrentThread()->Teb == NULL) ||
164 (KeGetCurrentThread()->Teb >= (PTEB)MM_SYSTEM_RANGE_START));
165 ASSERT(FastMutex->Owner == KeGetCurrentThread());
166
167 /* Erase the owner */
168 FastMutex->Owner = NULL;
169
170 /* Increase the count */
171 if (InterlockedIncrement(&FastMutex->Count) <= 0)
172 {
173 /* Someone was waiting for it, signal the waiter */
174 KeSetEventBoostPriority(&FastMutex->Gate, IO_NO_INCREMENT);
175 }
176 }
177
178 /*
179 * @implemented
180 */
181 BOOLEAN
182 FASTCALL
183 ExTryToAcquireFastMutex(PFAST_MUTEX FastMutex)
184 {
185 KIRQL OldIrql;
186 ASSERT_IRQL_LESS_OR_EQUAL(APC_LEVEL);
187
188 /* Raise to APC_LEVEL */
189 OldIrql = KfRaiseIrql(APC_LEVEL);
190
191 /* Check if we can quickly acquire it */
192 if (InterlockedCompareExchange(&FastMutex->Count, 0, 1) == 1)
193 {
194 /* We have, set us as owners */
195 FastMutex->Owner = KeGetCurrentThread();
196 FastMutex->OldIrql = OldIrql;
197 return TRUE;
198 }
199 else
200 {
201 /* Acquire attempt failed */
202 KfLowerIrql(OldIrql);
203 return FALSE;
204 }
205 }
206
207 /* EOF */