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
= (HANDLE
)dwThreadId
;
274 InitializeObjectAttributes(&ObjectAttributes
,
276 (bInheritHandle
? OBJ_INHERIT
: 0),
280 errCode
= NtOpenThread(&ThreadHandle
,
284 if (!NT_SUCCESS(errCode
))
286 SetLastErrorByStatus (errCode
);
299 return NtCurrentTeb();
310 Status
= NtYieldExecution();
311 return Status
!= STATUS_NO_YIELD_PERFORMED
;
320 GetCurrentThreadId(VOID
)
322 return (DWORD
)(NtCurrentTeb()->ClientId
).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
= *(LPFILETIME
)&KernelUserTimes
.CreateTime
;
351 *lpExitTime
= *(LPFILETIME
)&KernelUserTimes
.ExitTime
;
352 *lpKernelTime
= *(LPFILETIME
)&KernelUserTimes
.KernelTime
;
353 *lpUserTime
= *(LPFILETIME
)&KernelUserTimes
.UserTime
;
362 GetThreadContext(HANDLE hThread
,
367 Status
= NtGetContextThread(hThread
, lpContext
);
368 if (!NT_SUCCESS(Status
))
370 SetLastErrorByStatus(Status
);
382 SetThreadContext(HANDLE hThread
,
383 CONST CONTEXT
*lpContext
)
387 Status
= NtSetContextThread(hThread
, (PCONTEXT
)lpContext
);
388 if (!NT_SUCCESS(Status
))
390 SetLastErrorByStatus(Status
);
402 GetExitCodeThread(HANDLE hThread
,
405 THREAD_BASIC_INFORMATION ThreadBasic
;
408 Status
= NtQueryInformationThread(hThread
,
409 ThreadBasicInformation
,
411 sizeof(THREAD_BASIC_INFORMATION
),
413 if (!NT_SUCCESS(Status
))
415 SetLastErrorByStatus(Status
);
419 *lpExitCode
= ThreadBasic
.ExitStatus
;
428 ResumeThread(HANDLE hThread
)
430 ULONG PreviousResumeCount
;
433 Status
= NtResumeThread(hThread
, &PreviousResumeCount
);
434 if (!NT_SUCCESS(Status
))
436 SetLastErrorByStatus(Status
);
440 return PreviousResumeCount
;
448 TerminateThread(HANDLE hThread
,
455 SetLastError(ERROR_INVALID_HANDLE
);
459 Status
= NtTerminateThread(hThread
, dwExitCode
);
460 if (!NT_SUCCESS(Status
))
462 SetLastErrorByStatus(Status
);
474 SuspendThread(HANDLE hThread
)
476 ULONG PreviousSuspendCount
;
479 Status
= NtSuspendThread(hThread
, &PreviousSuspendCount
);
480 if (!NT_SUCCESS(Status
))
482 SetLastErrorByStatus(Status
);
486 return PreviousSuspendCount
;
494 SetThreadAffinityMask(HANDLE hThread
,
495 DWORD_PTR dwThreadAffinityMask
)
497 THREAD_BASIC_INFORMATION ThreadBasic
;
498 KAFFINITY AffinityMask
;
501 AffinityMask
= (KAFFINITY
)dwThreadAffinityMask
;
503 Status
= NtQueryInformationThread(hThread
,
504 ThreadBasicInformation
,
506 sizeof(THREAD_BASIC_INFORMATION
),
508 if (!NT_SUCCESS(Status
))
510 SetLastErrorByStatus(Status
);
514 Status
= NtSetInformationThread(hThread
,
518 if (!NT_SUCCESS(Status
))
520 SetLastErrorByStatus(Status
);
521 ThreadBasic
.AffinityMask
= 0;
524 return ThreadBasic
.AffinityMask
;
532 SetThreadPriority(HANDLE hThread
,
535 LONG Prio
= nPriority
;
538 /* Check if values forcing saturation should be used */
539 if (Prio
== THREAD_PRIORITY_TIME_CRITICAL
)
541 Prio
= (HIGH_PRIORITY
+ 1) / 2;
543 else if (Prio
== THREAD_PRIORITY_IDLE
)
545 Prio
= -((HIGH_PRIORITY
+ 1) / 2);
548 /* Set the Base Priority */
549 Status
= NtSetInformationThread(hThread
,
553 if (!NT_SUCCESS(Status
))
556 SetLastErrorByStatus(Status
);
569 GetThreadPriority(HANDLE hThread
)
571 THREAD_BASIC_INFORMATION ThreadBasic
;
574 /* Query the Base Priority Increment */
575 Status
= NtQueryInformationThread(hThread
,
576 ThreadBasicInformation
,
578 sizeof(THREAD_BASIC_INFORMATION
),
580 if (!NT_SUCCESS(Status
))
583 SetLastErrorByStatus(Status
);
584 return THREAD_PRIORITY_ERROR_RETURN
;
587 /* Do some conversions for out of boundary values */
588 if (ThreadBasic
.BasePriority
> THREAD_BASE_PRIORITY_MAX
)
590 ThreadBasic
.BasePriority
= THREAD_PRIORITY_TIME_CRITICAL
;
592 else if (ThreadBasic
.BasePriority
< THREAD_BASE_PRIORITY_MIN
)
594 ThreadBasic
.BasePriority
= THREAD_PRIORITY_IDLE
;
597 /* Return the final result */
598 return ThreadBasic
.BasePriority
;
606 GetThreadPriorityBoost(IN HANDLE hThread
,
607 OUT PBOOL pDisablePriorityBoost
)
612 Status
= NtQueryInformationThread(hThread
,
617 if (!NT_SUCCESS(Status
))
619 SetLastErrorByStatus(Status
);
623 *pDisablePriorityBoost
= PriorityBoost
;
632 SetThreadPriorityBoost(IN HANDLE hThread
,
633 IN BOOL bDisablePriorityBoost
)
638 PriorityBoost
= (ULONG
)bDisablePriorityBoost
;
640 Status
= NtSetInformationThread(hThread
,
644 if (!NT_SUCCESS(Status
))
646 SetLastErrorByStatus(Status
);
657 GetThreadSelectorEntry(IN HANDLE hThread
,
659 OUT LPLDT_ENTRY lpSelectorEntry
)
661 DESCRIPTOR_TABLE_ENTRY DescriptionTableEntry
;
664 DescriptionTableEntry
.Selector
= dwSelector
;
665 Status
= NtQueryInformationThread(hThread
,
666 ThreadDescriptorTableEntry
,
667 &DescriptionTableEntry
,
668 sizeof(DESCRIPTOR_TABLE_ENTRY
),
670 if(!NT_SUCCESS(Status
))
672 SetLastErrorByStatus(Status
);
676 *lpSelectorEntry
= DescriptionTableEntry
.Descriptor
;
685 SetThreadIdealProcessor(HANDLE hThread
,
686 DWORD dwIdealProcessor
)
690 Status
= NtSetInformationThread(hThread
,
691 ThreadIdealProcessor
,
694 if (!NT_SUCCESS(Status
))
696 SetLastErrorByStatus(Status
);
700 return dwIdealProcessor
;
707 GetProcessIdOfThread(HANDLE Thread
)
709 THREAD_BASIC_INFORMATION ThreadBasic
;
712 Status
= NtQueryInformationThread(Thread
,
713 ThreadBasicInformation
,
715 sizeof(THREAD_BASIC_INFORMATION
),
717 if(!NT_SUCCESS(Status
))
719 SetLastErrorByStatus(Status
);
723 return (DWORD
)ThreadBasic
.ClientId
.UniqueProcess
;
730 GetThreadId(HANDLE Thread
)
732 THREAD_BASIC_INFORMATION ThreadBasic
;
735 Status
= NtQueryInformationThread(Thread
,
736 ThreadBasicInformation
,
738 sizeof(THREAD_BASIC_INFORMATION
),
740 if(!NT_SUCCESS(Status
))
742 SetLastErrorByStatus(Status
);
746 return (DWORD
)ThreadBasic
.ClientId
.UniqueThread
;
753 SetThreadUILanguage(WORD wReserved
)
755 DPRINT1("SetThreadUILanguage(0x%4x) unimplemented!\n", wReserved
);
760 IntCallUserApc(PVOID Function
, PVOID dwData
, PVOID Argument3
)
762 PAPCFUNC pfnAPC
= (PAPCFUNC
)Function
;
763 pfnAPC((ULONG_PTR
)dwData
);
770 QueueUserAPC(PAPCFUNC pfnAPC
, HANDLE hThread
, ULONG_PTR dwData
)
774 Status
= NtQueueApcThread(hThread
, IntCallUserApc
, pfnAPC
,
775 (PVOID
)dwData
, NULL
);
777 SetLastErrorByStatus(Status
);
779 return NT_SUCCESS(Status
);
786 GetThreadIOPendingFlag(HANDLE hThread
,
792 if(lpIOIsPending
== NULL
)
794 SetLastError(ERROR_INVALID_PARAMETER
);
798 Status
= NtQueryInformationThread(hThread
,
803 if(NT_SUCCESS(Status
))
805 *lpIOIsPending
= ((IoPending
!= 0) ? TRUE
: FALSE
);
809 SetLastErrorByStatus(Status
);
818 Sleep(DWORD dwMilliseconds
)
820 SleepEx(dwMilliseconds
, FALSE
);
829 SleepEx(DWORD dwMilliseconds
,
832 LARGE_INTEGER Interval
;
835 if (dwMilliseconds
!= INFINITE
)
838 * System time units are 100 nanoseconds (a nanosecond is a billionth of
841 Interval
.QuadPart
= -((LONGLONG
)dwMilliseconds
* 10000);
845 /* Approximately 292000 years hence */
846 Interval
.QuadPart
= -0x7FFFFFFFFFFFFFFFLL
;
850 errCode
= NtDelayExecution ((BOOLEAN
)bAlertable
, &Interval
);
851 if ((bAlertable
) && (errCode
== STATUS_ALERTED
)) goto dowait
;
852 return (errCode
== STATUS_USER_APC
) ? WAIT_IO_COMPLETION
: 0;
856 typedef struct _QUEUE_USER_WORKITEM_CONTEXT
858 LPTHREAD_START_ROUTINE Function
;
860 } QUEUE_USER_WORKITEM_CONTEXT
, *PQUEUE_USER_WORKITEM_CONTEXT
;
864 InternalWorkItemTrampoline(PVOID Context
)
866 QUEUE_USER_WORKITEM_CONTEXT Info
;
870 /* Save the context to the stack */
871 Info
= *(volatile QUEUE_USER_WORKITEM_CONTEXT
*)Context
;
873 /* Free the context before calling the callback. This avoids
874 a memory leak in case the thread dies... */
875 RtlFreeHeap(RtlGetProcessHeap(),
879 /* Call the real callback */
880 Info
.Function(Info
.Context
);
890 LPTHREAD_START_ROUTINE Function
,
895 PQUEUE_USER_WORKITEM_CONTEXT WorkItemContext
;
898 /* Save the context for the trampoline function */
899 WorkItemContext
= RtlAllocateHeap(RtlGetProcessHeap(),
901 sizeof(*WorkItemContext
));
902 if (WorkItemContext
== NULL
)
904 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
908 WorkItemContext
->Function
= Function
;
909 WorkItemContext
->Context
= Context
;
911 /* NOTE: Don't use Function directly since the callback signature
912 differs. This might cause problems on certain platforms... */
913 Status
= RtlQueueWorkItem(InternalWorkItemTrampoline
,
916 if (!NT_SUCCESS(Status
))
918 /* Free the allocated context in case of failure */
919 RtlFreeHeap(RtlGetProcessHeap(),
923 SetLastErrorByStatus(Status
);
936 RegisterWaitForSingleObject(
937 PHANDLE phNewWaitObject
,
939 WAITORTIMERCALLBACK Callback
,
941 ULONG dwMilliseconds
,
945 NTSTATUS Status
= RtlRegisterWait( phNewWaitObject
,
952 if (Status
!= STATUS_SUCCESS
)
954 SetLastError( RtlNtStatusToDosError(Status
) );
966 RegisterWaitForSingleObjectEx(
968 WAITORTIMERCALLBACK Callback
,
970 ULONG dwMilliseconds
,
975 HANDLE hNewWaitObject
;
977 Status
= RtlRegisterWait( &hNewWaitObject
,
984 if (Status
!= STATUS_SUCCESS
)
986 SetLastError( RtlNtStatusToDosError(Status
) );
989 return hNewWaitObject
;
1002 NTSTATUS Status
= RtlDeregisterWaitEx( WaitHandle
, NULL
);
1003 if (Status
!= STATUS_SUCCESS
)
1005 SetLastError( RtlNtStatusToDosError(Status
) );
1019 HANDLE CompletionEvent
1022 NTSTATUS Status
= RtlDeregisterWaitEx( WaitHandle
, CompletionEvent
);
1023 if (Status
!= STATUS_SUCCESS
)
1025 SetLastError( RtlNtStatusToDosError(Status
) );