ntdll: Move the thread get/set information functions to the Unix library.

Signed-off-by: Alexandre Julliard <julliard@winehq.org>
feature/deterministic
Alexandre Julliard 2020-06-18 12:37:50 +02:00
parent 44a230937b
commit e84ec36a62
13 changed files with 514 additions and 473 deletions

View File

@ -3629,8 +3629,6 @@ void WINAPI LdrShutdownThread(void)
RtlAcquirePebLock();
RemoveEntryList( &NtCurrentTeb()->TlsLinks );
RtlReleasePebLock();
if ((pointers = NtCurrentTeb()->ThreadLocalStoragePointer))
{
for (i = 0; i < tls_module_count; i++) RtlFreeHeap( GetProcessHeap(), 0, pointers[i] );
@ -3638,6 +3636,9 @@ void WINAPI LdrShutdownThread(void)
}
RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->FlsSlots );
RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->TlsExpansionSlots );
NtCurrentTeb()->TlsExpansionSlots = NULL;
RtlReleasePebLock();
RtlLeaveCriticalSection( &loader_section );
}

View File

@ -55,7 +55,6 @@ struct drive_info
};
extern NTSTATUS close_handle( HANDLE ) DECLSPEC_HIDDEN;
extern ULONG_PTR get_system_affinity_mask(void) DECLSPEC_HIDDEN;
/* exceptions */
extern LONG call_vectored_handlers( EXCEPTION_RECORD *rec, CONTEXT *context ) DECLSPEC_HIDDEN;

View File

