[NTOSKRNL]
[reactos.git] / reactos / 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 /* Try removing it if it matches */
54 if (ExCompareExchangeCallBack(&PspProcessNotifyRoutine[i],
55 NULL,
56 CallBack))
57 {
58 /* Decrement the number of routines */
59 InterlockedDecrement((PLONG)&PspProcessNotifyRoutineCount);
60
61 /* Dereference the block */
62 ExDereferenceCallBackBlock(&PspProcessNotifyRoutine[i],
63 CallBack);
64
65 /* Wait for active callbacks */
66 ExWaitForCallBacks(CallBack);
67
68 /* Free the callback and exit */
69 ExFreeCallBack(CallBack);
70 return STATUS_SUCCESS;
71 }
72
73 /* Dereference the block */
74 ExDereferenceCallBackBlock(&PspProcessNotifyRoutine[i],
75 CallBack);
76 }
77 }
78
79 /* We didn't find any matching block */
80 return STATUS_PROCEDURE_NOT_FOUND;
81 }
82 else
83 {
84 /* Allocate a callback */
85 CallBack = ExAllocateCallBack((PVOID)NotifyRoutine, NULL);
86 if (!CallBack) return STATUS_INSUFFICIENT_RESOURCES;
87
88 /* Loop all callbacks */
89 for (i = 0; i < PSP_MAX_CREATE_PROCESS_NOTIFY; i++)
90 {
91 /* Add this routine if it's an empty slot */
92 if (ExCompareExchangeCallBack(&PspProcessNotifyRoutine[i],
93 CallBack,
94 NULL))
95 {
96 /* Found and inserted into an empty slot, return */
97 InterlockedIncrement((PLONG)&PspProcessNotifyRoutineCount);
98 return STATUS_SUCCESS;
99 }
100 }
101
102 /* We didn't find a free slot, free the callback and fail */
103 ExFreeCallBack(CallBack);
104 return STATUS_INVALID_PARAMETER;
105 }
106 }
107
108 /*
109 * @implemented
110 */
111 ULONG
112 NTAPI
113 PsSetLegoNotifyRoutine(PVOID LegoNotifyRoutine)
114 {
115 /* Set the System-Wide Lego Routine */
116 PspLegoNotifyRoutine = LegoNotifyRoutine;
117
118 /* Return the location to the Lego Data */
119 return FIELD_OFFSET(KTHREAD, LegoData);
120 }
121
122 /*
123 * @implemented
124 */
125 NTSTATUS
126 NTAPI
127 PsRemoveLoadImageNotifyRoutine(IN PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine)
128 {
129 ULONG i;
130 PEX_CALLBACK_ROUTINE_BLOCK CallBack;
131 PAGED_CODE();
132
133 /* Loop all callbacks */
134 for (i = 0; i < PSP_MAX_LOAD_IMAGE_NOTIFY; i++)
135 {
136 /* Reference this slot */
137 CallBack = ExReferenceCallBackBlock(&PspLoadImageNotifyRoutine[i]);
138 if (CallBack)
139 {
140 /* Check for a match */
141 if (ExGetCallBackBlockRoutine(CallBack) == (PVOID)NotifyRoutine)
142 {
143 /* Try removing it if it matches */
144 if (ExCompareExchangeCallBack(&PspLoadImageNotifyRoutine[i],
145 NULL,
146 CallBack))
147 {
148 /* We removed it, now dereference the block */
149 InterlockedDecrement((PLONG)&PspLoadImageNotifyRoutineCount);
150 ExDereferenceCallBackBlock(&PspLoadImageNotifyRoutine[i],
151 CallBack);
152
153 /* Wait for active callbacks */
154 ExWaitForCallBacks(CallBack);
155
156 /* Free the callback and return */
157 ExFreeCallBack(CallBack);
158 return STATUS_SUCCESS;
159 }
160 }
161
162 /* Dereference the callback */
163 ExDereferenceCallBackBlock(&PspLoadImageNotifyRoutine[i], CallBack);
164 }
165 }
166
167 /* Nothing found to remove */
168 return STATUS_PROCEDURE_NOT_FOUND;
169 }
170
171 /*
172 * @implemented
173 */
174 NTSTATUS
175 NTAPI
176 PsSetLoadImageNotifyRoutine(IN PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine)
177 {
178 ULONG i;
179 PEX_CALLBACK_ROUTINE_BLOCK CallBack;
180 PAGED_CODE();
181
182 /* Allocate a callback */
183 CallBack = ExAllocateCallBack((PVOID)NotifyRoutine, NULL);
184 if (!CallBack) return STATUS_INSUFFICIENT_RESOURCES;
185
186 /* Loop callbacks */
187 for (i = 0; i < PSP_MAX_LOAD_IMAGE_NOTIFY; i++)
188 {
189 /* Add this entry if the slot is empty */
190 if (ExCompareExchangeCallBack(&PspLoadImageNotifyRoutine[i],
191 CallBack,
192 NULL))
193 {
194 /* Return success */
195 InterlockedIncrement((PLONG)&PspLoadImageNotifyRoutineCount);
196 PsImageNotifyEnabled = TRUE;
197 return STATUS_SUCCESS;
198 }
199 }
200
201 /* No free space found, fail */
202 ExFreeCallBack(CallBack);
203 return STATUS_INSUFFICIENT_RESOURCES;
204 }
205
206 /*
207 * @implemented
208 */
209 NTSTATUS
210 NTAPI
211 PsRemoveCreateThreadNotifyRoutine(IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine)
212 {
213 ULONG i;
214 PEX_CALLBACK_ROUTINE_BLOCK CallBack;
215 PAGED_CODE();
216
217 /* Loop all callbacks */
218 for (i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++)
219 {
220 /* Reference this slot */
221 CallBack = ExReferenceCallBackBlock(&PspThreadNotifyRoutine[i]);
222 if (CallBack)
223 {
224 /* Check for a match */
225 if (ExGetCallBackBlockRoutine(CallBack) == (PVOID)NotifyRoutine)
226 {
227 /* Try removing it if it matches */
228 if (ExCompareExchangeCallBack(&PspThreadNotifyRoutine[i],
229 NULL,
230 CallBack))
231 {
232 /* We removed it, now dereference the block */
233 InterlockedDecrement((PLONG)&PspThreadNotifyRoutineCount);
234 ExDereferenceCallBackBlock(&PspThreadNotifyRoutine[i],
235 CallBack);
236
237 /* Wait for active callbacks */
238 ExWaitForCallBacks(CallBack);
239
240 /* Free the callback and return */
241 ExFreeCallBack(CallBack);
242 return STATUS_SUCCESS;
243 }
244 }
245
246 /* Dereference the callback */
247 ExDereferenceCallBackBlock(&PspThreadNotifyRoutine[i], CallBack);
248 }
249 }
250
251 /* Nothing found to remove */
252 return STATUS_PROCEDURE_NOT_FOUND;
253 }
254
255 /*
256 * @implemented
257 */
258 NTSTATUS
259 NTAPI
260 PsSetCreateThreadNotifyRoutine(IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine)
261 {
262 ULONG i;
263 PEX_CALLBACK_ROUTINE_BLOCK CallBack;
264 PAGED_CODE();
265
266 /* Allocate a callback */
267 CallBack = ExAllocateCallBack((PVOID)NotifyRoutine, NULL);
268 if (!CallBack) return STATUS_INSUFFICIENT_RESOURCES;
269
270 /* Loop callbacks */
271 for (i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++)
272 {
273 /* Add this entry if the slot is empty */
274 if (ExCompareExchangeCallBack(&PspThreadNotifyRoutine[i],
275 CallBack,
276 NULL))
277 {
278 /* Return success */
279 InterlockedIncrement((PLONG)&PspThreadNotifyRoutineCount);
280 return STATUS_SUCCESS;
281 }
282 }
283
284 /* No free space found, fail */
285 ExFreeCallBack(CallBack);
286 return STATUS_INSUFFICIENT_RESOURCES;
287 }
288
289 /* EOF */