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 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 */ 290