mirror of
https://github.com/reactos/reactos.git
synced 2024-12-28 10:04:49 +00:00
- Final ROSRTL removal patch. The next patch will remove the actual library and code.
- Changes: - CreateProcess * Cleanup creation of the initial thread using new utility functions and remove rosrtl * Almost entirely rewrote the function to support features such as: - SxS (locally only, patch will follow), - SFP (SAFER) (locally only, patch will follow), - DllPaths (locally only, patch will follow), - Proper process environment/paramter block creation - Proper console handle management (needs more work in kernel32/csr), - Tokens/CreateProcessAsUser (locally only, patch will follow), - Simpler code for path lookup, and more robust. - Support for "auto-correction" (see Raymond Chen's blog) - 16-bit/NE detection - A variety of creation flags are now properly supported - Added support for an undocumented-yet-known (see comment) shell flag - Alert for flags we don't support yet - Catch invalid flag combinations and other caller errors - Improve and correct path searcing to use documented behaviours - Created a multitude of helper functions to make the code easier to read and allow them to be used for other apis as time goes on. - BaseProcessStartup * Call NtSetThreadInformation to let the Kernel know of the Thread's Start Address. * Correct prototype of Thread Startup function for this case. This fixes MANY things, some of which may not be evident, and possibly creates regressions which I have not yet seen but will try to correct. Some of these may be caused by the fact that I've seen code send CreateProcessW incorrect flags. Some things of note: DO NOT send partial names as "lpApplicationName". It's not supposed to work unless you're in the same current directory. Also, do NOT send CREATE_UNICODE_ENVIRONMENT if you don't have a unicode environement, and vice-versa. I've seen lots of code doing mistakes related to this. I hope you appreciate this patch and won't all jump on me for possbile regressions :(. svn path=/trunk/; revision=16730
This commit is contained in:
parent
286cccb1de
commit
1e8c8e3fe6
4 changed files with 2083 additions and 2079 deletions
File diff suppressed because it is too large
Load diff
|
@ -18,7 +18,7 @@ _BaseThreadStartupThunk@0:
|
|||
push ebx /* lpParameter */
|
||||
push eax /* lpStartAddress */
|
||||
push 0 /* Return EIP */
|
||||
//jmp _BaseThreadStartup@8
|
||||
jmp _BaseThreadStartup@8
|
||||
|
||||
_BaseProcessStartThunk@0:
|
||||
|
||||
|
@ -27,6 +27,6 @@ _BaseProcessStartThunk@0:
|
|||
|
||||
push eax /* lpStartAddress */
|
||||
push 0 /* Return EIP */
|
||||
//jmp _BaseProcessStartup@4
|
||||
jmp _BaseProcessStartup@4
|
||||
|
||||
/* EOF */
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
/* $Id$
|
||||
*
|
||||
/*
|
||||
* 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)
|
||||
* Tls functions are modified from WINE
|
||||
* UPDATE HISTORY:
|
||||
* Created 01/11/98
|
||||
* PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
|
||||
* Ariadne ( ariadne@xs4all.nl)
|
||||
*
|
||||
*/
|
||||
|
||||
|
@ -15,13 +12,9 @@
|
|||
|
||||
#include <k32.h>
|
||||
|
||||
/* FIXME */
|
||||
#include <rosrtl/thread.h>
|
||||
|
||||
#define NDEBUG
|
||||
#include "../include/debug.h"
|
||||
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
_SEH_FILTER(BaseThreadExceptionFilter)
|
||||
{
|
||||
|
@ -68,198 +61,195 @@ BaseThreadStartup(LPTHREAD_START_ROUTINE lpStartAddress,
|
|||
ExitThread(uExitCode);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
HANDLE STDCALL
|
||||
CreateThread
|
||||
(
|
||||
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
HANDLE
|
||||
STDCALL
|
||||
CreateThread(LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
DWORD dwStackSize,
|
||||
LPTHREAD_START_ROUTINE lpStartAddress,
|
||||
LPVOID lpParameter,
|
||||
DWORD dwCreationFlags,
|
||||
LPDWORD lpThreadId
|
||||
)
|
||||
LPDWORD lpThreadId)
|
||||
{
|
||||
return CreateRemoteThread
|
||||
(
|
||||
NtCurrentProcess(),
|
||||
/* Act as if we're going to create a remote thread in ourselves */
|
||||
return CreateRemoteThread(NtCurrentProcess(),
|
||||
lpThreadAttributes,
|
||||
dwStackSize,
|
||||
lpStartAddress,
|
||||
lpParameter,
|
||||
dwCreationFlags,
|
||||
lpThreadId
|
||||
);
|
||||
lpThreadId);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
HANDLE STDCALL
|
||||
CreateRemoteThread
|
||||
(
|
||||
HANDLE hProcess,
|
||||
HANDLE
|
||||
STDCALL
|
||||
CreateRemoteThread(HANDLE hProcess,
|
||||
LPSECURITY_ATTRIBUTES lpThreadAttributes,
|
||||
DWORD dwStackSize,
|
||||
LPTHREAD_START_ROUTINE lpStartAddress,
|
||||
LPVOID lpParameter,
|
||||
DWORD dwCreationFlags,
|
||||
LPDWORD lpThreadId
|
||||
)
|
||||
LPDWORD lpThreadId)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
INITIAL_TEB InitialTeb;
|
||||
CONTEXT Context;
|
||||
CLIENT_ID ClientId;
|
||||
OBJECT_ATTRIBUTES LocalObjectAttributes;
|
||||
POBJECT_ATTRIBUTES ObjectAttributes;
|
||||
HANDLE hThread;
|
||||
CLIENT_ID cidClientId;
|
||||
NTSTATUS nErrCode;
|
||||
ULONG_PTR nStackReserve;
|
||||
ULONG_PTR nStackCommit;
|
||||
OBJECT_ATTRIBUTES oaThreadAttribs;
|
||||
PIMAGE_NT_HEADERS pinhHeader =
|
||||
RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
|
||||
ULONG Dummy;
|
||||
|
||||
DPRINT
|
||||
(
|
||||
"hProcess %08X\n"
|
||||
"lpThreadAttributes %08X\n"
|
||||
"dwStackSize %08X\n"
|
||||
"lpStartAddress %08X\n"
|
||||
"lpParameter %08X\n"
|
||||
"dwCreationFlags %08X\n"
|
||||
"lpThreadId %08X\n",
|
||||
hProcess,
|
||||
lpThreadAttributes,
|
||||
DPRINT("CreateRemoteThread: hProcess: %ld dwStackSize: %ld lpStartAddress"
|
||||
": %p lpParameter: %lx, dwCreationFlags: %lx\n", hProcess,
|
||||
dwStackSize, lpStartAddress, lpParameter, dwCreationFlags);
|
||||
|
||||
/* Clear the Context */
|
||||
RtlZeroMemory(&Context, sizeof(CONTEXT));
|
||||
|
||||
/* Write PID */
|
||||
ClientId.UniqueProcess = hProcess;
|
||||
|
||||
/* Create the Stack */
|
||||
Status = BasepCreateStack(hProcess,
|
||||
dwStackSize,
|
||||
lpStartAddress,
|
||||
lpParameter,
|
||||
dwCreationFlags,
|
||||
lpThreadId
|
||||
);
|
||||
|
||||
/* FIXME: do more checks - e.g. the image may not have an optional header */
|
||||
if(pinhHeader == NULL)
|
||||
dwCreationFlags & STACK_SIZE_PARAM_IS_A_RESERVATION ?
|
||||
dwStackSize : 0,
|
||||
&InitialTeb);
|
||||
if(!NT_SUCCESS(Status))
|
||||
{
|
||||
nStackReserve = 0x100000;
|
||||
nStackCommit = PAGE_SIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
nStackReserve = pinhHeader->OptionalHeader.SizeOfStackReserve;
|
||||
nStackCommit = pinhHeader->OptionalHeader.SizeOfStackCommit;
|
||||
}
|
||||
|
||||
/* FIXME: this should be defined in winbase.h */
|
||||
#ifndef STACK_SIZE_PARAM_IS_A_RESERVATION
|
||||
#define STACK_SIZE_PARAM_IS_A_RESERVATION 0x00010000
|
||||
#endif
|
||||
|
||||
/* use defaults */
|
||||
if(dwStackSize == 0);
|
||||
/* dwStackSize specifies the size to reserve */
|
||||
else if(dwCreationFlags & STACK_SIZE_PARAM_IS_A_RESERVATION)
|
||||
nStackReserve = dwStackSize;
|
||||
/* dwStackSize specifies the size to commit */
|
||||
else
|
||||
nStackCommit = dwStackSize;
|
||||
|
||||
/* fix the stack reserve size */
|
||||
if(nStackCommit > nStackReserve)
|
||||
nStackReserve = ROUNDUP(nStackCommit, 0x100000);
|
||||
|
||||
/* initialize the attributes for the thread object */
|
||||
InitializeObjectAttributes
|
||||
(
|
||||
&oaThreadAttribs,
|
||||
NULL,
|
||||
0,
|
||||
NULL,
|
||||
NULL
|
||||
);
|
||||
|
||||
if(lpThreadAttributes)
|
||||
{
|
||||
/* make the handle inheritable */
|
||||
if(lpThreadAttributes->bInheritHandle)
|
||||
oaThreadAttribs.Attributes |= OBJ_INHERIT;
|
||||
|
||||
/* user-defined security descriptor */
|
||||
oaThreadAttribs.SecurityDescriptor = lpThreadAttributes->lpSecurityDescriptor;
|
||||
}
|
||||
|
||||
DPRINT
|
||||
(
|
||||
"RtlRosCreateUserThreadVa\n"
|
||||
"(\n"
|
||||
" ProcessHandle %p,\n"
|
||||
" ObjectAttributes %p,\n"
|
||||
" CreateSuspended %d,\n"
|
||||
" StackZeroBits %d,\n"
|
||||
" StackReserve %lu,\n"
|
||||
" StackCommit %lu,\n"
|
||||
" StartAddress %p,\n"
|
||||
" ThreadHandle %p,\n"
|
||||
" ClientId %p,\n"
|
||||
" ParameterCount %u,\n"
|
||||
" Parameters[0] %p,\n"
|
||||
" Parameters[1] %p\n"
|
||||
")\n",
|
||||
hProcess,
|
||||
&oaThreadAttribs,
|
||||
dwCreationFlags & CREATE_SUSPENDED,
|
||||
0,
|
||||
nStackReserve,
|
||||
nStackCommit,
|
||||
BaseThreadStartup,
|
||||
&hThread,
|
||||
&cidClientId,
|
||||
2,
|
||||
lpStartAddress,
|
||||
lpParameter
|
||||
);
|
||||
|
||||
/* create the thread */
|
||||
nErrCode = RtlRosCreateUserThreadVa
|
||||
(
|
||||
hProcess,
|
||||
&oaThreadAttribs,
|
||||
dwCreationFlags & CREATE_SUSPENDED,
|
||||
0,
|
||||
&nStackReserve,
|
||||
&nStackCommit,
|
||||
(PTHREAD_START_ROUTINE)BaseThreadStartup,
|
||||
&hThread,
|
||||
&cidClientId,
|
||||
2,
|
||||
lpStartAddress,
|
||||
lpParameter
|
||||
);
|
||||
|
||||
/* failure */
|
||||
if(!NT_SUCCESS(nErrCode))
|
||||
{
|
||||
SetLastErrorByStatus(nErrCode);
|
||||
SetLastErrorByStatus(Status);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DPRINT
|
||||
(
|
||||
"StackReserve %p\n"
|
||||
"StackCommit %p\n"
|
||||
"ThreadHandle %p\n"
|
||||
"ClientId.UniqueThread %p\n",
|
||||
nStackReserve,
|
||||
nStackCommit,
|
||||
hThread,
|
||||
cidClientId.UniqueThread
|
||||
);
|
||||
/* Create Initial Context */
|
||||
BasepInitializeContext(&Context,
|
||||
lpParameter,
|
||||
lpStartAddress,
|
||||
InitialTeb.StackBase,
|
||||
1);
|
||||
|
||||
/* success */
|
||||
if(lpThreadId) *lpThreadId = (DWORD)cidClientId.UniqueThread;
|
||||
/* initialize the attributes for the thread object */
|
||||
ObjectAttributes = BasepConvertObjectAttributes(&LocalObjectAttributes,
|
||||
lpThreadAttributes,
|
||||
NULL);
|
||||
|
||||
/* Create the Kernel Thread Object */
|
||||
Status = NtCreateThread(&hThread,
|
||||
THREAD_ALL_ACCESS,
|
||||
ObjectAttributes,
|
||||
hProcess,
|
||||
&ClientId,
|
||||
&Context,
|
||||
&InitialTeb,
|
||||
TRUE);
|
||||
if(!NT_SUCCESS(Status))
|
||||
{
|
||||
BasepFreeStack(hProcess, &InitialTeb);
|
||||
SetLastErrorByStatus(Status);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#ifdef SXS_SUPPORT_ENABLED
|
||||
/* Are we in the same process? */
|
||||
if (Process = NtCurrentProcess())
|
||||
{
|
||||
PTEB Teb;
|
||||
PVOID ActivationContextStack;
|
||||
PTHREAD_BASIC_INFORMATION ThreadBasicInfo;
|
||||
PACTIVATION_CONTEXT_BASIC_INFORMATION ActivationCtxInfo;
|
||||
ULONG_PTR Cookie;
|
||||
|
||||
/* Get the TEB */
|
||||
Status = NtQueryInformationThread(hThread,
|
||||
ThreadBasicIformation,
|
||||
&ThreadBasicInfo,
|
||||
sizeof(ThreadBasicInfo),
|
||||
NULL);
|
||||
|
||||
/* Allocate the Activation Context Stack */
|
||||
Status = RtlAllocateActivationContextStack(&ActivationContextStack);
|
||||
Teb = ThreadBasicInfo.TebBaseAddress;
|
||||
|
||||
/* Save it */
|
||||
Teb->ActivationContextStackPointer = ActivationContextStack;
|
||||
|
||||
/* Query the Context */
|
||||
Status = RtlQueryInformationActivationContext(1,
|
||||
0,
|
||||
NULL,
|
||||
ActivationContextBasicInformation,
|
||||
&ActivationCtxInfo,
|
||||
sizeof(ActivationCtxInfo),
|
||||
NULL);
|
||||
|
||||
/* Does it need to be activated? */
|
||||
if (!ActivationCtxInfo.hActCtx)
|
||||
{
|
||||
/* Activate it */
|
||||
Status = RtlActivateActivationContextEx(1,
|
||||
Teb,
|
||||
ActivationCtxInfo.hActCtx,
|
||||
&Cookie);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* FIXME: Notify CSR */
|
||||
|
||||
/* Success */
|
||||
if(lpThreadId) *lpThreadId = (DWORD)ClientId.UniqueThread;
|
||||
|
||||
/* Resume it if asked */
|
||||
if (!(dwCreationFlags & CREATE_SUSPENDED))
|
||||
{
|
||||
NtResumeThread(hThread, &Dummy);
|
||||
}
|
||||
|
||||
/* Return handle to thread */
|
||||
return hThread;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
VOID
|
||||
STDCALL
|
||||
ExitThread(DWORD uExitCode)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
BOOLEAN LastThread;
|
||||
|
||||
/*
|
||||
* Terminate process if this is the last thread
|
||||
* of the current process
|
||||
*/
|
||||
Status = NtQueryInformationThread(NtCurrentThread(),
|
||||
ThreadAmILastThread,
|
||||
&LastThread,
|
||||
sizeof(BOOLEAN),
|
||||
NULL);
|
||||
if (NT_SUCCESS(Status) && LastThread)
|
||||
{
|
||||
/* Exit the Process */
|
||||
ExitProcess(uExitCode);
|
||||
}
|
||||
|
||||
/* Notify DLLs and TLS Callbacks of termination */
|
||||
LdrShutdownThread();
|
||||
|
||||
/* Tell the Kernel to free the Stack */
|
||||
NtCurrentTeb()->FreeStackOnTermination = TRUE;
|
||||
NtTerminateThread(NULL, uExitCode);
|
||||
|
||||
/* We will never reach this place. This silences the compiler */
|
||||
ExitThread(uExitCode);
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
|
@ -330,37 +320,6 @@ GetCurrentThreadId(VOID)
|
|||
return((DWORD)(NtCurrentTeb()->Cid).UniqueThread);
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
VOID STDCALL
|
||||
ExitThread(DWORD uExitCode)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
BOOLEAN LastThread;
|
||||
|
||||
/*
|
||||
* Terminate process if this is the last thread
|
||||
* of the current process
|
||||
*/
|
||||
Status = NtQueryInformationThread(NtCurrentThread(),
|
||||
ThreadAmILastThread,
|
||||
&LastThread,
|
||||
sizeof(BOOLEAN),
|
||||
NULL);
|
||||
if (NT_SUCCESS(Status) && LastThread == TRUE)
|
||||
{
|
||||
ExitProcess(uExitCode);
|
||||
}
|
||||
|
||||
/* FIXME: notify csrss of thread termination */
|
||||
|
||||
LdrShutdownThread();
|
||||
|
||||
RtlRosExitUserThread(uExitCode);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
|
|
|
@ -312,22 +312,11 @@ MmCreateTeb(PEPROCESS Process,
|
|||
|
||||
/* Store stack information from InitialTeb */
|
||||
if(InitialTeb != NULL)
|
||||
{
|
||||
/* fixed-size stack */
|
||||
if(InitialTeb->PreviousStackBase && InitialTeb->PreviousStackLimit)
|
||||
{
|
||||
Teb->Tib.StackBase = InitialTeb->PreviousStackBase;
|
||||
Teb->Tib.StackLimit = InitialTeb->PreviousStackLimit;
|
||||
Teb->DeallocationStack = InitialTeb->PreviousStackLimit;
|
||||
}
|
||||
/* expandable stack */
|
||||
else
|
||||
{
|
||||
Teb->Tib.StackBase = InitialTeb->StackBase;
|
||||
Teb->Tib.StackLimit = InitialTeb->StackLimit;
|
||||
Teb->DeallocationStack = InitialTeb->AllocatedStackBase;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return TEB Address */
|
||||
DPRINT("Allocated: %x\n", Teb);
|
||||
|
|
Loading…
Reference in a new issue