/* * NT threads support * * Copyright 1996, 2003 Alexandre Julliard * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include #include #include #define NONAMELESSUNION #include "ntstatus.h" #define WIN32_NO_STATUS #include "winternl.h" #include "wine/server.h" #include "wine/debug.h" #include "ntdll_misc.h" #include "ddk/wdm.h" #include "wine/exception.h" WINE_DECLARE_DEBUG_CHANNEL(relay); struct _KUSER_SHARED_DATA *user_shared_data = (void *)0x7ffe0000; /*********************************************************************** * __wine_dbg_get_channel_flags (NTDLL.@) * * Get the flags to use for a given channel, possibly setting them too in case of lazy init */ unsigned char __cdecl __wine_dbg_get_channel_flags( struct __wine_debug_channel *channel ) { return unix_funcs->dbg_get_channel_flags( channel ); } /*********************************************************************** * __wine_dbg_strdup (NTDLL.@) */ const char * __cdecl __wine_dbg_strdup( const char *str ) { return unix_funcs->dbg_strdup( str ); } /*********************************************************************** * __wine_dbg_header (NTDLL.@) */ int __cdecl __wine_dbg_header( enum __wine_debug_class cls, struct __wine_debug_channel *channel, const char *function ) { return unix_funcs->dbg_header( cls, channel, function ); } /*********************************************************************** * __wine_dbg_output (NTDLL.@) */ int __cdecl __wine_dbg_output( const char *str ) { return unix_funcs->dbg_output( str ); } /*********************************************************************** * RtlExitUserThread (NTDLL.@) */ void WINAPI RtlExitUserThread( ULONG status ) { ULONG last; if (status) /* send the exit code to the server (0 is already the default) */ { SERVER_START_REQ( terminate_thread ) { req->handle = wine_server_obj_handle( GetCurrentThread() ); req->exit_code = status; wine_server_call( req ); } SERVER_END_REQ; } NtQueryInformationThread( GetCurrentThread(), ThreadAmILastThread, &last, sizeof(last), NULL ); if (last) { LdrShutdownProcess(); unix_funcs->exit_process( status ); } LdrShutdownThread(); RtlFreeThreadActivationContextStack(); for (;;) unix_funcs->exit_thread( status ); } /*********************************************************************** * RtlUserThreadStart (NTDLL.@) */ #ifdef __i386__ __ASM_STDCALL_FUNC( RtlUserThreadStart, 8, "pushl %ebp\n\t" __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") "movl %esp,%ebp\n\t" __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") "pushl %ebx\n\t" /* arg */ "pushl %eax\n\t" /* entry */ "call " __ASM_NAME("call_thread_func") ) /* wrapper for apps that don't declare the thread function correctly */ extern DWORD call_thread_func_wrapper( PRTL_THREAD_START_ROUTINE entry, void *arg ); __ASM_GLOBAL_FUNC(call_thread_func_wrapper, "pushl %ebp\n\t" __ASM_CFI(".cfi_adjust_cfa_offset 4\n\t") __ASM_CFI(".cfi_rel_offset %ebp,0\n\t") "movl %esp,%ebp\n\t" __ASM_CFI(".cfi_def_cfa_register %ebp\n\t") "subl $4,%esp\n\t" "pushl 12(%ebp)\n\t" "call *8(%ebp)\n\t" "leave\n\t" __ASM_CFI(".cfi_def_cfa %esp,4\n\t") __ASM_CFI(".cfi_same_value %ebp\n\t") "ret" ) void DECLSPEC_HIDDEN call_thread_func( PRTL_THREAD_START_ROUTINE entry, void *arg ) { __TRY { TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg ); RtlExitUserThread( call_thread_func_wrapper( entry, arg )); } __EXCEPT(call_unhandled_exception_filter) { NtTerminateThread( GetCurrentThread(), GetExceptionCode() ); } __ENDTRY } #else /* __i386__ */ void WINAPI RtlUserThreadStart( PRTL_THREAD_START_ROUTINE entry, void *arg ) { __TRY { TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg ); RtlExitUserThread( ((LPTHREAD_START_ROUTINE)entry)( arg )); } __EXCEPT(call_unhandled_exception_filter) { NtTerminateThread( GetCurrentThread(), GetExceptionCode() ); } __ENDTRY } #endif /* __i386__ */ /*********************************************************************** * NtCreateThreadEx (NTDLL.@) */ NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle_ptr, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr, HANDLE process, PRTL_THREAD_START_ROUTINE start, void *param, ULONG flags, SIZE_T zero_bits, SIZE_T stack_commit, SIZE_T stack_reserve, PS_ATTRIBUTE_LIST *attr_list ) { return unix_funcs->NtCreateThreadEx( handle_ptr, access, attr, process, start, param, flags, zero_bits, stack_commit, stack_reserve, attr_list ); } /*********************************************************************** * RtlCreateUserThread (NTDLL.@) */ NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, SECURITY_DESCRIPTOR *descr, BOOLEAN suspended, PVOID stack_addr, SIZE_T stack_reserve, SIZE_T stack_commit, PRTL_THREAD_START_ROUTINE start, void *param, HANDLE *handle_ptr, CLIENT_ID *id ) { ULONG flags = suspended ? THREAD_CREATE_FLAGS_CREATE_SUSPENDED : 0; HANDLE handle; NTSTATUS status; CLIENT_ID client_id; OBJECT_ATTRIBUTES attr; PS_ATTRIBUTE_LIST attr_list = { sizeof(attr_list) }; attr_list.Attributes[0].Attribute = PS_ATTRIBUTE_CLIENT_ID; attr_list.Attributes[0].Size = sizeof(client_id); attr_list.Attributes[0].ValuePtr = &client_id; InitializeObjectAttributes( &attr, NULL, 0, NULL, descr ); status = NtCreateThreadEx( &handle, THREAD_ALL_ACCESS, &attr, process, start, param, flags, 0, stack_commit, stack_reserve, &attr_list ); if (!status) { if (id) *id = client_id; if (handle_ptr) *handle_ptr = handle; else NtClose( handle ); } return status; } /****************************************************************************** * RtlGetNtGlobalFlags (NTDLL.@) */ ULONG WINAPI RtlGetNtGlobalFlags(void) { return NtCurrentTeb()->Peb->NtGlobalFlag; } /*********************************************************************** * NtOpenThread (NTDLL.@) * ZwOpenThread (NTDLL.@) */ NTSTATUS WINAPI NtOpenThread( HANDLE *handle, ACCESS_MASK access, const OBJECT_ATTRIBUTES *attr, const CLIENT_ID *id ) { return unix_funcs->NtOpenThread( handle, access, attr, id ); } /****************************************************************************** * NtSuspendThread (NTDLL.@) * ZwSuspendThread (NTDLL.@) */ NTSTATUS WINAPI NtSuspendThread( HANDLE handle, PULONG count ) { return unix_funcs->NtSuspendThread( handle, count ); } /****************************************************************************** * NtResumeThread (NTDLL.@) * ZwResumeThread (NTDLL.@) */ NTSTATUS WINAPI NtResumeThread( HANDLE handle, PULONG count ) { return unix_funcs->NtResumeThread( handle, count ); } /****************************************************************************** * NtAlertResumeThread (NTDLL.@) * ZwAlertResumeThread (NTDLL.@) */ NTSTATUS WINAPI NtAlertResumeThread( HANDLE handle, PULONG count ) { return unix_funcs->NtAlertResumeThread( handle, count ); } /****************************************************************************** * NtAlertThread (NTDLL.@) * ZwAlertThread (NTDLL.@) */ NTSTATUS WINAPI NtAlertThread( HANDLE handle ) { return unix_funcs->NtAlertThread( handle ); } /****************************************************************************** * NtTerminateThread (NTDLL.@) * ZwTerminateThread (NTDLL.@) */ NTSTATUS WINAPI NtTerminateThread( HANDLE handle, LONG exit_code ) { return unix_funcs->NtTerminateThread( handle, exit_code ); } /****************************************************************************** * NtQueueApcThread (NTDLL.@) */ NTSTATUS WINAPI NtQueueApcThread( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 ) { return unix_funcs->NtQueueApcThread( handle, func, arg1, arg2, arg3 ); } /****************************************************************************** * RtlPushFrame (NTDLL.@) */ void WINAPI RtlPushFrame( TEB_ACTIVE_FRAME *frame ) { frame->Previous = NtCurrentTeb()->ActiveFrame; NtCurrentTeb()->ActiveFrame = frame; } /****************************************************************************** * RtlPopFrame (NTDLL.@) */ void WINAPI RtlPopFrame( TEB_ACTIVE_FRAME *frame ) { NtCurrentTeb()->ActiveFrame = frame->Previous; } /****************************************************************************** * RtlGetFrame (NTDLL.@) */ TEB_ACTIVE_FRAME * WINAPI RtlGetFrame(void) { return NtCurrentTeb()->ActiveFrame; } /*********************************************************************** * NtContinue (NTDLL.@) */ NTSTATUS WINAPI NtContinue( CONTEXT *context, BOOLEAN alertable ) { return unix_funcs->NtContinue( context, alertable ); } /*********************************************************************** * NtSetContextThread (NTDLL.@) * ZwSetContextThread (NTDLL.@) */ NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context ) { return unix_funcs->NtSetContextThread( handle, context ); } /*********************************************************************** * NtGetContextThread (NTDLL.@) * ZwGetContextThread (NTDLL.@) */ #ifndef __i386__ NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context ) { return unix_funcs->NtGetContextThread( handle, context ); } #endif /****************************************************************************** * NtSetLdtEntries (NTDLL.@) * ZwSetLdtEntries (NTDLL.@) */ NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 ) { return unix_funcs->NtSetLdtEntries( sel1, entry1, sel2, entry2 ); } /****************************************************************************** * NtQueryInformationThread (NTDLL.@) * ZwQueryInformationThread (NTDLL.@) */ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class, void *data, ULONG length, ULONG *ret_len ) { return unix_funcs->NtQueryInformationThread( handle, class, data, length, ret_len ); } /****************************************************************************** * NtSetInformationThread (NTDLL.@) * ZwSetInformationThread (NTDLL.@) */ NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class, LPCVOID data, ULONG length ) { return unix_funcs->NtSetInformationThread( handle, class, data, length ); } /****************************************************************************** * NtGetCurrentProcessorNumber (NTDLL.@) * * Return the processor, on which the thread is running * */ ULONG WINAPI NtGetCurrentProcessorNumber(void) { return unix_funcs->NtGetCurrentProcessorNumber(); }