mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 01:55:19 +00:00
289 lines
8.9 KiB
C
289 lines
8.9 KiB
C
/*
|
|
* PROJECT: ReactOS Kernel
|
|
* LICENSE: GPL - See COPYING in the top level directory
|
|
* FILE: ntoskrnl/ps/psnotify.c
|
|
* PURPOSE: Process Manager: Callbacks to Registered Clients (Drivers)
|
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
|
* Thomas Weidenmueller (w3seek@reactos.org)
|
|
*/
|
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
#include <ntoskrnl.h>
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* GLOBALS *******************************************************************/
|
|
|
|
BOOLEAN PsImageNotifyEnabled = FALSE;
|
|
ULONG PspThreadNotifyRoutineCount, PspProcessNotifyRoutineCount;
|
|
ULONG PspLoadImageNotifyRoutineCount;
|
|
EX_CALLBACK PspThreadNotifyRoutine[PSP_MAX_CREATE_THREAD_NOTIFY];
|
|
EX_CALLBACK PspProcessNotifyRoutine[PSP_MAX_CREATE_PROCESS_NOTIFY];
|
|
EX_CALLBACK PspLoadImageNotifyRoutine[PSP_MAX_LOAD_IMAGE_NOTIFY];
|
|
PLEGO_NOTIFY_ROUTINE PspLegoNotifyRoutine;
|
|
|
|
/* PUBLIC FUNCTIONS **********************************************************/
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
PsSetCreateProcessNotifyRoutine(IN PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine,
|
|
IN BOOLEAN Remove)
|
|
{
|
|
ULONG i;
|
|
PEX_CALLBACK_ROUTINE_BLOCK CallBack;
|
|
PAGED_CODE();
|
|
|
|
/* Check if we're removing */
|
|
if (Remove)
|
|
{
|
|
/* Loop all the routines */
|
|
for (i = 0; i < PSP_MAX_CREATE_PROCESS_NOTIFY; i++)
|
|
{
|
|
/* Reference the callback block */
|
|
CallBack = ExReferenceCallBackBlock(&PspProcessNotifyRoutine[i]);
|
|
if (!CallBack) continue;
|
|
|
|
/* Check it this is a matching block */
|
|
if (ExGetCallBackBlockRoutine(CallBack) == (PVOID)NotifyRoutine)
|
|
{
|
|
/* Try removing it if it matches */
|
|
if (ExCompareExchangeCallBack(&PspProcessNotifyRoutine[i],
|
|
NULL,
|
|
CallBack))
|
|
{
|
|
/* Decrement the number of routines */
|
|
InterlockedDecrement((PLONG)&PspProcessNotifyRoutineCount);
|
|
|
|
/* Dereference the block */
|
|
ExDereferenceCallBackBlock(&PspProcessNotifyRoutine[i],
|
|
CallBack);
|
|
|
|
/* Wait for active callbacks */
|
|
ExWaitForCallBacks(CallBack);
|
|
|
|
/* Free the callback and exit */
|
|
ExFreeCallBack(CallBack);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
/* Dereference the block */
|
|
ExDereferenceCallBackBlock(&PspProcessNotifyRoutine[i],
|
|
CallBack);
|
|
}
|
|
}
|
|
|
|
/* We didn't find any matching block */
|
|
return STATUS_PROCEDURE_NOT_FOUND;
|
|
}
|
|
else
|
|
{
|
|
/* Allocate a callback */
|
|
CallBack = ExAllocateCallBack((PVOID)NotifyRoutine, NULL);
|
|
if (!CallBack) return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
/* Loop all callbacks */
|
|
for (i = 0; i < PSP_MAX_CREATE_PROCESS_NOTIFY; i++)
|
|
{
|
|
/* Add this routine if it's an empty slot */
|
|
if (ExCompareExchangeCallBack(&PspProcessNotifyRoutine[i],
|
|
CallBack,
|
|
NULL))
|
|
{
|
|
/* Found and inserted into an empty slot, return */
|
|
InterlockedIncrement((PLONG)&PspProcessNotifyRoutineCount);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/* We didn't find a free slot, free the callback and fail */
|
|
ExFreeCallBack(CallBack);
|
|
return STATUS_INVALID_PARAMETER;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
ULONG
|
|
NTAPI
|
|
PsSetLegoNotifyRoutine(PVOID LegoNotifyRoutine)
|
|
{
|
|
/* Set the System-Wide Lego Routine */
|
|
PspLegoNotifyRoutine = LegoNotifyRoutine;
|
|
|
|
/* Return the location to the Lego Data */
|
|
return FIELD_OFFSET(KTHREAD, LegoData);
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
PsRemoveLoadImageNotifyRoutine(IN PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine)
|
|
{
|
|
ULONG i;
|
|
PEX_CALLBACK_ROUTINE_BLOCK CallBack;
|
|
PAGED_CODE();
|
|
|
|
/* Loop all callbacks */
|
|
for (i = 0; i < PSP_MAX_LOAD_IMAGE_NOTIFY; i++)
|
|
{
|
|
/* Reference this slot */
|
|
CallBack = ExReferenceCallBackBlock(&PspLoadImageNotifyRoutine[i]);
|
|
if (CallBack)
|
|
{
|
|
/* Check for a match */
|
|
if (ExGetCallBackBlockRoutine(CallBack) == (PVOID)NotifyRoutine)
|
|
{
|
|
/* Try removing it if it matches */
|
|
if (ExCompareExchangeCallBack(&PspLoadImageNotifyRoutine[i],
|
|
NULL,
|
|
CallBack))
|
|
{
|
|
/* We removed it, now dereference the block */
|
|
InterlockedDecrement((PLONG)&PspLoadImageNotifyRoutineCount);
|
|
ExDereferenceCallBackBlock(&PspLoadImageNotifyRoutine[i],
|
|
CallBack);
|
|
|
|
/* Wait for active callbacks */
|
|
ExWaitForCallBacks(CallBack);
|
|
|
|
/* Free the callback and return */
|
|
ExFreeCallBack(CallBack);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/* Dereference the callback */
|
|
ExDereferenceCallBackBlock(&PspLoadImageNotifyRoutine[i], CallBack);
|
|
}
|
|
}
|
|
|
|
/* Nothing found to remove */
|
|
return STATUS_PROCEDURE_NOT_FOUND;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
PsSetLoadImageNotifyRoutine(IN PLOAD_IMAGE_NOTIFY_ROUTINE NotifyRoutine)
|
|
{
|
|
ULONG i;
|
|
PEX_CALLBACK_ROUTINE_BLOCK CallBack;
|
|
PAGED_CODE();
|
|
|
|
/* Allocate a callback */
|
|
CallBack = ExAllocateCallBack((PVOID)NotifyRoutine, NULL);
|
|
if (!CallBack) return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
/* Loop callbacks */
|
|
for (i = 0; i < PSP_MAX_LOAD_IMAGE_NOTIFY; i++)
|
|
{
|
|
/* Add this entry if the slot is empty */
|
|
if (ExCompareExchangeCallBack(&PspLoadImageNotifyRoutine[i],
|
|
CallBack,
|
|
NULL))
|
|
{
|
|
/* Return success */
|
|
InterlockedIncrement((PLONG)&PspLoadImageNotifyRoutineCount);
|
|
PsImageNotifyEnabled = TRUE;
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/* No free space found, fail */
|
|
ExFreeCallBack(CallBack);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
PsRemoveCreateThreadNotifyRoutine(IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine)
|
|
{
|
|
ULONG i;
|
|
PEX_CALLBACK_ROUTINE_BLOCK CallBack;
|
|
PAGED_CODE();
|
|
|
|
/* Loop all callbacks */
|
|
for (i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++)
|
|
{
|
|
/* Reference this slot */
|
|
CallBack = ExReferenceCallBackBlock(&PspThreadNotifyRoutine[i]);
|
|
if (CallBack)
|
|
{
|
|
/* Check for a match */
|
|
if (ExGetCallBackBlockRoutine(CallBack) == (PVOID)NotifyRoutine)
|
|
{
|
|
/* Try removing it if it matches */
|
|
if (ExCompareExchangeCallBack(&PspThreadNotifyRoutine[i],
|
|
NULL,
|
|
CallBack))
|
|
{
|
|
/* We removed it, now dereference the block */
|
|
InterlockedDecrement((PLONG)&PspThreadNotifyRoutineCount);
|
|
ExDereferenceCallBackBlock(&PspThreadNotifyRoutine[i],
|
|
CallBack);
|
|
|
|
/* Wait for active callbacks */
|
|
ExWaitForCallBacks(CallBack);
|
|
|
|
/* Free the callback and return */
|
|
ExFreeCallBack(CallBack);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/* Dereference the callback */
|
|
ExDereferenceCallBackBlock(&PspThreadNotifyRoutine[i], CallBack);
|
|
}
|
|
}
|
|
|
|
/* Nothing found to remove */
|
|
return STATUS_PROCEDURE_NOT_FOUND;
|
|
}
|
|
|
|
/*
|
|
* @implemented
|
|
*/
|
|
NTSTATUS
|
|
NTAPI
|
|
PsSetCreateThreadNotifyRoutine(IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine)
|
|
{
|
|
ULONG i;
|
|
PEX_CALLBACK_ROUTINE_BLOCK CallBack;
|
|
PAGED_CODE();
|
|
|
|
/* Allocate a callback */
|
|
CallBack = ExAllocateCallBack((PVOID)NotifyRoutine, NULL);
|
|
if (!CallBack) return STATUS_INSUFFICIENT_RESOURCES;
|
|
|
|
/* Loop callbacks */
|
|
for (i = 0; i < PSP_MAX_CREATE_THREAD_NOTIFY; i++)
|
|
{
|
|
/* Add this entry if the slot is empty */
|
|
if (ExCompareExchangeCallBack(&PspThreadNotifyRoutine[i],
|
|
CallBack,
|
|
NULL))
|
|
{
|
|
/* Return success */
|
|
InterlockedIncrement((PLONG)&PspThreadNotifyRoutineCount);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
/* No free space found, fail */
|
|
ExFreeCallBack(CallBack);
|
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|
}
|
|
|
|
/* EOF */
|