@ -85,13 +85,6 @@ HANDLE CDECL __wine_make_process_system(void)
return ret;
}
ULONG_PTR get_system_affinity_mask(void)
{
ULONG num_cpus = NtCurrentTeb()->Peb->NumberOfProcessors;
if (num_cpus >= sizeof(ULONG_PTR) * 8) return ~(ULONG_PTR)0;
return ((ULONG_PTR)1 << num_cpus) - 1;
}
/******************************************************************************
* NtQueryInformationProcess [NTDLL.@]
* ZwQueryInformationProcess [NTDLL.@]

View File

@ -45,7 +45,6 @@
#include "ddk/wdm.h"
#include "wine/exception.h"
WINE_DEFAULT_DEBUG_CHANNEL(thread);
WINE_DECLARE_DEBUG_CHANNEL(relay);
struct _KUSER_SHARED_DATA *user_shared_data = (void *)0x7ffe0000;
@ -576,239 +575,7 @@ NTSTATUS WINAPI NtSetLdtEntries( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_E
NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
void *data, ULONG length, ULONG *ret_len )
{
NTSTATUS status;
switch(class)
{
case ThreadBasicInformation:
{
THREAD_BASIC_INFORMATION info;
const ULONG_PTR affinity_mask = get_system_affinity_mask();
SERVER_START_REQ( get_thread_info )
{
req->handle = wine_server_obj_handle( handle );
req->tid_in = 0;
if (!(status = wine_server_call( req )))
{
info.ExitStatus = reply->exit_code;
info.TebBaseAddress = wine_server_get_ptr( reply->teb );
info.ClientId.UniqueProcess = ULongToHandle(reply->pid);
info.ClientId.UniqueThread = ULongToHandle(reply->tid);
info.AffinityMask = reply->affinity & affinity_mask;
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;
case ThreadAffinityMask:
{
const ULONG_PTR affinity_mask = get_system_affinity_mask();
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;
case ThreadTimes:
{
KERNEL_USER_TIMES kusrt;
SERVER_START_REQ( get_thread_times )
{
req->handle = wine_server_obj_handle( handle );
status = wine_server_call( req );
if (status == STATUS_SUCCESS)
{
kusrt.CreateTime.QuadPart = reply->creation_time;
kusrt.ExitTime.QuadPart = reply->exit_time;
}
}
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
{
static BOOL reported = FALSE;
kusrt.KernelTime.QuadPart = 0;
kusrt.UserTime.QuadPart = 0;
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;
}
}
if (data) memcpy( data, &kusrt, min( length, sizeof(kusrt) ));
if (ret_len) *ret_len = min( length, sizeof(kusrt) );
}
}
return status;
case ThreadDescriptorTableEntry:
return unix_funcs->get_thread_ldt_entry( handle, data, length, ret_len );
case ThreadAmILastThread:
{
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)
{
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;
}
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;
}
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;
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;
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;
}
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)
{
info->Description.Length = info->Description.MaximumLength = desc_len;
info->Description.Buffer = ptr;
}
if (ret_len && (status == STATUS_SUCCESS || status == STATUS_BUFFER_TOO_SMALL))
*ret_len = sizeof(*info) + desc_len;
}
return status;
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;
}
return unix_funcs->NtQueryInformationThread( handle, class, data, length, ret_len );
}
@ -819,173 +586,7 @@ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
LPCVOID data, ULONG length )
{
NTSTATUS status;
switch(class)
{
case ThreadZeroTlsCell:
if (handle == GetCurrentThread())
{
LIST_ENTRY *entry;
DWORD index;
if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
index = *(const DWORD *)data;
if (index < TLS_MINIMUM_AVAILABLE)
{
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();
}
return STATUS_SUCCESS;
}
FIXME( "ZeroTlsCell not supported on other threads\n" );
return STATUS_NOT_IMPLEMENTED;
case ThreadImpersonationToken:
{
const HANDLE *phToken = data;
if (length != sizeof(HANDLE)) return STATUS_INVALID_PARAMETER;
TRACE("Setting ThreadImpersonationToken handle to %p\n", *phToken );
SERVER_START_REQ( set_thread_info )
{
req->handle = wine_server_obj_handle( handle );
req->token = wine_server_obj_handle( *phToken );
req->mask = SET_THREAD_INFO_TOKEN;
status = wine_server_call( req );
}
SERVER_END_REQ;
}
return status;
case ThreadBasePriority:
{
const DWORD *pprio = data;
if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
SERVER_START_REQ( set_thread_info )
{
req->handle = wine_server_obj_handle( handle );
req->priority = *pprio;
req->mask = SET_THREAD_INFO_PRIORITY;
status = wine_server_call( req );
}
SERVER_END_REQ;
}
return status;
case ThreadAffinityMask:
{
const ULONG_PTR affinity_mask = get_system_affinity_mask();
ULONG_PTR req_aff;
if (length != sizeof(ULONG_PTR)) return STATUS_INVALID_PARAMETER;
req_aff = *(const ULONG_PTR *)data & affinity_mask;
if (!req_aff) return STATUS_INVALID_PARAMETER;
SERVER_START_REQ( set_thread_info )
{
req->handle = wine_server_obj_handle( handle );
req->affinity = req_aff;
req->mask = SET_THREAD_INFO_AFFINITY;
status = wine_server_call( req );
}
SERVER_END_REQ;
}
return status;
case ThreadHideFromDebugger:
/* pretend the call succeeded to satisfy some code protectors */
return STATUS_SUCCESS;
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;
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;
case ThreadDescription:
{
const THREAD_DESCRIPTION_INFORMATION *info = data;
if (length != sizeof(*info)) return STATUS_INFO_LENGTH_MISMATCH;
if (!info) return STATUS_ACCESS_VIOLATION;
if (info->Description.Length != info->Description.MaximumLength) return STATUS_INVALID_PARAMETER;
if (info->Description.Length && !info->Description.Buffer) return STATUS_ACCESS_VIOLATION;
SERVER_START_REQ( set_thread_info )
{
req->handle = wine_server_obj_handle( handle );
req->mask = SET_THREAD_INFO_DESCRIPTION;
wine_server_add_data( req, info->Description.Buffer, info->Description.Length );
status = wine_server_call( req );
}
SERVER_END_REQ;
}
return status;
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;
}
return unix_funcs->NtSetInformationThread( handle, class, data, length );
}
/******************************************************************************
@ -996,36 +597,5 @@ NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
*/
ULONG WINAPI NtGetCurrentProcessorNumber(void)
{
ULONG processor;
#if defined(__linux__) && defined(__NR_getcpu)
int res = syscall(__NR_getcpu, &processor, NULL, NULL);
if (res != -1) return processor;
#endif
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;
}
}
}
}
/* fallback to the first processor */
return 0;
return unix_funcs->NtGetCurrentProcessorNumber();
}

