1998-08-25 04:27:26 +00:00
|
|
|
/*
|
2001-03-14 00:21:22 +00:00
|
|
|
* ReactOS kernel
|
|
|
|
* Copyright (C) 1998, 1999, 2000, 2001 ReactOS Team
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
|
|
|
*/
|
|
|
|
/*
|
1998-08-25 04:27:26 +00:00
|
|
|
* PROJECT: ReactOS kernel
|
|
|
|
* FILE: ntoskrnl/ke/apc.c
|
|
|
|
* PURPOSE: Possible implementation of APCs
|
1999-02-06 18:34:14 +00:00
|
|
|
* PROGRAMMER: David Welch (welch@cwcom.net)
|
2001-03-14 00:21:22 +00:00
|
|
|
* PORTABILITY: Unchecked
|
1998-08-25 04:27:26 +00:00
|
|
|
* UPDATE HISTORY:
|
|
|
|
* Created 22/05/98
|
1999-12-12 03:56:53 +00:00
|
|
|
* 12/11/99: Phillip Susi: Reworked the APC code
|
1998-08-25 04:27:26 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
|
|
|
|
#include <ddk/ntddk.h>
|
1998-10-05 04:01:30 +00:00
|
|
|
#include <internal/i386/segment.h>
|
|
|
|
#include <internal/ps.h>
|
1999-12-13 22:04:41 +00:00
|
|
|
#include <internal/ke.h>
|
2000-10-11 20:50:35 +00:00
|
|
|
#include <internal/ldr.h>
|
2001-03-07 16:48:45 +00:00
|
|
|
#include <internal/pool.h>
|
1998-08-25 04:27:26 +00:00
|
|
|
|
1998-10-05 04:01:30 +00:00
|
|
|
#define NDEBUG
|
1998-08-25 04:27:26 +00:00
|
|
|
#include <internal/debug.h>
|
|
|
|
|
1999-12-13 22:04:41 +00:00
|
|
|
/* GLOBALS *******************************************************************/
|
1999-11-24 11:51:55 +00:00
|
|
|
|
2000-07-07 00:44:07 +00:00
|
|
|
KSPIN_LOCK PiApcLock;
|
|
|
|
extern KSPIN_LOCK PiThreadListLock;
|
|
|
|
|
|
|
|
VOID PsTerminateCurrentThread(NTSTATUS ExitStatus);
|
1999-11-24 11:51:55 +00:00
|
|
|
|
2001-03-07 16:48:45 +00:00
|
|
|
#define TAG_KAPC TAG('K', 'A', 'P', 'C')
|
|
|
|
|
1998-08-25 04:27:26 +00:00
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
|
2000-10-11 20:50:35 +00:00
|
|
|
VOID KiRundownThread(VOID)
|
|
|
|
/*
|
|
|
|
* FUNCTION:
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2000-10-07 13:41:58 +00:00
|
|
|
BOOLEAN KiTestAlert(VOID)
|
|
|
|
/*
|
2000-10-11 20:50:35 +00:00
|
|
|
* FUNCTION: Tests whether there are any pending APCs for the current thread
|
2000-10-07 13:41:58 +00:00
|
|
|
* and if so the APCs will be delivered on exit from kernel mode
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
KIRQL oldIrql;
|
|
|
|
|
|
|
|
KeAcquireSpinLock(&PiApcLock, &oldIrql);
|
2001-01-19 15:09:01 +00:00
|
|
|
if (KeGetCurrentThread()->ApcState.UserApcPending == 0)
|
2000-10-07 13:41:58 +00:00
|
|
|
{
|
|
|
|
KeReleaseSpinLock(&PiApcLock, oldIrql);
|
|
|
|
return(FALSE);
|
|
|
|
}
|
2001-01-19 15:09:01 +00:00
|
|
|
KeGetCurrentThread()->Alerted[0] = 1;
|
2000-10-07 13:41:58 +00:00
|
|
|
KeReleaseSpinLock(&PiApcLock, oldIrql);
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
2001-02-06 00:11:20 +00:00
|
|
|
VOID
|
|
|
|
KiDeliverNormalApc(VOID)
|
|
|
|
{
|
|
|
|
PETHREAD Thread = PsGetCurrentThread();
|
|
|
|
PLIST_ENTRY current;
|
|
|
|
PKAPC Apc;
|
|
|
|
KIRQL oldlvl;
|
|
|
|
PKNORMAL_ROUTINE NormalRoutine;
|
|
|
|
PVOID NormalContext;
|
|
|
|
PVOID SystemArgument1;
|
|
|
|
PVOID SystemArgument2;
|
|
|
|
|
|
|
|
KeAcquireSpinLock(&PiApcLock, &oldlvl);
|
|
|
|
while(!IsListEmpty(&(Thread->Tcb.ApcState.ApcListHead[0])))
|
|
|
|
{
|
|
|
|
current = Thread->Tcb.ApcState.ApcListHead[0].Blink;
|
|
|
|
Apc = CONTAINING_RECORD(current, KAPC, ApcListEntry);
|
|
|
|
if (Apc->NormalRoutine != NULL)
|
|
|
|
{
|
2001-03-18 19:35:14 +00:00
|
|
|
(VOID)RemoveTailList(&Thread->Tcb.ApcState.ApcListHead[0]);
|
2001-02-06 00:11:20 +00:00
|
|
|
Thread->Tcb.ApcState.KernelApcInProgress++;
|
|
|
|
Thread->Tcb.ApcState.KernelApcPending--;
|
|
|
|
|
|
|
|
KeReleaseSpinLock(&PiApcLock, oldlvl);
|
|
|
|
|
|
|
|
NormalRoutine = Apc->NormalRoutine;
|
|
|
|
NormalContext = Apc->NormalContext;
|
|
|
|
SystemArgument1 = Apc->SystemArgument1;
|
|
|
|
SystemArgument2 = Apc->SystemArgument2;
|
|
|
|
Apc->KernelRoutine(Apc,
|
|
|
|
&NormalRoutine,
|
|
|
|
&NormalContext,
|
|
|
|
&SystemArgument1,
|
|
|
|
&SystemArgument2);
|
|
|
|
NormalRoutine(NormalContext, SystemArgument1, SystemArgument2);
|
|
|
|
|
|
|
|
KeAcquireSpinLock(&PiApcLock, &oldlvl);
|
|
|
|
Thread->Tcb.ApcState.KernelApcInProgress--;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
KeReleaseSpinLock(&PiApcLock, oldlvl);
|
|
|
|
}
|
|
|
|
|
|
|
|
BOOLEAN
|
|
|
|
KiDeliverUserApc(PKTRAP_FRAME TrapFrame)
|
1999-05-29 00:15:17 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Tests whether there are any pending APCs for the current thread
|
|
|
|
* and if so the APCs will be delivered on exit from kernel mode.
|
|
|
|
* ARGUMENTS:
|
|
|
|
* Thread = Thread to test for alerts
|
2000-07-10 21:55:49 +00:00
|
|
|
* UserContext = The user context saved on entry to kernel mode
|
1999-05-29 00:15:17 +00:00
|
|
|
*/
|
|
|
|
{
|
|
|
|
PLIST_ENTRY current_entry;
|
|
|
|
PKAPC Apc;
|
2000-05-13 13:51:08 +00:00
|
|
|
PULONG Esp;
|
2000-10-11 20:50:35 +00:00
|
|
|
PCONTEXT Context;
|
1999-12-12 03:56:53 +00:00
|
|
|
KIRQL oldlvl;
|
2000-10-07 13:41:58 +00:00
|
|
|
PKTHREAD Thread;
|
2001-01-17 15:38:03 +00:00
|
|
|
|
2000-10-11 20:50:35 +00:00
|
|
|
DPRINT("KiDeliverUserApc(TrapFrame %x/%x)\n", TrapFrame,
|
|
|
|
KeGetCurrentThread()->TrapFrame);
|
2000-10-07 13:41:58 +00:00
|
|
|
Thread = KeGetCurrentThread();
|
2001-01-17 15:38:03 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Check for thread termination
|
|
|
|
*/
|
|
|
|
|
2001-01-18 15:00:09 +00:00
|
|
|
KeAcquireSpinLock(&PiApcLock, &oldlvl);
|
|
|
|
|
2000-10-11 20:50:35 +00:00
|
|
|
current_entry = Thread->ApcState.ApcListHead[1].Flink;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Shouldn't happen but check anyway.
|
|
|
|
*/
|
|
|
|
if (current_entry == &Thread->ApcState.ApcListHead[1])
|
1999-11-24 11:51:55 +00:00
|
|
|
{
|
2000-10-11 20:50:35 +00:00
|
|
|
KeReleaseSpinLock(&PiApcLock, oldlvl);
|
|
|
|
DbgPrint("KiDeliverUserApc called but no APC was pending\n");
|
|
|
|
return(FALSE);
|
1999-11-24 11:51:55 +00:00
|
|
|
}
|
2000-10-11 20:50:35 +00:00
|
|
|
|
|
|
|
current_entry = RemoveHeadList(&Thread->ApcState.ApcListHead[1]);
|
|
|
|
Apc = CONTAINING_RECORD(current_entry, KAPC, ApcListEntry);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Save the thread's current context (in other words the registers
|
|
|
|
* that will be restored when it returns to user mode) so the
|
|
|
|
* APC dispatcher can restore them later
|
|
|
|
*/
|
|
|
|
Context = (PCONTEXT)(((PUCHAR)TrapFrame->Esp) - sizeof(CONTEXT));
|
|
|
|
memset(Context, 0, sizeof(CONTEXT));
|
|
|
|
Context->ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER |
|
|
|
|
CONTEXT_SEGMENTS | CONTEXT_i386;
|
|
|
|
Context->SegGs = TrapFrame->Gs;
|
|
|
|
Context->SegFs = TrapFrame->Fs;
|
|
|
|
Context->SegEs = TrapFrame->Es;
|
|
|
|
Context->SegDs = TrapFrame->Ds;
|
|
|
|
Context->Edi = TrapFrame->Edi;
|
|
|
|
Context->Esi = TrapFrame->Esi;
|
|
|
|
Context->Ebx = TrapFrame->Ebx;
|
|
|
|
Context->Edx = TrapFrame->Edx;
|
|
|
|
Context->Ecx = TrapFrame->Ecx;
|
|
|
|
Context->Eax = TrapFrame->Eax;
|
|
|
|
Context->Ebp = TrapFrame->Ebp;
|
|
|
|
Context->Eip = TrapFrame->Eip;
|
|
|
|
Context->SegCs = TrapFrame->Cs;
|
|
|
|
Context->EFlags = TrapFrame->Eflags;
|
|
|
|
Context->Esp = TrapFrame->Esp;
|
|
|
|
Context->SegSs = TrapFrame->Ss;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Setup the trap frame so the thread will start executing at the
|
|
|
|
* APC Dispatcher when it returns to user-mode
|
|
|
|
*/
|
|
|
|
Esp = (PULONG)(((PUCHAR)TrapFrame->Esp) -
|
|
|
|
(sizeof(CONTEXT) + (6 * sizeof(ULONG))));
|
|
|
|
|
|
|
|
Esp[0] = 0xdeadbeef;
|
|
|
|
Esp[1] = (ULONG)Apc->NormalRoutine;
|
|
|
|
Esp[2] = (ULONG)Apc->NormalContext;
|
|
|
|
Esp[3] = (ULONG)Apc->SystemArgument1;
|
|
|
|
Esp[4] = (ULONG)Apc->SystemArgument2;
|
|
|
|
Esp[5] = (ULONG)Context;
|
|
|
|
TrapFrame->Eip = (ULONG)LdrpGetSystemDllApcDispatcher();
|
|
|
|
TrapFrame->Esp = (ULONG)Esp;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We've dealt with one pending user-mode APC
|
|
|
|
*/
|
|
|
|
Thread->ApcState.UserApcPending--;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* FIXME: Give some justification for this
|
|
|
|
*/
|
|
|
|
KeReleaseSpinLock(&PiApcLock, oldlvl);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Now call for the kernel routine for the APC, which will free
|
|
|
|
* the APC data structure, we can't do this ourselves because
|
|
|
|
* the APC may be embedded in some larger structure e.g. an IRP
|
|
|
|
* We also give the kernel routine a last chance to modify the arguments to
|
|
|
|
* the user APC routine.
|
|
|
|
*/
|
|
|
|
Apc->KernelRoutine(Apc,
|
|
|
|
(PKNORMAL_ROUTINE*)&Esp[1],
|
|
|
|
(PVOID*)&Esp[2],
|
|
|
|
(PVOID*)&Esp[3],
|
|
|
|
(PVOID*)&Esp[4]);
|
2001-01-19 15:09:01 +00:00
|
|
|
|
|
|
|
Thread->Alerted[0] = 0;
|
2000-10-07 13:41:58 +00:00
|
|
|
return(TRUE);
|
1999-05-29 00:15:17 +00:00
|
|
|
}
|
|
|
|
|
2001-04-09 02:45:04 +00:00
|
|
|
VOID STDCALL
|
|
|
|
KiDeliverApc(ULONG Unknown1,
|
|
|
|
ULONG Unknown2,
|
|
|
|
ULONG Unknown3)
|
2000-10-11 20:50:35 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Deliver an APC to the current thread.
|
|
|
|
* NOTES: This is called from the IRQL switching code if the current thread
|
|
|
|
* is returning from an IRQL greater than or equal to APC_LEVEL to
|
|
|
|
* PASSIVE_LEVEL and there are kernel-mode APCs pending. This means any
|
|
|
|
* pending APCs will be delivered after a thread gets a new quantum and
|
|
|
|
* after it wakes from a wait.
|
|
|
|
*/
|
1999-11-24 11:51:55 +00:00
|
|
|
{
|
1999-12-12 03:56:53 +00:00
|
|
|
PETHREAD Thread = PsGetCurrentThread();
|
2001-03-18 19:35:14 +00:00
|
|
|
PLIST_ENTRY current_entry;
|
1999-12-12 03:56:53 +00:00
|
|
|
PKAPC Apc;
|
|
|
|
KIRQL oldlvl;
|
|
|
|
|
2000-07-10 21:55:49 +00:00
|
|
|
DPRINT("KiDeliverApc()\n");
|
1999-12-13 22:04:41 +00:00
|
|
|
KeAcquireSpinLock(&PiApcLock, &oldlvl);
|
2001-03-18 19:35:14 +00:00
|
|
|
current_entry = Thread->Tcb.ApcState.ApcListHead[0].Flink;
|
|
|
|
while(current_entry != &Thread->Tcb.ApcState.ApcListHead[0])
|
|
|
|
{
|
|
|
|
Apc = CONTAINING_RECORD(current_entry, KAPC, ApcListEntry);
|
|
|
|
if (Apc->NormalRoutine == NULL)
|
|
|
|
{
|
|
|
|
current_entry = current_entry->Flink;
|
|
|
|
RemoveEntryList(&Apc->ApcListEntry);
|
|
|
|
Thread->Tcb.ApcState.KernelApcInProgress++;
|
|
|
|
Thread->Tcb.ApcState.KernelApcPending--;
|
|
|
|
|
|
|
|
KeReleaseSpinLock(&PiApcLock, oldlvl);
|
|
|
|
|
|
|
|
Apc->KernelRoutine(Apc,
|
|
|
|
&Apc->NormalRoutine,
|
|
|
|
&Apc->NormalContext,
|
|
|
|
&Apc->SystemArgument1,
|
|
|
|
&Apc->SystemArgument2);
|
|
|
|
|
|
|
|
KeAcquireSpinLock(&PiApcLock, &oldlvl);
|
|
|
|
Thread->Tcb.ApcState.KernelApcInProgress--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
current_entry = current_entry->Flink;
|
|
|
|
}
|
|
|
|
}
|
1999-12-13 22:04:41 +00:00
|
|
|
KeReleaseSpinLock(&PiApcLock, oldlvl);
|
1998-10-05 04:01:30 +00:00
|
|
|
}
|
|
|
|
|
2001-02-04 17:28:13 +00:00
|
|
|
VOID STDCALL
|
2001-01-17 15:38:03 +00:00
|
|
|
KeInsertQueueApc (PKAPC Apc,
|
|
|
|
PVOID SystemArgument1,
|
|
|
|
PVOID SystemArgument2,
|
|
|
|
UCHAR Mode)
|
1999-06-09 15:50:16 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Queues an APC for execution
|
|
|
|
* ARGUMENTS:
|
|
|
|
* Apc = APC to be queued
|
|
|
|
* SystemArgument[1-2] = TBD
|
|
|
|
* Mode = TBD
|
|
|
|
*/
|
1998-08-28 23:24:42 +00:00
|
|
|
{
|
1998-10-05 04:01:30 +00:00
|
|
|
KIRQL oldlvl;
|
1999-05-29 00:15:17 +00:00
|
|
|
PKTHREAD TargetThread;
|
1998-10-05 04:01:30 +00:00
|
|
|
|
|
|
|
DPRINT("KeInsertQueueApc(Apc %x, SystemArgument1 %x, "
|
|
|
|
"SystemArgument2 %x, Mode %d)\n",Apc,SystemArgument1,
|
|
|
|
SystemArgument2,Mode);
|
1998-08-28 23:24:42 +00:00
|
|
|
|
1999-12-13 22:04:41 +00:00
|
|
|
KeAcquireSpinLock(&PiApcLock, &oldlvl);
|
1998-10-05 04:01:30 +00:00
|
|
|
|
1999-11-24 11:51:55 +00:00
|
|
|
Apc->SystemArgument1 = SystemArgument1;
|
|
|
|
Apc->SystemArgument2 = SystemArgument2;
|
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
if (Apc->Inserted)
|
|
|
|
{
|
|
|
|
DbgPrint("KeInsertQueueApc(): multiple APC insertations\n");
|
|
|
|
KeBugCheck(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
TargetThread = Apc->Thread;
|
1999-06-09 15:50:16 +00:00
|
|
|
if (Apc->ApcMode == KernelMode)
|
|
|
|
{
|
|
|
|
InsertTailList(&TargetThread->ApcState.ApcListHead[0],
|
|
|
|
&Apc->ApcListEntry);
|
|
|
|
TargetThread->ApcState.KernelApcPending++;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
InsertTailList(&TargetThread->ApcState.ApcListHead[1],
|
|
|
|
&Apc->ApcListEntry);
|
2001-01-19 15:09:01 +00:00
|
|
|
TargetThread->ApcState.UserApcPending++;
|
1999-06-09 15:50:16 +00:00
|
|
|
}
|
1999-05-29 00:15:17 +00:00
|
|
|
Apc->Inserted = TRUE;
|
2001-03-18 19:35:14 +00:00
|
|
|
|
2001-04-09 02:45:04 +00:00
|
|
|
/*
|
|
|
|
* If this is a kernel-mode APC for the current thread and we are not
|
|
|
|
* inside a critical section or at APC level then call it, in fact we
|
|
|
|
* rely on the side effects of dropping the IRQL level when we release
|
|
|
|
* the spinlock
|
|
|
|
*/
|
|
|
|
if (Apc->ApcMode == KernelMode && TargetThread == KeGetCurrentThread() &&
|
|
|
|
Apc->NormalRoutine == NULL)
|
|
|
|
{
|
|
|
|
KeReleaseSpinLock(&PiApcLock, oldlvl);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2001-03-18 19:35:14 +00:00
|
|
|
/*
|
|
|
|
* If this is a kernel-mode APC and it is waiting at PASSIVE_LEVEL and
|
|
|
|
* not inside a critical section then wake it up. Otherwise it will
|
|
|
|
* execute the APC as soon as it returns to PASSIVE_LEVEL.
|
|
|
|
* FIXME: If the thread is running on another processor then send an
|
|
|
|
* IPI.
|
|
|
|
* FIXME: Check if the thread is terminating.
|
|
|
|
*/
|
1999-12-13 22:04:41 +00:00
|
|
|
if (Apc->ApcMode == KernelMode && TargetThread->KernelApcDisable >= 1 &&
|
2001-02-06 00:11:20 +00:00
|
|
|
TargetThread->WaitIrql < APC_LEVEL && Apc->NormalRoutine == NULL)
|
1999-06-09 15:50:16 +00:00
|
|
|
{
|
1999-12-13 22:04:41 +00:00
|
|
|
KeRemoveAllWaitsThread(CONTAINING_RECORD(TargetThread, ETHREAD, Tcb),
|
|
|
|
STATUS_KERNEL_APC);
|
1999-06-09 15:50:16 +00:00
|
|
|
}
|
2001-03-18 19:35:14 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* If this is a 'funny' user-mode APC then mark the thread as
|
|
|
|
* alerted so it will execute the APC on exit from kernel mode. If it
|
|
|
|
* is waiting alertably then wake it up so it can return to user mode.
|
|
|
|
*/
|
2001-02-06 00:11:20 +00:00
|
|
|
if (Apc->ApcMode == KernelMode && Apc->NormalRoutine != NULL)
|
|
|
|
{
|
|
|
|
TargetThread->Alerted[1] = 1;
|
|
|
|
if (TargetThread->Alertable == TRUE &&
|
|
|
|
TargetThread->WaitMode == UserMode)
|
|
|
|
{
|
|
|
|
PETHREAD Thread;
|
|
|
|
|
|
|
|
Thread = CONTAINING_RECORD(TargetThread, ETHREAD, Tcb);
|
|
|
|
KeRemoveAllWaitsThread(Thread, STATUS_USER_APC);
|
|
|
|
}
|
|
|
|
}
|
2001-01-18 15:00:09 +00:00
|
|
|
|
|
|
|
/*
|
2001-03-18 19:35:14 +00:00
|
|
|
* If the thread is waiting alertably then wake it up and it will
|
|
|
|
* return to to user-mode executing the APC in the process. Otherwise the
|
|
|
|
* thread will execute the APC next time it enters an alertable wait.
|
2001-01-18 15:00:09 +00:00
|
|
|
*/
|
1999-11-24 11:51:55 +00:00
|
|
|
if (Apc->ApcMode == UserMode && TargetThread->Alertable == TRUE &&
|
|
|
|
TargetThread->WaitMode == UserMode)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
DPRINT("Resuming thread for user APC\n");
|
|
|
|
|
|
|
|
Status = STATUS_USER_APC;
|
2001-01-19 15:09:01 +00:00
|
|
|
TargetThread->Alerted[0] = 1;
|
1999-12-13 22:04:41 +00:00
|
|
|
KeRemoveAllWaitsThread(CONTAINING_RECORD(TargetThread, ETHREAD, Tcb),
|
|
|
|
STATUS_USER_APC);
|
1999-11-24 11:51:55 +00:00
|
|
|
}
|
2000-07-30 18:22:35 +00:00
|
|
|
KeReleaseSpinLock(&PiApcLock, oldlvl);
|
1998-08-28 23:24:42 +00:00
|
|
|
}
|
|
|
|
|
2001-02-04 17:28:13 +00:00
|
|
|
BOOLEAN STDCALL
|
|
|
|
KeRemoveQueueApc (PKAPC Apc)
|
|
|
|
/*
|
|
|
|
* FUNCTION: Removes APC object from the apc queue
|
|
|
|
* ARGUMENTS:
|
|
|
|
* Apc = APC to remove
|
|
|
|
* RETURNS: TRUE if the APC was in the queue
|
|
|
|
* FALSE otherwise
|
|
|
|
* NOTE: This function is not exported.
|
|
|
|
*/
|
|
|
|
{
|
|
|
|
KIRQL oldIrql;
|
|
|
|
PKTHREAD TargetThread;
|
|
|
|
|
|
|
|
KeAcquireSpinLockAtDpcLevel(&PiApcLock);
|
|
|
|
KeRaiseIrql(HIGH_LEVEL, &oldIrql);
|
|
|
|
if (Apc->Inserted == FALSE)
|
|
|
|
{
|
|
|
|
KeReleaseSpinLock(&PiApcLock, oldIrql);
|
|
|
|
return(FALSE);
|
|
|
|
}
|
|
|
|
|
|
|
|
TargetThread = Apc->Thread;
|
|
|
|
RemoveEntryList(&Apc->ApcListEntry);
|
|
|
|
if (Apc->ApcMode == KernelMode)
|
|
|
|
{
|
|
|
|
TargetThread->ApcState.KernelApcPending--;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TargetThread->ApcState.UserApcPending--;
|
|
|
|
}
|
|
|
|
Apc->Inserted = FALSE;
|
|
|
|
|
|
|
|
KeReleaseSpinLock(&PiApcLock, oldIrql);
|
|
|
|
return(TRUE);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2000-07-30 18:22:35 +00:00
|
|
|
VOID STDCALL
|
|
|
|
KeInitializeApc (PKAPC Apc,
|
|
|
|
PKTHREAD Thread,
|
|
|
|
UCHAR StateIndex,
|
|
|
|
PKKERNEL_ROUTINE KernelRoutine,
|
|
|
|
PKRUNDOWN_ROUTINE RundownRoutine,
|
|
|
|
PKNORMAL_ROUTINE NormalRoutine,
|
|
|
|
UCHAR Mode,
|
|
|
|
PVOID Context)
|
1999-06-09 15:50:16 +00:00
|
|
|
/*
|
|
|
|
* FUNCTION: Initialize an APC object
|
|
|
|
* ARGUMENTS:
|
|
|
|
* Apc = Pointer to the APC object to initialized
|
|
|
|
* Thread = Thread the APC is to be delivered to
|
|
|
|
* StateIndex = TBD
|
|
|
|
* KernelRoutine = Routine to be called for a kernel-mode APC
|
|
|
|
* RundownRoutine = Routine to be called if the thread has exited with
|
|
|
|
* the APC being executed
|
|
|
|
* NormalRoutine = Routine to be called for a user-mode APC
|
|
|
|
* Mode = APC mode
|
|
|
|
* Context = Parameter to be passed to the APC routine
|
|
|
|
*/
|
1999-11-24 11:51:55 +00:00
|
|
|
{
|
1999-05-29 00:15:17 +00:00
|
|
|
DPRINT("KeInitializeApc(Apc %x, Thread %x, StateIndex %d, "
|
|
|
|
"KernelRoutine %x, RundownRoutine %x, NormalRoutine %x, Mode %d, "
|
|
|
|
"Context %x)\n",Apc,Thread,StateIndex,KernelRoutine,RundownRoutine,
|
|
|
|
NormalRoutine,Mode,Context);
|
2001-03-18 19:35:14 +00:00
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
memset(Apc, 0, sizeof(KAPC));
|
1998-09-05 17:34:23 +00:00
|
|
|
Apc->Thread = Thread;
|
1999-05-29 00:15:17 +00:00
|
|
|
Apc->ApcListEntry.Flink = NULL;
|
|
|
|
Apc->ApcListEntry.Blink = NULL;
|
|
|
|
Apc->KernelRoutine = KernelRoutine;
|
|
|
|
Apc->RundownRoutine = RundownRoutine;
|
|
|
|
Apc->NormalRoutine = NormalRoutine;
|
|
|
|
Apc->NormalContext = Context;
|
|
|
|
Apc->Inserted = FALSE;
|
|
|
|
Apc->ApcStateIndex = StateIndex;
|
1999-11-24 11:51:55 +00:00
|
|
|
if (Apc->NormalRoutine != NULL)
|
|
|
|
{
|
|
|
|
Apc->ApcMode = Mode;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
Apc->ApcMode = KernelMode;
|
|
|
|
}
|
1998-08-28 23:24:42 +00:00
|
|
|
}
|
|
|
|
|
2000-10-11 20:50:35 +00:00
|
|
|
VOID NtQueueApcRundownRoutine(PKAPC Apc)
|
|
|
|
{
|
|
|
|
ExFreePool(Apc);
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID NtQueueApcKernelRoutine(PKAPC Apc,
|
|
|
|
PKNORMAL_ROUTINE* NormalRoutine,
|
|
|
|
PVOID* NormalContext,
|
|
|
|
PVOID* SystemArgument1,
|
|
|
|
PVOID* SystemArgument2)
|
|
|
|
{
|
|
|
|
ExFreePool(Apc);
|
|
|
|
}
|
1998-10-05 04:01:30 +00:00
|
|
|
|
1999-11-24 11:51:55 +00:00
|
|
|
NTSTATUS STDCALL NtQueueApcThread(HANDLE ThreadHandle,
|
|
|
|
PKNORMAL_ROUTINE ApcRoutine,
|
|
|
|
PVOID NormalContext,
|
|
|
|
PVOID SystemArgument1,
|
|
|
|
PVOID SystemArgument2)
|
1998-10-05 04:01:30 +00:00
|
|
|
{
|
1999-06-09 15:50:16 +00:00
|
|
|
PKAPC Apc;
|
|
|
|
PETHREAD Thread;
|
|
|
|
NTSTATUS Status;
|
|
|
|
|
|
|
|
Status = ObReferenceObjectByHandle(ThreadHandle,
|
|
|
|
THREAD_ALL_ACCESS, /* FIXME */
|
|
|
|
PsThreadType,
|
|
|
|
UserMode,
|
|
|
|
(PVOID*)&Thread,
|
|
|
|
NULL);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
return(Status);
|
|
|
|
}
|
|
|
|
|
2001-03-07 16:48:45 +00:00
|
|
|
Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_KAPC);
|
1999-06-09 15:50:16 +00:00
|
|
|
if (Apc == NULL)
|
|
|
|
{
|
|
|
|
ObDereferenceObject(Thread);
|
|
|
|
return(STATUS_NO_MEMORY);
|
|
|
|
}
|
|
|
|
|
|
|
|
KeInitializeApc(Apc,
|
|
|
|
&Thread->Tcb,
|
|
|
|
0,
|
2000-10-11 20:50:35 +00:00
|
|
|
NtQueueApcKernelRoutine,
|
|
|
|
NtQueueApcRundownRoutine,
|
1999-06-09 15:50:16 +00:00
|
|
|
ApcRoutine,
|
|
|
|
UserMode,
|
|
|
|
NormalContext);
|
|
|
|
KeInsertQueueApc(Apc,
|
|
|
|
SystemArgument1,
|
|
|
|
SystemArgument2,
|
|
|
|
UserMode);
|
|
|
|
|
|
|
|
ObDereferenceObject(Thread);
|
|
|
|
return(STATUS_SUCCESS);
|
1998-10-05 04:01:30 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-11-24 11:51:55 +00:00
|
|
|
NTSTATUS STDCALL NtTestAlert(VOID)
|
1998-10-05 04:01:30 +00:00
|
|
|
{
|
2000-10-07 13:41:58 +00:00
|
|
|
KiTestAlert();
|
1999-11-24 11:51:55 +00:00
|
|
|
return(STATUS_SUCCESS);
|
1998-10-05 04:01:30 +00:00
|
|
|
}
|
1999-12-12 03:56:53 +00:00
|
|
|
|
1999-12-13 22:04:41 +00:00
|
|
|
VOID PiInitApcManagement(VOID)
|
1999-12-12 03:56:53 +00:00
|
|
|
{
|
1999-12-13 22:04:41 +00:00
|
|
|
KeInitializeSpinLock(&PiApcLock);
|
1999-12-12 03:56:53 +00:00
|
|
|
}
|
|
|
|
|