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 ******************************************************************/
16 #include "../include/debug.h"
19 #define HIGH_PRIORITY 31
21 /* FUNCTIONS *****************************************************************/
22 _SEH_FILTER(BaseThreadExceptionFilter
)
24 EXCEPTION_POINTERS
* ExceptionInfo
= _SEH_GetExceptionPointers();
25 LONG ExceptionDisposition
= EXCEPTION_EXECUTE_HANDLER
;
27 if (GlobalTopLevelExceptionFilter
!= NULL
)
31 ExceptionDisposition
= GlobalTopLevelExceptionFilter(ExceptionInfo
);
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 _SEH_EXCEPT(BaseThreadExceptionFilter
)
59 /* Get the Exit code from the SEH Handler */
60 uExitCode
= _SEH_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
);
263 DWORD dwDesiredAccess
,
270 OBJECT_ATTRIBUTES ObjectAttributes
;
273 ClientId
.UniqueProcess
= 0;
274 ClientId
.UniqueThread
= (HANDLE
)dwThreadId
;
276 InitializeObjectAttributes (&ObjectAttributes
,
278 (bInheritHandle
? OBJ_INHERIT
: 0),
282 errCode
= NtOpenThread(&ThreadHandle
,
286 if (!NT_SUCCESS(errCode
))
288 SetLastErrorByStatus (errCode
);
301 return(NtCurrentTeb());
312 Status
= NtYieldExecution();
313 return Status
!= STATUS_NO_YIELD_PERFORMED
;
321 GetCurrentThreadId(VOID
)
323 return((DWORD
)(NtCurrentTeb()->Cid
).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
->dwLowDateTime
= KernelUserTimes
.CreateTime
.u
.LowPart
;
351 lpCreationTime
->dwHighDateTime
= KernelUserTimes
.CreateTime
.u
.HighPart
;
353 lpExitTime
->dwLowDateTime
= KernelUserTimes
.ExitTime
.u
.LowPart
;
354 lpExitTime
->dwHighDateTime
= KernelUserTimes
.ExitTime
.u
.HighPart
;
356 lpKernelTime
->dwLowDateTime
= KernelUserTimes
.KernelTime
.u
.LowPart
;
357 lpKernelTime
->dwHighDateTime
= KernelUserTimes
.KernelTime
.u
.HighPart
;
359 lpUserTime
->dwLowDateTime
= KernelUserTimes
.UserTime
.u
.LowPart
;
360 lpUserTime
->dwHighDateTime
= KernelUserTimes
.UserTime
.u
.HighPart
;
370 GetThreadContext(HANDLE hThread
,
375 Status
= NtGetContextThread(hThread
,
377 if (!NT_SUCCESS(Status
))
379 SetLastErrorByStatus(Status
);
391 SetThreadContext(HANDLE hThread
,
392 CONST CONTEXT
*lpContext
)
396 Status
= NtSetContextThread(hThread
,
398 if (!NT_SUCCESS(Status
))
400 SetLastErrorByStatus(Status
);
412 GetExitCodeThread(HANDLE hThread
,
415 THREAD_BASIC_INFORMATION ThreadBasic
;
418 Status
= NtQueryInformationThread(hThread
,
419 ThreadBasicInformation
,
421 sizeof(THREAD_BASIC_INFORMATION
),
423 if (!NT_SUCCESS(Status
))
425 SetLastErrorByStatus(Status
);
429 memcpy(lpExitCode
, &ThreadBasic
.ExitStatus
, sizeof(DWORD
));
439 ResumeThread(HANDLE hThread
)
441 ULONG PreviousResumeCount
;
444 Status
= NtResumeThread(hThread
,
445 &PreviousResumeCount
);
446 if (!NT_SUCCESS(Status
))
448 SetLastErrorByStatus(Status
);
452 return(PreviousResumeCount
);
460 TerminateThread(HANDLE hThread
,
467 SetLastError(ERROR_INVALID_HANDLE
);
471 Status
= NtTerminateThread(hThread
,
473 if (!NT_SUCCESS(Status
))
475 SetLastErrorByStatus(Status
);
487 SuspendThread(HANDLE hThread
)
489 ULONG PreviousSuspendCount
;
492 Status
= NtSuspendThread(hThread
,
493 &PreviousSuspendCount
);
494 if (!NT_SUCCESS(Status
))
496 SetLastErrorByStatus(Status
);
500 return(PreviousSuspendCount
);
508 SetThreadAffinityMask(HANDLE hThread
,
509 DWORD dwThreadAffinityMask
)
511 THREAD_BASIC_INFORMATION ThreadBasic
;
512 KAFFINITY AffinityMask
;
515 AffinityMask
= (KAFFINITY
)dwThreadAffinityMask
;
517 Status
= NtQueryInformationThread(hThread
,
518 ThreadBasicInformation
,
520 sizeof(THREAD_BASIC_INFORMATION
),
522 if (!NT_SUCCESS(Status
))
524 SetLastErrorByStatus(Status
);
528 Status
= NtSetInformationThread(hThread
,
532 if (!NT_SUCCESS(Status
))
533 SetLastErrorByStatus(Status
);
535 return(ThreadBasic
.AffinityMask
);
544 SetThreadPriority(HANDLE hThread
,
547 ULONG Prio
= nPriority
;
550 /* Check if values forcing saturation should be used */
551 if (Prio
== THREAD_PRIORITY_TIME_CRITICAL
)
553 Prio
= (HIGH_PRIORITY
+ 1) / 2;
555 else if (Prio
== THREAD_PRIORITY_IDLE
)
557 Prio
= -((HIGH_PRIORITY
+ 1) / 2);
560 /* Set the Base Priority */
561 Status
= NtSetInformationThread(hThread
,
565 if (!NT_SUCCESS(Status
))
568 SetLastErrorByStatus(Status
);
581 GetThreadPriority(HANDLE hThread
)
583 THREAD_BASIC_INFORMATION ThreadBasic
;
586 /* Query the Base Priority Increment */
587 Status
= NtQueryInformationThread(hThread
,
588 ThreadBasicInformation
,
590 sizeof(THREAD_BASIC_INFORMATION
),
592 if (!NT_SUCCESS(Status
))
595 SetLastErrorByStatus(Status
);
596 return THREAD_PRIORITY_ERROR_RETURN
;
599 /* Do some conversions for out of boundary values */
600 if (ThreadBasic
.BasePriority
> THREAD_BASE_PRIORITY_MAX
)
602 ThreadBasic
.BasePriority
= THREAD_PRIORITY_TIME_CRITICAL
;
604 else if (ThreadBasic
.BasePriority
< THREAD_BASE_PRIORITY_MIN
)
606 ThreadBasic
.BasePriority
= THREAD_PRIORITY_IDLE
;
609 /* Return the final result */
610 return ThreadBasic
.BasePriority
;
617 GetThreadPriorityBoost(IN HANDLE hThread
,
618 OUT PBOOL pDisablePriorityBoost
)
623 Status
= NtQueryInformationThread(hThread
,
628 if (!NT_SUCCESS(Status
))
630 SetLastErrorByStatus(Status
);
634 *pDisablePriorityBoost
= !((BOOL
)PriorityBoost
);
644 SetThreadPriorityBoost(IN HANDLE hThread
,
645 IN BOOL bDisablePriorityBoost
)
650 PriorityBoost
= (ULONG
)!bDisablePriorityBoost
;
652 Status
= NtSetInformationThread(hThread
,
656 if (!NT_SUCCESS(Status
))
658 SetLastErrorByStatus(Status
);
670 GetThreadSelectorEntry(IN HANDLE hThread
,
672 OUT LPLDT_ENTRY lpSelectorEntry
)
674 DESCRIPTOR_TABLE_ENTRY DescriptionTableEntry
;
677 DescriptionTableEntry
.Selector
= dwSelector
;
678 Status
= NtQueryInformationThread(hThread
,
679 ThreadDescriptorTableEntry
,
680 &DescriptionTableEntry
,
681 sizeof(DESCRIPTOR_TABLE_ENTRY
),
683 if(!NT_SUCCESS(Status
))
685 SetLastErrorByStatus(Status
);
689 *lpSelectorEntry
= DescriptionTableEntry
.Descriptor
;
698 SetThreadIdealProcessor(HANDLE hThread
,
699 DWORD dwIdealProcessor
)
703 Status
= NtSetInformationThread(hThread
,
704 ThreadIdealProcessor
,
707 if (!NT_SUCCESS(Status
))
709 SetLastErrorByStatus(Status
);
713 return dwIdealProcessor
;
721 GetProcessIdOfThread(HANDLE Thread
)
723 THREAD_BASIC_INFORMATION ThreadBasic
;
726 Status
= NtQueryInformationThread(Thread
,
727 ThreadBasicInformation
,
729 sizeof(THREAD_BASIC_INFORMATION
),
731 if(!NT_SUCCESS(Status
))
733 SetLastErrorByStatus(Status
);
737 return (DWORD
)ThreadBasic
.ClientId
.UniqueProcess
;
745 GetThreadId(HANDLE Thread
)
747 THREAD_BASIC_INFORMATION ThreadBasic
;
750 Status
= NtQueryInformationThread(Thread
,
751 ThreadBasicInformation
,
753 sizeof(THREAD_BASIC_INFORMATION
),
755 if(!NT_SUCCESS(Status
))
757 SetLastErrorByStatus(Status
);
761 return (DWORD
)ThreadBasic
.ClientId
.UniqueThread
;
768 SetThreadUILanguage(WORD wReserved
)
770 DPRINT1("SetThreadUILanguage(0x%4x) unimplemented!\n", wReserved
);
775 IntCallUserApc(PVOID Function
, PVOID dwData
, PVOID Argument3
)
777 PAPCFUNC pfnAPC
= (PAPCFUNC
)Function
;
778 pfnAPC((ULONG_PTR
)dwData
);
785 QueueUserAPC(PAPCFUNC pfnAPC
, HANDLE hThread
, ULONG_PTR dwData
)
789 Status
= NtQueueApcThread(hThread
, IntCallUserApc
, pfnAPC
,
790 (PVOID
)dwData
, NULL
);
792 SetLastErrorByStatus(Status
);
794 return NT_SUCCESS(Status
);
801 GetThreadIOPendingFlag(HANDLE hThread
,
807 if(lpIOIsPending
== NULL
)
809 SetLastError(ERROR_INVALID_PARAMETER
);
813 Status
= NtQueryInformationThread(hThread
,
818 if(NT_SUCCESS(Status
))
820 *lpIOIsPending
= ((IoPending
!= 0) ? TRUE
: FALSE
);
824 SetLastErrorByStatus(Status
);
833 Sleep(DWORD dwMilliseconds
)
835 SleepEx(dwMilliseconds
, FALSE
);
844 SleepEx(DWORD dwMilliseconds
,
847 LARGE_INTEGER Interval
;
850 if (dwMilliseconds
!= INFINITE
)
853 * System time units are 100 nanoseconds (a nanosecond is a billionth of
856 Interval
.QuadPart
= -((ULONGLONG
)dwMilliseconds
* 10000);
860 /* Approximately 292000 years hence */
861 Interval
.QuadPart
= -0x7FFFFFFFFFFFFFFFLL
;
864 errCode
= NtDelayExecution ((bAlertable
? TRUE
: FALSE
), &Interval
);
865 if (!NT_SUCCESS(errCode
))
867 SetLastErrorByStatus (errCode
);