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 <rosrtl/thread.h>
22 #include "../include/debug.h"
25 /* FUNCTIONS *****************************************************************/
26 _SEH_FILTER(BaseThreadExceptionFilter
)
28 EXCEPTION_POINTERS
* ExceptionInfo
= _SEH_GetExceptionPointers();
29 LONG ExceptionDisposition
= EXCEPTION_EXECUTE_HANDLER
;
31 if (GlobalTopLevelExceptionFilter
!= NULL
)
35 ExceptionDisposition
= GlobalTopLevelExceptionFilter(ExceptionInfo
);
39 ExceptionDisposition
= UnhandledExceptionFilter(ExceptionInfo
);
44 return ExceptionDisposition
;
50 BaseThreadStartup(LPTHREAD_START_ROUTINE lpStartAddress
,
53 volatile UINT uExitCode
= 0;
55 /* Attempt to call the Thread Start Address */
58 /* Get the exit code from the Thread Start */
59 uExitCode
= (lpStartAddress
)((PVOID
)lpParameter
);
61 _SEH_EXCEPT(BaseThreadExceptionFilter
)
63 /* Get the Exit code from the SEH Handler */
64 uExitCode
= _SEH_GetExceptionCode();
68 ExitThread(uExitCode
);
78 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
80 LPTHREAD_START_ROUTINE lpStartAddress
,
82 DWORD dwCreationFlags
,
86 return CreateRemoteThread
106 LPSECURITY_ATTRIBUTES lpThreadAttributes
,
108 LPTHREAD_START_ROUTINE lpStartAddress
,
110 DWORD dwCreationFlags
,
115 CLIENT_ID cidClientId
;
117 ULONG_PTR nStackReserve
;
118 ULONG_PTR nStackCommit
;
119 OBJECT_ATTRIBUTES oaThreadAttribs
;
120 PIMAGE_NT_HEADERS pinhHeader
=
121 RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress
);
126 "lpThreadAttributes %08X\n"
128 "lpStartAddress %08X\n"
130 "dwCreationFlags %08X\n"
141 /* FIXME: do more checks - e.g. the image may not have an optional header */
142 if(pinhHeader
== NULL
)
144 nStackReserve
= 0x100000;
145 nStackCommit
= PAGE_SIZE
;
149 nStackReserve
= pinhHeader
->OptionalHeader
.SizeOfStackReserve
;
150 nStackCommit
= pinhHeader
->OptionalHeader
.SizeOfStackCommit
;
153 /* FIXME: this should be defined in winbase.h */
154 #ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
155 #define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000
159 if(dwStackSize
== 0);
160 /* dwStackSize specifies the size to reserve */
161 else if(dwCreationFlags
& STACK_SIZE_PARAM_IS_A_RESERVATION
)
162 nStackReserve
= dwStackSize
;
163 /* dwStackSize specifies the size to commit */
165 nStackCommit
= dwStackSize
;
167 /* fix the stack reserve size */
168 if(nStackCommit
> nStackReserve
)
169 nStackReserve
= ROUNDUP(nStackCommit
, 0x100000);
171 /* initialize the attributes for the thread object */
172 InitializeObjectAttributes
181 if(lpThreadAttributes
)
183 /* make the handle inheritable */
184 if(lpThreadAttributes
->bInheritHandle
)
185 oaThreadAttribs
.Attributes
|= OBJ_INHERIT
;
187 /* user-defined security descriptor */
188 oaThreadAttribs
.SecurityDescriptor
= lpThreadAttributes
->lpSecurityDescriptor
;
193 "RtlRosCreateUserThreadVa\n"
195 " ProcessHandle %p,\n"
196 " ObjectAttributes %p,\n"
197 " CreateSuspended %d,\n"
198 " StackZeroBits %d,\n"
199 " StackReserve %lu,\n"
200 " StackCommit %lu,\n"
201 " StartAddress %p,\n"
202 " ThreadHandle %p,\n"
204 " ParameterCount %u,\n"
205 " Parameters[0] %p,\n"
206 " Parameters[1] %p\n"
210 dwCreationFlags
& CREATE_SUSPENDED
,
222 /* create the thread */
223 nErrCode
= RtlRosCreateUserThreadVa
227 dwCreationFlags
& CREATE_SUSPENDED
,
231 (PTHREAD_START_ROUTINE
)BaseThreadStartup
,
240 if(!NT_SUCCESS(nErrCode
))
242 SetLastErrorByStatus(nErrCode
);
251 "ClientId.UniqueThread %p\n",
255 cidClientId
.UniqueThread
259 if(lpThreadId
) *lpThreadId
= (DWORD
)cidClientId
.UniqueThread
;
270 DWORD dwDesiredAccess
,
277 OBJECT_ATTRIBUTES ObjectAttributes
;
280 ClientId
.UniqueProcess
= INVALID_HANDLE_VALUE
;
281 ClientId
.UniqueThread
= (HANDLE
)dwThreadId
;
283 InitializeObjectAttributes (&ObjectAttributes
,
285 (bInheritHandle
? OBJ_INHERIT
: 0),
289 errCode
= NtOpenThread(&ThreadHandle
,
293 if (!NT_SUCCESS(errCode
))
295 SetLastErrorByStatus (errCode
);
308 return(NtCurrentTeb());
319 Status
= NtYieldExecution();
320 return Status
!= STATUS_NO_YIELD_PERFORMED
;
328 GetCurrentThreadId(VOID
)
330 return((DWORD
)(NtCurrentTeb()->Cid
).UniqueThread
);
337 ExitThread(DWORD uExitCode
)
343 * Terminate process if this is the last thread
344 * of the current process
346 Status
= NtQueryInformationThread(NtCurrentThread(),
351 if (NT_SUCCESS(Status
) && LastThread
== TRUE
)
353 ExitProcess(uExitCode
);
356 /* FIXME: notify csrss of thread termination */
360 RtlRosExitUserThread(uExitCode
);
368 GetThreadTimes(HANDLE hThread
,
369 LPFILETIME lpCreationTime
,
370 LPFILETIME lpExitTime
,
371 LPFILETIME lpKernelTime
,
372 LPFILETIME lpUserTime
)
374 KERNEL_USER_TIMES KernelUserTimes
;
377 Status
= NtQueryInformationThread(hThread
,
380 sizeof(KERNEL_USER_TIMES
),
382 if (!NT_SUCCESS(Status
))
384 SetLastErrorByStatus(Status
);
388 lpCreationTime
->dwLowDateTime
= KernelUserTimes
.CreateTime
.u
.LowPart
;
389 lpCreationTime
->dwHighDateTime
= KernelUserTimes
.CreateTime
.u
.HighPart
;
391 lpExitTime
->dwLowDateTime
= KernelUserTimes
.ExitTime
.u
.LowPart
;
392 lpExitTime
->dwHighDateTime
= KernelUserTimes
.ExitTime
.u
.HighPart
;
394 lpKernelTime
->dwLowDateTime
= KernelUserTimes
.KernelTime
.u
.LowPart
;
395 lpKernelTime
->dwHighDateTime
= KernelUserTimes
.KernelTime
.u
.HighPart
;
397 lpUserTime
->dwLowDateTime
= KernelUserTimes
.UserTime
.u
.LowPart
;
398 lpUserTime
->dwHighDateTime
= KernelUserTimes
.UserTime
.u
.HighPart
;
408 GetThreadContext(HANDLE hThread
,
413 Status
= NtGetContextThread(hThread
,
415 if (!NT_SUCCESS(Status
))
417 SetLastErrorByStatus(Status
);
429 SetThreadContext(HANDLE hThread
,
430 CONST CONTEXT
*lpContext
)
434 Status
= NtSetContextThread(hThread
,
436 if (!NT_SUCCESS(Status
))
438 SetLastErrorByStatus(Status
);
450 GetExitCodeThread(HANDLE hThread
,
453 THREAD_BASIC_INFORMATION ThreadBasic
;
456 Status
= NtQueryInformationThread(hThread
,
457 ThreadBasicInformation
,
459 sizeof(THREAD_BASIC_INFORMATION
),
461 if (!NT_SUCCESS(Status
))
463 SetLastErrorByStatus(Status
);
467 memcpy(lpExitCode
, &ThreadBasic
.ExitStatus
, sizeof(DWORD
));
477 ResumeThread(HANDLE hThread
)
479 ULONG PreviousResumeCount
;
482 Status
= NtResumeThread(hThread
,
483 &PreviousResumeCount
);
484 if (!NT_SUCCESS(Status
))
486 SetLastErrorByStatus(Status
);
490 return(PreviousResumeCount
);
498 TerminateThread(HANDLE hThread
,
505 SetLastError(ERROR_INVALID_HANDLE
);
509 Status
= NtTerminateThread(hThread
,
511 if (!NT_SUCCESS(Status
))
513 SetLastErrorByStatus(Status
);
525 SuspendThread(HANDLE hThread
)
527 ULONG PreviousSuspendCount
;
530 Status
= NtSuspendThread(hThread
,
531 &PreviousSuspendCount
);
532 if (!NT_SUCCESS(Status
))
534 SetLastErrorByStatus(Status
);
538 return(PreviousSuspendCount
);
546 SetThreadAffinityMask(HANDLE hThread
,
547 DWORD dwThreadAffinityMask
)
549 THREAD_BASIC_INFORMATION ThreadBasic
;
550 KAFFINITY AffinityMask
;
553 AffinityMask
= (KAFFINITY
)dwThreadAffinityMask
;
555 Status
= NtQueryInformationThread(hThread
,
556 ThreadBasicInformation
,
558 sizeof(THREAD_BASIC_INFORMATION
),
560 if (!NT_SUCCESS(Status
))
562 SetLastErrorByStatus(Status
);
566 Status
= NtSetInformationThread(hThread
,
570 if (!NT_SUCCESS(Status
))
571 SetLastErrorByStatus(Status
);
573 return(ThreadBasic
.AffinityMask
);
581 SetThreadPriority(HANDLE hThread
,
584 ULONG Prio
= nPriority
;
587 Status
= NtSetInformationThread(hThread
,
592 if (!NT_SUCCESS(Status
))
594 SetLastErrorByStatus(Status
);
606 GetThreadPriority(HANDLE hThread
)
608 THREAD_BASIC_INFORMATION ThreadBasic
;
611 Status
= NtQueryInformationThread(hThread
,
612 ThreadBasicInformation
,
614 sizeof(THREAD_BASIC_INFORMATION
),
616 if (!NT_SUCCESS(Status
))
618 SetLastErrorByStatus(Status
);
619 return(THREAD_PRIORITY_ERROR_RETURN
);
622 return(ThreadBasic
.BasePriority
);
630 GetThreadPriorityBoost(IN HANDLE hThread
,
631 OUT PBOOL pDisablePriorityBoost
)
636 Status
= NtQueryInformationThread(hThread
,
641 if (!NT_SUCCESS(Status
))
643 SetLastErrorByStatus(Status
);
647 *pDisablePriorityBoost
= !((BOOL
)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 DescriptionTableEntry
.Selector
= dwSelector
;
691 Status
= NtQueryInformationThread(hThread
,
692 ThreadDescriptorTableEntry
,
693 &DescriptionTableEntry
,
694 sizeof(DESCRIPTOR_TABLE_ENTRY
),
696 if(!NT_SUCCESS(Status
))
698 SetLastErrorByStatus(Status
);
702 *lpSelectorEntry
= DescriptionTableEntry
.Descriptor
;
711 SetThreadIdealProcessor(HANDLE hThread
,
712 DWORD dwIdealProcessor
)
716 Status
= NtSetInformationThread(hThread
,
717 ThreadIdealProcessor
,
720 if (!NT_SUCCESS(Status
))
722 SetLastErrorByStatus(Status
);
726 return dwIdealProcessor
;
734 GetProcessIdOfThread(HANDLE Thread
)
736 THREAD_BASIC_INFORMATION ThreadBasic
;
739 Status
= NtQueryInformationThread(Thread
,
740 ThreadBasicInformation
,
742 sizeof(THREAD_BASIC_INFORMATION
),
744 if(!NT_SUCCESS(Status
))
746 SetLastErrorByStatus(Status
);
750 return (DWORD
)ThreadBasic
.ClientId
.UniqueProcess
;
758 GetThreadId(HANDLE Thread
)
760 THREAD_BASIC_INFORMATION ThreadBasic
;
763 Status
= NtQueryInformationThread(Thread
,
764 ThreadBasicInformation
,
766 sizeof(THREAD_BASIC_INFORMATION
),
768 if(!NT_SUCCESS(Status
))
770 SetLastErrorByStatus(Status
);
774 return (DWORD
)ThreadBasic
.ClientId
.UniqueThread
;
781 SetThreadUILanguage(DWORD Unknown1
)
783 DPRINT1("SetThreadUILanguage(0x%x) unimplemented!\n", Unknown1
);
787 IntCallUserApc(PVOID Function
, PVOID dwData
, PVOID Argument3
)
789 PAPCFUNC pfnAPC
= (PAPCFUNC
)Function
;
790 pfnAPC((ULONG_PTR
)dwData
);
797 QueueUserAPC(PAPCFUNC pfnAPC
, HANDLE hThread
, ULONG_PTR dwData
)
801 Status
= NtQueueApcThread(hThread
, IntCallUserApc
, pfnAPC
,
802 (PVOID
)dwData
, NULL
);
804 SetLastErrorByStatus(Status
);
806 return NT_SUCCESS(Status
);
813 GetThreadIOPendingFlag(HANDLE hThread
,
819 if(lpIOIsPending
== NULL
)
821 SetLastError(ERROR_INVALID_PARAMETER
);
825 Status
= NtQueryInformationThread(hThread
,
830 if(NT_SUCCESS(Status
))
832 *lpIOIsPending
= ((IoPending
!= 0) ? TRUE
: FALSE
);
836 SetLastErrorByStatus(Status
);
845 Sleep(DWORD dwMilliseconds
)
847 SleepEx(dwMilliseconds
, FALSE
);
856 SleepEx(DWORD dwMilliseconds
,
859 LARGE_INTEGER Interval
;
862 if (dwMilliseconds
!= INFINITE
)
865 * System time units are 100 nanoseconds (a nanosecond is a billionth of
868 Interval
.QuadPart
= -((ULONGLONG
)dwMilliseconds
* 10000);
872 /* Approximately 292000 years hence */
873 Interval
.QuadPart
= -0x7FFFFFFFFFFFFFFFLL
;
876 errCode
= NtDelayExecution ((bAlertable
? TRUE
: FALSE
), &Interval
);
877 if (!NT_SUCCESS(errCode
))
879 SetLastErrorByStatus (errCode
);