Allocate the TEB and signal stack separately from the main stack.
Dynamically allocate the initial TEB too so that it is properly page-aligned.
This commit is contained in:
parent
bcb09c198d
commit
7924f421e9
|
@ -55,32 +55,22 @@ WINE_DECLARE_DEBUG_CHANNEL(relay);
|
||||||
*/
|
*/
|
||||||
TEB *THREAD_InitStack( TEB *teb, DWORD stack_size )
|
TEB *THREAD_InitStack( TEB *teb, DWORD stack_size )
|
||||||
{
|
{
|
||||||
DWORD old_prot, total_size;
|
DWORD old_prot;
|
||||||
DWORD page_size = getpagesize();
|
DWORD page_size = getpagesize();
|
||||||
void *base;
|
void *base;
|
||||||
|
|
||||||
/* Memory layout in allocated block:
|
|
||||||
*
|
|
||||||
* size contents
|
|
||||||
* SIGNAL_STACK_SIZE signal stack
|
|
||||||
* stack_size normal stack (including a PAGE_GUARD page at the bottom)
|
|
||||||
* 1 page TEB (except for initial thread)
|
|
||||||
*/
|
|
||||||
|
|
||||||
stack_size = (stack_size + (page_size - 1)) & ~(page_size - 1);
|
stack_size = (stack_size + (page_size - 1)) & ~(page_size - 1);
|
||||||
total_size = stack_size + SIGNAL_STACK_SIZE;
|
|
||||||
|
|
||||||
if (!(base = VirtualAlloc( NULL, total_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE )))
|
if (!(base = VirtualAlloc( NULL, stack_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE )))
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
teb->DeallocationStack = base;
|
teb->DeallocationStack = base;
|
||||||
teb->Tib.StackBase = (char *)base + SIGNAL_STACK_SIZE + stack_size;
|
teb->Tib.StackBase = (char *)base + stack_size;
|
||||||
teb->Tib.StackLimit = base; /* note: limit is lower than base since the stack grows down */
|
teb->Tib.StackLimit = base; /* note: limit is lower than base since the stack grows down */
|
||||||
|
|
||||||
/* Setup guard pages */
|
/* Setup guard pages */
|
||||||
|
|
||||||
VirtualProtect( (char *)base + SIGNAL_STACK_SIZE, 1,
|
VirtualProtect( base, 1, PAGE_EXECUTE_READWRITE | PAGE_GUARD, &old_prot );
|
||||||
PAGE_EXECUTE_READWRITE | PAGE_GUARD, &old_prot );
|
|
||||||
return teb;
|
return teb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1933,16 +1933,7 @@ void __wine_process_init( int argc, char *argv[] )
|
||||||
ANSI_STRING func_name;
|
ANSI_STRING func_name;
|
||||||
void (* DECLSPEC_NORETURN init_func)();
|
void (* DECLSPEC_NORETURN init_func)();
|
||||||
|
|
||||||
/* setup the server connection */
|
thread_init();
|
||||||
wine_server_init_process();
|
|
||||||
wine_server_init_thread();
|
|
||||||
|
|
||||||
/* create the process heap */
|
|
||||||
if (!(NtCurrentTeb()->Peb->ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL )))
|
|
||||||
{
|
|
||||||
MESSAGE( "wine: failed to create the process heap\n" );
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* setup the load callback and create ntdll modref */
|
/* setup the load callback and create ntdll modref */
|
||||||
wine_dll_set_callback( load_builtin_callback );
|
wine_dll_set_callback( load_builtin_callback );
|
||||||
|
|
|
@ -31,6 +31,13 @@
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "wine/server.h"
|
#include "wine/server.h"
|
||||||
|
|
||||||
|
/* The per-thread signal stack size */
|
||||||
|
#ifdef __i386__
|
||||||
|
#define SIGNAL_STACK_SIZE 4096
|
||||||
|
#else
|
||||||
|
#define SIGNAL_STACK_SIZE 0 /* we don't need a signal stack on non-i386 */
|
||||||
|
#endif
|
||||||
|
|
||||||
/* debug helper */
|
/* debug helper */
|
||||||
extern LPCSTR debugstr_us( const UNICODE_STRING *str );
|
extern LPCSTR debugstr_us( const UNICODE_STRING *str );
|
||||||
extern void dump_ObjectAttributes (const OBJECT_ATTRIBUTES *ObjectAttributes);
|
extern void dump_ObjectAttributes (const OBJECT_ATTRIBUTES *ObjectAttributes);
|
||||||
|
@ -38,7 +45,11 @@ extern void dump_ObjectAttributes (const OBJECT_ATTRIBUTES *ObjectAttributes);
|
||||||
extern void NTDLL_get_server_timeout( abs_time_t *when, const LARGE_INTEGER *timeout );
|
extern void NTDLL_get_server_timeout( abs_time_t *when, const LARGE_INTEGER *timeout );
|
||||||
extern NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handles, UINT flags,
|
extern NTSTATUS NTDLL_wait_for_multiple_objects( UINT count, const HANDLE *handles, UINT flags,
|
||||||
const LARGE_INTEGER *timeout );
|
const LARGE_INTEGER *timeout );
|
||||||
|
|
||||||
|
/* init routines */
|
||||||
extern void wine_server_init_process(void);
|
extern void wine_server_init_process(void);
|
||||||
|
extern void wine_server_init_thread(void);
|
||||||
|
extern void thread_init(void);
|
||||||
|
|
||||||
/* module handling */
|
/* module handling */
|
||||||
extern BOOL MODULE_GetSystemDirectory( UNICODE_STRING *sysdir );
|
extern BOOL MODULE_GetSystemDirectory( UNICODE_STRING *sysdir );
|
||||||
|
|
|
@ -466,7 +466,7 @@ static inline int get_error_code( const SIGCONTEXT *sigcontext )
|
||||||
*/
|
*/
|
||||||
static inline void *get_signal_stack(void)
|
static inline void *get_signal_stack(void)
|
||||||
{
|
{
|
||||||
return NtCurrentTeb()->DeallocationStack;
|
return (char *)NtCurrentTeb() + 4096;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -831,19 +831,20 @@ static EXCEPTION_RECORD *setup_exception( SIGCONTEXT *sigcontext, raise_func fun
|
||||||
SYSDEPS_AbortThread(1);
|
SYSDEPS_AbortThread(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit + SIGNAL_STACK_SIZE + 4096 ||
|
if ((char *)(stack - 1) < (char *)NtCurrentTeb()->Tib.StackLimit + 4096 ||
|
||||||
(char *)stack > (char *)NtCurrentTeb()->Tib.StackBase)
|
(char *)stack > (char *)NtCurrentTeb()->Tib.StackBase)
|
||||||
{
|
{
|
||||||
UINT diff = (char *)NtCurrentTeb()->Tib.StackLimit + SIGNAL_STACK_SIZE + 4096 - (char *)stack;
|
UINT diff = (char *)NtCurrentTeb()->Tib.StackLimit + 4096 - (char *)stack;
|
||||||
if (diff < 4096)
|
if (diff < 4096)
|
||||||
|
{
|
||||||
ERR( "stack overflow %u bytes in thread %04lx eip %08lx esp %08lx stack %p-%p\n",
|
ERR( "stack overflow %u bytes in thread %04lx eip %08lx esp %08lx stack %p-%p\n",
|
||||||
diff, GetCurrentThreadId(), EIP_sig(sigcontext), ESP_sig(sigcontext),
|
diff, GetCurrentThreadId(), EIP_sig(sigcontext), ESP_sig(sigcontext),
|
||||||
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
||||||
else
|
SYSDEPS_AbortThread(1);
|
||||||
ERR( "exception outside of stack limits in thread %04lx eip %08lx esp %08lx stack %p-%p\n",
|
}
|
||||||
|
else WARN( "exception outside of stack limits in thread %04lx eip %08lx esp %08lx stack %p-%p\n",
|
||||||
GetCurrentThreadId(), EIP_sig(sigcontext), ESP_sig(sigcontext),
|
GetCurrentThreadId(), EIP_sig(sigcontext), ESP_sig(sigcontext),
|
||||||
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
NtCurrentTeb()->Tib.StackLimit, NtCurrentTeb()->Tib.StackBase );
|
||||||
SYSDEPS_AbortThread(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
stack--; /* push the stack_layout structure */
|
stack--; /* push the stack_layout structure */
|
||||||
|
|
|
@ -58,7 +58,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(thread);
|
||||||
struct thread_cleanup_info
|
struct thread_cleanup_info
|
||||||
{
|
{
|
||||||
void *stack_base;
|
void *stack_base;
|
||||||
int stack_size;
|
ULONG stack_size;
|
||||||
|
void *teb_base;
|
||||||
|
ULONG teb_size;
|
||||||
int status;
|
int status;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -126,6 +128,7 @@ static void cleanup_thread( void *ptr )
|
||||||
/* copy the info structure since it is on the stack we will free */
|
/* copy the info structure since it is on the stack we will free */
|
||||||
struct thread_cleanup_info info = *(struct thread_cleanup_info *)ptr;
|
struct thread_cleanup_info info = *(struct thread_cleanup_info *)ptr;
|
||||||
munmap( info.stack_base, info.stack_size );
|
munmap( info.stack_base, info.stack_size );
|
||||||
|
munmap( info.teb_base, info.teb_size );
|
||||||
wine_ldt_free_fs( wine_get_fs() );
|
wine_ldt_free_fs( wine_get_fs() );
|
||||||
#ifdef HAVE__LWP_CREATE
|
#ifdef HAVE__LWP_CREATE
|
||||||
_lwp_exit();
|
_lwp_exit();
|
||||||
|
@ -196,15 +199,13 @@ int SYSDEPS_SpawnThread( void (*func)(TEB *), TEB *teb )
|
||||||
*/
|
*/
|
||||||
void SYSDEPS_ExitThread( int status )
|
void SYSDEPS_ExitThread( int status )
|
||||||
{
|
{
|
||||||
TEB *teb = NtCurrentTeb();
|
|
||||||
DWORD size = 0;
|
|
||||||
|
|
||||||
#ifdef HAVE_NPTL
|
#ifdef HAVE_NPTL
|
||||||
static TEB *teb_to_free;
|
static TEB *teb_to_free;
|
||||||
TEB *free_teb;
|
TEB *free_teb;
|
||||||
|
|
||||||
if ((free_teb = interlocked_xchg_ptr( (void **)&teb_to_free, teb )) != NULL)
|
if ((free_teb = interlocked_xchg_ptr( (void **)&teb_to_free, NtCurrentTeb() )) != NULL)
|
||||||
{
|
{
|
||||||
|
DWORD size = 0;
|
||||||
void *ptr;
|
void *ptr;
|
||||||
|
|
||||||
TRACE("freeing prev teb %p stack %p fs %04x\n",
|
TRACE("freeing prev teb %p stack %p fs %04x\n",
|
||||||
|
@ -214,26 +215,28 @@ void SYSDEPS_ExitThread( int status )
|
||||||
wine_ldt_free_fs( free_teb->teb_sel );
|
wine_ldt_free_fs( free_teb->teb_sel );
|
||||||
ptr = free_teb->DeallocationStack;
|
ptr = free_teb->DeallocationStack;
|
||||||
NtFreeVirtualMemory( GetCurrentProcess(), &ptr, &size, MEM_RELEASE );
|
NtFreeVirtualMemory( GetCurrentProcess(), &ptr, &size, MEM_RELEASE );
|
||||||
|
ptr = free_teb;
|
||||||
|
NtFreeVirtualMemory( GetCurrentProcess(), &ptr, &size, MEM_RELEASE | MEM_SYSTEM );
|
||||||
|
munmap( ptr, size );
|
||||||
}
|
}
|
||||||
SYSDEPS_AbortThread( status );
|
SYSDEPS_AbortThread( status );
|
||||||
#else
|
#else
|
||||||
struct thread_cleanup_info info;
|
struct thread_cleanup_info info;
|
||||||
MEMORY_BASIC_INFORMATION meminfo;
|
|
||||||
|
|
||||||
NtQueryVirtualMemory( GetCurrentProcess(), teb->Tib.StackBase, MemoryBasicInformation,
|
|
||||||
&meminfo, sizeof(meminfo), NULL );
|
|
||||||
info.stack_base = meminfo.AllocationBase;
|
|
||||||
info.stack_size = meminfo.RegionSize + ((char *)teb->Tib.StackBase - (char *)meminfo.AllocationBase);
|
|
||||||
info.status = status;
|
|
||||||
|
|
||||||
SIGNAL_Block();
|
SIGNAL_Block();
|
||||||
size = 0;
|
info.status = status;
|
||||||
NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE | MEM_SYSTEM );
|
info.stack_base = NtCurrentTeb()->DeallocationStack;
|
||||||
close( teb->wait_fd[0] );
|
info.stack_size = 0;
|
||||||
close( teb->wait_fd[1] );
|
NtFreeVirtualMemory( GetCurrentProcess(), &info.stack_base,
|
||||||
close( teb->reply_fd );
|
&info.stack_size, MEM_RELEASE | MEM_SYSTEM );
|
||||||
close( teb->request_fd );
|
info.teb_base = NtCurrentTeb();
|
||||||
SIGNAL_Reset();
|
info.teb_size = 0;
|
||||||
|
NtFreeVirtualMemory( GetCurrentProcess(), &info.teb_base,
|
||||||
|
&info.teb_size, MEM_RELEASE | MEM_SYSTEM );
|
||||||
|
close( NtCurrentTeb()->wait_fd[0] );
|
||||||
|
close( NtCurrentTeb()->wait_fd[1] );
|
||||||
|
close( NtCurrentTeb()->reply_fd );
|
||||||
|
close( NtCurrentTeb()->request_fd );
|
||||||
wine_switch_to_stack( cleanup_thread, &info, get_temp_stack() );
|
wine_switch_to_stack( cleanup_thread, &info, get_temp_stack() );
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,15 +21,68 @@
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
#include "wine/port.h"
|
#include "wine/port.h"
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#ifdef HAVE_SYS_MMAN_H
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#include "ntstatus.h"
|
#include "ntstatus.h"
|
||||||
#include "thread.h"
|
#include "thread.h"
|
||||||
#include "winternl.h"
|
#include "winternl.h"
|
||||||
#include "wine/library.h"
|
#include "wine/library.h"
|
||||||
#include "wine/server.h"
|
#include "wine/server.h"
|
||||||
#include "wine/debug.h"
|
#include "wine/debug.h"
|
||||||
|
#include "ntdll_misc.h"
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(thread);
|
WINE_DEFAULT_DEBUG_CHANNEL(thread);
|
||||||
|
|
||||||
|
static PEB peb;
|
||||||
|
static PEB_LDR_DATA ldr;
|
||||||
|
static RTL_USER_PROCESS_PARAMETERS params; /* default parameters if no parent */
|
||||||
|
static RTL_BITMAP tls_bitmap;
|
||||||
|
static LIST_ENTRY tls_links;
|
||||||
|
static struct debug_info info; /* debug info for initial thread */
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* alloc_teb
|
||||||
|
*/
|
||||||
|
static TEB *alloc_teb( ULONG *size )
|
||||||
|
{
|
||||||
|
TEB *teb;
|
||||||
|
|
||||||
|
*size = SIGNAL_STACK_SIZE + sizeof(TEB);
|
||||||
|
teb = wine_anon_mmap( NULL, *size, PROT_READ | PROT_WRITE | PROT_EXEC, 0 );
|
||||||
|
if (teb == (TEB *)-1) return NULL;
|
||||||
|
if (!(teb->teb_sel = wine_ldt_alloc_fs()))
|
||||||
|
{
|
||||||
|
munmap( teb, *size );
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
teb->Tib.ExceptionList = (void *)~0UL;
|
||||||
|
teb->Tib.Self = &teb->Tib;
|
||||||
|
teb->Peb = &peb;
|
||||||
|
teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer;
|
||||||
|
teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
|
||||||
|
return teb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* free_teb
|
||||||
|
*/
|
||||||
|
static inline void free_teb( TEB *teb )
|
||||||
|
{
|
||||||
|
ULONG size = 0;
|
||||||
|
void *addr = teb;
|
||||||
|
|
||||||
|
if (teb->DeallocationStack)
|
||||||
|
NtFreeVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size, MEM_RELEASE );
|
||||||
|
NtFreeVirtualMemory( GetCurrentProcess(), &addr, &size, MEM_RELEASE );
|
||||||
|
wine_ldt_free_fs( teb->teb_sel );
|
||||||
|
munmap( teb, SIGNAL_STACK_SIZE + sizeof(TEB) );
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* thread_init
|
* thread_init
|
||||||
|
@ -38,35 +91,15 @@ WINE_DEFAULT_DEBUG_CHANNEL(thread);
|
||||||
*
|
*
|
||||||
* NOTES: The first allocated TEB on NT is at 0x7ffde000.
|
* NOTES: The first allocated TEB on NT is at 0x7ffde000.
|
||||||
*/
|
*/
|
||||||
DECL_GLOBAL_CONSTRUCTOR(thread_init)
|
void thread_init(void)
|
||||||
{
|
{
|
||||||
static TEB teb;
|
TEB *teb;
|
||||||
static PEB peb;
|
void *addr;
|
||||||
static PEB_LDR_DATA ldr;
|
ULONG size;
|
||||||
static RTL_USER_PROCESS_PARAMETERS params; /* default parameters if no parent */
|
|
||||||
static RTL_BITMAP tls_bitmap;
|
|
||||||
static struct debug_info info; /* debug info for initial thread */
|
|
||||||
|
|
||||||
if (teb.Tib.Self) return; /* do it only once */
|
|
||||||
|
|
||||||
info.str_pos = info.strings;
|
info.str_pos = info.strings;
|
||||||
info.out_pos = info.output;
|
info.out_pos = info.output;
|
||||||
|
|
||||||
teb.Tib.ExceptionList = (void *)~0UL;
|
|
||||||
teb.Tib.StackBase = (void *)~0UL;
|
|
||||||
teb.Tib.Self = &teb.Tib;
|
|
||||||
teb.Peb = &peb;
|
|
||||||
teb.tibflags = TEBF_WIN32;
|
|
||||||
teb.request_fd = -1;
|
|
||||||
teb.reply_fd = -1;
|
|
||||||
teb.wait_fd[0] = -1;
|
|
||||||
teb.wait_fd[1] = -1;
|
|
||||||
teb.teb_sel = wine_ldt_alloc_fs();
|
|
||||||
teb.debug_info = &info;
|
|
||||||
teb.StaticUnicodeString.MaximumLength = sizeof(teb.StaticUnicodeBuffer);
|
|
||||||
teb.StaticUnicodeString.Buffer = teb.StaticUnicodeBuffer;
|
|
||||||
InitializeListHead( &teb.TlsLinks );
|
|
||||||
|
|
||||||
peb.ProcessParameters = ¶ms;
|
peb.ProcessParameters = ¶ms;
|
||||||
peb.TlsBitmap = &tls_bitmap;
|
peb.TlsBitmap = &tls_bitmap;
|
||||||
peb.LdrData = &ldr;
|
peb.LdrData = &ldr;
|
||||||
|
@ -74,12 +107,42 @@ DECL_GLOBAL_CONSTRUCTOR(thread_init)
|
||||||
InitializeListHead( &ldr.InLoadOrderModuleList );
|
InitializeListHead( &ldr.InLoadOrderModuleList );
|
||||||
InitializeListHead( &ldr.InMemoryOrderModuleList );
|
InitializeListHead( &ldr.InMemoryOrderModuleList );
|
||||||
InitializeListHead( &ldr.InInitializationOrderModuleList );
|
InitializeListHead( &ldr.InInitializationOrderModuleList );
|
||||||
|
InitializeListHead( &tls_links );
|
||||||
|
|
||||||
SYSDEPS_SetCurThread( &teb );
|
teb = alloc_teb( &size );
|
||||||
|
teb->Tib.StackBase = (void *)~0UL;
|
||||||
|
teb->tibflags = TEBF_WIN32;
|
||||||
|
teb->request_fd = -1;
|
||||||
|
teb->reply_fd = -1;
|
||||||
|
teb->wait_fd[0] = -1;
|
||||||
|
teb->wait_fd[1] = -1;
|
||||||
|
teb->debug_info = &info;
|
||||||
|
InsertHeadList( &tls_links, &teb->TlsLinks );
|
||||||
|
|
||||||
|
SYSDEPS_SetCurThread( teb );
|
||||||
|
|
||||||
|
/* setup the server connection */
|
||||||
|
wine_server_init_process();
|
||||||
|
wine_server_init_thread();
|
||||||
|
|
||||||
|
/* create a memory view for the TEB */
|
||||||
|
NtAllocateVirtualMemory( GetCurrentProcess(), &addr, teb, &size,
|
||||||
|
MEM_SYSTEM, PAGE_EXECUTE_READWRITE );
|
||||||
|
|
||||||
|
/* create the process heap */
|
||||||
|
if (!(peb.ProcessHeap = RtlCreateHeap( HEAP_GROWABLE, NULL, 0, 0, NULL, NULL )))
|
||||||
|
{
|
||||||
|
MESSAGE( "wine: failed to create the process heap\n" );
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* startup routine for a newly created thread */
|
/***********************************************************************
|
||||||
|
* start_thread
|
||||||
|
*
|
||||||
|
* Startup routine for a newly created thread.
|
||||||
|
*/
|
||||||
static void start_thread( TEB *teb )
|
static void start_thread( TEB *teb )
|
||||||
{
|
{
|
||||||
LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)teb->entry_point;
|
LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)teb->entry_point;
|
||||||
|
@ -93,6 +156,10 @@ static void start_thread( TEB *teb )
|
||||||
SIGNAL_Init();
|
SIGNAL_Init();
|
||||||
wine_server_init_thread();
|
wine_server_init_thread();
|
||||||
|
|
||||||
|
RtlAcquirePebLock();
|
||||||
|
InsertHeadList( &tls_links, &teb->TlsLinks );
|
||||||
|
RtlReleasePebLock();
|
||||||
|
|
||||||
NtTerminateThread( GetCurrentThread(), func( NtCurrentTeb()->entry_arg ) );
|
NtTerminateThread( GetCurrentThread(), func( NtCurrentTeb()->entry_arg ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -107,11 +174,10 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *
|
||||||
HANDLE *handle_ptr, CLIENT_ID *id )
|
HANDLE *handle_ptr, CLIENT_ID *id )
|
||||||
{
|
{
|
||||||
HANDLE handle = 0;
|
HANDLE handle = 0;
|
||||||
TEB *teb;
|
TEB *teb = NULL;
|
||||||
DWORD tid = 0;
|
DWORD tid = 0;
|
||||||
SIZE_T total_size;
|
ULONG size;
|
||||||
SIZE_T page_size = getpagesize();
|
void *base;
|
||||||
void *ptr, *base = NULL;
|
|
||||||
int request_pipe[2];
|
int request_pipe[2];
|
||||||
NTSTATUS status;
|
NTSTATUS status;
|
||||||
|
|
||||||
|
@ -135,49 +201,13 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *
|
||||||
|
|
||||||
if (status) goto error;
|
if (status) goto error;
|
||||||
|
|
||||||
if (!stack_reserve || !stack_commit)
|
if (!(teb = alloc_teb( &size )))
|
||||||
{
|
{
|
||||||
IMAGE_NT_HEADERS *nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress );
|
status = STATUS_NO_MEMORY;
|
||||||
if (!stack_reserve) stack_reserve = nt->OptionalHeader.SizeOfStackReserve;
|
|
||||||
if (!stack_commit) stack_commit = nt->OptionalHeader.SizeOfStackCommit;
|
|
||||||
}
|
|
||||||
if (stack_reserve < stack_commit) stack_reserve = stack_commit;
|
|
||||||
stack_reserve = (stack_reserve + 0xffff) & ~0xffff; /* round to 64K boundary */
|
|
||||||
|
|
||||||
/* Memory layout in allocated block:
|
|
||||||
*
|
|
||||||
* size contents
|
|
||||||
* SIGNAL_STACK_SIZE signal stack
|
|
||||||
* stack_size normal stack (including a PAGE_GUARD page at the bottom)
|
|
||||||
* 1 page TEB (except for initial thread)
|
|
||||||
*/
|
|
||||||
|
|
||||||
total_size = stack_reserve + SIGNAL_STACK_SIZE + page_size;
|
|
||||||
if ((status = NtAllocateVirtualMemory( GetCurrentProcess(), &base, NULL, &total_size,
|
|
||||||
MEM_COMMIT, PAGE_EXECUTE_READWRITE )) != STATUS_SUCCESS)
|
|
||||||
goto error;
|
|
||||||
|
|
||||||
teb = (TEB *)((char *)base + total_size - page_size);
|
|
||||||
|
|
||||||
if (!(teb->teb_sel = wine_ldt_alloc_fs()))
|
|
||||||
{
|
|
||||||
status = STATUS_TOO_MANY_THREADS;
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
teb->Tib.ExceptionList = (void *)~0UL;
|
|
||||||
teb->Tib.StackBase = (char *)base + SIGNAL_STACK_SIZE + stack_reserve;
|
|
||||||
teb->Tib.StackLimit = base; /* limit is lower than base since the stack grows down */
|
|
||||||
teb->Tib.Self = &teb->Tib;
|
|
||||||
teb->ClientId.UniqueProcess = (HANDLE)GetCurrentProcessId();
|
teb->ClientId.UniqueProcess = (HANDLE)GetCurrentProcessId();
|
||||||
teb->ClientId.UniqueThread = (HANDLE)tid;
|
teb->ClientId.UniqueThread = (HANDLE)tid;
|
||||||
teb->Peb = NtCurrentTeb()->Peb;
|
|
||||||
teb->DeallocationStack = base;
|
|
||||||
teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer;
|
|
||||||
teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
|
|
||||||
RtlAcquirePebLock();
|
|
||||||
InsertHeadList( &NtCurrentTeb()->TlsLinks, &teb->TlsLinks );
|
|
||||||
RtlReleasePebLock();
|
|
||||||
|
|
||||||
teb->tibflags = TEBF_WIN32;
|
teb->tibflags = TEBF_WIN32;
|
||||||
teb->exit_code = STILL_ACTIVE;
|
teb->exit_code = STILL_ACTIVE;
|
||||||
|
@ -189,17 +219,33 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *
|
||||||
teb->entry_arg = param;
|
teb->entry_arg = param;
|
||||||
teb->htask16 = NtCurrentTeb()->htask16;
|
teb->htask16 = NtCurrentTeb()->htask16;
|
||||||
|
|
||||||
|
NtAllocateVirtualMemory( GetCurrentProcess(), &base, teb, &size,
|
||||||
|
MEM_SYSTEM, PAGE_EXECUTE_READWRITE );
|
||||||
|
|
||||||
|
if (!stack_reserve || !stack_commit)
|
||||||
|
{
|
||||||
|
IMAGE_NT_HEADERS *nt = RtlImageNtHeader( NtCurrentTeb()->Peb->ImageBaseAddress );
|
||||||
|
if (!stack_reserve) stack_reserve = nt->OptionalHeader.SizeOfStackReserve;
|
||||||
|
if (!stack_commit) stack_commit = nt->OptionalHeader.SizeOfStackCommit;
|
||||||
|
}
|
||||||
|
if (stack_reserve < stack_commit) stack_reserve = stack_commit;
|
||||||
|
stack_reserve = (stack_reserve + 0xffff) & ~0xffff; /* round to 64K boundary */
|
||||||
|
|
||||||
|
status = NtAllocateVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, NULL,
|
||||||
|
&stack_reserve, MEM_COMMIT, PAGE_EXECUTE_READWRITE );
|
||||||
|
if (status != STATUS_SUCCESS) goto error;
|
||||||
|
|
||||||
|
/* limit is lower than base since the stack grows down */
|
||||||
|
teb->Tib.StackBase = (char *)teb->DeallocationStack + stack_reserve;
|
||||||
|
teb->Tib.StackLimit = teb->DeallocationStack;
|
||||||
|
|
||||||
/* setup the guard page */
|
/* setup the guard page */
|
||||||
ptr = (char *)base + SIGNAL_STACK_SIZE;
|
size = 1;
|
||||||
NtProtectVirtualMemory( GetCurrentProcess(), &ptr, &page_size,
|
NtProtectVirtualMemory( GetCurrentProcess(), &teb->DeallocationStack, &size,
|
||||||
PAGE_EXECUTE_READWRITE | PAGE_GUARD, NULL );
|
PAGE_EXECUTE_READWRITE | PAGE_GUARD, NULL );
|
||||||
|
|
||||||
if (SYSDEPS_SpawnThread( start_thread, teb ) == -1)
|
if (SYSDEPS_SpawnThread( start_thread, teb ) == -1)
|
||||||
{
|
{
|
||||||
RtlAcquirePebLock();
|
|
||||||
RemoveEntryList( &teb->TlsLinks );
|
|
||||||
RtlReleasePebLock();
|
|
||||||
wine_ldt_free_fs( teb->teb_sel );
|
|
||||||
status = STATUS_TOO_MANY_THREADS;
|
status = STATUS_TOO_MANY_THREADS;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
@ -211,11 +257,7 @@ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, const SECURITY_DESCRIPTOR *
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
if (base)
|
if (teb) free_teb( teb );
|
||||||
{
|
|
||||||
total_size = 0;
|
|
||||||
NtFreeVirtualMemory( GetCurrentProcess(), &base, &total_size, MEM_RELEASE );
|
|
||||||
}
|
|
||||||
if (handle) NtClose( handle );
|
if (handle) NtClose( handle );
|
||||||
close( request_pipe[1] );
|
close( request_pipe[1] );
|
||||||
return status;
|
return status;
|
||||||
|
@ -444,19 +486,18 @@ NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
|
||||||
case ThreadZeroTlsCell:
|
case ThreadZeroTlsCell:
|
||||||
if (handle == GetCurrentThread())
|
if (handle == GetCurrentThread())
|
||||||
{
|
{
|
||||||
LIST_ENTRY *entry = &NtCurrentTeb()->TlsLinks;
|
LIST_ENTRY *entry;
|
||||||
DWORD index;
|
DWORD index;
|
||||||
|
|
||||||
if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
|
if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
|
||||||
index = *(DWORD *)data;
|
index = *(DWORD *)data;
|
||||||
if (index >= 64) return STATUS_INVALID_PARAMETER;
|
if (index >= 64) return STATUS_INVALID_PARAMETER;
|
||||||
RtlAcquirePebLock();
|
RtlAcquirePebLock();
|
||||||
do
|
for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
|
||||||
{
|
{
|
||||||
TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
|
TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
|
||||||
teb->TlsSlots[index] = 0;
|
teb->TlsSlots[index] = 0;
|
||||||
entry = entry->Flink;
|
}
|
||||||
} while (entry != &NtCurrentTeb()->TlsLinks);
|
|
||||||
RtlReleasePebLock();
|
RtlReleasePebLock();
|
||||||
return STATUS_SUCCESS;
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -834,7 +834,7 @@ DWORD VIRTUAL_HandleFault( LPCVOID addr )
|
||||||
{
|
{
|
||||||
BYTE vprot = view->prot[((char *)addr - (char *)view->base) >> page_shift];
|
BYTE vprot = view->prot[((char *)addr - (char *)view->base) >> page_shift];
|
||||||
void *page = (void *)((UINT_PTR)addr & ~page_mask);
|
void *page = (void *)((UINT_PTR)addr & ~page_mask);
|
||||||
char *stack = (char *)NtCurrentTeb()->DeallocationStack + SIGNAL_STACK_SIZE;
|
char *stack = NtCurrentTeb()->Tib.StackLimit;
|
||||||
if (vprot & VPROT_GUARD)
|
if (vprot & VPROT_GUARD)
|
||||||
{
|
{
|
||||||
VIRTUAL_SetProt( view, page, page_mask + 1, vprot & ~VPROT_GUARD );
|
VIRTUAL_SetProt( view, page, page_mask + 1, vprot & ~VPROT_GUARD );
|
||||||
|
@ -1101,8 +1101,12 @@ NTSTATUS WINAPI NtFreeVirtualMemory( HANDLE process, PVOID *addr_ptr, ULONG *siz
|
||||||
|
|
||||||
if (type & MEM_SYSTEM)
|
if (type & MEM_SYSTEM)
|
||||||
{
|
{
|
||||||
|
/* return the values that the caller should use to unmap the area */
|
||||||
|
*addr_ptr = view->base;
|
||||||
|
*size_ptr = view->size;
|
||||||
view->flags |= VFLAG_SYSTEM;
|
view->flags |= VFLAG_SYSTEM;
|
||||||
type &= ~MEM_SYSTEM;
|
VIRTUAL_DeleteView( view );
|
||||||
|
return STATUS_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((type != MEM_DECOMMIT) && (type != MEM_RELEASE))
|
if ((type != MEM_DECOMMIT) && (type != MEM_RELEASE))
|
||||||
|
|
|
@ -140,14 +140,6 @@ typedef struct _TEB
|
||||||
#define TEBF_WIN32 0x0001
|
#define TEBF_WIN32 0x0001
|
||||||
#define TEBF_TRAP 0x0002
|
#define TEBF_TRAP 0x0002
|
||||||
|
|
||||||
/* The per-thread signal stack size */
|
|
||||||
#ifdef __i386__
|
|
||||||
#define SIGNAL_STACK_SIZE 0x100000 /* 1Mb FIXME: should be much smaller than that */
|
|
||||||
#else
|
|
||||||
#define SIGNAL_STACK_SIZE 0 /* we don't need a signal stack on non-i386 */
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* scheduler/thread.c */
|
/* scheduler/thread.c */
|
||||||
extern TEB *THREAD_InitStack( TEB *teb, DWORD stack_size );
|
extern TEB *THREAD_InitStack( TEB *teb, DWORD stack_size );
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,6 @@ extern void wine_server_send_fd( int fd );
|
||||||
extern int wine_server_fd_to_handle( int fd, unsigned int access, int inherit, obj_handle_t *handle );
|
extern int wine_server_fd_to_handle( int fd, unsigned int access, int inherit, obj_handle_t *handle );
|
||||||
extern int wine_server_handle_to_fd( obj_handle_t handle, unsigned int access, int *unix_fd,
|
extern int wine_server_handle_to_fd( obj_handle_t handle, unsigned int access, int *unix_fd,
|
||||||
enum fd_type *type, int *flags );
|
enum fd_type *type, int *flags );
|
||||||
extern void wine_server_init_thread(void);
|
|
||||||
|
|
||||||
/* do a server call and set the last error code */
|
/* do a server call and set the last error code */
|
||||||
inline static unsigned int wine_server_call_err( void *req_ptr )
|
inline static unsigned int wine_server_call_err( void *req_ptr )
|
||||||
|
|
Loading…
Reference in New Issue