2003-04-05 00:26:34 +02:00
|
|
|
/*
|
|
|
|
* 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
|
2006-05-18 14:49:52 +02:00
|
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
2003-04-05 00:26:34 +02:00
|
|
|
*/
|
|
|
|
|
2003-10-09 06:59:03 +02:00
|
|
|
#include "config.h"
|
|
|
|
#include "wine/port.h"
|
|
|
|
|
2006-07-21 20:20:30 +02:00
|
|
|
#include <assert.h>
|
2008-03-01 11:57:00 +01:00
|
|
|
#include <stdarg.h>
|
2017-11-21 13:50:43 +01:00
|
|
|
#include <limits.h>
|
2003-11-04 05:50:18 +01:00
|
|
|
#include <sys/types.h>
|
|
|
|
#ifdef HAVE_SYS_MMAN_H
|
|
|
|
#include <sys/mman.h>
|
|
|
|
#endif
|
2005-09-13 00:01:33 +02:00
|
|
|
#ifdef HAVE_SYS_TIMES_H
|
|
|
|
#include <sys/times.h>
|
|
|
|
#endif
|
2012-05-18 01:03:31 +02:00
|
|
|
#ifdef HAVE_SYS_SYSCALL_H
|
|
|
|
#include <sys/syscall.h>
|
|
|
|
#endif
|
2003-11-04 05:50:18 +01:00
|
|
|
|
2005-11-05 11:43:50 +01:00
|
|
|
#define NONAMELESSUNION
|
2003-09-06 01:08:26 +02:00
|
|
|
#include "ntstatus.h"
|
2005-11-28 17:32:54 +01:00
|
|
|
#define WIN32_NO_STATUS
|
2003-04-05 00:26:34 +02:00
|
|
|
#include "winternl.h"
|
|
|
|
#include "wine/server.h"
|
2003-07-09 04:57:57 +02:00
|
|
|
#include "wine/debug.h"
|
2003-11-04 05:50:18 +01:00
|
|
|
#include "ntdll_misc.h"
|
2007-05-18 18:09:03 +02:00
|
|
|
#include "ddk/wdm.h"
|
2006-03-14 15:35:21 +01:00
|
|
|
#include "wine/exception.h"
|
2003-07-09 04:57:57 +02:00
|
|
|
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(thread);
|
2020-06-03 16:32:02 +02:00
|
|
|
WINE_DECLARE_DEBUG_CHANNEL(relay);
|
2003-04-05 00:26:34 +02:00
|
|
|
|
2020-06-04 19:48:26 +02:00
|
|
|
struct _KUSER_SHARED_DATA *user_shared_data = (void *)0x7ffe0000;
|
2007-05-18 18:09:03 +02:00
|
|
|
|
2010-01-22 12:32:40 +01:00
|
|
|
static PEB *peb;
|
2003-11-04 05:50:18 +01:00
|
|
|
static PEB_LDR_DATA ldr;
|
|
|
|
static RTL_BITMAP tls_bitmap;
|
2005-03-19 18:14:12 +01:00
|
|
|
static RTL_BITMAP tls_expansion_bitmap;
|
2008-02-29 19:55:34 +01:00
|
|
|
static RTL_BITMAP fls_bitmap;
|
2009-02-20 11:45:47 +01:00
|
|
|
static int nb_threads = 1;
|
2003-11-04 05:50:18 +01:00
|
|
|
|
2020-06-01 12:52:05 +02:00
|
|
|
struct ldt_copy *__wine_ldt_copy = NULL;
|
|
|
|
|
2017-08-31 10:01:04 +02:00
|
|
|
static RTL_CRITICAL_SECTION peb_lock;
|
|
|
|
static RTL_CRITICAL_SECTION_DEBUG critsect_debug =
|
|
|
|
{
|
|
|
|
0, 0, &peb_lock,
|
|
|
|
{ &critsect_debug.ProcessLocksList, &critsect_debug.ProcessLocksList },
|
|
|
|
0, 0, { (DWORD_PTR)(__FILE__ ": peb_lock") }
|
|
|
|
};
|
|
|
|
static RTL_CRITICAL_SECTION peb_lock = { &critsect_debug, -1, 0, 0, 0, 0 };
|
|
|
|
|
2017-04-25 16:38:23 +02:00
|
|
|
#ifdef __linux__
|
|
|
|
|
|
|
|
#ifdef HAVE_ELF_H
|
|
|
|
# include <elf.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_LINK_H
|
|
|
|
# include <link.h>
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_AUXV_H
|
|
|
|
# include <sys/auxv.h>
|
|
|
|
#endif
|
|
|
|
#ifndef HAVE_GETAUXVAL
|
|
|
|
static unsigned long getauxval( unsigned long id )
|
|
|
|
{
|
|
|
|
extern char **__wine_main_environ;
|
|
|
|
char **ptr = __wine_main_environ;
|
|
|
|
ElfW(auxv_t) *auxv;
|
|
|
|
|
|
|
|
while (*ptr) ptr++;
|
|
|
|
while (!*ptr) ptr++;
|
|
|
|
for (auxv = (ElfW(auxv_t) *)ptr; auxv->a_type; auxv++)
|
|
|
|
if (auxv->a_type == id) return auxv->a_un.a_val;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static ULONG_PTR get_image_addr(void)
|
|
|
|
{
|
|
|
|
ULONG_PTR size, num, phdr_addr = getauxval( AT_PHDR );
|
|
|
|
ElfW(Phdr) *phdr;
|
|
|
|
|
|
|
|
if (!phdr_addr) return 0;
|
|
|
|
phdr = (ElfW(Phdr) *)phdr_addr;
|
|
|
|
size = getauxval( AT_PHENT );
|
|
|
|
num = getauxval( AT_PHNUM );
|
|
|
|
while (num--)
|
|
|
|
{
|
|
|
|
if (phdr->p_type == PT_PHDR) return phdr_addr - phdr->p_offset;
|
|
|
|
phdr = (ElfW(Phdr) *)((char *)phdr + size);
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#elif defined(__APPLE__)
|
2013-12-04 23:07:55 +01:00
|
|
|
#include <mach/mach.h>
|
|
|
|
#include <mach/mach_error.h>
|
|
|
|
|
2017-04-25 16:38:23 +02:00
|
|
|
static ULONG_PTR get_image_addr(void)
|
2013-12-04 23:07:55 +01:00
|
|
|
{
|
2017-04-25 16:38:23 +02:00
|
|
|
ULONG_PTR ret = 0;
|
2013-12-04 23:07:55 +01:00
|
|
|
#ifdef TASK_DYLD_INFO
|
|
|
|
struct task_dyld_info dyld_info;
|
|
|
|
mach_msg_type_number_t size = TASK_DYLD_INFO_COUNT;
|
|
|
|
if (task_info(mach_task_self(), TASK_DYLD_INFO, (task_info_t)&dyld_info, &size) == KERN_SUCCESS)
|
|
|
|
ret = dyld_info.all_image_info_addr;
|
|
|
|
#endif
|
|
|
|
return ret;
|
|
|
|
}
|
2017-04-25 16:38:23 +02:00
|
|
|
|
|
|
|
#else
|
|
|
|
static ULONG_PTR get_image_addr(void)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
#endif
|
2013-12-04 23:07:55 +01:00
|
|
|
|
2019-10-22 10:00:57 +02:00
|
|
|
|
2020-05-17 11:07:02 +02:00
|
|
|
/***********************************************************************
|
|
|
|
* __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 );
|
|
|
|
}
|
|
|
|
|
2019-10-22 10:00:57 +02:00
|
|
|
|
2003-10-09 06:59:03 +02:00
|
|
|
/***********************************************************************
|
|
|
|
* thread_init
|
|
|
|
*
|
|
|
|
* Setup the initial thread.
|
|
|
|
*
|
|
|
|
* NOTES: The first allocated TEB on NT is at 0x7ffde000.
|
|
|
|
*/
|
2020-06-04 19:37:35 +02:00
|
|
|
TEB *thread_init( SIZE_T *info_size, BOOL *suspend )
|
2003-10-09 06:59:03 +02:00
|
|
|
{
|
2020-06-09 12:32:41 +02:00
|
|
|
TEB *teb = unix_funcs->init_threading( &nb_threads, &__wine_ldt_copy, info_size, suspend, &server_cpus,
|
|
|
|
&is_wow64, &server_start_time );
|
2020-06-01 12:52:05 +02:00
|
|
|
|
2020-04-30 10:05:56 +02:00
|
|
|
peb = teb->Peb;
|
2017-08-31 10:01:04 +02:00
|
|
|
peb->FastPebLock = &peb_lock;
|
2006-07-24 15:19:32 +02:00
|
|
|
peb->TlsBitmap = &tls_bitmap;
|
|
|
|
peb->TlsExpansionBitmap = &tls_expansion_bitmap;
|
2008-02-29 19:55:34 +01:00
|
|
|
peb->FlsBitmap = &fls_bitmap;
|
2006-07-24 15:19:32 +02:00
|
|
|
peb->LdrData = &ldr;
|
2016-04-12 21:22:05 +02:00
|
|
|
peb->OSMajorVersion = 5;
|
|
|
|
peb->OSMinorVersion = 1;
|
|
|
|
peb->OSBuildNumber = 0xA28;
|
|
|
|
peb->OSPlatformId = VER_PLATFORM_WIN32_NT;
|
2011-08-22 10:40:15 +02:00
|
|
|
ldr.Length = sizeof(ldr);
|
2017-04-23 23:17:00 +02:00
|
|
|
ldr.Initialized = TRUE;
|
2006-07-24 15:19:32 +02:00
|
|
|
RtlInitializeBitMap( &tls_bitmap, peb->TlsBitmapBits, sizeof(peb->TlsBitmapBits) * 8 );
|
|
|
|
RtlInitializeBitMap( &tls_expansion_bitmap, peb->TlsExpansionBitmapBits,
|
|
|
|
sizeof(peb->TlsExpansionBitmapBits) * 8 );
|
2008-02-29 19:55:34 +01:00
|
|
|
RtlInitializeBitMap( &fls_bitmap, peb->FlsBitmapBits, sizeof(peb->FlsBitmapBits) * 8 );
|
2014-03-28 13:46:17 +01:00
|
|
|
RtlSetBits( peb->TlsBitmap, 0, 1 ); /* TLS index 0 is reserved and should be initialized to NULL. */
|
2014-03-28 16:20:21 +01:00
|
|
|
RtlSetBits( peb->FlsBitmap, 0, 1 );
|
2008-02-29 19:55:34 +01:00
|
|
|
InitializeListHead( &peb->FlsListHead );
|
2003-10-09 06:59:03 +02:00
|
|
|
InitializeListHead( &ldr.InLoadOrderModuleList );
|
|
|
|
InitializeListHead( &ldr.InMemoryOrderModuleList );
|
|
|
|
InitializeListHead( &ldr.InInitializationOrderModuleList );
|
2017-04-25 16:38:23 +02:00
|
|
|
*(ULONG_PTR *)peb->Reserved = get_image_addr();
|
2003-11-04 05:50:18 +01:00
|
|
|
|
2015-10-08 14:19:43 +02:00
|
|
|
/*
|
|
|
|
* Starting with Vista, the first user to log on has session id 1.
|
|
|
|
* Session id 0 is for processes that don't interact with the user (like services).
|
|
|
|
*/
|
|
|
|
peb->SessionId = 1;
|
|
|
|
|
2020-05-19 17:37:08 +02:00
|
|
|
unix_funcs->get_paths( &build_dir, &data_dir, &config_dir );
|
2009-09-15 21:38:23 +02:00
|
|
|
fill_cpu_info();
|
2019-11-07 17:00:39 +01:00
|
|
|
return teb;
|
2003-10-09 06:59:03 +02:00
|
|
|
}
|
|
|
|
|
2009-02-20 11:23:08 +01:00
|
|
|
|
|
|
|
/***********************************************************************
|
2017-12-14 10:54:56 +01:00
|
|
|
* RtlExitUserThread (NTDLL.@)
|
2009-02-20 11:23:08 +01:00
|
|
|
*/
|
2017-12-14 10:54:56 +01:00
|
|
|
void WINAPI RtlExitUserThread( ULONG status )
|
2009-02-20 11:23:08 +01:00
|
|
|
{
|
2009-06-18 16:50:34 +02:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-05-02 15:10:04 +02:00
|
|
|
if (InterlockedDecrement( &nb_threads ) <= 0)
|
2009-06-18 16:50:34 +02:00
|
|
|
{
|
|
|
|
LdrShutdownProcess();
|
2020-06-01 12:52:05 +02:00
|
|
|
unix_funcs->exit_process( status );
|
2009-06-18 16:50:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
LdrShutdownThread();
|
2014-06-22 03:27:31 +02:00
|
|
|
RtlFreeThreadActivationContextStack();
|
2020-06-01 12:52:05 +02:00
|
|
|
for (;;) unix_funcs->exit_thread( status );
|
2009-02-20 11:23:08 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-06-03 16:32:02 +02:00
|
|
|
/***********************************************************************
|
2020-06-05 16:37:49 +02:00
|
|
|
* RtlUserThreadStart (NTDLL.@)
|
2020-06-03 16:32:02 +02:00
|
|
|
*/
|
|
|
|
#ifdef __i386__
|
2020-06-05 16:37:49 +02:00
|
|
|
__ASM_STDCALL_FUNC( RtlUserThreadStart, 8,
|
2020-06-03 16:32:02 +02:00
|
|
|
"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 */
|
2020-06-05 16:37:49 +02:00
|
|
|
extern DWORD call_thread_func_wrapper( PRTL_THREAD_START_ROUTINE entry, void *arg );
|
2020-06-03 16:32:02 +02:00
|
|
|
__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" )
|
|
|
|
|
2020-06-05 16:37:49 +02:00
|
|
|
void DECLSPEC_HIDDEN call_thread_func( PRTL_THREAD_START_ROUTINE entry, void *arg )
|
2020-06-03 16:32:02 +02:00
|
|
|
{
|
|
|
|
__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
|
|
|
|
abort(); /* should not be reached */
|
|
|
|
}
|
|
|
|
|
|
|
|
#else /* __i386__ */
|
|
|
|
|
2020-06-05 16:37:49 +02:00
|
|
|
void WINAPI RtlUserThreadStart( PRTL_THREAD_START_ROUTINE entry, void *arg )
|
2020-06-03 16:32:02 +02:00
|
|
|
{
|
|
|
|
__TRY
|
|
|
|
{
|
|
|
|
TRACE_(relay)( "\1Starting thread proc %p (arg=%p)\n", entry, arg );
|
2020-06-05 16:37:49 +02:00
|
|
|
RtlExitUserThread( ((LPTHREAD_START_ROUTINE)entry)( arg ));
|
2020-06-03 16:32:02 +02:00
|
|
|
}
|
|
|
|
__EXCEPT(call_unhandled_exception_filter)
|
|
|
|
{
|
|
|
|
NtTerminateThread( GetCurrentThread(), GetExceptionCode() );
|
|
|
|
}
|
|
|
|
__ENDTRY
|
|
|
|
abort(); /* should not be reached */
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif /* __i386__ */
|
|
|
|
|
|
|
|
|
2018-03-06 04:10:30 +01:00
|
|
|
/***********************************************************************
|
|
|
|
* NtCreateThreadEx (NTDLL.@)
|
|
|
|
*/
|
|
|
|
NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle_ptr, ACCESS_MASK access, OBJECT_ATTRIBUTES *attr,
|
2020-06-05 15:09:27 +02:00
|
|
|
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 )
|
2018-03-06 04:10:30 +01:00
|
|
|
{
|
2020-06-05 16:37:49 +02:00
|
|
|
return unix_funcs->NtCreateThreadEx( handle_ptr, access, attr, process, start, param,
|
|
|
|
flags, zero_bits, stack_commit, stack_reserve, attr_list );
|
2018-03-06 04:10:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-10-31 01:16:20 +01:00
|
|
|
/***********************************************************************
|
|
|
|
* RtlCreateUserThread (NTDLL.@)
|
|
|
|
*/
|
2018-09-20 13:06:12 +02:00
|
|
|
NTSTATUS WINAPI RtlCreateUserThread( HANDLE process, SECURITY_DESCRIPTOR *descr,
|
2003-10-31 01:16:20 +01:00
|
|
|
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 )
|
|
|
|
{
|
2020-06-05 14:09:19 +02:00
|
|
|
ULONG flags = suspended ? THREAD_CREATE_FLAGS_CREATE_SUSPENDED : 0;
|
|
|
|
HANDLE handle;
|
2003-10-31 01:16:20 +01:00
|
|
|
NTSTATUS status;
|
2020-06-05 14:09:19 +02:00
|
|
|
CLIENT_ID client_id;
|
|
|
|
OBJECT_ATTRIBUTES attr;
|
2020-06-05 15:09:27 +02:00
|
|
|
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;
|
2003-10-31 01:16:20 +01:00
|
|
|
|
2020-06-05 14:09:19 +02:00
|
|
|
InitializeObjectAttributes( &attr, NULL, 0, NULL, descr );
|
2009-11-19 12:25:52 +01:00
|
|
|
|
2020-06-05 15:09:27 +02:00
|
|
|
status = NtCreateThreadEx( &handle, THREAD_ALL_ACCESS, &attr, process, start, param,
|
|
|
|
flags, 0, stack_commit, stack_reserve, &attr_list );
|
2020-06-05 14:09:19 +02:00
|
|
|
if (!status)
|
2003-10-31 01:16:20 +01:00
|
|
|
{
|
2020-06-05 14:09:19 +02:00
|
|
|
if (id) *id = client_id;
|
|
|
|
if (handle_ptr) *handle_ptr = handle;
|
|
|
|
else NtClose( handle );
|
2003-10-31 01:16:20 +01:00
|
|
|
}
|
2020-06-05 14:09:19 +02:00
|
|
|
return status;
|
2003-10-31 01:16:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-01-22 12:32:40 +01:00
|
|
|
/******************************************************************************
|
|
|
|
* RtlGetNtGlobalFlags (NTDLL.@)
|
|
|
|
*/
|
|
|
|
ULONG WINAPI RtlGetNtGlobalFlags(void)
|
|
|
|
{
|
|
|
|
if (!peb) return 0; /* init not done yet */
|
|
|
|
return peb->NtGlobalFlag;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-04-05 00:26:34 +02:00
|
|
|
/***********************************************************************
|
|
|
|
* NtOpenThread (NTDLL.@)
|
|
|
|
* ZwOpenThread (NTDLL.@)
|
|
|
|
*/
|
|
|
|
NTSTATUS WINAPI NtOpenThread( HANDLE *handle, ACCESS_MASK access,
|
|
|
|
const OBJECT_ATTRIBUTES *attr, const CLIENT_ID *id )
|
|
|
|
{
|
2020-06-09 12:34:37 +02:00
|
|
|
return unix_funcs->NtOpenThread( handle, access, attr, id );
|
2003-04-05 00:26:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* NtSuspendThread (NTDLL.@)
|
|
|
|
* ZwSuspendThread (NTDLL.@)
|
|
|
|
*/
|
|
|
|
NTSTATUS WINAPI NtSuspendThread( HANDLE handle, PULONG count )
|
|
|
|
{
|
2020-06-09 12:34:37 +02:00
|
|
|
return unix_funcs->NtSuspendThread( handle, count );
|
2003-04-05 00:26:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* NtResumeThread (NTDLL.@)
|
|
|
|
* ZwResumeThread (NTDLL.@)
|
|
|
|
*/
|
|
|
|
NTSTATUS WINAPI NtResumeThread( HANDLE handle, PULONG count )
|
|
|
|
{
|
2020-06-09 12:34:37 +02:00
|
|
|
return unix_funcs->NtResumeThread( handle, count );
|
2003-04-05 00:26:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-08-18 13:47:17 +02:00
|
|
|
/******************************************************************************
|
|
|
|
* NtAlertResumeThread (NTDLL.@)
|
|
|
|
* ZwAlertResumeThread (NTDLL.@)
|
|
|
|
*/
|
|
|
|
NTSTATUS WINAPI NtAlertResumeThread( HANDLE handle, PULONG count )
|
|
|
|
{
|
2020-06-09 12:34:37 +02:00
|
|
|
return unix_funcs->NtAlertResumeThread( handle, count );
|
2005-08-18 13:47:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* NtAlertThread (NTDLL.@)
|
|
|
|
* ZwAlertThread (NTDLL.@)
|
|
|
|
*/
|
|
|
|
NTSTATUS WINAPI NtAlertThread( HANDLE handle )
|
|
|
|
{
|
2020-06-09 12:34:37 +02:00
|
|
|
return unix_funcs->NtAlertThread( handle );
|
2005-08-18 13:47:17 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-04-05 00:26:34 +02:00
|
|
|
/******************************************************************************
|
|
|
|
* NtTerminateThread (NTDLL.@)
|
|
|
|
* ZwTerminateThread (NTDLL.@)
|
|
|
|
*/
|
|
|
|
NTSTATUS WINAPI NtTerminateThread( HANDLE handle, LONG exit_code )
|
|
|
|
{
|
2020-06-09 12:34:37 +02:00
|
|
|
return unix_funcs->NtTerminateThread( handle, exit_code );
|
2003-04-05 00:26:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* NtQueueApcThread (NTDLL.@)
|
|
|
|
*/
|
|
|
|
NTSTATUS WINAPI NtQueueApcThread( HANDLE handle, PNTAPCFUNC func, ULONG_PTR arg1,
|
|
|
|
ULONG_PTR arg2, ULONG_PTR arg3 )
|
|
|
|
{
|
2020-06-09 12:34:37 +02:00
|
|
|
return unix_funcs->NtQueueApcThread( handle, func, arg1, arg2, arg3 );
|
2003-04-05 00:26:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2018-01-22 16:25:22 +01:00
|
|
|
/******************************************************************************
|
|
|
|
* 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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2017-07-18 11:07:48 +02:00
|
|
|
/***********************************************************************
|
|
|
|
* set_thread_context
|
|
|
|
*/
|
2018-06-12 10:46:27 +02:00
|
|
|
NTSTATUS set_thread_context( HANDLE handle, const context_t *context, BOOL *self )
|
2017-07-18 11:07:48 +02:00
|
|
|
{
|
|
|
|
NTSTATUS ret;
|
|
|
|
|
|
|
|
SERVER_START_REQ( set_thread_context )
|
|
|
|
{
|
|
|
|
req->handle = wine_server_obj_handle( handle );
|
2018-06-12 10:46:27 +02:00
|
|
|
wine_server_add_data( req, context, sizeof(*context) );
|
2017-07-18 11:07:48 +02:00
|
|
|
ret = wine_server_call( req );
|
|
|
|
*self = reply->self;
|
|
|
|
}
|
|
|
|
SERVER_END_REQ;
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/***********************************************************************
|
|
|
|
* get_thread_context
|
|
|
|
*/
|
2018-06-12 10:46:27 +02:00
|
|
|
NTSTATUS get_thread_context( HANDLE handle, context_t *context, unsigned int flags, BOOL *self )
|
2017-07-18 11:07:48 +02:00
|
|
|
{
|
|
|
|
NTSTATUS ret;
|
|
|
|
|
|
|
|
SERVER_START_REQ( get_thread_context )
|
|
|
|
{
|
|
|
|
req->handle = wine_server_obj_handle( handle );
|
2018-06-12 10:46:27 +02:00
|
|
|
req->flags = flags;
|
|
|
|
wine_server_set_reply( req, context, sizeof(*context) );
|
2017-07-18 11:07:48 +02:00
|
|
|
ret = wine_server_call( req );
|
|
|
|
*self = reply->self;
|
2020-04-22 14:33:23 +02:00
|
|
|
handle = wine_server_ptr_handle( reply->handle );
|
2017-07-18 11:07:48 +02:00
|
|
|
}
|
|
|
|
SERVER_END_REQ;
|
|
|
|
|
|
|
|
if (ret == STATUS_PENDING)
|
|
|
|
{
|
2020-04-22 14:33:23 +02:00
|
|
|
LARGE_INTEGER timeout;
|
|
|
|
timeout.QuadPart = -1000000;
|
|
|
|
if (NtWaitForSingleObject( handle, FALSE, &timeout ))
|
2017-07-18 11:07:48 +02:00
|
|
|
{
|
2020-04-22 14:33:23 +02:00
|
|
|
NtClose( handle );
|
|
|
|
return STATUS_ACCESS_DENIED;
|
2017-07-18 11:07:48 +02:00
|
|
|
}
|
2020-04-22 14:33:23 +02:00
|
|
|
SERVER_START_REQ( get_thread_context )
|
|
|
|
{
|
|
|
|
req->handle = wine_server_obj_handle( handle );
|
|
|
|
req->flags = flags;
|
|
|
|
wine_server_set_reply( req, context, sizeof(*context) );
|
|
|
|
ret = wine_server_call( req );
|
|
|
|
}
|
|
|
|
SERVER_END_REQ;
|
2017-07-18 11:07:48 +02:00
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-06-06 15:16:38 +02:00
|
|
|
/***********************************************************************
|
|
|
|
* NtContinue (NTDLL.@)
|
|
|
|
*/
|
|
|
|
NTSTATUS WINAPI NtContinue( CONTEXT *context, BOOLEAN alertable )
|
|
|
|
{
|
|
|
|
return unix_funcs->NtContinue( context, alertable );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-06-02 13:11:54 +02:00
|
|
|
/***********************************************************************
|
|
|
|
* NtSetContextThread (NTDLL.@)
|
|
|
|
* ZwSetContextThread (NTDLL.@)
|
|
|
|
*/
|
|
|
|
NTSTATUS WINAPI NtSetContextThread( HANDLE handle, const CONTEXT *context )
|
|
|
|
{
|
|
|
|
return unix_funcs->NtSetContextThread( handle, context );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-06-02 14:05:42 +02:00
|
|
|
/***********************************************************************
|
|
|
|
* NtGetContextThread (NTDLL.@)
|
|
|
|
* ZwGetContextThread (NTDLL.@)
|
|
|
|
*/
|
|
|
|
#ifndef __i386__
|
|
|
|
NTSTATUS WINAPI NtGetContextThread( HANDLE handle, CONTEXT *context )
|
|
|
|
{
|
|
|
|
return unix_funcs->NtGetContextThread( handle, context );
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
2020-06-01 12:52:05 +02:00
|
|
|
/******************************************************************************
|
|
|
|
* 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 );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2003-07-09 04:57:57 +02:00
|
|
|
/******************************************************************************
|
|
|
|
* NtQueryInformationThread (NTDLL.@)
|
|
|
|
* ZwQueryInformationThread (NTDLL.@)
|
|
|
|
*/
|
|
|
|
NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
|
|
|
|
void *data, ULONG length, ULONG *ret_len )
|
|
|
|
{
|
|
|
|
NTSTATUS status;
|
|
|
|
|
|
|
|
switch(class)
|
|
|
|
{
|
|
|
|
case ThreadBasicInformation:
|
|
|
|
{
|
|
|
|
THREAD_BASIC_INFORMATION info;
|
2015-01-21 13:24:14 +01:00
|
|
|
const ULONG_PTR affinity_mask = get_system_affinity_mask();
|
2003-07-09 04:57:57 +02:00
|
|
|
|
|
|
|
SERVER_START_REQ( get_thread_info )
|
|
|
|
{
|
2008-12-08 16:05:17 +01:00
|
|
|
req->handle = wine_server_obj_handle( handle );
|
2003-07-09 04:57:57 +02:00
|
|
|
req->tid_in = 0;
|
|
|
|
if (!(status = wine_server_call( req )))
|
|
|
|
{
|
|
|
|
info.ExitStatus = reply->exit_code;
|
2008-12-30 23:02:33 +01:00
|
|
|
info.TebBaseAddress = wine_server_get_ptr( reply->teb );
|
2007-05-23 09:36:29 +02:00
|
|
|
info.ClientId.UniqueProcess = ULongToHandle(reply->pid);
|
|
|
|
info.ClientId.UniqueThread = ULongToHandle(reply->tid);
|
2008-01-16 21:02:04 +01:00
|
|
|
info.AffinityMask = reply->affinity & affinity_mask;
|
2003-07-09 04:57:57 +02:00
|
|
|
info.Priority = reply->priority;
|
|
|
|
info.BasePriority = reply->priority; /* FIXME */
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SERVER_END_REQ;
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
|
|
{
|
|
|
|
if (data) memcpy( data, &info, min( length, sizeof(info) ));
|
|
|
|
if (ret_len) *ret_len = min( length, sizeof(info) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return status;
|
2009-01-21 18:51:49 +01:00
|
|
|
case ThreadAffinityMask:
|
|
|
|
{
|
2015-01-21 13:24:14 +01:00
|
|
|
const ULONG_PTR affinity_mask = get_system_affinity_mask();
|
2009-01-21 18:51:49 +01:00
|
|
|
ULONG_PTR affinity = 0;
|
|
|
|
|
|
|
|
SERVER_START_REQ( get_thread_info )
|
|
|
|
{
|
|
|
|
req->handle = wine_server_obj_handle( handle );
|
|
|
|
req->tid_in = 0;
|
|
|
|
if (!(status = wine_server_call( req )))
|
|
|
|
affinity = reply->affinity & affinity_mask;
|
|
|
|
}
|
|
|
|
SERVER_END_REQ;
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
|
|
{
|
|
|
|
if (data) memcpy( data, &affinity, min( length, sizeof(affinity) ));
|
|
|
|
if (ret_len) *ret_len = min( length, sizeof(affinity) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return status;
|
2003-07-09 04:57:57 +02:00
|
|
|
case ThreadTimes:
|
2005-09-13 00:01:33 +02:00
|
|
|
{
|
|
|
|
KERNEL_USER_TIMES kusrt;
|
2015-07-27 18:30:53 +02:00
|
|
|
|
|
|
|
SERVER_START_REQ( get_thread_times )
|
2005-09-13 00:01:33 +02:00
|
|
|
{
|
2008-12-08 16:05:17 +01:00
|
|
|
req->handle = wine_server_obj_handle( handle );
|
2005-09-13 00:01:33 +02:00
|
|
|
status = wine_server_call( req );
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
|
|
{
|
2007-04-17 20:08:59 +02:00
|
|
|
kusrt.CreateTime.QuadPart = reply->creation_time;
|
|
|
|
kusrt.ExitTime.QuadPart = reply->exit_time;
|
2005-09-13 00:01:33 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
SERVER_END_REQ;
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
|
|
{
|
|
|
|
/* We call times(2) for kernel time or user time */
|
|
|
|
/* We can only (portably) do this for the current thread */
|
|
|
|
if (handle == GetCurrentThread())
|
|
|
|
{
|
|
|
|
struct tms time_buf;
|
|
|
|
long clocks_per_sec = sysconf(_SC_CLK_TCK);
|
|
|
|
|
|
|
|
times(&time_buf);
|
|
|
|
kusrt.KernelTime.QuadPart = (ULONGLONG)time_buf.tms_stime * 10000000 / clocks_per_sec;
|
|
|
|
kusrt.UserTime.QuadPart = (ULONGLONG)time_buf.tms_utime * 10000000 / clocks_per_sec;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2007-10-29 14:11:23 +01:00
|
|
|
static BOOL reported = FALSE;
|
|
|
|
|
2005-09-13 00:01:33 +02:00
|
|
|
kusrt.KernelTime.QuadPart = 0;
|
|
|
|
kusrt.UserTime.QuadPart = 0;
|
2007-10-29 14:11:23 +01:00
|
|
|
if (reported)
|
|
|
|
TRACE("Cannot get kerneltime or usertime of other threads\n");
|
|
|
|
else
|
|
|
|
{
|
|
|
|
FIXME("Cannot get kerneltime or usertime of other threads\n");
|
|
|
|
reported = TRUE;
|
|
|
|
}
|
2005-09-13 00:01:33 +02:00
|
|
|
}
|
|
|
|
if (data) memcpy( data, &kusrt, min( length, sizeof(kusrt) ));
|
|
|
|
if (ret_len) *ret_len = min( length, sizeof(kusrt) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return status;
|
2020-04-01 12:33:29 +02:00
|
|
|
|
2006-05-26 12:10:57 +02:00
|
|
|
case ThreadDescriptorTableEntry:
|
2020-06-01 12:52:05 +02:00
|
|
|
return unix_funcs->get_thread_ldt_entry( handle, data, length, ret_len );
|
2020-04-01 12:33:29 +02:00
|
|
|
|
2006-10-01 08:17:27 +02:00
|
|
|
case ThreadAmILastThread:
|
|
|
|
{
|
|
|
|
SERVER_START_REQ(get_thread_info)
|
|
|
|
{
|
2008-12-08 16:05:17 +01:00
|
|
|
req->handle = wine_server_obj_handle( handle );
|
2006-10-01 08:17:27 +02:00
|
|
|
req->tid_in = 0;
|
|
|
|
status = wine_server_call( req );
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
|
|
{
|
|
|
|
BOOLEAN last = reply->last;
|
|
|
|
if (data) memcpy( data, &last, min( length, sizeof(last) ));
|
|
|
|
if (ret_len) *ret_len = min( length, sizeof(last) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SERVER_END_REQ;
|
|
|
|
return status;
|
|
|
|
}
|
2015-07-27 18:31:33 +02:00
|
|
|
case ThreadQuerySetWin32StartAddress:
|
|
|
|
{
|
|
|
|
SERVER_START_REQ( get_thread_info )
|
|
|
|
{
|
|
|
|
req->handle = wine_server_obj_handle( handle );
|
|
|
|
req->tid_in = 0;
|
|
|
|
status = wine_server_call( req );
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
|
|
{
|
|
|
|
PRTL_THREAD_START_ROUTINE entry = wine_server_get_ptr( reply->entry_point );
|
|
|
|
if (data) memcpy( data, &entry, min( length, sizeof(entry) ) );
|
|
|
|
if (ret_len) *ret_len = min( length, sizeof(entry) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
SERVER_END_REQ;
|
|
|
|
return status;
|
|
|
|
}
|
2015-09-23 22:51:14 +02:00
|
|
|
case ThreadGroupInformation:
|
|
|
|
{
|
|
|
|
const ULONG_PTR affinity_mask = get_system_affinity_mask();
|
|
|
|
GROUP_AFFINITY affinity;
|
|
|
|
|
|
|
|
memset(&affinity, 0, sizeof(affinity));
|
|
|
|
affinity.Group = 0; /* Wine only supports max 64 processors */
|
|
|
|
|
|
|
|
SERVER_START_REQ( get_thread_info )
|
|
|
|
{
|
|
|
|
req->handle = wine_server_obj_handle( handle );
|
|
|
|
req->tid_in = 0;
|
|
|
|
if (!(status = wine_server_call( req )))
|
|
|
|
affinity.Mask = reply->affinity & affinity_mask;
|
|
|
|
}
|
|
|
|
SERVER_END_REQ;
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
|
|
{
|
|
|
|
if (data) memcpy( data, &affinity, min( length, sizeof(affinity) ));
|
|
|
|
if (ret_len) *ret_len = min( length, sizeof(affinity) );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return status;
|
2017-02-02 19:27:26 +01:00
|
|
|
case ThreadIsIoPending:
|
|
|
|
FIXME( "ThreadIsIoPending info class not supported yet\n" );
|
|
|
|
if (length != sizeof(BOOL)) return STATUS_INFO_LENGTH_MISMATCH;
|
|
|
|
if (!data) return STATUS_ACCESS_DENIED;
|
|
|
|
|
|
|
|
*(BOOL*)data = FALSE;
|
|
|
|
if (ret_len) *ret_len = sizeof(BOOL);
|
|
|
|
return STATUS_SUCCESS;
|
2019-12-03 10:05:22 +01:00
|
|
|
case ThreadSuspendCount:
|
|
|
|
{
|
|
|
|
ULONG count = 0;
|
|
|
|
|
|
|
|
if (length != sizeof(ULONG)) return STATUS_INFO_LENGTH_MISMATCH;
|
|
|
|
if (!data) return STATUS_ACCESS_VIOLATION;
|
|
|
|
|
|
|
|
SERVER_START_REQ( get_thread_info )
|
|
|
|
{
|
|
|
|
req->handle = wine_server_obj_handle( handle );
|
|
|
|
req->tid_in = 0;
|
|
|
|
if (!(status = wine_server_call( req )))
|
|
|
|
count = reply->suspend_count;
|
|
|
|
}
|
|
|
|
SERVER_END_REQ;
|
|
|
|
|
|
|
|
if (!status)
|
|
|
|
*(ULONG *)data = count;
|
|
|
|
|
|
|
|
return status;
|
|
|
|
}
|
2019-11-26 07:48:10 +01:00
|
|
|
case ThreadDescription:
|
|
|
|
{
|
|
|
|
THREAD_DESCRIPTION_INFORMATION *info = data;
|
|
|
|
data_size_t len, desc_len = 0;
|
|
|
|
WCHAR *ptr;
|
|
|
|
|
|
|
|
len = length >= sizeof(*info) ? length - sizeof(*info) : 0;
|
|
|
|
ptr = info ? (WCHAR *)(info + 1) : NULL;
|
|
|
|
|
|
|
|
SERVER_START_REQ( get_thread_info )
|
|
|
|
{
|
|
|
|
req->handle = wine_server_obj_handle( handle );
|
|
|
|
if (ptr) wine_server_set_reply( req, ptr, len );
|
|
|
|
status = wine_server_call( req );
|
|
|
|
desc_len = reply->desc_len;
|
|
|
|
}
|
|
|
|
SERVER_END_REQ;
|
|
|
|
|
|
|
|
if (!info)
|
|
|
|
status = STATUS_BUFFER_TOO_SMALL;
|
|
|
|
else if (status == STATUS_SUCCESS)
|
|
|
|
{
|
2019-12-03 10:05:21 +01:00
|
|
|
info->Description.Length = info->Description.MaximumLength = desc_len;
|
|
|
|
info->Description.Buffer = ptr;
|
2019-11-26 07:48:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ret_len && (status == STATUS_SUCCESS || status == STATUS_BUFFER_TOO_SMALL))
|
|
|
|
*ret_len = sizeof(*info) + desc_len;
|
|
|
|
}
|
|
|
|
return status;
|
2003-07-09 04:57:57 +02:00
|
|
|
case ThreadPriority:
|
|
|
|
case ThreadBasePriority:
|
|
|
|
case ThreadImpersonationToken:
|
|
|
|
case ThreadEnableAlignmentFaultFixup:
|
|
|
|
case ThreadEventPair_Reusable:
|
|
|
|
case ThreadZeroTlsCell:
|
|
|
|
case ThreadPerformanceCount:
|
|
|
|
case ThreadIdealProcessor:
|
|
|
|
case ThreadPriorityBoost:
|
|
|
|
case ThreadSetTlsArrayAddress:
|
|
|
|
default:
|
|
|
|
FIXME( "info class %d not supported yet\n", class );
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
}
|
2003-09-08 21:02:01 +02:00
|
|
|
|
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* NtSetInformationThread (NTDLL.@)
|
|
|
|
* ZwSetInformationThread (NTDLL.@)
|
|
|
|
*/
|
|
|
|
NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
|
|
|
|
LPCVOID data, ULONG length )
|
|
|
|
{
|
2005-06-20 15:18:38 +02:00
|
|
|
NTSTATUS status;
|
2003-09-08 21:02:01 +02:00
|
|
|
switch(class)
|
|
|
|
{
|
|
|
|
case ThreadZeroTlsCell:
|
|
|
|
if (handle == GetCurrentThread())
|
|
|
|
{
|
2003-11-04 05:50:18 +01:00
|
|
|
LIST_ENTRY *entry;
|
2003-09-08 21:02:01 +02:00
|
|
|
DWORD index;
|
|
|
|
|
|
|
|
if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
|
2004-06-15 02:52:03 +02:00
|
|
|
index = *(const DWORD *)data;
|
2005-03-19 18:14:12 +01:00
|
|
|
if (index < TLS_MINIMUM_AVAILABLE)
|
2003-09-08 21:02:01 +02:00
|
|
|
{
|
2005-03-19 18:14:12 +01:00
|
|
|
RtlAcquirePebLock();
|
|
|
|
for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
|
|
|
|
{
|
|
|
|
TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
|
|
|
|
teb->TlsSlots[index] = 0;
|
|
|
|
}
|
|
|
|
RtlReleasePebLock();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
index -= TLS_MINIMUM_AVAILABLE;
|
|
|
|
if (index >= 8 * sizeof(NtCurrentTeb()->Peb->TlsExpansionBitmapBits))
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
RtlAcquirePebLock();
|
|
|
|
for (entry = tls_links.Flink; entry != &tls_links; entry = entry->Flink)
|
|
|
|
{
|
|
|
|
TEB *teb = CONTAINING_RECORD(entry, TEB, TlsLinks);
|
|
|
|
if (teb->TlsExpansionSlots) teb->TlsExpansionSlots[index] = 0;
|
|
|
|
}
|
|
|
|
RtlReleasePebLock();
|
2003-11-04 05:50:18 +01:00
|
|
|
}
|
2003-09-08 21:02:01 +02:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
FIXME( "ZeroTlsCell not supported on other threads\n" );
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
|
2004-08-14 01:20:27 +02:00
|
|
|
case ThreadImpersonationToken:
|
|
|
|
{
|
|
|
|
const HANDLE *phToken = data;
|
|
|
|
if (length != sizeof(HANDLE)) return STATUS_INVALID_PARAMETER;
|
2005-06-20 15:18:38 +02:00
|
|
|
TRACE("Setting ThreadImpersonationToken handle to %p\n", *phToken );
|
|
|
|
SERVER_START_REQ( set_thread_info )
|
|
|
|
{
|
2008-12-08 16:05:17 +01:00
|
|
|
req->handle = wine_server_obj_handle( handle );
|
|
|
|
req->token = wine_server_obj_handle( *phToken );
|
2005-06-20 15:18:38 +02:00
|
|
|
req->mask = SET_THREAD_INFO_TOKEN;
|
|
|
|
status = wine_server_call( req );
|
|
|
|
}
|
|
|
|
SERVER_END_REQ;
|
2004-08-14 01:20:27 +02:00
|
|
|
}
|
2005-09-07 15:25:35 +02:00
|
|
|
return status;
|
|
|
|
case ThreadBasePriority:
|
|
|
|
{
|
|
|
|
const DWORD *pprio = data;
|
|
|
|
if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
|
|
|
|
SERVER_START_REQ( set_thread_info )
|
|
|
|
{
|
2008-12-08 16:05:17 +01:00
|
|
|
req->handle = wine_server_obj_handle( handle );
|
2005-09-07 15:25:35 +02:00
|
|
|
req->priority = *pprio;
|
|
|
|
req->mask = SET_THREAD_INFO_PRIORITY;
|
|
|
|
status = wine_server_call( req );
|
|
|
|
}
|
|
|
|
SERVER_END_REQ;
|
|
|
|
}
|
|
|
|
return status;
|
2006-01-11 12:32:19 +01:00
|
|
|
case ThreadAffinityMask:
|
|
|
|
{
|
2015-01-21 13:24:14 +01:00
|
|
|
const ULONG_PTR affinity_mask = get_system_affinity_mask();
|
2010-02-20 03:07:41 +01:00
|
|
|
ULONG_PTR req_aff;
|
|
|
|
|
2009-01-19 14:15:51 +01:00
|
|
|
if (length != sizeof(ULONG_PTR)) return STATUS_INVALID_PARAMETER;
|
2018-09-11 02:41:09 +02:00
|
|
|
req_aff = *(const ULONG_PTR *)data & affinity_mask;
|
|
|
|
if (!req_aff) return STATUS_INVALID_PARAMETER;
|
|
|
|
|
2006-01-11 12:32:19 +01:00
|
|
|
SERVER_START_REQ( set_thread_info )
|
|
|
|
{
|
2008-12-08 16:05:17 +01:00
|
|
|
req->handle = wine_server_obj_handle( handle );
|
2010-02-20 03:07:41 +01:00
|
|
|
req->affinity = req_aff;
|
2006-01-11 12:32:19 +01:00
|
|
|
req->mask = SET_THREAD_INFO_AFFINITY;
|
|
|
|
status = wine_server_call( req );
|
|
|
|
}
|
|
|
|
SERVER_END_REQ;
|
|
|
|
}
|
|
|
|
return status;
|
2009-10-06 11:34:48 +02:00
|
|
|
case ThreadHideFromDebugger:
|
|
|
|
/* pretend the call succeeded to satisfy some code protectors */
|
|
|
|
return STATUS_SUCCESS;
|
2015-07-27 18:31:11 +02:00
|
|
|
case ThreadQuerySetWin32StartAddress:
|
|
|
|
{
|
|
|
|
const PRTL_THREAD_START_ROUTINE *entry = data;
|
|
|
|
if (length != sizeof(PRTL_THREAD_START_ROUTINE)) return STATUS_INVALID_PARAMETER;
|
|
|
|
SERVER_START_REQ( set_thread_info )
|
|
|
|
{
|
|
|
|
req->handle = wine_server_obj_handle( handle );
|
|
|
|
req->mask = SET_THREAD_INFO_ENTRYPOINT;
|
|
|
|
req->entry_point = wine_server_client_ptr( *entry );
|
|
|
|
status = wine_server_call( req );
|
|
|
|
}
|
|
|
|
SERVER_END_REQ;
|
|
|
|
}
|
|
|
|
return status;
|
2015-09-23 22:51:14 +02:00
|
|
|
case ThreadGroupInformation:
|
|
|
|
{
|
|
|
|
const ULONG_PTR affinity_mask = get_system_affinity_mask();
|
|
|
|
const GROUP_AFFINITY *req_aff;
|
|
|
|
|
|
|
|
if (length != sizeof(*req_aff)) return STATUS_INVALID_PARAMETER;
|
|
|
|
if (!data) return STATUS_ACCESS_VIOLATION;
|
|
|
|
req_aff = data;
|
|
|
|
|
|
|
|
/* On Windows the request fails if the reserved fields are set */
|
|
|
|
if (req_aff->Reserved[0] || req_aff->Reserved[1] || req_aff->Reserved[2])
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
/* Wine only supports max 64 processors */
|
|
|
|
if (req_aff->Group) return STATUS_INVALID_PARAMETER;
|
|
|
|
if (req_aff->Mask & ~affinity_mask) return STATUS_INVALID_PARAMETER;
|
|
|
|
if (!req_aff->Mask) return STATUS_INVALID_PARAMETER;
|
|
|
|
SERVER_START_REQ( set_thread_info )
|
|
|
|
{
|
|
|
|
req->handle = wine_server_obj_handle( handle );
|
|
|
|
req->affinity = req_aff->Mask;
|
|
|
|
req->mask = SET_THREAD_INFO_AFFINITY;
|
|
|
|
status = wine_server_call( req );
|
|
|
|
}
|
|
|
|
SERVER_END_REQ;
|
|
|
|
}
|
|
|
|
return status;
|
2019-11-26 07:48:10 +01:00
|
|
|
case ThreadDescription:
|
|
|
|
{
|
|
|
|
const THREAD_DESCRIPTION_INFORMATION *info = data;
|
|
|
|
|
|
|
|
if (length != sizeof(*info)) return STATUS_INFO_LENGTH_MISMATCH;
|
|
|
|
if (!info) return STATUS_ACCESS_VIOLATION;
|
|
|
|
|
2019-12-03 10:05:21 +01:00
|
|
|
if (info->Description.Length != info->Description.MaximumLength) return STATUS_INVALID_PARAMETER;
|
|
|
|
if (info->Description.Length && !info->Description.Buffer) return STATUS_ACCESS_VIOLATION;
|
2019-11-26 07:48:10 +01:00
|
|
|
|
|
|
|
SERVER_START_REQ( set_thread_info )
|
|
|
|
{
|
|
|
|
req->handle = wine_server_obj_handle( handle );
|
|
|
|
req->mask = SET_THREAD_INFO_DESCRIPTION;
|
2019-12-03 10:05:21 +01:00
|
|
|
wine_server_add_data( req, info->Description.Buffer, info->Description.Length );
|
2019-11-26 07:48:10 +01:00
|
|
|
status = wine_server_call( req );
|
|
|
|
}
|
|
|
|
SERVER_END_REQ;
|
|
|
|
}
|
|
|
|
return status;
|
2003-09-08 21:02:01 +02:00
|
|
|
case ThreadBasicInformation:
|
|
|
|
case ThreadTimes:
|
|
|
|
case ThreadPriority:
|
|
|
|
case ThreadDescriptorTableEntry:
|
|
|
|
case ThreadEnableAlignmentFaultFixup:
|
|
|
|
case ThreadEventPair_Reusable:
|
|
|
|
case ThreadPerformanceCount:
|
|
|
|
case ThreadAmILastThread:
|
|
|
|
case ThreadIdealProcessor:
|
|
|
|
case ThreadPriorityBoost:
|
|
|
|
case ThreadSetTlsArrayAddress:
|
|
|
|
case ThreadIsIoPending:
|
|
|
|
default:
|
|
|
|
FIXME( "info class %d not supported yet\n", class );
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
}
|
2012-05-17 19:28:31 +02:00
|
|
|
|
|
|
|
/******************************************************************************
|
|
|
|
* NtGetCurrentProcessorNumber (NTDLL.@)
|
|
|
|
*
|
|
|
|
* Return the processor, on which the thread is running
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
ULONG WINAPI NtGetCurrentProcessorNumber(void)
|
|
|
|
{
|
2012-05-17 19:28:33 +02:00
|
|
|
ULONG processor;
|
2012-05-17 19:28:31 +02:00
|
|
|
|
2012-05-18 01:03:31 +02:00
|
|
|
#if defined(__linux__) && defined(__NR_getcpu)
|
2012-05-29 21:49:35 +02:00
|
|
|
int res = syscall(__NR_getcpu, &processor, NULL, NULL);
|
2012-05-18 01:03:31 +02:00
|
|
|
if (res != -1) return processor;
|
|
|
|
#endif
|
|
|
|
|
2012-05-17 19:28:33 +02:00
|
|
|
if (NtCurrentTeb()->Peb->NumberOfProcessors > 1)
|
|
|
|
{
|
|
|
|
ULONG_PTR thread_mask, processor_mask;
|
|
|
|
NTSTATUS status;
|
|
|
|
|
|
|
|
status = NtQueryInformationThread(GetCurrentThread(), ThreadAffinityMask,
|
|
|
|
&thread_mask, sizeof(thread_mask), NULL);
|
|
|
|
if (status == STATUS_SUCCESS)
|
|
|
|
{
|
|
|
|
for (processor = 0; processor < NtCurrentTeb()->Peb->NumberOfProcessors; processor++)
|
|
|
|
{
|
|
|
|
processor_mask = (1 << processor);
|
|
|
|
if (thread_mask & processor_mask)
|
|
|
|
{
|
|
|
|
if (thread_mask != processor_mask)
|
|
|
|
FIXME("need multicore support (%d processors)\n",
|
|
|
|
NtCurrentTeb()->Peb->NumberOfProcessors);
|
|
|
|
return processor;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-05-17 19:28:31 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/* fallback to the first processor */
|
|
|
|
return 0;
|
|
|
|
}
|