diff --git a/reactos/ntoskrnl/Makefile b/reactos/ntoskrnl/Makefile index 96e3f2ab3db..43a1e1774b7 100644 --- a/reactos/ntoskrnl/Makefile +++ b/reactos/ntoskrnl/Makefile @@ -226,9 +226,10 @@ OBJECTS_PS = \ ps/locale.o \ ps/process.o \ ps/psmgr.o \ + ps/query.o \ + ps/security.o \ ps/suspend.o \ ps/thread.o \ - ps/tinfo.o \ ps/win32.o \ ps/w32call.o diff --git a/reactos/ntoskrnl/cm/ntfunc.c b/reactos/ntoskrnl/cm/ntfunc.c index d69c10bbd2b..7add4806390 100644 --- a/reactos/ntoskrnl/cm/ntfunc.c +++ b/reactos/ntoskrnl/cm/ntfunc.c @@ -2003,6 +2003,34 @@ NtNotifyChangeKey (IN HANDLE KeyHandle, return(STATUS_NOT_IMPLEMENTED); } +#if 0 +NTSTATUS STDCALL +NtNotifyChangeKey (IN HANDLE KeyHandle, + IN HANDLE Event, + IN PIO_APC_ROUTINE ApcRoutine OPTIONAL, + IN PVOID ApcContext OPTIONAL, + OUT PIO_STATUS_BLOCK IoStatusBlock, + IN ULONG CompletionFilter, + IN BOOLEAN WatchSubtree, + OUT PVOID Buffer, + IN ULONG Length, + IN BOOLEAN Asynchronous) +{ + return NtNotifyChangeMultipleKeys(KeyHandle, + 0, + NULL, + Event, + ApcRoutine, + ApcContext, + IoStatusBlock, + CompletionFilter, + WatchTree, + Buffer, + Length, + Asynchronous); +} + +#endif NTSTATUS STDCALL NtQueryMultipleValueKey (IN HANDLE KeyHandle, diff --git a/reactos/ntoskrnl/ex/timer.c b/reactos/ntoskrnl/ex/timer.c index 10cf2b994b2..e5878f6295f 100644 --- a/reactos/ntoskrnl/ex/timer.c +++ b/reactos/ntoskrnl/ex/timer.c @@ -53,6 +53,66 @@ static const INFORMATION_CLASS_INFO ExTimerInfoClass[] = { /* FUNCTIONS *****************************************************************/ +VOID +STDCALL +ExTimerRundown(VOID) +{ + PETHREAD Thread = PsGetCurrentThread(); + KIRQL OldIrql; + PLIST_ENTRY CurrentEntry; + BOOLEAN KillTimer = FALSE; + PETIMER Timer; + + /* Lock the Thread's Active Timer List*/ + KeAcquireSpinLock(&Thread->ActiveTimerListLock, &OldIrql); + + /* Loop through all the timers */ + CurrentEntry = Thread->ActiveTimerListHead.Flink; + while (CurrentEntry != &Thread->ActiveTimerListHead) { + + /* Get the Timer */ + Timer = CONTAINING_RECORD(CurrentEntry, ETIMER, ActiveTimerListEntry); + DPRINT("Timer, ThreadList: %x, %x\n", Timer, Thread); + + /* Unlock the list */ + KeReleaseSpinLock(&Thread->ActiveTimerListLock, OldIrql); + + /* Lock the Timer */ + KeAcquireSpinLock(&Timer->Lock, &OldIrql); + + /* Relock the active list */ + KeAcquireSpinLockAtDpcLevel(&Thread->ActiveTimerListLock); + + /* Make sure it's associated to us */ + if ((Timer->ApcAssociated) && (&Thread->Tcb == Timer->TimerApc.Thread)) { + + /* Remove it */ + DPRINT("Removing from Thread: %x\n", Thread); + RemoveEntryList(&Thread->ActiveTimerListHead); + KeCancelTimer(&Timer->KeTimer); + KeRemoveQueueDpc(&Timer->TimerDpc); + KeRemoveQueueApc(&Timer->TimerApc); + Timer->ApcAssociated = FALSE; + KillTimer = TRUE; + } + + /* Unlock the list */ + KeReleaseSpinLockFromDpcLevel(&Thread->ActiveTimerListLock); + + /* Unlock the Timer */ + KeReleaseSpinLock(&Timer->Lock, OldIrql); + + /* Dereference it, if needed */ + if (KillTimer) ObDereferenceObject(Timer); + + /* Loop again */ + KeAcquireSpinLock(&Thread->ActiveTimerListLock, &OldIrql); + CurrentEntry = CurrentEntry->Flink; + } + + KeReleaseSpinLock(&Thread->ActiveTimerListLock, OldIrql); +} + VOID STDCALL ExpDeleteTimer(PVOID ObjectBody) diff --git a/reactos/ntoskrnl/include/internal/ex.h b/reactos/ntoskrnl/include/internal/ex.h index c2d17e94687..4fe107e5618 100644 --- a/reactos/ntoskrnl/include/internal/ex.h +++ b/reactos/ntoskrnl/include/internal/ex.h @@ -185,6 +185,10 @@ ExpSetTimeZoneInformation(PTIME_ZONE_INFORMATION TimeZoneInformation); NTSTATUS ExpAllocateLocallyUniqueId(OUT LUID *LocallyUniqueId); +VOID +STDCALL +ExTimerRundown(VOID); + #define InterlockedDecrementUL(Addend) \ (ULONG)InterlockedDecrement((PLONG)(Addend)) diff --git a/reactos/ntoskrnl/include/internal/ke.h b/reactos/ntoskrnl/include/internal/ke.h index 4a3d1e7263e..305d46f4490 100644 --- a/reactos/ntoskrnl/include/internal/ke.h +++ b/reactos/ntoskrnl/include/internal/ke.h @@ -49,6 +49,35 @@ struct _KEXCEPTION_FRAME; #define IPI_REQUEST_DPC 2 #define IPI_REQUEST_FREEZE 3 +/* threadsch.c ********************************************************************/ + +/* Thread Scheduler Functions */ + +/* Readies a Thread for Execution. */ +VOID +STDCALL +KiDispatchThreadNoLock(ULONG NewThreadStatus); + +/* Readies a Thread for Execution. */ +VOID +STDCALL +KiDispatchThread(ULONG NewThreadStatus); + +/* Puts a Thread into a block state. */ +VOID +STDCALL +KiBlockThread(PNTSTATUS Status, + UCHAR Alertable, + ULONG WaitMode, + UCHAR WaitReason); + +/* Removes a thread out of a block state. */ +VOID +STDCALL +KiUnblockThread(PKTHREAD Thread, + PNTSTATUS WaitStatus, + KPRIORITY Increment); + /* ipi.c ********************************************************************/ BOOLEAN STDCALL @@ -150,6 +179,29 @@ VOID inline FASTCALL KeAcquireDispatcherDatabaseLockAtDpcLevel(VOID); VOID inline FASTCALL KeReleaseDispatcherDatabaseLock(KIRQL Irql); VOID inline FASTCALL KeReleaseDispatcherDatabaseLockFromDpcLevel(VOID); +VOID +STDCALL +KeInitializeThread(struct _KPROCESS* Process, PKTHREAD Thread, BOOLEAN First); + +VOID +STDCALL +KeRundownThread(VOID); + +NTSTATUS KeReleaseThread(PKTHREAD Thread); + +VOID +STDCALL +KeStackAttachProcess ( + IN struct _KPROCESS* Process, + OUT PKAPC_STATE ApcState + ); + +VOID +STDCALL +KeUnstackDetachProcess ( + IN PKAPC_STATE ApcState + ); + BOOLEAN KiDispatcherObjectWake(DISPATCHER_HEADER* hdr, KPRIORITY increment); VOID STDCALL KeExpireTimers(PKDPC Apc, PVOID Arg1, @@ -165,6 +217,10 @@ FASTCALL KiAbortWaitThread(PKTHREAD Thread, NTSTATUS WaitStatus, KPRIORITY Increment); + +ULONG +STDCALL +KeForceResumeThread(IN PKTHREAD Thread); BOOLEAN STDCALL KiInsertTimer(PKTIMER Timer, LARGE_INTEGER DueTime); @@ -182,6 +238,18 @@ VOID STDCALL KiDeliverApc(KPROCESSOR_MODE PreviousMode, PVOID Reserved, PKTRAP_FRAME TrapFrame); +LONG +STDCALL +KiInsertQueue(IN PKQUEUE Queue, + IN PLIST_ENTRY Entry, + BOOLEAN Head); + +ULONG +STDCALL +KeSetProcess(struct _KPROCESS* Process, + KPRIORITY Increment); + + VOID STDCALL KeInitializeEventPair(PKEVENT_PAIR EventPair); VOID STDCALL KiInitializeUserApc(IN PVOID Reserved, diff --git a/reactos/ntoskrnl/include/internal/ob.h b/reactos/ntoskrnl/include/internal/ob.h index 3e4df5e920c..7e539064202 100644 --- a/reactos/ntoskrnl/include/internal/ob.h +++ b/reactos/ntoskrnl/include/internal/ob.h @@ -302,7 +302,9 @@ ObQueryDeviceMapInformation(PEPROCESS Process, PPROCESS_DEVICEMAP_INFORMATION De VOID FASTCALL ObpSetPermanentObject (IN PVOID ObjectBody, IN BOOLEAN Permanent); - +VOID +STDCALL +ObKillProcess(PEPROCESS Process); /* Security descriptor cache functions */ NTSTATUS diff --git a/reactos/ntoskrnl/include/internal/port.h b/reactos/ntoskrnl/include/internal/port.h index c987f67c811..2ac3064af50 100644 --- a/reactos/ntoskrnl/include/internal/port.h +++ b/reactos/ntoskrnl/include/internal/port.h @@ -29,14 +29,6 @@ typedef struct _EPORT ULONG MaxPoolUsage; /* size of NP zone */ } EPORT, * PEPORT; - -typedef struct _EPORT_TERMINATION_REQUEST -{ - LIST_ENTRY ThreadListEntry; - PEPORT Port; -} EPORT_TERMINATION_REQUEST, *PEPORT_TERMINATION_REQUEST; - - typedef struct _EPORT_CONNECT_REQUEST_MESSAGE { LPC_MESSAGE MessageHeader; @@ -59,6 +51,11 @@ typedef struct _EPORT_CONNECT_REPLY_MESSAGE UCHAR ConnectData[0]; } EPORT_CONNECT_REPLY_MESSAGE, *PEPORT_CONNECT_REPLY_MESSAGE; +typedef struct _TERMINATION_PORT { + LIST_ENTRY Links; + PVOID Port; +} TERMINATION_PORT, *PTERMINATION_PORT; + NTSTATUS STDCALL LpcRequestPort (PEPORT Port, PLPC_MESSAGE LpcMessage); diff --git a/reactos/ntoskrnl/include/internal/ps.h b/reactos/ntoskrnl/include/internal/ps.h index 307a0a89839..fd8b7b2c241 100644 --- a/reactos/ntoskrnl/include/internal/ps.h +++ b/reactos/ntoskrnl/include/internal/ps.h @@ -201,6 +201,7 @@ typedef struct _ETHREAD UCHAR ActiveImpersonationInfo; ULONG PerformanceCountHigh; LIST_ENTRY ThreadListEntry; + BOOLEAN SystemThread; } ETHREAD; #include @@ -437,7 +438,6 @@ VOID PiShutdownProcessManager(VOID); VOID PsInitThreadManagment(VOID); VOID PsInitProcessManagment(VOID); VOID PsInitIdleThread(VOID); -VOID PsDispatchThreadNoLock(ULONG NewThreadStatus); VOID PiTerminateProcessThreads(PEPROCESS Process, NTSTATUS ExitStatus); VOID PsTerminateCurrentThread(NTSTATUS ExitStatus); VOID PsTerminateOtherThread(PETHREAD Thread, NTSTATUS ExitStatus); @@ -458,17 +458,23 @@ PsInitializeThread(PEPROCESS Process, KPROCESSOR_MODE AccessMode, BOOLEAN First); -PACCESS_TOKEN PsReferenceEffectiveToken(PETHREAD Thread, +PACCESS_TOKEN STDCALL PsReferenceEffectiveToken(PETHREAD Thread, PTOKEN_TYPE TokenType, PUCHAR b, PSECURITY_IMPERSONATION_LEVEL Level); -NTSTATUS PsOpenTokenOfProcess(HANDLE ProcessHandle, +NTSTATUS STDCALL PsOpenTokenOfProcess(HANDLE ProcessHandle, PACCESS_TOKEN* Token); - +VOID +STDCALL +PspTerminateProcessThreads(PEPROCESS Process, + NTSTATUS ExitStatus); NTSTATUS PsSuspendThread(PETHREAD Thread, PULONG PreviousCount); NTSTATUS PsResumeThread(PETHREAD Thread, PULONG PreviousCount); - +NTSTATUS +STDCALL +PspAssignPrimaryToken(PEPROCESS Process, + HANDLE TokenHandle); VOID STDCALL PsExitSpecialApc(PKAPC Apc, PKNORMAL_ROUTINE *NormalRoutine, PVOID *NormalContext, @@ -497,27 +503,25 @@ VOID STDCALL PsExitSpecialApc(PKAPC Apc, #define PROCESS_PRIO_RT 18 -VOID STDCALL -KeInitializeThread(PKPROCESS Process, PKTHREAD Thread, BOOLEAN First); -NTSTATUS KeReleaseThread(PKTHREAD Thread); - -VOID -STDCALL -KeStackAttachProcess ( - IN PKPROCESS Process, - OUT PKAPC_STATE ApcState - ); - -VOID -STDCALL -KeUnstackDetachProcess ( - IN PKAPC_STATE ApcState - ); - VOID STDCALL PiDeleteProcess(PVOID ObjectBody); -VOID PsReapThreads(VOID); -VOID PsInitializeThreadReaper(VOID); -VOID PsQueueThreadReap(PETHREAD Thread); + +VOID +STDCALL +PspReapRoutine(PVOID Context); + +VOID +STDCALL +PspExitThread(NTSTATUS ExitStatus); + +extern LIST_ENTRY PspReaperListHead; +extern WORK_QUEUE_ITEM PspReaperWorkItem; +extern BOOLEAN PspReaping; + +VOID +STDCALL +PspTerminateThreadByPointer(PETHREAD Thread, + NTSTATUS ExitStatus); + VOID PsUnfreezeOtherThread(PETHREAD Thread); VOID PsFreezeOtherThread(PETHREAD Thread); VOID PsFreezeProcessThreads(PEPROCESS Process); @@ -525,19 +529,9 @@ VOID PsUnfreezeProcessThreads(PEPROCESS Process); ULONG PsEnumThreadsByProcess(PEPROCESS Process); PEPROCESS PsGetNextProcess(PEPROCESS OldProcess); VOID -STDCALL -PsBlockThread(PNTSTATUS Status, - UCHAR Alertable, - ULONG WaitMode, - UCHAR WaitReason); -VOID -PsUnblockThread(PETHREAD Thread, PNTSTATUS WaitStatus, KPRIORITY Increment); -VOID PsApplicationProcessorInit(VOID); VOID PsPrepareForApplicationProcessorInit(ULONG Id); -VOID -PsInitReaperThread(VOID); VOID STDCALL PsIdleThreadMain(PVOID Context); @@ -553,10 +547,19 @@ VOID STDCALL PiSuspendThreadNormalRoutine(PVOID NormalContext, PVOID SystemArgument1, PVOID SystemArgument2); -VOID STDCALL -PsDispatchThread(ULONG NewThreadStatus); VOID PsInitialiseSuspendImplementation(VOID); +NTSTATUS +STDCALL +PspExitProcess(PEPROCESS Process); + +VOID +STDCALL +PspDeleteProcess(PVOID ObjectBody); + +VOID +STDCALL +PspDeleteThread(PVOID ObjectBody); extern LONG PiNrThreadsAwaitingReaping; diff --git a/reactos/ntoskrnl/ke/apc.c b/reactos/ntoskrnl/ke/apc.c index daefbada63c..b2f06266117 100644 --- a/reactos/ntoskrnl/ke/apc.c +++ b/reactos/ntoskrnl/ke/apc.c @@ -14,10 +14,6 @@ #define NDEBUG #include -/* GLOBALS *******************************************************************/ - -VOID PsTerminateCurrentThread(NTSTATUS ExitStatus); - /* FUNCTIONS *****************************************************************/ /*++ @@ -144,6 +140,120 @@ KeInitializeApc(IN PKAPC Apc, } } +/*++ + * KiInsertQueueApc + * + * The KiInsertQueueApc routine queues a APC for execution when the right + * scheduler environment exists. + * + * Params: + * Apc - Pointer to an initialized control object of type DPC for which the + * caller provides the storage. + * + * PriorityBoost - Priority Boost to apply to the Thread. + * + * Returns: + * If the APC is already inserted or APC queueing is disabled, FALSE. + * Otherwise, TRUE. + * + * Remarks: + * The APC will execute at APC_LEVEL for the KernelRoutine registered, and + * at PASSIVE_LEVEL for the NormalRoutine registered. + * + * Callers of this routine must be running at IRQL = PASSIVE_LEVEL. + * + *--*/ +BOOLEAN +STDCALL +KiInsertQueueApc(PKAPC Apc, + KPRIORITY PriorityBoost) +{ + PKTHREAD Thread = Apc->Thread; + PLIST_ENTRY ApcListEntry; + PKAPC QueuedApc; + + /* Don't do anything if the APC is already inserted */ + if (Apc->Inserted) { + + return FALSE; + } + + /* Three scenarios: + 1) Kernel APC with Normal Routine or User APC = Put it at the end of the List + 2) User APC which is PsExitSpecialApc = Put it at the front of the List + 3) Kernel APC without Normal Routine = Put it at the end of the No-Normal Routine Kernel APC list + */ + if ((Apc->ApcMode != KernelMode) && (Apc->KernelRoutine == (PKKERNEL_ROUTINE)PsExitSpecialApc)) { + + DPRINT ("Inserting the Process Exit APC into the Queue\n"); + Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->UserApcPending = TRUE; + InsertHeadList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode], + &Apc->ApcListEntry); + + } else if (Apc->NormalRoutine == NULL) { + + DPRINT ("Inserting Special APC %x into the Queue\n", Apc); + + for (ApcListEntry = Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode].Flink; + ApcListEntry != &Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode]; + ApcListEntry = ApcListEntry->Flink) { + + QueuedApc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry); + if (Apc->NormalRoutine != NULL) break; + } + + /* We found the first "Normal" APC, so write right before it */ + ApcListEntry = ApcListEntry->Blink; + InsertHeadList(ApcListEntry, &Apc->ApcListEntry); + + } else { + + DPRINT ("Inserting Normal APC %x into the %x Queue\n", Apc, Apc->ApcMode); + InsertTailList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode], + &Apc->ApcListEntry); + } + + /* Confirm Insertion */ + Apc->Inserted = TRUE; + + /* + * Three possibilites here again: + * 1) Kernel APC, The thread is Running: Request an Interrupt + * 2) Kernel APC, The Thread is Waiting at PASSIVE_LEVEL and APCs are enabled and not in progress: Unwait the Thread + * 3) User APC, Unwait the Thread if it is alertable + */ + if (Apc->ApcMode == KernelMode) { + + /* Set Kernel APC pending */ + Thread->ApcState.KernelApcPending = TRUE; + + /* Check the Thread State */ + if (Thread->State == THREAD_STATE_RUNNING) { + + /* FIXME: Use IPI */ + DPRINT ("Requesting APC Interrupt for Running Thread \n"); + HalRequestSoftwareInterrupt(APC_LEVEL); + + } else if ((Thread->State == THREAD_STATE_BLOCKED) && (Thread->WaitIrql == PASSIVE_LEVEL) && + ((Apc->NormalRoutine == NULL) || + ((!Thread->KernelApcDisable) && (!Thread->ApcState.KernelApcInProgress)))) { + + DPRINT("Waking up Thread for Kernel-Mode APC Delivery \n"); + KiAbortWaitThread(Thread, STATUS_KERNEL_APC, PriorityBoost); + } + + } else if ((Thread->State == THREAD_STATE_BLOCKED) && + (Thread->WaitMode == UserMode) && + (Thread->Alertable)) { + + DPRINT("Waking up Thread for User-Mode APC Delivery \n"); + Thread->ApcState.UserApcPending = TRUE; + KiAbortWaitThread(Thread, STATUS_USER_APC, PriorityBoost); + } + + return TRUE; +} + /*++ * KeInsertQueueApc * @implemented NT4 @@ -181,8 +291,7 @@ KeInsertQueueApc(PKAPC Apc, { KIRQL OldIrql; PKTHREAD Thread; - PLIST_ENTRY ApcListEntry; - PKAPC QueuedApc; + BOOLEAN Inserted; ASSERT_IRQL_LESS_OR_EQUAL(DISPATCH_LEVEL); DPRINT("KeInsertQueueApc(Apc %x, SystemArgument1 %x, " @@ -208,89 +317,12 @@ KeInsertQueueApc(PKAPC Apc, Apc->SystemArgument1 = SystemArgument1; Apc->SystemArgument2 = SystemArgument2; - /* Don't do anything if the APC is already inserted */ - if (Apc->Inserted) { - - KeReleaseDispatcherDatabaseLock(OldIrql); - return FALSE; - } - - /* Three scenarios: - 1) Kernel APC with Normal Routine or User APC = Put it at the end of the List - 2) User APC which is PsExitSpecialApc = Put it at the front of the List - 3) Kernel APC without Normal Routine = Put it at the end of the No-Normal Routine Kernel APC list - */ - if ((Apc->ApcMode != KernelMode) && (Apc->KernelRoutine == (PKKERNEL_ROUTINE)PsExitSpecialApc)) { - - DPRINT ("Inserting the Process Exit APC into the Queue\n"); - Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->UserApcPending = TRUE; - InsertHeadList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode], - &Apc->ApcListEntry); - - } else if (Apc->NormalRoutine == NULL) { - - DPRINT ("Inserting Special APC %x into the Queue\n", Apc); - - for (ApcListEntry = Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode].Flink; - ApcListEntry != &Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode]; - ApcListEntry = ApcListEntry->Flink) { - - QueuedApc = CONTAINING_RECORD(ApcListEntry, KAPC, ApcListEntry); - if (Apc->NormalRoutine != NULL) break; - } - - /* We found the first "Normal" APC, so write right before it */ - ApcListEntry = ApcListEntry->Blink; - InsertHeadList(ApcListEntry, &Apc->ApcListEntry); - - } else { - - DPRINT ("Inserting Normal APC %x into the %x Queue\n", Apc, Apc->ApcMode); - InsertTailList(&Thread->ApcStatePointer[(int)Apc->ApcStateIndex]->ApcListHead[(int)Apc->ApcMode], - &Apc->ApcListEntry); - } - - /* Confirm Insertion */ - Apc->Inserted = TRUE; - - /* - * Three possibilites here again: - * 1) Kernel APC, The thread is Running: Request an Interrupt - * 2) Kernel APC, The Thread is Waiting at PASSIVE_LEVEL and APCs are enabled and not in progress: Unwait the Thread - * 3) User APC, Unwait the Thread if it is alertable - */ - if (Apc->ApcMode == KernelMode) { - - /* Set Kernel APC pending */ - Thread->ApcState.KernelApcPending = TRUE; - - /* Check the Thread State */ - if (Thread->State == THREAD_STATE_RUNNING) { - - /* FIXME: Use IPI */ - DPRINT ("Requesting APC Interrupt for Running Thread \n"); - HalRequestSoftwareInterrupt(APC_LEVEL); - - } else if ((Thread->State == THREAD_STATE_BLOCKED) && - (Thread->WaitIrql < APC_LEVEL) && - (Apc->NormalRoutine == NULL)) { - - DPRINT("Waking up Thread for Kernel-Mode APC Delivery \n"); - KiAbortWaitThread(Thread, STATUS_KERNEL_APC, PriorityBoost); - } - - } else if ((Thread->State == THREAD_STATE_BLOCKED) && - (Thread->WaitMode == UserMode) && - (Thread->Alertable)) { - - DPRINT("Waking up Thread for User-Mode APC Delivery \n"); - Thread->ApcState.UserApcPending = TRUE; - KiAbortWaitThread(Thread, STATUS_USER_APC, PriorityBoost); - } + /* Call the Internal Function */ + Inserted = KiInsertQueueApc(Apc, PriorityBoost); /* Return Sucess if we are here */ KeReleaseDispatcherDatabaseLock(OldIrql); - return TRUE; + return Inserted; } /*++ diff --git a/reactos/ntoskrnl/ke/dpc.c b/reactos/ntoskrnl/ke/dpc.c index 668ffdcf753..b65e96133db 100644 --- a/reactos/ntoskrnl/ke/dpc.c +++ b/reactos/ntoskrnl/ke/dpc.c @@ -491,7 +491,7 @@ KiQuantumEnd(VOID) /* Dispatch the Thread */ KeLowerIrql(DISPATCH_LEVEL); - PsDispatchThread(THREAD_STATE_READY); + KiDispatchThread(THREAD_STATE_READY); } /* diff --git a/reactos/ntoskrnl/ke/i386/exp.c b/reactos/ntoskrnl/ke/i386/exp.c index 0928b08f408..b61e1f8ca09 100644 --- a/reactos/ntoskrnl/ke/i386/exp.c +++ b/reactos/ntoskrnl/ke/i386/exp.c @@ -581,6 +581,125 @@ KiTrapHandler(PKTRAP_FRAME Tf, ULONG ExceptionNr) } } +VOID +KeContextToTrapFrame(PCONTEXT Context, + PKTRAP_FRAME TrapFrame) +{ + if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) + { + TrapFrame->Esp = Context->Esp; + TrapFrame->Ss = Context->SegSs; + TrapFrame->Cs = Context->SegCs; + TrapFrame->Eip = Context->Eip; + TrapFrame->Eflags = Context->EFlags; + TrapFrame->Ebp = Context->Ebp; + } + if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) + { + TrapFrame->Eax = Context->Eax; + TrapFrame->Ebx = Context->Ebx; + TrapFrame->Ecx = Context->Ecx; + TrapFrame->Edx = Context->Edx; + TrapFrame->Esi = Context->Esi; + TrapFrame->Edi = Context->Edi; + } + if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) + { + TrapFrame->Ds = Context->SegDs; + TrapFrame->Es = Context->SegEs; + TrapFrame->Fs = Context->SegFs; + TrapFrame->Gs = Context->SegGs; + } + if ((Context->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) + { + /* + * Not handled + * + * This should be handled separately I think. + * - blight + */ + } + if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS) + { + /* + * Not handled + */ + } +} + +VOID +KeTrapFrameToContext(PKTRAP_FRAME TrapFrame, + PCONTEXT Context) +{ + if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) + { + Context->SegSs = TrapFrame->Ss; + Context->Esp = TrapFrame->Esp; + Context->SegCs = TrapFrame->Cs; + Context->Eip = TrapFrame->Eip; + Context->EFlags = TrapFrame->Eflags; + Context->Ebp = TrapFrame->Ebp; + } + if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) + { + Context->Eax = TrapFrame->Eax; + Context->Ebx = TrapFrame->Ebx; + Context->Ecx = TrapFrame->Ecx; + /* + * NOTE: In the trap frame which is built on entry to a system + * call TrapFrame->Edx will actually hold the address of the + * previous TrapFrame. I don't believe leaking this information + * has security implications. Also EDX holds the address of the + * arguments to the system call in progress so it isn't of much + * interest to the debugger. + */ + Context->Edx = TrapFrame->Edx; + Context->Esi = TrapFrame->Esi; + Context->Edi = TrapFrame->Edi; + } + if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) + { + Context->SegDs = TrapFrame->Ds; + Context->SegEs = TrapFrame->Es; + Context->SegFs = TrapFrame->Fs; + Context->SegGs = TrapFrame->Gs; + } + if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS) + { + /* + * FIXME: Implement this case + */ + Context->ContextFlags &= (~CONTEXT_DEBUG_REGISTERS) | CONTEXT_i386; + } + if ((Context->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) + { + /* + * FIXME: Implement this case + * + * I think this should only be filled for FPU exceptions, otherwise I + * would not know where to get it from as it can be the current state + * of the FPU or already saved in the thread's FPU save area. + * -blight + */ + Context->ContextFlags &= (~CONTEXT_FLOATING_POINT) | CONTEXT_i386; + } +#if 0 + if ((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS) + { + /* + * FIXME: Investigate this + * + * This is the XMM state (first 512 bytes of FXSAVE_FORMAT/FX_SAVE_AREA) + * This should only be filled in case of a SIMD exception I think, so + * this is not the right place (like for FPU the state could already be + * saved in the thread's FX_SAVE_AREA or still be in the CPU) + * -blight + */ + Context->ContextFlags &= ~CONTEXT_EXTENDED_REGISTERS; + } +#endif +} + VOID KeDumpStackFrames(PULONG Frame) { diff --git a/reactos/ntoskrnl/ke/i386/tskswitch.S b/reactos/ntoskrnl/ke/i386/tskswitch.S index 9e3bf2b1eac..4084b18e163 100644 --- a/reactos/ntoskrnl/ke/i386/tskswitch.S +++ b/reactos/ntoskrnl/ke/i386/tskswitch.S @@ -206,11 +206,6 @@ SaveTrapFrameForKDB_Return: call @KeReleaseDispatcherDatabaseLockFromDpcLevel@0 - cmpl $0, _PiNrThreadsAwaitingReaping - je 5f - call _PiWakeupReaperThread@0 -5: - /* * Restore the saved register and exit */ diff --git a/reactos/ntoskrnl/ke/kthread.c b/reactos/ntoskrnl/ke/kthread.c index cd017145283..f8a05ad5dec 100644 --- a/reactos/ntoskrnl/ke/kthread.c +++ b/reactos/ntoskrnl/ke/kthread.c @@ -15,8 +15,476 @@ #include #define THREAD_ALERT_INCREMENT 2 + +extern EX_WORK_QUEUE ExWorkerQueue[MaximumWorkQueue]; + +/* + * PURPOSE: List of threads associated with each priority level + */ +LIST_ENTRY PriorityListHead[MAXIMUM_PRIORITY]; +static ULONG PriorityListMask = 0; +ULONG IdleProcessorMask = 0; +extern BOOLEAN DoneInitYet; + /* FUNCTIONS *****************************************************************/ +STATIC +VOID +KiRequestReschedule(CCHAR Processor) +{ + PKPCR Pcr; + + Pcr = (PKPCR)(KPCR_BASE + Processor * PAGE_SIZE); + Pcr->Prcb->QuantumEnd = TRUE; + KiIpiSendRequest(1 << Processor, IPI_REQUEST_DPC); +} + +STATIC +VOID +KiInsertIntoThreadList(KPRIORITY Priority, + PKTHREAD Thread) +{ + ASSERT(THREAD_STATE_READY == Thread->State); + ASSERT(Thread->Priority == Priority); + + if (Priority >= MAXIMUM_PRIORITY || Priority < LOW_PRIORITY) { + + DPRINT1("Invalid thread priority (%d)\n", Priority); + KEBUGCHECK(0); + } + + InsertTailList(&PriorityListHead[Priority], &Thread->QueueListEntry); + PriorityListMask |= (1 << Priority); +} + +STATIC +VOID +KiRemoveFromThreadList(PKTHREAD Thread) +{ + ASSERT(THREAD_STATE_READY == Thread->State); + RemoveEntryList(&Thread->QueueListEntry); + if (IsListEmpty(&PriorityListHead[(ULONG)Thread->Priority])) { + + PriorityListMask &= ~(1 << Thread->Priority); + } +} + +STATIC +PKTHREAD +KiScanThreadList(KPRIORITY Priority, + KAFFINITY Affinity) +{ + PLIST_ENTRY current_entry; + PKTHREAD current; + ULONG Mask; + + Mask = (1 << Priority); + + if (PriorityListMask & Mask) { + + current_entry = PriorityListHead[Priority].Flink; + + while (current_entry != &PriorityListHead[Priority]) { + + current = CONTAINING_RECORD(current_entry, KTHREAD, QueueListEntry); + + if (current->State != THREAD_STATE_READY) { + + DPRINT1("%d/%d\n", ¤t, current->State); + } + + ASSERT(current->State == THREAD_STATE_READY); + + if (current->Affinity & Affinity) { + + KiRemoveFromThreadList(current); + return(current); + } + + current_entry = current_entry->Flink; + } + } + + return(NULL); +} + +VOID +STDCALL +KiDispatchThreadNoLock(ULONG NewThreadStatus) +{ + KPRIORITY CurrentPriority; + PKTHREAD Candidate; + ULONG Affinity; + PKTHREAD CurrentThread = KeGetCurrentThread(); + + DPRINT("KiDispatchThreadNoLock() %d/%d/%d/%d\n", KeGetCurrentProcessorNumber(), + CurrentThread, NewThreadStatus, CurrentThread->State); + + CurrentThread->State = (UCHAR)NewThreadStatus; + + if (NewThreadStatus == THREAD_STATE_READY) { + + KiInsertIntoThreadList(CurrentThread->Priority, + CurrentThread); + } + + Affinity = 1 << KeGetCurrentProcessorNumber(); + + for (CurrentPriority = HIGH_PRIORITY; CurrentPriority >= LOW_PRIORITY; CurrentPriority--) { + + Candidate = KiScanThreadList(CurrentPriority, Affinity); + + if (Candidate == CurrentThread) { + + Candidate->State = THREAD_STATE_RUNNING; + KeReleaseDispatcherDatabaseLockFromDpcLevel(); + return; + } + + if (Candidate != NULL) { + + PKTHREAD OldThread; + PKTHREAD IdleThread; + + DPRINT("Scheduling %x(%d)\n",Candidate, CurrentPriority); + + Candidate->State = THREAD_STATE_RUNNING; + + OldThread = CurrentThread; + CurrentThread = Candidate; + IdleThread = KeGetCurrentPrcb()->IdleThread; + + if (OldThread == IdleThread) { + + IdleProcessorMask &= ~Affinity; + + } else if (CurrentThread == IdleThread) { + + IdleProcessorMask |= Affinity; + } + + MmUpdatePageDir(PsGetCurrentProcess(),((PETHREAD)CurrentThread)->ThreadsProcess, sizeof(EPROCESS)); + + /* Special note for Filip: This will release the Dispatcher DB Lock ;-) -- Alex */ + KiArchContextSwitch(CurrentThread, OldThread); + return; + } + } + + DPRINT1("CRITICAL: No threads are ready (CPU%d)\n", KeGetCurrentProcessorNumber()); + KEBUGCHECK(0); +} + +VOID +STDCALL +KiBlockThread(PNTSTATUS Status, + UCHAR Alertable, + ULONG WaitMode, + UCHAR WaitReason) +{ + PKTHREAD Thread = KeGetCurrentThread(); + PKWAIT_BLOCK WaitBlock; + + if (Thread->ApcState.KernelApcPending) { + + DPRINT("Dispatching Thread as ready (APC!)\n"); + + /* Remove Waits */ + WaitBlock = Thread->WaitBlockList; + while (WaitBlock) { + RemoveEntryList (&WaitBlock->WaitListEntry); + WaitBlock = WaitBlock->NextWaitBlock; + } + Thread->WaitBlockList = NULL; + + /* Dispatch it and return status */ + KiDispatchThreadNoLock (THREAD_STATE_READY); + if (Status != NULL) *Status = STATUS_KERNEL_APC; + + } else { + + /* Set the Thread Data as Requested */ + DPRINT("Dispatching Thread as blocked\n"); + Thread->Alertable = Alertable; + Thread->WaitMode = (UCHAR)WaitMode; + Thread->WaitReason = WaitReason; + + /* Dispatch it and return status */ + KiDispatchThreadNoLock(THREAD_STATE_BLOCKED); + if (Status != NULL) *Status = Thread->WaitStatus; + } + + DPRINT("Releasing Dispatcher Lock\n"); + KfLowerIrql(Thread->WaitIrql); +} + +VOID +STDCALL +KiDispatchThread(ULONG NewThreadStatus) +{ + KIRQL OldIrql; + + if (!DoneInitYet || KeGetCurrentPrcb()->IdleThread == NULL) { + return; + } + + OldIrql = KeAcquireDispatcherDatabaseLock(); + KiDispatchThreadNoLock(NewThreadStatus); + KeLowerIrql(OldIrql); +} + +VOID +STDCALL +KiUnblockThread(PKTHREAD Thread, + PNTSTATUS WaitStatus, + KPRIORITY Increment) +{ + if (THREAD_STATE_TERMINATED_1 == Thread->State || + THREAD_STATE_TERMINATED_2 == Thread->State) { + + DPRINT("Can't unblock thread %d because it's terminating\n", + Thread->Cid.UniqueThread); + + } else if (THREAD_STATE_READY == Thread->State || + THREAD_STATE_RUNNING == Thread->State) { + + DPRINT("Can't unblock thread %d because it's ready or running\n", + Thread->Cid.UniqueThread); + + } else { + + ULONG Processor; + KAFFINITY Affinity; + + /* FIXME: This propably isn't the right way to do it... */ + /* No it's not... i'll fix it later-- Alex */ + if (Thread->Priority < LOW_REALTIME_PRIORITY && + Thread->BasePriority < LOW_REALTIME_PRIORITY - 2) { + + if (!Thread->PriorityDecrement && !Thread->DisableBoost) { + + Thread->Priority = Thread->BasePriority + Increment; + Thread->PriorityDecrement = Increment; + } + + } else { + + Thread->Quantum = Thread->ApcState.Process->ThreadQuantum; + } + + if (WaitStatus != NULL) { + + Thread->WaitStatus = *WaitStatus; + } + + Thread->State = THREAD_STATE_READY; + KiInsertIntoThreadList(Thread->Priority, Thread); + Processor = KeGetCurrentProcessorNumber(); + Affinity = Thread->Affinity; + + if (!(IdleProcessorMask & (1 << Processor) & Affinity) && + (IdleProcessorMask & ~(1 << Processor) & Affinity)) { + + ULONG i; + + for (i = 0; i < KeNumberProcessors - 1; i++) { + + Processor++; + + if (Processor >= KeNumberProcessors) { + + Processor = 0; + } + + if (IdleProcessorMask & (1 << Processor) & Affinity) { +#if 0 + /* FIXME: + * Reschedule the threads on an other processor + */ + KeReleaseDispatcherDatabaseLockFromDpcLevel(); + KiRequestReschedule(Processor); + KeAcquireDispatcherDatabaseLockAtDpcLevel(); +#endif + break; + } + } + } + } +} + +VOID +STDCALL +KiSuspendThreadKernelRoutine(PKAPC Apc, + PKNORMAL_ROUTINE* NormalRoutine, + PVOID* NormalContext, + PVOID* SystemArgument1, + PVOID* SystemArguemnt2) +{ +} + +VOID +STDCALL +KiSuspendThreadNormalRoutine(PVOID NormalContext, + PVOID SystemArgument1, + PVOID SystemArgument2) +{ + PKTHREAD CurrentThread = KeGetCurrentThread(); + + /* Non-alertable kernel-mode suspended wait */ + DPRINT1("Waiting...\n"); + KeWaitForSingleObject(&CurrentThread->SuspendSemaphore, + Suspended, + KernelMode, + FALSE, + NULL); + DPRINT1("Done Waiting\n"); +} + +VOID +STDCALL +KeRundownThread(VOID) +{ + KIRQL OldIrql; + PKTHREAD Thread = KeGetCurrentThread(); + PLIST_ENTRY CurrentEntry; + PKMUTANT Mutant; + + DPRINT("KeRundownThread: %x\n", Thread); + + /* Lock the Dispatcher Database */ + OldIrql = KeAcquireDispatcherDatabaseLock(); + + CurrentEntry = Thread->MutantListHead.Flink; + while (CurrentEntry != &Thread->MutantListHead) { + + /* Get the Mutant */ + Mutant = CONTAINING_RECORD(CurrentEntry, KMUTANT, MutantListEntry); + ASSERT(Mutant->ApcDisable); + + /* Uncondtionally abandon it */ + DPRINT("Abandonning the Mutant\n"); + Mutant->Header.SignalState = 1; + Mutant->Abandoned = TRUE; + Mutant->OwnerThread = NULL; + RemoveEntryList(&Mutant->MutantListEntry); + + /* Check if the Wait List isn't empty */ + DPRINT("Checking whether to wake the Mutant\n"); + if (!IsListEmpty(&Mutant->Header.WaitListHead)) { + + /* Wake the Mutant */ + DPRINT("Waking the Mutant\n"); + KiWaitTest(&Mutant->Header, MUTANT_INCREMENT); + } + } + + /* Release the Lock */ + KeReleaseDispatcherDatabaseLock(OldIrql); +} + +ULONG +STDCALL +KeResumeThread(PKTHREAD Thread) +{ + ULONG PreviousCount; + KIRQL OldIrql; + + DPRINT1("KeResumeThread (Thread %p called). %x, %x\n", Thread, Thread->SuspendCount, Thread->FreezeCount); + + /* Lock the Dispatcher */ + OldIrql = KeAcquireDispatcherDatabaseLock(); + + /* Save the Old Count */ + PreviousCount = Thread->SuspendCount; + + /* Check if it existed */ + if (PreviousCount) { + + Thread->SuspendCount--; + + /* Decrease the current Suspend Count and Check Freeze Count */ + if ((!Thread->SuspendCount) && (!Thread->FreezeCount)) { + + /* Signal the Suspend Semaphore */ + Thread->SuspendSemaphore.Header.SignalState++; + KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT); + } + } + + /* Release Lock and return the Old State */ + KeReleaseDispatcherDatabaseLock(OldIrql); + return PreviousCount; +} + +BOOLEAN +STDCALL +KiInsertQueueApc(PKAPC Apc, + KPRIORITY PriorityBoost); + +NTSTATUS +STDCALL +KeSuspendThread(PKTHREAD Thread) +{ + ULONG PreviousCount; + KIRQL OldIrql; + + DPRINT1("KeSuspendThread (Thread %p called). %x, %x\n", Thread, Thread->SuspendCount, Thread->FreezeCount); + + /* Lock the Dispatcher */ + OldIrql = KeAcquireDispatcherDatabaseLock(); + + /* Save the Old Count */ + PreviousCount = Thread->SuspendCount; + + /* Increment it */ + Thread->SuspendCount++; + + /* Check if we should suspend it */ + if (!PreviousCount && !Thread->FreezeCount) { + + /* Insert the APC */ + if (!KiInsertQueueApc(&Thread->SuspendApc, IO_NO_INCREMENT)) { + + /* Unsignal the Semaphore, the APC already got inserted */ + Thread->SuspendSemaphore.Header.SignalState--; + } + } + + /* Release Lock and return the Old State */ + KeReleaseDispatcherDatabaseLock(OldIrql); + return PreviousCount; +} + +ULONG +STDCALL +KeForceResumeThread(IN PKTHREAD Thread) +{ + KIRQL OldIrql; + ULONG PreviousCount; + + /* Lock the Dispatcher Database and the APC Queue */ + OldIrql = KeAcquireDispatcherDatabaseLock(); + + /* Save the old Suspend Count */ + PreviousCount = Thread->SuspendCount + Thread->FreezeCount; + + /* If the thread is suspended, wake it up!!! */ + if (PreviousCount) { + + /* Unwait it completely */ + Thread->SuspendCount = 0; + Thread->FreezeCount = 0; + + /* Signal and satisfy */ + Thread->SuspendSemaphore.Header.SignalState++; + KiWaitTest(&Thread->SuspendSemaphore.Header, IO_NO_INCREMENT); + } + + /* Release Lock and return the Old State */ + KeReleaseDispatcherDatabaseLock(OldIrql); + return PreviousCount; +} + ULONG STDCALL KeAlertResumeThread(IN PKTHREAD Thread) @@ -319,9 +787,9 @@ KeInitializeThread(PKPROCESS Process, KeInitializeApc(&Thread->SuspendApc, Thread, OriginalApcEnvironment, - PiSuspendThreadKernelRoutine, - PiSuspendThreadRundownRoutine, - PiSuspendThreadNormalRoutine, + KiSuspendThreadKernelRoutine, + NULL, + KiSuspendThreadNormalRoutine, KernelMode, NULL); @@ -462,7 +930,7 @@ KeRevertToUserAffinityThread(VOID) /* We need to dispatch a new thread */ CurrentThread->WaitIrql = OldIrql; - PsDispatchThreadNoLock(THREAD_STATE_READY); + KiDispatchThreadNoLock(THREAD_STATE_READY); KeLowerIrql(OldIrql); } } @@ -525,11 +993,195 @@ KeSetSystemAffinityThread(IN KAFFINITY Affinity) /* We need to dispatch a new thread */ CurrentThread->WaitIrql = OldIrql; - PsDispatchThreadNoLock(THREAD_STATE_READY); + KiDispatchThreadNoLock(THREAD_STATE_READY); KeLowerIrql(OldIrql); } } +/* + * @implemented + */ +LONG STDCALL +KeSetBasePriorityThread (PKTHREAD Thread, + LONG Increment) +/* + * Sets thread's base priority relative to the process' base priority + * Should only be passed in THREAD_PRIORITY_ constants in pstypes.h + */ +{ + KPRIORITY Priority; + if (Increment < -2) + { + Increment = -2; + } + else if (Increment > 2) + { + Increment = 2; + } + Priority = ((PETHREAD)Thread)->ThreadsProcess->Pcb.BasePriority + Increment; + if (Priority < LOW_PRIORITY) + { + Priority = LOW_PRIORITY; + } + else if (Priority >= MAXIMUM_PRIORITY) + { + Thread->BasePriority = HIGH_PRIORITY; + } + KeSetPriorityThread(Thread, Priority); + return 1; +} + +/* + * @implemented + */ +KPRIORITY +STDCALL +KeSetPriorityThread(PKTHREAD Thread, + KPRIORITY Priority) +{ + KPRIORITY OldPriority; + KIRQL OldIrql; + PKTHREAD CurrentThread; + ULONG Mask; + int i; + PKPCR Pcr; + + if (Priority < LOW_PRIORITY || Priority >= MAXIMUM_PRIORITY) { + + KEBUGCHECK(0); + } + + OldIrql = KeAcquireDispatcherDatabaseLock(); + + OldPriority = Thread->Priority; + + if (OldPriority != Priority) { + + CurrentThread = KeGetCurrentThread(); + + if (Thread->State == THREAD_STATE_READY) { + + KiRemoveFromThreadList(Thread); + Thread->BasePriority = Thread->Priority = (CHAR)Priority; + KiInsertIntoThreadList(Priority, Thread); + + if (CurrentThread->Priority < Priority) { + + KiDispatchThreadNoLock(THREAD_STATE_READY); + KeLowerIrql(OldIrql); + return (OldPriority); + } + + } else if (Thread->State == THREAD_STATE_RUNNING) { + + Thread->BasePriority = Thread->Priority = (CHAR)Priority; + + if (Priority < OldPriority) { + + /* Check for threads with a higher priority */ + Mask = ~((1 << (Priority + 1)) - 1); + if (PriorityListMask & Mask) { + + if (Thread == CurrentThread) { + + KiDispatchThreadNoLock(THREAD_STATE_READY); + KeLowerIrql(OldIrql); + return (OldPriority); + + } else { + + for (i = 0; i < KeNumberProcessors; i++) { + + Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE); + + if (Pcr->Prcb->CurrentThread == Thread) { + + KeReleaseDispatcherDatabaseLockFromDpcLevel(); + KiRequestReschedule(i); + KeLowerIrql(OldIrql); + return (OldPriority); + } + } + } + } + } + } else { + + Thread->BasePriority = Thread->Priority = (CHAR)Priority; + } + } + + KeReleaseDispatcherDatabaseLock(OldIrql); + return(OldPriority); +} + +/* + * @implemented + * + * Sets thread's affinity + */ +NTSTATUS +STDCALL +KeSetAffinityThread(PKTHREAD Thread, + KAFFINITY Affinity) +{ + KIRQL OldIrql; + ULONG i; + PKPCR Pcr; + KAFFINITY ProcessorMask; + + DPRINT("KeSetAffinityThread(Thread %x, Affinity %x)\n", Thread, Affinity); + + ASSERT(Affinity & ((1 << KeNumberProcessors) - 1)); + + OldIrql = KeAcquireDispatcherDatabaseLock(); + + Thread->UserAffinity = Affinity; + + if (Thread->SystemAffinityActive == FALSE) { + + Thread->Affinity = Affinity; + + if (Thread->State == THREAD_STATE_RUNNING) { + + ProcessorMask = 1 << KeGetCurrentKPCR()->ProcessorNumber; + if (Thread == KeGetCurrentThread()) { + + if (!(Affinity & ProcessorMask)) { + + KiDispatchThreadNoLock(THREAD_STATE_READY); + KeLowerIrql(OldIrql); + return STATUS_SUCCESS; + } + + } else { + + for (i = 0; i < KeNumberProcessors; i++) { + + Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE); + if (Pcr->Prcb->CurrentThread == Thread) { + + if (!(Affinity & ProcessorMask)) { + + KeReleaseDispatcherDatabaseLockFromDpcLevel(); + KiRequestReschedule(i); + KeLowerIrql(OldIrql); + return STATUS_SUCCESS; + } + + break; + } + } + + ASSERT (i < KeNumberProcessors); + } + } + } + + KeReleaseDispatcherDatabaseLock(OldIrql); + return STATUS_SUCCESS; +} + /* * @implemented */ @@ -538,8 +1190,45 @@ VOID STDCALL KeTerminateThread(IN KPRIORITY Increment) { - /* Call our own internal routine */ - PsTerminateCurrentThread(0); + KIRQL OldIrql; + PKTHREAD Thread = KeGetCurrentThread(); + + /* Lock the Dispatcher Database and the APC Queue */ + DPRINT1("Terminating\n"); + OldIrql = KeAcquireDispatcherDatabaseLock(); + + /* Insert into the Reaper List */ + InsertTailList(&PspReaperListHead, &((PETHREAD)Thread)->TerminationPortList); + + /* Check if it's active */ + if (PspReaping == FALSE) { + + /* Activate it. We use the internal function for speed, and use the Hyper Critical Queue */ + PspReaping = TRUE; + DPRINT1("Terminating\n"); + KiInsertQueue(&ExWorkerQueue[HyperCriticalWorkQueue].WorkerQueue, + &PspReaperWorkItem.List, + FALSE); + } + + /* Handle Kernel Queues */ + if (Thread->Queue) { + + DPRINT1("Waking Queue\n"); + RemoveEntryList(&Thread->QueueListEntry); + KiWakeQueue(Thread->Queue); + } + + /* Signal the thread */ + Thread->DispatcherHeader.SignalState = TRUE; + if (IsListEmpty(&Thread->DispatcherHeader.WaitListHead) != TRUE) { + + /* Satisfy waits */ + KiWaitTest((PVOID)Thread, Increment); + } + + /* Find a new Thread */ + KiDispatchThreadNoLock(THREAD_STATE_TERMINATED_1); } /* diff --git a/reactos/ntoskrnl/ke/main.c b/reactos/ntoskrnl/ke/main.c index b25d272522e..0efcd836158 100644 --- a/reactos/ntoskrnl/ke/main.c +++ b/reactos/ntoskrnl/ke/main.c @@ -104,7 +104,8 @@ KiSystemStartup(BOOLEAN BootProcessor) MiFreeInitMemory(); /* Never returns */ - PsTerminateSystemThread(STATUS_SUCCESS); + PspExitThread(STATUS_SUCCESS); + } else { /* Do application processor initialization */ diff --git a/reactos/ntoskrnl/ke/process.c b/reactos/ntoskrnl/ke/process.c index c5237917529..49b1aca222d 100644 --- a/reactos/ntoskrnl/ke/process.c +++ b/reactos/ntoskrnl/ke/process.c @@ -53,6 +53,35 @@ UpdatePageDirs(PKTHREAD Thread, PKPROCESS Process) MmUpdatePageDir((PEPROCESS)Process, (PVOID)Thread, sizeof(ETHREAD)); } +ULONG +STDCALL +KeSetProcess(PKPROCESS Process, + KPRIORITY Increment) +{ + KIRQL OldIrql; + ULONG OldState; + + /* Lock Dispatcher */ + OldIrql = KeAcquireDispatcherDatabaseLock(); + + /* Get Old State */ + OldState = Process->DispatcherHeader.SignalState; + + /* Signal the Process */ + Process->DispatcherHeader.SignalState = TRUE; + if ((OldState == 0) && IsListEmpty(&Process->DispatcherHeader.WaitListHead) != TRUE) { + + /* Satisfy waits */ + KiWaitTest((PVOID)Process, Increment); + } + + /* Release Dispatcher Database */ + KeReleaseDispatcherDatabaseLock(OldIrql); + + /* Return the previous State */ + return OldState; +} + /* * @implemented */ diff --git a/reactos/ntoskrnl/ke/queue.c b/reactos/ntoskrnl/ke/queue.c index abfddd90aa4..5f2983d71b5 100644 --- a/reactos/ntoskrnl/ke/queue.c +++ b/reactos/ntoskrnl/ke/queue.c @@ -287,7 +287,7 @@ KeRemoveQueue(IN PKQUEUE Queue, /* Block the Thread */ DPRINT("Blocking the Thread: %x %x!\n", KeGetCurrentThread(), Thread); - PsBlockThread(&Status, + KiBlockThread(&Status, FALSE, WaitMode, WrQueue); @@ -473,7 +473,7 @@ KiInsertQueue(IN PKQUEUE Queue, /* Reschedule the Thread */ DPRINT("Unblocking the Thread\n"); - PsUnblockThread((PETHREAD)Thread, (PNTSTATUS)&Entry, 0); + KiUnblockThread(Thread, (PNTSTATUS)&Entry, 0); } else { diff --git a/reactos/ntoskrnl/ke/wait.c b/reactos/ntoskrnl/ke/wait.c index 9e639db94cd..7ee692025c6 100644 --- a/reactos/ntoskrnl/ke/wait.c +++ b/reactos/ntoskrnl/ke/wait.c @@ -139,7 +139,7 @@ KeDelayExecutionThread(KPROCESSOR_MODE WaitMode, /* Block the Thread */ DPRINT("Blocking the Thread: %d, %d, %x\n", Alertable, WaitMode, KeGetCurrentThread()); - PsBlockThread(&Status, + KiBlockThread(&Status, Alertable, WaitMode, DelayExecution); @@ -326,7 +326,7 @@ KeWaitForSingleObject(PVOID Object, /* Block the Thread */ DPRINT("Blocking the Thread: %d, %d, %d, %x\n", Alertable, WaitMode, WaitReason, KeGetCurrentThread()); - PsBlockThread(&Status, + KiBlockThread(&Status, Alertable, WaitMode, (UCHAR)WaitReason); @@ -575,7 +575,7 @@ KeWaitForMultipleObjects(ULONG Count, /* Block the Thread */ DPRINT("Blocking the Thread: %d, %d, %d, %x\n", Alertable, WaitMode, WaitReason, KeGetCurrentThread()); - PsBlockThread(&Status, + KiBlockThread(&Status, Alertable, WaitMode, (UCHAR)WaitReason); @@ -756,7 +756,7 @@ KiAbortWaitThread(PKTHREAD Thread, /* Reschedule the Thread */ DPRINT("Unblocking the Thread\n"); - PsUnblockThread((PETHREAD)Thread, &WaitStatus, 0); + KiUnblockThread(Thread, &WaitStatus, 0); } BOOLEAN @@ -884,7 +884,7 @@ KeReleaseDispatcherDatabaseLock(KIRQL OldIrql) if (!KeIsExecutingDpc() && OldIrql < DISPATCH_LEVEL && KeGetCurrentThread() != NULL && KeGetCurrentThread() == KeGetCurrentPrcb()->IdleThread) { - PsDispatchThreadNoLock(THREAD_STATE_READY); + KiDispatchThreadNoLock(THREAD_STATE_READY); KeLowerIrql(OldIrql); } else { diff --git a/reactos/ntoskrnl/ob/handle.c b/reactos/ntoskrnl/ob/handle.c index b8dd343d35d..a8acfd2d80e 100644 --- a/reactos/ntoskrnl/ob/handle.c +++ b/reactos/ntoskrnl/ob/handle.c @@ -42,6 +42,12 @@ /* FUNCTIONS ***************************************************************/ +VOID +STDCALL +ObKillProcess(PEPROCESS Process) +{ + ObDeleteHandleTable(Process); +} VOID ObpDecrementHandleCount(PVOID ObjectBody) diff --git a/reactos/ntoskrnl/ps/cid.c b/reactos/ntoskrnl/ps/cid.c index f311cd30c87..73787b574a7 100644 --- a/reactos/ntoskrnl/ps/cid.c +++ b/reactos/ntoskrnl/ps/cid.c @@ -128,6 +128,69 @@ PsLookupCidHandle(HANDLE CidHandle, POBJECT_TYPE ObjectType, PVOID *Object) return NULL; } +/* + * @implemented + */ +NTSTATUS STDCALL +PsLookupProcessThreadByCid(IN PCLIENT_ID Cid, + OUT PEPROCESS *Process OPTIONAL, + OUT PETHREAD *Thread) +{ + PHANDLE_TABLE_ENTRY CidEntry; + PETHREAD FoundThread; + + PAGED_CODE(); + + ASSERT(Thread); + ASSERT(Cid); + + CidEntry = PsLookupCidHandle(Cid->UniqueThread, PsThreadType, (PVOID*)&FoundThread); + if(CidEntry != NULL) + { + ObReferenceObject(FoundThread); + + PsUnlockCidHandle(CidEntry); + + if(Process != NULL) + { + *Process = FoundThread->ThreadsProcess; + } + *Thread = FoundThread; + return STATUS_SUCCESS; + } + + return STATUS_INVALID_PARAMETER; +} + + +/* + * @implemented + */ +NTSTATUS STDCALL +PsLookupThreadByThreadId(IN HANDLE ThreadId, + OUT PETHREAD *Thread) +{ + PHANDLE_TABLE_ENTRY CidEntry; + PETHREAD FoundThread; + + PAGED_CODE(); + + ASSERT(Thread); + + CidEntry = PsLookupCidHandle(ThreadId, PsThreadType, (PVOID*)&FoundThread); + if(CidEntry != NULL) + { + ObReferenceObject(FoundThread); + + PsUnlockCidHandle(CidEntry); + + *Thread = FoundThread; + return STATUS_SUCCESS; + } + + return STATUS_INVALID_PARAMETER; +} + VOID PsUnlockCidHandle(PHANDLE_TABLE_ENTRY CidEntry) { diff --git a/reactos/ntoskrnl/ps/create.c b/reactos/ntoskrnl/ps/create.c index 7082ca55724..4758532b623 100644 --- a/reactos/ntoskrnl/ps/create.c +++ b/reactos/ntoskrnl/ps/create.c @@ -32,369 +32,17 @@ static ULONG PiThreadNotifyRoutineCount = 0; static PCREATE_THREAD_NOTIFY_ROUTINE PiThreadNotifyRoutine[MAX_THREAD_NOTIFY_ROUTINE_COUNT]; +ULONG +STDCALL +KeSuspendThread(PKTHREAD Thread); /* FUNCTIONS ***************************************************************/ -/* - * @implemented - */ -NTSTATUS STDCALL -PsAssignImpersonationToken(PETHREAD Thread, - HANDLE TokenHandle) -{ - PACCESS_TOKEN Token; - SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; - NTSTATUS Status; - - if (TokenHandle != NULL) - { - Status = ObReferenceObjectByHandle(TokenHandle, - TOKEN_IMPERSONATE, - SepTokenObjectType, - KeGetPreviousMode(), - (PVOID*)&Token, - NULL); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - ImpersonationLevel = SeTokenImpersonationLevel(Token); - } - else - { - Token = NULL; - ImpersonationLevel = 0; - } - - PsImpersonateClient(Thread, - Token, - FALSE, - FALSE, - ImpersonationLevel); - if (Token != NULL) - { - ObDereferenceObject(Token); - } - - return(STATUS_SUCCESS); -} - - -/* - * @implemented - */ -VOID STDCALL -PsRevertToSelf (VOID) -{ - PsRevertThreadToSelf(PsGetCurrentThread()); -} - -/* - * @implemented - */ -VOID -STDCALL -PsRevertThreadToSelf( - IN PETHREAD Thread - ) -{ - if (Thread->ActiveImpersonationInfo == TRUE) - { - ObDereferenceObject (Thread->ImpersonationInfo->Token); - Thread->ActiveImpersonationInfo = FALSE; - } -} - -/* - * @implemented - */ -VOID STDCALL -PsImpersonateClient (IN PETHREAD Thread, - IN PACCESS_TOKEN Token, - IN BOOLEAN CopyOnOpen, - IN BOOLEAN EffectiveOnly, - IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel) -{ - if (Token == NULL) - { - if (Thread->ActiveImpersonationInfo == TRUE) - { - Thread->ActiveImpersonationInfo = FALSE; - if (Thread->ImpersonationInfo->Token != NULL) - { - ObDereferenceObject (Thread->ImpersonationInfo->Token); - } - } - return; - } - - if (Thread->ImpersonationInfo == NULL) - { - Thread->ImpersonationInfo = ExAllocatePool (NonPagedPool, - sizeof(PS_IMPERSONATION_INFORMATION)); - } - - Thread->ImpersonationInfo->ImpersonationLevel = ImpersonationLevel; - Thread->ImpersonationInfo->CopyOnOpen = CopyOnOpen; - Thread->ImpersonationInfo->EffectiveOnly = EffectiveOnly; - Thread->ImpersonationInfo->Token = Token; - ObReferenceObjectByPointer (Token, - 0, - SepTokenObjectType, - KernelMode); - Thread->ActiveImpersonationInfo = TRUE; -} - - -PACCESS_TOKEN -PsReferenceEffectiveToken(PETHREAD Thread, - PTOKEN_TYPE TokenType, - PBOOLEAN EffectiveOnly, - PSECURITY_IMPERSONATION_LEVEL Level) -{ - PEPROCESS Process; - PACCESS_TOKEN Token; - - if (Thread->ActiveImpersonationInfo == FALSE) - { - Process = Thread->ThreadsProcess; - *TokenType = TokenPrimary; - *EffectiveOnly = FALSE; - Token = Process->Token; - } - else - { - Token = Thread->ImpersonationInfo->Token; - *TokenType = TokenImpersonation; - *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly; - *Level = Thread->ImpersonationInfo->ImpersonationLevel; - } - return(Token); -} - - -NTSTATUS STDCALL -NtImpersonateThread(IN HANDLE ThreadHandle, - IN HANDLE ThreadToImpersonateHandle, - IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService) -{ - SECURITY_QUALITY_OF_SERVICE SafeServiceQoS; - SECURITY_CLIENT_CONTEXT ClientContext; - PETHREAD Thread; - PETHREAD ThreadToImpersonate; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status = STATUS_SUCCESS; - - PAGED_CODE(); - - PreviousMode = ExGetPreviousMode(); - - if(PreviousMode != KernelMode) - { - _SEH_TRY - { - ProbeForRead(SecurityQualityOfService, - sizeof(SECURITY_QUALITY_OF_SERVICE), - sizeof(ULONG)); - SafeServiceQoS = *SecurityQualityOfService; - SecurityQualityOfService = &SafeServiceQoS; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if(!NT_SUCCESS(Status)) - { - return Status; - } - } - - Status = ObReferenceObjectByHandle(ThreadHandle, - THREAD_IMPERSONATE, - PsThreadType, - PreviousMode, - (PVOID*)&Thread, - NULL); - if(NT_SUCCESS(Status)) - { - Status = ObReferenceObjectByHandle(ThreadToImpersonateHandle, - THREAD_DIRECT_IMPERSONATION, - PsThreadType, - PreviousMode, - (PVOID*)&ThreadToImpersonate, - NULL); - if(NT_SUCCESS(Status)) - { - Status = SeCreateClientSecurity(ThreadToImpersonate, - SecurityQualityOfService, - 0, - &ClientContext); - if(NT_SUCCESS(Status)) - { - SeImpersonateClient(&ClientContext, - Thread); - if(ClientContext.ClientToken != NULL) - { - ObDereferenceObject (ClientContext.ClientToken); - } - } - - ObDereferenceObject(ThreadToImpersonate); - } - ObDereferenceObject(Thread); - } - - return Status; -} - -/* - * @implemented - */ -PACCESS_TOKEN STDCALL -PsReferenceImpersonationToken(IN PETHREAD Thread, - OUT PBOOLEAN CopyOnOpen, - OUT PBOOLEAN EffectiveOnly, - OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel) -{ - if (Thread->ActiveImpersonationInfo == FALSE) - { - return NULL; - } - - *ImpersonationLevel = Thread->ImpersonationInfo->ImpersonationLevel; - *CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen; - *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly; - ObReferenceObjectByPointer (Thread->ImpersonationInfo->Token, - TOKEN_ALL_ACCESS, - SepTokenObjectType, - KernelMode); - - return Thread->ImpersonationInfo->Token; -} - -#ifdef PsDereferencePrimaryToken -#undef PsDereferenceImpersonationToken -#endif -/* - * @implemented - */ -VOID -STDCALL -PsDereferenceImpersonationToken( - IN PACCESS_TOKEN ImpersonationToken - ) -{ - if (ImpersonationToken) { - ObDereferenceObject(ImpersonationToken); - } -} - -#ifdef PsDereferencePrimaryToken -#undef PsDereferencePrimaryToken -#endif -/* - * @implemented - */ -VOID -STDCALL -PsDereferencePrimaryToken( - IN PACCESS_TOKEN PrimaryToken - ) -{ - ObDereferenceObject(PrimaryToken); -} - -/* - * @implemented - */ -BOOLEAN -STDCALL -PsDisableImpersonation( - IN PETHREAD Thread, - IN PSE_IMPERSONATION_STATE ImpersonationState - ) -{ - if (Thread->ActiveImpersonationInfo == FALSE) - { - ImpersonationState->Token = NULL; - ImpersonationState->CopyOnOpen = FALSE; - ImpersonationState->EffectiveOnly = FALSE; - ImpersonationState->Level = 0; - return TRUE; - } - -/* FIXME */ -/* ExfAcquirePushLockExclusive(&Thread->ThreadLock); */ - - Thread->ActiveImpersonationInfo = FALSE; - ImpersonationState->Token = Thread->ImpersonationInfo->Token; - ImpersonationState->CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen; - ImpersonationState->EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly; - ImpersonationState->Level = Thread->ImpersonationInfo->ImpersonationLevel; - -/* FIXME */ -/* ExfReleasePushLock(&Thread->ThreadLock); */ - - return TRUE; -} - -/* - * @implemented - */ -VOID -STDCALL -PsRestoreImpersonation( - IN PETHREAD Thread, - IN PSE_IMPERSONATION_STATE ImpersonationState - ) -{ - PsImpersonateClient(Thread, ImpersonationState->Token, - ImpersonationState->CopyOnOpen, - ImpersonationState->EffectiveOnly, - ImpersonationState->Level); - ObfDereferenceObject(ImpersonationState->Token); -} - VOID PiBeforeBeginThread(CONTEXT c) { KeLowerIrql(PASSIVE_LEVEL); } - -VOID STDCALL -PiDeleteThread(PVOID ObjectBody) -{ - PETHREAD Thread; - PEPROCESS Process; - - Thread = (PETHREAD)ObjectBody; - - DPRINT("PiDeleteThread(ObjectBody %x)\n",ObjectBody); - - Process = Thread->ThreadsProcess; - Thread->ThreadsProcess = NULL; - - if(Thread->Cid.UniqueThread != NULL) - { - PsDeleteCidHandle(Thread->Cid.UniqueThread, PsThreadType); - } - - if(Thread->Tcb.Win32Thread != NULL) - { - /* Free the W32THREAD structure if present */ - ExFreePool (Thread->Tcb.Win32Thread); - } - - KeReleaseThread(ETHREAD_TO_KTHREAD(Thread)); - - ObDereferenceObject(Process); - - DPRINT("PiDeleteThread() finished\n"); -} - - NTSTATUS PsInitializeThread(PEPROCESS Process, PETHREAD* ThreadPtr, @@ -446,6 +94,7 @@ PsInitializeThread(PEPROCESS Process, KeInitializeThread(&Process->Pcb, &Thread->Tcb, First); InitializeListHead(&Thread->TerminationPortList); + InitializeListHead(&Thread->ActiveTimerListHead); KeInitializeSpinLock(&Thread->ActiveTimerListLock); InitializeListHead(&Thread->IrpList); Thread->DeadThread = FALSE; @@ -784,7 +433,7 @@ NtCreateThread(OUT PHANDLE ThreadHandle, */ if (CreateSuspended) { - PsSuspendThread(Thread, NULL); + KeSuspendThread(&Thread->Tcb); } /* @@ -806,7 +455,7 @@ NtCreateThread(OUT PHANDLE ThreadHandle, Thread->Tcb.Alerted[KernelMode] = TRUE; oldIrql = KeAcquireDispatcherDatabaseLock (); - PsUnblockThread(Thread, NULL, 0); + KiUnblockThread(&Thread->Tcb, NULL, 0); KeReleaseDispatcherDatabaseLock(oldIrql); Status = ObInsertObject((PVOID)Thread, @@ -883,6 +532,9 @@ PsCreateSystemThread(PHANDLE ThreadHandle, return(Status); } + /* Set the thread as a system thread */ + Thread->SystemThread = TRUE; + Status = PsCreateCidHandle(Thread, PsThreadType, &Thread->Cid.UniqueThread); @@ -906,7 +558,7 @@ PsCreateSystemThread(PHANDLE ThreadHandle, } oldIrql = KeAcquireDispatcherDatabaseLock (); - PsUnblockThread(Thread, NULL, 0); + KiUnblockThread(&Thread->Tcb, NULL, 0); KeReleaseDispatcherDatabaseLock(oldIrql); Status = ObInsertObject((PVOID)Thread, diff --git a/reactos/ntoskrnl/ps/debug.c b/reactos/ntoskrnl/ps/debug.c index a028cdb9a32..a9015623aa8 100644 --- a/reactos/ntoskrnl/ps/debug.c +++ b/reactos/ntoskrnl/ps/debug.c @@ -1,5 +1,4 @@ -/* $Id$ - * +/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ps/debug.c @@ -9,13 +8,6 @@ * Phillip Susi */ -/* - * NOTE: - * - * All of the routines that manipulate the thread queue synchronize on - * a single spinlock - * - */ /* INCLUDES ****************************************************************/ @@ -23,378 +15,256 @@ #define NDEBUG #include +/* GLOBALS *****************************************************************/ + +/* Thread "Set/Get Context" Context Structure */ +typedef struct _GET_SET_CTX_CONTEXT { + KAPC Apc; + KEVENT Event; + CONTEXT Context; +} GET_SET_CTX_CONTEXT, *PGET_SET_CTX_CONTEXT; + + /* FUNCTIONS ***************************************************************/ -VOID -KeContextToTrapFrame(PCONTEXT Context, - PKTRAP_FRAME TrapFrame) -{ - if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) - { - TrapFrame->Esp = Context->Esp; - TrapFrame->Ss = Context->SegSs; - TrapFrame->Cs = Context->SegCs; - TrapFrame->Eip = Context->Eip; - TrapFrame->Eflags = Context->EFlags; - TrapFrame->Ebp = Context->Ebp; - } - if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) - { - TrapFrame->Eax = Context->Eax; - TrapFrame->Ebx = Context->Ebx; - TrapFrame->Ecx = Context->Ecx; - TrapFrame->Edx = Context->Edx; - TrapFrame->Esi = Context->Esi; - TrapFrame->Edi = Context->Edi; - } - if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) - { - TrapFrame->Ds = Context->SegDs; - TrapFrame->Es = Context->SegEs; - TrapFrame->Fs = Context->SegFs; - TrapFrame->Gs = Context->SegGs; - } - if ((Context->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) - { - /* - * Not handled - * - * This should be handled separately I think. - * - blight - */ - } - if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS) - { - /* - * Not handled - */ - } -} - -VOID -KeTrapFrameToContext(PKTRAP_FRAME TrapFrame, - PCONTEXT Context) -{ - if ((Context->ContextFlags & CONTEXT_CONTROL) == CONTEXT_CONTROL) - { - Context->SegSs = TrapFrame->Ss; - Context->Esp = TrapFrame->Esp; - Context->SegCs = TrapFrame->Cs; - Context->Eip = TrapFrame->Eip; - Context->EFlags = TrapFrame->Eflags; - Context->Ebp = TrapFrame->Ebp; - } - if ((Context->ContextFlags & CONTEXT_INTEGER) == CONTEXT_INTEGER) - { - Context->Eax = TrapFrame->Eax; - Context->Ebx = TrapFrame->Ebx; - Context->Ecx = TrapFrame->Ecx; - /* - * NOTE: In the trap frame which is built on entry to a system - * call TrapFrame->Edx will actually hold the address of the - * previous TrapFrame. I don't believe leaking this information - * has security implications. Also EDX holds the address of the - * arguments to the system call in progress so it isn't of much - * interest to the debugger. - */ - Context->Edx = TrapFrame->Edx; - Context->Esi = TrapFrame->Esi; - Context->Edi = TrapFrame->Edi; - } - if ((Context->ContextFlags & CONTEXT_SEGMENTS) == CONTEXT_SEGMENTS) - { - Context->SegDs = TrapFrame->Ds; - Context->SegEs = TrapFrame->Es; - Context->SegFs = TrapFrame->Fs; - Context->SegGs = TrapFrame->Gs; - } - if ((Context->ContextFlags & CONTEXT_DEBUG_REGISTERS) == CONTEXT_DEBUG_REGISTERS) - { - /* - * FIXME: Implement this case - */ - Context->ContextFlags &= (~CONTEXT_DEBUG_REGISTERS) | CONTEXT_i386; - } - if ((Context->ContextFlags & CONTEXT_FLOATING_POINT) == CONTEXT_FLOATING_POINT) - { - /* - * FIXME: Implement this case - * - * I think this should only be filled for FPU exceptions, otherwise I - * would not know where to get it from as it can be the current state - * of the FPU or already saved in the thread's FPU save area. - * -blight - */ - Context->ContextFlags &= (~CONTEXT_FLOATING_POINT) | CONTEXT_i386; - } -#if 0 - if ((Context->ContextFlags & CONTEXT_EXTENDED_REGISTERS) == CONTEXT_EXTENDED_REGISTERS) - { - /* - * FIXME: Investigate this - * - * This is the XMM state (first 512 bytes of FXSAVE_FORMAT/FX_SAVE_AREA) - * This should only be filled in case of a SIMD exception I think, so - * this is not the right place (like for FPU the state could already be - * saved in the thread's FX_SAVE_AREA or still be in the CPU) - * -blight - */ - Context->ContextFlags &= ~CONTEXT_EXTENDED_REGISTERS; - } -#endif -} - -VOID STDCALL -KeGetSetContextRundownRoutine(PKAPC Apc) -{ - PKEVENT Event; - PNTSTATUS Status; - - Event = (PKEVENT)Apc->SystemArgument1; - Status = (PNTSTATUS)Apc->SystemArgument2; - (*Status) = STATUS_THREAD_IS_TERMINATING; - KeSetEvent(Event, IO_NO_INCREMENT, FALSE); -} - -VOID STDCALL -KeGetContextKernelRoutine(PKAPC Apc, - PKNORMAL_ROUTINE* NormalRoutine, - PVOID* NormalContext, - PVOID* SystemArgument1, - PVOID* SystemArgument2) /* * FUNCTION: This routine is called by an APC sent by NtGetContextThread to * copy the context of a thread into a buffer. */ +VOID +STDCALL +PspGetOrSetContextKernelRoutine(PKAPC Apc, + PKNORMAL_ROUTINE* NormalRoutine, + PVOID* NormalContext, + PVOID* SystemArgument1, + PVOID* SystemArgument2) { - PKEVENT Event; - PCONTEXT Context; - PNTSTATUS Status; + PGET_SET_CTX_CONTEXT GetSetContext; + PKEVENT Event; + PCONTEXT Context; - Context = (PCONTEXT)(*NormalContext); - Event = (PKEVENT)(*SystemArgument1); - Status = (PNTSTATUS)(*SystemArgument2); + /* Get the Context Structure */ + GetSetContext = CONTAINING_RECORD(Apc, GET_SET_CTX_CONTEXT, Apc); + Context = &GetSetContext->Context; + Event = &GetSetContext->Event; + + /* Check if it's a set or get */ + if (SystemArgument1) { + + /* Get the Context */ + KeTrapFrameToContext(KeGetCurrentThread()->TrapFrame, Context); + + } else { + + /* Set the Context */ + KeContextToTrapFrame(Context, KeGetCurrentThread()->TrapFrame); + } - KeTrapFrameToContext(KeGetCurrentThread()->TrapFrame, Context); - - *Status = STATUS_SUCCESS; - KeSetEvent(Event, IO_NO_INCREMENT, FALSE); + /* Notify the Native API that we are done */ + KeSetEvent(Event, IO_NO_INCREMENT, FALSE); } -NTSTATUS STDCALL +NTSTATUS +STDCALL NtGetContextThread(IN HANDLE ThreadHandle, - OUT PCONTEXT ThreadContext) + OUT PCONTEXT ThreadContext) { - PETHREAD Thread; - CONTEXT Context; - KAPC Apc; - KEVENT Event; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status = STATUS_SUCCESS; + PETHREAD Thread; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + GET_SET_CTX_CONTEXT GetSetContext; + NTSTATUS Status = STATUS_SUCCESS; - PAGED_CODE(); - - PreviousMode = ExGetPreviousMode(); + PAGED_CODE(); - if(PreviousMode != KernelMode) - { - _SEH_TRY - { - ProbeForWrite(ThreadContext, - sizeof(CONTEXT), - sizeof(ULONG)); - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if(!NT_SUCCESS(Status)) - { - return Status; - } - } - - Status = ObReferenceObjectByHandle(ThreadHandle, - THREAD_GET_CONTEXT, - PsThreadType, - PreviousMode, - (PVOID*)&Thread, - NULL); - if(NT_SUCCESS(Status)) - { - if(Thread == PsGetCurrentThread()) - { - /* - * I don't know if trying to get your own context makes much - * sense but we can handle it more efficently. - */ - - KeTrapFrameToContext(Thread->Tcb.TrapFrame, &Context); - } - else - { - KeInitializeEvent(&Event, - NotificationEvent, - FALSE); - - KeInitializeApc(&Apc, - &Thread->Tcb, - OriginalApcEnvironment, - KeGetContextKernelRoutine, - KeGetSetContextRundownRoutine, - NULL, - KernelMode, - (PVOID)&Context); - if (!KeInsertQueueApc(&Apc, - (PVOID)&Event, - (PVOID)&Status, - IO_NO_INCREMENT)) - { - Status = STATUS_THREAD_IS_TERMINATING; - } - else - { - Status = KeWaitForSingleObject(&Event, - 0, - KernelMode, - FALSE, - NULL); - } - } - ObDereferenceObject(Thread); + /* Check the buffer to be OK */ + if(PreviousMode != KernelMode) { - if(NT_SUCCESS(Status)) - { - _SEH_TRY - { - *ThreadContext = Context; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; + _SEH_TRY { + + ProbeForWrite(ThreadContext, + sizeof(CONTEXT), + sizeof(ULONG)); + } _SEH_HANDLE { + + Status = _SEH_GetExceptionCode(); + + } _SEH_END; + + if(!NT_SUCCESS(Status)) return Status; } - } - return Status; + /* Get the Thread Object */ + Status = ObReferenceObjectByHandle(ThreadHandle, + THREAD_GET_CONTEXT, + PsThreadType, + PreviousMode, + (PVOID*)&Thread, + NULL); + + /* Check success */ + if(NT_SUCCESS(Status)) { + + /* Check if we're running in the same thread */ + if(Thread == PsGetCurrentThread()) { + + /* + * I don't know if trying to get your own context makes much + * sense but we can handle it more efficently. + */ + KeTrapFrameToContext(Thread->Tcb.TrapFrame, &GetSetContext.Context); + + } else { + + /* Use an APC... Initialize the Event */ + KeInitializeEvent(&GetSetContext.Event, + NotificationEvent, + FALSE); + + /* Initialize the APC */ + KeInitializeApc(&GetSetContext.Apc, + &Thread->Tcb, + OriginalApcEnvironment, + PspGetOrSetContextKernelRoutine, + NULL, + NULL, + KernelMode, + NULL); + + /* Queue it as a Get APC */ + if (!KeInsertQueueApc(&GetSetContext.Apc, + (PVOID)1, + NULL, + IO_NO_INCREMENT)) { + + Status = STATUS_THREAD_IS_TERMINATING; + + } else { + + /* Wait for the APC to complete */ + Status = KeWaitForSingleObject(&GetSetContext.Event, + 0, + KernelMode, + FALSE, + NULL); + } + } + + /* Dereference the thread */ + ObDereferenceObject(Thread); + + /* Check for success and return the Context */ + if(NT_SUCCESS(Status)) { + + _SEH_TRY { + + *ThreadContext = GetSetContext.Context; + + } _SEH_HANDLE { + + Status = _SEH_GetExceptionCode(); + + } _SEH_END; + } + } + + /* Return status */ + return Status; } -VOID STDCALL -KeSetContextKernelRoutine(PKAPC Apc, - PKNORMAL_ROUTINE* NormalRoutine, - PVOID* NormalContext, - PVOID* SystemArgument1, - PVOID* SystemArgument2) -/* - * FUNCTION: This routine is called by an APC sent by NtSetContextThread to - * set the context of a thread from a buffer. - */ -{ - PKEVENT Event; - PCONTEXT Context; - PNTSTATUS Status; - - Context = (PCONTEXT)(*NormalContext); - Event = (PKEVENT)(*SystemArgument1); - Status = (PNTSTATUS)(*SystemArgument2); - - KeContextToTrapFrame(Context, KeGetCurrentThread()->TrapFrame); - - *Status = STATUS_SUCCESS; - KeSetEvent(Event, IO_NO_INCREMENT, FALSE); -} - -NTSTATUS STDCALL +NTSTATUS +STDCALL NtSetContextThread(IN HANDLE ThreadHandle, - IN PCONTEXT ThreadContext) + IN PCONTEXT ThreadContext) { - PETHREAD Thread; - KAPC Apc; - KEVENT Event; - CONTEXT Context; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status = STATUS_SUCCESS; + PETHREAD Thread; + GET_SET_CTX_CONTEXT GetSetContext; + KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); + NTSTATUS Status = STATUS_SUCCESS; - PAGED_CODE(); + PAGED_CODE(); - PreviousMode = ExGetPreviousMode(); - - if(PreviousMode != KernelMode) - { - _SEH_TRY - { - ProbeForRead(ThreadContext, - sizeof(CONTEXT), - sizeof(ULONG)); - Context = *ThreadContext; - ThreadContext = &Context; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; + /* Check the buffer to be OK */ + if(PreviousMode != KernelMode) { - if(!NT_SUCCESS(Status)) - { - return Status; + _SEH_TRY { + + ProbeForRead(ThreadContext, + sizeof(CONTEXT), + sizeof(ULONG)); + + GetSetContext.Context = *ThreadContext; + ThreadContext = &GetSetContext.Context; + + } _SEH_HANDLE { + + Status = _SEH_GetExceptionCode(); + } _SEH_END; + + if(!NT_SUCCESS(Status)) return Status; } - } - Status = ObReferenceObjectByHandle(ThreadHandle, - THREAD_SET_CONTEXT, - PsThreadType, - PreviousMode, - (PVOID*)&Thread, - NULL); - if(NT_SUCCESS(Status)) - { - if (Thread == PsGetCurrentThread()) - { - /* - * I don't know if trying to set your own context makes much - * sense but we can handle it more efficently. - */ - - KeContextToTrapFrame(&Context, Thread->Tcb.TrapFrame); + /* Get the Thread Object */ + Status = ObReferenceObjectByHandle(ThreadHandle, + THREAD_SET_CONTEXT, + PsThreadType, + PreviousMode, + (PVOID*)&Thread, + NULL); + + /* Check success */ + if(NT_SUCCESS(Status)) { + + /* Check if we're running in the same thread */ + if(Thread == PsGetCurrentThread()) { + + /* + * I don't know if trying to get your own context makes much + * sense but we can handle it more efficently. + */ + KeContextToTrapFrame(&GetSetContext.Context, Thread->Tcb.TrapFrame); + + } else { + + /* Use an APC... Initialize the Event */ + KeInitializeEvent(&GetSetContext.Event, + NotificationEvent, + FALSE); + + /* Initialize the APC */ + KeInitializeApc(&GetSetContext.Apc, + &Thread->Tcb, + OriginalApcEnvironment, + PspGetOrSetContextKernelRoutine, + NULL, + NULL, + KernelMode, + NULL); + + /* Queue it as a Get APC */ + if (!KeInsertQueueApc(&GetSetContext.Apc, + NULL, + NULL, + IO_NO_INCREMENT)) { + + Status = STATUS_THREAD_IS_TERMINATING; + + } else { + + /* Wait for the APC to complete */ + Status = KeWaitForSingleObject(&GetSetContext.Event, + 0, + KernelMode, + FALSE, + NULL); + } + } + + /* Dereference the thread */ + ObDereferenceObject(Thread); } - else - { - KeInitializeEvent(&Event, - NotificationEvent, - FALSE); - - KeInitializeApc(&Apc, - &Thread->Tcb, - OriginalApcEnvironment, - KeSetContextKernelRoutine, - KeGetSetContextRundownRoutine, - NULL, - KernelMode, - (PVOID)&Context); - if (!KeInsertQueueApc(&Apc, - (PVOID)&Event, - (PVOID)&Status, - IO_NO_INCREMENT)) - { - Status = STATUS_THREAD_IS_TERMINATING; - } - else - { - Status = KeWaitForSingleObject(&Event, - 0, - KernelMode, - FALSE, - NULL); - } - } - ObDereferenceObject(Thread); - } - return Status; + /* Return status */ + return Status; } /* EOF */ diff --git a/reactos/ntoskrnl/ps/idle.c b/reactos/ntoskrnl/ps/idle.c index 430d4acd001..b8d2598c9b1 100644 --- a/reactos/ntoskrnl/ps/idle.c +++ b/reactos/ntoskrnl/ps/idle.c @@ -79,7 +79,7 @@ PsInitIdleThread(VOID) } oldIrql = KeAcquireDispatcherDatabaseLock (); - PsUnblockThread(IdleThread, NULL, 0); + KiUnblockThread(&IdleThread->Tcb, NULL, 0); KeReleaseDispatcherDatabaseLock(oldIrql); KeGetCurrentPrcb()->IdleThread = &IdleThread->Tcb; diff --git a/reactos/ntoskrnl/ps/kill.c b/reactos/ntoskrnl/ps/kill.c index ea167976184..5572bec1fbe 100644 --- a/reactos/ntoskrnl/ps/kill.c +++ b/reactos/ntoskrnl/ps/kill.c @@ -1,11 +1,11 @@ -/* $Id$ - * +/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS kernel * FILE: ntoskrnl/ps/kill.c - * PURPOSE: Terminating a thread + * PURPOSE: Thread Termination and Reaping * - * PROGRAMMERS: David Welch (welch@cwcom.net) + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) + * David Welch (welch@cwcom.net) */ /* INCLUDES *****************************************************************/ @@ -15,486 +15,531 @@ #include /* GLOBALS *******************************************************************/ - -VOID PsTerminateCurrentThread(NTSTATUS ExitStatus); -NTSTATUS STDCALL NtCallTerminatePorts(PETHREAD Thread); - + #define TAG_TERMINATE_APC TAG('T', 'A', 'P', 'C') -LIST_ENTRY ThreadsToReapHead; - -#define TERMINATE_PROC 0x1 -#define TERMINATE_APC 0x2 +LIST_ENTRY PspReaperListHead; +WORK_QUEUE_ITEM PspReaperWorkItem; +BOOLEAN PspReaping = FALSE; +extern LIST_ENTRY PsActiveProcessHead; +extern FAST_MUTEX PspActiveProcessMutex; /* FUNCTIONS *****************************************************************/ +STDCALL VOID -PsInitializeThreadReaper(VOID) +PspReapRoutine(PVOID Context) { - InitializeListHead(&ThreadsToReapHead); + KIRQL OldIrql; + PETHREAD Thread; + PLIST_ENTRY ListEntry; + + /* Acquire lock */ + DPRINT("Evil reaper running!!\n"); + OldIrql = KeAcquireDispatcherDatabaseLock(); + + /* Loop the reap list */ + while((ListEntry = RemoveHeadList(&PspReaperListHead)) != &PspReaperListHead) { + + /* Get the Current Thread to Terminate */ + Thread = CONTAINING_RECORD(ListEntry, ETHREAD, TerminationPortList); + + /* Unlock the Dispatcher */ + KeReleaseDispatcherDatabaseLock(OldIrql); + + /* Remove the Reference */ + ObDereferenceObject(Thread); + + /* Reacquire the Lock */ + OldIrql = KeAcquireDispatcherDatabaseLock(); + } + + PspReaping = FALSE; + KeReleaseDispatcherDatabaseLock(OldIrql); } VOID -PsReapThreads(VOID) +STDCALL +PspTerminateProcessThreads(PEPROCESS Process, + NTSTATUS ExitStatus) { - KIRQL oldlvl; - PETHREAD Thread; - PLIST_ENTRY ListEntry; - - oldlvl = KeAcquireDispatcherDatabaseLock(); - while((ListEntry = RemoveHeadList(&ThreadsToReapHead)) != &ThreadsToReapHead) - { - PiNrThreadsAwaitingReaping--; - KeReleaseDispatcherDatabaseLock(oldlvl); - Thread = CONTAINING_RECORD(ListEntry, ETHREAD, TerminationPortList); - - ObDereferenceObject(Thread); - oldlvl = KeAcquireDispatcherDatabaseLock(); - } - KeReleaseDispatcherDatabaseLock(oldlvl); -} - -VOID -PsQueueThreadReap(PETHREAD Thread) -{ - InsertTailList(&ThreadsToReapHead, &Thread->TerminationPortList); - PiNrThreadsAwaitingReaping++; -} - -VOID -PiTerminateProcessThreads(PEPROCESS Process, - NTSTATUS ExitStatus) -{ - KIRQL oldlvl; - PLIST_ENTRY current_entry; - PETHREAD current, CurrentThread = PsGetCurrentThread(); + PLIST_ENTRY CurrentEntry; + PETHREAD Thread, CurrentThread = PsGetCurrentThread(); - DPRINT("PiTerminateProcessThreads(Process %x, ExitStatus %x)\n", - Process, ExitStatus); - - oldlvl = KeAcquireDispatcherDatabaseLock(); - - current_entry = Process->ThreadListHead.Flink; - while (current_entry != &Process->ThreadListHead) - { - current = CONTAINING_RECORD(current_entry, ETHREAD, - ThreadListEntry); - if (current != CurrentThread && current->HasTerminated == 0) - { - DPRINT("Terminating %x, current thread: %x, " - "thread's process: %x\n", current, PsGetCurrentThread(), - current->ThreadsProcess); - KeReleaseDispatcherDatabaseLock(oldlvl); - PsTerminateOtherThread(current, ExitStatus); - oldlvl = KeAcquireDispatcherDatabaseLock(); - current_entry = Process->ThreadListHead.Flink; - } - else - { - current_entry = current_entry->Flink; - } - } - KeReleaseDispatcherDatabaseLock(oldlvl); - DPRINT("Finished PiTerminateProcessThreads()\n"); + CurrentEntry = Process->ThreadListHead.Flink; + while (CurrentEntry != &Process->ThreadListHead) { + + /* Get the Current Thread */ + Thread = CONTAINING_RECORD(CurrentEntry, ETHREAD, ThreadListEntry); + + /* Make sure it's not the one we're in */ + if (Thread != CurrentThread) { + + /* Make sure it didn't already terminate */ + if (!Thread->HasTerminated) { + + Thread->HasTerminated = TRUE; + /* Terminate it by APC */ + PspTerminateThreadByPointer(Thread, ExitStatus); + + /* Unsuspend it */ + KeForceResumeThread(&Thread->Tcb); + } + } + + /* Move to the Next Thread */ + CurrentEntry = CurrentEntry->Flink; + } } -VOID -PsTerminateCurrentThread(NTSTATUS ExitStatus) +VOID +STDCALL +PspDeleteProcess(PVOID ObjectBody) +{ + PEPROCESS Process = (PEPROCESS)ObjectBody; + + DPRINT("PiDeleteProcess(ObjectBody %x)\n",Process); + + /* Delete the CID Handle */ + if(Process->UniqueProcessId != NULL) { + + PsDeleteCidHandle(Process->UniqueProcessId, PsProcessType); + } + + /* KDB hook */ + KDB_DELETEPROCESS_HOOK(Process); + + /* Dereference the Token and release Memory Information */ + ObDereferenceObject(Process->Token); + MmReleaseMmInfo(Process); + + /* Delete the W32PROCESS structure if there's one associated */ + if(Process->Win32Process != NULL) ExFreePool(Process->Win32Process); +} + +VOID +STDCALL +PspDeleteThread(PVOID ObjectBody) +{ + PETHREAD Thread = (PETHREAD)ObjectBody; + PEPROCESS Process = Thread->ThreadsProcess; + + DPRINT("PiDeleteThread(ObjectBody %x)\n",ObjectBody); + + /* Deassociate the Process */ + Thread->ThreadsProcess = NULL; + + /* Delete the CID Handle */ + if(Thread->Cid.UniqueThread != NULL) { + + PsDeleteCidHandle(Thread->Cid.UniqueThread, PsThreadType); + } + + /* Free the W32THREAD structure if present */ + if(Thread->Tcb.Win32Thread != NULL) ExFreePool (Thread->Tcb.Win32Thread); + + /* Release the Thread */ + KeReleaseThread(ETHREAD_TO_KTHREAD(Thread)); + + /* Dereference the Process */ + ObDereferenceObject(Process); +} + /* * FUNCTION: Terminates the current thread + * See "Windows Internals" - Chapter 13, Page 50-53 */ +VOID +STDCALL +PspExitThread(NTSTATUS ExitStatus) { - KIRQL oldIrql; - PETHREAD CurrentThread; - PLIST_ENTRY current_entry; - PKMUTANT Mutant; - BOOLEAN Last; - PEPROCESS CurrentProcess; - SIZE_T Length = PAGE_SIZE; - PVOID TebBlock; + PETHREAD CurrentThread; + BOOLEAN Last; + PEPROCESS CurrentProcess; + SIZE_T Length = PAGE_SIZE; + PVOID TebBlock; + PLIST_ENTRY CurrentEntry; + PTERMINATION_PORT TerminationPort; - DPRINT("PsTerminateCurrentThread(ExitStatus %x)\n", ExitStatus); + DPRINT("PsTerminateCurrentThread(ExitStatus %x)\n", ExitStatus); - CurrentThread = PsGetCurrentThread(); + /* Get the Current Thread and Process */ + CurrentThread = PsGetCurrentThread(); + CurrentThread->HasTerminated = TRUE; + CurrentProcess = CurrentThread->ThreadsProcess; - oldIrql = KeAcquireDispatcherDatabaseLock(); - if (CurrentThread->HasTerminated & TERMINATE_PROC) - { - KeReleaseDispatcherDatabaseLock(oldIrql); - return; - } - CurrentThread->HasTerminated |= TERMINATE_PROC; - KeReleaseDispatcherDatabaseLock(oldIrql); - - KeLowerIrql(PASSIVE_LEVEL); - - CurrentProcess = CurrentThread->ThreadsProcess; - - /* Can't terminate a thread if it attached another process */ - if (AttachedApcEnvironment == CurrentThread->Tcb.ApcStateIndex) - { + /* Can't terminate a thread if it attached another process */ + if (KeIsAttachedProcess()) { + KEBUGCHECKEX(INVALID_PROCESS_ATTACH_ATTEMPT, (ULONG) CurrentProcess, (ULONG) CurrentThread->Tcb.ApcState.Process, (ULONG) CurrentThread->Tcb.ApcStateIndex, (ULONG) CurrentThread); - } + } + + /* Lower to Passive Level */ + KeLowerIrql(PASSIVE_LEVEL); - KeCancelTimer(&CurrentThread->Tcb.Timer); + /* Run Thread Notify Routines before we desintegrate the thread */ + PspRunCreateThreadNotifyRoutines(CurrentThread, FALSE); - oldIrql = KeAcquireDispatcherDatabaseLock(); + /* Lock the Process before we modify its thread entries */ + PsLockProcess(CurrentProcess, FALSE); - DPRINT("terminating %x\n",CurrentThread); - - CurrentThread->ExitStatus = ExitStatus; - KeQuerySystemTime((PLARGE_INTEGER)&CurrentThread->ExitTime); - - /* If the ProcessoR Control Block's NpxThread points to the current thread - * unset it. - */ - InterlockedCompareExchangePointer(&KeGetCurrentPrcb()->NpxThread, - NULL, ETHREAD_TO_KTHREAD(CurrentThread)); - - KeReleaseDispatcherDatabaseLock(oldIrql); - - PsLockProcess(CurrentProcess, FALSE); - - /* Cancel I/O for the thread. */ - IoCancelThreadIo(CurrentThread); - - /* Remove the thread from the thread list of its process */ - RemoveEntryList(&CurrentThread->ThreadListEntry); - Last = IsListEmpty(&CurrentProcess->ThreadListHead); - PsUnlockProcess(CurrentProcess); - - /* Notify subsystems of the thread termination */ - PspRunCreateThreadNotifyRoutines(CurrentThread, FALSE); - PsTerminateWin32Thread(CurrentThread); - - /* Free the TEB */ - if(CurrentThread->Tcb.Teb) - { - DPRINT("Decommit teb at %p\n", CurrentThread->Tcb.Teb); - ExAcquireFastMutex(&CurrentProcess->TebLock); - TebBlock = MM_ROUND_DOWN(CurrentThread->Tcb.Teb, MM_VIRTMEM_GRANULARITY); - ZwFreeVirtualMemory(NtCurrentProcess(), - (PVOID *)&CurrentThread->Tcb.Teb, - &Length, - MEM_DECOMMIT); - DPRINT("teb %p, TebBlock %p\n", CurrentThread->Tcb.Teb, TebBlock); - if (TebBlock != CurrentProcess->TebBlock || - CurrentProcess->TebBlock == CurrentProcess->TebLastAllocated) - { - MmLockAddressSpace(&CurrentProcess->AddressSpace); - MmReleaseMemoryAreaIfDecommitted(CurrentProcess, &CurrentProcess->AddressSpace, TebBlock); - MmUnlockAddressSpace(&CurrentProcess->AddressSpace); - } - CurrentThread->Tcb.Teb = NULL; - ExReleaseFastMutex(&CurrentProcess->TebLock); - } - - /* abandon all owned mutants */ - current_entry = CurrentThread->Tcb.MutantListHead.Flink; - while (current_entry != &CurrentThread->Tcb.MutantListHead) - { - Mutant = CONTAINING_RECORD(current_entry, KMUTANT, - MutantListEntry); - KeReleaseMutant(Mutant, - MUTANT_INCREMENT, - TRUE, - FALSE); - current_entry = CurrentThread->Tcb.MutantListHead.Flink; - } - - oldIrql = KeAcquireDispatcherDatabaseLock(); - CurrentThread->Tcb.DispatcherHeader.SignalState = TRUE; - KiWaitTest(&CurrentThread->Tcb.DispatcherHeader, IO_NO_INCREMENT); - KeReleaseDispatcherDatabaseLock (oldIrql); - - /* The last thread shall close the door on exit */ - if(Last) - { - /* save the last thread exit status */ + /* Remove the thread from the thread list of its process */ + RemoveEntryList(&CurrentThread->ThreadListEntry); + Last = IsListEmpty(&CurrentProcess->ThreadListHead); + + /* Set the last Thread Exit Status */ CurrentProcess->LastThreadExitStatus = ExitStatus; - PspRunCreateProcessNotifyRoutines(CurrentProcess, FALSE); - PsTerminateWin32Process(CurrentProcess); + /* Unlock the Process */ + PsUnlockProcess(CurrentProcess); - PiTerminateProcess(CurrentProcess, ExitStatus); - } - - oldIrql = KeAcquireDispatcherDatabaseLock(); - -#ifdef _ENABLE_THRDEVTPAIR - ExpSwapThreadEventPair(CurrentThread, NULL); /* Release the associated eventpair object, if there was one */ -#endif /* _ENABLE_THRDEVTPAIR */ - - PsDispatchThreadNoLock(THREAD_STATE_TERMINATED_1); - DPRINT1("Unexpected return, CurrentThread %x PsGetCurrentThread() %x\n", CurrentThread, PsGetCurrentThread()); - KEBUGCHECK(0); -} - -VOID STDCALL -PiTerminateThreadRundownRoutine(PKAPC Apc) -{ - ExFreePool(Apc); -} - -VOID STDCALL -PiTerminateThreadKernelRoutine(PKAPC Apc, - PKNORMAL_ROUTINE* NormalRoutine, - PVOID* NormalContext, - PVOID* SystemArgument1, - PVOID* SystemArguemnt2) -{ - ExFreePool(Apc); -} - -VOID STDCALL -PiTerminateThreadNormalRoutine(PVOID NormalContext, - PVOID SystemArgument1, - PVOID SystemArgument2) -{ - PsTerminateCurrentThread((NTSTATUS)SystemArgument1); -} - -VOID -PsTerminateOtherThread(PETHREAD Thread, - NTSTATUS ExitStatus) -/* - * FUNCTION: Terminate a thread when calling from another thread's context - * NOTES: This function must be called with PiThreadLock held - */ -{ - PKAPC Apc; - KIRQL OldIrql; - - DPRINT("PsTerminateOtherThread(Thread %x, ExitStatus %x)\n", - Thread, ExitStatus); - - OldIrql = KeAcquireDispatcherDatabaseLock(); - if (Thread->HasTerminated & TERMINATE_APC) - { - KeReleaseDispatcherDatabaseLock (OldIrql); - return; - } - Thread->HasTerminated |= TERMINATE_APC; - KeReleaseDispatcherDatabaseLock (OldIrql); - Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_TERMINATE_APC); - KeInitializeApc(Apc, - &Thread->Tcb, - OriginalApcEnvironment, - PiTerminateThreadKernelRoutine, - PiTerminateThreadRundownRoutine, - PiTerminateThreadNormalRoutine, - KernelMode, - NULL); - KeInsertQueueApc(Apc, - (PVOID)ExitStatus, - NULL, - IO_NO_INCREMENT); - - OldIrql = KeAcquireDispatcherDatabaseLock(); - if (THREAD_STATE_BLOCKED == Thread->Tcb.State && UserMode == Thread->Tcb.WaitMode) - { - DPRINT("Unblocking thread\n"); - KiAbortWaitThread((PKTHREAD)Thread, STATUS_THREAD_IS_TERMINATING, IO_NO_INCREMENT); + /* Check if the process has a debug port */ + if (CurrentProcess->DebugPort) { + + /* Notify the Debug API. TODO */ + //Last ? DbgkExitProcess(ExitStatus) : DbgkExitThread(ExitStatus); } - KeReleaseDispatcherDatabaseLock(OldIrql); + + /* Process the Termination Ports */ + while ((CurrentEntry = RemoveHeadList(&CurrentThread->TerminationPortList)) != + &CurrentThread->TerminationPortList) { + + /* Get the Termination Port */ + TerminationPort = CONTAINING_RECORD(CurrentEntry, + TERMINATION_PORT, + Links); + + /* Send the LPC Message */ + LpcSendTerminationPort(TerminationPort->Port, CurrentThread->CreateTime); + + /* Free the Port */ + ExFreePool(TerminationPort); + } + + /* Rundown Win32 Structures */ + PsTerminateWin32Thread(CurrentThread); + if (Last) PsTerminateWin32Process(CurrentProcess); + + /* Cancel I/O for the thread. */ + IoCancelThreadIo(CurrentThread); + + /* Rundown Timers */ + ExTimerRundown(); + KeCancelTimer(&CurrentThread->Tcb.Timer); + + /* Rundown Registry Notifications. TODO (refers to NtChangeNotify, not Cm callbacks) */ + //CmNotifyRunDown(CurrentThread); + + /* Rundown Mutexes */ + KeRundownThread(); + + /* Free the TEB */ + if(CurrentThread->Tcb.Teb) { + + DPRINT("Decommit teb at %p\n", CurrentThread->Tcb.Teb); + ExAcquireFastMutex(&CurrentProcess->TebLock); + TebBlock = MM_ROUND_DOWN(CurrentThread->Tcb.Teb, MM_VIRTMEM_GRANULARITY); + + ZwFreeVirtualMemory(NtCurrentProcess(), + (PVOID *)&CurrentThread->Tcb.Teb, + &Length, + MEM_DECOMMIT); + + DPRINT("teb %p, TebBlock %p\n", CurrentThread->Tcb.Teb, TebBlock); + + if (TebBlock != CurrentProcess->TebBlock || + CurrentProcess->TebBlock == CurrentProcess->TebLastAllocated) { + + MmLockAddressSpace(&CurrentProcess->AddressSpace); + MmReleaseMemoryAreaIfDecommitted(CurrentProcess, &CurrentProcess->AddressSpace, TebBlock); + MmUnlockAddressSpace(&CurrentProcess->AddressSpace); + } + + CurrentThread->Tcb.Teb = NULL; + ExReleaseFastMutex(&CurrentProcess->TebLock); + } + + /* Set the Exit Status and Exit Time */ + CurrentThread->ExitStatus = ExitStatus; + KeQuerySystemTime((PLARGE_INTEGER)&CurrentThread->ExitTime); + + /* If the Processor Control Block's NpxThread points to the current thread + * unset it. + */ + InterlockedCompareExchangePointer(&KeGetCurrentPrcb()->NpxThread, + NULL, + (PKPROCESS)CurrentThread); + + /* The last Thread shuts down the Process */ + if (Last) PspExitProcess(CurrentProcess); + + /* Terminate the Thread from the Scheduler */ + KeTerminateThread(0); + DPRINT1("Unexpected return, CurrentThread %x PsGetCurrentThread() %x\n", CurrentThread, PsGetCurrentThread()); + KEBUGCHECK(0); } -NTSTATUS STDCALL -PiTerminateProcess(PEPROCESS Process, - NTSTATUS ExitStatus) +VOID +STDCALL +PsExitSpecialApc(PKAPC Apc, + PKNORMAL_ROUTINE* NormalRoutine, + PVOID* NormalContext, + PVOID* SystemArgument1, + PVOID* SystemArguemnt2) { - KIRQL OldIrql; - PEPROCESS CurrentProcess; + NTSTATUS ExitStatus = (NTSTATUS)Apc->NormalContext; + + /* Free the APC */ + ExFreePool(Apc); + + /* Terminate the Thread */ + PspExitThread(ExitStatus); +} - DPRINT("PiTerminateProcess(Process %x, ExitStatus %x) PC %d HC %d\n", - Process, ExitStatus, ObGetObjectPointerCount(Process), - ObGetObjectHandleCount(Process)); +VOID +STDCALL +PspExitNormalApc(PVOID NormalContext, + PVOID SystemArgument1, + PVOID SystemArgument2) +{ + /* Not fully supported yet... must work out some issues that + * I don't understand yet -- Alex + */ + DPRINT1("APC2\n"); + PspExitThread((NTSTATUS)NormalContext); +} + +/* + * See "Windows Internals" - Chapter 13, Page 49 + */ +VOID +STDCALL +PspTerminateThreadByPointer(PETHREAD Thread, + NTSTATUS ExitStatus) +{ + PKAPC Apc; + + DPRINT("PspTerminatedThreadByPointer(Thread %x, ExitStatus %x)\n", + Thread, ExitStatus); + + /* Check if we are already in the right context */ + if (PsGetCurrentThread() == Thread) { + + /* Directly terminate the thread */ + PspExitThread(ExitStatus); + } + + /* Allocate the APC */ + Apc = ExAllocatePoolWithTag(NonPagedPool, sizeof(KAPC), TAG_TERMINATE_APC); + + /* Initialize a Kernel Mode APC to Kill the Thread */ + KeInitializeApc(Apc, + &Thread->Tcb, + OriginalApcEnvironment, + PsExitSpecialApc, + NULL, + PspExitNormalApc, + KernelMode, + (PVOID)ExitStatus); + + /* Insert it into the APC Queue */ + KeInsertQueueApc(Apc, + Apc, + NULL, + 2); + + /* Forcefully resume the thread */ + KeForceResumeThread(&Thread->Tcb); +} - ObReferenceObject(Process); - if (Process->Pcb.State == PROCESS_STATE_TERMINATED) - { +NTSTATUS +STDCALL +PspExitProcess(PEPROCESS Process) +{ + DPRINT("PspExitProcess\n"); + + PspRunCreateProcessNotifyRoutines(Process, FALSE); + + /* Remove it from the Active List */ + ExAcquireFastMutex(&PspActiveProcessMutex); + RemoveEntryList(&Process->ProcessListEntry); + ExReleaseFastMutex(&PspActiveProcessMutex); + + ObKillProcess(Process); + KeSetProcess(&Process->Pcb, IO_NO_INCREMENT); + return(STATUS_SUCCESS); +} + +NTSTATUS +STDCALL +NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL, + IN NTSTATUS ExitStatus) +{ + NTSTATUS Status; + PEPROCESS Process; + + PAGED_CODE(); + + DPRINT("NtTerminateProcess(ProcessHandle %x, ExitStatus %x)\n", + ProcessHandle, ExitStatus); + + /* Get the Process Object */ + Status = ObReferenceObjectByHandle(ProcessHandle, + PROCESS_TERMINATE, + PsProcessType, + KeGetPreviousMode(), + (PVOID*)&Process, + NULL); + if (!NT_SUCCESS(Status)) { + + DPRINT1("Invalid handle to Process\n"); + return(Status); + } + + if(Process->ExitTime.QuadPart) { + + DPRINT1("Process has an exit time!\n"); + KeLeaveCriticalRegion(); + return STATUS_PROCESS_IS_TERMINATING; + } + + /* Terminate all the Process's Threads */ + PspTerminateProcessThreads(Process, ExitStatus); + + /* Save the Exit Time */ + KeQuerySystemTime(&Process->ExitTime); + + /* Only master thread remains... kill it off */ + if (PsGetCurrentThread()->ThreadsProcess == Process) { + + /* Unlock and dereference */ ObDereferenceObject(Process); - return(STATUS_SUCCESS); - } - - Process->Pcb.State = PROCESS_STATE_TERMINATED; - - CurrentProcess = PsGetCurrentProcess(); - if (Process != CurrentProcess) - { - KeAttachProcess(&Process->Pcb); - } - - ObDeleteHandleTable(Process); - if (Process != CurrentProcess) - { - KeDetachProcess(); - } - OldIrql = KeAcquireDispatcherDatabaseLock (); - Process->Pcb.DispatcherHeader.SignalState = TRUE; - KiWaitTest(&Process->Pcb.DispatcherHeader, IO_NO_INCREMENT); - KeReleaseDispatcherDatabaseLock (OldIrql); - ObDereferenceObject(Process); - return(STATUS_SUCCESS); + PspExitThread(ExitStatus); + return(STATUS_SUCCESS); + } + + /* If we took this path instead, then do the same as above */ + ObDereferenceObject(Process); + return(STATUS_SUCCESS); } -NTSTATUS STDCALL -NtTerminateProcess(IN HANDLE ProcessHandle OPTIONAL, - IN NTSTATUS ExitStatus) +NTSTATUS +STDCALL +NtTerminateThread(IN HANDLE ThreadHandle, + IN NTSTATUS ExitStatus) { - NTSTATUS Status; - PEPROCESS Process; + PETHREAD Thread; + NTSTATUS Status; - PAGED_CODE(); + PAGED_CODE(); + + /* Get the Thread Object */ + Status = ObReferenceObjectByHandle(ThreadHandle, + THREAD_TERMINATE, + PsThreadType, + KeGetPreviousMode(), + (PVOID*)&Thread, + NULL); + if (Status != STATUS_SUCCESS) { + + DPRINT1("Could not reference thread object\n"); + return(Status); + } - DPRINT("NtTerminateProcess(ProcessHandle %x, ExitStatus %x)\n", - ProcessHandle, ExitStatus); - - Status = ObReferenceObjectByHandle(ProcessHandle, - PROCESS_TERMINATE, - PsProcessType, - KeGetCurrentThread()->PreviousMode, - (PVOID*)&Process, - NULL); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - Process->ExitStatus = ExitStatus; - PiTerminateProcessThreads(Process, ExitStatus); - if (PsGetCurrentThread()->ThreadsProcess == Process) - { - ObDereferenceObject(Process); - PsTerminateCurrentThread(ExitStatus); - /* - * We should never get here! - */ - return(STATUS_SUCCESS); - } - ObDereferenceObject(Process); - return(STATUS_SUCCESS); + /* Make sure this is not a system thread */ + if (PsIsSystemThread(Thread)) { + + DPRINT1("Trying to Terminate a system thread!\n"); + return STATUS_INVALID_PARAMETER; + } + + /* Check to see if we're running in the same thread */ + if (Thread != PsGetCurrentThread()) { + + /* This isn't our thread, check if it's terminated already */ + if (!Thread->HasTerminated) { + + /* Terminate it */ + PspTerminateThreadByPointer(Thread, ExitStatus); + + /* Resume it */ + KeForceResumeThread(&Thread->Tcb); + } + + } else { + + /* Terminate him, he's ours */ + PspExitThread(ExitStatus); + } + + /* Dereference the Thread and return */ + ObDereferenceObject(Thread); + return(STATUS_SUCCESS); } - -NTSTATUS STDCALL -NtTerminateThread(IN HANDLE ThreadHandle, - IN NTSTATUS ExitStatus) -{ - PETHREAD Thread; - NTSTATUS Status; - - PAGED_CODE(); - - Status = ObReferenceObjectByHandle(ThreadHandle, - THREAD_TERMINATE, - PsThreadType, - KeGetCurrentThread()->PreviousMode, - (PVOID*)&Thread, - NULL); - if (Status != STATUS_SUCCESS) - { - return(Status); - } - - if (Thread == PsGetCurrentThread()) - { - /* dereference the thread object before we kill our thread */ - ObDereferenceObject(Thread); - PsTerminateCurrentThread(ExitStatus); - /* - * We should never get here! - */ - } - else - { - PsTerminateOtherThread(Thread, ExitStatus); - ObDereferenceObject(Thread); - } - return(STATUS_SUCCESS); -} - - /* * @implemented */ -NTSTATUS STDCALL +NTSTATUS +STDCALL PsTerminateSystemThread(NTSTATUS ExitStatus) -/* - * FUNCTION: Terminates the current thread - * ARGUMENTS: - * ExitStatus = Status to pass to the creater - * RETURNS: Doesn't - */ { - PsTerminateCurrentThread(ExitStatus); - return(STATUS_SUCCESS); + PETHREAD Thread = PsGetCurrentThread(); + + /* Make sure this is a system thread */ + if (!PsIsSystemThread(Thread)) { + + DPRINT1("Trying to Terminate a non-system thread!\n"); + return STATUS_INVALID_PARAMETER; + } + + /* Terminate it for real */ + PspExitThread(ExitStatus); + return(STATUS_SUCCESS); } -NTSTATUS STDCALL -NtCallTerminatePorts(PETHREAD Thread) -{ - KIRQL oldIrql; - PLIST_ENTRY current_entry; - PEPORT_TERMINATION_REQUEST current; - - PAGED_CODE(); - - KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql); - while ((current_entry = RemoveHeadList(&Thread->TerminationPortList)) != - &Thread->TerminationPortList); - { - current = CONTAINING_RECORD(current_entry, - EPORT_TERMINATION_REQUEST, - ThreadListEntry); - KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql); - LpcSendTerminationPort(current->Port, - Thread->CreateTime); - ExFreePool(current); - KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql); - } - KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql); - return(STATUS_SUCCESS); -} - -NTSTATUS STDCALL +NTSTATUS +STDCALL NtRegisterThreadTerminatePort(HANDLE PortHandle) { - NTSTATUS Status; - PEPORT_TERMINATION_REQUEST Request; - PEPORT TerminationPort; - KIRQL oldIrql; - PETHREAD Thread; + NTSTATUS Status; + PTERMINATION_PORT TerminationPort; + PVOID TerminationLpcPort; - PAGED_CODE(); + PAGED_CODE(); + + /* Get the Port */ + Status = ObReferenceObjectByHandle(PortHandle, + PORT_ALL_ACCESS, + LpcPortObjectType, + KeGetPreviousMode(), + &TerminationLpcPort, + NULL); + if (!NT_SUCCESS(Status)) { + + DPRINT1("Failed to reference Port\n"); + return(Status); + } - Status = ObReferenceObjectByHandle(PortHandle, - PORT_ALL_ACCESS, - LpcPortObjectType, - KeGetCurrentThread()->PreviousMode, - (PVOID*)&TerminationPort, - NULL); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - - Request = ExAllocatePool(NonPagedPool, sizeof(EPORT_TERMINATION_REQUEST)); - if(Request != NULL) - { - Request->Port = TerminationPort; - Thread = PsGetCurrentThread(); - KeAcquireSpinLock(&Thread->ActiveTimerListLock, &oldIrql); - InsertTailList(&Thread->TerminationPortList, &Request->ThreadListEntry); - KeReleaseSpinLock(&Thread->ActiveTimerListLock, oldIrql); + /* Allocate the Port and make sure it suceeded */ + if((TerminationPort = ExAllocatePoolWithTag(NonPagedPool, + sizeof(PTERMINATION_PORT), + TAG('P', 's', 'T', '=')))) { + + /* Associate the Port */ + TerminationPort->Port = TerminationLpcPort; + InsertTailList(&PsGetCurrentThread()->TerminationPortList, &TerminationPort->Links); - return(STATUS_SUCCESS); - } - else - { - ObDereferenceObject(TerminationPort); - return(STATUS_INSUFFICIENT_RESOURCES); - } + /* Return success */ + return(STATUS_SUCCESS); + + } else { + + /* Dereference and Fail */ + ObDereferenceObject(TerminationPort); + return(STATUS_INSUFFICIENT_RESOURCES); + } } diff --git a/reactos/ntoskrnl/ps/process.c b/reactos/ntoskrnl/ps/process.c index d7d0541144b..5e2823cb14e 100644 --- a/reactos/ntoskrnl/ps/process.c +++ b/reactos/ntoskrnl/ps/process.c @@ -34,56 +34,6 @@ static GENERIC_MAPPING PiProcessMapping = {STANDARD_RIGHTS_READ | PROCESS_QUERY_ STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE, PROCESS_ALL_ACCESS}; -static const INFORMATION_CLASS_INFO PsProcessInfoClass[] = -{ - ICI_SQ_SAME( sizeof(PROCESS_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* ProcessBasicInformation */ - ICI_SQ_SAME( sizeof(QUOTA_LIMITS), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessQuotaLimits */ - ICI_SQ_SAME( sizeof(IO_COUNTERS), sizeof(ULONG), ICIF_QUERY ), /* ProcessIoCounters */ - ICI_SQ_SAME( sizeof(VM_COUNTERS), sizeof(ULONG), ICIF_QUERY ), /* ProcessVmCounters */ - ICI_SQ_SAME( sizeof(KERNEL_USER_TIMES), sizeof(ULONG), ICIF_QUERY ), /* ProcessTimes */ - ICI_SQ_SAME( sizeof(KPRIORITY), sizeof(ULONG), ICIF_SET ), /* ProcessBasePriority */ - ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_SET ), /* ProcessRaisePriority */ - ICI_SQ_SAME( sizeof(HANDLE), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessDebugPort */ - ICI_SQ_SAME( sizeof(HANDLE), sizeof(ULONG), ICIF_SET ), /* ProcessExceptionPort */ - ICI_SQ_SAME( sizeof(PROCESS_ACCESS_TOKEN), sizeof(ULONG), ICIF_SET ), /* ProcessAccessToken */ - ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessLdtInformation */ - ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_SET ), /* ProcessLdtSize */ - ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessDefaultHardErrorMode */ - ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_SET ), /* ProcessIoPortHandlers */ - ICI_SQ_SAME( sizeof(POOLED_USAGE_AND_LIMITS), sizeof(ULONG), ICIF_QUERY ), /* ProcessPooledUsageAndLimits */ - ICI_SQ_SAME( sizeof(PROCESS_WS_WATCH_INFORMATION), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessWorkingSetWatch */ - ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_SET ), /* ProcessUserModeIOPL */ - ICI_SQ_SAME( sizeof(BOOLEAN), sizeof(ULONG), ICIF_SET ), /* ProcessEnableAlignmentFaultFixup */ - ICI_SQ_SAME( sizeof(PROCESS_PRIORITY_CLASS), sizeof(USHORT), ICIF_QUERY | ICIF_SET ), /* ProcessPriorityClass */ - ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY ), /* ProcessWx86Information */ - ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY ), /* ProcessHandleCount */ - ICI_SQ_SAME( sizeof(KAFFINITY), sizeof(ULONG), ICIF_SET ), /* ProcessAffinityMask */ - ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessPriorityBoost */ - - ICI_SQ(/*Q*/ sizeof(((PPROCESS_DEVICEMAP_INFORMATION)0x0)->Query), /* ProcessDeviceMap */ - /*S*/ sizeof(((PPROCESS_DEVICEMAP_INFORMATION)0x0)->Set), - /*Q*/ sizeof(ULONG), - /*S*/ sizeof(ULONG), - ICIF_QUERY | ICIF_SET ), - - ICI_SQ_SAME( sizeof(PROCESS_SESSION_INFORMATION), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessSessionInformation */ - ICI_SQ_SAME( sizeof(BOOLEAN), sizeof(ULONG), ICIF_SET ), /* ProcessForegroundInformation */ - ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY ), /* ProcessWow64Information */ - ICI_SQ_SAME( sizeof(UNICODE_STRING), sizeof(ULONG), ICIF_QUERY | ICIF_SIZE_VARIABLE), /* ProcessImageFileName */ - - /* FIXME */ - ICI_SQ_SAME( 0, 1, 0 ), /* ProcessLUIDDeviceMapsEnabled */ - ICI_SQ_SAME( 0, 1, 0 ), /* ProcessBreakOnTermination */ - ICI_SQ_SAME( 0, 1, 0 ), /* ProcessDebugObjectHandle */ - ICI_SQ_SAME( 0, 1, 0 ), /* ProcessDebugFlags */ - ICI_SQ_SAME( 0, 1, 0 ), /* ProcessHandleTracing */ - ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown33 */ - ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown34 */ - ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown35 */ - - ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY), /* ProcessCookie */ -}; - #define MAX_PROCESS_NOTIFY_ROUTINE_COUNT 8 #define MAX_LOAD_IMAGE_NOTIFY_ROUTINE_COUNT 8 @@ -93,26 +43,8 @@ static PLOAD_IMAGE_NOTIFY_ROUTINE PiLoadImageNotifyRoutine[MAX_LOAD_IMAGE_NOTIFY_ROUTINE_COUNT]; -typedef struct -{ - WORK_QUEUE_ITEM WorkQueueItem; - KEVENT Event; - PEPROCESS Process; - BOOLEAN IsWorkerQueue; -} DEL_CONTEXT, *PDEL_CONTEXT; - /* FUNCTIONS *****************************************************************/ -VOID -STDCALL -PsExitSpecialApc(PKAPC Apc, - PKNORMAL_ROUTINE *NormalRoutine, - PVOID *NormalContext, - PVOID *SystemArgument1, - PVOID *SystemArgument2) -{ -} - PEPROCESS PsGetNextProcess(PEPROCESS OldProcess) { @@ -175,130 +107,6 @@ PsGetNextProcess(PEPROCESS OldProcess) return(NextProcess); } - -/* - * @implemented - */ -NTSTATUS STDCALL -NtOpenProcessToken(IN HANDLE ProcessHandle, - IN ACCESS_MASK DesiredAccess, - OUT PHANDLE TokenHandle) -{ - return NtOpenProcessTokenEx(ProcessHandle, - DesiredAccess, - 0, - TokenHandle); -} - - -/* - * @unimplemented - */ -NTSTATUS -STDCALL -NtOpenProcessTokenEx( - IN HANDLE ProcessHandle, - IN ACCESS_MASK DesiredAccess, - IN ULONG HandleAttributes, - OUT PHANDLE TokenHandle - ) -{ - PACCESS_TOKEN Token; - HANDLE hToken; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status = STATUS_SUCCESS; - - PAGED_CODE(); - - PreviousMode = ExGetPreviousMode(); - - if(PreviousMode == UserMode) - { - _SEH_TRY - { - ProbeForWrite(TokenHandle, - sizeof(HANDLE), - sizeof(ULONG)); - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if(!NT_SUCCESS(Status)) - { - return Status; - } - } - - Status = PsOpenTokenOfProcess(ProcessHandle, - &Token); - if(NT_SUCCESS(Status)) - { - Status = ObCreateHandle(PsGetCurrentProcess(), - Token, - DesiredAccess, - FALSE, - &hToken); - ObDereferenceObject(Token); - - if (NT_SUCCESS(Status)) - { - - _SEH_TRY - { - *TokenHandle = hToken; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - } - } - - return Status; -} - - -/* - * @implemented - */ -PACCESS_TOKEN STDCALL -PsReferencePrimaryToken(PEPROCESS Process) -{ - ObReferenceObjectByPointer(Process->Token, - TOKEN_ALL_ACCESS, - SepTokenObjectType, - KernelMode); - return(Process->Token); -} - - -NTSTATUS -PsOpenTokenOfProcess(HANDLE ProcessHandle, - PACCESS_TOKEN* Token) -{ - PEPROCESS Process; - NTSTATUS Status; - - Status = ObReferenceObjectByHandle(ProcessHandle, - PROCESS_QUERY_INFORMATION, - PsProcessType, - ExGetPreviousMode(), - (PVOID*)&Process, - NULL); - if(NT_SUCCESS(Status)) - { - *Token = PsReferencePrimaryToken(Process); - ObDereferenceObject(Process); - } - - return Status; -} - - VOID PiKillMostProcesses(VOID) { @@ -317,14 +125,13 @@ PiKillMostProcesses(VOID) if (current->UniqueProcessId != PsInitialSystemProcess->UniqueProcessId && current->UniqueProcessId != PsGetCurrentProcessId()) { - PiTerminateProcessThreads(current, STATUS_SUCCESS); + PspTerminateProcessThreads(current, STATUS_SUCCESS); } } ExReleaseFastMutex(&PspActiveProcessMutex); } - VOID INIT_FUNCTION PsInitProcessManagment(VOID) { @@ -350,7 +157,7 @@ PsInitProcessManagment(VOID) PsProcessType->Dump = NULL; PsProcessType->Open = NULL; PsProcessType->Close = NULL; - PsProcessType->Delete = PiDeleteProcess; + PsProcessType->Delete = PspDeleteProcess; PsProcessType->Parse = NULL; PsProcessType->Security = NULL; PsProcessType->QueryName = NULL; @@ -490,87 +297,6 @@ PspPostInitSystemProcess(VOID) } } -VOID STDCALL -PiDeleteProcessWorker(PVOID pContext) -{ - PDEL_CONTEXT Context; - PEPROCESS CurrentProcess; - PEPROCESS Process; - - Context = (PDEL_CONTEXT)pContext; - Process = Context->Process; - CurrentProcess = PsGetCurrentProcess(); - - DPRINT("PiDeleteProcess(ObjectBody %x)\n",Process); - - if (CurrentProcess != Process) - { - KeAttachProcess(&Process->Pcb); - } - - ExAcquireFastMutex(&PspActiveProcessMutex); - RemoveEntryList(&Process->ProcessListEntry); - ExReleaseFastMutex(&PspActiveProcessMutex); - - /* KDB hook */ - KDB_DELETEPROCESS_HOOK(Process); - - ObDereferenceObject(Process->Token); - - if (CurrentProcess != Process) - { - KeDetachProcess(); - } - - if(Process->UniqueProcessId != NULL) - { - PsDeleteCidHandle(Process->UniqueProcessId, PsProcessType); - } - - MmReleaseMmInfo(Process); - if (Context->IsWorkerQueue) - { - KeSetEvent(&Context->Event, IO_NO_INCREMENT, FALSE); - } -} - -VOID STDCALL -PiDeleteProcess(PVOID ObjectBody) -{ - DEL_CONTEXT Context; - - Context.Process = (PEPROCESS)ObjectBody; - - if (PsGetCurrentProcess() == Context.Process || - PsGetCurrentThread()->ThreadsProcess == Context.Process) - { - KEBUGCHECK(0); - } - - if (PsGetCurrentThread()->ThreadsProcess == PsGetCurrentProcess()) - { - Context.IsWorkerQueue = FALSE; - PiDeleteProcessWorker(&Context); - } - else - { - Context.IsWorkerQueue = TRUE; - KeInitializeEvent(&Context.Event, NotificationEvent, FALSE); - ExInitializeWorkItem (&Context.WorkQueueItem, PiDeleteProcessWorker, &Context); - ExQueueWorkItem(&Context.WorkQueueItem, HyperCriticalWorkQueue); - if (KeReadStateEvent(&Context.Event) == 0) - { - KeWaitForSingleObject(&Context.Event, Executive, KernelMode, FALSE, NULL); - } - } - - if(((PEPROCESS)ObjectBody)->Win32Process != NULL) - { - /* delete the W32PROCESS structure if there's one associated */ - ExFreePool (((PEPROCESS)ObjectBody)->Win32Process); - } -} - static NTSTATUS PsCreatePeb(HANDLE ProcessHandle, PEPROCESS Process, @@ -1382,1112 +1108,6 @@ NtOpenProcess(OUT PHANDLE ProcessHandle, } } - -/* - * @unimplemented - */ -NTSTATUS STDCALL -NtQueryInformationProcess(IN HANDLE ProcessHandle, - IN PROCESSINFOCLASS ProcessInformationClass, - OUT PVOID ProcessInformation, - IN ULONG ProcessInformationLength, - OUT PULONG ReturnLength OPTIONAL) -{ - PEPROCESS Process; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status = STATUS_SUCCESS; - - PAGED_CODE(); - - PreviousMode = ExGetPreviousMode(); - - DefaultQueryInfoBufferCheck(ProcessInformationClass, - PsProcessInfoClass, - ProcessInformation, - ProcessInformationLength, - ReturnLength, - PreviousMode, - &Status); - if(!NT_SUCCESS(Status)) - { - DPRINT1("NtQueryInformationProcess() failed, Status: 0x%x\n", Status); - return Status; - } - - if(ProcessInformationClass != ProcessCookie) - { - Status = ObReferenceObjectByHandle(ProcessHandle, - PROCESS_QUERY_INFORMATION, - PsProcessType, - PreviousMode, - (PVOID*)&Process, - NULL); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - } - else if(ProcessHandle != NtCurrentProcess()) - { - /* retreiving the process cookie is only allowed for the calling process - itself! XP only allowes NtCurrentProcess() as process handles even if a - real handle actually represents the current process. */ - return STATUS_INVALID_PARAMETER; - } - - switch (ProcessInformationClass) - { - case ProcessBasicInformation: - { - PPROCESS_BASIC_INFORMATION ProcessBasicInformationP = - (PPROCESS_BASIC_INFORMATION)ProcessInformation; - - _SEH_TRY - { - ProcessBasicInformationP->ExitStatus = Process->ExitStatus; - ProcessBasicInformationP->PebBaseAddress = Process->Peb; - ProcessBasicInformationP->AffinityMask = Process->Pcb.Affinity; - ProcessBasicInformationP->UniqueProcessId = - Process->UniqueProcessId; - ProcessBasicInformationP->InheritedFromUniqueProcessId = - Process->InheritedFromUniqueProcessId; - ProcessBasicInformationP->BasePriority = - Process->Pcb.BasePriority; - - if (ReturnLength) - { - *ReturnLength = sizeof(PROCESS_BASIC_INFORMATION); - } - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - break; - } - - case ProcessQuotaLimits: - case ProcessIoCounters: - Status = STATUS_NOT_IMPLEMENTED; - break; - - case ProcessTimes: - { - PKERNEL_USER_TIMES ProcessTimeP = (PKERNEL_USER_TIMES)ProcessInformation; - _SEH_TRY - { - ProcessTimeP->CreateTime = Process->CreateTime; - ProcessTimeP->UserTime.QuadPart = Process->Pcb.UserTime * 100000LL; - ProcessTimeP->KernelTime.QuadPart = Process->Pcb.KernelTime * 100000LL; - ProcessTimeP->ExitTime = Process->ExitTime; - - if (ReturnLength) - { - *ReturnLength = sizeof(KERNEL_USER_TIMES); - } - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - break; - } - - case ProcessDebugPort: - { - _SEH_TRY - { - *(PHANDLE)ProcessInformation = (Process->DebugPort != NULL ? (HANDLE)-1 : NULL); - if (ReturnLength) - { - *ReturnLength = sizeof(HANDLE); - } - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - break; - } - - case ProcessLdtInformation: - case ProcessWorkingSetWatch: - case ProcessWx86Information: - Status = STATUS_NOT_IMPLEMENTED; - break; - - case ProcessHandleCount: - { - ULONG HandleCount = ObpGetHandleCountByHandleTable(Process->ObjectTable); - - _SEH_TRY - { - *(PULONG)ProcessInformation = HandleCount; - if (ReturnLength) - { - *ReturnLength = sizeof(ULONG); - } - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - break; - } - - case ProcessSessionInformation: - { - PPROCESS_SESSION_INFORMATION SessionInfo = (PPROCESS_SESSION_INFORMATION)ProcessInformation; - - _SEH_TRY - { - SessionInfo->SessionId = Process->SessionId; - if (ReturnLength) - { - *ReturnLength = sizeof(PROCESS_SESSION_INFORMATION); - } - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - break; - } - - case ProcessWow64Information: - DPRINT1("We currently don't support the ProcessWow64Information information class!\n"); - Status = STATUS_NOT_IMPLEMENTED; - break; - - case ProcessVmCounters: - { - PVM_COUNTERS pOut = (PVM_COUNTERS)ProcessInformation; - - _SEH_TRY - { - pOut->PeakVirtualSize = Process->PeakVirtualSize; - /* - * Here we should probably use VirtualSize.LowPart, but due to - * incompatibilities in current headers (no unnamed union), - * I opted for cast. - */ - pOut->VirtualSize = (ULONG)Process->VirtualSize.QuadPart; - pOut->PageFaultCount = Process->Vm.PageFaultCount; - pOut->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize; - pOut->WorkingSetSize = Process->Vm.WorkingSetSize; - pOut->QuotaPeakPagedPoolUsage = Process->QuotaPeakPoolUsage[0]; // TODO: Verify! - pOut->QuotaPagedPoolUsage = Process->QuotaPoolUsage[0]; // TODO: Verify! - pOut->QuotaPeakNonPagedPoolUsage = Process->QuotaPeakPoolUsage[1]; // TODO: Verify! - pOut->QuotaNonPagedPoolUsage = Process->QuotaPoolUsage[1]; // TODO: Verify! - pOut->PagefileUsage = Process->PagefileUsage; - pOut->PeakPagefileUsage = Process->PeakPagefileUsage; - - if (ReturnLength) - { - *ReturnLength = sizeof(VM_COUNTERS); - } - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - break; - } - - case ProcessDefaultHardErrorMode: - { - PULONG HardErrMode = (PULONG)ProcessInformation; - _SEH_TRY - { - *HardErrMode = Process->DefaultHardErrorProcessing; - if (ReturnLength) - { - *ReturnLength = sizeof(ULONG); - } - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - break; - } - - case ProcessPriorityBoost: - { - PULONG BoostEnabled = (PULONG)ProcessInformation; - - _SEH_TRY - { - *BoostEnabled = Process->Pcb.DisableBoost ? FALSE : TRUE; - - if (ReturnLength) - { - *ReturnLength = sizeof(ULONG); - } - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - break; - } - - case ProcessDeviceMap: - { - PROCESS_DEVICEMAP_INFORMATION DeviceMap; - - ObQueryDeviceMapInformation(Process, &DeviceMap); - - _SEH_TRY - { - *(PPROCESS_DEVICEMAP_INFORMATION)ProcessInformation = DeviceMap; - if (ReturnLength) - { - *ReturnLength = sizeof(PROCESS_DEVICEMAP_INFORMATION); - } - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - break; - } - - case ProcessPriorityClass: - { - PUSHORT Priority = (PUSHORT)ProcessInformation; - - _SEH_TRY - { - *Priority = Process->PriorityClass; - - if (ReturnLength) - { - *ReturnLength = sizeof(USHORT); - } - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - break; - } - - case ProcessImageFileName: - { - /* - * We DO NOT return the file name stored in the EPROCESS structure. - * Propably if we can't find a PEB or ProcessParameters structure for the - * process! - */ - if(Process->Peb != NULL) - { - PRTL_USER_PROCESS_PARAMETERS ProcParams = NULL; - UNICODE_STRING LocalDest; - BOOLEAN Attached; - ULONG ImagePathLen = 0; - PUNICODE_STRING DstPath = (PUNICODE_STRING)ProcessInformation; - - /* we need to attach to the process to make sure we're in the right context! */ - Attached = Process != PsGetCurrentProcess(); - - if(Attached) - KeAttachProcess(&Process->Pcb); - - _SEH_TRY - { - ProcParams = Process->Peb->ProcessParameters; - ImagePathLen = ProcParams->ImagePathName.Length; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if(NT_SUCCESS(Status)) - { - if(ProcessInformationLength < sizeof(UNICODE_STRING) + ImagePathLen + sizeof(WCHAR)) - { - Status = STATUS_INFO_LENGTH_MISMATCH; - } - else - { - PWSTR StrSource = NULL; - - /* create a DstPath structure on the stack */ - _SEH_TRY - { - LocalDest.Length = ImagePathLen; - LocalDest.MaximumLength = ImagePathLen + sizeof(WCHAR); - LocalDest.Buffer = (PWSTR)(DstPath + 1); - - /* save a copy of the pointer to the source buffer */ - StrSource = ProcParams->ImagePathName.Buffer; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if(NT_SUCCESS(Status)) - { - /* now, let's allocate some anonymous memory to copy the string to. - we can't just copy it to the buffer the caller pointed as it might - be user memory in another context */ - PWSTR PathCopy = ExAllocatePool(PagedPool, LocalDest.Length + sizeof(WCHAR)); - if(PathCopy != NULL) - { - /* make a copy of the buffer to the temporary buffer */ - _SEH_TRY - { - RtlCopyMemory(PathCopy, StrSource, LocalDest.Length); - PathCopy[LocalDest.Length / sizeof(WCHAR)] = L'\0'; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - /* detach from the process */ - if(Attached) - KeDetachProcess(); - - /* only copy the string back to the caller if we were able to - copy it into the temporary buffer! */ - if(NT_SUCCESS(Status)) - { - /* now let's copy the buffer back to the caller */ - _SEH_TRY - { - *DstPath = LocalDest; - RtlCopyMemory(LocalDest.Buffer, PathCopy, LocalDest.Length + sizeof(WCHAR)); - if (ReturnLength) - { - *ReturnLength = sizeof(UNICODE_STRING) + LocalDest.Length + sizeof(WCHAR); - } - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - } - - /* we're done with the copy operation, free the temporary kernel buffer */ - ExFreePool(PathCopy); - - /* we need to bail because we're already detached from the process */ - break; - } - else - { - Status = STATUS_INSUFFICIENT_RESOURCES; - } - } - } - } - - /* don't forget to detach from the process!!! */ - if(Attached) - KeDetachProcess(); - } - else - { - /* FIXME - what to do here? */ - Status = STATUS_UNSUCCESSFUL; - } - break; - } - - case ProcessCookie: - { - ULONG Cookie; - - /* receive the process cookie, this is only allowed for the current - process! */ - - Process = PsGetCurrentProcess(); - - Cookie = Process->Cookie; - if(Cookie == 0) - { - LARGE_INTEGER SystemTime; - ULONG NewCookie; - PKPRCB Prcb; - - /* generate a new cookie */ - - KeQuerySystemTime(&SystemTime); - - Prcb = KeGetCurrentPrcb(); - - NewCookie = Prcb->KeSystemCalls ^ Prcb->InterruptTime ^ - SystemTime.u.LowPart ^ SystemTime.u.HighPart; - - /* try to set the new cookie, return the current one if another thread - set it in the meanwhile */ - Cookie = InterlockedCompareExchange((LONG*)&Process->Cookie, - NewCookie, - Cookie); - if(Cookie == 0) - { - /* successfully set the cookie */ - Cookie = NewCookie; - } - } - - _SEH_TRY - { - *(PULONG)ProcessInformation = Cookie; - if (ReturnLength) - { - *ReturnLength = sizeof(ULONG); - } - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - break; - } - - /* - * Note: The following 10 information classes are verified to not be - * implemented on NT, and do indeed return STATUS_INVALID_INFO_CLASS; - */ - case ProcessBasePriority: - case ProcessRaisePriority: - case ProcessExceptionPort: - case ProcessAccessToken: - case ProcessLdtSize: - case ProcessIoPortHandlers: - case ProcessUserModeIOPL: - case ProcessEnableAlignmentFaultFixup: - case ProcessAffinityMask: - case ProcessForegroundInformation: - default: - Status = STATUS_INVALID_INFO_CLASS; - } - - if(ProcessInformationClass != ProcessCookie) - { - ObDereferenceObject(Process); - } - - return Status; -} - - -NTSTATUS -PspAssignPrimaryToken(PEPROCESS Process, - HANDLE TokenHandle) -{ - PACCESS_TOKEN Token; - PACCESS_TOKEN OldToken; - NTSTATUS Status; - - Status = ObReferenceObjectByHandle(TokenHandle, - 0, - SepTokenObjectType, - UserMode, - (PVOID*)&Token, - NULL); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - Status = SeExchangePrimaryToken(Process, Token, &OldToken); - if (NT_SUCCESS(Status)) - { - ObDereferenceObject(OldToken); - } - ObDereferenceObject(Token); - return(Status); -} - -/* - * @unimplemented - */ -NTSTATUS STDCALL -NtSetInformationProcess(IN HANDLE ProcessHandle, - IN PROCESSINFOCLASS ProcessInformationClass, - IN PVOID ProcessInformation, - IN ULONG ProcessInformationLength) -{ - PEPROCESS Process; - KPROCESSOR_MODE PreviousMode; - ACCESS_MASK Access; - NTSTATUS Status = STATUS_SUCCESS; - - PAGED_CODE(); - - PreviousMode = ExGetPreviousMode(); - - DefaultSetInfoBufferCheck(ProcessInformationClass, - PsProcessInfoClass, - ProcessInformation, - ProcessInformationLength, - PreviousMode, - &Status); - if(!NT_SUCCESS(Status)) - { - DPRINT1("NtSetInformationProcess() %d %x %x called\n", ProcessInformationClass, ProcessInformation, ProcessInformationLength); - DPRINT1("NtSetInformationProcess() %x failed, Status: 0x%x\n", Status); - return Status; - } - - switch(ProcessInformationClass) - { - case ProcessSessionInformation: - Access = PROCESS_SET_INFORMATION | PROCESS_SET_SESSIONID; - break; - case ProcessExceptionPort: - case ProcessDebugPort: - Access = PROCESS_SET_INFORMATION | PROCESS_SET_PORT; - break; - - default: - Access = PROCESS_SET_INFORMATION; - break; - } - - Status = ObReferenceObjectByHandle(ProcessHandle, - Access, - PsProcessType, - PreviousMode, - (PVOID*)&Process, - NULL); - if (!NT_SUCCESS(Status)) - { - return(Status); - } - - switch (ProcessInformationClass) - { - case ProcessQuotaLimits: - case ProcessBasePriority: - case ProcessRaisePriority: - Status = STATUS_NOT_IMPLEMENTED; - break; - - case ProcessDebugPort: - { - HANDLE PortHandle = NULL; - - /* make a safe copy of the buffer on the stack */ - _SEH_TRY - { - PortHandle = *(PHANDLE)ProcessInformation; - Status = (PortHandle != NULL ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER); - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if(NT_SUCCESS(Status)) - { - PEPORT DebugPort; - - /* in case we had success reading from the buffer, verify the provided - * LPC port handle - */ - Status = ObReferenceObjectByHandle(PortHandle, - 0, - LpcPortObjectType, - PreviousMode, - (PVOID)&DebugPort, - NULL); - if(NT_SUCCESS(Status)) - { - /* lock the process to be thread-safe! */ - - Status = PsLockProcess(Process, FALSE); - if(NT_SUCCESS(Status)) - { - /* - * according to "NT Native API" documentation, setting the debug - * port is only permitted once! - */ - if(Process->DebugPort == NULL) - { - /* keep the reference to the handle! */ - Process->DebugPort = DebugPort; - - if(Process->Peb) - { - /* we're now debugging the process, so set the flag in the PEB - structure. However, to access it we need to attach to the - process so we're sure we're in the right context! */ - - KeAttachProcess(&Process->Pcb); - _SEH_TRY - { - Process->Peb->BeingDebugged = TRUE; - } - _SEH_HANDLE - { - DPRINT1("Trying to set the Peb->BeingDebugged field of process 0x%x failed, exception: 0x%x\n", Process, _SEH_GetExceptionCode()); - } - _SEH_END; - KeDetachProcess(); - } - Status = STATUS_SUCCESS; - } - else - { - ObDereferenceObject(DebugPort); - Status = STATUS_PORT_ALREADY_SET; - } - PsUnlockProcess(Process); - } - else - { - ObDereferenceObject(DebugPort); - } - } - } - break; - } - - case ProcessExceptionPort: - { - HANDLE PortHandle = NULL; - - /* make a safe copy of the buffer on the stack */ - _SEH_TRY - { - PortHandle = *(PHANDLE)ProcessInformation; - Status = STATUS_SUCCESS; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if(NT_SUCCESS(Status)) - { - PEPORT ExceptionPort; - - /* in case we had success reading from the buffer, verify the provided - * LPC port handle - */ - Status = ObReferenceObjectByHandle(PortHandle, - 0, - LpcPortObjectType, - PreviousMode, - (PVOID)&ExceptionPort, - NULL); - if(NT_SUCCESS(Status)) - { - /* lock the process to be thread-safe! */ - - Status = PsLockProcess(Process, FALSE); - if(NT_SUCCESS(Status)) - { - /* - * according to "NT Native API" documentation, setting the exception - * port is only permitted once! - */ - if(Process->ExceptionPort == NULL) - { - /* keep the reference to the handle! */ - Process->ExceptionPort = ExceptionPort; - Status = STATUS_SUCCESS; - } - else - { - ObDereferenceObject(ExceptionPort); - Status = STATUS_PORT_ALREADY_SET; - } - PsUnlockProcess(Process); - } - else - { - ObDereferenceObject(ExceptionPort); - } - } - } - break; - } - - case ProcessAccessToken: - { - HANDLE TokenHandle = NULL; - - /* make a safe copy of the buffer on the stack */ - _SEH_TRY - { - TokenHandle = ((PPROCESS_ACCESS_TOKEN)ProcessInformation)->Token; - Status = STATUS_SUCCESS; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if(NT_SUCCESS(Status)) - { - /* in case we had success reading from the buffer, perform the actual task */ - Status = PspAssignPrimaryToken(Process, TokenHandle); - } - break; - } - - case ProcessDefaultHardErrorMode: - { - _SEH_TRY - { - InterlockedExchange((LONG*)&Process->DefaultHardErrorProcessing, - *(PLONG)ProcessInformation); - Status = STATUS_SUCCESS; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - break; - } - - case ProcessSessionInformation: - { - PROCESS_SESSION_INFORMATION SessionInfo; - Status = STATUS_SUCCESS; - - _SEH_TRY - { - /* copy the structure to the stack */ - SessionInfo = *(PPROCESS_SESSION_INFORMATION)ProcessInformation; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if(NT_SUCCESS(Status)) - { - /* we successfully copied the structure to the stack, continue processing */ - - /* - * setting the session id requires the SeTcbPrivilege! - */ - if(!SeSinglePrivilegeCheck(SeTcbPrivilege, - PreviousMode)) - { - DPRINT1("NtSetInformationProcess: Caller requires the SeTcbPrivilege privilege for setting ProcessSessionInformation!\n"); - /* can't set the session id, bail! */ - Status = STATUS_PRIVILEGE_NOT_HELD; - break; - } - - /* FIXME - update the session id for the process token */ - - Status = PsLockProcess(Process, FALSE); - if(NT_SUCCESS(Status)) - { - Process->SessionId = SessionInfo.SessionId; - - /* Update the session id in the PEB structure */ - if(Process->Peb != NULL) - { - /* we need to attach to the process to make sure we're in the right - context to access the PEB structure */ - KeAttachProcess(&Process->Pcb); - - _SEH_TRY - { - /* FIXME: Process->Peb->SessionId = SessionInfo.SessionId; */ - - Status = STATUS_SUCCESS; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - KeDetachProcess(); - } - - PsUnlockProcess(Process); - } - } - break; - } - - case ProcessPriorityClass: - { - PROCESS_PRIORITY_CLASS ppc; - - _SEH_TRY - { - ppc = *(PPROCESS_PRIORITY_CLASS)ProcessInformation; - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if(NT_SUCCESS(Status)) - { - } - - break; - } - - case ProcessLdtInformation: - case ProcessLdtSize: - case ProcessIoPortHandlers: - case ProcessWorkingSetWatch: - case ProcessUserModeIOPL: - case ProcessEnableAlignmentFaultFixup: - case ProcessAffinityMask: - Status = STATUS_NOT_IMPLEMENTED; - break; - - case ProcessBasicInformation: - case ProcessIoCounters: - case ProcessTimes: - case ProcessPooledUsageAndLimits: - case ProcessWx86Information: - case ProcessHandleCount: - case ProcessWow64Information: - default: - Status = STATUS_INVALID_INFO_CLASS; - } - ObDereferenceObject(Process); - return(Status); -} - - -/********************************************************************** - * NAME INTERNAL - * PiQuerySystemProcessInformation - * - * DESCRIPTION - * Compute the size of a process+thread snapshot as - * expected by NtQuerySystemInformation. - * - * RETURN VALUE - * 0 on error; otherwise the size, in bytes of the buffer - * required to write a full snapshot. - * - * NOTE - * We assume (sizeof (PVOID) == sizeof (ULONG)) holds. - */ -NTSTATUS -PiQuerySystemProcessInformation(PVOID Buffer, - ULONG Size, - PULONG ReqSize) -{ - return STATUS_NOT_IMPLEMENTED; - -#if 0 - PLIST_ENTRY CurrentEntryP; - PEPROCESS CurrentP; - PLIST_ENTRY CurrentEntryT; - PETHREAD CurrentT; - - ULONG RequiredSize = 0L; - BOOLEAN SizeOnly = FALSE; - - ULONG SpiSize = 0L; - - PSYSTEM_PROCESS_INFORMATION pInfoP = (PSYSTEM_PROCESS_INFORMATION) SnapshotBuffer; - PSYSTEM_PROCESS_INFORMATION pInfoPLast = NULL; - PSYSTEM_THREAD_INFO pInfoT = NULL; - - - /* Lock the process list. */ - ExAcquireFastMutex(&PspActiveProcessMutex); - - /* - * Scan the process list. Since the - * list is circular, the guard is false - * after the last process. - */ - for ( CurrentEntryP = PsActiveProcessHead.Flink; - (CurrentEntryP != & PsActiveProcessHead); - CurrentEntryP = CurrentEntryP->Flink - ) - { - /* - * Compute how much space is - * occupied in the snapshot - * by adding this process info. - * (at least one thread). - */ - SpiSizeCurrent = sizeof (SYSTEM_PROCESS_INFORMATION); - RequiredSize += SpiSizeCurrent; - /* - * Do not write process data in the - * buffer if it is too small. - */ - if (TRUE == SizeOnly) continue; - /* - * Check if the buffer can contain - * the full snapshot. - */ - if (Size < RequiredSize) - { - SizeOnly = TRUE; - continue; - } - /* - * Get a reference to the - * process descriptor we are - * handling. - */ - CurrentP = CONTAINING_RECORD( - CurrentEntryP, - EPROCESS, - ProcessListEntry - ); - /* - * Write process data in the buffer. - */ - RtlZeroMemory (pInfoP, sizeof (SYSTEM_PROCESS_INFORMATION)); - /* PROCESS */ - pInfoP->ThreadCount = 0L; - pInfoP->ProcessId = CurrentP->UniqueProcessId; - RtlInitUnicodeString ( - & pInfoP->Name, - CurrentP->ImageFileName - ); - /* THREAD */ - for ( pInfoT = & CurrentP->ThreadSysInfo [0], - CurrentEntryT = CurrentP->ThreadListHead.Flink; - - (CurrentEntryT != & CurrentP->ThreadListHead); - - pInfoT = & CurrentP->ThreadSysInfo [pInfoP->ThreadCount], - CurrentEntryT = CurrentEntryT->Flink - ) - { - /* - * Recalculate the size of the - * information block. - */ - if (0 < pInfoP->ThreadCount) - { - RequiredSize += sizeof (SYSTEM_THREAD_INFORMATION); - } - /* - * Do not write thread data in the - * buffer if it is too small. - */ - if (TRUE == SizeOnly) continue; - /* - * Check if the buffer can contain - * the full snapshot. - */ - if (Size < RequiredSize) - { - SizeOnly = TRUE; - continue; - } - /* - * Get a reference to the - * thread descriptor we are - * handling. - */ - CurrentT = CONTAINING_RECORD( - CurrentEntryT, - KTHREAD, - ThreadListEntry - ); - /* - * Write thread data. - */ - RtlZeroMemory ( - pInfoT, - sizeof (SYSTEM_THREAD_INFORMATION) - ); - pInfoT->KernelTime = CurrentT-> ; /* TIME */ - pInfoT->UserTime = CurrentT-> ; /* TIME */ - pInfoT->CreateTime = CurrentT-> ; /* TIME */ - pInfoT->TickCount = CurrentT-> ; /* ULONG */ - pInfoT->StartEIP = CurrentT-> ; /* ULONG */ - pInfoT->ClientId = CurrentT-> ; /* CLIENT_ID */ - pInfoT->ClientId = CurrentT-> ; /* CLIENT_ID */ - pInfoT->DynamicPriority = CurrentT-> ; /* ULONG */ - pInfoT->BasePriority = CurrentT-> ; /* ULONG */ - pInfoT->nSwitches = CurrentT-> ; /* ULONG */ - pInfoT->State = CurrentT-> ; /* DWORD */ - pInfoT->WaitReason = CurrentT-> ; /* KWAIT_REASON */ - /* - * Count the number of threads - * this process has. - */ - ++ pInfoP->ThreadCount; - } - /* - * Save the size of information - * stored in the buffer for the - * current process. - */ - pInfoP->RelativeOffset = SpiSize; - /* - * Save a reference to the last - * valid information block. - */ - pInfoPLast = pInfoP; - /* - * Compute the offset of the - * SYSTEM_PROCESS_INFORMATION - * descriptor in the snapshot - * buffer for the next process. - */ - (ULONG) pInfoP += SpiSize; - } - /* - * Unlock the process list. - */ - ExReleaseFastMutex ( - & PspActiveProcessMutex - ); - /* - * Return the proper error status code, - * if the buffer was too small. - */ - if (TRUE == SizeOnly) - { - if (NULL != RequiredSize) - { - *pRequiredSize = RequiredSize; - } - return STATUS_INFO_LENGTH_MISMATCH; - } - /* - * Mark the end of the snapshot. - */ - pInfoP->RelativeOffset = 0L; - /* OK */ - return STATUS_SUCCESS; -#endif -} - /* * @implemented */ @@ -3039,12 +1659,6 @@ PsLockProcess(PEPROCESS Process, BOOL Timeout) for(;;) { - if(Process->Pcb.State == PROCESS_STATE_TERMINATED) - { - KeLeaveCriticalRegion(); - return STATUS_PROCESS_IS_TERMINATING; - } - PrevLockOwner = (PKTHREAD)InterlockedCompareExchangePointer( &Process->LockOwner, CallingThread, NULL); if(PrevLockOwner == NULL || PrevLockOwner == CallingThread) diff --git a/reactos/ntoskrnl/ps/psmgr.c b/reactos/ntoskrnl/ps/psmgr.c index 52d9fa6ca7f..d8070ab7f56 100644 --- a/reactos/ntoskrnl/ps/psmgr.c +++ b/reactos/ntoskrnl/ps/psmgr.c @@ -30,8 +30,6 @@ PiInitProcessManager(VOID) PsInitProcessManagment(); PsInitThreadManagment(); PsInitIdleThread(); - PsInitReaperThread(); - PsInitialiseSuspendImplementation(); PsInitialiseW32Call(); } diff --git a/reactos/ntoskrnl/ps/query.c b/reactos/ntoskrnl/ps/query.c new file mode 100644 index 00000000000..b6dbac108a7 --- /dev/null +++ b/reactos/ntoskrnl/ps/query.c @@ -0,0 +1,1414 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/ps/query.c + * PURPOSE: Set/Query Process/Thread Information APIs + * + * PROGRAMMERS: Alex Ionescu (alex@relsoft.net) - Created File + * David Welch + */ + +/* INCLUDES ******************************************************************/ + +#include +#define NDEBUG +#include + +/* GLOBALS ******************************************************************/ + + +static const INFORMATION_CLASS_INFO PsProcessInfoClass[] = +{ + ICI_SQ_SAME( sizeof(PROCESS_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY ), /* ProcessBasicInformation */ + ICI_SQ_SAME( sizeof(QUOTA_LIMITS), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessQuotaLimits */ + ICI_SQ_SAME( sizeof(IO_COUNTERS), sizeof(ULONG), ICIF_QUERY ), /* ProcessIoCounters */ + ICI_SQ_SAME( sizeof(VM_COUNTERS), sizeof(ULONG), ICIF_QUERY ), /* ProcessVmCounters */ + ICI_SQ_SAME( sizeof(KERNEL_USER_TIMES), sizeof(ULONG), ICIF_QUERY ), /* ProcessTimes */ + ICI_SQ_SAME( sizeof(KPRIORITY), sizeof(ULONG), ICIF_SET ), /* ProcessBasePriority */ + ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_SET ), /* ProcessRaisePriority */ + ICI_SQ_SAME( sizeof(HANDLE), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessDebugPort */ + ICI_SQ_SAME( sizeof(HANDLE), sizeof(ULONG), ICIF_SET ), /* ProcessExceptionPort */ + ICI_SQ_SAME( sizeof(PROCESS_ACCESS_TOKEN), sizeof(ULONG), ICIF_SET ), /* ProcessAccessToken */ + ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessLdtInformation */ + ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_SET ), /* ProcessLdtSize */ + ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessDefaultHardErrorMode */ + ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_SET ), /* ProcessIoPortHandlers */ + ICI_SQ_SAME( sizeof(POOLED_USAGE_AND_LIMITS), sizeof(ULONG), ICIF_QUERY ), /* ProcessPooledUsageAndLimits */ + ICI_SQ_SAME( sizeof(PROCESS_WS_WATCH_INFORMATION), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessWorkingSetWatch */ + ICI_SQ_SAME( 0 /* FIXME */, sizeof(ULONG), ICIF_SET ), /* ProcessUserModeIOPL */ + ICI_SQ_SAME( sizeof(BOOLEAN), sizeof(ULONG), ICIF_SET ), /* ProcessEnableAlignmentFaultFixup */ + ICI_SQ_SAME( sizeof(PROCESS_PRIORITY_CLASS), sizeof(USHORT), ICIF_QUERY | ICIF_SET ), /* ProcessPriorityClass */ + ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY ), /* ProcessWx86Information */ + ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY ), /* ProcessHandleCount */ + ICI_SQ_SAME( sizeof(KAFFINITY), sizeof(ULONG), ICIF_SET ), /* ProcessAffinityMask */ + ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessPriorityBoost */ + + ICI_SQ(/*Q*/ sizeof(((PPROCESS_DEVICEMAP_INFORMATION)0x0)->Query), /* ProcessDeviceMap */ + /*S*/ sizeof(((PPROCESS_DEVICEMAP_INFORMATION)0x0)->Set), + /*Q*/ sizeof(ULONG), + /*S*/ sizeof(ULONG), + ICIF_QUERY | ICIF_SET ), + + ICI_SQ_SAME( sizeof(PROCESS_SESSION_INFORMATION), sizeof(ULONG), ICIF_QUERY | ICIF_SET ), /* ProcessSessionInformation */ + ICI_SQ_SAME( sizeof(BOOLEAN), sizeof(ULONG), ICIF_SET ), /* ProcessForegroundInformation */ + ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY ), /* ProcessWow64Information */ + ICI_SQ_SAME( sizeof(UNICODE_STRING), sizeof(ULONG), ICIF_QUERY | ICIF_SIZE_VARIABLE), /* ProcessImageFileName */ + + /* FIXME */ + ICI_SQ_SAME( 0, 1, 0 ), /* ProcessLUIDDeviceMapsEnabled */ + ICI_SQ_SAME( 0, 1, 0 ), /* ProcessBreakOnTermination */ + ICI_SQ_SAME( 0, 1, 0 ), /* ProcessDebugObjectHandle */ + ICI_SQ_SAME( 0, 1, 0 ), /* ProcessDebugFlags */ + ICI_SQ_SAME( 0, 1, 0 ), /* ProcessHandleTracing */ + ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown33 */ + ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown34 */ + ICI_SQ_SAME( 0, 1, 0 ), /* ProcessUnknown35 */ + + ICI_SQ_SAME( sizeof(ULONG), sizeof(ULONG), ICIF_QUERY), /* ProcessCookie */ +}; + +/* + * FIXME: + * Remove the Implemented value if all functions are implemented. + */ + +static const struct +{ + BOOLEAN Implemented; + ULONG Size; +} QueryInformationData[MaxThreadInfoClass + 1] = +{ + {TRUE, sizeof(THREAD_BASIC_INFORMATION)}, // ThreadBasicInformation + {TRUE, sizeof(KERNEL_USER_TIMES)}, // ThreadTimes + {TRUE, 0}, // ThreadPriority + {TRUE, 0}, // ThreadBasePriority + {TRUE, 0}, // ThreadAffinityMask + {TRUE, 0}, // ThreadImpersonationToken + {FALSE, 0}, // ThreadDescriptorTableEntry + {TRUE, 0}, // ThreadEnableAlignmentFaultFixup + {TRUE, 0}, // ThreadEventPair + {TRUE, sizeof(PVOID)}, // ThreadQuerySetWin32StartAddress + {TRUE, 0}, // ThreadZeroTlsCell + {TRUE, sizeof(LARGE_INTEGER)}, // ThreadPerformanceCount + {TRUE, sizeof(BOOLEAN)}, // ThreadAmILastThread + {TRUE, 0}, // ThreadIdealProcessor + {FALSE, 0}, // ThreadPriorityBoost + {TRUE, 0}, // ThreadSetTlsArrayAddress + {FALSE, 0}, // ThreadIsIoPending + {TRUE, 0} // ThreadHideFromDebugger +}; + +static const struct +{ + BOOLEAN Implemented; + ULONG Size; +} SetInformationData[MaxThreadInfoClass + 1] = +{ + {TRUE, 0}, // ThreadBasicInformation + {TRUE, 0}, // ThreadTimes + {TRUE, sizeof(KPRIORITY)}, // ThreadPriority + {TRUE, sizeof(LONG)}, // ThreadBasePriority + {TRUE, sizeof(KAFFINITY)}, // ThreadAffinityMask + {TRUE, sizeof(HANDLE)}, // ThreadImpersonationToken + {TRUE, 0}, // ThreadDescriptorTableEntry + {FALSE, 0}, // ThreadEnableAlignmentFaultFixup + {FALSE, 0}, // ThreadEventPair + {TRUE, sizeof(PVOID)}, // ThreadQuerySetWin32StartAddress + {FALSE, 0}, // ThreadZeroTlsCell + {TRUE, 0}, // ThreadPerformanceCount + {TRUE, 0}, // ThreadAmILastThread + {FALSE, 0}, // ThreadIdealProcessor + {FALSE, 0}, // ThreadPriorityBoost + {FALSE, 0}, // ThreadSetTlsArrayAddress + {TRUE, 0}, // ThreadIsIoPending + {FALSE, 0} // ThreadHideFromDebugger +}; + +/* FUNCTIONS *****************************************************************/ + +/* + * @unimplemented + */ +NTSTATUS STDCALL +NtQueryInformationProcess(IN HANDLE ProcessHandle, + IN PROCESSINFOCLASS ProcessInformationClass, + OUT PVOID ProcessInformation, + IN ULONG ProcessInformationLength, + OUT PULONG ReturnLength OPTIONAL) +{ + PEPROCESS Process; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status = STATUS_SUCCESS; + + PAGED_CODE(); + + PreviousMode = ExGetPreviousMode(); + + DefaultQueryInfoBufferCheck(ProcessInformationClass, + PsProcessInfoClass, + ProcessInformation, + ProcessInformationLength, + ReturnLength, + PreviousMode, + &Status); + if(!NT_SUCCESS(Status)) + { + DPRINT1("NtQueryInformationProcess() failed, Status: 0x%x\n", Status); + return Status; + } + + if(ProcessInformationClass != ProcessCookie) + { + Status = ObReferenceObjectByHandle(ProcessHandle, + PROCESS_QUERY_INFORMATION, + PsProcessType, + PreviousMode, + (PVOID*)&Process, + NULL); + if (!NT_SUCCESS(Status)) + { + return(Status); + } + } + else if(ProcessHandle != NtCurrentProcess()) + { + /* retreiving the process cookie is only allowed for the calling process + itself! XP only allowes NtCurrentProcess() as process handles even if a + real handle actually represents the current process. */ + return STATUS_INVALID_PARAMETER; + } + + switch (ProcessInformationClass) + { + case ProcessBasicInformation: + { + PPROCESS_BASIC_INFORMATION ProcessBasicInformationP = + (PPROCESS_BASIC_INFORMATION)ProcessInformation; + + _SEH_TRY + { + ProcessBasicInformationP->ExitStatus = Process->ExitStatus; + ProcessBasicInformationP->PebBaseAddress = Process->Peb; + ProcessBasicInformationP->AffinityMask = Process->Pcb.Affinity; + ProcessBasicInformationP->UniqueProcessId = + Process->UniqueProcessId; + ProcessBasicInformationP->InheritedFromUniqueProcessId = + Process->InheritedFromUniqueProcessId; + ProcessBasicInformationP->BasePriority = + Process->Pcb.BasePriority; + + if (ReturnLength) + { + *ReturnLength = sizeof(PROCESS_BASIC_INFORMATION); + } + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + break; + } + + case ProcessQuotaLimits: + case ProcessIoCounters: + Status = STATUS_NOT_IMPLEMENTED; + break; + + case ProcessTimes: + { + PKERNEL_USER_TIMES ProcessTimeP = (PKERNEL_USER_TIMES)ProcessInformation; + _SEH_TRY + { + ProcessTimeP->CreateTime = Process->CreateTime; + ProcessTimeP->UserTime.QuadPart = Process->Pcb.UserTime * 100000LL; + ProcessTimeP->KernelTime.QuadPart = Process->Pcb.KernelTime * 100000LL; + ProcessTimeP->ExitTime = Process->ExitTime; + + if (ReturnLength) + { + *ReturnLength = sizeof(KERNEL_USER_TIMES); + } + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + break; + } + + case ProcessDebugPort: + { + _SEH_TRY + { + *(PHANDLE)ProcessInformation = (Process->DebugPort != NULL ? (HANDLE)-1 : NULL); + if (ReturnLength) + { + *ReturnLength = sizeof(HANDLE); + } + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + break; + } + + case ProcessLdtInformation: + case ProcessWorkingSetWatch: + case ProcessWx86Information: + Status = STATUS_NOT_IMPLEMENTED; + break; + + case ProcessHandleCount: + { + ULONG HandleCount = ObpGetHandleCountByHandleTable(Process->ObjectTable); + + _SEH_TRY + { + *(PULONG)ProcessInformation = HandleCount; + if (ReturnLength) + { + *ReturnLength = sizeof(ULONG); + } + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + break; + } + + case ProcessSessionInformation: + { + PPROCESS_SESSION_INFORMATION SessionInfo = (PPROCESS_SESSION_INFORMATION)ProcessInformation; + + _SEH_TRY + { + SessionInfo->SessionId = Process->SessionId; + if (ReturnLength) + { + *ReturnLength = sizeof(PROCESS_SESSION_INFORMATION); + } + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + break; + } + + case ProcessWow64Information: + DPRINT1("We currently don't support the ProcessWow64Information information class!\n"); + Status = STATUS_NOT_IMPLEMENTED; + break; + + case ProcessVmCounters: + { + PVM_COUNTERS pOut = (PVM_COUNTERS)ProcessInformation; + + _SEH_TRY + { + pOut->PeakVirtualSize = Process->PeakVirtualSize; + /* + * Here we should probably use VirtualSize.LowPart, but due to + * incompatibilities in current headers (no unnamed union), + * I opted for cast. + */ + pOut->VirtualSize = (ULONG)Process->VirtualSize.QuadPart; + pOut->PageFaultCount = Process->Vm.PageFaultCount; + pOut->PeakWorkingSetSize = Process->Vm.PeakWorkingSetSize; + pOut->WorkingSetSize = Process->Vm.WorkingSetSize; + pOut->QuotaPeakPagedPoolUsage = Process->QuotaPeakPoolUsage[0]; // TODO: Verify! + pOut->QuotaPagedPoolUsage = Process->QuotaPoolUsage[0]; // TODO: Verify! + pOut->QuotaPeakNonPagedPoolUsage = Process->QuotaPeakPoolUsage[1]; // TODO: Verify! + pOut->QuotaNonPagedPoolUsage = Process->QuotaPoolUsage[1]; // TODO: Verify! + pOut->PagefileUsage = Process->PagefileUsage; + pOut->PeakPagefileUsage = Process->PeakPagefileUsage; + + if (ReturnLength) + { + *ReturnLength = sizeof(VM_COUNTERS); + } + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + break; + } + + case ProcessDefaultHardErrorMode: + { + PULONG HardErrMode = (PULONG)ProcessInformation; + _SEH_TRY + { + *HardErrMode = Process->DefaultHardErrorProcessing; + if (ReturnLength) + { + *ReturnLength = sizeof(ULONG); + } + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + break; + } + + case ProcessPriorityBoost: + { + PULONG BoostEnabled = (PULONG)ProcessInformation; + + _SEH_TRY + { + *BoostEnabled = Process->Pcb.DisableBoost ? FALSE : TRUE; + + if (ReturnLength) + { + *ReturnLength = sizeof(ULONG); + } + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + break; + } + + case ProcessDeviceMap: + { + PROCESS_DEVICEMAP_INFORMATION DeviceMap; + + ObQueryDeviceMapInformation(Process, &DeviceMap); + + _SEH_TRY + { + *(PPROCESS_DEVICEMAP_INFORMATION)ProcessInformation = DeviceMap; + if (ReturnLength) + { + *ReturnLength = sizeof(PROCESS_DEVICEMAP_INFORMATION); + } + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + break; + } + + case ProcessPriorityClass: + { + PUSHORT Priority = (PUSHORT)ProcessInformation; + + _SEH_TRY + { + *Priority = Process->PriorityClass; + + if (ReturnLength) + { + *ReturnLength = sizeof(USHORT); + } + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + break; + } + + case ProcessImageFileName: + { + /* + * We DO NOT return the file name stored in the EPROCESS structure. + * Propably if we can't find a PEB or ProcessParameters structure for the + * process! + */ + if(Process->Peb != NULL) + { + PRTL_USER_PROCESS_PARAMETERS ProcParams = NULL; + UNICODE_STRING LocalDest; + BOOLEAN Attached; + ULONG ImagePathLen = 0; + PUNICODE_STRING DstPath = (PUNICODE_STRING)ProcessInformation; + + /* we need to attach to the process to make sure we're in the right context! */ + Attached = Process != PsGetCurrentProcess(); + + if(Attached) + KeAttachProcess(&Process->Pcb); + + _SEH_TRY + { + ProcParams = Process->Peb->ProcessParameters; + ImagePathLen = ProcParams->ImagePathName.Length; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(NT_SUCCESS(Status)) + { + if(ProcessInformationLength < sizeof(UNICODE_STRING) + ImagePathLen + sizeof(WCHAR)) + { + Status = STATUS_INFO_LENGTH_MISMATCH; + } + else + { + PWSTR StrSource = NULL; + + /* create a DstPath structure on the stack */ + _SEH_TRY + { + LocalDest.Length = ImagePathLen; + LocalDest.MaximumLength = ImagePathLen + sizeof(WCHAR); + LocalDest.Buffer = (PWSTR)(DstPath + 1); + + /* save a copy of the pointer to the source buffer */ + StrSource = ProcParams->ImagePathName.Buffer; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(NT_SUCCESS(Status)) + { + /* now, let's allocate some anonymous memory to copy the string to. + we can't just copy it to the buffer the caller pointed as it might + be user memory in another context */ + PWSTR PathCopy = ExAllocatePool(PagedPool, LocalDest.Length + sizeof(WCHAR)); + if(PathCopy != NULL) + { + /* make a copy of the buffer to the temporary buffer */ + _SEH_TRY + { + RtlCopyMemory(PathCopy, StrSource, LocalDest.Length); + PathCopy[LocalDest.Length / sizeof(WCHAR)] = L'\0'; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + /* detach from the process */ + if(Attached) + KeDetachProcess(); + + /* only copy the string back to the caller if we were able to + copy it into the temporary buffer! */ + if(NT_SUCCESS(Status)) + { + /* now let's copy the buffer back to the caller */ + _SEH_TRY + { + *DstPath = LocalDest; + RtlCopyMemory(LocalDest.Buffer, PathCopy, LocalDest.Length + sizeof(WCHAR)); + if (ReturnLength) + { + *ReturnLength = sizeof(UNICODE_STRING) + LocalDest.Length + sizeof(WCHAR); + } + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } + + /* we're done with the copy operation, free the temporary kernel buffer */ + ExFreePool(PathCopy); + + /* we need to bail because we're already detached from the process */ + break; + } + else + { + Status = STATUS_INSUFFICIENT_RESOURCES; + } + } + } + } + + /* don't forget to detach from the process!!! */ + if(Attached) + KeDetachProcess(); + } + else + { + /* FIXME - what to do here? */ + Status = STATUS_UNSUCCESSFUL; + } + break; + } + + case ProcessCookie: + { + ULONG Cookie; + + /* receive the process cookie, this is only allowed for the current + process! */ + + Process = PsGetCurrentProcess(); + + Cookie = Process->Cookie; + if(Cookie == 0) + { + LARGE_INTEGER SystemTime; + ULONG NewCookie; + PKPRCB Prcb; + + /* generate a new cookie */ + + KeQuerySystemTime(&SystemTime); + + Prcb = KeGetCurrentPrcb(); + + NewCookie = Prcb->KeSystemCalls ^ Prcb->InterruptTime ^ + SystemTime.u.LowPart ^ SystemTime.u.HighPart; + + /* try to set the new cookie, return the current one if another thread + set it in the meanwhile */ + Cookie = InterlockedCompareExchange((LONG*)&Process->Cookie, + NewCookie, + Cookie); + if(Cookie == 0) + { + /* successfully set the cookie */ + Cookie = NewCookie; + } + } + + _SEH_TRY + { + *(PULONG)ProcessInformation = Cookie; + if (ReturnLength) + { + *ReturnLength = sizeof(ULONG); + } + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + break; + } + + /* + * Note: The following 10 information classes are verified to not be + * implemented on NT, and do indeed return STATUS_INVALID_INFO_CLASS; + */ + case ProcessBasePriority: + case ProcessRaisePriority: + case ProcessExceptionPort: + case ProcessAccessToken: + case ProcessLdtSize: + case ProcessIoPortHandlers: + case ProcessUserModeIOPL: + case ProcessEnableAlignmentFaultFixup: + case ProcessAffinityMask: + case ProcessForegroundInformation: + default: + Status = STATUS_INVALID_INFO_CLASS; + } + + if(ProcessInformationClass != ProcessCookie) + { + ObDereferenceObject(Process); + } + + return Status; +} + +/* + * @unimplemented + */ +NTSTATUS STDCALL +NtSetInformationProcess(IN HANDLE ProcessHandle, + IN PROCESSINFOCLASS ProcessInformationClass, + IN PVOID ProcessInformation, + IN ULONG ProcessInformationLength) +{ + PEPROCESS Process; + KPROCESSOR_MODE PreviousMode; + ACCESS_MASK Access; + NTSTATUS Status = STATUS_SUCCESS; + + PAGED_CODE(); + + PreviousMode = ExGetPreviousMode(); + + DefaultSetInfoBufferCheck(ProcessInformationClass, + PsProcessInfoClass, + ProcessInformation, + ProcessInformationLength, + PreviousMode, + &Status); + if(!NT_SUCCESS(Status)) + { + DPRINT1("NtSetInformationProcess() %d %x %x called\n", ProcessInformationClass, ProcessInformation, ProcessInformationLength); + DPRINT1("NtSetInformationProcess() %x failed, Status: 0x%x\n", Status); + return Status; + } + + switch(ProcessInformationClass) + { + case ProcessSessionInformation: + Access = PROCESS_SET_INFORMATION | PROCESS_SET_SESSIONID; + break; + case ProcessExceptionPort: + case ProcessDebugPort: + Access = PROCESS_SET_INFORMATION | PROCESS_SET_PORT; + break; + + default: + Access = PROCESS_SET_INFORMATION; + break; + } + + Status = ObReferenceObjectByHandle(ProcessHandle, + Access, + PsProcessType, + PreviousMode, + (PVOID*)&Process, + NULL); + if (!NT_SUCCESS(Status)) + { + return(Status); + } + + switch (ProcessInformationClass) + { + case ProcessQuotaLimits: + case ProcessBasePriority: + case ProcessRaisePriority: + Status = STATUS_NOT_IMPLEMENTED; + break; + + case ProcessDebugPort: + { + HANDLE PortHandle = NULL; + + /* make a safe copy of the buffer on the stack */ + _SEH_TRY + { + PortHandle = *(PHANDLE)ProcessInformation; + Status = (PortHandle != NULL ? STATUS_SUCCESS : STATUS_INVALID_PARAMETER); + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(NT_SUCCESS(Status)) + { + PEPORT DebugPort; + + /* in case we had success reading from the buffer, verify the provided + * LPC port handle + */ + Status = ObReferenceObjectByHandle(PortHandle, + 0, + LpcPortObjectType, + PreviousMode, + (PVOID)&DebugPort, + NULL); + if(NT_SUCCESS(Status)) + { + /* lock the process to be thread-safe! */ + + Status = PsLockProcess(Process, FALSE); + if(NT_SUCCESS(Status)) + { + /* + * according to "NT Native API" documentation, setting the debug + * port is only permitted once! + */ + if(Process->DebugPort == NULL) + { + /* keep the reference to the handle! */ + Process->DebugPort = DebugPort; + + if(Process->Peb) + { + /* we're now debugging the process, so set the flag in the PEB + structure. However, to access it we need to attach to the + process so we're sure we're in the right context! */ + + KeAttachProcess(&Process->Pcb); + _SEH_TRY + { + Process->Peb->BeingDebugged = TRUE; + } + _SEH_HANDLE + { + DPRINT1("Trying to set the Peb->BeingDebugged field of process 0x%x failed, exception: 0x%x\n", Process, _SEH_GetExceptionCode()); + } + _SEH_END; + KeDetachProcess(); + } + Status = STATUS_SUCCESS; + } + else + { + ObDereferenceObject(DebugPort); + Status = STATUS_PORT_ALREADY_SET; + } + PsUnlockProcess(Process); + } + else + { + ObDereferenceObject(DebugPort); + } + } + } + break; + } + + case ProcessExceptionPort: + { + HANDLE PortHandle = NULL; + + /* make a safe copy of the buffer on the stack */ + _SEH_TRY + { + PortHandle = *(PHANDLE)ProcessInformation; + Status = STATUS_SUCCESS; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(NT_SUCCESS(Status)) + { + PEPORT ExceptionPort; + + /* in case we had success reading from the buffer, verify the provided + * LPC port handle + */ + Status = ObReferenceObjectByHandle(PortHandle, + 0, + LpcPortObjectType, + PreviousMode, + (PVOID)&ExceptionPort, + NULL); + if(NT_SUCCESS(Status)) + { + /* lock the process to be thread-safe! */ + + Status = PsLockProcess(Process, FALSE); + if(NT_SUCCESS(Status)) + { + /* + * according to "NT Native API" documentation, setting the exception + * port is only permitted once! + */ + if(Process->ExceptionPort == NULL) + { + /* keep the reference to the handle! */ + Process->ExceptionPort = ExceptionPort; + Status = STATUS_SUCCESS; + } + else + { + ObDereferenceObject(ExceptionPort); + Status = STATUS_PORT_ALREADY_SET; + } + PsUnlockProcess(Process); + } + else + { + ObDereferenceObject(ExceptionPort); + } + } + } + break; + } + + case ProcessAccessToken: + { + HANDLE TokenHandle = NULL; + + /* make a safe copy of the buffer on the stack */ + _SEH_TRY + { + TokenHandle = ((PPROCESS_ACCESS_TOKEN)ProcessInformation)->Token; + Status = STATUS_SUCCESS; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(NT_SUCCESS(Status)) + { + /* in case we had success reading from the buffer, perform the actual task */ + Status = PspAssignPrimaryToken(Process, TokenHandle); + } + break; + } + + case ProcessDefaultHardErrorMode: + { + _SEH_TRY + { + InterlockedExchange((LONG*)&Process->DefaultHardErrorProcessing, + *(PLONG)ProcessInformation); + Status = STATUS_SUCCESS; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + break; + } + + case ProcessSessionInformation: + { + PROCESS_SESSION_INFORMATION SessionInfo; + Status = STATUS_SUCCESS; + + _SEH_TRY + { + /* copy the structure to the stack */ + SessionInfo = *(PPROCESS_SESSION_INFORMATION)ProcessInformation; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(NT_SUCCESS(Status)) + { + /* we successfully copied the structure to the stack, continue processing */ + + /* + * setting the session id requires the SeTcbPrivilege! + */ + if(!SeSinglePrivilegeCheck(SeTcbPrivilege, + PreviousMode)) + { + DPRINT1("NtSetInformationProcess: Caller requires the SeTcbPrivilege privilege for setting ProcessSessionInformation!\n"); + /* can't set the session id, bail! */ + Status = STATUS_PRIVILEGE_NOT_HELD; + break; + } + + /* FIXME - update the session id for the process token */ + + Status = PsLockProcess(Process, FALSE); + if(NT_SUCCESS(Status)) + { + Process->SessionId = SessionInfo.SessionId; + + /* Update the session id in the PEB structure */ + if(Process->Peb != NULL) + { + /* we need to attach to the process to make sure we're in the right + context to access the PEB structure */ + KeAttachProcess(&Process->Pcb); + + _SEH_TRY + { + /* FIXME: Process->Peb->SessionId = SessionInfo.SessionId; */ + + Status = STATUS_SUCCESS; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + KeDetachProcess(); + } + + PsUnlockProcess(Process); + } + } + break; + } + + case ProcessPriorityClass: + { + PROCESS_PRIORITY_CLASS ppc; + + _SEH_TRY + { + ppc = *(PPROCESS_PRIORITY_CLASS)ProcessInformation; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(NT_SUCCESS(Status)) + { + } + + break; + } + + case ProcessLdtInformation: + case ProcessLdtSize: + case ProcessIoPortHandlers: + case ProcessWorkingSetWatch: + case ProcessUserModeIOPL: + case ProcessEnableAlignmentFaultFixup: + case ProcessAffinityMask: + Status = STATUS_NOT_IMPLEMENTED; + break; + + case ProcessBasicInformation: + case ProcessIoCounters: + case ProcessTimes: + case ProcessPooledUsageAndLimits: + case ProcessWx86Information: + case ProcessHandleCount: + case ProcessWow64Information: + default: + Status = STATUS_INVALID_INFO_CLASS; + } + ObDereferenceObject(Process); + return(Status); +} + + +/********************************************************************** + * NAME INTERNAL + * PiQuerySystemProcessInformation + * + * DESCRIPTION + * Compute the size of a process+thread snapshot as + * expected by NtQuerySystemInformation. + * + * RETURN VALUE + * 0 on error; otherwise the size, in bytes of the buffer + * required to write a full snapshot. + * + * NOTE + * We assume (sizeof (PVOID) == sizeof (ULONG)) holds. + */ +NTSTATUS +PiQuerySystemProcessInformation(PVOID Buffer, + ULONG Size, + PULONG ReqSize) +{ + return STATUS_NOT_IMPLEMENTED; + +#if 0 + PLIST_ENTRY CurrentEntryP; + PEPROCESS CurrentP; + PLIST_ENTRY CurrentEntryT; + PETHREAD CurrentT; + + ULONG RequiredSize = 0L; + BOOLEAN SizeOnly = FALSE; + + ULONG SpiSize = 0L; + + PSYSTEM_PROCESS_INFORMATION pInfoP = (PSYSTEM_PROCESS_INFORMATION) SnapshotBuffer; + PSYSTEM_PROCESS_INFORMATION pInfoPLast = NULL; + PSYSTEM_THREAD_INFO pInfoT = NULL; + + + /* Lock the process list. */ + ExAcquireFastMutex(&PspActiveProcessMutex); + + /* + * Scan the process list. Since the + * list is circular, the guard is false + * after the last process. + */ + for ( CurrentEntryP = PsActiveProcessHead.Flink; + (CurrentEntryP != & PsActiveProcessHead); + CurrentEntryP = CurrentEntryP->Flink + ) + { + /* + * Compute how much space is + * occupied in the snapshot + * by adding this process info. + * (at least one thread). + */ + SpiSizeCurrent = sizeof (SYSTEM_PROCESS_INFORMATION); + RequiredSize += SpiSizeCurrent; + /* + * Do not write process data in the + * buffer if it is too small. + */ + if (TRUE == SizeOnly) continue; + /* + * Check if the buffer can contain + * the full snapshot. + */ + if (Size < RequiredSize) + { + SizeOnly = TRUE; + continue; + } + /* + * Get a reference to the + * process descriptor we are + * handling. + */ + CurrentP = CONTAINING_RECORD( + CurrentEntryP, + EPROCESS, + ProcessListEntry + ); + /* + * Write process data in the buffer. + */ + RtlZeroMemory (pInfoP, sizeof (SYSTEM_PROCESS_INFORMATION)); + /* PROCESS */ + pInfoP->ThreadCount = 0L; + pInfoP->ProcessId = CurrentP->UniqueProcessId; + RtlInitUnicodeString ( + & pInfoP->Name, + CurrentP->ImageFileName + ); + /* THREAD */ + for ( pInfoT = & CurrentP->ThreadSysInfo [0], + CurrentEntryT = CurrentP->ThreadListHead.Flink; + + (CurrentEntryT != & CurrentP->ThreadListHead); + + pInfoT = & CurrentP->ThreadSysInfo [pInfoP->ThreadCount], + CurrentEntryT = CurrentEntryT->Flink + ) + { + /* + * Recalculate the size of the + * information block. + */ + if (0 < pInfoP->ThreadCount) + { + RequiredSize += sizeof (SYSTEM_THREAD_INFORMATION); + } + /* + * Do not write thread data in the + * buffer if it is too small. + */ + if (TRUE == SizeOnly) continue; + /* + * Check if the buffer can contain + * the full snapshot. + */ + if (Size < RequiredSize) + { + SizeOnly = TRUE; + continue; + } + /* + * Get a reference to the + * thread descriptor we are + * handling. + */ + CurrentT = CONTAINING_RECORD( + CurrentEntryT, + KTHREAD, + ThreadListEntry + ); + /* + * Write thread data. + */ + RtlZeroMemory ( + pInfoT, + sizeof (SYSTEM_THREAD_INFORMATION) + ); + pInfoT->KernelTime = CurrentT-> ; /* TIME */ + pInfoT->UserTime = CurrentT-> ; /* TIME */ + pInfoT->CreateTime = CurrentT-> ; /* TIME */ + pInfoT->TickCount = CurrentT-> ; /* ULONG */ + pInfoT->StartEIP = CurrentT-> ; /* ULONG */ + pInfoT->ClientId = CurrentT-> ; /* CLIENT_ID */ + pInfoT->ClientId = CurrentT-> ; /* CLIENT_ID */ + pInfoT->DynamicPriority = CurrentT-> ; /* ULONG */ + pInfoT->BasePriority = CurrentT-> ; /* ULONG */ + pInfoT->nSwitches = CurrentT-> ; /* ULONG */ + pInfoT->State = CurrentT-> ; /* DWORD */ + pInfoT->WaitReason = CurrentT-> ; /* KWAIT_REASON */ + /* + * Count the number of threads + * this process has. + */ + ++ pInfoP->ThreadCount; + } + /* + * Save the size of information + * stored in the buffer for the + * current process. + */ + pInfoP->RelativeOffset = SpiSize; + /* + * Save a reference to the last + * valid information block. + */ + pInfoPLast = pInfoP; + /* + * Compute the offset of the + * SYSTEM_PROCESS_INFORMATION + * descriptor in the snapshot + * buffer for the next process. + */ + (ULONG) pInfoP += SpiSize; + } + /* + * Unlock the process list. + */ + ExReleaseFastMutex ( + & PspActiveProcessMutex + ); + /* + * Return the proper error status code, + * if the buffer was too small. + */ + if (TRUE == SizeOnly) + { + if (NULL != RequiredSize) + { + *pRequiredSize = RequiredSize; + } + return STATUS_INFO_LENGTH_MISMATCH; + } + /* + * Mark the end of the snapshot. + */ + pInfoP->RelativeOffset = 0L; + /* OK */ + return STATUS_SUCCESS; +#endif +} + +/* + * @unimplemented + */ +NTSTATUS STDCALL +NtSetInformationThread (IN HANDLE ThreadHandle, + IN THREADINFOCLASS ThreadInformationClass, + IN PVOID ThreadInformation, + IN ULONG ThreadInformationLength) +{ + PETHREAD Thread; + NTSTATUS Status; + union + { + KPRIORITY Priority; + LONG Increment; + KAFFINITY Affinity; + HANDLE Handle; + PVOID Address; + }u; + + PAGED_CODE(); + + if (ThreadInformationClass <= MaxThreadInfoClass && + !SetInformationData[ThreadInformationClass].Implemented) + { + return STATUS_NOT_IMPLEMENTED; + } + if (ThreadInformationClass > MaxThreadInfoClass || + SetInformationData[ThreadInformationClass].Size == 0) + { + return STATUS_INVALID_INFO_CLASS; + } + if (ThreadInformationLength != SetInformationData[ThreadInformationClass].Size) + { + return STATUS_INFO_LENGTH_MISMATCH; + } + + Status = ObReferenceObjectByHandle (ThreadHandle, + THREAD_SET_INFORMATION, + PsThreadType, + ExGetPreviousMode (), + (PVOID*)&Thread, + NULL); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + Status = MmCopyFromCaller(&u.Priority, + ThreadInformation, + SetInformationData[ThreadInformationClass].Size); + if (NT_SUCCESS(Status)) + { + switch (ThreadInformationClass) + { + case ThreadPriority: + if (u.Priority < LOW_PRIORITY || u.Priority >= MAXIMUM_PRIORITY) + { + Status = STATUS_INVALID_PARAMETER; + break; + } + KeSetPriorityThread(&Thread->Tcb, u.Priority); + break; + + case ThreadBasePriority: + KeSetBasePriorityThread (&Thread->Tcb, u.Increment); + break; + + case ThreadAffinityMask: + Status = KeSetAffinityThread(&Thread->Tcb, u.Affinity); + break; + + case ThreadImpersonationToken: + Status = PsAssignImpersonationToken (Thread, u.Handle); + break; + + case ThreadQuerySetWin32StartAddress: + Thread->Win32StartAddress = u.Address; + break; + + default: + /* Shoult never occure if the data table is correct */ + KEBUGCHECK(0); + } + } + ObDereferenceObject (Thread); + + return Status; +} + +/* + * @implemented + */ +NTSTATUS STDCALL +NtQueryInformationThread (IN HANDLE ThreadHandle, + IN THREADINFOCLASS ThreadInformationClass, + OUT PVOID ThreadInformation, + IN ULONG ThreadInformationLength, + OUT PULONG ReturnLength OPTIONAL) +{ + PETHREAD Thread; + NTSTATUS Status; + union + { + THREAD_BASIC_INFORMATION TBI; + KERNEL_USER_TIMES TTI; + PVOID Address; + LARGE_INTEGER Count; + BOOLEAN Last; + }u; + + PAGED_CODE(); + + if (ThreadInformationClass <= MaxThreadInfoClass && + !QueryInformationData[ThreadInformationClass].Implemented) + { + return STATUS_NOT_IMPLEMENTED; + } + if (ThreadInformationClass > MaxThreadInfoClass || + QueryInformationData[ThreadInformationClass].Size == 0) + { + return STATUS_INVALID_INFO_CLASS; + } + if (ThreadInformationLength != QueryInformationData[ThreadInformationClass].Size) + { + return STATUS_INFO_LENGTH_MISMATCH; + } + + Status = ObReferenceObjectByHandle(ThreadHandle, + THREAD_QUERY_INFORMATION, + PsThreadType, + ExGetPreviousMode(), + (PVOID*)&Thread, + NULL); + if (!NT_SUCCESS(Status)) + { + return Status; + } + + switch (ThreadInformationClass) + { + case ThreadBasicInformation: + /* A test on W2K agains ntdll shows NtQueryInformationThread return STATUS_PENDING + * as ExitStatus for current/running thread, while KETHREAD's ExitStatus is + * 0. So do the conversion here: + * -Gunnar */ + u.TBI.ExitStatus = (Thread->ExitStatus == 0) ? STATUS_PENDING : Thread->ExitStatus; + u.TBI.TebBaseAddress = Thread->Tcb.Teb; + u.TBI.ClientId = Thread->Cid; + u.TBI.AffinityMask = Thread->Tcb.Affinity; + u.TBI.Priority = Thread->Tcb.Priority; + u.TBI.BasePriority = Thread->Tcb.BasePriority; + break; + + case ThreadTimes: + u.TTI.KernelTime.QuadPart = Thread->Tcb.KernelTime * 100000LL; + u.TTI.UserTime.QuadPart = Thread->Tcb.UserTime * 100000LL; + u.TTI.CreateTime = Thread->CreateTime; + /*This works*/ + u.TTI.ExitTime = Thread->ExitTime; + break; + + case ThreadQuerySetWin32StartAddress: + u.Address = Thread->Win32StartAddress; + break; + + case ThreadPerformanceCount: + /* Nebbett says this class is always zero */ + u.Count.QuadPart = 0; + break; + + case ThreadAmILastThread: + if (Thread->ThreadsProcess->ThreadListHead.Flink->Flink == + &Thread->ThreadsProcess->ThreadListHead) + { + u.Last = TRUE; + } + else + { + u.Last = FALSE; + } + break; + default: + /* Shoult never occure if the data table is correct */ + KEBUGCHECK(0); + } + if (QueryInformationData[ThreadInformationClass].Size) + { + Status = MmCopyToCaller(ThreadInformation, + &u.TBI, + QueryInformationData[ThreadInformationClass].Size); + } + if (ReturnLength) + { + NTSTATUS Status2; + static ULONG Null = 0; + Status2 = MmCopyToCaller(ReturnLength, + NT_SUCCESS(Status) ? &QueryInformationData[ThreadInformationClass].Size : &Null, + sizeof(ULONG)); + if (NT_SUCCESS(Status)) + { + Status = Status2; + } + } + + ObDereferenceObject(Thread); + return(Status); +} +/* EOF */ diff --git a/reactos/ntoskrnl/ps/security.c b/reactos/ntoskrnl/ps/security.c new file mode 100644 index 00000000000..7c85bd67892 --- /dev/null +++ b/reactos/ntoskrnl/ps/security.c @@ -0,0 +1,499 @@ +/* + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS kernel + * FILE: ntoskrnl/ps/security.c + * PURPOSE: Process Manager Security (Tokens, Impersionation) + * + * PROGRAMMERS: David Welch (welch@cwcom.net) + */ + +/* INCLUDES ******************************************************************/ + +#include +#define NDEBUG +#include + +/* GLOBALS ******************************************************************/ + +/* FUNCTIONS *****************************************************************/ + +/* + * @implemented + */ +NTSTATUS +STDCALL +NtOpenProcessToken(IN HANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + OUT PHANDLE TokenHandle) +{ + return NtOpenProcessTokenEx(ProcessHandle, + DesiredAccess, + 0, + TokenHandle); +} + +/* + * @implemented + */ +NTSTATUS +STDCALL +NtOpenProcessTokenEx(IN HANDLE ProcessHandle, + IN ACCESS_MASK DesiredAccess, + IN ULONG HandleAttributes, + OUT PHANDLE TokenHandle) +{ + PACCESS_TOKEN Token; + HANDLE hToken; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status = STATUS_SUCCESS; + + PAGED_CODE(); + + PreviousMode = ExGetPreviousMode(); + + if(PreviousMode == UserMode) + { + _SEH_TRY + { + ProbeForWrite(TokenHandle, + sizeof(HANDLE), + sizeof(ULONG)); + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(!NT_SUCCESS(Status)) + { + return Status; + } + } + + Status = PsOpenTokenOfProcess(ProcessHandle, + &Token); + if(NT_SUCCESS(Status)) + { + Status = ObCreateHandle(PsGetCurrentProcess(), + Token, + DesiredAccess, + FALSE, + &hToken); + ObDereferenceObject(Token); + + _SEH_TRY + { + *TokenHandle = hToken; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + } + + return Status; +} + +/* + * @implemented + */ +PACCESS_TOKEN +STDCALL +PsReferencePrimaryToken(PEPROCESS Process) +{ + /* Reference and return the Token */ + ObReferenceObjectByPointer(Process->Token, + TOKEN_ALL_ACCESS, + SepTokenObjectType, + KernelMode); + return(Process->Token); +} + +/* + * @implemented + */ +NTSTATUS +STDCALL +PsOpenTokenOfProcess(HANDLE ProcessHandle, + PACCESS_TOKEN* Token) +{ + PEPROCESS Process; + NTSTATUS Status; + + /* Get the Token */ + Status = ObReferenceObjectByHandle(ProcessHandle, + PROCESS_QUERY_INFORMATION, + PsProcessType, + ExGetPreviousMode(), + (PVOID*)&Process, + NULL); + + /* Reference it */ + if(NT_SUCCESS(Status)) { + + *Token = PsReferencePrimaryToken(Process); + ObDereferenceObject(Process); + } + + /* Return */ + return Status; +} + +NTSTATUS +STDCALL +PspAssignPrimaryToken(PEPROCESS Process, + HANDLE TokenHandle) +{ + PACCESS_TOKEN Token; + PACCESS_TOKEN OldToken; + NTSTATUS Status; + + /* Reference the Token */ + Status = ObReferenceObjectByHandle(TokenHandle, + 0, + SepTokenObjectType, + KeGetPreviousMode(), + (PVOID*)&Token, + NULL); + if (!NT_SUCCESS(Status)) { + + return(Status); + } + + /* Exchange them */ + Status = SeExchangePrimaryToken(Process, Token, &OldToken); + + /* Derefernece Tokens and Return */ + if (NT_SUCCESS(Status)) ObDereferenceObject(OldToken); + ObDereferenceObject(Token); + return(Status); +} + +/* + * @implemented + */ +NTSTATUS +STDCALL +PsAssignImpersonationToken(PETHREAD Thread, + HANDLE TokenHandle) +{ + PACCESS_TOKEN Token; + SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; + NTSTATUS Status; + + if (TokenHandle != NULL) { + + Status = ObReferenceObjectByHandle(TokenHandle, + TOKEN_IMPERSONATE, + SepTokenObjectType, + KeGetPreviousMode(), + (PVOID*)&Token, + NULL); + + if (!NT_SUCCESS(Status)) { + + return(Status); + } + + ImpersonationLevel = SeTokenImpersonationLevel(Token); + + } else { + + Token = NULL; + ImpersonationLevel = 0; + } + + PsImpersonateClient(Thread, + Token, + FALSE, + FALSE, + ImpersonationLevel); + + if (Token != NULL) ObDereferenceObject(Token); + return(STATUS_SUCCESS); +} + +/* + * @implemented + */ +VOID STDCALL +PsRevertToSelf (VOID) +{ + PsRevertThreadToSelf(PsGetCurrentThread()); +} + +/* + * @implemented + */ +VOID +STDCALL +PsRevertThreadToSelf(IN PETHREAD Thread) +{ + if (Thread->ActiveImpersonationInfo == TRUE) { + + ObDereferenceObject (Thread->ImpersonationInfo->Token); + Thread->ActiveImpersonationInfo = FALSE; + } +} + +/* + * @implemented + */ +VOID +STDCALL +PsImpersonateClient(IN PETHREAD Thread, + IN PACCESS_TOKEN Token, + IN BOOLEAN CopyOnOpen, + IN BOOLEAN EffectiveOnly, + IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel) +{ + + if (Token == NULL) { + + if (Thread->ActiveImpersonationInfo == TRUE) { + + Thread->ActiveImpersonationInfo = FALSE; + + if (Thread->ImpersonationInfo->Token != NULL) { + + ObDereferenceObject (Thread->ImpersonationInfo->Token); + } + } + + return; + } + + if (Thread->ImpersonationInfo == NULL) { + + Thread->ImpersonationInfo = ExAllocatePool(NonPagedPool, + sizeof(PS_IMPERSONATION_INFORMATION)); + } + + Thread->ImpersonationInfo->ImpersonationLevel = ImpersonationLevel; + Thread->ImpersonationInfo->CopyOnOpen = CopyOnOpen; + Thread->ImpersonationInfo->EffectiveOnly = EffectiveOnly; + Thread->ImpersonationInfo->Token = Token; + + ObReferenceObjectByPointer(Token, + 0, + SepTokenObjectType, + KernelMode); + + Thread->ActiveImpersonationInfo = TRUE; +} + + +PACCESS_TOKEN +STDCALL +PsReferenceEffectiveToken(PETHREAD Thread, + PTOKEN_TYPE TokenType, + PBOOLEAN EffectiveOnly, + PSECURITY_IMPERSONATION_LEVEL Level) +{ + PEPROCESS Process; + PACCESS_TOKEN Token; + + if (Thread->ActiveImpersonationInfo == FALSE) { + + Process = Thread->ThreadsProcess; + *TokenType = TokenPrimary; + *EffectiveOnly = FALSE; + Token = Process->Token; + + } else { + + Token = Thread->ImpersonationInfo->Token; + *TokenType = TokenImpersonation; + *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly; + *Level = Thread->ImpersonationInfo->ImpersonationLevel; + } + + return(Token); +} + +NTSTATUS +STDCALL +NtImpersonateThread(IN HANDLE ThreadHandle, + IN HANDLE ThreadToImpersonateHandle, + IN PSECURITY_QUALITY_OF_SERVICE SecurityQualityOfService) +{ + SECURITY_QUALITY_OF_SERVICE SafeServiceQoS; + SECURITY_CLIENT_CONTEXT ClientContext; + PETHREAD Thread; + PETHREAD ThreadToImpersonate; + KPROCESSOR_MODE PreviousMode; + NTSTATUS Status = STATUS_SUCCESS; + + PAGED_CODE(); + + PreviousMode = ExGetPreviousMode(); + + if(PreviousMode != KernelMode) + { + _SEH_TRY + { + ProbeForRead(SecurityQualityOfService, + sizeof(SECURITY_QUALITY_OF_SERVICE), + sizeof(ULONG)); + SafeServiceQoS = *SecurityQualityOfService; + SecurityQualityOfService = &SafeServiceQoS; + } + _SEH_HANDLE + { + Status = _SEH_GetExceptionCode(); + } + _SEH_END; + + if(!NT_SUCCESS(Status)) + { + return Status; + } + } + + Status = ObReferenceObjectByHandle(ThreadHandle, + THREAD_IMPERSONATE, + PsThreadType, + PreviousMode, + (PVOID*)&Thread, + NULL); + if(NT_SUCCESS(Status)) + { + Status = ObReferenceObjectByHandle(ThreadToImpersonateHandle, + THREAD_DIRECT_IMPERSONATION, + PsThreadType, + PreviousMode, + (PVOID*)&ThreadToImpersonate, + NULL); + if(NT_SUCCESS(Status)) + { + Status = SeCreateClientSecurity(ThreadToImpersonate, + SecurityQualityOfService, + 0, + &ClientContext); + if(NT_SUCCESS(Status)) + { + SeImpersonateClient(&ClientContext, + Thread); + if(ClientContext.ClientToken != NULL) + { + ObDereferenceObject (ClientContext.ClientToken); + } + } + + ObDereferenceObject(ThreadToImpersonate); + } + ObDereferenceObject(Thread); + } + + return Status; +} + +/* + * @implemented + */ +PACCESS_TOKEN +STDCALL +PsReferenceImpersonationToken(IN PETHREAD Thread, + OUT PBOOLEAN CopyOnOpen, + OUT PBOOLEAN EffectiveOnly, + OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel) +{ + + if (Thread->ActiveImpersonationInfo == FALSE) { + + return NULL; + } + + *ImpersonationLevel = Thread->ImpersonationInfo->ImpersonationLevel; + *CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen; + *EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly; + + ObReferenceObjectByPointer(Thread->ImpersonationInfo->Token, + TOKEN_ALL_ACCESS, + SepTokenObjectType, + KernelMode); + + return Thread->ImpersonationInfo->Token; +} + +#ifdef PsDereferencePrimaryToken +#undef PsDereferenceImpersonationToken +#endif +/* + * @implemented + */ +VOID +STDCALL +PsDereferenceImpersonationToken(IN PACCESS_TOKEN ImpersonationToken) +{ + if (ImpersonationToken) { + + ObDereferenceObject(ImpersonationToken); + } +} + +#ifdef PsDereferencePrimaryToken +#undef PsDereferencePrimaryToken +#endif +/* + * @implemented + */ +VOID +STDCALL +PsDereferencePrimaryToken(IN PACCESS_TOKEN PrimaryToken) +{ + ObDereferenceObject(PrimaryToken); +} + +/* + * @implemented + */ +BOOLEAN +STDCALL +PsDisableImpersonation(IN PETHREAD Thread, + IN PSE_IMPERSONATION_STATE ImpersonationState) +{ + if (Thread->ActiveImpersonationInfo == FALSE) { + ImpersonationState->Token = NULL; + ImpersonationState->CopyOnOpen = FALSE; + ImpersonationState->EffectiveOnly = FALSE; + ImpersonationState->Level = 0; + return TRUE; + } + +/* FIXME */ +/* ExfAcquirePushLockExclusive(&Thread->ThreadLock); */ + + Thread->ActiveImpersonationInfo = FALSE; + ImpersonationState->Token = Thread->ImpersonationInfo->Token; + ImpersonationState->CopyOnOpen = Thread->ImpersonationInfo->CopyOnOpen; + ImpersonationState->EffectiveOnly = Thread->ImpersonationInfo->EffectiveOnly; + ImpersonationState->Level = Thread->ImpersonationInfo->ImpersonationLevel; + +/* FIXME */ +/* ExfReleasePushLock(&Thread->ThreadLock); */ + + return TRUE; +} + +/* + * @implemented + */ +VOID +STDCALL +PsRestoreImpersonation(IN PETHREAD Thread, + IN PSE_IMPERSONATION_STATE ImpersonationState) +{ + + PsImpersonateClient(Thread, + ImpersonationState->Token, + ImpersonationState->CopyOnOpen, + ImpersonationState->EffectiveOnly, + ImpersonationState->Level); + + ObfDereferenceObject(ImpersonationState->Token); +} + +/* EOF */ diff --git a/reactos/ntoskrnl/ps/suspend.c b/reactos/ntoskrnl/ps/suspend.c index 7e1d56ec5a5..3c2da35a037 100644 --- a/reactos/ntoskrnl/ps/suspend.c +++ b/reactos/ntoskrnl/ps/suspend.c @@ -14,112 +14,15 @@ #define NDEBUG #include -/* NOTES ********************************************************************** - * - */ - -/* GLOBALS *******************************************************************/ - -static FAST_MUTEX SuspendMutex; +ULONG +STDCALL +KeResumeThread(PKTHREAD Thread); +ULONG +STDCALL +KeSuspendThread(PKTHREAD Thread); /* FUNCTIONS *****************************************************************/ -VOID STDCALL -PiSuspendThreadRundownRoutine(PKAPC Apc) -{ -} - - -VOID STDCALL -PiSuspendThreadKernelRoutine(PKAPC Apc, - PKNORMAL_ROUTINE* NormalRoutine, - PVOID* NormalContext, - PVOID* SystemArgument1, - PVOID* SystemArguemnt2) -{ -} - - -VOID STDCALL -PiSuspendThreadNormalRoutine(PVOID NormalContext, - PVOID SystemArgument1, - PVOID SystemArgument2) -{ - PETHREAD CurrentThread = PsGetCurrentThread(); - while (CurrentThread->Tcb.SuspendCount > 0) - { - KeWaitForSingleObject(&CurrentThread->Tcb.SuspendSemaphore, - 0, - UserMode, - TRUE, - NULL); - } -} - - -NTSTATUS -PsResumeThread (PETHREAD Thread, - PULONG SuspendCount) -{ - DPRINT("PsResumeThread (Thread %p SuspendCount %p) called\n"); - - ExAcquireFastMutex (&SuspendMutex); - - if (SuspendCount != NULL) - { - *SuspendCount = Thread->Tcb.SuspendCount; - } - - if (Thread->Tcb.SuspendCount > 0) - { - Thread->Tcb.SuspendCount--; - if (Thread->Tcb.SuspendCount == 0) - { - KeReleaseSemaphore (&Thread->Tcb.SuspendSemaphore, - IO_NO_INCREMENT, - 1, - FALSE); - } - } - - ExReleaseFastMutex (&SuspendMutex); - - return STATUS_SUCCESS; -} - - -NTSTATUS -PsSuspendThread(PETHREAD Thread, PULONG PreviousSuspendCount) -{ - ULONG OldValue; - - ExAcquireFastMutex(&SuspendMutex); - OldValue = Thread->Tcb.SuspendCount; - Thread->Tcb.SuspendCount++; - if (!Thread->Tcb.SuspendApc.Inserted) - { - if (!KeInsertQueueApc(&Thread->Tcb.SuspendApc, - NULL, - NULL, - IO_NO_INCREMENT)) - { - Thread->Tcb.SuspendCount--; - ExReleaseFastMutex(&SuspendMutex); - return(STATUS_THREAD_IS_TERMINATING); - } - } - ExReleaseFastMutex(&SuspendMutex); - if (PreviousSuspendCount != NULL) - { - *PreviousSuspendCount = OldValue; - } - return(STATUS_SUCCESS); -} - - -NTSTATUS STDCALL -NtResumeThread(IN HANDLE ThreadHandle, - IN PULONG SuspendCount OPTIONAL) /* * FUNCTION: Decrements a thread's resume count * ARGUMENTS: @@ -127,48 +30,39 @@ NtResumeThread(IN HANDLE ThreadHandle, * ResumeCount = The resulting resume count. * RETURNS: Status */ +NTSTATUS +STDCALL +NtResumeThread(IN HANDLE ThreadHandle, + IN PULONG SuspendCount OPTIONAL) { - PETHREAD Thread; - NTSTATUS Status; - ULONG Count; + PETHREAD Thread; + NTSTATUS Status; - PAGED_CODE(); + PAGED_CODE(); - DPRINT("NtResumeThead(ThreadHandle %lx SuspendCount %p)\n", - ThreadHandle, SuspendCount); + DPRINT1("NtResumeThead(ThreadHandle %lx SuspendCount %p)\n", + ThreadHandle, SuspendCount); - Status = ObReferenceObjectByHandle (ThreadHandle, - THREAD_SUSPEND_RESUME, - PsThreadType, - UserMode, - (PVOID*)&Thread, - NULL); - if (!NT_SUCCESS(Status)) - { - return Status; + /* Get the Thread Object */ + Status = ObReferenceObjectByHandle(ThreadHandle, + THREAD_SUSPEND_RESUME, + PsThreadType, + KeGetPreviousMode(), + (PVOID*)&Thread, + NULL); + if (!NT_SUCCESS(Status)) { + + return Status; } + + /* Call the Kernel Function */ + *SuspendCount = KeResumeThread(&Thread->Tcb); - Status = PsResumeThread (Thread, &Count); - if (!NT_SUCCESS(Status)) - { - ObDereferenceObject ((PVOID)Thread); - return Status; - } - - if (SuspendCount != NULL) - { - *SuspendCount = Count; - } - - ObDereferenceObject ((PVOID)Thread); - - return STATUS_SUCCESS; + /* Dereference and Return */ + ObDereferenceObject ((PVOID)Thread); + return STATUS_SUCCESS; } - -NTSTATUS STDCALL -NtSuspendThread(IN HANDLE ThreadHandle, - IN PULONG PreviousSuspendCount OPTIONAL) /* * FUNCTION: Increments a thread's suspend count * ARGUMENTS: @@ -182,45 +76,34 @@ NtSuspendThread(IN HANDLE ThreadHandle, * MAXIMUM_SUSPEND_COUNT. * RETURNS: Status */ +NTSTATUS +STDCALL +NtSuspendThread(IN HANDLE ThreadHandle, + IN PULONG PreviousSuspendCount OPTIONAL) { - PETHREAD Thread; - NTSTATUS Status; - ULONG Count; + PETHREAD Thread; + NTSTATUS Status; - PAGED_CODE(); + PAGED_CODE(); - Status = ObReferenceObjectByHandle(ThreadHandle, - THREAD_SUSPEND_RESUME, - PsThreadType, - UserMode, - (PVOID*)&Thread, - NULL); - if (!NT_SUCCESS(Status)) - { - return(Status); + /* Get the Thread Object */ + Status = ObReferenceObjectByHandle(ThreadHandle, + THREAD_SUSPEND_RESUME, + PsThreadType, + KeGetPreviousMode(), + (PVOID*)&Thread, + NULL); + if (!NT_SUCCESS(Status)) { + + return Status; } + + /* Call the Kernel Function */ + *PreviousSuspendCount = KeSuspendThread(&Thread->Tcb); - Status = PsSuspendThread(Thread, &Count); - if (!NT_SUCCESS(Status)) - { - ObDereferenceObject ((PVOID)Thread); - return Status; - } - - if (PreviousSuspendCount != NULL) - { - *PreviousSuspendCount = Count; - } - - ObDereferenceObject ((PVOID)Thread); - - return STATUS_SUCCESS; -} - -VOID INIT_FUNCTION -PsInitialiseSuspendImplementation(VOID) -{ - ExInitializeFastMutex(&SuspendMutex); + /* Dereference and Return */ + ObDereferenceObject((PVOID)Thread); + return STATUS_SUCCESS; } /* EOF */ diff --git a/reactos/ntoskrnl/ps/thread.c b/reactos/ntoskrnl/ps/thread.c index 08a0a10dd02..e91b58986ba 100644 --- a/reactos/ntoskrnl/ps/thread.c +++ b/reactos/ntoskrnl/ps/thread.c @@ -23,8 +23,6 @@ #define NDEBUG #include -/* TYPES *******************************************************************/ - /* GLOBALS ******************************************************************/ extern LIST_ENTRY PsActiveProcessHead; @@ -32,20 +30,12 @@ extern PEPROCESS PsIdleProcess; POBJECT_TYPE EXPORTED PsThreadType = NULL; -LONG PiNrThreadsAwaitingReaping = 0; - extern PVOID Ki386InitialStackArray[MAXIMUM_PROCESSORS]; +extern ULONG IdleProcessorMask; +extern LIST_ENTRY PriorityListHead[MAXIMUM_PRIORITY]; -/* - * PURPOSE: List of threads associated with each priority level - */ -static LIST_ENTRY PriorityListHead[MAXIMUM_PRIORITY]; -static ULONG PriorityListMask = 0; -static ULONG IdleProcessorMask = 0; -static BOOLEAN DoneInitYet = FALSE; -static KEVENT PiReaperThreadEvent; -static BOOLEAN PiReaperThreadShouldTerminate = FALSE; +BOOLEAN DoneInitYet = FALSE; static GENERIC_MAPPING PiThreadMapping = {STANDARD_RIGHTS_READ | THREAD_GET_CONTEXT | THREAD_QUERY_INFORMATION, STANDARD_RIGHTS_WRITE | THREAD_TERMINATE | THREAD_SUSPEND_RESUME | THREAD_ALERT | THREAD_SET_INFORMATION | THREAD_SET_CONTEXT, @@ -222,16 +212,13 @@ PsIsThreadTerminating(IN PETHREAD Thread) } /* - * @unimplemented + * @implemented */ BOOLEAN STDCALL -PsIsSystemThread( - PETHREAD Thread - ) +PsIsSystemThread(PETHREAD Thread) { - UNIMPLEMENTED; - return FALSE; + return (Thread->SystemThread ? TRUE: FALSE); } /* @@ -246,41 +233,6 @@ PsIsThreadImpersonating( return Thread->ActiveImpersonationInfo; } -static VOID -KiRequestReschedule(CCHAR Processor) -{ - PKPCR Pcr; - - Pcr = (PKPCR)(KPCR_BASE + Processor * PAGE_SIZE); - Pcr->Prcb->QuantumEnd = TRUE; - KiIpiSendRequest(1 << Processor, IPI_REQUEST_DPC); -} - -static VOID -PsInsertIntoThreadList(KPRIORITY Priority, PETHREAD Thread) -{ - ASSERT(THREAD_STATE_READY == Thread->Tcb.State); - ASSERT(Thread->Tcb.Priority == Priority); - if (Priority >= MAXIMUM_PRIORITY || Priority < LOW_PRIORITY) - { - DPRINT1("Invalid thread priority (%d)\n", Priority); - KEBUGCHECK(0); - } - InsertTailList(&PriorityListHead[Priority], &Thread->Tcb.QueueListEntry); - PriorityListMask |= (1 << Priority); -} - -static VOID PsRemoveFromThreadList(PETHREAD Thread) -{ - ASSERT(THREAD_STATE_READY == Thread->Tcb.State); - RemoveEntryList(&Thread->Tcb.QueueListEntry); - if (IsListEmpty(&PriorityListHead[(ULONG)Thread->Tcb.Priority])) - { - PriorityListMask &= ~(1 << Thread->Tcb.Priority); - } -} - - VOID PsDumpThreads(BOOLEAN IncludeSystem) { PLIST_ENTRY AThread, AProcess; @@ -335,259 +287,6 @@ VOID PsDumpThreads(BOOLEAN IncludeSystem) } } -static PETHREAD PsScanThreadList(KPRIORITY Priority, ULONG Affinity) -{ - PLIST_ENTRY current_entry; - PETHREAD current; - ULONG Mask; - - Mask = (1 << Priority); - if (PriorityListMask & Mask) - { - current_entry = PriorityListHead[Priority].Flink; - while (current_entry != &PriorityListHead[Priority]) - { - current = CONTAINING_RECORD(current_entry, ETHREAD, - Tcb.QueueListEntry); - if (current->Tcb.State != THREAD_STATE_READY) - { - DPRINT1("%d/%d\n", current->Cid.UniqueThread, current->Tcb.State); - } - ASSERT(current->Tcb.State == THREAD_STATE_READY); - DPRINT("current->Tcb.Affinity %x Affinity %x PID %d %d\n", - current->Tcb.Affinity, Affinity, current->Cid.UniqueThread, - Priority); - if (current->Tcb.Affinity & Affinity) - { - PsRemoveFromThreadList(current); - return(current); - } - current_entry = current_entry->Flink; - } - } - return(NULL); -} - -VOID STDCALL -PiWakeupReaperThread(VOID) -{ - KeSetEvent(&PiReaperThreadEvent, 0, FALSE); -} - -VOID STDCALL -PiReaperThreadMain(PVOID Ignored) -{ - for(;;) - { - KeWaitForSingleObject(&PiReaperThreadEvent, - Executive, - KernelMode, - FALSE, - NULL); - if (PiReaperThreadShouldTerminate) - { - PsTerminateSystemThread(0); - } - PsReapThreads(); - } -} - -VOID PsDispatchThreadNoLock (ULONG NewThreadStatus) -{ - KPRIORITY CurrentPriority; - PETHREAD Candidate; - ULONG Affinity; - PKTHREAD KCurrentThread = KeGetCurrentThread(); - PETHREAD CurrentThread = CONTAINING_RECORD(KCurrentThread, ETHREAD, Tcb); - - DPRINT("PsDispatchThread() %d/%d/%d/%d\n", KeGetCurrentProcessorNumber(), - CurrentThread->Cid.UniqueThread, NewThreadStatus, CurrentThread->Tcb.State); - - CurrentThread->Tcb.State = (UCHAR)NewThreadStatus; - switch(NewThreadStatus) - { - case THREAD_STATE_READY: - PsInsertIntoThreadList(CurrentThread->Tcb.Priority, - CurrentThread); - break; - case THREAD_STATE_TERMINATED_1: - PsQueueThreadReap(CurrentThread); - break; - } - - Affinity = 1 << KeGetCurrentProcessorNumber(); - for (CurrentPriority = HIGH_PRIORITY; - CurrentPriority >= LOW_PRIORITY; - CurrentPriority--) - { - Candidate = PsScanThreadList(CurrentPriority, Affinity); - if (Candidate == CurrentThread) - { - Candidate->Tcb.State = THREAD_STATE_RUNNING; - KeReleaseDispatcherDatabaseLockFromDpcLevel(); - return; - } - if (Candidate != NULL) - { - PETHREAD OldThread; - PKTHREAD IdleThread; - - DPRINT("Scheduling %x(%d)\n",Candidate, CurrentPriority); - - Candidate->Tcb.State = THREAD_STATE_RUNNING; - - OldThread = CurrentThread; - CurrentThread = Candidate; - IdleThread = KeGetCurrentPrcb()->IdleThread; - - if (&OldThread->Tcb == IdleThread) - { - IdleProcessorMask &= ~Affinity; - } - else if (&CurrentThread->Tcb == IdleThread) - { - IdleProcessorMask |= Affinity; - } - - MmUpdatePageDir(PsGetCurrentProcess(),(PVOID)CurrentThread->ThreadsProcess, sizeof(EPROCESS)); - - KiArchContextSwitch(&CurrentThread->Tcb, &OldThread->Tcb); - return; - } - } - CPRINT("CRITICAL: No threads are ready (CPU%d)\n", KeGetCurrentProcessorNumber()); - PsDumpThreads(TRUE); - KEBUGCHECK(0); -} - -VOID STDCALL -PsDispatchThread(ULONG NewThreadStatus) -{ - KIRQL oldIrql; - - if (!DoneInitYet || KeGetCurrentPrcb()->IdleThread == NULL) - { - return; - } - oldIrql = KeAcquireDispatcherDatabaseLock(); - PsDispatchThreadNoLock(NewThreadStatus); - KeLowerIrql(oldIrql); -} - -VOID -PsUnblockThread(PETHREAD Thread, PNTSTATUS WaitStatus, KPRIORITY Increment) -{ - if (THREAD_STATE_TERMINATED_1 == Thread->Tcb.State || - THREAD_STATE_TERMINATED_2 == Thread->Tcb.State) - { - DPRINT("Can't unblock thread %d because it's terminating\n", - Thread->Cid.UniqueThread); - } - else if (THREAD_STATE_READY == Thread->Tcb.State || - THREAD_STATE_RUNNING == Thread->Tcb.State) - { - DPRINT("Can't unblock thread %d because it's ready or running\n", - Thread->Cid.UniqueThread); - } - else - { - ULONG Processor; - KAFFINITY Affinity; - - /* FIXME: This propably isn't the right way to do it... */ - if (Thread->Tcb.Priority < LOW_REALTIME_PRIORITY && - Thread->Tcb.BasePriority < LOW_REALTIME_PRIORITY - 2) - { - if (!Thread->Tcb.PriorityDecrement && !Thread->Tcb.DisableBoost) - { - Thread->Tcb.Priority = Thread->Tcb.BasePriority + Increment; - Thread->Tcb.PriorityDecrement = Increment; - } - } - else - { - Thread->Tcb.Quantum = Thread->Tcb.ApcState.Process->ThreadQuantum; - } - - if (WaitStatus != NULL) - { - Thread->Tcb.WaitStatus = *WaitStatus; - } - Thread->Tcb.State = THREAD_STATE_READY; - PsInsertIntoThreadList(Thread->Tcb.Priority, Thread); - Processor = KeGetCurrentProcessorNumber(); - Affinity = Thread->Tcb.Affinity; - if (!(IdleProcessorMask & (1 << Processor) & Affinity) && - (IdleProcessorMask & ~(1 << Processor) & Affinity)) - { - ULONG i; - for (i = 0; i < KeNumberProcessors - 1; i++) - { - Processor++; - if (Processor >= KeNumberProcessors) - { - Processor = 0; - } - if (IdleProcessorMask & (1 << Processor) & Affinity) - { -#if 0 - /* FIXME: - * Reschedule the threads on an other processor - */ - KeReleaseDispatcherDatabaseLockFromDpcLevel(); - KiRequestReschedule(Processor); - KeAcquireDispatcherDatabaseLockAtDpcLevel(); -#endif - break; - } - } - } - } -} - -VOID -STDCALL -PsBlockThread(PNTSTATUS Status, - UCHAR Alertable, - ULONG WaitMode, - UCHAR WaitReason) -{ - PKTHREAD Thread = KeGetCurrentThread(); - PKWAIT_BLOCK WaitBlock; - - if (Thread->ApcState.KernelApcPending) { - - DPRINT("Dispatching Thread as ready (APC!)\n"); - - /* Remove Waits */ - WaitBlock = Thread->WaitBlockList; - while (WaitBlock) { - RemoveEntryList (&WaitBlock->WaitListEntry); - WaitBlock = WaitBlock->NextWaitBlock; - } - Thread->WaitBlockList = NULL; - - /* Dispatch it and return status */ - PsDispatchThreadNoLock (THREAD_STATE_READY); - if (Status != NULL) *Status = STATUS_KERNEL_APC; - - } else { - - /* Set the Thread Data as Requested */ - DPRINT("Dispatching Thread as blocked\n"); - Thread->Alertable = Alertable; - Thread->WaitMode = (UCHAR)WaitMode; - Thread->WaitReason = WaitReason; - - /* Dispatch it and return status */ - PsDispatchThreadNoLock(THREAD_STATE_BLOCKED); - if (Status != NULL) *Status = Thread->WaitStatus; - } - - DPRINT("Releasing Dispatcher Lock\n"); - KfLowerIrql(Thread->WaitIrql); -} - VOID PsFreezeAllThreads(PEPROCESS Process) /* @@ -751,7 +450,7 @@ PsInitThreadManagment(VOID) PsThreadType->Dump = NULL; PsThreadType->Open = NULL; PsThreadType->Close = NULL; - PsThreadType->Delete = PiDeleteThread; + PsThreadType->Delete = PspDeleteThread; PsThreadType->Parse = NULL; PsThreadType->Security = NULL; PsThreadType->QueryName = NULL; @@ -773,219 +472,11 @@ PsInitThreadManagment(VOID) DPRINT("FirstThread %x\n",FirstThread); DoneInitYet = TRUE; -} - -VOID -PsInitReaperThread(VOID) -{ - PETHREAD ReaperThread; - KIRQL oldIrql; - NTSTATUS Status; - /* - * Create the reaper thread - */ - PsInitializeThreadReaper(); - KeInitializeEvent(&PiReaperThreadEvent, SynchronizationEvent, FALSE); - Status = PsInitializeThread(NULL, - &ReaperThread, - NULL, - KernelMode, - FALSE); - if (!NT_SUCCESS(Status)) - { - DPRINT1("PS: Failed to create reaper thread.\n"); - KEBUGCHECK(0); - } - - ReaperThread->StartAddress = PiReaperThreadMain; - Status = KiArchInitThread(&ReaperThread->Tcb, PiReaperThreadMain, NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT1("PS: Failed to initialize reaper thread.\n"); - KEBUGCHECK(0); - } - - oldIrql = KeAcquireDispatcherDatabaseLock (); - PsUnblockThread(ReaperThread, NULL, 0); - KeReleaseDispatcherDatabaseLock(oldIrql); + InitializeListHead(&PspReaperListHead); + ExInitializeWorkItem(&PspReaperWorkItem, PspReapRoutine, NULL); } -/* - * @implemented - */ -LONG STDCALL -KeSetBasePriorityThread (PKTHREAD Thread, - LONG Increment) -/* - * Sets thread's base priority relative to the process' base priority - * Should only be passed in THREAD_PRIORITY_ constants in pstypes.h - */ -{ - KPRIORITY Priority; - if (Increment < -2) - { - Increment = -2; - } - else if (Increment > 2) - { - Increment = 2; - } - Priority = ((PETHREAD)Thread)->ThreadsProcess->Pcb.BasePriority + Increment; - if (Priority < LOW_PRIORITY) - { - Priority = LOW_PRIORITY; - } - else if (Priority >= MAXIMUM_PRIORITY) - { - Thread->BasePriority = HIGH_PRIORITY; - } - KeSetPriorityThread(Thread, Priority); - return 1; -} - - -/* - * @implemented - */ -KPRIORITY STDCALL -KeSetPriorityThread (PKTHREAD Thread, KPRIORITY Priority) -{ - KPRIORITY OldPriority; - KIRQL oldIrql; - PKTHREAD CurrentThread; - ULONG Mask; - int i; - PKPCR Pcr; - - if (Priority < LOW_PRIORITY || Priority >= MAXIMUM_PRIORITY) - { - KEBUGCHECK(0); - } - - oldIrql = KeAcquireDispatcherDatabaseLock(); - - OldPriority = Thread->Priority; - - if (OldPriority != Priority) - { - CurrentThread = KeGetCurrentThread(); - if (Thread->State == THREAD_STATE_READY) - { - PsRemoveFromThreadList((PETHREAD)Thread); - Thread->BasePriority = Thread->Priority = (CHAR)Priority; - PsInsertIntoThreadList(Priority, (PETHREAD)Thread); - if (CurrentThread->Priority < Priority) - { - PsDispatchThreadNoLock(THREAD_STATE_READY); - KeLowerIrql(oldIrql); - return (OldPriority); - } - } - else if (Thread->State == THREAD_STATE_RUNNING) - { - Thread->BasePriority = Thread->Priority = (CHAR)Priority; - if (Priority < OldPriority) - { - /* Check for threads with a higher priority */ - Mask = ~((1 << (Priority + 1)) - 1); - if (PriorityListMask & Mask) - { - if (Thread == CurrentThread) - { - PsDispatchThreadNoLock(THREAD_STATE_READY); - KeLowerIrql(oldIrql); - return (OldPriority); - } - else - { - for (i = 0; i < KeNumberProcessors; i++) - { - Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE); - if (Pcr->Prcb->CurrentThread == Thread) - { - KeReleaseDispatcherDatabaseLockFromDpcLevel(); - KiRequestReschedule(i); - KeLowerIrql(oldIrql); - return (OldPriority); - } - } - } - } - } - } - else - { - Thread->BasePriority = Thread->Priority = (CHAR)Priority; - } - } - KeReleaseDispatcherDatabaseLock(oldIrql); - return(OldPriority); -} - -/* - * @unimplemented - */ -NTSTATUS STDCALL -KeSetAffinityThread(PKTHREAD Thread, - KAFFINITY Affinity) -/* - * Sets thread's affinity - */ -{ - KIRQL oldIrql; - ULONG i; - PKPCR Pcr; - KAFFINITY ProcessorMask; - - DPRINT("KeSetAffinityThread(Thread %x, Affinity %x)\n", Thread, Affinity); - - ASSERT(Affinity & ((1 << KeNumberProcessors) - 1)); - - oldIrql = KeAcquireDispatcherDatabaseLock(); - - Thread->UserAffinity = Affinity; - if (Thread->SystemAffinityActive == FALSE) - { - Thread->Affinity = Affinity; - if (Thread->State == THREAD_STATE_RUNNING) - { - ProcessorMask = 1 << KeGetCurrentKPCR()->ProcessorNumber; - if (Thread == KeGetCurrentThread()) - { - if (!(Affinity & ProcessorMask)) - { - PsDispatchThreadNoLock(THREAD_STATE_READY); - KeLowerIrql(oldIrql); - return STATUS_SUCCESS; - } - } - else - { - for (i = 0; i < KeNumberProcessors; i++) - { - Pcr = (PKPCR)(KPCR_BASE + i * PAGE_SIZE); - if (Pcr->Prcb->CurrentThread == Thread) - { - if (!(Affinity & ProcessorMask)) - { - KeReleaseDispatcherDatabaseLockFromDpcLevel(); - KiRequestReschedule(i); - KeLowerIrql(oldIrql); - return STATUS_SUCCESS; - } - break; - } - } - ASSERT (i < KeNumberProcessors); - } - } - } - KeReleaseDispatcherDatabaseLock(oldIrql); - return STATUS_SUCCESS; -} - - /********************************************************************** * NtOpenThread/4 * @@ -1088,7 +579,7 @@ NtOpenThread(OUT PHANDLE ThreadHandle, NTSTATUS STDCALL NtYieldExecution(VOID) { - PsDispatchThread(THREAD_STATE_READY); + KiDispatchThread(THREAD_STATE_READY); return(STATUS_SUCCESS); } @@ -1103,68 +594,30 @@ NtTestAlert(VOID) return KeTestAlertThread(ExGetPreviousMode()) ? STATUS_ALERTED : STATUS_SUCCESS; } - -/* - * @implemented - */ -NTSTATUS STDCALL -PsLookupProcessThreadByCid(IN PCLIENT_ID Cid, - OUT PEPROCESS *Process OPTIONAL, - OUT PETHREAD *Thread) +VOID +KeSetPreviousMode (ULONG Mode) { - PHANDLE_TABLE_ENTRY CidEntry; - PETHREAD FoundThread; - - PAGED_CODE(); - - ASSERT(Thread); - ASSERT(Cid); - - CidEntry = PsLookupCidHandle(Cid->UniqueThread, PsThreadType, (PVOID*)&FoundThread); - if(CidEntry != NULL) - { - ObReferenceObject(FoundThread); - - PsUnlockCidHandle(CidEntry); - - if(Process != NULL) - { - *Process = FoundThread->ThreadsProcess; - } - *Thread = FoundThread; - return STATUS_SUCCESS; - } - - return STATUS_INVALID_PARAMETER; + PsGetCurrentThread()->Tcb.PreviousMode = (UCHAR)Mode; } /* * @implemented */ -NTSTATUS STDCALL -PsLookupThreadByThreadId(IN HANDLE ThreadId, - OUT PETHREAD *Thread) +KPROCESSOR_MODE STDCALL +KeGetPreviousMode (VOID) { - PHANDLE_TABLE_ENTRY CidEntry; - PETHREAD FoundThread; + return (ULONG)PsGetCurrentThread()->Tcb.PreviousMode; +} - PAGED_CODE(); - ASSERT(Thread); - - CidEntry = PsLookupCidHandle(ThreadId, PsThreadType, (PVOID*)&FoundThread); - if(CidEntry != NULL) - { - ObReferenceObject(FoundThread); - - PsUnlockCidHandle(CidEntry); - - *Thread = FoundThread; - return STATUS_SUCCESS; - } - - return STATUS_INVALID_PARAMETER; +/* + * @implemented + */ +KPROCESSOR_MODE STDCALL +ExGetPreviousMode (VOID) +{ + return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode; } /* EOF */ diff --git a/reactos/ntoskrnl/ps/tinfo.c b/reactos/ntoskrnl/ps/tinfo.c deleted file mode 100644 index c9ca051d48f..00000000000 --- a/reactos/ntoskrnl/ps/tinfo.c +++ /dev/null @@ -1,337 +0,0 @@ -/* $Id$ - * - * COPYRIGHT: See COPYING in the top level directory - * PROJECT: ReactOS kernel - * FILE: ntoskrnl/ps/tinfo.c - * PURPOSE: Getting/setting thread information - * - * PROGRAMMERS: David Welch (welch@mcmail.com) - * Skywing (skywing@valhallalegends.com) - */ - -/* INCLUDES *****************************************************************/ - -#include -#include - -/* GLOBALS *****************************************************************/ - -/* - * FIXME: - * Remove the Implemented value if all functions are implemented. - */ - -static const struct -{ - BOOLEAN Implemented; - ULONG Size; -} QueryInformationData[MaxThreadInfoClass + 1] = -{ - {TRUE, sizeof(THREAD_BASIC_INFORMATION)}, // ThreadBasicInformation - {TRUE, sizeof(KERNEL_USER_TIMES)}, // ThreadTimes - {TRUE, 0}, // ThreadPriority - {TRUE, 0}, // ThreadBasePriority - {TRUE, 0}, // ThreadAffinityMask - {TRUE, 0}, // ThreadImpersonationToken - {FALSE, 0}, // ThreadDescriptorTableEntry - {TRUE, 0}, // ThreadEnableAlignmentFaultFixup - {TRUE, 0}, // ThreadEventPair - {TRUE, sizeof(PVOID)}, // ThreadQuerySetWin32StartAddress - {TRUE, 0}, // ThreadZeroTlsCell - {TRUE, sizeof(LARGE_INTEGER)}, // ThreadPerformanceCount - {TRUE, sizeof(BOOLEAN)}, // ThreadAmILastThread - {TRUE, 0}, // ThreadIdealProcessor - {FALSE, 0}, // ThreadPriorityBoost - {TRUE, 0}, // ThreadSetTlsArrayAddress - {FALSE, 0}, // ThreadIsIoPending - {TRUE, 0} // ThreadHideFromDebugger -}; - -static const struct -{ - BOOLEAN Implemented; - ULONG Size; -} SetInformationData[MaxThreadInfoClass + 1] = -{ - {TRUE, 0}, // ThreadBasicInformation - {TRUE, 0}, // ThreadTimes - {TRUE, sizeof(KPRIORITY)}, // ThreadPriority - {TRUE, sizeof(LONG)}, // ThreadBasePriority - {TRUE, sizeof(KAFFINITY)}, // ThreadAffinityMask - {TRUE, sizeof(HANDLE)}, // ThreadImpersonationToken - {TRUE, 0}, // ThreadDescriptorTableEntry - {FALSE, 0}, // ThreadEnableAlignmentFaultFixup -#ifdef _ENABLE_THRDEVTPAIR - {TRUE, sizeof(HANDLE)}, // ThreadEventPair -#else - {FALSE, 0}, // ThreadEventPair -#endif - {TRUE, sizeof(PVOID)}, // ThreadQuerySetWin32StartAddress - {FALSE, 0}, // ThreadZeroTlsCell - {TRUE, 0}, // ThreadPerformanceCount - {TRUE, 0}, // ThreadAmILastThread - {FALSE, 0}, // ThreadIdealProcessor - {FALSE, 0}, // ThreadPriorityBoost - {FALSE, 0}, // ThreadSetTlsArrayAddress - {TRUE, 0}, // ThreadIsIoPending - {FALSE, 0} // ThreadHideFromDebugger -}; - -/* FUNCTIONS *****************************************************************/ - -/* - * @unimplemented - */ -NTSTATUS STDCALL -NtSetInformationThread (IN HANDLE ThreadHandle, - IN THREADINFOCLASS ThreadInformationClass, - IN PVOID ThreadInformation, - IN ULONG ThreadInformationLength) -{ - PETHREAD Thread; - NTSTATUS Status; - union - { - KPRIORITY Priority; - LONG Increment; - KAFFINITY Affinity; - HANDLE Handle; - PVOID Address; - }u; - - PAGED_CODE(); - - if (ThreadInformationClass <= MaxThreadInfoClass && - !SetInformationData[ThreadInformationClass].Implemented) - { - return STATUS_NOT_IMPLEMENTED; - } - if (ThreadInformationClass > MaxThreadInfoClass || - SetInformationData[ThreadInformationClass].Size == 0) - { - return STATUS_INVALID_INFO_CLASS; - } - if (ThreadInformationLength != SetInformationData[ThreadInformationClass].Size) - { - return STATUS_INFO_LENGTH_MISMATCH; - } - - Status = ObReferenceObjectByHandle (ThreadHandle, - THREAD_SET_INFORMATION, - PsThreadType, - ExGetPreviousMode (), - (PVOID*)&Thread, - NULL); - if (!NT_SUCCESS(Status)) - { - return Status; - } - - Status = MmCopyFromCaller(&u.Priority, - ThreadInformation, - SetInformationData[ThreadInformationClass].Size); - if (NT_SUCCESS(Status)) - { - switch (ThreadInformationClass) - { - case ThreadPriority: - if (u.Priority < LOW_PRIORITY || u.Priority >= MAXIMUM_PRIORITY) - { - Status = STATUS_INVALID_PARAMETER; - break; - } - KeSetPriorityThread(&Thread->Tcb, u.Priority); - break; - - case ThreadBasePriority: - KeSetBasePriorityThread (&Thread->Tcb, u.Increment); - break; - - case ThreadAffinityMask: - Status = KeSetAffinityThread(&Thread->Tcb, u.Affinity); - break; - - case ThreadImpersonationToken: - Status = PsAssignImpersonationToken (Thread, u.Handle); - break; - -#ifdef _ENABLE_THRDEVTPAIR - case ThreadEventPair: - { - PKEVENT_PAIR EventPair; - - Status = ObReferenceObjectByHandle(u.Handle, - STANDARD_RIGHTS_ALL, - ExEventPairObjectType, - ExGetPreviousMode(), - (PVOID*)&EventPair, - NULL); - if (NT_SUCCESS(Status)) - { - ExpSwapThreadEventPair(Thread, EventPair); /* Note that the extra reference is kept intentionally */ - } - break; - } -#endif /* _ENABLE_THRDEVTPAIR */ - - case ThreadQuerySetWin32StartAddress: - Thread->Win32StartAddress = u.Address; - break; - - default: - /* Shoult never occure if the data table is correct */ - KEBUGCHECK(0); - } - } - ObDereferenceObject (Thread); - - return Status; -} - -/* - * @implemented - */ -NTSTATUS STDCALL -NtQueryInformationThread (IN HANDLE ThreadHandle, - IN THREADINFOCLASS ThreadInformationClass, - OUT PVOID ThreadInformation, - IN ULONG ThreadInformationLength, - OUT PULONG ReturnLength OPTIONAL) -{ - PETHREAD Thread; - NTSTATUS Status; - union - { - THREAD_BASIC_INFORMATION TBI; - KERNEL_USER_TIMES TTI; - PVOID Address; - LARGE_INTEGER Count; - BOOLEAN Last; - }u; - - PAGED_CODE(); - - if (ThreadInformationClass <= MaxThreadInfoClass && - !QueryInformationData[ThreadInformationClass].Implemented) - { - return STATUS_NOT_IMPLEMENTED; - } - if (ThreadInformationClass > MaxThreadInfoClass || - QueryInformationData[ThreadInformationClass].Size == 0) - { - return STATUS_INVALID_INFO_CLASS; - } - if (ThreadInformationLength != QueryInformationData[ThreadInformationClass].Size) - { - return STATUS_INFO_LENGTH_MISMATCH; - } - - Status = ObReferenceObjectByHandle(ThreadHandle, - THREAD_QUERY_INFORMATION, - PsThreadType, - ExGetPreviousMode(), - (PVOID*)&Thread, - NULL); - if (!NT_SUCCESS(Status)) - { - return Status; - } - - switch (ThreadInformationClass) - { - case ThreadBasicInformation: - /* A test on W2K agains ntdll shows NtQueryInformationThread return STATUS_PENDING - * as ExitStatus for current/running thread, while KETHREAD's ExitStatus is - * 0. So do the conversion here: - * -Gunnar */ - u.TBI.ExitStatus = (Thread->ExitStatus == 0) ? STATUS_PENDING : Thread->ExitStatus; - u.TBI.TebBaseAddress = Thread->Tcb.Teb; - u.TBI.ClientId = Thread->Cid; - u.TBI.AffinityMask = Thread->Tcb.Affinity; - u.TBI.Priority = Thread->Tcb.Priority; - u.TBI.BasePriority = Thread->Tcb.BasePriority; - break; - - case ThreadTimes: - u.TTI.KernelTime.QuadPart = Thread->Tcb.KernelTime * 100000LL; - u.TTI.UserTime.QuadPart = Thread->Tcb.UserTime * 100000LL; - u.TTI.CreateTime = Thread->CreateTime; - /*This works*/ - u.TTI.ExitTime = Thread->ExitTime; - break; - - case ThreadQuerySetWin32StartAddress: - u.Address = Thread->Win32StartAddress; - break; - - case ThreadPerformanceCount: - /* Nebbett says this class is always zero */ - u.Count.QuadPart = 0; - break; - - case ThreadAmILastThread: - if (Thread->ThreadsProcess->ThreadListHead.Flink->Flink == - &Thread->ThreadsProcess->ThreadListHead) - { - u.Last = TRUE; - } - else - { - u.Last = FALSE; - } - break; - default: - /* Shoult never occure if the data table is correct */ - KEBUGCHECK(0); - } - if (QueryInformationData[ThreadInformationClass].Size) - { - Status = MmCopyToCaller(ThreadInformation, - &u.TBI, - QueryInformationData[ThreadInformationClass].Size); - } - if (ReturnLength) - { - NTSTATUS Status2; - static ULONG Null = 0; - Status2 = MmCopyToCaller(ReturnLength, - NT_SUCCESS(Status) ? &QueryInformationData[ThreadInformationClass].Size : &Null, - sizeof(ULONG)); - if (NT_SUCCESS(Status)) - { - Status = Status2; - } - } - - ObDereferenceObject(Thread); - return(Status); -} - - -VOID -KeSetPreviousMode (ULONG Mode) -{ - PsGetCurrentThread()->Tcb.PreviousMode = (UCHAR)Mode; -} - - -/* - * @implemented - */ -KPROCESSOR_MODE STDCALL -KeGetPreviousMode (VOID) -{ - return (ULONG)PsGetCurrentThread()->Tcb.PreviousMode; -} - - -/* - * @implemented - */ -KPROCESSOR_MODE STDCALL -ExGetPreviousMode (VOID) -{ - return (KPROCESSOR_MODE)PsGetCurrentThread()->Tcb.PreviousMode; -} - -/* EOF */