[NTOSKRNL]
[reactos.git] / ntoskrnl / ps / psnotify.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ps/notify.c
5 * PURPOSE: Process Manager: Callbacks to Registered Clients (Drivers)
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Thomas Weidenmueller (w3seek@reactos.org)
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18 BOOLEAN PsImageNotifyEnabled = FALSE;
19 ULONG PspThreadNotifyRoutineCount, PspProcessNotifyRoutineCount;
20 ULONG PspLoadImageNotifyRoutineCount;
21 EX_CALLBACK PspThreadNotifyRoutine[PSP_MAX_CREATE_THREAD_NOTIFY];
22 EX_CALLBACK PspProcessNotifyRoutine[PSP_MAX_CREATE_PROCESS_NOTIFY];
23 EX_CALLBACK PspLoadImageNotifyRoutine[PSP_MAX_LOAD_IMAGE_NOTIFY];
24 PLEGO_NOTIFY_ROUTINE PspLegoNotifyRoutine;
25
26 /* PUBLIC FUNCTIONS **********************************************************/
27
28 /*
29 * @implemented
30 */
31 NTSTATUS
32 NTAPI
33 PsSetCreateProcessNotifyRoutine(IN PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine,
34 IN BOOLEAN Remove)
35 {
36 ULONG i;
37 PEX_CALLBACK_ROUTINE_BLOCK CallBack;
38 PAGED_CODE();
39
40 /* Check if we're removing */
41 if (Remove)
42 {
43 /* Loop all the routines */
44 for (i = 0; i < PSP_MAX_CREATE_PROCESS_NOTIFY; i++)
45 {
46 /* Reference the callback block */
47 CallBack = ExReferenceCallBackBlock(&PspProcessNotifyRoutine[i]);
48 if (!CallBack) continue;
49
50 /* Check it this is a matching block */
51 if (ExGetCallBackBlockRoutine(CallBack) != (PVOID)NotifyRoutine)
52 {
53 /* It's not, try the next one */
54 continue;
55 }
56
57 /* It is, clear the current routine */
58 if (ExCompareExchangeCallBack(&PspProcessNotifyRoutine[i],
59 NULL,
60 CallBack))
61 {
62 /* Decrement the number of routines */
63 InterlockedDecrement((PLONG)&PspProcessNotifyRoutineCount);
64
65 /* Dereference the block */
66 ExDereferenceCallBackBlock(&PspProcessNotifyRoutine[i],
67 CallBack);
68
69 /* Wait for actice callbacks */
70 ExWaitForCallBacks(CallBack);
71
72 /* Free the callback and exit */
73 ExFreeCallBack (CallBack);
74 return STATUS_SUCCESS;
75 }
76
77 /* Dereference the block */
78 ExDereferenceCallBackBlock(&PspProcessNotifyRoutine[i],
79 CallBack);
80 }
81
82 /* We didn't find any matching block */
83 return STATUS_PROCEDURE_NOT_FOUND;
84 }
85 else
86 {
87 /* Allocate a callback */
88 CallBack = ExAllocateCallBack((PVOID)NotifyRoutine, NULL);
89 if (!CallBack) return STATUS_INSUFFICIENT_RESOURCES;
90
91 /* Loop all callbacks */
92 for (i = 0; i < PSP_MAX_CREATE_PROCESS_NOTIFY; i++)
93 {
94 /* Add this routine if it's an empty slot */
95 if (ExCompareExchangeCallBack(&PspProcessNotifyRoutine[i],
96 CallBack,
97 NULL))
98 {
99 /* Found and inserted into an empty slot, return */
100 InterlockedIncrement((PLONG)&PspProcessNotifyRoutineCount);
101 return STATUS_SUCCESS;
102 }
103 }
104
105 /* We didn't find a free slot, free the callback and fail */
106 ExFreeCallBack(CallBack);
107 return STATUS_INVALID_PARAMETER;
108 }
109 }
110
111 /*
112 * @implemented
113 */
114 ULONG
115 NTAPI
116 PsSetLegoNotifyRoutine(PVOID LegoNotifyRoutine)
117 {
118 /* Set the System-Wide Lego Routine */
119 PspLegoNotifyRoutine = LegoNotifyRoutine;
120
121 /* Return the location to the Lego Data */
122 return FIELD_OFFSET(KTHREAD, LegoData);
123 }
124
125 /*
126 * @implemented
127 */
128 NTSTATUS
129 NTAPI
130 PsRemoveLoadImageNotifyRoutine(IN PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine)
131 {
132 ULONG i;
133 PEX_CALLBACK_ROUTINE_BLOCK CallBack;
134 PAGED_CODE();
135
136 /* Loop all callbacks */
137 for (i = 0; i < PSP_MAX_LOAD_IMAGE_NOTIFY; i++)
138 {
139 /* Reference this slot */
140 CallBack = ExReferenceCallBackBlock(&PspLoadImageNotifyRoutine[i]);
141 if (CallBack)
142 {
143 /* Check for a match */
144 if (ExGetCallBackBlockRoutine(CallBack) == (PVOID)NotifyRoutine)
145 {
146 /* Try removing it if it matches */
147 if (ExCompareExchangeCallBack(&PspLoadImageNotifyRoutine[i],
148 NULL,
149 CallBack))
150 {
151 /* We removed it, now dereference the block */
152 InterlockedDecrement((PLONG)&PspLoadImageNotifyRoutineCount);
153 ExDereferenceCallBackBlock(&PspLoadImageNotifyRoutine[i],
154 CallBack);
155
156 /* Wait for active callbacks */
157 ExWaitForCallBacks(CallBack);
158
159 /* Free the callback and return */
160 ExFreeCallBack(CallBack);
161 return STATUS_SUCCESS;
162 }
163 }
164
165 /* Dereference the callback */
166 ExDereferenceCallBackBlock(&PspLoadImageNotifyRoutine[i], CallBack);
167 }
168 }
169
170 /* Nothing found to remove */
171 return STATUS_PROCEDURE_NOT_FOUND;
172 }
173
174 /*
175 * @implemented
176 */
177 NTSTATUS
178 NTAPI
179 PsSetLoadImageNotifyRoutine(IN PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine)
180 {
181 ULONG i;
182 PEX_CALLBACK_ROUTINE_BLOCK CallBack;
183 PAGED_CODE();
184
185 /* Allocate a callback */
186 CallBack = ExAllocateCallBack((PVOID)NotifyRoutine, NULL);
187 if (!CallBack) return STATUS_INSUFFICIENT_RESOURCES;
188
189 /* Loop callbacks */
190 for (i = 0; i < PSP_MAX_LOAD_IMAGE_NOTIFY; i++)
191 {
192 /* Add this entry if the slot is empty */
193 if (ExCompareExchangeCallBack(&PspLoadImageNotifyRoutine[i],
194 CallBack,
195 NULL))
196 {
197 /* Return success */
198 InterlockedIncrement((PLONG)&PspLoadImageNotifyRoutineCount);
199 PsImageNotifyEnabled = TRUE;
200 return STATUS_SUCCESS;
201 }
202 }
203
204 /* No free space found, fail */
205 ExFreeCallBack(CallBack);
206 return STATUS_INSUFFICIENT_RESOURCES;
207 }
208
209 /*
210 * @implemented
211 */
212 NTSTATUS
213 NTAPI
214 PsRemoveCreateThreadNotifyRoutine(IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine)
215 {
216 ULONG i;
217 PEX_CALLBACK_ROUTINE_BLOCK CallBack;
218 PAGED_CODE();
219
220 /* Loop all callbacks */
221 for (i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++)
222 {
223 /* Reference this slot */
224 CallBack = ExReferenceCallBackBlock(&PspThreadNotifyRoutine[i]);
225 if (CallBack)
226 {
227 /* Check for a match */
228 if (ExGetCallBackBlockRoutine(CallBack) == (PVOID)NotifyRoutine)
229 {
230 /* Try removing it if it matches */
231 if (ExCompareExchangeCallBack(&PspThreadNotifyRoutine[i],
232 NULL,
233 CallBack))
234 {
235 /* We removed it, now dereference the block */
236 InterlockedDecrement((PLONG)&PspThreadNotifyRoutineCount);
237 ExDereferenceCallBackBlock(&PspThreadNotifyRoutine[i],
238 CallBack);
239
240 /* Wait for active callbacks */
241 ExWaitForCallBacks(CallBack);
242
243 /* Free the callback and return */
244 ExFreeCallBack(CallBack);
245 return STATUS_SUCCESS;
246 }
247 }
248
249 /* Dereference the callback */
250 ExDereferenceCallBackBlock(&PspThreadNotifyRoutine[i], CallBack);
251 }
252 }
253
254 /* Nothing found to remove */
255 return STATUS_PROCEDURE_NOT_FOUND;
256 }
257
258 /*
259 * @implemented
260 */
261 NTSTATUS
262 NTAPI
263 PsSetCreateThreadNotifyRoutine(IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine)
264 {
265 ULONG i;
266 PEX_CALLBACK_ROUTINE_BLOCK CallBack;
267 PAGED_CODE();
268
269 /* Allocate a callback */
270 CallBack = ExAllocateCallBack((PVOID)NotifyRoutine, NULL);
271 if (!CallBack) return STATUS_INSUFFICIENT_RESOURCES;
272
273 /* Loop callbacks */
274 for (i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++)
275 {
276 /* Add this entry if the slot is empty */
277 if (ExCompareExchangeCallBack(&PspThreadNotifyRoutine[i],
278 CallBack,
279 NULL))
280 {
281 /* Return success */
282 InterlockedIncrement((PLONG)&PspThreadNotifyRoutineCount);
283 return STATUS_SUCCESS;
284 }
285 }
286
287 /* No free space found, fail */
288 ExFreeCallBack(CallBack);
289 return STATUS_INSUFFICIENT_RESOURCES;
290 }
291
292 /* EOF */