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 ******************************************************************/
19 #define HIGH_PRIORITY 31
20 #define SXS_SUPPORT_FIXME
22 /* FUNCTIONS *****************************************************************/
24 LONG
BaseThreadExceptionFilter(EXCEPTION_POINTERS
* ExceptionInfo
)
26 LONG ExceptionDisposition
= EXCEPTION_EXECUTE_HANDLER
;
28 if (GlobalTopLevelExceptionFilter
!= NULL
)
32 ExceptionDisposition
= GlobalTopLevelExceptionFilter(ExceptionInfo
);
34 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
36 ExceptionDisposition
= UnhandledExceptionFilter(ExceptionInfo
);
41 return ExceptionDisposition
;
47 BaseThreadStartup(LPTHREAD_START_ROUTINE lpStartAddress
,
50 volatile UINT uExitCode
= 0;
52 /* Attempt to call the Thread Start Address */
55 /* Get the exit code from the Thread Start */
56 uExitCode
= (lpStartAddress
)((PVOID
)lpParameter
);
58 _SEH2_EXCEPT(BaseThreadExceptionFilter(_SEH2_GetExceptionInformation()))
60 /* Get the Exit code from the SEH Handler */
61 uExitCode
= _SEH2_GetExceptionCode();
65 ExitThread(uExitCode
);
73 CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes
,
75 LPTHREAD_START_ROUTINE lpStartAddress
,
77 DWORD dwCreationFlags
,
80 /* Act as if we're going to create a remote thread in ourselves */
81 return CreateRemoteThread(NtCurrentProcess(),
95 CreateRemoteThread(HANDLE hProcess
,
96 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
98 LPTHREAD_START_ROUTINE lpStartAddress
,
100 DWORD dwCreationFlags
,
104 INITIAL_TEB InitialTeb
;
107 OBJECT_ATTRIBUTES LocalObjectAttributes
;
108 POBJECT_ATTRIBUTES ObjectAttributes
;
112 DPRINT("CreateRemoteThread: hProcess: %ld dwStackSize: %ld lpStartAddress"
113 ": %p lpParameter: %lx, dwCreationFlags: %lx\n", hProcess
,
114 dwStackSize
, lpStartAddress
, lpParameter
, dwCreationFlags
);
116 /* Clear the Context */
117 RtlZeroMemory(&Context
, sizeof(CONTEXT
));
120 ClientId
.UniqueProcess
= hProcess
;
122 /* Create the Stack */
123 Status
= BasepCreateStack(hProcess
,
125 dwCreationFlags
& STACK_SIZE_PARAM_IS_A_RESERVATION
?
128 if(!NT_SUCCESS(Status
))
130 SetLastErrorByStatus(Status
);
134 /* Create Initial Context */
135 BasepInitializeContext(&Context
,
138 InitialTeb
.StackBase
,
141 /* initialize the attributes for the thread object */
142 ObjectAttributes
= BasepConvertObjectAttributes(&LocalObjectAttributes
,
146 /* Create the Kernel Thread Object */
147 Status
= NtCreateThread(&hThread
,
155 if(!NT_SUCCESS(Status
))
157 BasepFreeStack(hProcess
, &InitialTeb
);
158 SetLastErrorByStatus(Status
);
162 /* Are we in the same process? */
163 if (hProcess
== NtCurrentProcess())
166 PVOID ActivationContextStack
;
167 THREAD_BASIC_INFORMATION ThreadBasicInfo
;
168 #ifndef SXS_SUPPORT_FIXME
169 ACTIVATION_CONTEXT_BASIC_INFORMATION ActivationCtxInfo
;
175 Status
= NtQueryInformationThread(hThread
,
176 ThreadBasicInformation
,
178 sizeof(ThreadBasicInfo
),
180 if (NT_SUCCESS(Status
))
182 /* Allocate the Activation Context Stack */
183 Status
= RtlAllocateActivationContextStack(&ActivationContextStack
);
186 if (NT_SUCCESS(Status
))
188 Teb
= ThreadBasicInfo
.TebBaseAddress
;
191 Teb
->ActivationContextStackPointer
= ActivationContextStack
;
192 #ifndef SXS_SUPPORT_FIXME
193 /* Query the Context */
194 Status
= RtlQueryInformationActivationContext(1,
197 ActivationContextBasicInformation
,
199 sizeof(ActivationCtxInfo
),
201 if (NT_SUCCESS(Status
))
203 /* Does it need to be activated? */
204 if (!ActivationCtxInfo
.hActCtx
)
207 Status
= RtlActivateActivationContext(1,
208 ActivationCtxInfo
.hActCtx
,
210 if (!NT_SUCCESS(Status
))
211 DPRINT1("RtlActivateActivationContext failed %x\n", Status
);
215 DPRINT1("RtlQueryInformationActivationContext failed %x\n", Status
);
219 DPRINT1("RtlAllocateActivationContextStack failed %x\n", Status
);
222 /* FIXME: Notify CSR */
225 if(lpThreadId
) *lpThreadId
= (DWORD
)ClientId
.UniqueThread
;
227 /* Resume it if asked */
228 if (!(dwCreationFlags
& CREATE_SUSPENDED
))
230 NtResumeThread(hThread
, &Dummy
);
233 /* Return handle to thread */
242 ExitThread(DWORD uExitCode
)
248 * Terminate process if this is the last thread
249 * of the current process
251 Status
= NtQueryInformationThread(NtCurrentThread(),
256 if (NT_SUCCESS(Status
) && LastThread
)
258 /* Exit the Process */
259 ExitProcess(uExitCode
);
262 /* Notify DLLs and TLS Callbacks of termination */
265 /* Tell the Kernel to free the Stack */
266 NtCurrentTeb()->FreeStackOnTermination
= TRUE
;
267 NtTerminateThread(NULL
, uExitCode
);
269 /* We should never reach this place */
270 DPRINT1("It should not happen\n");
279 OpenThread(DWORD dwDesiredAccess
,
285 OBJECT_ATTRIBUTES ObjectAttributes
;
288 ClientId
.UniqueProcess
= 0;
289 ClientId
.UniqueThread
= ULongToHandle(dwThreadId
);
291 InitializeObjectAttributes(&ObjectAttributes
,
293 (bInheritHandle
? OBJ_INHERIT
: 0),
297 Status
= NtOpenThread(&ThreadHandle
,
301 if (!NT_SUCCESS(Status
))
303 SetLastErrorByStatus(Status
);
316 return NtCurrentTeb();
326 return NtYieldExecution() != STATUS_NO_YIELD_PERFORMED
;
335 GetCurrentThreadId(VOID
)
337 return (DWORD
)(NtCurrentTeb()->ClientId
).UniqueThread
;
345 GetThreadTimes(HANDLE hThread
,
346 LPFILETIME lpCreationTime
,
347 LPFILETIME lpExitTime
,
348 LPFILETIME lpKernelTime
,
349 LPFILETIME lpUserTime
)
351 KERNEL_USER_TIMES KernelUserTimes
;
354 Status
= NtQueryInformationThread(hThread
,
357 sizeof(KERNEL_USER_TIMES
),
359 if (!NT_SUCCESS(Status
))
361 SetLastErrorByStatus(Status
);
365 *lpCreationTime
= *(LPFILETIME
)&KernelUserTimes
.CreateTime
;
366 *lpExitTime
= *(LPFILETIME
)&KernelUserTimes
.ExitTime
;
367 *lpKernelTime
= *(LPFILETIME
)&KernelUserTimes
.KernelTime
;
368 *lpUserTime
= *(LPFILETIME
)&KernelUserTimes
.UserTime
;
377 GetThreadContext(HANDLE hThread
,
382 Status
= NtGetContextThread(hThread
, lpContext
);
383 if (!NT_SUCCESS(Status
))
385 SetLastErrorByStatus(Status
);
397 SetThreadContext(HANDLE hThread
,
398 CONST CONTEXT
*lpContext
)
402 Status
= NtSetContextThread(hThread
, (PCONTEXT
)lpContext
);
403 if (!NT_SUCCESS(Status
))
405 SetLastErrorByStatus(Status
);
417 GetExitCodeThread(HANDLE hThread
,
420 THREAD_BASIC_INFORMATION ThreadBasic
;
423 Status
= NtQueryInformationThread(hThread
,
424 ThreadBasicInformation
,
426 sizeof(THREAD_BASIC_INFORMATION
),
428 if (!NT_SUCCESS(Status
))
430 SetLastErrorByStatus(Status
);
434 *lpExitCode
= ThreadBasic
.ExitStatus
;
443 ResumeThread(HANDLE hThread
)
445 ULONG PreviousResumeCount
;
448 Status
= NtResumeThread(hThread
, &PreviousResumeCount
);
449 if (!NT_SUCCESS(Status
))
451 SetLastErrorByStatus(Status
);
455 return PreviousResumeCount
;
463 TerminateThread(HANDLE hThread
,
470 SetLastError(ERROR_INVALID_HANDLE
);
474 Status
= NtTerminateThread(hThread
, dwExitCode
);
475 if (!NT_SUCCESS(Status
))
477 SetLastErrorByStatus(Status
);
489 SuspendThread(HANDLE hThread
)
491 ULONG PreviousSuspendCount
;
494 Status
= NtSuspendThread(hThread
, &PreviousSuspendCount
);
495 if (!NT_SUCCESS(Status
))
497 SetLastErrorByStatus(Status
);
501 return PreviousSuspendCount
;
509 SetThreadAffinityMask(HANDLE hThread
,
510 DWORD_PTR dwThreadAffinityMask
)
512 THREAD_BASIC_INFORMATION ThreadBasic
;
513 KAFFINITY AffinityMask
;
516 AffinityMask
= (KAFFINITY
)dwThreadAffinityMask
;
518 Status
= NtQueryInformationThread(hThread
,
519 ThreadBasicInformation
,
521 sizeof(THREAD_BASIC_INFORMATION
),
523 if (!NT_SUCCESS(Status
))
525 SetLastErrorByStatus(Status
);
529 Status
= NtSetInformationThread(hThread
,
533 if (!NT_SUCCESS(Status
))
535 SetLastErrorByStatus(Status
);
536 ThreadBasic
.AffinityMask
= 0;
539 return ThreadBasic
.AffinityMask
;
547 SetThreadPriority(HANDLE hThread
,
550 LONG 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
;
621 GetThreadPriorityBoost(IN HANDLE hThread
,
622 OUT PBOOL pDisablePriorityBoost
)
627 Status
= NtQueryInformationThread(hThread
,
632 if (!NT_SUCCESS(Status
))
634 SetLastErrorByStatus(Status
);
638 *pDisablePriorityBoost
= 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 /* Set the selector and do the query */
681 DescriptionTableEntry
.Selector
= dwSelector
;
682 Status
= NtQueryInformationThread(hThread
,
683 ThreadDescriptorTableEntry
,
684 &DescriptionTableEntry
,
685 sizeof(DESCRIPTOR_TABLE_ENTRY
),
687 if (!NT_SUCCESS(Status
))
690 SetLastErrorByStatus(Status
);
694 /* Success, return the selector */
695 *lpSelectorEntry
= DescriptionTableEntry
.Descriptor
;
704 SetThreadIdealProcessor(HANDLE hThread
,
705 DWORD dwIdealProcessor
)
709 Status
= NtSetInformationThread(hThread
,
710 ThreadIdealProcessor
,
713 if (!NT_SUCCESS(Status
))
715 SetLastErrorByStatus(Status
);
719 return (DWORD
)Status
;
726 GetProcessIdOfThread(HANDLE Thread
)
728 THREAD_BASIC_INFORMATION ThreadBasic
;
731 Status
= NtQueryInformationThread(Thread
,
732 ThreadBasicInformation
,
734 sizeof(THREAD_BASIC_INFORMATION
),
736 if(!NT_SUCCESS(Status
))
738 SetLastErrorByStatus(Status
);
742 return (DWORD
)ThreadBasic
.ClientId
.UniqueProcess
;
749 GetThreadId(HANDLE Thread
)
751 THREAD_BASIC_INFORMATION ThreadBasic
;
754 Status
= NtQueryInformationThread(Thread
,
755 ThreadBasicInformation
,
757 sizeof(THREAD_BASIC_INFORMATION
),
759 if(!NT_SUCCESS(Status
))
761 SetLastErrorByStatus(Status
);
765 return (DWORD
)ThreadBasic
.ClientId
.UniqueThread
;
772 SetThreadUILanguage(LANGID LangId
)
774 DPRINT1("SetThreadUILanguage(0x%4x) unimplemented!\n", LangId
);
779 IntCallUserApc(PVOID Function
, PVOID dwData
, PVOID Argument3
)
781 PAPCFUNC pfnAPC
= (PAPCFUNC
)Function
;
782 pfnAPC((ULONG_PTR
)dwData
);
789 QueueUserAPC(PAPCFUNC pfnAPC
, HANDLE hThread
, ULONG_PTR dwData
)
793 Status
= NtQueueApcThread(hThread
, IntCallUserApc
, pfnAPC
,
794 (PVOID
)dwData
, NULL
);
795 if (!NT_SUCCESS(Status
))
797 SetLastErrorByStatus(Status
);
808 GetThreadIOPendingFlag(HANDLE hThread
,
814 if(lpIOIsPending
== NULL
)
816 SetLastError(ERROR_INVALID_PARAMETER
);
820 Status
= NtQueryInformationThread(hThread
,
825 if(NT_SUCCESS(Status
))
827 *lpIOIsPending
= ((IoPending
!= 0) ? TRUE
: FALSE
);
831 SetLastErrorByStatus(Status
);
840 Sleep(DWORD dwMilliseconds
)
842 SleepEx(dwMilliseconds
, FALSE
);
851 SleepEx(DWORD dwMilliseconds
,
854 LARGE_INTEGER Interval
;
857 if (dwMilliseconds
!= INFINITE
)
860 * System time units are 100 nanoseconds (a nanosecond is a billionth of
863 Interval
.QuadPart
= -((LONGLONG
)dwMilliseconds
* 10000);
867 /* Approximately 292000 years hence */
868 Interval
.QuadPart
= -0x7FFFFFFFFFFFFFFFLL
;
872 errCode
= NtDelayExecution ((BOOLEAN
)bAlertable
, &Interval
);
873 if ((bAlertable
) && (errCode
== STATUS_ALERTED
)) goto dowait
;
874 return (errCode
== STATUS_USER_APC
) ? WAIT_IO_COMPLETION
: 0;
878 typedef struct _QUEUE_USER_WORKITEM_CONTEXT
880 LPTHREAD_START_ROUTINE Function
;
882 } QUEUE_USER_WORKITEM_CONTEXT
, *PQUEUE_USER_WORKITEM_CONTEXT
;
886 InternalWorkItemTrampoline(PVOID Context
)
888 QUEUE_USER_WORKITEM_CONTEXT Info
;
892 /* Save the context to the stack */
893 Info
= *(volatile QUEUE_USER_WORKITEM_CONTEXT
*)Context
;
895 /* Free the context before calling the callback. This avoids
896 a memory leak in case the thread dies... */
897 RtlFreeHeap(RtlGetProcessHeap(),
901 /* Call the real callback */
902 Info
.Function(Info
.Context
);
912 LPTHREAD_START_ROUTINE Function
,
917 PQUEUE_USER_WORKITEM_CONTEXT WorkItemContext
;
920 /* Save the context for the trampoline function */
921 WorkItemContext
= RtlAllocateHeap(RtlGetProcessHeap(),
923 sizeof(*WorkItemContext
));
924 if (WorkItemContext
== NULL
)
926 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
930 WorkItemContext
->Function
= Function
;
931 WorkItemContext
->Context
= Context
;
933 /* NOTE: Don't use Function directly since the callback signature
934 differs. This might cause problems on certain platforms... */
935 Status
= RtlQueueWorkItem(InternalWorkItemTrampoline
,
938 if (!NT_SUCCESS(Status
))
940 /* Free the allocated context in case of failure */
941 RtlFreeHeap(RtlGetProcessHeap(),
945 SetLastErrorByStatus(Status
);
958 RegisterWaitForSingleObject(
959 PHANDLE phNewWaitObject
,
961 WAITORTIMERCALLBACK Callback
,
963 ULONG dwMilliseconds
,
967 NTSTATUS Status
= RtlRegisterWait(phNewWaitObject
,
974 if (!NT_SUCCESS(Status
))
976 SetLastErrorByStatus(Status
);
988 RegisterWaitForSingleObjectEx(
990 WAITORTIMERCALLBACK Callback
,
992 ULONG dwMilliseconds
,
997 HANDLE hNewWaitObject
;
999 Status
= RtlRegisterWait(&hNewWaitObject
,
1006 if (!NT_SUCCESS(Status
))
1008 SetLastErrorByStatus(Status
);
1012 return hNewWaitObject
;
1025 NTSTATUS Status
= RtlDeregisterWaitEx(WaitHandle
, NULL
);
1027 if (!NT_SUCCESS(Status
))
1029 SetLastErrorByStatus(Status
);
1044 HANDLE CompletionEvent
1047 NTSTATUS Status
= RtlDeregisterWaitEx(WaitHandle
, CompletionEvent
);
1049 if (!NT_SUCCESS(Status
))
1051 SetLastErrorByStatus(Status
);