3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/ps/thread.c
6 * PURPOSE: Thread managment
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
15 * All of the routines that manipulate the thread queue synchronize on
20 /* INCLUDES ****************************************************************/
24 #include <internal/debug.h>
26 /* GLOBALS ******************************************************************/
28 extern LIST_ENTRY PsActiveProcessHead
;
29 extern PEPROCESS PsIdleProcess
;
31 POBJECT_TYPE EXPORTED PsThreadType
= NULL
;
33 extern PVOID Ki386InitialStackArray
[MAXIMUM_PROCESSORS
];
34 extern ULONG IdleProcessorMask
;
35 extern LIST_ENTRY PriorityListHead
[MAXIMUM_PRIORITY
];
38 BOOLEAN DoneInitYet
= FALSE
;
39 static GENERIC_MAPPING PiThreadMapping
= {STANDARD_RIGHTS_READ
| THREAD_GET_CONTEXT
| THREAD_QUERY_INFORMATION
,
40 STANDARD_RIGHTS_WRITE
| THREAD_TERMINATE
| THREAD_SUSPEND_RESUME
| THREAD_ALERT
|
41 THREAD_SET_INFORMATION
| THREAD_SET_CONTEXT
,
42 STANDARD_RIGHTS_EXECUTE
| SYNCHRONIZE
,
45 /* FUNCTIONS ***************************************************************/
50 PKTHREAD STDCALL
KeGetCurrentThread(VOID
)
55 Ke386SaveFlags(Flags
);
56 Ke386DisableInterrupts();
57 Thread
= KeGetCurrentPrcb()->CurrentThread
;
58 Ke386RestoreFlags(Flags
);
61 return(KeGetCurrentPrcb()->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
->Tcb
.Win32Thread
;
174 PsGetCurrentThreadPreviousMode (
178 return (KPROCESSOR_MODE
)PsGetCurrentThread()->Tcb
.PreviousMode
;
186 PsGetCurrentThreadStackBase (
190 return PsGetCurrentThread()->Tcb
.StackBase
;
198 PsGetCurrentThreadStackLimit (
202 return (PVOID
)PsGetCurrentThread()->Tcb
.StackLimit
;
209 PsIsThreadTerminating(IN PETHREAD Thread
)
211 return (Thread
->HasTerminated
? TRUE
: FALSE
);
219 PsIsSystemThread(PETHREAD Thread
)
221 return (Thread
->SystemThread
? TRUE
: FALSE
);
229 PsIsThreadImpersonating(
233 return Thread
->ActiveImpersonationInfo
;
236 VOID
PsDumpThreads(BOOLEAN IncludeSystem
)
238 PLIST_ENTRY AThread
, AProcess
;
243 AProcess
= PsActiveProcessHead
.Flink
;
244 while(AProcess
!= &PsActiveProcessHead
)
246 Process
= CONTAINING_RECORD(AProcess
, EPROCESS
, ProcessListEntry
);
247 /* FIXME - skip suspended, ... processes? */
248 if((Process
!= PsInitialSystemProcess
) ||
249 (Process
== PsInitialSystemProcess
&& IncludeSystem
))
251 AThread
= Process
->ThreadListHead
.Flink
;
252 while(AThread
!= &Process
->ThreadListHead
)
254 Thread
= CONTAINING_RECORD(AThread
, ETHREAD
, ThreadListEntry
);
257 DbgPrint("Thread->Tcb.State %d Affinity %08x Priority %d PID.TID %d.%d Name %.8s Stack: \n",
259 Thread
->Tcb
.Affinity
,
260 Thread
->Tcb
.Priority
,
261 Thread
->ThreadsProcess
->UniqueProcessId
,
262 Thread
->Cid
.UniqueThread
,
263 Thread
->ThreadsProcess
->ImageFileName
);
264 if(Thread
->Tcb
.State
== THREAD_STATE_READY
||
265 Thread
->Tcb
.State
== THREAD_STATE_SUSPENDED
||
266 Thread
->Tcb
.State
== THREAD_STATE_BLOCKED
)
269 PULONG Esp
= (PULONG
)Thread
->Tcb
.KernelStack
;
270 PULONG Ebp
= (PULONG
)Esp
[4];
271 DbgPrint("Ebp 0x%.8X\n", Ebp
);
272 while(Ebp
!= 0 && Ebp
>= (PULONG
)Thread
->Tcb
.StackLimit
)
274 DbgPrint("%.8X %.8X%s", Ebp
[0], Ebp
[1], (i
% 8) == 7 ? "\n" : " ");
275 Ebp
= (PULONG
)Ebp
[0];
283 AThread
= AThread
->Flink
;
286 AProcess
= AProcess
->Flink
;
291 PsFreezeAllThreads(PEPROCESS Process
)
293 * Used by the debugging code to freeze all the process's threads
294 * while the debugger is examining their state.
298 PLIST_ENTRY current_entry
;
301 oldIrql
= KeAcquireDispatcherDatabaseLock();
302 current_entry
= Process
->ThreadListHead
.Flink
;
303 while (current_entry
!= &Process
->ThreadListHead
)
305 current
= CONTAINING_RECORD(current_entry
, ETHREAD
,
309 * We have to be careful here, we can't just set the freeze the
310 * thread inside kernel mode since it may be holding a lock.
313 current_entry
= current_entry
->Flink
;
316 KeReleaseDispatcherDatabaseLock(oldIrql
);
320 PsEnumThreadsByProcess(PEPROCESS Process
)
323 PLIST_ENTRY current_entry
;
326 oldIrql
= KeAcquireDispatcherDatabaseLock();
328 current_entry
= Process
->ThreadListHead
.Flink
;
329 while (current_entry
!= &Process
->ThreadListHead
)
332 current_entry
= current_entry
->Flink
;
335 KeReleaseDispatcherDatabaseLock(oldIrql
);
344 PsRemoveCreateThreadNotifyRoutine (
345 IN PCREATE_THREAD_NOTIFY_ROUTINE NotifyRoutine
349 return STATUS_NOT_IMPLEMENTED
;
357 PsSetLegoNotifyRoutine(
358 PVOID LegoNotifyRoutine
370 PsSetThreadHardErrorsAreDisabled(
372 BOOLEAN HardErrorsAreDisabled
375 Thread
->HardErrorsAreDisabled
= HardErrorsAreDisabled
;
383 PsSetThreadWin32Thread(
388 Thread
->Tcb
.Win32Thread
= Win32Thread
;
392 PsApplicationProcessorInit(VOID
)
395 oldIrql
= KeAcquireDispatcherDatabaseLock();
396 IdleProcessorMask
|= (1 << KeGetCurrentProcessorNumber());
397 KeReleaseDispatcherDatabaseLock(oldIrql
);
401 PsPrepareForApplicationProcessorInit(ULONG Id
)
404 PKPRCB Prcb
= ((PKPCR
)((ULONG_PTR
)KPCR_BASE
+ Id
* PAGE_SIZE
))->Prcb
;
406 PsInitializeThread(PsIdleProcess
,
411 IdleThread
->Tcb
.State
= THREAD_STATE_RUNNING
;
412 IdleThread
->Tcb
.FreezeCount
= 0;
413 IdleThread
->Tcb
.Affinity
= 1 << Id
;
414 IdleThread
->Tcb
.UserAffinity
= 1 << Id
;
415 IdleThread
->Tcb
.Priority
= LOW_PRIORITY
;
416 IdleThread
->Tcb
.BasePriority
= LOW_PRIORITY
;
417 Prcb
->IdleThread
= &IdleThread
->Tcb
;
418 Prcb
->CurrentThread
= &IdleThread
->Tcb
;
420 Ki386InitialStackArray
[Id
] = (PVOID
)IdleThread
->Tcb
.StackLimit
;
422 DPRINT("IdleThread for Processor %d has PID %d\n",
423 Id
, IdleThread
->Cid
.UniqueThread
);
427 PsInitThreadManagment(VOID
)
429 * FUNCTION: Initialize thread managment
432 PETHREAD FirstThread
;
435 for (i
=0; i
< MAXIMUM_PRIORITY
; i
++)
437 InitializeListHead(&PriorityListHead
[i
]);
440 PsThreadType
= ExAllocatePool(NonPagedPool
,sizeof(OBJECT_TYPE
));
442 PsThreadType
->Tag
= TAG('T', 'H', 'R', 'T');
443 PsThreadType
->TotalObjects
= 0;
444 PsThreadType
->TotalHandles
= 0;
445 PsThreadType
->PeakObjects
= 0;
446 PsThreadType
->PeakHandles
= 0;
447 PsThreadType
->PagedPoolCharge
= 0;
448 PsThreadType
->NonpagedPoolCharge
= sizeof(ETHREAD
);
449 PsThreadType
->Mapping
= &PiThreadMapping
;
450 PsThreadType
->Dump
= NULL
;
451 PsThreadType
->Open
= NULL
;
452 PsThreadType
->Close
= NULL
;
453 PsThreadType
->Delete
= PspDeleteThread
;
454 PsThreadType
->Parse
= NULL
;
455 PsThreadType
->Security
= NULL
;
456 PsThreadType
->QueryName
= NULL
;
457 PsThreadType
->OkayToClose
= NULL
;
458 PsThreadType
->Create
= NULL
;
459 PsThreadType
->DuplicationNotify
= NULL
;
461 RtlInitUnicodeString(&PsThreadType
->TypeName
, L
"Thread");
463 ObpCreateTypeObject(PsThreadType
);
465 PsInitializeThread(NULL
, &FirstThread
, NULL
, KernelMode
, TRUE
);
466 FirstThread
->Tcb
.State
= THREAD_STATE_RUNNING
;
467 FirstThread
->Tcb
.FreezeCount
= 0;
468 FirstThread
->Tcb
.UserAffinity
= (1 << 0); /* Set the affinity of the first thread to the boot processor */
469 FirstThread
->Tcb
.Affinity
= (1 << 0);
470 KeGetCurrentPrcb()->CurrentThread
= (PVOID
)FirstThread
;
472 DPRINT("FirstThread %x\n",FirstThread
);
476 ExInitializeWorkItem(&PspReaperWorkItem
, PspReapRoutine
, NULL
);
479 /**********************************************************************
485 NtOpenThread(OUT PHANDLE ThreadHandle
,
486 IN ACCESS_MASK DesiredAccess
,
487 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL
,
488 IN PCLIENT_ID ClientId OPTIONAL
)
490 KPROCESSOR_MODE PreviousMode
;
491 CLIENT_ID SafeClientId
;
493 NTSTATUS Status
= STATUS_SUCCESS
;
497 PreviousMode
= ExGetPreviousMode();
499 if(PreviousMode
!= KernelMode
)
503 ProbeForWrite(ThreadHandle
,
508 ProbeForRead(ClientId
,
511 SafeClientId
= *ClientId
;
512 ClientId
= &SafeClientId
;
517 Status
= _SEH_GetExceptionCode();
521 if(!NT_SUCCESS(Status
))
527 if(!((ObjectAttributes
== NULL
) ^ (ClientId
== NULL
)))
529 DPRINT("NtOpenThread should be called with either ObjectAttributes or ClientId!\n");
530 return STATUS_INVALID_PARAMETER
;
537 Status
= PsLookupThreadByThreadId(ClientId
->UniqueThread
,
539 if(NT_SUCCESS(Status
))
541 Status
= ObInsertObject(Thread
,
548 ObDereferenceObject(Thread
);
553 Status
= ObOpenObjectByName(ObjectAttributes
,
562 if(NT_SUCCESS(Status
))
566 *ThreadHandle
= hThread
;
570 Status
= _SEH_GetExceptionCode();
579 NtYieldExecution(VOID
)
581 KiDispatchThread(THREAD_STATE_READY
);
582 return(STATUS_SUCCESS
);
592 /* Check and Alert Thread if needed */
593 return KeTestAlertThread(ExGetPreviousMode()) ? STATUS_ALERTED
: STATUS_SUCCESS
;
597 KeSetPreviousMode (ULONG Mode
)
599 PsGetCurrentThread()->Tcb
.PreviousMode
= (UCHAR
)Mode
;
606 KPROCESSOR_MODE STDCALL
607 KeGetPreviousMode (VOID
)
609 return (ULONG
)PsGetCurrentThread()->Tcb
.PreviousMode
;
616 KPROCESSOR_MODE STDCALL
617 ExGetPreviousMode (VOID
)
619 return (KPROCESSOR_MODE
)PsGetCurrentThread()->Tcb
.PreviousMode
;