a56f8725847314d1c58169e55496f8e1b686a3d6
[reactos.git] / reactos / ntoskrnl / include / internal / ke_x.h
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/include/ke_x.h
5 * PURPOSE: Internal Inlined Functions for the Kernel
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 //
10 // Enters a Critical Region
11 //
12 #define KeEnterGuardedRegion() \
13 { \
14 PKTHREAD Thread = KeGetCurrentThread(); \
15 \
16 /* Sanity checks */ \
17 ASSERT_IRQL_LESS_OR_EQUAL(APC_LEVEL); \
18 ASSERT(Thread == KeGetCurrentThread()); \
19 ASSERT((Thread->SpecialApcDisable <= 0) && \
20 (Thread->SpecialApcDisable != -32768)); \
21 \
22 /* Disable Special APCs */ \
23 Thread->SpecialApcDisable--; \
24 }
25
26 //
27 // Leaves a Critical Region
28 //
29 #define KeLeaveGuardedRegion() \
30 { \
31 PKTHREAD Thread = KeGetCurrentThread(); \
32 \
33 /* Sanity checks */ \
34 ASSERT_IRQL_LESS_OR_EQUAL(APC_LEVEL); \
35 ASSERT(Thread == KeGetCurrentThread()); \
36 ASSERT(Thread->SpecialApcDisable < 0); \
37 \
38 /* Leave region and check if APCs are OK now */ \
39 if (!(++Thread->SpecialApcDisable)) \
40 { \
41 /* Check for Kernel APCs on the list */ \
42 if (!IsListEmpty(&Thread->ApcState. \
43 ApcListHead[KernelMode])) \
44 { \
45 /* Check for APC Delivery */ \
46 KiCheckForKernelApcDelivery(); \
47 } \
48 } \
49 }
50
51 //
52 // TODO: Guarded Mutex Routines
53 //
54
55 //
56 // TODO: Critical Region Routines
57 //
58
59 //
60 // Satisfies the wait of any dispatcher object
61 //
62 #define KiSatisfyObjectWait(Object, Thread) \
63 { \
64 /* Special case for Mutants */ \
65 if ((Object)->Header.Type == MutantObject) \
66 { \
67 /* Decrease the Signal State */ \
68 (Object)->Header.SignalState--; \
69 \
70 /* Check if it's now non-signaled */ \
71 if (!(Object)->Header.SignalState) \
72 { \
73 /* Set the Owner Thread */ \
74 (Object)->OwnerThread = Thread; \
75 \
76 /* Disable APCs if needed */ \
77 Thread->KernelApcDisable -= (Object)->ApcDisable; \
78 \
79 /* Check if it's abandoned */ \
80 if ((Object)->Abandoned) \
81 { \
82 /* Unabandon it */ \
83 (Object)->Abandoned = FALSE; \
84 \
85 /* Return Status */ \
86 Thread->WaitStatus = STATUS_ABANDONED; \
87 } \
88 \
89 /* Insert it into the Mutant List */ \
90 InsertHeadList(Thread->MutantListHead.Blink, \
91 &(Object)->MutantListEntry); \
92 } \
93 } \
94 else if (((Object)->Header.Type & TIMER_OR_EVENT_TYPE) == \
95 EventSynchronizationObject) \
96 { \
97 /* Synchronization Timers and Events just get un-signaled */ \
98 (Object)->Header.SignalState = 0; \
99 } \
100 else if ((Object)->Header.Type == SemaphoreObject) \
101 { \
102 /* These ones can have multiple states, so we only decrease it */ \
103 (Object)->Header.SignalState--; \
104 } \
105 }
106
107 //
108 // Satisfies the wait of a mutant dispatcher object
109 //
110 #define KiSatisfyMutantWait(Object, Thread) \
111 { \
112 /* Decrease the Signal State */ \
113 (Object)->Header.SignalState--; \
114 \
115 /* Check if it's now non-signaled */ \
116 if (!(Object)->Header.SignalState) \
117 { \
118 /* Set the Owner Thread */ \
119 (Object)->OwnerThread = Thread; \
120 \
121 /* Disable APCs if needed */ \
122 Thread->KernelApcDisable -= (Object)->ApcDisable; \
123 \
124 /* Check if it's abandoned */ \
125 if ((Object)->Abandoned) \
126 { \
127 /* Unabandon it */ \
128 (Object)->Abandoned = FALSE; \
129 \
130 /* Return Status */ \
131 Thread->WaitStatus = STATUS_ABANDONED; \
132 } \
133 \
134 /* Insert it into the Mutant List */ \
135 InsertHeadList(Thread->MutantListHead.Blink, \
136 &(Object)->MutantListEntry); \
137 } \
138 }
139
140 //
141 // Satisfies the wait of any nonmutant dispatcher object
142 //
143 #define KiSatisfyNonMutantWait(Object, Thread) \
144 { \
145 if (((Object)->Header.Type & TIMER_OR_EVENT_TYPE) == \
146 EventSynchronizationObject) \
147 { \
148 /* Synchronization Timers and Events just get un-signaled */ \
149 (Object)->Header.SignalState = 0; \
150 } \
151 else if ((Object)->Header.Type == SemaphoreObject) \
152 { \
153 /* These ones can have multiple states, so we only decrease it */ \
154 (Object)->Header.SignalState--; \
155 } \
156 }
157
158 //
159 // Determines wether a thread should be added to the wait list
160 //
161 #define KiCheckThreadStackSwap(WaitMode, Thread, Swappable) \
162 { \
163 /* Check the required conditions */ \
164 if ((WaitMode != KernelMode) && \
165 (Thread->EnableStackSwap) && \
166 (Thread->Priority >= (LOW_REALTIME_PRIORITY + 9))) \
167 { \
168 /* We are go for swap */ \
169 Swappable = TRUE; \
170 } \
171 else \
172 { \
173 /* Don't swap the thread */ \
174 Swappable = FALSE; \
175 } \
176 }
177
178 //
179 // Adds a thread to the wait list
180 //
181 #define KiAddThreadToWaitList(Thread, Swappable) \
182 { \
183 /* Make sure it's swappable */ \
184 if (Swappable) \
185 { \
186 /* Insert it into the PRCB's List */ \
187 InsertTailList(&KeGetCurrentPrcb()->WaitListHead, \
188 &Thread->WaitListEntry); \
189 } \
190 }
191
192 //
193 // Rules for checking alertability:
194 // - For Alertable waits ONLY:
195 // * We don't wait and return STATUS_ALERTED if the thread is alerted
196 // in EITHER the specified wait mode OR in Kernel Mode.
197 // - For BOTH Alertable AND Non-Alertable waits:
198 // * We don't want and return STATUS_USER_APC if the User Mode APC list
199 // is not empty AND the wait mode is User Mode.
200 //
201 #define KiCheckAlertability() \
202 { \
203 if (Alertable) \
204 { \
205 if (CurrentThread->Alerted[(int)WaitMode]) \
206 { \
207 CurrentThread->Alerted[(int)WaitMode] = FALSE; \
208 WaitStatus = STATUS_ALERTED; \
209 break; \
210 } \
211 else if ((WaitMode != KernelMode) && \
212 (!IsListEmpty(&CurrentThread-> \
213 ApcState.ApcListHead[UserMode]))) \
214 { \
215 CurrentThread->ApcState.UserApcPending = TRUE; \
216 WaitStatus = STATUS_USER_APC; \
217 break; \
218 } \
219 else if (CurrentThread->Alerted[KernelMode]) \
220 { \
221 CurrentThread->Alerted[KernelMode] = FALSE; \
222 WaitStatus = STATUS_ALERTED; \
223 break; \
224 } \
225 } \
226 else if ((WaitMode != KernelMode) && \
227 (CurrentThread->ApcState.UserApcPending)) \
228 { \
229 WaitStatus = STATUS_USER_APC; \
230 break; \
231 } \
232 }