diff --git a/reactos/include/ddk/winddk.h b/reactos/include/ddk/winddk.h index 119262d0315..e9695a694ff 100644 --- a/reactos/include/ddk/winddk.h +++ b/reactos/include/ddk/winddk.h @@ -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, diff --git a/reactos/ntoskrnl/include/internal/ke_x.h b/reactos/ntoskrnl/include/internal/ke_x.h index 40183b9167a..9c193e9b06f 100644 --- a/reactos/ntoskrnl/include/internal/ke_x.h +++ b/reactos/ntoskrnl/include/internal/ke_x.h @@ -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 diff --git a/reactos/ntoskrnl/include/internal/tag.h b/reactos/ntoskrnl/include/internal/tag.h index 862d321b585..e474a624038 100644 --- a/reactos/ntoskrnl/include/internal/tag.h +++ b/reactos/ntoskrnl/include/internal/tag.h @@ -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') diff --git a/reactos/ntoskrnl/ke/apc.c b/reactos/ntoskrnl/ke/apc.c index 6ae0679cf67..52ab295f300 100644 --- a/reactos/ntoskrnl/ke/apc.c +++ b/reactos/ntoskrnl/ke/apc.c @@ -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; -} - diff --git a/reactos/ntoskrnl/ke/i386/userapc.c b/reactos/ntoskrnl/ke/i386/userapc.c index cfc2a0aa8f5..13fcf7f0625 100644 --- a/reactos/ntoskrnl/ke/i386/userapc.c +++ b/reactos/ntoskrnl/ke/i386/userapc.c @@ -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 diff --git a/reactos/ntoskrnl/ps/state.c b/reactos/ntoskrnl/ps/state.c index 9739fec7593..964b9f62aed 100644 --- a/reactos/ntoskrnl/ps/state.c +++ b/reactos/ntoskrnl/ps/state.c @@ -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 */