View File

@ -868,6 +868,7 @@ static struct unix_funcs unix_funcs =
NtFreeVirtualMemory,
NtFsControlFile,
NtGetContextThread,
NtGetCurrentProcessorNumber,
NtGetWriteWatch,
NtIsProcessInJob,
NtLockVirtualMemory,
@ -892,6 +893,7 @@ static struct unix_funcs unix_funcs =
NtQueryInformationFile,
NtQueryInformationJobObject,
NtQueryInformationProcess,
NtQueryInformationThread,
NtQueryIoCompletion,
NtQueryMutant,
NtQueryPerformanceCounter,
@ -919,6 +921,7 @@ static struct unix_funcs unix_funcs =
NtSetInformationFile,
NtSetInformationJobObject,
NtSetInformationProcess,
NtSetInformationThread,
NtSetIoCompletion,
NtSetLdtEntries,
NtSetSystemTime,
@ -975,7 +978,6 @@ static struct unix_funcs unix_funcs =
init_threading,
exit_thread,
exit_process,
get_thread_ldt_entry,
exec_process,
wine_server_call,
server_send_fd,

View File

@ -781,7 +781,7 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext )
/**********************************************************************
* get_thread_ldt_entry
*/
NTSTATUS CDECL get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
{
return STATUS_NOT_IMPLEMENTED;
}

View File

@ -695,7 +695,7 @@ static void usr2_handler( int signal, siginfo_t *siginfo, void *sigcontext )
/**********************************************************************
* get_thread_ldt_entry
*/
NTSTATUS CDECL get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
{
return STATUS_NOT_IMPLEMENTED;
}

View File

@ -2039,7 +2039,7 @@ static void ldt_set_fs( WORD sel, TEB *teb )
/**********************************************************************
* get_thread_ldt_entry
*/
NTSTATUS CDECL get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
{
THREAD_DESCRIPTOR_INFORMATION *info = data;
NTSTATUS status = STATUS_SUCCESS;

View File

@ -1245,7 +1245,7 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *ucontext )
/**********************************************************************
* get_thread_ldt_entry
*/
NTSTATUS CDECL get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len )
{
return STATUS_NOT_IMPLEMENTED;
}

View File

