- Re-implement KiRequestApcInterrupt in ke_x.h. Make it work by CPU number (as documented) instead of comparing PRCBs.

- Move NtQueueApcThread to ps/state.c since it's a Ps-level function.
- Make NtQueueApcThread use POOL_QUOTA_FAIL_INSTEAD_OF_RAISE and add that flag to our DDK. Also fix the check for SystemThread by looking at the flag, not checking if TEB == NULL. Also fix a memory leak and comment header.
- Fix comment header in KiInitalizeUserApc.

svn path=/trunk/; revision=24051
This commit is contained in:
Alex Ionescu 2006-09-11 01:15:03 +00:00
parent 1462b71058
commit 2fea34f0e1
6 changed files with 153 additions and 144 deletions

View file

@ -4108,6 +4108,11 @@ typedef enum _POOL_TYPE {
NonPagedPoolCacheAlignedMustSSession
} POOL_TYPE;
#define POOL_COLD_ALLOCATION 256
#define POOL_QUOTA_FAIL_INSTEAD_OF_RAISE 8
#define POOL_RAISE_IF_ALLOCATION_FAILURE 16
typedef enum _EX_POOL_PRIORITY {
LowPoolPriority,
LowPoolPrioritySpecialPoolOverrun = 8,

View file

@ -428,6 +428,14 @@ KiRundownThread(IN PKTHREAD Thread)
}
}
FORCEINLINE
VOID
KiRequestApcInterrupt(IN UCHAR Processor)
{
/* Request a software interrupt */
HalRequestSoftwareInterrupt(APC_LEVEL);
}
#else
KIRQL
@ -594,6 +602,22 @@ KiCheckDeferredReadyList(IN PKPRCB Prcb)
if (Prcb->DeferredReadyListHead.Next) KiProcessDeferredReadyList(Prcb);
}
FORCEINLINE
VOID
KiRequestApcInterrupt(IN UCHAR Processor)
{
/* Check if we're on the same CPU */
if (KeGetCurrentPrcb()->Number == Processor)
{
/* Request a software interrupt */
HalRequestSoftwareInterrupt(APC_LEVEL);
}
else
{
KiIpiSendRequest(KeGetCurrentPrcb()->SetMember, IPI_APC);
}
}
#endif
FORCEINLINE

View file

@ -140,6 +140,7 @@
/* formerly located in ps/notify.c */
#define TAG_KAPC TAG('k','p','a','p') /* kpap - kernel ps apc */
#define TAG_PS_APC TAG('P', 's', 'a', 'p') /* Psap - Ps APC */
/* formerly located in rtl/handle.c */
#define TAG_HDTB TAG('H', 'D', 'T', 'B')

View file

