2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS system libraries
4 * FILE: lib/kernel32/thread/thread.c
5 * PURPOSE: Thread functions
6 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
7 * Ariadne ( ariadne@xs4all.nl)
11 /* INCLUDES ******************************************************************/
16 #include "../include/debug.h"
19 #define HIGH_PRIORITY 31
21 /* FUNCTIONS *****************************************************************/
22 _SEH_FILTER(BaseThreadExceptionFilter
)
24 EXCEPTION_POINTERS
* ExceptionInfo
= _SEH_GetExceptionPointers();
25 LONG ExceptionDisposition
= EXCEPTION_EXECUTE_HANDLER
;
27 if (GlobalTopLevelExceptionFilter
!= NULL
)
31 ExceptionDisposition
= GlobalTopLevelExceptionFilter(ExceptionInfo
);
35 ExceptionDisposition
= UnhandledExceptionFilter(ExceptionInfo
);
40 return ExceptionDisposition
;
46 BaseThreadStartup(LPTHREAD_START_ROUTINE lpStartAddress
,
49 volatile UINT uExitCode
= 0;
51 /* Attempt to call the Thread Start Address */
54 /* Get the exit code from the Thread Start */
55 uExitCode
= (lpStartAddress
)((PVOID
)lpParameter
);
57 _SEH_EXCEPT(BaseThreadExceptionFilter
)
59 /* Get the Exit code from the SEH Handler */
60 uExitCode
= _SEH_GetExceptionCode();
64 ExitThread(uExitCode
);
72 CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes
,
74 LPTHREAD_START_ROUTINE lpStartAddress
,
76 DWORD dwCreationFlags
,
79 /* Act as if we're going to create a remote thread in ourselves */
80 return CreateRemoteThread(NtCurrentProcess(),
94 CreateRemoteThread(HANDLE hProcess
,
95 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
97 LPTHREAD_START_ROUTINE lpStartAddress
,
99 DWORD dwCreationFlags
,
103 INITIAL_TEB InitialTeb
;
106 OBJECT_ATTRIBUTES LocalObjectAttributes
;
107 POBJECT_ATTRIBUTES ObjectAttributes
;
111 DPRINT("CreateRemoteThread: hProcess: %ld dwStackSize: %ld lpStartAddress"
112 ": %p lpParameter: %lx, dwCreationFlags: %lx\n", hProcess
,
113 dwStackSize
, lpStartAddress
, lpParameter
, dwCreationFlags
);
115 /* Clear the Context */
116 RtlZeroMemory(&Context
, sizeof(CONTEXT
));
119 ClientId
.UniqueProcess
= hProcess
;
121 /* Create the Stack */
122 Status
= BasepCreateStack(hProcess
,
124 dwCreationFlags
& STACK_SIZE_PARAM_IS_A_RESERVATION
?
127 if(!NT_SUCCESS(Status
))
129 SetLastErrorByStatus(Status
);
133 /* Create Initial Context */
134 BasepInitializeContext(&Context
,
137 InitialTeb
.StackBase
,
140 /* initialize the attributes for the thread object */
141 ObjectAttributes
= BasepConvertObjectAttributes(&LocalObjectAttributes
,
145 /* Create the Kernel Thread Object */
146 Status
= NtCreateThread(&hThread
,
154 if(!NT_SUCCESS(Status
))
156 BasepFreeStack(hProcess
, &InitialTeb
);
157 SetLastErrorByStatus(Status
);
161 #ifdef SXS_SUPPORT_ENABLED
162 /* Are we in the same process? */
163 if (Process
= NtCurrentProcess())
166 PVOID ActivationContextStack
;
167 PTHREAD_BASIC_INFORMATION ThreadBasicInfo
;
168 PACTIVATION_CONTEXT_BASIC_INFORMATION ActivationCtxInfo
;
172 Status
= NtQueryInformationThread(hThread
,
173 ThreadBasicIformation
,
175 sizeof(ThreadBasicInfo
),
178 /* Allocate the Activation Context Stack */
179 Status
= RtlAllocateActivationContextStack(&ActivationContextStack
);
180 Teb
= ThreadBasicInfo
.TebBaseAddress
;
183 Teb
->ActivationContextStackPointer
= ActivationContextStack
;
185 /* Query the Context */
186 Status
= RtlQueryInformationActivationContext(1,
189 ActivationContextBasicInformation
,
191 sizeof(ActivationCtxInfo
),
194 /* Does it need to be activated? */
195 if (!ActivationCtxInfo
.hActCtx
)
198 Status
= RtlActivateActivationContextEx(1,
200 ActivationCtxInfo
.hActCtx
,
206 /* FIXME: Notify CSR */
209 if(lpThreadId
) *lpThreadId
= (DWORD
)ClientId
.UniqueThread
;
211 /* Resume it if asked */
212 if (!(dwCreationFlags
& CREATE_SUSPENDED
))
214 NtResumeThread(hThread
, &Dummy
);
217 /* Return handle to thread */
226 ExitThread(DWORD uExitCode
)
232 * Terminate process if this is the last thread
233 * of the current process
235 Status
= NtQueryInformationThread(NtCurrentThread(),
240 if (NT_SUCCESS(Status
) && LastThread
)
242 /* Exit the Process */
243 ExitProcess(uExitCode
);
246 /* Notify DLLs and TLS Callbacks of termination */
249 /* Tell the Kernel to free the Stack */
250 NtCurrentTeb()->FreeStackOnTermination
= TRUE
;
251 NtTerminateThread(NULL
, uExitCode
);
253 /* We will never reach this place. This silences the compiler */
254 ExitThread(uExitCode
);
263 DWORD dwDesiredAccess
,
270 OBJECT_ATTRIBUTES ObjectAttributes
;
273 ClientId
.UniqueProcess
= 0;
274 ClientId
.UniqueThread
= (HANDLE
)dwThreadId
;
276 InitializeObjectAttributes (&ObjectAttributes
,
278 (bInheritHandle
? OBJ_INHERIT
: 0),
282 errCode
= NtOpenThread(&ThreadHandle
,
286 if (!NT_SUCCESS(errCode
))
288 SetLastErrorByStatus (errCode
);
301 return(NtCurrentTeb());
312 Status
= NtYieldExecution();
313 return Status
!= STATUS_NO_YIELD_PERFORMED
;
321 GetCurrentThreadId(VOID
)
323 return((DWORD
)(NtCurrentTeb()->Cid
).UniqueThread
);
330 GetThreadTimes(HANDLE hThread
,
331 LPFILETIME lpCreationTime
,
332 LPFILETIME lpExitTime
,
333 LPFILETIME lpKernelTime
,
334 LPFILETIME lpUserTime
)
336 KERNEL_USER_TIMES KernelUserTimes
;
339 Status
= NtQueryInformationThread(hThread
,
342 sizeof(KERNEL_USER_TIMES
),
344 if (!NT_SUCCESS(Status
))
346 SetLastErrorByStatus(Status
);
350 lpCreationTime
->dwLowDateTime
= KernelUserTimes
.CreateTime
.u
.LowPart
;
351 lpCreationTime
->dwHighDateTime
= KernelUserTimes
.CreateTime
.u
.HighPart
;
353 lpExitTime
->dwLowDateTime
= KernelUserTimes
.ExitTime
.u
.LowPart
;
354 lpExitTime
->dwHighDateTime
= KernelUserTimes
.ExitTime
.u
.HighPart
;
356 lpKernelTime
->dwLowDateTime
= KernelUserTimes
.KernelTime
.u
.LowPart
;
357 lpKernelTime
->dwHighDateTime
= KernelUserTimes
.KernelTime
.u
.HighPart
;
359 lpUserTime
->dwLowDateTime
= KernelUserTimes
.UserTime
.u
.LowPart
;
360 lpUserTime
->dwHighDateTime
= KernelUserTimes
.UserTime
.u
.HighPart
;
370 GetThreadContext(HANDLE hThread
,
375 Status
= NtGetContextThread(hThread
,
377 if (!NT_SUCCESS(Status
))
379 SetLastErrorByStatus(Status
);
391 SetThreadContext(HANDLE hThread
,
392 CONST CONTEXT
*lpContext
)
396 Status
= NtSetContextThread(hThread
,
398 if (!NT_SUCCESS(Status
))
400 SetLastErrorByStatus(Status
);
412 GetExitCodeThread(HANDLE hThread
,
415 THREAD_BASIC_INFORMATION ThreadBasic
;
418 Status
= NtQueryInformationThread(hThread
,
419 ThreadBasicInformation
,
421 sizeof(THREAD_BASIC_INFORMATION
),
423 if (!NT_SUCCESS(Status
))
425 SetLastErrorByStatus(Status
);
429 memcpy(lpExitCode
, &ThreadBasic
.ExitStatus
, sizeof(DWORD
));
439 ResumeThread(HANDLE hThread
)
441 ULONG PreviousResumeCount
;
444 Status
= NtResumeThread(hThread
,
445 &PreviousResumeCount
);
446 if (!NT_SUCCESS(Status
))
448 SetLastErrorByStatus(Status
);
452 return(PreviousResumeCount
);
460 TerminateThread(HANDLE hThread
,
467 SetLastError(ERROR_INVALID_HANDLE
);
471 Status
= NtTerminateThread(hThread
,
473 if (!NT_SUCCESS(Status
))
475 SetLastErrorByStatus(Status
);
487 SuspendThread(HANDLE hThread
)
489 ULONG PreviousSuspendCount
;
492 Status
= NtSuspendThread(hThread
,
493 &PreviousSuspendCount
);
494 if (!NT_SUCCESS(Status
))
496 SetLastErrorByStatus(Status
);
500 return(PreviousSuspendCount
);
508 SetThreadAffinityMask(HANDLE hThread
,
509 DWORD dwThreadAffinityMask
)
511 THREAD_BASIC_INFORMATION ThreadBasic
;
512 KAFFINITY AffinityMask
;
515 AffinityMask
= (KAFFINITY
)dwThreadAffinityMask
;
517 Status
= NtQueryInformationThread(hThread
,
518 ThreadBasicInformation
,
520 sizeof(THREAD_BASIC_INFORMATION
),
522 if (!NT_SUCCESS(Status
))
524 SetLastErrorByStatus(Status
);
528 Status
= NtSetInformationThread(hThread
,
532 if (!NT_SUCCESS(Status
))
534 SetLastErrorByStatus(Status
);
535 ThreadBasic
.AffinityMask
= 0;
538 return(ThreadBasic
.AffinityMask
);
547 SetThreadPriority(HANDLE hThread
,
550 ULONG Prio
= nPriority
;
553 /* Check if values forcing saturation should be used */
554 if (Prio
== THREAD_PRIORITY_TIME_CRITICAL
)
556 Prio
= (HIGH_PRIORITY
+ 1) / 2;
558 else if (Prio
== THREAD_PRIORITY_IDLE
)
560 Prio
= -((HIGH_PRIORITY
+ 1) / 2);
563 /* Set the Base Priority */
564 Status
= NtSetInformationThread(hThread
,
568 if (!NT_SUCCESS(Status
))
571 SetLastErrorByStatus(Status
);
584 GetThreadPriority(HANDLE hThread
)
586 THREAD_BASIC_INFORMATION ThreadBasic
;
589 /* Query the Base Priority Increment */
590 Status
= NtQueryInformationThread(hThread
,
591 ThreadBasicInformation
,
593 sizeof(THREAD_BASIC_INFORMATION
),
595 if (!NT_SUCCESS(Status
))
598 SetLastErrorByStatus(Status
);
599 return THREAD_PRIORITY_ERROR_RETURN
;
602 /* Do some conversions for out of boundary values */
603 if (ThreadBasic
.BasePriority
> THREAD_BASE_PRIORITY_MAX
)
605 ThreadBasic
.BasePriority
= THREAD_PRIORITY_TIME_CRITICAL
;
607 else if (ThreadBasic
.BasePriority
< THREAD_BASE_PRIORITY_MIN
)
609 ThreadBasic
.BasePriority
= THREAD_PRIORITY_IDLE
;
612 /* Return the final result */
613 return ThreadBasic
.BasePriority
;
620 GetThreadPriorityBoost(IN HANDLE hThread
,
621 OUT PBOOL pDisablePriorityBoost
)
626 Status
= NtQueryInformationThread(hThread
,
631 if (!NT_SUCCESS(Status
))
633 SetLastErrorByStatus(Status
);
637 *pDisablePriorityBoost
= !((BOOL
)PriorityBoost
);
647 SetThreadPriorityBoost(IN HANDLE hThread
,
648 IN BOOL bDisablePriorityBoost
)
653 PriorityBoost
= (ULONG
)!bDisablePriorityBoost
;
655 Status
= NtSetInformationThread(hThread
,
659 if (!NT_SUCCESS(Status
))
661 SetLastErrorByStatus(Status
);
673 GetThreadSelectorEntry(IN HANDLE hThread
,
675 OUT LPLDT_ENTRY lpSelectorEntry
)
677 DESCRIPTOR_TABLE_ENTRY DescriptionTableEntry
;
680 DescriptionTableEntry
.Selector
= dwSelector
;
681 Status
= NtQueryInformationThread(hThread
,
682 ThreadDescriptorTableEntry
,
683 &DescriptionTableEntry
,
684 sizeof(DESCRIPTOR_TABLE_ENTRY
),
686 if(!NT_SUCCESS(Status
))
688 SetLastErrorByStatus(Status
);
692 *lpSelectorEntry
= DescriptionTableEntry
.Descriptor
;
701 SetThreadIdealProcessor(HANDLE hThread
,
702 DWORD dwIdealProcessor
)
706 Status
= NtSetInformationThread(hThread
,
707 ThreadIdealProcessor
,
710 if (!NT_SUCCESS(Status
))
712 SetLastErrorByStatus(Status
);
716 return dwIdealProcessor
;
724 GetProcessIdOfThread(HANDLE Thread
)
726 THREAD_BASIC_INFORMATION ThreadBasic
;
729 Status
= NtQueryInformationThread(Thread
,
730 ThreadBasicInformation
,
732 sizeof(THREAD_BASIC_INFORMATION
),
734 if(!NT_SUCCESS(Status
))
736 SetLastErrorByStatus(Status
);
740 return (DWORD
)ThreadBasic
.ClientId
.UniqueProcess
;
748 GetThreadId(HANDLE Thread
)
750 THREAD_BASIC_INFORMATION ThreadBasic
;
753 Status
= NtQueryInformationThread(Thread
,
754 ThreadBasicInformation
,
756 sizeof(THREAD_BASIC_INFORMATION
),
758 if(!NT_SUCCESS(Status
))
760 SetLastErrorByStatus(Status
);
764 return (DWORD
)ThreadBasic
.ClientId
.UniqueThread
;
771 SetThreadUILanguage(WORD wReserved
)
773 DPRINT1("SetThreadUILanguage(0x%4x) unimplemented!\n", wReserved
);
778 IntCallUserApc(PVOID Function
, PVOID dwData
, PVOID Argument3
)
780 PAPCFUNC pfnAPC
= (PAPCFUNC
)Function
;
781 pfnAPC((ULONG_PTR
)dwData
);
788 QueueUserAPC(PAPCFUNC pfnAPC
, HANDLE hThread
, ULONG_PTR dwData
)
792 Status
= NtQueueApcThread(hThread
, IntCallUserApc
, pfnAPC
,
793 (PVOID
)dwData
, NULL
);
795 SetLastErrorByStatus(Status
);
797 return NT_SUCCESS(Status
);
804 GetThreadIOPendingFlag(HANDLE hThread
,
810 if(lpIOIsPending
== NULL
)
812 SetLastError(ERROR_INVALID_PARAMETER
);
816 Status
= NtQueryInformationThread(hThread
,
821 if(NT_SUCCESS(Status
))
823 *lpIOIsPending
= ((IoPending
!= 0) ? TRUE
: FALSE
);
827 SetLastErrorByStatus(Status
);
836 Sleep(DWORD dwMilliseconds
)
838 SleepEx(dwMilliseconds
, FALSE
);
847 SleepEx(DWORD dwMilliseconds
,
850 LARGE_INTEGER Interval
;
853 if (dwMilliseconds
!= INFINITE
)
856 * System time units are 100 nanoseconds (a nanosecond is a billionth of
859 Interval
.QuadPart
= -((ULONGLONG
)dwMilliseconds
* 10000);
863 /* Approximately 292000 years hence */
864 Interval
.QuadPart
= -0x7FFFFFFFFFFFFFFFLL
;
868 errCode
= NtDelayExecution (bAlertable
, &Interval
);
869 if ((bAlertable
) && (errCode
== STATUS_ALERTED
)) goto dowait
;
870 return (errCode
== STATUS_USER_APC
) ? WAIT_IO_COMPLETION
: 0;
874 typedef struct _QUEUE_USER_WORKITEM_CONTEXT
876 LPTHREAD_START_ROUTINE Function
;
878 } QUEUE_USER_WORKITEM_CONTEXT
, *PQUEUE_USER_WORKITEM_CONTEXT
;
882 InternalWorkItemTrampoline(PVOID Context
)
884 QUEUE_USER_WORKITEM_CONTEXT Info
;
886 ASSERT(Context
!= NULL
);
888 /* Save the context to the stack */
889 Info
= *(volatile QUEUE_USER_WORKITEM_CONTEXT
*)Context
;
891 /* Free the context before calling the callback. This avoids
892 a memory leak in case the thread dies... */
893 RtlFreeHeap(RtlGetProcessHeap(),
897 /* Call the real callback */
898 Info
.Function(Info
.Context
);
908 LPTHREAD_START_ROUTINE Function
,
913 PQUEUE_USER_WORKITEM_CONTEXT WorkItemContext
;
916 /* Save the context for the trampoline function */
917 WorkItemContext
= RtlAllocateHeap(RtlGetProcessHeap(),
919 sizeof(*WorkItemContext
));
920 if (WorkItemContext
== NULL
)
922 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
926 WorkItemContext
->Function
= Function
;
927 WorkItemContext
->Context
= Context
;
929 /* NOTE: Don't use Function directly since the callback signature
930 differs. This might cause problems on certain platforms... */
931 Status
= RtlQueueWorkItem(InternalWorkItemTrampoline
,
934 if (!NT_SUCCESS(Status
))
936 /* Free the allocated context in case of failure */
937 RtlFreeHeap(RtlGetProcessHeap(),
941 SetLastErrorByStatus(Status
);