@ -89,7 +89,6 @@ TEB * CDECL init_threading( int *nb_threads_ptr, struct ldt_copy **ldt_copy, SIZ
{
TEB *teb;
SIZE_T info_size;
struct ntdll_thread_data *thread_data;
#ifdef __i386__
extern struct ldt_copy __wine_ldt_copy;
*ldt_copy = &__wine_ldt_copy;
@ -97,11 +96,6 @@ TEB * CDECL init_threading( int *nb_threads_ptr, struct ldt_copy **ldt_copy, SIZ
nb_threads = nb_threads_ptr;
teb = virtual_alloc_first_teb();
thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
thread_data->request_fd = -1;
thread_data->reply_fd = -1;
thread_data->wait_fd[0] = -1;
thread_data->wait_fd[1] = -1;
signal_init_threading();
signal_alloc_thread( teb );
@ -288,9 +282,6 @@ NTSTATUS WINAPI NtCreateThreadEx( HANDLE *handle, ACCESS_MASK access, OBJECT_ATT
thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
thread_data->request_fd = request_pipe[1];
thread_data->reply_fd = -1;
thread_data->wait_fd[0] = -1;
thread_data->wait_fd[1] = -1;
thread_data->start_stack = (char *)teb->Tib.StackBase;
pthread_attr_init( &pthread_attr );
@ -673,3 +664,434 @@ NTSTATUS get_thread_context( HANDLE handle, context_t *context, unsigned int fla
}
return ret;
}
/******************************************************************************
* NtQueryInformationThread (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;
const ULONG_PTR affinity_mask = get_system_affinity_mask();
SERVER_START_REQ( get_thread_info )
{
req->handle = wine_server_obj_handle( handle );
req->tid_in = 0;
if (!(status = wine_server_call( req )))
{
info.ExitStatus = reply->exit_code;
info.TebBaseAddress = wine_server_get_ptr( reply->teb );
info.ClientId.UniqueProcess = ULongToHandle(reply->pid);
info.ClientId.UniqueThread = ULongToHandle(reply->tid);
info.AffinityMask = reply->affinity & affinity_mask;
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;
}
case ThreadAffinityMask:
{
const ULONG_PTR affinity_mask = get_system_affinity_mask();
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;
}
case ThreadTimes:
{
KERNEL_USER_TIMES kusrt;
SERVER_START_REQ( get_thread_times )
{
req->handle = wine_server_obj_handle( handle );
status = wine_server_call( req );
if (status == STATUS_SUCCESS)
{
kusrt.CreateTime.QuadPart = reply->creation_time;
kusrt.ExitTime.QuadPart = reply->exit_time;
}
}
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
{
static BOOL reported = FALSE;
kusrt.KernelTime.QuadPart = 0;
kusrt.UserTime.QuadPart = 0;
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;
}
}
if (data) memcpy( data, &kusrt, min( length, sizeof(kusrt) ));
if (ret_len) *ret_len = min( length, sizeof(kusrt) );
}
return status;
}
case ThreadDescriptorTableEntry:
return get_thread_ldt_entry( handle, data, length, ret_len );
case ThreadAmILastThread:
{
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)
{
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;
}
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;
}
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;
}
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;
case ThreadSuspendCount:
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 ))) *(ULONG *)data = reply->suspend_count;
}
SERVER_END_REQ;
return status;
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)
{
info->Description.Length = info->Description.MaximumLength = desc_len;
info->Description.Buffer = ptr;
}
if (ret_len && (status == STATUS_SUCCESS || status == STATUS_BUFFER_TOO_SMALL))
*ret_len = sizeof(*info) + desc_len;
return status;
}
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;
}
}
/******************************************************************************
* NtSetInformationThread (NTDLL.@)
*/
NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
const void *data, ULONG length )
{
NTSTATUS status;
switch (class)
{
case ThreadZeroTlsCell:
if (handle == GetCurrentThread())
{
if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
return virtual_clear_tls_index( *(const ULONG *)data );
}
FIXME( "ZeroTlsCell not supported on other threads\n" );
return STATUS_NOT_IMPLEMENTED;
case ThreadImpersonationToken:
{
const HANDLE *token = data;
if (length != sizeof(HANDLE)) return STATUS_INVALID_PARAMETER;
TRACE("Setting ThreadImpersonationToken handle to %p\n", *token );
SERVER_START_REQ( set_thread_info )
{
req->handle = wine_server_obj_handle( handle );
req->token = wine_server_obj_handle( *token );
req->mask = SET_THREAD_INFO_TOKEN;
status = wine_server_call( req );
}
SERVER_END_REQ;
return status;
}
case ThreadBasePriority:
{
const DWORD *pprio = data;
if (length != sizeof(DWORD)) return STATUS_INVALID_PARAMETER;
SERVER_START_REQ( set_thread_info )
{
req->handle = wine_server_obj_handle( handle );
req->priority = *pprio;
req->mask = SET_THREAD_INFO_PRIORITY;
status = wine_server_call( req );
}
SERVER_END_REQ;
return status;
}
case ThreadAffinityMask:
{
const ULONG_PTR affinity_mask = get_system_affinity_mask();
ULONG_PTR req_aff;
if (length != sizeof(ULONG_PTR)) return STATUS_INVALID_PARAMETER;
req_aff = *(const ULONG_PTR *)data & affinity_mask;
if (!req_aff) return STATUS_INVALID_PARAMETER;
SERVER_START_REQ( set_thread_info )
{
req->handle = wine_server_obj_handle( handle );
req->affinity = req_aff;
req->mask = SET_THREAD_INFO_AFFINITY;
status = wine_server_call( req );
}
SERVER_END_REQ;
return status;
}
case ThreadHideFromDebugger:
/* pretend the call succeeded to satisfy some code protectors */
return STATUS_SUCCESS;
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;
}
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;
}
case ThreadDescription:
{
const THREAD_DESCRIPTION_INFORMATION *info = data;
if (length != sizeof(*info)) return STATUS_INFO_LENGTH_MISMATCH;
if (!info) return STATUS_ACCESS_VIOLATION;
if (info->Description.Length != info->Description.MaximumLength) return STATUS_INVALID_PARAMETER;
if (info->Description.Length && !info->Description.Buffer) return STATUS_ACCESS_VIOLATION;
SERVER_START_REQ( set_thread_info )
{
req->handle = wine_server_obj_handle( handle );
req->mask = SET_THREAD_INFO_DESCRIPTION;
wine_server_add_data( req, info->Description.Buffer, info->Description.Length );
status = wine_server_call( req );
}
SERVER_END_REQ;
return status;
}
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;
}
}
/******************************************************************************
* NtGetCurrentProcessorNumber (NTDLL.@)
*/
ULONG WINAPI NtGetCurrentProcessorNumber(void)
{
ULONG processor;
#if defined(__linux__) && defined(__NR_getcpu)
int res = syscall(__NR_getcpu, &processor, NULL, NULL);
if (res != -1) return processor;
#endif
if (NtCurrentTeb()->Peb->NumberOfProcessors > 1)
{
ULONG_PTR thread_mask, processor_mask;
if (!NtQueryInformationThread( GetCurrentThread(), ThreadAffinityMask,
&thread_mask, sizeof(thread_mask), NULL ))
{
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;
}
}
}
}
/* fallback to the first processor */
return 0;
}

