1999-01-16 02:11:45 +00:00
|
|
|
/*
|
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS system libraries
|
|
|
|
* FILE: lib/kernel32/thread/thread.c
|
|
|
|
* PURPOSE: Thread functions
|
|
|
|
* PROGRAMMER: Ariadne ( ariadne@xs4all.nl)
|
1999-05-29 00:15:17 +00:00
|
|
|
* Tls functions are modified from WINE
|
1999-01-16 02:11:45 +00:00
|
|
|
* UPDATE HISTORY:
|
|
|
|
* Created 01/11/98
|
|
|
|
*/
|
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
/* INCLUDES ******************************************************************/
|
|
|
|
|
1999-10-07 23:46:27 +00:00
|
|
|
#include <ddk/ntddk.h>
|
1999-01-16 02:11:45 +00:00
|
|
|
#include <windows.h>
|
|
|
|
#include <kernel32/thread.h>
|
|
|
|
#include <string.h>
|
1999-01-16 21:03:00 +00:00
|
|
|
#include <internal/i386/segment.h>
|
1999-01-16 02:11:45 +00:00
|
|
|
|
1999-12-13 22:04:41 +00:00
|
|
|
#define NDEBUG
|
1999-09-05 10:22:05 +00:00
|
|
|
#include <kernel32/kernel32.h>
|
|
|
|
|
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
/* FUNCTIONS *****************************************************************/
|
|
|
|
|
1999-09-06 21:32:57 +00:00
|
|
|
static VOID STDCALL
|
|
|
|
ThreadStartup (LPTHREAD_START_ROUTINE lpStartAddress,
|
|
|
|
LPVOID lpParameter)
|
|
|
|
{
|
|
|
|
UINT uExitCode;
|
|
|
|
|
|
|
|
uExitCode = (lpStartAddress)(lpParameter);
|
|
|
|
|
|
|
|
NtTerminateThread(NtCurrentThread(),
|
|
|
|
uExitCode);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
HANDLE STDCALL CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
|
|
|
DWORD dwStackSize,
|
|
|
|
LPTHREAD_START_ROUTINE lpStartAddress,
|
|
|
|
LPVOID lpParameter,
|
|
|
|
DWORD dwCreationFlags,
|
|
|
|
LPDWORD lpThreadId)
|
1999-01-16 02:11:45 +00:00
|
|
|
{
|
1999-05-29 00:15:17 +00:00
|
|
|
return(CreateRemoteThread(NtCurrentProcess(),
|
|
|
|
lpThreadAttributes,
|
|
|
|
dwStackSize,
|
|
|
|
lpStartAddress,
|
|
|
|
lpParameter,
|
|
|
|
dwCreationFlags,
|
|
|
|
lpThreadId));
|
1999-01-16 02:11:45 +00:00
|
|
|
}
|
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
HANDLE STDCALL CreateRemoteThread(HANDLE hProcess,
|
|
|
|
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
|
|
|
DWORD dwStackSize,
|
|
|
|
LPTHREAD_START_ROUTINE lpStartAddress,
|
|
|
|
LPVOID lpParameter,
|
|
|
|
DWORD dwCreationFlags,
|
|
|
|
LPDWORD lpThreadId)
|
1999-01-16 02:11:45 +00:00
|
|
|
{
|
1999-01-16 21:03:00 +00:00
|
|
|
HANDLE ThreadHandle;
|
|
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
|
|
CLIENT_ID ClientId;
|
|
|
|
CONTEXT ThreadContext;
|
|
|
|
INITIAL_TEB InitialTeb;
|
|
|
|
BOOLEAN CreateSuspended = FALSE;
|
1999-05-29 00:15:17 +00:00
|
|
|
PVOID BaseAddress;
|
1999-09-05 10:22:05 +00:00
|
|
|
DWORD StackSize;
|
|
|
|
NTSTATUS Status;
|
1999-01-16 21:03:00 +00:00
|
|
|
|
|
|
|
ObjectAttributes.Length = sizeof(OBJECT_ATTRIBUTES);
|
|
|
|
ObjectAttributes.RootDirectory = NULL;
|
|
|
|
ObjectAttributes.ObjectName = NULL;
|
|
|
|
ObjectAttributes.Attributes = 0;
|
1999-05-29 00:15:17 +00:00
|
|
|
if (lpThreadAttributes != NULL)
|
|
|
|
{
|
|
|
|
if (lpThreadAttributes->bInheritHandle)
|
|
|
|
ObjectAttributes.Attributes = OBJ_INHERIT;
|
|
|
|
ObjectAttributes.SecurityDescriptor =
|
|
|
|
lpThreadAttributes->lpSecurityDescriptor;
|
|
|
|
}
|
1999-01-16 21:03:00 +00:00
|
|
|
ObjectAttributes.SecurityQualityOfService = NULL;
|
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
if ((dwCreationFlags & CREATE_SUSPENDED) == CREATE_SUSPENDED)
|
|
|
|
CreateSuspended = TRUE;
|
1999-01-16 21:03:00 +00:00
|
|
|
else
|
|
|
|
CreateSuspended = FALSE;
|
1999-09-05 10:22:05 +00:00
|
|
|
|
|
|
|
StackSize = (dwStackSize == 0) ? 4096 : dwStackSize;
|
|
|
|
|
1999-01-16 21:03:00 +00:00
|
|
|
BaseAddress = 0;
|
1999-11-02 08:55:45 +00:00
|
|
|
|
1999-09-05 10:22:05 +00:00
|
|
|
Status = NtAllocateVirtualMemory(hProcess,
|
|
|
|
&BaseAddress,
|
|
|
|
0,
|
|
|
|
(PULONG)&StackSize,
|
|
|
|
MEM_COMMIT,
|
|
|
|
PAGE_READWRITE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT("Could not allocate stack space!\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
1999-01-16 21:03:00 +00:00
|
|
|
|
1999-11-02 08:55:45 +00:00
|
|
|
|
1999-09-05 10:22:05 +00:00
|
|
|
DPRINT("Stack base address: %p\n", BaseAddress);
|
|
|
|
|
1999-01-16 21:03:00 +00:00
|
|
|
memset(&ThreadContext,0,sizeof(CONTEXT));
|
1999-09-06 21:32:57 +00:00
|
|
|
// ThreadContext.Eip = (LONG)lpStartAddress;
|
|
|
|
ThreadContext.Eip = (LONG)ThreadStartup;
|
1999-01-16 21:03:00 +00:00
|
|
|
ThreadContext.SegGs = USER_DS;
|
|
|
|
ThreadContext.SegFs = USER_DS;
|
|
|
|
ThreadContext.SegEs = USER_DS;
|
|
|
|
ThreadContext.SegDs = USER_DS;
|
|
|
|
ThreadContext.SegCs = USER_CS;
|
|
|
|
ThreadContext.SegSs = USER_DS;
|
1999-09-06 21:32:57 +00:00
|
|
|
ThreadContext.Esp = (ULONG)(BaseAddress + StackSize - 12);
|
1999-01-16 21:03:00 +00:00
|
|
|
ThreadContext.EFlags = (1<<1) + (1<<9);
|
|
|
|
|
1999-09-06 21:32:57 +00:00
|
|
|
/* initialize call stack */
|
|
|
|
*((PULONG)(BaseAddress + StackSize - 4)) = (ULONG)lpParameter;
|
|
|
|
*((PULONG)(BaseAddress + StackSize - 8)) = (ULONG)lpStartAddress;
|
|
|
|
*((PULONG)(BaseAddress + StackSize - 12)) = 0xdeadbeef;
|
|
|
|
|
|
|
|
DPRINT("Esp: %p\n", ThreadContext.Esp);
|
|
|
|
DPRINT("Eip: %p\n", ThreadContext.Eip);
|
1999-09-05 10:22:05 +00:00
|
|
|
|
|
|
|
Status = NtCreateThread(&ThreadHandle,
|
|
|
|
THREAD_ALL_ACCESS,
|
|
|
|
&ObjectAttributes,
|
|
|
|
hProcess,
|
|
|
|
&ClientId,
|
|
|
|
&ThreadContext,
|
|
|
|
&InitialTeb,
|
|
|
|
CreateSuspended);
|
|
|
|
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT("NtCreateThread() failed!\n");
|
|
|
|
return NULL;
|
|
|
|
}
|
1999-01-16 21:03:00 +00:00
|
|
|
|
|
|
|
if ( lpThreadId != NULL )
|
|
|
|
memcpy(lpThreadId, &ClientId.UniqueThread,sizeof(ULONG));
|
|
|
|
|
|
|
|
return ThreadHandle;
|
1999-01-16 02:11:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NT_TEB *GetTeb(VOID)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
WINBOOL STDCALL SwitchToThread(VOID)
|
1999-01-16 02:11:45 +00:00
|
|
|
{
|
1999-05-29 00:15:17 +00:00
|
|
|
NTSTATUS errCode;
|
|
|
|
errCode = NtYieldExecution();
|
|
|
|
return TRUE;
|
1999-01-16 02:11:45 +00:00
|
|
|
}
|
|
|
|
|
1999-01-16 21:03:00 +00:00
|
|
|
DWORD STDCALL GetCurrentThreadId()
|
1999-01-16 02:11:45 +00:00
|
|
|
{
|
1999-05-29 00:15:17 +00:00
|
|
|
return((DWORD)(GetTeb()->Cid).UniqueThread);
|
1999-01-16 02:11:45 +00:00
|
|
|
}
|
|
|
|
|
1999-01-16 21:03:00 +00:00
|
|
|
VOID STDCALL ExitThread(UINT uExitCode)
|
1999-01-16 02:11:45 +00:00
|
|
|
{
|
1999-05-29 00:15:17 +00:00
|
|
|
NTSTATUS errCode;
|
|
|
|
|
|
|
|
errCode = NtTerminateThread(NtCurrentThread(),
|
|
|
|
uExitCode);
|
|
|
|
if (!NT_SUCCESS(errCode))
|
|
|
|
{
|
|
|
|
SetLastError(RtlNtStatusToDosError(errCode));
|
|
|
|
}
|
1999-01-16 02:11:45 +00:00
|
|
|
}
|
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
WINBOOL STDCALL GetThreadTimes(HANDLE hThread,
|
|
|
|
LPFILETIME lpCreationTime,
|
|
|
|
LPFILETIME lpExitTime,
|
|
|
|
LPFILETIME lpKernelTime,
|
|
|
|
LPFILETIME lpUserTime)
|
1999-01-16 02:11:45 +00:00
|
|
|
{
|
1999-05-29 00:15:17 +00:00
|
|
|
NTSTATUS errCode;
|
|
|
|
KERNEL_USER_TIMES KernelUserTimes;
|
|
|
|
ULONG ReturnLength;
|
|
|
|
|
|
|
|
errCode = NtQueryInformationThread(hThread,
|
|
|
|
ThreadTimes,
|
|
|
|
&KernelUserTimes,
|
|
|
|
sizeof(KERNEL_USER_TIMES),
|
|
|
|
&ReturnLength);
|
|
|
|
if (!NT_SUCCESS(errCode))
|
|
|
|
{
|
|
|
|
SetLastError(RtlNtStatusToDosError(errCode));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
memcpy(lpCreationTime, &KernelUserTimes.CreateTime, sizeof(FILETIME));
|
|
|
|
memcpy(lpExitTime, &KernelUserTimes.ExitTime, sizeof(FILETIME));
|
|
|
|
memcpy(lpKernelTime, &KernelUserTimes.KernelTime, sizeof(FILETIME));
|
|
|
|
memcpy(lpUserTime, &KernelUserTimes.UserTime, sizeof(FILETIME));
|
|
|
|
return TRUE;
|
1999-01-16 02:11:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
WINBOOL STDCALL GetThreadContext(HANDLE hThread,
|
|
|
|
LPCONTEXT lpContext)
|
1999-01-16 02:11:45 +00:00
|
|
|
{
|
1999-05-29 00:15:17 +00:00
|
|
|
NTSTATUS errCode;
|
|
|
|
|
|
|
|
errCode = NtGetContextThread(hThread,
|
|
|
|
lpContext);
|
|
|
|
if (!NT_SUCCESS(errCode))
|
|
|
|
{
|
|
|
|
SetLastError(RtlNtStatusToDosError(errCode));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
1999-01-16 02:11:45 +00:00
|
|
|
}
|
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
WINBOOL STDCALL SetThreadContext(HANDLE hThread,
|
|
|
|
CONST CONTEXT *lpContext)
|
1999-01-16 02:11:45 +00:00
|
|
|
{
|
1999-05-29 00:15:17 +00:00
|
|
|
NTSTATUS errCode;
|
|
|
|
|
|
|
|
errCode = NtSetContextThread(hThread,
|
|
|
|
(void *)lpContext);
|
|
|
|
if (!NT_SUCCESS(errCode))
|
|
|
|
{
|
|
|
|
SetLastError(RtlNtStatusToDosError(errCode));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
1999-01-16 02:11:45 +00:00
|
|
|
}
|
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
WINBOOL STDCALL GetExitCodeThread(HANDLE hThread,
|
|
|
|
LPDWORD lpExitCode)
|
1999-01-16 02:11:45 +00:00
|
|
|
{
|
1999-05-29 00:15:17 +00:00
|
|
|
NTSTATUS errCode;
|
|
|
|
THREAD_BASIC_INFORMATION ThreadBasic;
|
|
|
|
ULONG DataWritten;
|
|
|
|
|
|
|
|
errCode = NtQueryInformationThread(hThread,
|
|
|
|
ThreadBasicInformation,
|
|
|
|
&ThreadBasic,
|
|
|
|
sizeof(THREAD_BASIC_INFORMATION),
|
|
|
|
&DataWritten);
|
|
|
|
if (!NT_SUCCESS(errCode))
|
|
|
|
{
|
|
|
|
SetLastError(RtlNtStatusToDosError(errCode));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
memcpy(lpExitCode, &ThreadBasic.ExitStatus, sizeof(DWORD));
|
|
|
|
return TRUE;
|
1999-01-16 02:11:45 +00:00
|
|
|
}
|
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
DWORD STDCALL ResumeThread(HANDLE hThread)
|
1999-01-16 02:11:45 +00:00
|
|
|
{
|
1999-05-29 00:15:17 +00:00
|
|
|
NTSTATUS errCode;
|
|
|
|
ULONG PreviousResumeCount;
|
|
|
|
|
|
|
|
errCode = NtResumeThread(hThread,
|
|
|
|
&PreviousResumeCount);
|
|
|
|
if (!NT_SUCCESS(errCode))
|
|
|
|
{
|
|
|
|
SetLastError(RtlNtStatusToDosError(errCode));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return PreviousResumeCount;
|
1999-01-16 02:11:45 +00:00
|
|
|
}
|
|
|
|
|
1999-10-02 20:20:44 +00:00
|
|
|
|
|
|
|
WINBOOL
|
|
|
|
STDCALL
|
|
|
|
TerminateThread (
|
|
|
|
HANDLE hThread,
|
|
|
|
DWORD dwExitCode
|
|
|
|
)
|
|
|
|
{
|
|
|
|
NTSTATUS errCode;
|
|
|
|
|
|
|
|
errCode = NtTerminateThread(hThread,
|
|
|
|
dwExitCode);
|
|
|
|
if (!NT_SUCCESS(errCode))
|
|
|
|
{
|
|
|
|
SetLastError(RtlNtStatusToDosError(errCode));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
DWORD STDCALL SuspendThread(HANDLE hThread)
|
1999-01-16 02:11:45 +00:00
|
|
|
{
|
1999-05-29 00:15:17 +00:00
|
|
|
NTSTATUS errCode;
|
|
|
|
ULONG PreviousSuspendCount;
|
|
|
|
|
|
|
|
errCode = NtSuspendThread(hThread,
|
|
|
|
&PreviousSuspendCount);
|
|
|
|
if (!NT_SUCCESS(errCode))
|
|
|
|
{
|
|
|
|
SetLastError(RtlNtStatusToDosError(errCode));
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return PreviousSuspendCount;
|
1999-01-16 02:11:45 +00:00
|
|
|
}
|
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
DWORD STDCALL SetThreadAffinityMask(HANDLE hThread,
|
|
|
|
DWORD dwThreadAffinityMask)
|
1999-01-16 02:11:45 +00:00
|
|
|
{
|
1999-05-29 00:15:17 +00:00
|
|
|
return 0;
|
1999-01-16 02:11:45 +00:00
|
|
|
}
|
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
WINBOOL STDCALL SetThreadPriority(HANDLE hThread,
|
|
|
|
int nPriority)
|
1999-01-16 02:11:45 +00:00
|
|
|
{
|
1999-05-29 00:15:17 +00:00
|
|
|
NTSTATUS errCode;
|
|
|
|
THREAD_BASIC_INFORMATION ThreadBasic;
|
|
|
|
ULONG DataWritten;
|
|
|
|
|
|
|
|
errCode = NtQueryInformationThread(hThread,
|
|
|
|
ThreadBasicInformation,
|
|
|
|
&ThreadBasic,
|
|
|
|
sizeof(THREAD_BASIC_INFORMATION),
|
|
|
|
&DataWritten);
|
|
|
|
if (!NT_SUCCESS(errCode))
|
|
|
|
{
|
|
|
|
SetLastError(RtlNtStatusToDosError(errCode));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
ThreadBasic.BasePriority = nPriority;
|
|
|
|
errCode = NtSetInformationThread(hThread,
|
|
|
|
ThreadBasicInformation,
|
|
|
|
&ThreadBasic,
|
|
|
|
sizeof(THREAD_BASIC_INFORMATION));
|
|
|
|
if (!NT_SUCCESS(errCode))
|
|
|
|
{
|
|
|
|
SetLastError(RtlNtStatusToDosError(errCode));
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
return TRUE;
|
1999-01-16 02:11:45 +00:00
|
|
|
}
|
|
|
|
|
1999-05-29 00:15:17 +00:00
|
|
|
int STDCALL GetThreadPriority(HANDLE hThread)
|
1999-01-16 02:11:45 +00:00
|
|
|
{
|
1999-05-29 00:15:17 +00:00
|
|
|
NTSTATUS errCode;
|
|
|
|
THREAD_BASIC_INFORMATION ThreadBasic;
|
|
|
|
ULONG DataWritten;
|
|
|
|
|
|
|
|
errCode = NtQueryInformationThread(hThread,
|
|
|
|
ThreadBasicInformation,
|
|
|
|
&ThreadBasic,
|
|
|
|
sizeof(THREAD_BASIC_INFORMATION),
|
|
|
|
&DataWritten);
|
|
|
|
if (!NT_SUCCESS(errCode))
|
|
|
|
{
|
|
|
|
SetLastError(RtlNtStatusToDosError(errCode));
|
|
|
|
return THREAD_PRIORITY_ERROR_RETURN;
|
|
|
|
}
|
|
|
|
return ThreadBasic.BasePriority;
|
1999-01-16 02:11:45 +00:00
|
|
|
}
|