@ -18,8 +18,8 @@
* @name KiCheckForKernelApcDelivery
* @implemented NT 5.2
*
* The KiCheckForKernelApcDelivery routine is called whenever APCs have just
* been re-enabled in Kernel Mode, such as after leaving a Critical or
* The KiCheckForKernelApcDelivery routine is called whenever APCs have
* just been re-enabled in Kernel Mode, such as after leaving a Critical or
* Guarded Region. It delivers APCs if the environment is right.
*
* @param None.
@ -57,32 +57,6 @@ KiCheckForKernelApcDelivery(VOID)
}
}
static
__inline
VOID
KiRequestApcInterrupt(IN PKTHREAD Thread)
{
#ifdef CONFIG_SMP
PKPRCB Prcb, CurrentPrcb;
LONG i;
CurrentPrcb = KeGetCurrentPrcb();
for (i = 0; i < KeNumberProcessors; i++)
{
Prcb = ((PKPCR)(KPCR_BASE + i * PAGE_SIZE))->Prcb;
if (Prcb->CurrentThread == Thread)
{
ASSERT (CurrentPrcb != Prcb);
KiIpiSendRequest(Prcb->SetMember, IPI_APC);
break;
}
}
ASSERT (i < KeNumberProcessors);
#else
HalRequestSoftwareInterrupt(APC_LEVEL);
#endif
}
/*++
* KiInsertQueueApc
*
@ -236,7 +210,7 @@ KiInsertQueueApc(PKAPC Apc,
if (Thread->State == Running)
{
/* The thread is running, so send an APC request */
KiRequestApcInterrupt(Thread);
KiRequestApcInterrupt(Thread->NextProcessor);
}
else
{
@ -498,18 +472,6 @@ Quickie:
return;
}
VOID
STDCALL
KiFreeApcRoutine(PKAPC Apc,
PKNORMAL_ROUTINE* NormalRoutine,
PVOID* NormalContext,
PVOID* SystemArgument1,
PVOID* SystemArgument2)
{
/* Free the APC and do nothing else */
ExFreePool(Apc);
}
static __inline
VOID RepairList(PLIST_ENTRY Original,
PLIST_ENTRY Copy,
@ -900,94 +862,3 @@ KeAreApcsDisabled(VOID)
return KeGetCurrentThread()->CombinedApcDisable ? TRUE : FALSE;
}
/*++
* NtQueueApcThread
* NT4
*
* This routine is used to queue an APC from user-mode for the specified
* thread.
*
* Params:
* Thread Handle - Handle to the Thread. This handle must have THREAD_SET_CONTEXT privileges.
*
* ApcRoutine - Pointer to the APC Routine to call when the APC executes.
*
* NormalContext - Pointer to the context to send to the Normal Routine.
*
* SystemArgument[1-2] - Pointer to a set of two parameters that contain
* untyped data.
*
* Returns:
* STATUS_SUCCESS or failure cute from associated calls.
*
* Remarks:
* The thread must enter an alertable wait before the APC will be
* delivered.
*
*--*/
NTSTATUS
STDCALL
NtQueueApcThread(HANDLE ThreadHandle,
PKNORMAL_ROUTINE ApcRoutine,
PVOID NormalContext,
PVOID SystemArgument1,
PVOID SystemArgument2)
{
PKAPC Apc;
PETHREAD Thread;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status;
/* Get ETHREAD from Handle */
Status = ObReferenceObjectByHandle(ThreadHandle,
THREAD_SET_CONTEXT,
PsThreadType,
PreviousMode,
(PVOID)&Thread,
NULL);
/* Fail if the Handle is invalid for some reason */
if (!NT_SUCCESS(Status)) {
return(Status);
}
/* If this is a Kernel or System Thread, then fail */
if (Thread->Tcb.Teb == NULL) {
ObDereferenceObject(Thread);
return STATUS_INVALID_HANDLE;
}
/* Allocate an APC */
Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG('P', 's', 'a', 'p'));
if (Apc == NULL) {
ObDereferenceObject(Thread);
return(STATUS_NO_MEMORY);
}
/* Initialize and Queue a user mode apc (always!) */
KeInitializeApc(Apc,
&Thread->Tcb,
OriginalApcEnvironment,
KiFreeApcRoutine,
NULL,
ApcRoutine,
UserMode,
NormalContext);
if (!KeInsertQueueApc(Apc, SystemArgument1, SystemArgument2, IO_NO_INCREMENT)) {
Status = STATUS_UNSUCCESSFUL;
} else {
Status = STATUS_SUCCESS;
}
/* Dereference Thread and Return */
ObDereferenceObject(Thread);
return Status;
}

View file

