3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS system libraries
5 * FILE: lib/kernel32/thread/thread.c
6 * PURPOSE: Thread functions
7 * PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
8 * Tls functions are modified from WINE
14 /* INCLUDES ******************************************************************/
19 #include "../include/debug.h"
22 /* FUNCTIONS *****************************************************************/
24 /* FIXME: please put this in some header */
25 static EXCEPTION_DISPOSITION __cdecl
26 _except_handler(EXCEPTION_RECORD
*ExceptionRecord
,
27 void * EstablisherFrame
,
28 CONTEXT
*ContextRecord
,
29 void * DispatcherContext
)
31 EXCEPTION_POINTERS ExceptionInfo
;
32 EXCEPTION_DISPOSITION ExceptionDisposition
;
34 ExceptionInfo
.ExceptionRecord
= ExceptionRecord
;
35 ExceptionInfo
.ContextRecord
= ContextRecord
;
37 if (GlobalTopLevelExceptionFilter
!= NULL
)
41 ExceptionDisposition
= GlobalTopLevelExceptionFilter(&ExceptionInfo
);
45 ExceptionDisposition
= UnhandledExceptionFilter(&ExceptionInfo
);
51 ExceptionDisposition
= EXCEPTION_EXECUTE_HANDLER
;
54 if (ExceptionDisposition
== EXCEPTION_EXECUTE_HANDLER
)
55 ExitThread(ExceptionRecord
->ExceptionCode
);
57 /* translate EXCEPTION_XXX defines into EXCEPTION_DISPOSITION enum values */
58 if (ExceptionDisposition
== EXCEPTION_CONTINUE_EXECUTION
)
59 return ExceptionContinueExecution
;
60 else if (ExceptionDisposition
== EXCEPTION_CONTINUE_SEARCH
)
61 return ExceptionContinueSearch
;
63 return -1; /* unknown return from UnhandledExceptionFilter */
67 __declspec(noreturn
) void STDCALL
70 LPTHREAD_START_ROUTINE lpStartAddress
,
74 volatile UINT uExitCode
= 0;
76 __try1(_except_handler
)
78 /* FIXME: notify csrss of thread creation ?? */
79 uExitCode
= (lpStartAddress
)(lpParameter
);
83 ExitThread(uExitCode
);
93 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
95 LPTHREAD_START_ROUTINE lpStartAddress
,
97 DWORD dwCreationFlags
,
101 return CreateRemoteThread
121 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
123 LPTHREAD_START_ROUTINE lpStartAddress
,
125 DWORD dwCreationFlags
,
130 CLIENT_ID cidClientId
;
132 ULONG_PTR nStackReserve
;
133 ULONG_PTR nStackCommit
;
134 OBJECT_ATTRIBUTES oaThreadAttribs
;
135 PIMAGE_NT_HEADERS pinhHeader
=
136 RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress
);
141 "lpThreadAttributes %08X\n"
143 "lpStartAddress %08X\n"
145 "dwCreationFlags %08X\n"
156 /* FIXME: do more checks - e.g. the image may not have an optional header */
157 if(pinhHeader
== NULL
)
159 nStackReserve
= 0x100000;
160 nStackCommit
= PAGE_SIZE
;
164 nStackReserve
= pinhHeader
->OptionalHeader
.SizeOfStackReserve
;
165 nStackCommit
= pinhHeader
->OptionalHeader
.SizeOfStackCommit
;
168 /* FIXME: this should be defined in winbase.h */
169 #ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
170 #define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000
174 if(dwStackSize
== 0);
175 /* dwStackSize specifies the size to reserve */
176 else if(dwCreationFlags
& STACK_SIZE_PARAM_IS_A_RESERVATION
)
177 nStackReserve
= dwStackSize
;
178 /* dwStackSize specifies the size to commit */
180 nStackCommit
= dwStackSize
;
182 /* fix the stack reserve size */
183 if(nStackCommit
> nStackReserve
)
184 nStackReserve
= ROUNDUP(nStackCommit
, 0x100000);
186 /* initialize the attributes for the thread object */
187 InitializeObjectAttributes
196 if(lpThreadAttributes
)
198 /* make the handle inheritable */
199 if(lpThreadAttributes
->bInheritHandle
)
200 oaThreadAttribs
.Attributes
|= OBJ_INHERIT
;
202 /* user-defined security descriptor */
203 oaThreadAttribs
.SecurityDescriptor
= lpThreadAttributes
->lpSecurityDescriptor
;
208 "RtlRosCreateUserThreadVa\n"
210 " ProcessHandle %p,\n"
211 " ObjectAttributes %p,\n"
212 " CreateSuspended %d,\n"
213 " StackZeroBits %d,\n"
214 " StackReserve %lu,\n"
215 " StackCommit %lu,\n"
216 " StartAddress %p,\n"
217 " ThreadHandle %p,\n"
219 " ParameterCount %u,\n"
220 " Parameters[0] %p,\n"
221 " Parameters[1] %p\n"
225 dwCreationFlags
& CREATE_SUSPENDED
,
237 /* create the thread */
238 nErrCode
= RtlRosCreateUserThreadVa
242 dwCreationFlags
& CREATE_SUSPENDED
,
246 (PTHREAD_START_ROUTINE
)ThreadStartup
,
255 if(!NT_SUCCESS(nErrCode
))
257 SetLastErrorByStatus(nErrCode
);
266 "ClientId.UniqueThread %p\n",
270 cidClientId
.UniqueThread
274 if(lpThreadId
) *lpThreadId
= (DWORD
)cidClientId
.UniqueThread
;
285 DWORD dwDesiredAccess
,
292 OBJECT_ATTRIBUTES ObjectAttributes
;
295 ClientId
.UniqueProcess
= INVALID_HANDLE_VALUE
;
296 ClientId
.UniqueThread
= (HANDLE
)dwThreadId
;
298 InitializeObjectAttributes (&ObjectAttributes
,
300 (bInheritHandle
? OBJ_INHERIT
: 0),
304 errCode
= NtOpenThread(&ThreadHandle
,
308 if (!NT_SUCCESS(errCode
))
310 SetLastErrorByStatus (errCode
);
323 return(NtCurrentTeb());
334 errCode
= NtYieldExecution();
343 GetCurrentThreadId(VOID
)
345 return((DWORD
)(NtCurrentTeb()->Cid
).UniqueThread
);
352 ExitThread(DWORD uExitCode
)
358 * Terminate process if this is the last thread
359 * of the current process
361 Status
= NtQueryInformationThread(NtCurrentThread(),
366 if (NT_SUCCESS(Status
) && LastThread
== TRUE
)
368 ExitProcess(uExitCode
);
371 /* FIXME: notify csrss of thread termination */
375 RtlRosExitUserThread(uExitCode
);
383 GetThreadTimes(HANDLE hThread
,
384 LPFILETIME lpCreationTime
,
385 LPFILETIME lpExitTime
,
386 LPFILETIME lpKernelTime
,
387 LPFILETIME lpUserTime
)
389 KERNEL_USER_TIMES KernelUserTimes
;
392 Status
= NtQueryInformationThread(hThread
,
395 sizeof(KERNEL_USER_TIMES
),
397 if (!NT_SUCCESS(Status
))
399 SetLastErrorByStatus(Status
);
403 lpCreationTime
->dwLowDateTime
= KernelUserTimes
.CreateTime
.u
.LowPart
;
404 lpCreationTime
->dwHighDateTime
= KernelUserTimes
.CreateTime
.u
.HighPart
;
406 lpExitTime
->dwLowDateTime
= KernelUserTimes
.ExitTime
.u
.LowPart
;
407 lpExitTime
->dwHighDateTime
= KernelUserTimes
.ExitTime
.u
.HighPart
;
409 lpKernelTime
->dwLowDateTime
= KernelUserTimes
.KernelTime
.u
.LowPart
;
410 lpKernelTime
->dwHighDateTime
= KernelUserTimes
.KernelTime
.u
.HighPart
;
412 lpUserTime
->dwLowDateTime
= KernelUserTimes
.UserTime
.u
.LowPart
;
413 lpUserTime
->dwHighDateTime
= KernelUserTimes
.UserTime
.u
.HighPart
;
423 GetThreadContext(HANDLE hThread
,
428 Status
= NtGetContextThread(hThread
,
430 if (!NT_SUCCESS(Status
))
432 SetLastErrorByStatus(Status
);
444 SetThreadContext(HANDLE hThread
,
445 CONST CONTEXT
*lpContext
)
449 Status
= NtSetContextThread(hThread
,
451 if (!NT_SUCCESS(Status
))
453 SetLastErrorByStatus(Status
);
465 GetExitCodeThread(HANDLE hThread
,
468 THREAD_BASIC_INFORMATION ThreadBasic
;
471 Status
= NtQueryInformationThread(hThread
,
472 ThreadBasicInformation
,
474 sizeof(THREAD_BASIC_INFORMATION
),
476 if (!NT_SUCCESS(Status
))
478 SetLastErrorByStatus(Status
);
482 memcpy(lpExitCode
, &ThreadBasic
.ExitStatus
, sizeof(DWORD
));
492 ResumeThread(HANDLE hThread
)
494 ULONG PreviousResumeCount
;
497 Status
= NtResumeThread(hThread
,
498 &PreviousResumeCount
);
499 if (!NT_SUCCESS(Status
))
501 SetLastErrorByStatus(Status
);
505 return(PreviousResumeCount
);
513 TerminateThread(HANDLE hThread
,
520 SetLastError(ERROR_INVALID_HANDLE
);
524 Status
= NtTerminateThread(hThread
,
526 if (!NT_SUCCESS(Status
))
528 SetLastErrorByStatus(Status
);
540 SuspendThread(HANDLE hThread
)
542 ULONG PreviousSuspendCount
;
545 Status
= NtSuspendThread(hThread
,
546 &PreviousSuspendCount
);
547 if (!NT_SUCCESS(Status
))
549 SetLastErrorByStatus(Status
);
553 return(PreviousSuspendCount
);
561 SetThreadAffinityMask(HANDLE hThread
,
562 DWORD dwThreadAffinityMask
)
564 THREAD_BASIC_INFORMATION ThreadBasic
;
565 KAFFINITY AffinityMask
;
568 AffinityMask
= (KAFFINITY
)dwThreadAffinityMask
;
570 Status
= NtQueryInformationThread(hThread
,
571 ThreadBasicInformation
,
573 sizeof(THREAD_BASIC_INFORMATION
),
575 if (!NT_SUCCESS(Status
))
577 SetLastErrorByStatus(Status
);
581 Status
= NtSetInformationThread(hThread
,
585 if (!NT_SUCCESS(Status
))
586 SetLastErrorByStatus(Status
);
588 return(ThreadBasic
.AffinityMask
);
596 SetThreadPriority(HANDLE hThread
,
599 ULONG Prio
= nPriority
;
602 Status
= NtSetInformationThread(hThread
,
607 if (!NT_SUCCESS(Status
))
609 SetLastErrorByStatus(Status
);
621 GetThreadPriority(HANDLE hThread
)
623 THREAD_BASIC_INFORMATION ThreadBasic
;
626 Status
= NtQueryInformationThread(hThread
,
627 ThreadBasicInformation
,
629 sizeof(THREAD_BASIC_INFORMATION
),
631 if (!NT_SUCCESS(Status
))
633 SetLastErrorByStatus(Status
);
634 return(THREAD_PRIORITY_ERROR_RETURN
);
637 return(ThreadBasic
.BasePriority
);
645 GetThreadPriorityBoost(IN HANDLE hThread
,
646 OUT PBOOL pDisablePriorityBoost
)
651 Status
= NtQueryInformationThread(hThread
,
656 if (!NT_SUCCESS(Status
))
658 SetLastErrorByStatus(Status
);
662 *pDisablePriorityBoost
= !((BOOL
)PriorityBoost
);
672 SetThreadPriorityBoost(IN HANDLE hThread
,
673 IN BOOL bDisablePriorityBoost
)
678 PriorityBoost
= (ULONG
)!bDisablePriorityBoost
;
680 Status
= NtSetInformationThread(hThread
,
684 if (!NT_SUCCESS(Status
))
686 SetLastErrorByStatus(Status
);
698 GetThreadSelectorEntry(IN HANDLE hThread
,
700 OUT LPLDT_ENTRY lpSelectorEntry
)
702 DESCRIPTOR_TABLE_ENTRY DescriptionTableEntry
;
705 DescriptionTableEntry
.Selector
= dwSelector
;
706 Status
= NtQueryInformationThread(hThread
,
707 ThreadDescriptorTableEntry
,
708 &DescriptionTableEntry
,
709 sizeof(DESCRIPTOR_TABLE_ENTRY
),
711 if(!NT_SUCCESS(Status
))
713 SetLastErrorByStatus(Status
);
717 *lpSelectorEntry
= DescriptionTableEntry
.Descriptor
;
726 SetThreadIdealProcessor(HANDLE hThread
,
727 DWORD dwIdealProcessor
)
731 Status
= NtSetInformationThread(hThread
,
732 ThreadIdealProcessor
,
735 if (!NT_SUCCESS(Status
))
737 SetLastErrorByStatus(Status
);
741 return dwIdealProcessor
;
749 GetProcessIdOfThread(HANDLE Thread
)
751 THREAD_BASIC_INFORMATION ThreadBasic
;
754 Status
= NtQueryInformationThread(Thread
,
755 ThreadBasicInformation
,
757 sizeof(THREAD_BASIC_INFORMATION
),
759 if(!NT_SUCCESS(Status
))
761 SetLastErrorByStatus(Status
);
765 return (DWORD
)ThreadBasic
.ClientId
.UniqueProcess
;
773 GetThreadId(HANDLE Thread
)
775 THREAD_BASIC_INFORMATION ThreadBasic
;
778 Status
= NtQueryInformationThread(Thread
,
779 ThreadBasicInformation
,
781 sizeof(THREAD_BASIC_INFORMATION
),
783 if(!NT_SUCCESS(Status
))
785 SetLastErrorByStatus(Status
);
789 return (DWORD
)ThreadBasic
.ClientId
.UniqueThread
;
796 SetThreadUILanguage(DWORD Unknown1
)
798 DPRINT1("SetThreadUILanguage(0x%x) unimplemented!\n", Unknown1
);
802 IntCallUserApc(PVOID Function
, PVOID dwData
, PVOID Argument3
)
804 PAPCFUNC pfnAPC
= (PAPCFUNC
)Function
;
805 pfnAPC((ULONG_PTR
)dwData
);
812 QueueUserAPC(PAPCFUNC pfnAPC
, HANDLE hThread
, ULONG_PTR dwData
)
816 Status
= NtQueueApcThread(hThread
, IntCallUserApc
, pfnAPC
,
817 (PVOID
)dwData
, NULL
);
819 SetLastErrorByStatus(Status
);
821 return NT_SUCCESS(Status
);
828 GetThreadIOPendingFlag(HANDLE hThread
,
834 if(lpIOIsPending
== NULL
)
836 SetLastError(ERROR_INVALID_PARAMETER
);
840 Status
= NtQueryInformationThread(hThread
,
845 if(NT_SUCCESS(Status
))
847 *lpIOIsPending
= ((IoPending
!= 0) ? TRUE
: FALSE
);
851 SetLastErrorByStatus(Status
);