View File

@ -22,6 +22,7 @@
#define __NTDLL_UNIX_PRIVATE_H
#include "unixlib.h"
#include "wine/list.h"
#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
#define InterlockedCompareExchange64(dest,xchg,cmp) RtlInterlockedCompareExchange64(dest,xchg,cmp)
@ -45,6 +46,7 @@ struct ntdll_thread_data
int wait_fd[2]; /* fd for sleeping server requests */
BOOL wow64_redir; /* Wow64 filesystem redirection flag */
pthread_t pthread_id; /* pthread thread id */
struct list entry; /* entry in TEB list */
};
C_ASSERT( sizeof(struct ntdll_thread_data) <= sizeof(((TEB *)0)->GdiTebBatch) );
@ -113,7 +115,6 @@ extern TEB * CDECL init_threading( int *nb_threads_ptr, struct ldt_copy **ldt_co
timeout_t *start_time ) DECLSPEC_HIDDEN;
extern void CDECL DECLSPEC_NORETURN exit_thread( int status ) DECLSPEC_HIDDEN;
extern void CDECL DECLSPEC_NORETURN exit_process( int status ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL exec_process( UNICODE_STRING *path, UNICODE_STRING *cmdline, NTSTATUS status ) DECLSPEC_HIDDEN;
extern NTSTATUS CDECL nt_to_unix_file_name( const UNICODE_STRING *nameW, ANSI_STRING *unix_name_ret,
@ -173,6 +174,7 @@ extern ULONG_PTR get_system_affinity_mask(void) DECLSPEC_HIDDEN;
extern TEB *virtual_alloc_first_teb(void) DECLSPEC_HIDDEN;
extern NTSTATUS virtual_alloc_teb( TEB **ret_teb ) DECLSPEC_HIDDEN;
extern void virtual_free_teb( TEB *teb ) DECLSPEC_HIDDEN;
extern NTSTATUS virtual_clear_tls_index( ULONG index ) DECLSPEC_HIDDEN;
extern void virtual_map_user_shared_data(void) DECLSPEC_HIDDEN;
extern NTSTATUS virtual_handle_fault( LPCVOID addr, DWORD err, BOOL on_signal_stack ) DECLSPEC_HIDDEN;
extern unsigned int virtual_locked_server_call( void *req_ptr ) DECLSPEC_HIDDEN;
@ -188,6 +190,7 @@ extern void virtual_set_force_exec( BOOL enable ) DECLSPEC_HIDDEN;
extern void virtual_fill_image_information( const pe_image_info_t *pe_info,
SECTION_IMAGE_INFORMATION *info ) DECLSPEC_HIDDEN;
extern NTSTATUS get_thread_ldt_entry( HANDLE handle, void *data, ULONG len, ULONG *ret_len ) DECLSPEC_HIDDEN;
extern void signal_init_threading(void) DECLSPEC_HIDDEN;
extern NTSTATUS signal_alloc_thread( TEB *teb ) DECLSPEC_HIDDEN;
extern void signal_free_thread( TEB *teb ) DECLSPEC_HIDDEN;

View File

@ -170,6 +170,7 @@ static SIZE_T signal_stack_align;
static TEB *teb_block;
static TEB *next_free_teb;
static int teb_block_pos;
static struct list teb_list = LIST_INIT( teb_list );
#define ROUND_ADDR(addr,mask) ((void *)((UINT_PTR)(addr) & ~(UINT_PTR)(mask)))
#define ROUND_SIZE(addr,size) (((SIZE_T)(size) + ((UINT_PTR)(addr) & page_mask) + page_mask) & ~page_mask)
@ -2537,6 +2538,25 @@ NTSTATUS CDECL virtual_create_builtin_view( void *module )
}
/* set some initial values in a new TEB */
static void init_teb( TEB *teb, PEB *peb )
{
struct ntdll_thread_data *thread_data = (struct ntdll_thread_data *)&teb->GdiTebBatch;
teb->Peb = peb;
teb->Tib.Self = &teb->Tib;
teb->Tib.ExceptionList = (void *)~0ul;
teb->Tib.StackBase = (void *)~0ul;
teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer;
teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
thread_data->request_fd = -1;
thread_data->reply_fd = -1;
thread_data->wait_fd[0] = -1;
thread_data->wait_fd[1] = -1;
list_add_head( &teb_list, &thread_data->entry );
}
/***********************************************************************
* virtual_alloc_first_teb
*/
@ -2566,13 +2586,7 @@ TEB *virtual_alloc_first_teb(void)
peb = (PEB *)((char *)teb_block + 32 * teb_size - peb_size);
NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&teb, 0, &teb_size, MEM_COMMIT, PAGE_READWRITE );
NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&peb, 0, &peb_size, MEM_COMMIT, PAGE_READWRITE );
teb->Peb = peb;
teb->Tib.Self = &teb->Tib;
teb->Tib.ExceptionList = (void *)~0ul;
teb->Tib.StackBase = (void *)~0ul;
teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer;
teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
init_teb( teb, peb );
use_locks = TRUE;
return teb;
}
@ -2615,14 +2629,10 @@ NTSTATUS virtual_alloc_teb( TEB **ret_teb )
NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&teb, 0, &teb_size,
MEM_COMMIT, PAGE_READWRITE );
}
init_teb( teb, NtCurrentTeb()->Peb );
*ret_teb = teb;
server_leave_uninterrupted_section( &csVirtual, &sigset );
*ret_teb = teb;
teb->Peb = NtCurrentTeb()->Peb;
teb->Tib.Self = &teb->Tib;
teb->Tib.ExceptionList = (void *)~0UL;
teb->StaticUnicodeString.Buffer = teb->StaticUnicodeBuffer;
teb->StaticUnicodeString.MaximumLength = sizeof(teb->StaticUnicodeBuffer);
if ((status = signal_alloc_thread( teb )))
{
server_enter_uninterrupted_section( &csVirtual, &sigset );
@ -2656,12 +2666,49 @@ void virtual_free_teb( TEB *teb )
}
server_enter_uninterrupted_section( &csVirtual, &sigset );
list_remove( &thread_data->entry );
*(TEB **)teb = next_free_teb;
next_free_teb = teb;
server_leave_uninterrupted_section( &csVirtual, &sigset );
}
/***********************************************************************
* virtual_clear_tls_index
*/
NTSTATUS virtual_clear_tls_index( ULONG index )
{
struct ntdll_thread_data *thread_data;
sigset_t sigset;
if (index < TLS_MINIMUM_AVAILABLE)
{
server_enter_uninterrupted_section( &csVirtual, &sigset );
LIST_FOR_EACH_ENTRY( thread_data, &teb_list, struct ntdll_thread_data, entry )
{
TEB *teb = CONTAINING_RECORD( thread_data, TEB, GdiTebBatch );
teb->TlsSlots[index] = 0;
}
server_leave_uninterrupted_section( &csVirtual, &sigset );
}
else
{
index -= TLS_MINIMUM_AVAILABLE;
if (index >= 8 * sizeof(NtCurrentTeb()->Peb->TlsExpansionBitmapBits))
return STATUS_INVALID_PARAMETER;
server_enter_uninterrupted_section( &csVirtual, &sigset );
LIST_FOR_EACH_ENTRY( thread_data, &teb_list, struct ntdll_thread_data, entry )
{
TEB *teb = CONTAINING_RECORD( thread_data, TEB, GdiTebBatch );
if (teb->TlsExpansionSlots) teb->TlsExpansionSlots[index] = 0;
}
server_leave_uninterrupted_section( &csVirtual, &sigset );
}
return STATUS_SUCCESS;
}
/***********************************************************************
* virtual_alloc_thread_stack
*/

