Moved almost all remaining process, thread, fiber and exception
functions to dlls/kernel.
This commit is contained in:
parent
1479aebda3
commit
aaf3503ea5
|
@ -1,4 +1,4 @@
|
|||
EXTRADEFS = -D_KERNEL32_
|
||||
EXTRADEFS = -D_KERNEL32_ -DBINDIR="\"$(bindir)\""
|
||||
TOPSRCDIR = @top_srcdir@
|
||||
TOPOBJDIR = ../..
|
||||
SRCDIR = @srcdir@
|
||||
|
@ -27,6 +27,8 @@ C_SRCS = \
|
|||
console.c \
|
||||
debugger.c \
|
||||
editline.c \
|
||||
except.c \
|
||||
fiber.c \
|
||||
file.c \
|
||||
file16.c \
|
||||
format_msg.c \
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -37,11 +37,346 @@
|
|||
#include "winbase.h"
|
||||
#include "winerror.h"
|
||||
#include "winnls.h"
|
||||
#include "module.h"
|
||||
#include "thread.h"
|
||||
#include "wine/winbase16.h"
|
||||
#include "wine/library.h"
|
||||
#include "wine/server.h"
|
||||
#include "wine/debug.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(thread);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(relay);
|
||||
|
||||
|
||||
/* TEB of the initial thread */
|
||||
static TEB initial_teb;
|
||||
extern struct _PDB current_process;
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* THREAD_InitTEB
|
||||
*
|
||||
* Initialization of a newly created TEB.
|
||||
*/
|
||||
static BOOL THREAD_InitTEB( TEB *teb )
|
||||
{
|
||||
teb->Tib.ExceptionList = (void *)~0UL;
|
||||
teb->Tib.StackBase = (void *)~0UL;
|
||||
teb->Tib.Self = &teb->Tib;
|
||||
teb->tibflags = TEBF_WIN32;
|
||||
teb->exit_code = STILL_ACTIVE;
|
||||
teb->request_fd = -1;
|
||||
teb->reply_fd = -1;
|
||||
teb->wait_fd[0] = -1;
|
||||
teb->wait_fd[1] = -1;
|
||||
teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
|
||||
teb->StaticUnicodeString.Buffer = (PWSTR)teb->StaticUnicodeBuffer;
|
||||
InitializeListHead(&teb->TlsLinks);
|
||||
teb->teb_sel = wine_ldt_alloc_fs();
|
||||
return (teb->teb_sel != 0);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* THREAD_InitStack
|
||||
*
|
||||
* Allocate the stack of a thread.
|
||||
*/
|
||||
TEB *THREAD_InitStack( TEB *teb, DWORD stack_size )
|
||||
{
|
||||
DWORD old_prot, total_size;
|
||||
DWORD page_size = getpagesize();
|
||||
void *base;
|
||||
|
||||
/* Allocate the stack */
|
||||
|
||||
/* if size is smaller than default, get stack size from parent */
|
||||
if (stack_size < 1024 * 1024)
|
||||
{
|
||||
if (teb)
|
||||
stack_size = 1024 * 1024; /* no parent */
|
||||
else
|
||||
stack_size = ((char *)NtCurrentTeb()->Tib.StackBase
|
||||
- (char *)NtCurrentTeb()->DeallocationStack
|
||||
- SIGNAL_STACK_SIZE - 3 * page_size);
|
||||
}
|
||||
|
||||
/* FIXME: some Wine functions use a lot of stack, so we add 64Kb here */
|
||||
stack_size += 64 * 1024;
|
||||
|
||||
/* Memory layout in allocated block:
|
||||
*
|
||||
* size contents
|
||||
* 1 page NOACCESS guard page
|
||||
* SIGNAL_STACK_SIZE signal stack
|
||||
* 1 page NOACCESS guard page
|
||||
* 1 page PAGE_GUARD guard page
|
||||
* stack_size normal stack
|
||||
* 1 page TEB (except for initial thread)
|
||||
*/
|
||||
|
||||
stack_size = (stack_size + (page_size - 1)) & ~(page_size - 1);
|
||||
total_size = stack_size + SIGNAL_STACK_SIZE + 3 * page_size;
|
||||
if (!teb) total_size += page_size;
|
||||
|
||||
if (!(base = VirtualAlloc( NULL, total_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE )))
|
||||
return NULL;
|
||||
|
||||
if (!teb)
|
||||
{
|
||||
teb = (TEB *)((char *)base + total_size - page_size);
|
||||
if (!THREAD_InitTEB( teb ))
|
||||
{
|
||||
VirtualFree( base, 0, MEM_RELEASE );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
teb->DeallocationStack = base;
|
||||
teb->signal_stack = (char *)base + page_size;
|
||||
teb->Tib.StackBase = (char *)base + 3 * page_size + SIGNAL_STACK_SIZE + stack_size;
|
||||
teb->Tib.StackLimit = base; /* note: limit is lower than base since the stack grows down */
|
||||
|
||||
/* Setup guard pages */
|
||||
|
||||
VirtualProtect( base, 1, PAGE_NOACCESS, &old_prot );
|
||||
VirtualProtect( (char *)teb->signal_stack + SIGNAL_STACK_SIZE, 1, PAGE_NOACCESS, &old_prot );
|
||||
VirtualProtect( (char *)teb->signal_stack + SIGNAL_STACK_SIZE + page_size, 1,
|
||||
PAGE_EXECUTE_READWRITE | PAGE_GUARD, &old_prot );
|
||||
return teb;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* THREAD_Init
|
||||
*
|
||||
* Setup the initial thread.
|
||||
*
|
||||
* NOTES: The first allocated TEB on NT is at 0x7ffde000.
|
||||
*/
|
||||
void THREAD_Init(void)
|
||||
{
|
||||
static struct debug_info info; /* debug info for initial thread */
|
||||
|
||||
if (!initial_teb.Tib.Self) /* do it only once */
|
||||
{
|
||||
THREAD_InitTEB( &initial_teb );
|
||||
assert( initial_teb.teb_sel );
|
||||
info.str_pos = info.strings;
|
||||
info.out_pos = info.output;
|
||||
initial_teb.debug_info = &info;
|
||||
initial_teb.Peb = (PEB *)¤t_process; /* FIXME */
|
||||
SYSDEPS_SetCurThread( &initial_teb );
|
||||
}
|
||||
}
|
||||
|
||||
DECL_GLOBAL_CONSTRUCTOR(thread_init) { THREAD_Init(); }
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* THREAD_Start
|
||||
*
|
||||
* Start execution of a newly created thread. Does not return.
|
||||
*/
|
||||
static void THREAD_Start( TEB *teb )
|
||||
{
|
||||
LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)teb->entry_point;
|
||||
struct debug_info info;
|
||||
|
||||
info.str_pos = info.strings;
|
||||
info.out_pos = info.output;
|
||||
teb->debug_info = &info;
|
||||
|
||||
SYSDEPS_SetCurThread( teb );
|
||||
SIGNAL_Init();
|
||||
CLIENT_InitThread();
|
||||
|
||||
if (TRACE_ON(relay))
|
||||
DPRINTF("%04lx:Starting thread (entryproc=%p)\n", GetCurrentThreadId(), func );
|
||||
|
||||
__TRY
|
||||
{
|
||||
MODULE_DllThreadAttach( NULL );
|
||||
ExitThread( func( NtCurrentTeb()->entry_arg ) );
|
||||
}
|
||||
__EXCEPT(UnhandledExceptionFilter)
|
||||
{
|
||||
TerminateThread( GetCurrentThread(), GetExceptionCode() );
|
||||
}
|
||||
__ENDTRY
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* CreateThread (KERNEL32.@)
|
||||
*/
|
||||
HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, SIZE_T stack,
|
||||
LPTHREAD_START_ROUTINE start, LPVOID param,
|
||||
DWORD flags, LPDWORD id )
|
||||
{
|
||||
HANDLE handle = 0;
|
||||
TEB *teb;
|
||||
DWORD tid = 0;
|
||||
int request_pipe[2];
|
||||
|
||||
if (pipe( request_pipe ) == -1)
|
||||
{
|
||||
SetLastError( ERROR_TOO_MANY_OPEN_FILES );
|
||||
return 0;
|
||||
}
|
||||
fcntl( request_pipe[1], F_SETFD, 1 ); /* set close on exec flag */
|
||||
wine_server_send_fd( request_pipe[0] );
|
||||
|
||||
SERVER_START_REQ( new_thread )
|
||||
{
|
||||
req->suspend = ((flags & CREATE_SUSPENDED) != 0);
|
||||
req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
|
||||
req->request_fd = request_pipe[0];
|
||||
if (!wine_server_call_err( req ))
|
||||
{
|
||||
handle = reply->handle;
|
||||
tid = reply->tid;
|
||||
}
|
||||
close( request_pipe[0] );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
if (!handle || !(teb = THREAD_InitStack( NULL, stack )))
|
||||
{
|
||||
close( request_pipe[1] );
|
||||
return 0;
|
||||
}
|
||||
|
||||
teb->Peb = NtCurrentTeb()->Peb;
|
||||
teb->ClientId.UniqueThread = (HANDLE)tid;
|
||||
teb->request_fd = request_pipe[1];
|
||||
teb->entry_point = start;
|
||||
teb->entry_arg = param;
|
||||
teb->htask16 = GetCurrentTask();
|
||||
RtlAcquirePebLock();
|
||||
InsertHeadList( &NtCurrentTeb()->TlsLinks, &teb->TlsLinks );
|
||||
RtlReleasePebLock();
|
||||
|
||||
if (id) *id = tid;
|
||||
if (SYSDEPS_SpawnThread( THREAD_Start, teb ) == -1)
|
||||
{
|
||||
CloseHandle( handle );
|
||||
close( request_pipe[1] );
|
||||
RtlAcquirePebLock();
|
||||
RemoveEntryList( &teb->TlsLinks );
|
||||
RtlReleasePebLock();
|
||||
wine_ldt_free_fs( teb->teb_sel );
|
||||
VirtualFree( teb->DeallocationStack, 0, MEM_RELEASE );
|
||||
return 0;
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* OpenThread [KERNEL32.@] Retrieves a handle to a thread from its thread id
|
||||
*/
|
||||
HANDLE WINAPI OpenThread( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId )
|
||||
{
|
||||
HANDLE ret = 0;
|
||||
SERVER_START_REQ( open_thread )
|
||||
{
|
||||
req->tid = dwThreadId;
|
||||
req->access = dwDesiredAccess;
|
||||
req->inherit = bInheritHandle;
|
||||
if (!wine_server_call_err( req )) ret = reply->handle;
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* ExitThread [KERNEL32.@] Ends a thread
|
||||
*
|
||||
* RETURNS
|
||||
* None
|
||||
*/
|
||||
void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */
|
||||
{
|
||||
BOOL last;
|
||||
SERVER_START_REQ( terminate_thread )
|
||||
{
|
||||
/* send the exit code to the server */
|
||||
req->handle = GetCurrentThread();
|
||||
req->exit_code = code;
|
||||
wine_server_call( req );
|
||||
last = reply->last;
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
if (last)
|
||||
{
|
||||
LdrShutdownProcess();
|
||||
exit( code );
|
||||
}
|
||||
else
|
||||
{
|
||||
LdrShutdownThread();
|
||||
RtlAcquirePebLock();
|
||||
RemoveEntryList( &NtCurrentTeb()->TlsLinks );
|
||||
RtlReleasePebLock();
|
||||
SYSDEPS_ExitThread( code );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* TerminateThread [KERNEL32.@] Terminates a thread
|
||||
*
|
||||
* RETURNS
|
||||
* Success: TRUE
|
||||
* Failure: FALSE
|
||||
*/
|
||||
BOOL WINAPI TerminateThread( HANDLE handle, /* [in] Handle to thread */
|
||||
DWORD exit_code) /* [in] Exit code for thread */
|
||||
{
|
||||
NTSTATUS status = NtTerminateThread( handle, exit_code );
|
||||
if (status) SetLastError( RtlNtStatusToDosError(status) );
|
||||
return !status;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* FreeLibraryAndExitThread (KERNEL32.@)
|
||||
*/
|
||||
void WINAPI FreeLibraryAndExitThread(HINSTANCE hLibModule, DWORD dwExitCode)
|
||||
{
|
||||
FreeLibrary(hLibModule);
|
||||
ExitThread(dwExitCode);
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* GetExitCodeThread (KERNEL32.@)
|
||||
*
|
||||
* Gets termination status of thread.
|
||||
*
|
||||
* RETURNS
|
||||
* Success: TRUE
|
||||
* Failure: FALSE
|
||||
*/
|
||||
BOOL WINAPI GetExitCodeThread(
|
||||
HANDLE hthread, /* [in] Handle to thread */
|
||||
LPDWORD exitcode) /* [out] Address to receive termination status */
|
||||
{
|
||||
THREAD_BASIC_INFORMATION info;
|
||||
NTSTATUS status = NtQueryInformationThread( hthread, ThreadBasicInformation,
|
||||
&info, sizeof(info), NULL );
|
||||
|
||||
if (status)
|
||||
{
|
||||
SetLastError( RtlNtStatusToDosError(status) );
|
||||
return FALSE;
|
||||
}
|
||||
if (exitcode) *exitcode = info.ExitStatus;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
|
|
|
@ -37,7 +37,6 @@ C_SRCS = \
|
|||
$(TOPOBJDIR)/relay32/relay386.c \
|
||||
$(TOPOBJDIR)/relay32/snoop.c \
|
||||
$(TOPOBJDIR)/scheduler/client.c \
|
||||
$(TOPOBJDIR)/scheduler/fiber.c \
|
||||
$(TOPOBJDIR)/scheduler/handle.c \
|
||||
$(TOPOBJDIR)/scheduler/process.c \
|
||||
$(TOPOBJDIR)/scheduler/pthread.c \
|
||||
|
@ -45,7 +44,6 @@ C_SRCS = \
|
|||
$(TOPOBJDIR)/scheduler/syslevel.c \
|
||||
$(TOPOBJDIR)/scheduler/thread.c \
|
||||
$(TOPOBJDIR)/win32/device.c \
|
||||
$(TOPOBJDIR)/win32/except.c \
|
||||
$(TOPOBJDIR)/win32/newfns.c \
|
||||
cdrom.c \
|
||||
critsection.c \
|
||||
|
|
|
@ -418,13 +418,13 @@ void *wine_dll_load_main_exe( const char *name, char *error, int errorsize,
|
|||
void wine_init( int argc, char *argv[], char *error, int error_size )
|
||||
{
|
||||
int file_exists;
|
||||
void *ntdll;
|
||||
void *kernel;
|
||||
void (*init_func)(int, char **);
|
||||
|
||||
if (!(ntdll = dlopen_dll( "ntdll.dll", error, error_size, 0, &file_exists ))) return;
|
||||
if (!dlopen_dll( "ntdll.dll", error, error_size, 0, &file_exists )) return;
|
||||
/* make sure kernel32 is loaded too */
|
||||
if (!dlopen_dll( "kernel32.dll", error, error_size, 0, &file_exists )) return;
|
||||
if (!(init_func = wine_dlsym( ntdll, "__wine_process_init", error, error_size ))) return;
|
||||
if (!(kernel = dlopen_dll( "kernel32.dll", error, error_size, 0, &file_exists ))) return;
|
||||
if (!(init_func = wine_dlsym( kernel, "__wine_process_init", error, error_size ))) return;
|
||||
init_func( argc, argv );
|
||||
}
|
||||
|
||||
|
|
126
loader/module.c
126
loader/module.c
|
@ -52,25 +52,6 @@ WINE_DECLARE_DEBUG_CHANNEL(win32);
|
|||
WINE_DECLARE_DEBUG_CHANNEL(loaddll);
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* wait_input_idle
|
||||
*
|
||||
* Wrapper to call WaitForInputIdle USER function
|
||||
*/
|
||||
typedef DWORD (WINAPI *WaitForInputIdle_ptr)( HANDLE hProcess, DWORD dwTimeOut );
|
||||
|
||||
static DWORD wait_input_idle( HANDLE process, DWORD timeout )
|
||||
{
|
||||
HMODULE mod = GetModuleHandleA( "user32.dll" );
|
||||
if (mod)
|
||||
{
|
||||
WaitForInputIdle_ptr ptr = (WaitForInputIdle_ptr)GetProcAddress( mod, "WaitForInputIdle" );
|
||||
if (ptr) return ptr( process, timeout );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/****************************************************************************
|
||||
* DisableThreadLibraryCalls (KERNEL32.@)
|
||||
*
|
||||
|
@ -387,104 +368,6 @@ BOOL WINAPI GetBinaryTypeW( LPCWSTR lpApplicationName, LPDWORD lpBinaryType )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* WinExec (KERNEL32.@)
|
||||
*/
|
||||
UINT WINAPI WinExec( LPCSTR lpCmdLine, UINT nCmdShow )
|
||||
{
|
||||
PROCESS_INFORMATION info;
|
||||
STARTUPINFOA startup;
|
||||
char *cmdline;
|
||||
UINT ret;
|
||||
|
||||
memset( &startup, 0, sizeof(startup) );
|
||||
startup.cb = sizeof(startup);
|
||||
startup.dwFlags = STARTF_USESHOWWINDOW;
|
||||
startup.wShowWindow = nCmdShow;
|
||||
|
||||
/* cmdline needs to be writeable for CreateProcess */
|
||||
if (!(cmdline = HeapAlloc( GetProcessHeap(), 0, strlen(lpCmdLine)+1 ))) return 0;
|
||||
strcpy( cmdline, lpCmdLine );
|
||||
|
||||
if (CreateProcessA( NULL, cmdline, NULL, NULL, FALSE,
|
||||
0, NULL, NULL, &startup, &info ))
|
||||
{
|
||||
/* Give 30 seconds to the app to come up */
|
||||
if (wait_input_idle( info.hProcess, 30000 ) == 0xFFFFFFFF)
|
||||
WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() );
|
||||
ret = 33;
|
||||
/* Close off the handles */
|
||||
CloseHandle( info.hThread );
|
||||
CloseHandle( info.hProcess );
|
||||
}
|
||||
else if ((ret = GetLastError()) >= 32)
|
||||
{
|
||||
FIXME("Strange error set by CreateProcess: %d\n", ret );
|
||||
ret = 11;
|
||||
}
|
||||
HeapFree( GetProcessHeap(), 0, cmdline );
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* LoadModule (KERNEL32.@)
|
||||
*/
|
||||
HINSTANCE WINAPI LoadModule( LPCSTR name, LPVOID paramBlock )
|
||||
{
|
||||
LOADPARAMS *params = (LOADPARAMS *)paramBlock;
|
||||
PROCESS_INFORMATION info;
|
||||
STARTUPINFOA startup;
|
||||
HINSTANCE hInstance;
|
||||
LPSTR cmdline, p;
|
||||
char filename[MAX_PATH];
|
||||
BYTE len;
|
||||
|
||||
if (!name) return (HINSTANCE)ERROR_FILE_NOT_FOUND;
|
||||
|
||||
if (!SearchPathA( NULL, name, ".exe", sizeof(filename), filename, NULL ) &&
|
||||
!SearchPathA( NULL, name, NULL, sizeof(filename), filename, NULL ))
|
||||
return (HINSTANCE)GetLastError();
|
||||
|
||||
len = (BYTE)params->lpCmdLine[0];
|
||||
if (!(cmdline = HeapAlloc( GetProcessHeap(), 0, strlen(filename) + len + 2 )))
|
||||
return (HINSTANCE)ERROR_NOT_ENOUGH_MEMORY;
|
||||
|
||||
strcpy( cmdline, filename );
|
||||
p = cmdline + strlen(cmdline);
|
||||
*p++ = ' ';
|
||||
memcpy( p, params->lpCmdLine + 1, len );
|
||||
p[len] = 0;
|
||||
|
||||
memset( &startup, 0, sizeof(startup) );
|
||||
startup.cb = sizeof(startup);
|
||||
if (params->lpCmdShow)
|
||||
{
|
||||
startup.dwFlags = STARTF_USESHOWWINDOW;
|
||||
startup.wShowWindow = params->lpCmdShow[1];
|
||||
}
|
||||
|
||||
if (CreateProcessA( filename, cmdline, NULL, NULL, FALSE, 0,
|
||||
params->lpEnvAddress, NULL, &startup, &info ))
|
||||
{
|
||||
/* Give 30 seconds to the app to come up */
|
||||
if (wait_input_idle( info.hProcess, 30000 ) == 0xFFFFFFFF )
|
||||
WARN("WaitForInputIdle failed: Error %ld\n", GetLastError() );
|
||||
hInstance = (HINSTANCE)33;
|
||||
/* Close off the handles */
|
||||
CloseHandle( info.hThread );
|
||||
CloseHandle( info.hProcess );
|
||||
}
|
||||
else if ((hInstance = (HINSTANCE)GetLastError()) >= (HINSTANCE)32)
|
||||
{
|
||||
FIXME("Strange error set by CreateProcess: %p\n", hInstance );
|
||||
hInstance = (HINSTANCE)11;
|
||||
}
|
||||
|
||||
HeapFree( GetProcessHeap(), 0, cmdline );
|
||||
return hInstance;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* GetModuleHandleA (KERNEL32.@)
|
||||
* GetModuleHandle32 (KERNEL.488)
|
||||
|
@ -778,15 +661,6 @@ BOOL WINAPI FreeLibrary(HINSTANCE hLibModule)
|
|||
return retv;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* FreeLibraryAndExitThread (KERNEL32.@)
|
||||
*/
|
||||
VOID WINAPI FreeLibraryAndExitThread(HINSTANCE hLibModule, DWORD dwExitCode)
|
||||
{
|
||||
FreeLibrary(hLibModule);
|
||||
ExitThread(dwExitCode);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* GetProcAddress (KERNEL32.@)
|
||||
*/
|
||||
|
|
1486
scheduler/process.c
1486
scheduler/process.c
File diff suppressed because it is too large
Load Diff
|
@ -36,385 +36,13 @@
|
|||
#include "wine/winbase16.h"
|
||||
#include "ntstatus.h"
|
||||
#include "thread.h"
|
||||
#include "module.h"
|
||||
#include "winerror.h"
|
||||
#include "selectors.h"
|
||||
#include "winnt.h"
|
||||
#include "wine/server.h"
|
||||
#include "wine/debug.h"
|
||||
#include "winnls.h"
|
||||
|
||||
WINE_DEFAULT_DEBUG_CHANNEL(thread);
|
||||
WINE_DECLARE_DEBUG_CHANNEL(relay);
|
||||
|
||||
/* TEB of the initial thread */
|
||||
static TEB initial_teb;
|
||||
|
||||
extern struct _PDB current_process;
|
||||
|
||||
/***********************************************************************
|
||||
* THREAD_InitTEB
|
||||
*
|
||||
* Initialization of a newly created TEB.
|
||||
*/
|
||||
static BOOL THREAD_InitTEB( TEB *teb )
|
||||
{
|
||||
teb->Tib.ExceptionList = (void *)~0UL;
|
||||
teb->Tib.StackBase = (void *)~0UL;
|
||||
teb->Tib.Self = &teb->Tib;
|
||||
teb->tibflags = TEBF_WIN32;
|
||||
teb->exit_code = STILL_ACTIVE;
|
||||
teb->request_fd = -1;
|
||||
teb->reply_fd = -1;
|
||||
teb->wait_fd[0] = -1;
|
||||
teb->wait_fd[1] = -1;
|
||||
teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
|
||||
teb->StaticUnicodeString.Buffer = (PWSTR)teb->StaticUnicodeBuffer;
|
||||
InitializeListHead(&teb->TlsLinks);
|
||||
teb->teb_sel = wine_ldt_alloc_fs();
|
||||
return (teb->teb_sel != 0);
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* THREAD_FreeTEB
|
||||
*
|
||||
* Free data structures associated with a thread.
|
||||
* Must be called from the context of another thread.
|
||||
*/
|
||||
static void THREAD_FreeTEB( TEB *teb )
|
||||
{
|
||||
TRACE("(%p) called\n", teb );
|
||||
/* Free the associated memory */
|
||||
wine_ldt_free_fs( teb->teb_sel );
|
||||
VirtualFree( teb->DeallocationStack, 0, MEM_RELEASE );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* THREAD_InitStack
|
||||
*
|
||||
* Allocate the stack of a thread.
|
||||
*/
|
||||
TEB *THREAD_InitStack( TEB *teb, DWORD stack_size )
|
||||
{
|
||||
DWORD old_prot, total_size;
|
||||
DWORD page_size = getpagesize();
|
||||
void *base;
|
||||
|
||||
/* Allocate the stack */
|
||||
|
||||
if (stack_size >= 16*1024*1024)
|
||||
WARN("Thread stack size is %ld MB.\n",stack_size/1024/1024);
|
||||
|
||||
/* if size is smaller than default, get stack size from parent */
|
||||
if (stack_size < 1024 * 1024)
|
||||
{
|
||||
if (teb)
|
||||
stack_size = 1024 * 1024; /* no parent */
|
||||
else
|
||||
stack_size = ((char *)NtCurrentTeb()->Tib.StackBase - (char *)NtCurrentTeb()->DeallocationStack
|
||||
- SIGNAL_STACK_SIZE - 3 * page_size);
|
||||
}
|
||||
|
||||
/* FIXME: some Wine functions use a lot of stack, so we add 64Kb here */
|
||||
stack_size += 64 * 1024;
|
||||
|
||||
/* Memory layout in allocated block:
|
||||
*
|
||||
* size contents
|
||||
* 1 page NOACCESS guard page
|
||||
* SIGNAL_STACK_SIZE signal stack
|
||||
* 1 page NOACCESS guard page
|
||||
* 1 page PAGE_GUARD guard page
|
||||
* stack_size normal stack
|
||||
* 1 page TEB (except for initial thread)
|
||||
*/
|
||||
|
||||
stack_size = (stack_size + (page_size - 1)) & ~(page_size - 1);
|
||||
total_size = stack_size + SIGNAL_STACK_SIZE + 3 * page_size;
|
||||
if (!teb) total_size += page_size;
|
||||
|
||||
if (!(base = VirtualAlloc( NULL, total_size, MEM_COMMIT, PAGE_EXECUTE_READWRITE )))
|
||||
return NULL;
|
||||
|
||||
if (!teb)
|
||||
{
|
||||
teb = (TEB *)((char *)base + total_size - page_size);
|
||||
if (!THREAD_InitTEB( teb ))
|
||||
{
|
||||
VirtualFree( base, 0, MEM_RELEASE );
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
teb->DeallocationStack = base;
|
||||
teb->signal_stack = (char *)base + page_size;
|
||||
teb->Tib.StackBase = (char *)base + 3 * page_size + SIGNAL_STACK_SIZE + stack_size;
|
||||
teb->Tib.StackLimit = base; /* note: limit is lower than base since the stack grows down */
|
||||
|
||||
/* Setup guard pages */
|
||||
|
||||
VirtualProtect( base, 1, PAGE_NOACCESS, &old_prot );
|
||||
VirtualProtect( (char *)teb->signal_stack + SIGNAL_STACK_SIZE, 1, PAGE_NOACCESS, &old_prot );
|
||||
VirtualProtect( (char *)teb->signal_stack + SIGNAL_STACK_SIZE + page_size, 1,
|
||||
PAGE_EXECUTE_READWRITE | PAGE_GUARD, &old_prot );
|
||||
return teb;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* THREAD_Init
|
||||
*
|
||||
* Setup the initial thread.
|
||||
*
|
||||
* NOTES: The first allocated TEB on NT is at 0x7ffde000.
|
||||
*/
|
||||
void THREAD_Init(void)
|
||||
{
|
||||
static struct debug_info info; /* debug info for initial thread */
|
||||
|
||||
if (!initial_teb.Tib.Self) /* do it only once */
|
||||
{
|
||||
THREAD_InitTEB( &initial_teb );
|
||||
assert( initial_teb.teb_sel );
|
||||
info.str_pos = info.strings;
|
||||
info.out_pos = info.output;
|
||||
initial_teb.debug_info = &info;
|
||||
initial_teb.Peb = (PEB *)¤t_process; /* FIXME */
|
||||
SYSDEPS_SetCurThread( &initial_teb );
|
||||
}
|
||||
}
|
||||
|
||||
DECL_GLOBAL_CONSTRUCTOR(thread_init) { THREAD_Init(); }
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* THREAD_Start
|
||||
*
|
||||
* Start execution of a newly created thread. Does not return.
|
||||
*/
|
||||
static void THREAD_Start( TEB *teb )
|
||||
{
|
||||
LPTHREAD_START_ROUTINE func = (LPTHREAD_START_ROUTINE)teb->entry_point;
|
||||
struct debug_info info;
|
||||
|
||||
info.str_pos = info.strings;
|
||||
info.out_pos = info.output;
|
||||
teb->debug_info = &info;
|
||||
|
||||
SYSDEPS_SetCurThread( teb );
|
||||
SIGNAL_Init();
|
||||
CLIENT_InitThread();
|
||||
|
||||
if (TRACE_ON(relay))
|
||||
DPRINTF("%04lx:Starting thread (entryproc=%p)\n", GetCurrentThreadId(), func );
|
||||
|
||||
__TRY
|
||||
{
|
||||
MODULE_DllThreadAttach( NULL );
|
||||
ExitThread( func( NtCurrentTeb()->entry_arg ) );
|
||||
}
|
||||
__EXCEPT(UnhandledExceptionFilter)
|
||||
{
|
||||
TerminateThread( GetCurrentThread(), GetExceptionCode() );
|
||||
}
|
||||
__ENDTRY
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* CreateThread (KERNEL32.@)
|
||||
*/
|
||||
HANDLE WINAPI CreateThread( SECURITY_ATTRIBUTES *sa, SIZE_T stack,
|
||||
LPTHREAD_START_ROUTINE start, LPVOID param,
|
||||
DWORD flags, LPDWORD id )
|
||||
{
|
||||
HANDLE handle = 0;
|
||||
TEB *teb;
|
||||
DWORD tid = 0;
|
||||
int request_pipe[2];
|
||||
|
||||
if (pipe( request_pipe ) == -1)
|
||||
{
|
||||
SetLastError( ERROR_TOO_MANY_OPEN_FILES );
|
||||
return 0;
|
||||
}
|
||||
fcntl( request_pipe[1], F_SETFD, 1 ); /* set close on exec flag */
|
||||
wine_server_send_fd( request_pipe[0] );
|
||||
|
||||
SERVER_START_REQ( new_thread )
|
||||
{
|
||||
req->suspend = ((flags & CREATE_SUSPENDED) != 0);
|
||||
req->inherit = (sa && (sa->nLength>=sizeof(*sa)) && sa->bInheritHandle);
|
||||
req->request_fd = request_pipe[0];
|
||||
if (!wine_server_call_err( req ))
|
||||
{
|
||||
handle = reply->handle;
|
||||
tid = reply->tid;
|
||||
}
|
||||
close( request_pipe[0] );
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
if (!handle || !(teb = THREAD_InitStack( NULL, stack )))
|
||||
{
|
||||
close( request_pipe[1] );
|
||||
return 0;
|
||||
}
|
||||
|
||||
teb->Peb = NtCurrentTeb()->Peb;
|
||||
teb->ClientId.UniqueThread = (HANDLE)tid;
|
||||
teb->request_fd = request_pipe[1];
|
||||
teb->entry_point = start;
|
||||
teb->entry_arg = param;
|
||||
teb->htask16 = GetCurrentTask();
|
||||
RtlAcquirePebLock();
|
||||
InsertHeadList( &NtCurrentTeb()->TlsLinks, &teb->TlsLinks );
|
||||
RtlReleasePebLock();
|
||||
|
||||
if (id) *id = tid;
|
||||
if (SYSDEPS_SpawnThread( THREAD_Start, teb ) == -1)
|
||||
{
|
||||
CloseHandle( handle );
|
||||
close( request_pipe[1] );
|
||||
RtlAcquirePebLock();
|
||||
RemoveEntryList( &teb->TlsLinks );
|
||||
RtlReleasePebLock();
|
||||
THREAD_FreeTEB( teb );
|
||||
return 0;
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* ExitThread [KERNEL32.@] Ends a thread
|
||||
*
|
||||
* RETURNS
|
||||
* None
|
||||
*/
|
||||
void WINAPI ExitThread( DWORD code ) /* [in] Exit code for this thread */
|
||||
{
|
||||
BOOL last;
|
||||
SERVER_START_REQ( terminate_thread )
|
||||
{
|
||||
/* send the exit code to the server */
|
||||
req->handle = GetCurrentThread();
|
||||
req->exit_code = code;
|
||||
wine_server_call( req );
|
||||
last = reply->last;
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
if (last)
|
||||
{
|
||||
LdrShutdownProcess();
|
||||
exit( code );
|
||||
}
|
||||
else
|
||||
{
|
||||
LdrShutdownThread();
|
||||
RtlAcquirePebLock();
|
||||
RemoveEntryList( &NtCurrentTeb()->TlsLinks );
|
||||
RtlReleasePebLock();
|
||||
SYSDEPS_ExitThread( code );
|
||||
}
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* OpenThread Retrieves a handle to a thread from its thread id
|
||||
*
|
||||
* RETURNS
|
||||
* None
|
||||
*/
|
||||
HANDLE WINAPI OpenThread( DWORD dwDesiredAccess, BOOL bInheritHandle, DWORD dwThreadId )
|
||||
{
|
||||
HANDLE ret = 0;
|
||||
SERVER_START_REQ( open_thread )
|
||||
{
|
||||
req->tid = dwThreadId;
|
||||
req->access = dwDesiredAccess;
|
||||
req->inherit = bInheritHandle;
|
||||
if (!wine_server_call_err( req )) ret = reply->handle;
|
||||
}
|
||||
SERVER_END_REQ;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**********************************************************************
|
||||
* TerminateThread [KERNEL32.@] Terminates a thread
|
||||
*
|
||||
* RETURNS
|
||||
* Success: TRUE
|
||||
* Failure: FALSE
|
||||
*/
|
||||
BOOL WINAPI TerminateThread( HANDLE handle, /* [in] Handle to thread */
|
||||
DWORD exit_code) /* [in] Exit code for thread */
|
||||
{
|
||||
NTSTATUS status = NtTerminateThread( handle, exit_code );
|
||||
if (status) SetLastError( RtlNtStatusToDosError(status) );
|
||||
return !status;
|
||||
}
|
||||
|
||||
|
||||
/**********************************************************************
|
||||
* GetExitCodeThread (KERNEL32.@)
|
||||
*
|
||||
* Gets termination status of thread.
|
||||
*
|
||||
* RETURNS
|
||||
* Success: TRUE
|
||||
* Failure: FALSE
|
||||
*/
|
||||
BOOL WINAPI GetExitCodeThread(
|
||||
HANDLE hthread, /* [in] Handle to thread */
|
||||
LPDWORD exitcode) /* [out] Address to receive termination status */
|
||||
{
|
||||
THREAD_BASIC_INFORMATION info;
|
||||
NTSTATUS status = NtQueryInformationThread( hthread, ThreadBasicInformation,
|
||||
&info, sizeof(info), NULL );
|
||||
|
||||
if (status)
|
||||
{
|
||||
SetLastError( RtlNtStatusToDosError(status) );
|
||||
return FALSE;
|
||||
}
|
||||
if (exitcode) *exitcode = info.ExitStatus;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/* callback for QueueUserAPC */
|
||||
static void CALLBACK call_user_apc( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
|
||||
{
|
||||
PAPCFUNC func = (PAPCFUNC)arg1;
|
||||
func( arg2 );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* QueueUserAPC (KERNEL32.@)
|
||||
*/
|
||||
DWORD WINAPI QueueUserAPC( PAPCFUNC func, HANDLE hthread, ULONG_PTR data )
|
||||
{
|
||||
NTSTATUS status = NtQueueApcThread( hthread, call_user_apc, (ULONG_PTR)func, data, 0 );
|
||||
|
||||
if (status) SetLastError( RtlNtStatusToDosError(status) );
|
||||
return !status;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* ProcessIdToSessionId (KERNEL32.@)
|
||||
* This function is available on Terminal Server 4SP4 and Windows 2000
|
||||
*/
|
||||
BOOL WINAPI ProcessIdToSessionId( DWORD procid, DWORD *sessionid_ptr )
|
||||
{
|
||||
/* According to MSDN, if the calling process is not in a terminal
|
||||
* services environment, then the sessionid returned is zero.
|
||||
*/
|
||||
*sessionid_ptr = 0;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __i386__
|
||||
|
|
Loading…
Reference in New Issue