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
24 BasepNotifyCsrOfThread(IN HANDLE ThreadHandle
,
25 IN PCLIENT_ID ClientId
);
27 /* FUNCTIONS *****************************************************************/
29 LONG
BaseThreadExceptionFilter(EXCEPTION_POINTERS
* ExceptionInfo
)
31 LONG ExceptionDisposition
= EXCEPTION_EXECUTE_HANDLER
;
33 if (GlobalTopLevelExceptionFilter
!= NULL
)
37 ExceptionDisposition
= GlobalTopLevelExceptionFilter(ExceptionInfo
);
39 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
41 ExceptionDisposition
= UnhandledExceptionFilter(ExceptionInfo
);
46 return ExceptionDisposition
;
52 BaseThreadStartup(LPTHREAD_START_ROUTINE lpStartAddress
,
55 volatile UINT uExitCode
= 0;
57 /* Attempt to call the Thread Start Address */
60 /* Get the exit code from the Thread Start */
61 uExitCode
= (lpStartAddress
)((PVOID
)lpParameter
);
63 _SEH2_EXCEPT(BaseThreadExceptionFilter(_SEH2_GetExceptionInformation()))
65 /* Get the Exit code from the SEH Handler */
66 uExitCode
= _SEH2_GetExceptionCode();
70 ExitThread(uExitCode
);
78 CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes
,
80 LPTHREAD_START_ROUTINE lpStartAddress
,
82 DWORD dwCreationFlags
,
85 /* Act as if we're going to create a remote thread in ourselves */
86 return CreateRemoteThread(NtCurrentProcess(),
100 CreateRemoteThread(HANDLE hProcess
,
101 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
103 LPTHREAD_START_ROUTINE lpStartAddress
,
105 DWORD dwCreationFlags
,
109 INITIAL_TEB InitialTeb
;
112 OBJECT_ATTRIBUTES LocalObjectAttributes
;
113 POBJECT_ATTRIBUTES ObjectAttributes
;
117 DPRINT("CreateRemoteThread: hProcess: %ld dwStackSize: %ld lpStartAddress"
118 ": %p lpParameter: %lx, dwCreationFlags: %lx\n", hProcess
,
119 dwStackSize
, lpStartAddress
, lpParameter
, dwCreationFlags
);
121 /* Clear the Context */
122 RtlZeroMemory(&Context
, sizeof(CONTEXT
));
125 ClientId
.UniqueProcess
= hProcess
;
127 /* Create the Stack */
128 Status
= BasepCreateStack(hProcess
,
130 dwCreationFlags
& STACK_SIZE_PARAM_IS_A_RESERVATION
?
133 if(!NT_SUCCESS(Status
))
135 SetLastErrorByStatus(Status
);
139 /* Create Initial Context */
140 BasepInitializeContext(&Context
,
143 InitialTeb
.StackBase
,
146 /* initialize the attributes for the thread object */
147 ObjectAttributes
= BasepConvertObjectAttributes(&LocalObjectAttributes
,
151 /* Create the Kernel Thread Object */
152 Status
= NtCreateThread(&hThread
,
160 if(!NT_SUCCESS(Status
))
162 BasepFreeStack(hProcess
, &InitialTeb
);
163 SetLastErrorByStatus(Status
);
167 /* Are we in the same process? */
168 if (hProcess
== NtCurrentProcess())
171 PVOID ActivationContextStack
;
172 THREAD_BASIC_INFORMATION ThreadBasicInfo
;
173 #ifndef SXS_SUPPORT_FIXME
174 ACTIVATION_CONTEXT_BASIC_INFORMATION ActivationCtxInfo
;
180 Status
= NtQueryInformationThread(hThread
,
181 ThreadBasicInformation
,
183 sizeof(ThreadBasicInfo
),
185 if (NT_SUCCESS(Status
))
187 /* Allocate the Activation Context Stack */
188 Status
= RtlAllocateActivationContextStack(&ActivationContextStack
);
191 if (NT_SUCCESS(Status
))
193 Teb
= ThreadBasicInfo
.TebBaseAddress
;
196 Teb
->ActivationContextStackPointer
= ActivationContextStack
;
197 #ifndef SXS_SUPPORT_FIXME
198 /* Query the Context */
199 Status
= RtlQueryInformationActivationContext(1,
202 ActivationContextBasicInformation
,
204 sizeof(ActivationCtxInfo
),
206 if (NT_SUCCESS(Status
))
208 /* Does it need to be activated? */
209 if (!ActivationCtxInfo
.hActCtx
)
212 Status
= RtlActivateActivationContext(1,
213 ActivationCtxInfo
.hActCtx
,
215 if (!NT_SUCCESS(Status
))
216 DPRINT1("RtlActivateActivationContext failed %x\n", Status
);
220 DPRINT1("RtlQueryInformationActivationContext failed %x\n", Status
);
224 DPRINT1("RtlAllocateActivationContextStack failed %x\n", Status
);
228 Status
= BasepNotifyCsrOfThread(hThread
, &ClientId
);
229 if (!NT_SUCCESS(Status
))
235 if(lpThreadId
) *lpThreadId
= (DWORD
)ClientId
.UniqueThread
;
237 /* Resume it if asked */
238 if (!(dwCreationFlags
& CREATE_SUSPENDED
))
240 NtResumeThread(hThread
, &Dummy
);
243 /* Return handle to thread */
252 ExitThread(DWORD uExitCode
)
258 * Terminate process if this is the last thread
259 * of the current process
261 Status
= NtQueryInformationThread(NtCurrentThread(),
266 if (NT_SUCCESS(Status
) && LastThread
)
268 /* Exit the Process */
269 ExitProcess(uExitCode
);
272 /* Notify DLLs and TLS Callbacks of termination */
275 /* Tell the Kernel to free the Stack */
276 NtCurrentTeb()->FreeStackOnTermination
= TRUE
;
277 NtTerminateThread(NULL
, uExitCode
);
279 /* We should never reach this place */
280 DPRINT1("It should not happen\n");
289 OpenThread(DWORD dwDesiredAccess
,
295 OBJECT_ATTRIBUTES ObjectAttributes
;
298 ClientId
.UniqueProcess
= 0;
299 ClientId
.UniqueThread
= ULongToHandle(dwThreadId
);
301 InitializeObjectAttributes(&ObjectAttributes
,
303 (bInheritHandle
? OBJ_INHERIT
: 0),
307 Status
= NtOpenThread(&ThreadHandle
,
311 if (!NT_SUCCESS(Status
))
313 SetLastErrorByStatus(Status
);
326 return NtCurrentTeb();
336 return NtYieldExecution() != STATUS_NO_YIELD_PERFORMED
;
345 GetCurrentThreadId(VOID
)
347 return (DWORD
)(NtCurrentTeb()->ClientId
).UniqueThread
;
355 GetThreadTimes(HANDLE hThread
,
356 LPFILETIME lpCreationTime
,
357 LPFILETIME lpExitTime
,
358 LPFILETIME lpKernelTime
,
359 LPFILETIME lpUserTime
)
361 KERNEL_USER_TIMES KernelUserTimes
;
364 Status
= NtQueryInformationThread(hThread
,
367 sizeof(KERNEL_USER_TIMES
),
369 if (!NT_SUCCESS(Status
))
371 SetLastErrorByStatus(Status
);
375 *lpCreationTime
= *(LPFILETIME
)&KernelUserTimes
.CreateTime
;
376 *lpExitTime
= *(LPFILETIME
)&KernelUserTimes
.ExitTime
;
377 *lpKernelTime
= *(LPFILETIME
)&KernelUserTimes
.KernelTime
;
378 *lpUserTime
= *(LPFILETIME
)&KernelUserTimes
.UserTime
;
387 GetThreadContext(HANDLE hThread
,
392 Status
= NtGetContextThread(hThread
, lpContext
);
393 if (!NT_SUCCESS(Status
))
395 SetLastErrorByStatus(Status
);
407 SetThreadContext(HANDLE hThread
,
408 CONST CONTEXT
*lpContext
)
412 Status
= NtSetContextThread(hThread
, (PCONTEXT
)lpContext
);
413 if (!NT_SUCCESS(Status
))
415 SetLastErrorByStatus(Status
);
427 GetExitCodeThread(HANDLE hThread
,
430 THREAD_BASIC_INFORMATION ThreadBasic
;
433 Status
= NtQueryInformationThread(hThread
,
434 ThreadBasicInformation
,
436 sizeof(THREAD_BASIC_INFORMATION
),
438 if (!NT_SUCCESS(Status
))
440 SetLastErrorByStatus(Status
);
444 *lpExitCode
= ThreadBasic
.ExitStatus
;
453 ResumeThread(HANDLE hThread
)
455 ULONG PreviousResumeCount
;
458 Status
= NtResumeThread(hThread
, &PreviousResumeCount
);
459 if (!NT_SUCCESS(Status
))
461 SetLastErrorByStatus(Status
);
465 return PreviousResumeCount
;
473 TerminateThread(HANDLE hThread
,
480 SetLastError(ERROR_INVALID_HANDLE
);
484 Status
= NtTerminateThread(hThread
, dwExitCode
);
485 if (!NT_SUCCESS(Status
))
487 SetLastErrorByStatus(Status
);
499 SuspendThread(HANDLE hThread
)
501 ULONG PreviousSuspendCount
;
504 Status
= NtSuspendThread(hThread
, &PreviousSuspendCount
);
505 if (!NT_SUCCESS(Status
))
507 SetLastErrorByStatus(Status
);
511 return PreviousSuspendCount
;
519 SetThreadAffinityMask(HANDLE hThread
,
520 DWORD_PTR dwThreadAffinityMask
)
522 THREAD_BASIC_INFORMATION ThreadBasic
;
523 KAFFINITY AffinityMask
;
526 AffinityMask
= (KAFFINITY
)dwThreadAffinityMask
;
528 Status
= NtQueryInformationThread(hThread
,
529 ThreadBasicInformation
,
531 sizeof(THREAD_BASIC_INFORMATION
),
533 if (!NT_SUCCESS(Status
))
535 SetLastErrorByStatus(Status
);
539 Status
= NtSetInformationThread(hThread
,
543 if (!NT_SUCCESS(Status
))
545 SetLastErrorByStatus(Status
);
546 ThreadBasic
.AffinityMask
= 0;
549 return ThreadBasic
.AffinityMask
;
557 SetThreadPriority(HANDLE hThread
,
560 LONG Prio
= nPriority
;
563 /* Check if values forcing saturation should be used */
564 if (Prio
== THREAD_PRIORITY_TIME_CRITICAL
)
566 Prio
= (HIGH_PRIORITY
+ 1) / 2;
568 else if (Prio
== THREAD_PRIORITY_IDLE
)
570 Prio
= -((HIGH_PRIORITY
+ 1) / 2);
573 /* Set the Base Priority */
574 Status
= NtSetInformationThread(hThread
,
578 if (!NT_SUCCESS(Status
))
581 SetLastErrorByStatus(Status
);
594 GetThreadPriority(HANDLE hThread
)
596 THREAD_BASIC_INFORMATION ThreadBasic
;
599 /* Query the Base Priority Increment */
600 Status
= NtQueryInformationThread(hThread
,
601 ThreadBasicInformation
,
603 sizeof(THREAD_BASIC_INFORMATION
),
605 if (!NT_SUCCESS(Status
))
608 SetLastErrorByStatus(Status
);
609 return THREAD_PRIORITY_ERROR_RETURN
;
612 /* Do some conversions for out of boundary values */
613 if (ThreadBasic
.BasePriority
> THREAD_BASE_PRIORITY_MAX
)
615 ThreadBasic
.BasePriority
= THREAD_PRIORITY_TIME_CRITICAL
;
617 else if (ThreadBasic
.BasePriority
< THREAD_BASE_PRIORITY_MIN
)
619 ThreadBasic
.BasePriority
= THREAD_PRIORITY_IDLE
;
622 /* Return the final result */
623 return ThreadBasic
.BasePriority
;
631 GetThreadPriorityBoost(IN HANDLE hThread
,
632 OUT PBOOL pDisablePriorityBoost
)
637 Status
= NtQueryInformationThread(hThread
,
642 if (!NT_SUCCESS(Status
))
644 SetLastErrorByStatus(Status
);
648 *pDisablePriorityBoost
= PriorityBoost
;
657 SetThreadPriorityBoost(IN HANDLE hThread
,
658 IN BOOL bDisablePriorityBoost
)
663 PriorityBoost
= (ULONG
)bDisablePriorityBoost
;
665 Status
= NtSetInformationThread(hThread
,
669 if (!NT_SUCCESS(Status
))
671 SetLastErrorByStatus(Status
);
683 GetThreadSelectorEntry(IN HANDLE hThread
,
685 OUT LPLDT_ENTRY lpSelectorEntry
)
687 DESCRIPTOR_TABLE_ENTRY DescriptionTableEntry
;
690 /* Set the selector and do the query */
691 DescriptionTableEntry
.Selector
= dwSelector
;
692 Status
= NtQueryInformationThread(hThread
,
693 ThreadDescriptorTableEntry
,
694 &DescriptionTableEntry
,
695 sizeof(DESCRIPTOR_TABLE_ENTRY
),
697 if (!NT_SUCCESS(Status
))
700 SetLastErrorByStatus(Status
);
704 /* Success, return the selector */
705 *lpSelectorEntry
= DescriptionTableEntry
.Descriptor
;
714 SetThreadIdealProcessor(HANDLE hThread
,
715 DWORD dwIdealProcessor
)
719 Status
= NtSetInformationThread(hThread
,
720 ThreadIdealProcessor
,
723 if (!NT_SUCCESS(Status
))
725 SetLastErrorByStatus(Status
);
729 return (DWORD
)Status
;
736 GetProcessIdOfThread(HANDLE Thread
)
738 THREAD_BASIC_INFORMATION ThreadBasic
;
741 Status
= NtQueryInformationThread(Thread
,
742 ThreadBasicInformation
,
744 sizeof(THREAD_BASIC_INFORMATION
),
746 if(!NT_SUCCESS(Status
))
748 SetLastErrorByStatus(Status
);
752 return (DWORD
)ThreadBasic
.ClientId
.UniqueProcess
;
759 GetThreadId(HANDLE Thread
)
761 THREAD_BASIC_INFORMATION ThreadBasic
;
764 Status
= NtQueryInformationThread(Thread
,
765 ThreadBasicInformation
,
767 sizeof(THREAD_BASIC_INFORMATION
),
769 if(!NT_SUCCESS(Status
))
771 SetLastErrorByStatus(Status
);
775 return (DWORD
)ThreadBasic
.ClientId
.UniqueThread
;
782 SetThreadUILanguage(LANGID LangId
)
784 DPRINT1("SetThreadUILanguage(0x%4x) unimplemented!\n", LangId
);
789 IntCallUserApc(PVOID Function
, PVOID dwData
, PVOID Argument3
)
791 PAPCFUNC pfnAPC
= (PAPCFUNC
)Function
;
792 pfnAPC((ULONG_PTR
)dwData
);
799 QueueUserAPC(PAPCFUNC pfnAPC
, HANDLE hThread
, ULONG_PTR dwData
)
803 Status
= NtQueueApcThread(hThread
, IntCallUserApc
, pfnAPC
,
804 (PVOID
)dwData
, NULL
);
805 if (!NT_SUCCESS(Status
))
807 SetLastErrorByStatus(Status
);
818 GetThreadIOPendingFlag(HANDLE hThread
,
824 if(lpIOIsPending
== NULL
)
826 SetLastError(ERROR_INVALID_PARAMETER
);
830 Status
= NtQueryInformationThread(hThread
,
835 if(NT_SUCCESS(Status
))
837 *lpIOIsPending
= ((IoPending
!= 0) ? TRUE
: FALSE
);
841 SetLastErrorByStatus(Status
);
850 Sleep(DWORD dwMilliseconds
)
852 SleepEx(dwMilliseconds
, FALSE
);
861 SleepEx(DWORD dwMilliseconds
,
864 LARGE_INTEGER Interval
;
867 if (dwMilliseconds
!= INFINITE
)
870 * System time units are 100 nanoseconds (a nanosecond is a billionth of
873 Interval
.QuadPart
= -((LONGLONG
)dwMilliseconds
* 10000);
877 /* Approximately 292000 years hence */
878 Interval
.QuadPart
= -0x7FFFFFFFFFFFFFFFLL
;
882 errCode
= NtDelayExecution ((BOOLEAN
)bAlertable
, &Interval
);
883 if ((bAlertable
) && (errCode
== STATUS_ALERTED
)) goto dowait
;
884 return (errCode
== STATUS_USER_APC
) ? WAIT_IO_COMPLETION
: 0;
888 typedef struct _QUEUE_USER_WORKITEM_CONTEXT
890 LPTHREAD_START_ROUTINE Function
;
892 } QUEUE_USER_WORKITEM_CONTEXT
, *PQUEUE_USER_WORKITEM_CONTEXT
;
896 InternalWorkItemTrampoline(PVOID Context
)
898 QUEUE_USER_WORKITEM_CONTEXT Info
;
902 /* Save the context to the stack */
903 Info
= *(volatile QUEUE_USER_WORKITEM_CONTEXT
*)Context
;
905 /* Free the context before calling the callback. This avoids
906 a memory leak in case the thread dies... */
907 RtlFreeHeap(RtlGetProcessHeap(),
911 /* Call the real callback */
912 Info
.Function(Info
.Context
);
922 LPTHREAD_START_ROUTINE Function
,
927 PQUEUE_USER_WORKITEM_CONTEXT WorkItemContext
;
930 /* Save the context for the trampoline function */
931 WorkItemContext
= RtlAllocateHeap(RtlGetProcessHeap(),
933 sizeof(*WorkItemContext
));
934 if (WorkItemContext
== NULL
)
936 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
940 WorkItemContext
->Function
= Function
;
941 WorkItemContext
->Context
= Context
;
943 /* NOTE: Don't use Function directly since the callback signature
944 differs. This might cause problems on certain platforms... */
945 Status
= RtlQueueWorkItem(InternalWorkItemTrampoline
,
948 if (!NT_SUCCESS(Status
))
950 /* Free the allocated context in case of failure */
951 RtlFreeHeap(RtlGetProcessHeap(),
955 SetLastErrorByStatus(Status
);
968 RegisterWaitForSingleObject(
969 PHANDLE phNewWaitObject
,
971 WAITORTIMERCALLBACK Callback
,
973 ULONG dwMilliseconds
,
977 NTSTATUS Status
= RtlRegisterWait(phNewWaitObject
,
984 if (!NT_SUCCESS(Status
))
986 SetLastErrorByStatus(Status
);
998 RegisterWaitForSingleObjectEx(
1000 WAITORTIMERCALLBACK Callback
,
1002 ULONG dwMilliseconds
,
1007 HANDLE hNewWaitObject
;
1009 Status
= RtlRegisterWait(&hNewWaitObject
,
1016 if (!NT_SUCCESS(Status
))
1018 SetLastErrorByStatus(Status
);
1022 return hNewWaitObject
;
1035 NTSTATUS Status
= RtlDeregisterWaitEx(WaitHandle
, NULL
);
1037 if (!NT_SUCCESS(Status
))
1039 SetLastErrorByStatus(Status
);
1054 HANDLE CompletionEvent
1057 NTSTATUS Status
= RtlDeregisterWaitEx(WaitHandle
, CompletionEvent
);
1059 if (!NT_SUCCESS(Status
))
1061 SetLastErrorByStatus(Status
);