1 /* $Id: thread.c,v 1.132 2004/08/15 16:39:10 chorns Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ps/thread.c
6 * PURPOSE: Thread managment
7 * PROGRAMMER: David Welch (welch@mcmail.com)
10 * 12/10/99: Phillip Susi: Thread priorities, and APC work
16 * All of the routines that manipulate the thread queue synchronize on
21 /* INCLUDES ****************************************************************/
25 #include <internal/debug.h>
27 /* TYPES *******************************************************************/
29 /* GLOBALS ******************************************************************/
31 POBJECT_TYPE EXPORTED PsThreadType
= NULL
;
33 KSPIN_LOCK PiThreadListLock
;
36 * PURPOSE: List of threads associated with each priority level
38 LIST_ENTRY PiThreadListHead
;
39 static LIST_ENTRY PriorityListHead
[MAXIMUM_PRIORITY
];
40 static ULONG PriorityListMask
= 0;
41 static BOOLEAN DoneInitYet
= FALSE
;
42 static PETHREAD IdleThreads
[MAXIMUM_PROCESSORS
];
43 ULONG PiNrThreads
= 0;
44 ULONG PiNrReadyThreads
= 0;
45 static HANDLE PiReaperThreadHandle
;
46 static KEVENT PiReaperThreadEvent
;
47 static BOOLEAN PiReaperThreadShouldTerminate
= FALSE
;
48 ULONG PiNrThreadsAwaitingReaping
= 0;
50 static GENERIC_MAPPING PiThreadMapping
= {THREAD_READ
,
55 /* FUNCTIONS ***************************************************************/
60 PKTHREAD STDCALL
KeGetCurrentThread(VOID
)
62 return(((PIKPCR
) KeGetCurrentKPCR())->CurrentThread
);
68 HANDLE STDCALL
PsGetCurrentThreadId(VOID
)
70 return(PsGetCurrentThread()->Cid
.UniqueThread
);
78 PsGetThreadFreezeCount(
82 return Thread
->Tcb
.FreezeCount
;
90 PsGetThreadHardErrorsAreDisabled(
94 return Thread
->HardErrorsAreDisabled
;
106 return Thread
->Cid
.UniqueThread
;
118 return Thread
->ThreadsProcess
;
126 PsGetThreadProcessId(
130 return Thread
->Cid
.UniqueProcess
;
138 PsGetThreadSessionId(
142 return (HANDLE
)Thread
->ThreadsProcess
->SessionId
;
154 return Thread
->Tcb
.Teb
;
162 PsGetThreadWin32Thread(
166 return Thread
->Win32Thread
;
173 PsGetCurrentThreadPreviousMode (
177 return (KPROCESSOR_MODE
)PsGetCurrentThread()->Tcb
.PreviousMode
;
185 PsGetCurrentThreadStackBase (
189 return PsGetCurrentThread()->Tcb
.StackBase
;
197 PsGetCurrentThreadStackLimit (
201 return (PVOID
)PsGetCurrentThread()->Tcb
.StackLimit
;
208 PsIsThreadTerminating(IN PETHREAD Thread
)
210 return(Thread
->DeadThread
);
231 PsIsThreadImpersonating(
240 PsInsertIntoThreadList(KPRIORITY Priority
, PETHREAD Thread
)
242 assert(THREAD_STATE_READY
== Thread
->Tcb
.State
);
243 if (Priority
>= MAXIMUM_PRIORITY
|| Priority
< LOW_PRIORITY
)
245 DPRINT1("Invalid thread priority (%d)\n", Priority
);
248 InsertTailList(&PriorityListHead
[Priority
], &Thread
->Tcb
.QueueListEntry
);
249 PriorityListMask
|= (1 << Priority
);
253 static VOID
PsRemoveFromThreadList(PETHREAD Thread
)
255 assert(THREAD_STATE_READY
== Thread
->Tcb
.State
);
256 RemoveEntryList(&Thread
->Tcb
.QueueListEntry
);
257 if (IsListEmpty(&PriorityListHead
[(ULONG
)Thread
->Tcb
.Priority
]))
259 PriorityListMask
&= ~(1 << Thread
->Tcb
.Priority
);
265 VOID
PsDumpThreads(BOOLEAN IncludeSystem
)
267 PLIST_ENTRY current_entry
;
272 current_entry
= PiThreadListHead
.Flink
;
275 while (current_entry
!= &PiThreadListHead
)
280 current
= CONTAINING_RECORD(current_entry
, ETHREAD
,
281 Tcb
.ThreadListEntry
);
285 DbgPrint("Too many threads on list\n");
288 if (IncludeSystem
|| current
->ThreadsProcess
->UniqueProcessId
>= 6)
290 DbgPrint("current->Tcb.State %d PID.TID %d.%d Name %.8s Stack: \n",
292 current
->ThreadsProcess
->UniqueProcessId
,
293 current
->Cid
.UniqueThread
,
294 current
->ThreadsProcess
->ImageFileName
);
295 if (current
->Tcb
.State
== THREAD_STATE_READY
||
296 current
->Tcb
.State
== THREAD_STATE_SUSPENDED
||
297 current
->Tcb
.State
== THREAD_STATE_BLOCKED
)
299 Esp
= (PULONG
)current
->Tcb
.KernelStack
;
300 Ebp
= (PULONG
)Esp
[3];
301 DbgPrint("Ebp 0x%.8X\n", Ebp
);
303 while (Ebp
!= 0 && Ebp
>= (PULONG
)current
->Tcb
.StackLimit
)
305 DbgPrint("%.8X %.8X%s", Ebp
[0], Ebp
[1],
306 (i
% 8) == 7 ? "\n" : " ");
307 Ebp
= (PULONG
)Ebp
[0];
316 current_entry
= current_entry
->Flink
;
320 static PETHREAD
PsScanThreadList (KPRIORITY Priority
, ULONG Affinity
)
322 PLIST_ENTRY current_entry
;
326 Mask
= (1 << Priority
);
327 if (PriorityListMask
& Mask
)
329 current_entry
= PriorityListHead
[Priority
].Flink
;
330 while (current_entry
!= &PriorityListHead
[Priority
])
332 current
= CONTAINING_RECORD(current_entry
, ETHREAD
,
334 if (current
->Tcb
.State
!= THREAD_STATE_READY
)
336 DPRINT1("%d/%d\n", current
->Cid
.UniqueThread
, current
->Tcb
.State
);
338 assert(current
->Tcb
.State
== THREAD_STATE_READY
);
339 DPRINT("current->Tcb.UserAffinity %x Affinity %x PID %d %d\n",
340 current
->Tcb
.UserAffinity
, Affinity
, current
->Cid
.UniqueThread
,
342 if (current
->Tcb
.UserAffinity
& Affinity
)
344 PsRemoveFromThreadList(current
);
347 current_entry
= current_entry
->Flink
;
354 PiWakeupReaperThread(VOID
)
356 KeSetEvent(&PiReaperThreadEvent
, 0, FALSE
);
360 PiReaperThreadMain(PVOID Ignored
)
364 KeWaitForSingleObject(&PiReaperThreadEvent
,
369 if (PiReaperThreadShouldTerminate
)
371 PsTerminateSystemThread(0);
377 VOID
PsDispatchThreadNoLock (ULONG NewThreadStatus
)
379 KPRIORITY CurrentPriority
;
382 PKTHREAD KCurrentThread
= ((PIKPCR
) KeGetCurrentKPCR())->CurrentThread
;
383 PETHREAD CurrentThread
= CONTAINING_RECORD(KCurrentThread
, ETHREAD
, Tcb
);
385 DPRINT("PsDispatchThread() %d/%d/%d/%d\n", KeGetCurrentProcessorNumber(),
386 CurrentThread
->Cid
.UniqueThread
, NewThreadStatus
, CurrentThread
->Tcb
.State
);
388 CurrentThread
->Tcb
.State
= (UCHAR
)NewThreadStatus
;
389 if (CurrentThread
->Tcb
.State
== THREAD_STATE_READY
)
391 PsInsertIntoThreadList(CurrentThread
->Tcb
.Priority
,
394 if (CurrentThread
->Tcb
.State
== THREAD_STATE_TERMINATED_1
)
396 PiNrThreadsAwaitingReaping
++;
399 Affinity
= 1 << KeGetCurrentProcessorNumber();
400 for (CurrentPriority
= HIGH_PRIORITY
;
401 CurrentPriority
>= LOW_PRIORITY
;
404 Candidate
= PsScanThreadList(CurrentPriority
, Affinity
);
405 if (Candidate
== CurrentThread
)
407 Candidate
->Tcb
.State
= THREAD_STATE_RUNNING
;
408 KeReleaseSpinLockFromDpcLevel(&PiThreadListLock
);
411 if (Candidate
!= NULL
)
415 DPRINT("Scheduling %x(%d)\n",Candidate
, CurrentPriority
);
417 Candidate
->Tcb
.State
= THREAD_STATE_RUNNING
;
419 OldThread
= CurrentThread
;
420 CurrentThread
= Candidate
;
423 * This code is moved to the end of KiArchContextSwitch.
424 * It should be execute after the context switch.
426 KeReleaseSpinLockFromDpcLevel(&PiThreadListLock
);
427 if (PiNrThreadsAwaitingReaping
> 0)
429 PiWakeupReaperThread();
432 KiArchContextSwitch(&CurrentThread
->Tcb
, &OldThread
->Tcb
);
436 CPRINT("CRITICAL: No threads are ready\n");
441 PsDispatchThread(ULONG NewThreadStatus
)
450 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
454 ((PIKPCR
) KeGetCurrentKPCR())->CurrentThread
->WaitIrql
= oldIrql
;
455 PsDispatchThreadNoLock(NewThreadStatus
);
456 KeLowerIrql(oldIrql
);
460 PsUnblockThread(PETHREAD Thread
, PNTSTATUS WaitStatus
)
464 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
465 if (THREAD_STATE_TERMINATED_1
== Thread
->Tcb
.State
||
466 THREAD_STATE_TERMINATED_2
== Thread
->Tcb
.State
)
468 DPRINT("Can't unblock thread %d because it's terminating\n",
469 Thread
->Cid
.UniqueThread
);
471 else if (THREAD_STATE_READY
== Thread
->Tcb
.State
||
472 THREAD_STATE_RUNNING
== Thread
->Tcb
.State
)
474 DPRINT("Can't unblock thread %d because it's ready or running\n",
475 Thread
->Cid
.UniqueThread
);
479 if (WaitStatus
!= NULL
)
481 Thread
->Tcb
.WaitStatus
= *WaitStatus
;
483 Thread
->Tcb
.State
= THREAD_STATE_READY
;
484 PsInsertIntoThreadList(Thread
->Tcb
.Priority
, Thread
);
486 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
490 PsBlockThread(PNTSTATUS Status
, UCHAR Alertable
, ULONG WaitMode
,
491 BOOLEAN DispatcherLock
, KIRQL WaitIrql
, UCHAR WaitReason
)
496 PKWAIT_BLOCK WaitBlock
;
498 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
500 KThread
= ((PIKPCR
) KeGetCurrentKPCR())->CurrentThread
;
501 Thread
= CONTAINING_RECORD (KThread
, ETHREAD
, Tcb
);
502 if (KThread
->ApcState
.KernelApcPending
)
506 KeAcquireDispatcherDatabaseLockAtDpcLevel();
508 WaitBlock
= (PKWAIT_BLOCK
)Thread
->Tcb
.WaitBlockList
;
511 RemoveEntryList (&WaitBlock
->WaitListEntry
);
512 WaitBlock
= WaitBlock
->NextWaitBlock
;
514 Thread
->Tcb
.WaitBlockList
= NULL
;
515 KeReleaseDispatcherDatabaseLockFromDpcLevel();
516 PsDispatchThreadNoLock (THREAD_STATE_READY
);
519 *Status
= STATUS_KERNEL_APC
;
526 KeReleaseDispatcherDatabaseLockFromDpcLevel();
528 Thread
->Tcb
.Alertable
= Alertable
;
529 Thread
->Tcb
.WaitMode
= (UCHAR
)WaitMode
;
530 Thread
->Tcb
.WaitIrql
= WaitIrql
;
531 Thread
->Tcb
.WaitReason
= WaitReason
;
532 PsDispatchThreadNoLock(THREAD_STATE_BLOCKED
);
536 *Status
= Thread
->Tcb
.WaitStatus
;
539 KeLowerIrql(WaitIrql
);
543 PsFreezeAllThreads(PEPROCESS Process
)
545 * Used by the debugging code to freeze all the process's threads
546 * while the debugger is examining their state.
550 PLIST_ENTRY current_entry
;
553 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
555 current_entry
= Process
->ThreadListHead
.Flink
;
556 while (current_entry
!= &Process
->ThreadListHead
)
558 current
= CONTAINING_RECORD(current_entry
, ETHREAD
,
559 Tcb
.ProcessThreadListEntry
);
562 * We have to be careful here, we can't just set the freeze the
563 * thread inside kernel mode since it may be holding a lock.
566 current_entry
= current_entry
->Flink
;
569 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
573 PsEnumThreadsByProcess(PEPROCESS Process
)
576 PLIST_ENTRY current_entry
;
579 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
581 current_entry
= Process
->ThreadListHead
.Flink
;
582 while (current_entry
!= &Process
->ThreadListHead
)
585 current_entry
= current_entry
->Flink
;
588 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
597 PsRemoveCreateThreadNotifyRoutine (
598 IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine
602 return STATUS_NOT_IMPLEMENTED
;
610 PsSetLegoNotifyRoutine(
611 PVOID LegoNotifyRoutine
623 PsSetThreadHardErrorsAreDisabled(
625 BOOLEAN HardErrorsAreDisabled
628 Thread
->HardErrorsAreDisabled
= HardErrorsAreDisabled
;
636 PsSetThreadWin32Thread(
641 Thread
->Win32Thread
= Win32Thread
;
645 PsApplicationProcessorInit(VOID
)
647 ((PIKPCR
) KeGetCurrentKPCR())->CurrentThread
=
648 (PVOID
)IdleThreads
[KeGetCurrentProcessorNumber()];
652 PsPrepareForApplicationProcessorInit(ULONG Id
)
655 HANDLE IdleThreadHandle
;
657 PsInitializeThread(NULL
,
663 IdleThread
->Tcb
.State
= THREAD_STATE_RUNNING
;
664 IdleThread
->Tcb
.FreezeCount
= 0;
665 IdleThread
->Tcb
.UserAffinity
= 1 << Id
;
666 IdleThread
->Tcb
.Priority
= LOW_PRIORITY
;
667 IdleThreads
[Id
] = IdleThread
;
669 NtClose(IdleThreadHandle
);
670 DPRINT("IdleThread for Processor %d has PID %d\n",
671 Id
, IdleThread
->Cid
.UniqueThread
);
675 PsInitThreadManagment(VOID
)
677 * FUNCTION: Initialize thread managment
680 PETHREAD FirstThread
;
682 HANDLE FirstThreadHandle
;
685 KeInitializeSpinLock(&PiThreadListLock
);
686 for (i
=0; i
< MAXIMUM_PRIORITY
; i
++)
688 InitializeListHead(&PriorityListHead
[i
]);
691 InitializeListHead(&PiThreadListHead
);
693 PsThreadType
= ExAllocatePool(NonPagedPool
,sizeof(OBJECT_TYPE
));
695 PsThreadType
->Tag
= TAG('T', 'H', 'R', 'T');
696 PsThreadType
->TotalObjects
= 0;
697 PsThreadType
->TotalHandles
= 0;
698 PsThreadType
->MaxObjects
= 0;
699 PsThreadType
->MaxHandles
= 0;
700 PsThreadType
->PagedPoolCharge
= 0;
701 PsThreadType
->NonpagedPoolCharge
= sizeof(ETHREAD
);
702 PsThreadType
->Mapping
= &PiThreadMapping
;
703 PsThreadType
->Dump
= NULL
;
704 PsThreadType
->Open
= NULL
;
705 PsThreadType
->Close
= NULL
;
706 PsThreadType
->Delete
= PiDeleteThread
;
707 PsThreadType
->Parse
= NULL
;
708 PsThreadType
->Security
= NULL
;
709 PsThreadType
->QueryName
= NULL
;
710 PsThreadType
->OkayToClose
= NULL
;
711 PsThreadType
->Create
= NULL
;
712 PsThreadType
->DuplicationNotify
= NULL
;
714 RtlRosInitUnicodeStringFromLiteral(&PsThreadType
->TypeName
, L
"Thread");
716 ObpCreateTypeObject(PsThreadType
);
718 PsInitializeThread(NULL
,&FirstThread
,&FirstThreadHandle
,
719 THREAD_ALL_ACCESS
,NULL
, TRUE
);
720 FirstThread
->Tcb
.State
= THREAD_STATE_RUNNING
;
721 FirstThread
->Tcb
.FreezeCount
= 0;
722 ((PIKPCR
) KeGetCurrentKPCR())->CurrentThread
= (PVOID
)FirstThread
;
723 NtClose(FirstThreadHandle
);
725 DPRINT("FirstThread %x\n",FirstThread
);
730 * Create the reaper thread
732 KeInitializeEvent(&PiReaperThreadEvent
, SynchronizationEvent
, FALSE
);
733 Status
= PsCreateSystemThread(&PiReaperThreadHandle
,
740 if (!NT_SUCCESS(Status
))
742 DPRINT1("PS: Failed to create reaper thread.\n");
751 KeSetBasePriorityThread (PKTHREAD Thread
,
754 * Sets thread's base priority relative to the process' base priority
755 * Should only be passed in THREAD_PRIORITY_ constants in pstypes.h
763 else if (Increment
> 2)
767 Priority
= ((PETHREAD
)Thread
)->ThreadsProcess
->Pcb
.BasePriority
+ Increment
;
768 if (Priority
< LOW_PRIORITY
)
770 Priority
= LOW_PRIORITY
;
772 else if (Priority
>= MAXIMUM_PRIORITY
)
774 Thread
->BasePriority
= HIGH_PRIORITY
;
776 KeSetPriorityThread(Thread
, Priority
);
785 KeSetPriorityThread (PKTHREAD Thread
, KPRIORITY Priority
)
787 KPRIORITY OldPriority
;
789 PKTHREAD CurrentThread
;
792 if (Priority
< LOW_PRIORITY
|| Priority
>= MAXIMUM_PRIORITY
)
797 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
799 OldPriority
= Thread
->Priority
;
800 Thread
->BasePriority
= Thread
->Priority
= (CHAR
)Priority
;
802 if (OldPriority
!= Priority
)
804 if (Thread
->State
== THREAD_STATE_READY
)
806 PsRemoveFromThreadList((PETHREAD
)Thread
);
807 PsInsertIntoThreadList(Priority
, (PETHREAD
)Thread
);
808 CurrentThread
= ((PIKPCR
) KeGetCurrentKPCR())->CurrentThread
;
809 if (CurrentThread
->Priority
< Priority
)
811 PsDispatchThreadNoLock(THREAD_STATE_READY
);
812 KeLowerIrql(oldIrql
);
813 return (OldPriority
);
816 else if (Thread
->State
== THREAD_STATE_RUNNING
)
818 if (Priority
< OldPriority
)
820 /* Check for threads with a higher priority */
821 Mask
= ~((1 << (Priority
+ 1)) - 1);
822 if (PriorityListMask
& Mask
)
824 PsDispatchThreadNoLock(THREAD_STATE_READY
);
825 KeLowerIrql(oldIrql
);
826 return (OldPriority
);
831 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
839 KeSetAffinityThread(PKTHREAD Thread
,
842 * Sets thread's affinity
845 DPRINT1("KeSetAffinityThread() is a stub returning STATUS_SUCCESS");
846 return STATUS_SUCCESS
; // FIXME: Use function below
847 //return ZwSetInformationThread(handle, ThreadAffinityMask,<pointer to affinity mask>,sizeof(KAFFINITY));
852 NtAlertResumeThread(IN HANDLE ThreadHandle
,
853 OUT PULONG SuspendCount
)
856 return(STATUS_NOT_IMPLEMENTED
);
862 NtAlertThread (IN HANDLE ThreadHandle
)
866 NTSTATUS ThreadStatus
;
868 Status
= ObReferenceObjectByHandle(ThreadHandle
,
869 THREAD_SUSPEND_RESUME
,
874 if (Status
!= STATUS_SUCCESS
)
879 ThreadStatus
= STATUS_ALERTED
;
880 (VOID
)PsUnblockThread(Thread
, &ThreadStatus
);
882 ObDereferenceObject(Thread
);
883 return(STATUS_SUCCESS
);
886 /**********************************************************************
892 NtOpenThread(OUT PHANDLE ThreadHandle
,
893 IN ACCESS_MASK DesiredAccess
,
894 IN POBJECT_ATTRIBUTES ObjectAttributes
,
895 IN PCLIENT_ID ClientId
)
897 NTSTATUS Status
= STATUS_INVALID_PARAMETER
;
899 if((NULL
!= ThreadHandle
)&&(NULL
!= ObjectAttributes
))
901 PETHREAD EThread
= NULL
;
904 && (ClientId
->UniqueThread
))
906 // It is an error to specify both
907 // ObjectAttributes.ObjectName
909 if((ObjectAttributes
)
910 && (ObjectAttributes
->ObjectName
)
911 && (0 < ObjectAttributes
->ObjectName
->Length
))
913 return(STATUS_INVALID_PARAMETER_MIX
);
916 Status
= PsLookupThreadByThreadId(ClientId
->UniqueThread
,
919 else if((ObjectAttributes
)
920 && (ObjectAttributes
->ObjectName
)
921 && (0 < ObjectAttributes
->ObjectName
->Length
))
923 // Three Ob attributes are forbidden
924 if(!(ObjectAttributes
->Attributes
&
925 (OBJ_PERMANENT
| OBJ_EXCLUSIVE
| OBJ_OPENIF
)))
927 Status
= ObReferenceObjectByName(ObjectAttributes
->ObjectName
,
928 ObjectAttributes
->Attributes
,
937 // EThread may be OK...
938 if(STATUS_SUCCESS
== Status
)
940 Status
= ObCreateHandle(PsGetCurrentProcess(),
945 ObDereferenceObject(EThread
);
952 NtYieldExecution(VOID
)
954 PsDispatchThread(THREAD_STATE_READY
);
955 return(STATUS_SUCCESS
);
963 PsLookupProcessThreadByCid(IN PCLIENT_ID Cid
,
964 OUT PEPROCESS
*Process OPTIONAL
,
965 OUT PETHREAD
*Thread
)
968 PLIST_ENTRY current_entry
;
971 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
973 current_entry
= PiThreadListHead
.Flink
;
974 while (current_entry
!= &PiThreadListHead
)
976 current
= CONTAINING_RECORD(current_entry
,
978 Tcb
.ThreadListEntry
);
979 if (current
->Cid
.UniqueThread
== Cid
->UniqueThread
&&
980 current
->Cid
.UniqueProcess
== Cid
->UniqueProcess
)
984 *Process
= current
->ThreadsProcess
;
985 ObReferenceObject(current
->ThreadsProcess
);
989 ObReferenceObject(current
);
991 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
992 return(STATUS_SUCCESS
);
995 current_entry
= current_entry
->Flink
;
998 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
1000 return(STATUS_INVALID_PARAMETER
);
1008 PsLookupThreadByThreadId(IN PVOID ThreadId
,
1009 OUT PETHREAD
*Thread
)
1012 PLIST_ENTRY current_entry
;
1015 KeAcquireSpinLock(&PiThreadListLock
, &oldIrql
);
1017 current_entry
= PiThreadListHead
.Flink
;
1018 while (current_entry
!= &PiThreadListHead
)
1020 current
= CONTAINING_RECORD(current_entry
,
1022 Tcb
.ThreadListEntry
);
1023 if (current
->Cid
.UniqueThread
== (HANDLE
)ThreadId
)
1025 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
1027 ObReferenceObject(current
);
1028 return(STATUS_SUCCESS
);
1031 current_entry
= current_entry
->Flink
;
1034 KeReleaseSpinLock(&PiThreadListLock
, oldIrql
);
1036 return(STATUS_INVALID_PARAMETER
);
1044 NtOpenThreadTokenEx(
1045 IN HANDLE ThreadHandle
,
1046 IN ACCESS_MASK DesiredAccess
,
1047 IN BOOLEAN OpenAsSelf
,
1048 IN ULONG HandleAttributes
,
1049 OUT PHANDLE TokenHandle
1053 return STATUS_NOT_IMPLEMENTED
;