@ -31,27 +31,28 @@ _SEH_FILTER(KiCopyInformation2)
}
/*++
* KiInitializeUserApc
* @name KiInitializeUserApc
*
* Prepares the Context for a User-Mode APC called through NTDLL.DLL
*
* Params:
* Reserved - Pointer to the Exception Frame on non-i386 builds.
* @param Reserved
* Pointer to the Exception Frame on non-i386 builds.
*
* TrapFrame - Pointer to the Trap Frame.
* @param TrapFrame
* Pointer to the Trap Frame.
*
* NormalRoutine - Pointer to the NormalRoutine to call.
* @param NormalRoutine
* Pointer to the NormalRoutine to call.
*
* NormalContext - Pointer to the context to send to the Normal Routine.
* @param NormalContext
* Pointer to the context to send to the Normal Routine.
*
* SystemArgument[1-2] - Pointer to a set of two parameters that contain
* untyped data.
* @param SystemArgument[1-2]
* Pointer to a set of two parameters that contain untyped data.
*
* Returns:
* None.
* @return None.
*
* Remarks:
* None.
* @remarks None.
*
*--*/
VOID

View file

@ -15,6 +15,18 @@
/* PRIVATE FUNCTIONS *********************************************************/
VOID
NTAPI
PspQueueApcSpecialApc(IN PKAPC Apc,
IN OUT PKNORMAL_ROUTINE* NormalRoutine,
IN OUT PVOID* NormalContext,
IN OUT PVOID* SystemArgument1,
IN OUT PVOID* SystemArgument2)
{
/* Free the APC and do nothing else */
ExFreePool(Apc);
}
NTSTATUS
NTAPI
PsResumeThread(IN PETHREAD Thread,
@ -448,4 +460,99 @@ NtTestAlert(VOID)
STATUS_ALERTED : STATUS_SUCCESS;
}
/*++
* @name NtQueueApcThread
* NT4
*
* This routine is used to queue an APC from user-mode for the specified
* thread.
*
* @param ThreadHandle
* Handle to the Thread.
* This handle must have THREAD_SET_CONTEXT privileges.
*
* @param ApcRoutine
* Pointer to the APC Routine to call when the APC executes.
*
* @param NormalContext
* Pointer to the context to send to the Normal Routine.
*
* @param SystemArgument[1-2]
* Pointer to a set of two parameters that contain untyped data.
*
* @return STATUS_SUCCESS or failure cute from associated calls.
*
* @remarks The thread must enter an alertable wait before the APC will be
* delivered.
*
*--*/
NTSTATUS
NTAPI
NtQueueApcThread(IN HANDLE ThreadHandle,
IN PKNORMAL_ROUTINE ApcRoutine,
IN PVOID NormalContext,
IN PVOID SystemArgument1,
IN PVOID SystemArgument2)
{
PKAPC Apc;
PETHREAD Thread;
NTSTATUS Status = STATUS_SUCCESS;
PAGED_CODE();
/* Get ETHREAD from Handle */
Status = ObReferenceObjectByHandle(ThreadHandle,
THREAD_SET_CONTEXT,
PsThreadType,
ExGetPreviousMode(),
(PVOID)&Thread,
NULL);
if (NT_SUCCESS(Status)) return Status;
/* Check if this is a System Thread */
if (Thread->SystemThread)
{
/* Fail */
Status = STATUS_INVALID_HANDLE;
goto Quit;
}
/* Allocate an APC */
Apc = ExAllocatePoolWithTag(NonPagedPool |
POOL_QUOTA_FAIL_INSTEAD_OF_RAISE,
sizeof(KAPC),
TAG_PS_APC);
if (!Apc)
{
/* Fail */
Status = STATUS_NO_MEMORY;
goto Quit;
}
/* Initialize the APC */
KeInitializeApc(Apc,
&Thread->Tcb,
OriginalApcEnvironment,
PspQueueApcSpecialApc,
NULL,
ApcRoutine,
UserMode,
NormalContext);
/* Queue it */
if (!KeInsertQueueApc(Apc,
SystemArgument1,
SystemArgument2,
IO_NO_INCREMENT))
{
/* We failed, free it */
ExFreePool(Apc);
Status = STATUS_UNSUCCESSFUL;
}
/* Dereference Thread and Return */
Quit:
ObDereferenceObject(Thread);
return Status;
}
/* EOF */