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
21 /* FUNCTIONS *****************************************************************/
23 LONG
BaseThreadExceptionFilter(EXCEPTION_POINTERS
* ExceptionInfo
)
25 LONG ExceptionDisposition
= EXCEPTION_EXECUTE_HANDLER
;
27 if (GlobalTopLevelExceptionFilter
!= NULL
)
31 ExceptionDisposition
= GlobalTopLevelExceptionFilter(ExceptionInfo
);
33 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
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 _SEH2_EXCEPT(BaseThreadExceptionFilter(_SEH2_GetExceptionInformation()))
59 /* Get the Exit code from the SEH Handler */
60 uExitCode
= _SEH2_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
);
262 OpenThread(DWORD dwDesiredAccess
,
268 OBJECT_ATTRIBUTES ObjectAttributes
;
271 ClientId
.UniqueProcess
= 0;
272 ClientId
.UniqueThread
= ULongToHandle(dwThreadId
);
274 InitializeObjectAttributes(&ObjectAttributes
,
276 (bInheritHandle
? OBJ_INHERIT
: 0),
280 Status
= NtOpenThread(&ThreadHandle
,
284 if (!NT_SUCCESS(Status
))
286 SetLastErrorByStatus(Status
);
299 return NtCurrentTeb();
309 return NtYieldExecution() != STATUS_NO_YIELD_PERFORMED
;
318 GetCurrentThreadId(VOID
)
320 return (DWORD
)(NtCurrentTeb()->ClientId
).UniqueThread
;
328 GetThreadTimes(HANDLE hThread
,
329 LPFILETIME lpCreationTime
,
330 LPFILETIME lpExitTime
,
331 LPFILETIME lpKernelTime
,
332 LPFILETIME lpUserTime
)
334 KERNEL_USER_TIMES KernelUserTimes
;
337 Status
= NtQueryInformationThread(hThread
,
340 sizeof(KERNEL_USER_TIMES
),
342 if (!NT_SUCCESS(Status
))
344 SetLastErrorByStatus(Status
);
348 *lpCreationTime
= *(LPFILETIME
)&KernelUserTimes
.CreateTime
;
349 *lpExitTime
= *(LPFILETIME
)&KernelUserTimes
.ExitTime
;
350 *lpKernelTime
= *(LPFILETIME
)&KernelUserTimes
.KernelTime
;
351 *lpUserTime
= *(LPFILETIME
)&KernelUserTimes
.UserTime
;
360 GetThreadContext(HANDLE hThread
,
365 Status
= NtGetContextThread(hThread
, lpContext
);
366 if (!NT_SUCCESS(Status
))
368 SetLastErrorByStatus(Status
);
380 SetThreadContext(HANDLE hThread
,
381 CONST CONTEXT
*lpContext
)
385 Status
= NtSetContextThread(hThread
, (PCONTEXT
)lpContext
);
386 if (!NT_SUCCESS(Status
))
388 SetLastErrorByStatus(Status
);
400 GetExitCodeThread(HANDLE hThread
,
403 THREAD_BASIC_INFORMATION ThreadBasic
;
406 Status
= NtQueryInformationThread(hThread
,
407 ThreadBasicInformation
,
409 sizeof(THREAD_BASIC_INFORMATION
),
411 if (!NT_SUCCESS(Status
))
413 SetLastErrorByStatus(Status
);
417 *lpExitCode
= ThreadBasic
.ExitStatus
;
426 ResumeThread(HANDLE hThread
)
428 ULONG PreviousResumeCount
;
431 Status
= NtResumeThread(hThread
, &PreviousResumeCount
);
432 if (!NT_SUCCESS(Status
))
434 SetLastErrorByStatus(Status
);
438 return PreviousResumeCount
;
446 TerminateThread(HANDLE hThread
,
453 SetLastError(ERROR_INVALID_HANDLE
);
457 Status
= NtTerminateThread(hThread
, dwExitCode
);
458 if (!NT_SUCCESS(Status
))
460 SetLastErrorByStatus(Status
);
472 SuspendThread(HANDLE hThread
)
474 ULONG PreviousSuspendCount
;
477 Status
= NtSuspendThread(hThread
, &PreviousSuspendCount
);
478 if (!NT_SUCCESS(Status
))
480 SetLastErrorByStatus(Status
);
484 return PreviousSuspendCount
;
492 SetThreadAffinityMask(HANDLE hThread
,
493 DWORD_PTR dwThreadAffinityMask
)
495 THREAD_BASIC_INFORMATION ThreadBasic
;
496 KAFFINITY AffinityMask
;
499 AffinityMask
= (KAFFINITY
)dwThreadAffinityMask
;
501 Status
= NtQueryInformationThread(hThread
,
502 ThreadBasicInformation
,
504 sizeof(THREAD_BASIC_INFORMATION
),
506 if (!NT_SUCCESS(Status
))
508 SetLastErrorByStatus(Status
);
512 Status
= NtSetInformationThread(hThread
,
516 if (!NT_SUCCESS(Status
))
518 SetLastErrorByStatus(Status
);
519 ThreadBasic
.AffinityMask
= 0;
522 return ThreadBasic
.AffinityMask
;
530 SetThreadPriority(HANDLE hThread
,
533 LONG Prio
= nPriority
;
536 /* Check if values forcing saturation should be used */
537 if (Prio
== THREAD_PRIORITY_TIME_CRITICAL
)
539 Prio
= (HIGH_PRIORITY
+ 1) / 2;
541 else if (Prio
== THREAD_PRIORITY_IDLE
)
543 Prio
= -((HIGH_PRIORITY
+ 1) / 2);
546 /* Set the Base Priority */
547 Status
= NtSetInformationThread(hThread
,
551 if (!NT_SUCCESS(Status
))
554 SetLastErrorByStatus(Status
);
567 GetThreadPriority(HANDLE hThread
)
569 THREAD_BASIC_INFORMATION ThreadBasic
;
572 /* Query the Base Priority Increment */
573 Status
= NtQueryInformationThread(hThread
,
574 ThreadBasicInformation
,
576 sizeof(THREAD_BASIC_INFORMATION
),
578 if (!NT_SUCCESS(Status
))
581 SetLastErrorByStatus(Status
);
582 return THREAD_PRIORITY_ERROR_RETURN
;
585 /* Do some conversions for out of boundary values */
586 if (ThreadBasic
.BasePriority
> THREAD_BASE_PRIORITY_MAX
)
588 ThreadBasic
.BasePriority
= THREAD_PRIORITY_TIME_CRITICAL
;
590 else if (ThreadBasic
.BasePriority
< THREAD_BASE_PRIORITY_MIN
)
592 ThreadBasic
.BasePriority
= THREAD_PRIORITY_IDLE
;
595 /* Return the final result */
596 return ThreadBasic
.BasePriority
;
604 GetThreadPriorityBoost(IN HANDLE hThread
,
605 OUT PBOOL pDisablePriorityBoost
)
610 Status
= NtQueryInformationThread(hThread
,
615 if (!NT_SUCCESS(Status
))
617 SetLastErrorByStatus(Status
);
621 *pDisablePriorityBoost
= PriorityBoost
;
630 SetThreadPriorityBoost(IN HANDLE hThread
,
631 IN BOOL bDisablePriorityBoost
)
636 PriorityBoost
= (ULONG
)bDisablePriorityBoost
;
638 Status
= NtSetInformationThread(hThread
,
642 if (!NT_SUCCESS(Status
))
644 SetLastErrorByStatus(Status
);
656 GetThreadSelectorEntry(IN HANDLE hThread
,
658 OUT LPLDT_ENTRY lpSelectorEntry
)
661 DESCRIPTOR_TABLE_ENTRY DescriptionTableEntry
;
664 /* Set the selector and do the query */
665 DescriptionTableEntry
.Selector
= dwSelector
;
666 Status
= NtQueryInformationThread(hThread
,
667 ThreadDescriptorTableEntry
,
668 &DescriptionTableEntry
,
669 sizeof(DESCRIPTOR_TABLE_ENTRY
),
671 if (!NT_SUCCESS(Status
))
674 SetLastErrorByStatus(Status
);
678 /* Success, return the selector */
679 *lpSelectorEntry
= DescriptionTableEntry
.Descriptor
;
682 DPRINT1("Calling GetThreadSelectorEntry!\n");
692 SetThreadIdealProcessor(HANDLE hThread
,
693 DWORD dwIdealProcessor
)
697 Status
= NtSetInformationThread(hThread
,
698 ThreadIdealProcessor
,
701 if (!NT_SUCCESS(Status
))
703 SetLastErrorByStatus(Status
);
707 return (DWORD
)Status
;
714 GetProcessIdOfThread(HANDLE Thread
)
716 THREAD_BASIC_INFORMATION ThreadBasic
;
719 Status
= NtQueryInformationThread(Thread
,
720 ThreadBasicInformation
,
722 sizeof(THREAD_BASIC_INFORMATION
),
724 if(!NT_SUCCESS(Status
))
726 SetLastErrorByStatus(Status
);
730 return (DWORD
)ThreadBasic
.ClientId
.UniqueProcess
;
737 GetThreadId(HANDLE Thread
)
739 THREAD_BASIC_INFORMATION ThreadBasic
;
742 Status
= NtQueryInformationThread(Thread
,
743 ThreadBasicInformation
,
745 sizeof(THREAD_BASIC_INFORMATION
),
747 if(!NT_SUCCESS(Status
))
749 SetLastErrorByStatus(Status
);
753 return (DWORD
)ThreadBasic
.ClientId
.UniqueThread
;
760 SetThreadUILanguage(LANGID LangId
)
762 DPRINT1("SetThreadUILanguage(0x%4x) unimplemented!\n", LangId
);
767 IntCallUserApc(PVOID Function
, PVOID dwData
, PVOID Argument3
)
769 PAPCFUNC pfnAPC
= (PAPCFUNC
)Function
;
770 pfnAPC((ULONG_PTR
)dwData
);
777 QueueUserAPC(PAPCFUNC pfnAPC
, HANDLE hThread
, ULONG_PTR dwData
)
781 Status
= NtQueueApcThread(hThread
, IntCallUserApc
, pfnAPC
,
782 (PVOID
)dwData
, NULL
);
783 if (!NT_SUCCESS(Status
))
785 SetLastErrorByStatus(Status
);
796 GetThreadIOPendingFlag(HANDLE hThread
,
802 if(lpIOIsPending
== NULL
)
804 SetLastError(ERROR_INVALID_PARAMETER
);
808 Status
= NtQueryInformationThread(hThread
,
813 if(NT_SUCCESS(Status
))
815 *lpIOIsPending
= ((IoPending
!= 0) ? TRUE
: FALSE
);
819 SetLastErrorByStatus(Status
);
828 Sleep(DWORD dwMilliseconds
)
830 SleepEx(dwMilliseconds
, FALSE
);
839 SleepEx(DWORD dwMilliseconds
,
842 LARGE_INTEGER Interval
;
845 if (dwMilliseconds
!= INFINITE
)
848 * System time units are 100 nanoseconds (a nanosecond is a billionth of
851 Interval
.QuadPart
= -((LONGLONG
)dwMilliseconds
* 10000);
855 /* Approximately 292000 years hence */
856 Interval
.QuadPart
= -0x7FFFFFFFFFFFFFFFLL
;
860 errCode
= NtDelayExecution ((BOOLEAN
)bAlertable
, &Interval
);
861 if ((bAlertable
) && (errCode
== STATUS_ALERTED
)) goto dowait
;
862 return (errCode
== STATUS_USER_APC
) ? WAIT_IO_COMPLETION
: 0;
866 typedef struct _QUEUE_USER_WORKITEM_CONTEXT
868 LPTHREAD_START_ROUTINE Function
;
870 } QUEUE_USER_WORKITEM_CONTEXT
, *PQUEUE_USER_WORKITEM_CONTEXT
;
874 InternalWorkItemTrampoline(PVOID Context
)
876 QUEUE_USER_WORKITEM_CONTEXT Info
;
880 /* Save the context to the stack */
881 Info
= *(volatile QUEUE_USER_WORKITEM_CONTEXT
*)Context
;
883 /* Free the context before calling the callback. This avoids
884 a memory leak in case the thread dies... */
885 RtlFreeHeap(RtlGetProcessHeap(),
889 /* Call the real callback */
890 Info
.Function(Info
.Context
);
900 LPTHREAD_START_ROUTINE Function
,
905 PQUEUE_USER_WORKITEM_CONTEXT WorkItemContext
;
908 /* Save the context for the trampoline function */
909 WorkItemContext
= RtlAllocateHeap(RtlGetProcessHeap(),
911 sizeof(*WorkItemContext
));
912 if (WorkItemContext
== NULL
)
914 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
918 WorkItemContext
->Function
= Function
;
919 WorkItemContext
->Context
= Context
;
921 /* NOTE: Don't use Function directly since the callback signature
922 differs. This might cause problems on certain platforms... */
923 Status
= RtlQueueWorkItem(InternalWorkItemTrampoline
,
926 if (!NT_SUCCESS(Status
))
928 /* Free the allocated context in case of failure */
929 RtlFreeHeap(RtlGetProcessHeap(),
933 SetLastErrorByStatus(Status
);
946 RegisterWaitForSingleObject(
947 PHANDLE phNewWaitObject
,
949 WAITORTIMERCALLBACK Callback
,
951 ULONG dwMilliseconds
,
955 NTSTATUS Status
= RtlRegisterWait(phNewWaitObject
,
962 if (!NT_SUCCESS(Status
))
964 SetLastErrorByStatus(Status
);
976 RegisterWaitForSingleObjectEx(
978 WAITORTIMERCALLBACK Callback
,
980 ULONG dwMilliseconds
,
985 HANDLE hNewWaitObject
;
987 Status
= RtlRegisterWait(&hNewWaitObject
,
994 if (!NT_SUCCESS(Status
))
996 SetLastErrorByStatus(Status
);
1000 return hNewWaitObject
;
1013 NTSTATUS Status
= RtlDeregisterWaitEx(WaitHandle
, NULL
);
1015 if (!NT_SUCCESS(Status
))
1017 SetLastErrorByStatus(Status
);
1032 HANDLE CompletionEvent
1035 NTSTATUS Status
= RtlDeregisterWaitEx(WaitHandle
, CompletionEvent
);
1037 if (!NT_SUCCESS(Status
))
1039 SetLastErrorByStatus(Status
);