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 /* Attempt to call the Thread Start Address */
58 /* Legacy check which is still used today for Win32 threads */
59 if (NtCurrentTeb()->NtTib
.Version
== (30 << 8)) // OS/2 V3.0 ("Cruiser")
61 /* This registers the termination port with CSRSS */
62 if (!BaseRunningInServerProcess
) CsrNewThread();
65 /* Get the exit code from the Thread Start */
66 ExitThread((lpStartAddress
)((PVOID
)lpParameter
));
68 _SEH2_EXCEPT(BaseThreadExceptionFilter(_SEH2_GetExceptionInformation()))
70 /* Get the Exit code from the SEH Handler */
71 if (!BaseRunningInServerProcess
)
73 /* Kill the whole process, usually */
74 ExitProcess(_SEH2_GetExceptionCode());
78 /* If running inside CSRSS, kill just this thread */
79 ExitThread(_SEH2_GetExceptionCode());
90 CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes
,
92 LPTHREAD_START_ROUTINE lpStartAddress
,
94 DWORD dwCreationFlags
,
97 /* Act as if we're going to create a remote thread in ourselves */
98 return CreateRemoteThread(NtCurrentProcess(),
112 CreateRemoteThread(HANDLE hProcess
,
113 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
115 LPTHREAD_START_ROUTINE lpStartAddress
,
117 DWORD dwCreationFlags
,
121 INITIAL_TEB InitialTeb
;
124 OBJECT_ATTRIBUTES LocalObjectAttributes
;
125 POBJECT_ATTRIBUTES ObjectAttributes
;
129 DPRINT("CreateRemoteThread: hProcess: %ld dwStackSize: %ld lpStartAddress"
130 ": %p lpParameter: %lx, dwCreationFlags: %lx\n", hProcess
,
131 dwStackSize
, lpStartAddress
, lpParameter
, dwCreationFlags
);
133 /* Clear the Context */
134 RtlZeroMemory(&Context
, sizeof(CONTEXT
));
137 ClientId
.UniqueProcess
= hProcess
;
139 /* Create the Stack */
140 Status
= BasepCreateStack(hProcess
,
142 dwCreationFlags
& STACK_SIZE_PARAM_IS_A_RESERVATION
?
145 if(!NT_SUCCESS(Status
))
147 BaseSetLastNTError(Status
);
151 /* Create Initial Context */
152 BasepInitializeContext(&Context
,
155 InitialTeb
.StackBase
,
158 /* initialize the attributes for the thread object */
159 ObjectAttributes
= BasepConvertObjectAttributes(&LocalObjectAttributes
,
163 /* Create the Kernel Thread Object */
164 Status
= NtCreateThread(&hThread
,
172 if(!NT_SUCCESS(Status
))
174 BasepFreeStack(hProcess
, &InitialTeb
);
175 BaseSetLastNTError(Status
);
179 /* Are we in the same process? */
180 if (hProcess
== NtCurrentProcess())
183 PVOID ActivationContextStack
;
184 THREAD_BASIC_INFORMATION ThreadBasicInfo
;
185 #ifndef SXS_SUPPORT_FIXME
186 ACTIVATION_CONTEXT_BASIC_INFORMATION ActivationCtxInfo
;
192 Status
= NtQueryInformationThread(hThread
,
193 ThreadBasicInformation
,
195 sizeof(ThreadBasicInfo
),
197 if (NT_SUCCESS(Status
))
199 /* Allocate the Activation Context Stack */
200 Status
= RtlAllocateActivationContextStack(&ActivationContextStack
);
203 if (NT_SUCCESS(Status
))
205 Teb
= ThreadBasicInfo
.TebBaseAddress
;
208 Teb
->ActivationContextStackPointer
= ActivationContextStack
;
209 #ifndef SXS_SUPPORT_FIXME
210 /* Query the Context */
211 Status
= RtlQueryInformationActivationContext(1,
214 ActivationContextBasicInformation
,
216 sizeof(ActivationCtxInfo
),
218 if (NT_SUCCESS(Status
))
220 /* Does it need to be activated? */
221 if (!ActivationCtxInfo
.hActCtx
)
224 Status
= RtlActivateActivationContext(1,
225 ActivationCtxInfo
.hActCtx
,
227 if (!NT_SUCCESS(Status
))
228 DPRINT1("RtlActivateActivationContext failed %x\n", Status
);
232 DPRINT1("RtlQueryInformationActivationContext failed %x\n", Status
);
236 DPRINT1("RtlAllocateActivationContextStack failed %x\n", Status
);
240 Status
= BasepNotifyCsrOfThread(hThread
, &ClientId
);
241 if (!NT_SUCCESS(Status
))
247 if(lpThreadId
) *lpThreadId
= HandleToUlong(ClientId
.UniqueThread
);
249 /* Resume it if asked */
250 if (!(dwCreationFlags
& CREATE_SUSPENDED
))
252 NtResumeThread(hThread
, &Dummy
);
255 /* Return handle to thread */
264 ExitThread(DWORD uExitCode
)
270 * Terminate process if this is the last thread
271 * of the current process
273 Status
= NtQueryInformationThread(NtCurrentThread(),
278 if (NT_SUCCESS(Status
) && LastThread
)
280 /* Exit the Process */
281 ExitProcess(uExitCode
);
284 /* Notify DLLs and TLS Callbacks of termination */
287 /* Tell the Kernel to free the Stack */
288 NtCurrentTeb()->FreeStackOnTermination
= TRUE
;
289 NtTerminateThread(NULL
, uExitCode
);
291 /* We should never reach this place */
292 DPRINT1("It should not happen\n");
301 OpenThread(DWORD dwDesiredAccess
,
307 OBJECT_ATTRIBUTES ObjectAttributes
;
310 ClientId
.UniqueProcess
= 0;
311 ClientId
.UniqueThread
= ULongToHandle(dwThreadId
);
313 InitializeObjectAttributes(&ObjectAttributes
,
315 (bInheritHandle
? OBJ_INHERIT
: 0),
319 Status
= NtOpenThread(&ThreadHandle
,
323 if (!NT_SUCCESS(Status
))
325 BaseSetLastNTError(Status
);
338 return NtCurrentTeb();
348 return NtYieldExecution() != STATUS_NO_YIELD_PERFORMED
;
357 GetCurrentThreadId(VOID
)
359 return HandleToUlong(NtCurrentTeb()->ClientId
.UniqueThread
);
367 GetThreadTimes(HANDLE hThread
,
368 LPFILETIME lpCreationTime
,
369 LPFILETIME lpExitTime
,
370 LPFILETIME lpKernelTime
,
371 LPFILETIME lpUserTime
)
373 KERNEL_USER_TIMES KernelUserTimes
;
376 Status
= NtQueryInformationThread(hThread
,
379 sizeof(KERNEL_USER_TIMES
),
381 if (!NT_SUCCESS(Status
))
383 BaseSetLastNTError(Status
);
387 *lpCreationTime
= *(LPFILETIME
)&KernelUserTimes
.CreateTime
;
388 *lpExitTime
= *(LPFILETIME
)&KernelUserTimes
.ExitTime
;
389 *lpKernelTime
= *(LPFILETIME
)&KernelUserTimes
.KernelTime
;
390 *lpUserTime
= *(LPFILETIME
)&KernelUserTimes
.UserTime
;
399 GetThreadContext(HANDLE hThread
,
404 Status
= NtGetContextThread(hThread
, lpContext
);
405 if (!NT_SUCCESS(Status
))
407 BaseSetLastNTError(Status
);
419 SetThreadContext(HANDLE hThread
,
420 CONST CONTEXT
*lpContext
)
424 Status
= NtSetContextThread(hThread
, (PCONTEXT
)lpContext
);
425 if (!NT_SUCCESS(Status
))
427 BaseSetLastNTError(Status
);
439 GetExitCodeThread(HANDLE hThread
,
442 THREAD_BASIC_INFORMATION ThreadBasic
;
445 Status
= NtQueryInformationThread(hThread
,
446 ThreadBasicInformation
,
448 sizeof(THREAD_BASIC_INFORMATION
),
450 if (!NT_SUCCESS(Status
))
452 BaseSetLastNTError(Status
);
456 *lpExitCode
= ThreadBasic
.ExitStatus
;
465 ResumeThread(HANDLE hThread
)
467 ULONG PreviousResumeCount
;
470 Status
= NtResumeThread(hThread
, &PreviousResumeCount
);
471 if (!NT_SUCCESS(Status
))
473 BaseSetLastNTError(Status
);
477 return PreviousResumeCount
;
485 TerminateThread(HANDLE hThread
,
492 SetLastError(ERROR_INVALID_HANDLE
);
496 Status
= NtTerminateThread(hThread
, dwExitCode
);
497 if (!NT_SUCCESS(Status
))
499 BaseSetLastNTError(Status
);
511 SuspendThread(HANDLE hThread
)
513 ULONG PreviousSuspendCount
;
516 Status
= NtSuspendThread(hThread
, &PreviousSuspendCount
);
517 if (!NT_SUCCESS(Status
))
519 BaseSetLastNTError(Status
);
523 return PreviousSuspendCount
;
531 SetThreadAffinityMask(HANDLE hThread
,
532 DWORD_PTR dwThreadAffinityMask
)
534 THREAD_BASIC_INFORMATION ThreadBasic
;
535 KAFFINITY AffinityMask
;
538 AffinityMask
= (KAFFINITY
)dwThreadAffinityMask
;
540 Status
= NtQueryInformationThread(hThread
,
541 ThreadBasicInformation
,
543 sizeof(THREAD_BASIC_INFORMATION
),
545 if (!NT_SUCCESS(Status
))
547 BaseSetLastNTError(Status
);
551 Status
= NtSetInformationThread(hThread
,
555 if (!NT_SUCCESS(Status
))
557 BaseSetLastNTError(Status
);
558 ThreadBasic
.AffinityMask
= 0;
561 return ThreadBasic
.AffinityMask
;
569 SetThreadPriority(HANDLE hThread
,
572 LONG Prio
= nPriority
;
575 /* Check if values forcing saturation should be used */
576 if (Prio
== THREAD_PRIORITY_TIME_CRITICAL
)
578 Prio
= (HIGH_PRIORITY
+ 1) / 2;
580 else if (Prio
== THREAD_PRIORITY_IDLE
)
582 Prio
= -((HIGH_PRIORITY
+ 1) / 2);
585 /* Set the Base Priority */
586 Status
= NtSetInformationThread(hThread
,
590 if (!NT_SUCCESS(Status
))
593 BaseSetLastNTError(Status
);
606 GetThreadPriority(HANDLE hThread
)
608 THREAD_BASIC_INFORMATION ThreadBasic
;
611 /* Query the Base Priority Increment */
612 Status
= NtQueryInformationThread(hThread
,
613 ThreadBasicInformation
,
615 sizeof(THREAD_BASIC_INFORMATION
),
617 if (!NT_SUCCESS(Status
))
620 BaseSetLastNTError(Status
);
621 return THREAD_PRIORITY_ERROR_RETURN
;
624 /* Do some conversions for saturation values */
625 if (ThreadBasic
.BasePriority
== ((HIGH_PRIORITY
+ 1) / 2))
627 /* Win32 calls this "time critical" */
628 ThreadBasic
.BasePriority
= THREAD_PRIORITY_TIME_CRITICAL
;
630 else if (ThreadBasic
.BasePriority
== -((HIGH_PRIORITY
+ 1) / 2))
632 /* Win32 calls this "idle" */
633 ThreadBasic
.BasePriority
= THREAD_PRIORITY_IDLE
;
636 /* Return the final result */
637 return ThreadBasic
.BasePriority
;
645 GetThreadPriorityBoost(IN HANDLE hThread
,
646 OUT PBOOL pDisablePriorityBoost
)
651 Status
= NtQueryInformationThread(hThread
,
656 if (!NT_SUCCESS(Status
))
658 BaseSetLastNTError(Status
);
662 *pDisablePriorityBoost
= PriorityBoost
;
671 SetThreadPriorityBoost(IN HANDLE hThread
,
672 IN BOOL bDisablePriorityBoost
)
677 PriorityBoost
= (ULONG
)bDisablePriorityBoost
;
679 Status
= NtSetInformationThread(hThread
,
683 if (!NT_SUCCESS(Status
))
685 BaseSetLastNTError(Status
);
697 GetThreadSelectorEntry(IN HANDLE hThread
,
699 OUT LPLDT_ENTRY lpSelectorEntry
)
702 DESCRIPTOR_TABLE_ENTRY DescriptionTableEntry
;
705 /* Set the selector and do the query */
706 DescriptionTableEntry
.Selector
= dwSelector
;
707 Status
= NtQueryInformationThread(hThread
,
708 ThreadDescriptorTableEntry
,
709 &DescriptionTableEntry
,
710 sizeof(DESCRIPTOR_TABLE_ENTRY
),
712 if (!NT_SUCCESS(Status
))
715 BaseSetLastNTError(Status
);
719 /* Success, return the selector */
720 *lpSelectorEntry
= DescriptionTableEntry
.Descriptor
;
723 DPRINT1("Calling GetThreadSelectorEntry!\n");
733 SetThreadIdealProcessor(HANDLE hThread
,
734 DWORD dwIdealProcessor
)
738 Status
= NtSetInformationThread(hThread
,
739 ThreadIdealProcessor
,
742 if (!NT_SUCCESS(Status
))
744 BaseSetLastNTError(Status
);
748 return (DWORD
)Status
;
755 GetProcessIdOfThread(HANDLE Thread
)
757 THREAD_BASIC_INFORMATION ThreadBasic
;
760 Status
= NtQueryInformationThread(Thread
,
761 ThreadBasicInformation
,
763 sizeof(THREAD_BASIC_INFORMATION
),
765 if(!NT_SUCCESS(Status
))
767 BaseSetLastNTError(Status
);
771 return HandleToUlong(ThreadBasic
.ClientId
.UniqueProcess
);
778 GetThreadId(HANDLE Thread
)
780 THREAD_BASIC_INFORMATION ThreadBasic
;
783 Status
= NtQueryInformationThread(Thread
,
784 ThreadBasicInformation
,
786 sizeof(THREAD_BASIC_INFORMATION
),
788 if(!NT_SUCCESS(Status
))
790 BaseSetLastNTError(Status
);
794 return HandleToUlong(ThreadBasic
.ClientId
.UniqueThread
);
801 SetThreadUILanguage(LANGID LangId
)
803 DPRINT1("SetThreadUILanguage(0x%4x) unimplemented!\n", LangId
);
808 IntCallUserApc(PVOID Function
, PVOID dwData
, PVOID Argument3
)
810 PAPCFUNC pfnAPC
= (PAPCFUNC
)Function
;
811 pfnAPC((ULONG_PTR
)dwData
);
818 QueueUserAPC(PAPCFUNC pfnAPC
, HANDLE hThread
, ULONG_PTR dwData
)
822 Status
= NtQueueApcThread(hThread
, IntCallUserApc
, pfnAPC
,
823 (PVOID
)dwData
, NULL
);
824 if (!NT_SUCCESS(Status
))
826 BaseSetLastNTError(Status
);
835 SetThreadStackGuarantee(IN OUT PULONG StackSizeInBytes
)
846 GetThreadIOPendingFlag(HANDLE hThread
,
852 if(lpIOIsPending
== NULL
)
854 SetLastError(ERROR_INVALID_PARAMETER
);
858 Status
= NtQueryInformationThread(hThread
,
863 if(NT_SUCCESS(Status
))
865 *lpIOIsPending
= ((IoPending
!= 0) ? TRUE
: FALSE
);
869 BaseSetLastNTError(Status
);
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
;
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 BaseSetLastNTError(Status
);
959 /* Get the PEB and TEB, lock the PEB */
960 Teb
= NtCurrentTeb();
961 Peb
= Teb
->ProcessEnvironmentBlock
;
964 /* Try to get regular TEB slot */
965 Index
= RtlFindClearBitsAndSet(Peb
->TlsBitmap
, 1, 0);
966 if (Index
!= 0xFFFFFFFF)
968 /* Clear the value. */
969 Teb
->TlsSlots
[Index
] = 0;
974 /* If it fails, try to find expansion TEB slot. */
975 Index
= RtlFindClearBitsAndSet(Peb
->TlsExpansionBitmap
, 1, 0);
976 if (Index
!= 0xFFFFFFFF)
978 /* Is there no expansion slot yet? */
979 if (!Teb
->TlsExpansionSlots
)
981 /* Allocate an array */
982 Teb
->TlsExpansionSlots
= RtlAllocateHeap(RtlGetProcessHeap(),
984 TLS_EXPANSION_SLOTS
*
988 /* Did we get an array? */
989 if (!Teb
->TlsExpansionSlots
)
992 RtlClearBits(Peb
->TlsExpansionBitmap
, Index
, 1);
994 BaseSetLastNTError(STATUS_NO_MEMORY
);
998 /* Clear the value. */
999 Teb
->TlsExpansionSlots
[Index
] = 0;
1000 Index
+= TLS_MINIMUM_AVAILABLE
;
1006 BaseSetLastNTError(STATUS_NO_MEMORY
);
1009 /* Release the lock and return */
1010 RtlReleasePebLock();
1019 TlsFree(IN DWORD Index
)
1027 /* Acquire the PEB lock and grab the PEB */
1028 Peb
= NtCurrentPeb();
1029 RtlAcquirePebLock();
1031 /* Check if the index is too high */
1032 if (Index
>= TLS_MINIMUM_AVAILABLE
)
1034 /* Check if it can fit in the expansion slots */
1035 TlsIndex
= Index
- TLS_MINIMUM_AVAILABLE
;
1036 if (TlsIndex
>= TLS_EXPANSION_SLOTS
)
1039 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
1040 RtlReleasePebLock();
1045 /* Use the expansion bitmap */
1046 TlsBitmap
= Peb
->TlsExpansionBitmap
;
1052 /* Use the normal bitmap */
1053 TlsBitmap
= Peb
->TlsBitmap
;
1056 /* Check if the index was set */
1057 BitSet
= RtlAreBitsSet(TlsBitmap
, Index
, 1);
1060 /* Tell the kernel to free the TLS cells */
1061 Status
= NtSetInformationThread(NtCurrentThread(),
1065 if (!NT_SUCCESS(Status
))
1067 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
1068 RtlReleasePebLock();
1073 RtlClearBits(TlsBitmap
, Index
, 1);
1078 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
1079 RtlReleasePebLock();
1084 RtlReleasePebLock();
1093 TlsGetValue(IN DWORD Index
)
1097 /* Get the TEB and clear the last error */
1098 Teb
= NtCurrentTeb();
1099 Teb
->LastErrorValue
= 0;
1101 /* Check for simple TLS index */
1102 if (Index
< TLS_MINIMUM_AVAILABLE
)
1105 return Teb
->TlsSlots
[Index
];
1108 /* Check for valid index */
1109 if (Index
>= TLS_EXPANSION_SLOTS
+ TLS_MINIMUM_AVAILABLE
)
1112 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
1116 /* The expansion slots are allocated on demand, so check for it. */
1117 Teb
->LastErrorValue
= 0;
1118 if (!Teb
->TlsExpansionSlots
) return NULL
;
1120 /* Return the value from the expansion slots */
1121 return Teb
->TlsExpansionSlots
[Index
- TLS_MINIMUM_AVAILABLE
];
1129 TlsSetValue(IN DWORD Index
,
1133 PTEB Teb
= NtCurrentTeb();
1135 /* Check for simple TLS index */
1136 if (Index
< TLS_MINIMUM_AVAILABLE
)
1139 Teb
->TlsSlots
[Index
] = Value
;
1143 /* Check if this is an expansion slot */
1144 TlsIndex
= Index
- TLS_MINIMUM_AVAILABLE
;
1145 if (TlsIndex
>= TLS_EXPANSION_SLOTS
)
1148 BaseSetLastNTError(STATUS_INVALID_PARAMETER
);
1152 /* Do we not have expansion slots? */
1153 if (!Teb
->TlsExpansionSlots
)
1155 /* Get the PEB lock to see if we still need them */
1156 RtlAcquirePebLock();
1157 if (!Teb
->TlsExpansionSlots
)
1160 Teb
->TlsExpansionSlots
= RtlAllocateHeap(RtlGetProcessHeap(),
1162 TLS_EXPANSION_SLOTS
*
1164 if (!Teb
->TlsExpansionSlots
)
1167 RtlReleasePebLock();
1168 BaseSetLastNTError(STATUS_NO_MEMORY
);
1173 /* Release the lock */
1174 RtlReleasePebLock();
1177 /* Write the value */
1178 Teb
->TlsExpansionSlots
[TlsIndex
] = Value
;