xref: /reactos/ntoskrnl/ps/psnotify.c (revision c2c66aff)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            ntoskrnl/ps/psnotify.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
PsSetCreateProcessNotifyRoutine(IN PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine,IN BOOLEAN Remove)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
PsSetLegoNotifyRoutine(PVOID LegoNotifyRoutine)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
PsRemoveLoadImageNotifyRoutine(IN PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine)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
PsSetLoadImageNotifyRoutine(IN PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine)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
PsRemoveCreateThreadNotifyRoutine(IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine)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
PsSetCreateThreadNotifyRoutine(IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine)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 */
290