View File

@ -28,7 +28,7 @@ struct ldt_copy;
struct msghdr;
/* increment this when you change the function table */
#define NTDLL_UNIXLIB_VERSION 53
#define NTDLL_UNIXLIB_VERSION 54
struct unix_funcs
{
@ -105,6 +105,7 @@ struct unix_funcs
void *in_buffer, ULONG in_size,
void *out_buffer, ULONG out_size );
NTSTATUS (WINAPI *NtGetContextThread)( HANDLE handle, CONTEXT *context );
ULONG (WINAPI *NtGetCurrentProcessorNumber)(void);
NTSTATUS (WINAPI *NtGetWriteWatch)( HANDLE process, ULONG flags, PVOID base, SIZE_T size,
PVOID *addresses, ULONG_PTR *count, ULONG *granularity );
NTSTATUS (WINAPI *NtIsProcessInJob)( HANDLE process, HANDLE job );
@ -154,6 +155,8 @@ struct unix_funcs
void *info, ULONG len, ULONG *ret_len );
NTSTATUS (WINAPI *NtQueryInformationProcess)( HANDLE handle, PROCESSINFOCLASS class, void *info,
ULONG size, ULONG *ret_len );
NTSTATUS (WINAPI *NtQueryInformationThread)( HANDLE handle, THREADINFOCLASS class,
void *data, ULONG length, ULONG *ret_len );
NTSTATUS (WINAPI *NtQueryIoCompletion)( HANDLE handle, IO_COMPLETION_INFORMATION_CLASS class,
void *buffer, ULONG len, ULONG *ret_len );
NTSTATUS (WINAPI *NtQueryMutant)( HANDLE handle, MUTANT_INFORMATION_CLASS class,
@ -202,6 +205,8 @@ struct unix_funcs
void *info, ULONG len );
NTSTATUS (WINAPI *NtSetInformationProcess)( HANDLE handle, PROCESSINFOCLASS class,
void *info, ULONG size );
NTSTATUS (WINAPI *NtSetInformationThread)( HANDLE handle, THREADINFOCLASS class,
const void *data, ULONG length );
NTSTATUS (WINAPI *NtSetIoCompletion)( HANDLE handle, ULONG_PTR key, ULONG_PTR value,
NTSTATUS status, SIZE_T count );
NTSTATUS (WINAPI *NtSetLdtEntries)( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 );
@ -291,7 +296,6 @@ struct unix_funcs
BOOL *suspend, unsigned int *cpus, BOOL *wow64, timeout_t *start_time );
void (CDECL *exit_thread)( int status );
void (CDECL *exit_process)( int status );
NTSTATUS (CDECL *get_thread_ldt_entry)( HANDLE handle, void *data, ULONG len, ULONG *ret_len );
NTSTATUS (CDECL *exec_process)( UNICODE_STRING *path, UNICODE_STRING *cmdline, NTSTATUS status );
/* server functions */