- 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 NonPagedPoolCacheAlignedMustSSession
} POOL_TYPE; } 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 { typedef enum _EX_POOL_PRIORITY {
LowPoolPriority, LowPoolPriority,
LowPoolPrioritySpecialPoolOverrun = 8, 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 #else
KIRQL KIRQL
@ -594,6 +602,22 @@ KiCheckDeferredReadyList(IN PKPRCB Prcb)
if (Prcb->DeferredReadyListHead.Next) KiProcessDeferredReadyList(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 #endif
FORCEINLINE FORCEINLINE

View file

@ -140,6 +140,7 @@
/* formerly located in ps/notify.c */ /* formerly located in ps/notify.c */
#define TAG_KAPC TAG('k','p','a','p') /* kpap - kernel ps apc */ #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 */ /* formerly located in rtl/handle.c */
#define TAG_HDTB TAG('H', 'D', 'T', 'B') #define TAG_HDTB TAG('H', 'D', 'T', 'B')

View file

@ -18,8 +18,8 @@
* @name KiCheckForKernelApcDelivery * @name KiCheckForKernelApcDelivery
* @implemented NT 5.2 * @implemented NT 5.2
* *
* The KiCheckForKernelApcDelivery routine is called whenever APCs have just * The KiCheckForKernelApcDelivery routine is called whenever APCs have
* been re-enabled in Kernel Mode, such as after leaving a Critical or * just been re-enabled in Kernel Mode, such as after leaving a Critical or
* Guarded Region. It delivers APCs if the environment is right. * Guarded Region. It delivers APCs if the environment is right.
* *
* @param None. * @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 * KiInsertQueueApc
* *
@ -236,7 +210,7 @@ KiInsertQueueApc(PKAPC Apc,
if (Thread->State == Running) if (Thread->State == Running)
{ {
/* The thread is running, so send an APC request */ /* The thread is running, so send an APC request */
KiRequestApcInterrupt(Thread); KiRequestApcInterrupt(Thread->NextProcessor);
} }
else else
{ {
@ -498,18 +472,6 @@ Quickie:
return; 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 static __inline
VOID RepairList(PLIST_ENTRY Original, VOID RepairList(PLIST_ENTRY Original,
PLIST_ENTRY Copy, PLIST_ENTRY Copy,
@ -900,94 +862,3 @@ KeAreApcsDisabled(VOID)
return KeGetCurrentThread()->CombinedApcDisable ? TRUE : FALSE; 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 * Prepares the Context for a User-Mode APC called through NTDLL.DLL
* *
* Params: * @param Reserved
* Reserved - Pointer to the Exception Frame on non-i386 builds. * 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 * @param SystemArgument[1-2]
* untyped data. * Pointer to a set of two parameters that contain untyped data.
* *
* Returns: * @return None.
* None.
* *
* Remarks: * @remarks None.
* None.
* *
*--*/ *--*/
VOID VOID

View file

@ -15,6 +15,18 @@
/* PRIVATE FUNCTIONS *********************************************************/ /* 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 NTSTATUS
NTAPI NTAPI
PsResumeThread(IN PETHREAD Thread, PsResumeThread(IN PETHREAD Thread,
@ -448,4 +460,99 @@ NtTestAlert(VOID)
STATUS_ALERTED : STATUS_SUCCESS; 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 */ /* EOF */