forked from Mirrors/wine-wine
ntdll: Move the thread get/set information functions to the Unix library.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>feature/deterministic
parent
44a230937b
commit
e84ec36a62
|
@ -3629,8 +3629,6 @@ void WINAPI LdrShutdownThread(void)
|
||||||
|
|
||||||
RtlAcquirePebLock();
|
RtlAcquirePebLock();
|
||||||
RemoveEntryList( &NtCurrentTeb()->TlsLinks );
|
RemoveEntryList( &NtCurrentTeb()->TlsLinks );
|
||||||
RtlReleasePebLock();
|
|
||||||
|
|
||||||
if ((pointers = NtCurrentTeb()->ThreadLocalStoragePointer))
|
if ((pointers = NtCurrentTeb()->ThreadLocalStoragePointer))
|
||||||
{
|
{
|
||||||
for (i = 0; i < tls_module_count; i++) RtlFreeHeap( GetProcessHeap(), 0, pointers[i] );
|
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()->FlsSlots );
|
||||||
RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->TlsExpansionSlots );
|
RtlFreeHeap( GetProcessHeap(), 0, NtCurrentTeb()->TlsExpansionSlots );
|
||||||
|
NtCurrentTeb()->TlsExpansionSlots = NULL;
|
||||||
|
RtlReleasePebLock();
|
||||||
|
|
||||||
RtlLeaveCriticalSection( &loader_section );
|
RtlLeaveCriticalSection( &loader_section );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -55,7 +55,6 @@ struct drive_info
|
||||||
};
|
};
|
||||||
|
|
||||||
extern NTSTATUS close_handle( HANDLE ) DECLSPEC_HIDDEN;
|
extern NTSTATUS close_handle( HANDLE ) DECLSPEC_HIDDEN;
|
||||||
extern ULONG_PTR get_system_affinity_mask(void) DECLSPEC_HIDDEN;
|
|
||||||
|
|
||||||
/* exceptions */
|
/* exceptions */
|
||||||
extern LONG call_vectored_handlers( EXCEPTION_RECORD *rec, CONTEXT *context ) DECLSPEC_HIDDEN;
|
extern LONG call_vectored_handlers( EXCEPTION_RECORD *rec, CONTEXT *context ) DECLSPEC_HIDDEN;
|
||||||
|
|
|
@ -85,13 +85,6 @@ HANDLE CDECL __wine_make_process_system(void)
|
||||||
return ret;
|
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.@]
|
* NtQueryInformationProcess [NTDLL.@]
|
||||||
* ZwQueryInformationProcess [NTDLL.@]
|
* ZwQueryInformationProcess [NTDLL.@]
|
||||||
|
|
|
@ -45,7 +45,6 @@
|
||||||
#include "ddk/wdm.h"
|
#include "ddk/wdm.h"
|
||||||
#include "wine/exception.h"
|
#include "wine/exception.h"
|
||||||
|
|
||||||
WINE_DEFAULT_DEBUG_CHANNEL(thread);
|
|
||||||
WINE_DECLARE_DEBUG_CHANNEL(relay);
|
WINE_DECLARE_DEBUG_CHANNEL(relay);
|
||||||
|
|
||||||
struct _KUSER_SHARED_DATA *user_shared_data = (void *)0x7ffe0000;
|
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,
|
NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
|
||||||
void *data, ULONG length, ULONG *ret_len )
|
void *data, ULONG length, ULONG *ret_len )
|
||||||
{
|
{
|
||||||
NTSTATUS status;
|
return unix_funcs->NtQueryInformationThread( handle, class, data, length, ret_len );
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -819,173 +586,7 @@ NTSTATUS WINAPI NtQueryInformationThread( HANDLE handle, THREADINFOCLASS class,
|
||||||
NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
|
NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
|
||||||
LPCVOID data, ULONG length )
|
LPCVOID data, ULONG length )
|
||||||
{
|
{
|
||||||
NTSTATUS status;
|
return unix_funcs->NtSetInformationThread( handle, class, data, length );
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
|
@ -996,36 +597,5 @@ NTSTATUS WINAPI NtSetInformationThread( HANDLE handle, THREADINFOCLASS class,
|
||||||
*/
|
*/
|
||||||
ULONG WINAPI NtGetCurrentProcessorNumber(void)
|
ULONG WINAPI NtGetCurrentProcessorNumber(void)
|
||||||
{
|
{
|
||||||
ULONG processor;
|
return unix_funcs->NtGetCurrentProcessorNumber();
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -868,6 +868,7 @@ static struct unix_funcs unix_funcs =
|
||||||
NtFreeVirtualMemory,
|
NtFreeVirtualMemory,
|
||||||
NtFsControlFile,
|
NtFsControlFile,
|
||||||
NtGetContextThread,
|
NtGetContextThread,
|
||||||
|
NtGetCurrentProcessorNumber,
|
||||||
NtGetWriteWatch,
|
NtGetWriteWatch,
|
||||||
NtIsProcessInJob,
|
NtIsProcessInJob,
|
||||||
NtLockVirtualMemory,
|
NtLockVirtualMemory,
|
||||||
|
@ -892,6 +893,7 @@ static struct unix_funcs unix_funcs =
|
||||||
NtQueryInformationFile,
|
NtQueryInformationFile,
|
||||||
NtQueryInformationJobObject,
|
NtQueryInformationJobObject,
|
||||||
NtQueryInformationProcess,
|
NtQueryInformationProcess,
|
||||||
|
NtQueryInformationThread,
|
||||||
NtQueryIoCompletion,
|
NtQueryIoCompletion,
|
||||||
NtQueryMutant,
|
NtQueryMutant,
|
||||||
NtQueryPerformanceCounter,
|
NtQueryPerformanceCounter,
|
||||||
|
@ -919,6 +921,7 @@ static struct unix_funcs unix_funcs =
|
||||||
NtSetInformationFile,
|
NtSetInformationFile,
|
||||||
NtSetInformationJobObject,
|
NtSetInformationJobObject,
|
||||||
NtSetInformationProcess,
|
NtSetInformationProcess,
|
||||||
|
NtSetInformationThread,
|
||||||
NtSetIoCompletion,
|
NtSetIoCompletion,
|
||||||
NtSetLdtEntries,
|
NtSetLdtEntries,
|
||||||
NtSetSystemTime,
|
NtSetSystemTime,
|
||||||
|
@ -975,7 +978,6 @@ static struct unix_funcs unix_funcs =
|
||||||
init_threading,
|
init_threading,
|
||||||
exit_thread,
|
exit_thread,
|
||||||
exit_process,
|
exit_process,
|
||||||
get_thread_ldt_entry,
|
|
||||||
exec_process,
|
exec_process,
|
||||||
wine_server_call,
|
wine_server_call,
|
||||||
server_send_fd,
|
server_send_fd,
|
||||||
|
|
|
@ -781,7 +781,7 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *sigcontext )
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* get_thread_ldt_entry
|
* 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;
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -695,7 +695,7 @@ static void usr2_handler( int signal, siginfo_t *siginfo, void *sigcontext )
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* get_thread_ldt_entry
|
* 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;
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -2039,7 +2039,7 @@ static void ldt_set_fs( WORD sel, TEB *teb )
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* get_thread_ldt_entry
|
* 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;
|
THREAD_DESCRIPTOR_INFORMATION *info = data;
|
||||||
NTSTATUS status = STATUS_SUCCESS;
|
NTSTATUS status = STATUS_SUCCESS;
|
||||||
|
|
|
@ -1245,7 +1245,7 @@ static void usr1_handler( int signal, siginfo_t *siginfo, void *ucontext )
|
||||||
/**********************************************************************
|
/**********************************************************************
|
||||||
* get_thread_ldt_entry
|
* 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;
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
|
@ -89,7 +89,6 @@ TEB * CDECL init_threading( int *nb_threads_ptr, struct ldt_copy **ldt_copy, SIZ
|
||||||
{
|
{
|
||||||
TEB *teb;
|
TEB *teb;
|
||||||
SIZE_T info_size;
|
SIZE_T info_size;
|
||||||
struct ntdll_thread_data *thread_data;
|
|
||||||
#ifdef __i386__
|
#ifdef __i386__
|
||||||
extern struct ldt_copy __wine_ldt_copy;
|
extern struct ldt_copy __wine_ldt_copy;
|
||||||
*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;
|
nb_threads = nb_threads_ptr;
|
||||||
|
|
||||||
teb = virtual_alloc_first_teb();
|
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_init_threading();
|
||||||
signal_alloc_thread( teb );
|
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 = (struct ntdll_thread_data *)&teb->GdiTebBatch;
|
||||||
thread_data->request_fd = request_pipe[1];
|
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;
|
thread_data->start_stack = (char *)teb->Tib.StackBase;
|
||||||
|
|
||||||
pthread_attr_init( &pthread_attr );
|
pthread_attr_init( &pthread_attr );
|
||||||
|
@ -673,3 +664,434 @@ NTSTATUS get_thread_context( HANDLE handle, context_t *context, unsigned int fla
|
||||||
}
|
}
|
||||||
return ret;
|
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;
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@
|
||||||
#define __NTDLL_UNIX_PRIVATE_H
|
#define __NTDLL_UNIX_PRIVATE_H
|
||||||
|
|
||||||
#include "unixlib.h"
|
#include "unixlib.h"
|
||||||
|
#include "wine/list.h"
|
||||||
|
|
||||||
#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
|
#ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_8
|
||||||
#define InterlockedCompareExchange64(dest,xchg,cmp) RtlInterlockedCompareExchange64(dest,xchg,cmp)
|
#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 */
|
int wait_fd[2]; /* fd for sleeping server requests */
|
||||||
BOOL wow64_redir; /* Wow64 filesystem redirection flag */
|
BOOL wow64_redir; /* Wow64 filesystem redirection flag */
|
||||||
pthread_t pthread_id; /* pthread thread id */
|
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) );
|
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;
|
timeout_t *start_time ) DECLSPEC_HIDDEN;
|
||||||
extern void CDECL DECLSPEC_NORETURN exit_thread( int status ) 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 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 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,
|
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 TEB *virtual_alloc_first_teb(void) DECLSPEC_HIDDEN;
|
||||||
extern NTSTATUS virtual_alloc_teb( TEB **ret_teb ) DECLSPEC_HIDDEN;
|
extern NTSTATUS virtual_alloc_teb( TEB **ret_teb ) DECLSPEC_HIDDEN;
|
||||||
extern void virtual_free_teb( TEB *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 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 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;
|
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,
|
extern void virtual_fill_image_information( const pe_image_info_t *pe_info,
|
||||||
SECTION_IMAGE_INFORMATION *info ) DECLSPEC_HIDDEN;
|
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 void signal_init_threading(void) DECLSPEC_HIDDEN;
|
||||||
extern NTSTATUS signal_alloc_thread( TEB *teb ) DECLSPEC_HIDDEN;
|
extern NTSTATUS signal_alloc_thread( TEB *teb ) DECLSPEC_HIDDEN;
|
||||||
extern void signal_free_thread( TEB *teb ) DECLSPEC_HIDDEN;
|
extern void signal_free_thread( TEB *teb ) DECLSPEC_HIDDEN;
|
||||||
|
|
|
@ -170,6 +170,7 @@ static SIZE_T signal_stack_align;
|
||||||
static TEB *teb_block;
|
static TEB *teb_block;
|
||||||
static TEB *next_free_teb;
|
static TEB *next_free_teb;
|
||||||
static int teb_block_pos;
|
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_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)
|
#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
|
* virtual_alloc_first_teb
|
||||||
*/
|
*/
|
||||||
|
@ -2566,13 +2586,7 @@ TEB *virtual_alloc_first_teb(void)
|
||||||
peb = (PEB *)((char *)teb_block + 32 * teb_size - peb_size);
|
peb = (PEB *)((char *)teb_block + 32 * teb_size - peb_size);
|
||||||
NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&teb, 0, &teb_size, MEM_COMMIT, PAGE_READWRITE );
|
NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&teb, 0, &teb_size, MEM_COMMIT, PAGE_READWRITE );
|
||||||
NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&peb, 0, &peb_size, MEM_COMMIT, PAGE_READWRITE );
|
NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&peb, 0, &peb_size, MEM_COMMIT, PAGE_READWRITE );
|
||||||
|
init_teb( teb, peb );
|
||||||
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);
|
|
||||||
use_locks = TRUE;
|
use_locks = TRUE;
|
||||||
return teb;
|
return teb;
|
||||||
}
|
}
|
||||||
|
@ -2615,14 +2629,10 @@ NTSTATUS virtual_alloc_teb( TEB **ret_teb )
|
||||||
NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&teb, 0, &teb_size,
|
NtAllocateVirtualMemory( NtCurrentProcess(), (void **)&teb, 0, &teb_size,
|
||||||
MEM_COMMIT, PAGE_READWRITE );
|
MEM_COMMIT, PAGE_READWRITE );
|
||||||
}
|
}
|
||||||
|
init_teb( teb, NtCurrentTeb()->Peb );
|
||||||
|
*ret_teb = teb;
|
||||||
server_leave_uninterrupted_section( &csVirtual, &sigset );
|
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 )))
|
if ((status = signal_alloc_thread( teb )))
|
||||||
{
|
{
|
||||||
server_enter_uninterrupted_section( &csVirtual, &sigset );
|
server_enter_uninterrupted_section( &csVirtual, &sigset );
|
||||||
|
@ -2656,12 +2666,49 @@ void virtual_free_teb( TEB *teb )
|
||||||
}
|
}
|
||||||
|
|
||||||
server_enter_uninterrupted_section( &csVirtual, &sigset );
|
server_enter_uninterrupted_section( &csVirtual, &sigset );
|
||||||
|
list_remove( &thread_data->entry );
|
||||||
*(TEB **)teb = next_free_teb;
|
*(TEB **)teb = next_free_teb;
|
||||||
next_free_teb = teb;
|
next_free_teb = teb;
|
||||||
server_leave_uninterrupted_section( &csVirtual, &sigset );
|
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
|
* virtual_alloc_thread_stack
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -28,7 +28,7 @@ struct ldt_copy;
|
||||||
struct msghdr;
|
struct msghdr;
|
||||||
|
|
||||||
/* increment this when you change the function table */
|
/* increment this when you change the function table */
|
||||||
#define NTDLL_UNIXLIB_VERSION 53
|
#define NTDLL_UNIXLIB_VERSION 54
|
||||||
|
|
||||||
struct unix_funcs
|
struct unix_funcs
|
||||||
{
|
{
|
||||||
|
@ -105,6 +105,7 @@ struct unix_funcs
|
||||||
void *in_buffer, ULONG in_size,
|
void *in_buffer, ULONG in_size,
|
||||||
void *out_buffer, ULONG out_size );
|
void *out_buffer, ULONG out_size );
|
||||||
NTSTATUS (WINAPI *NtGetContextThread)( HANDLE handle, CONTEXT *context );
|
NTSTATUS (WINAPI *NtGetContextThread)( HANDLE handle, CONTEXT *context );
|
||||||
|
ULONG (WINAPI *NtGetCurrentProcessorNumber)(void);
|
||||||
NTSTATUS (WINAPI *NtGetWriteWatch)( HANDLE process, ULONG flags, PVOID base, SIZE_T size,
|
NTSTATUS (WINAPI *NtGetWriteWatch)( HANDLE process, ULONG flags, PVOID base, SIZE_T size,
|
||||||
PVOID *addresses, ULONG_PTR *count, ULONG *granularity );
|
PVOID *addresses, ULONG_PTR *count, ULONG *granularity );
|
||||||
NTSTATUS (WINAPI *NtIsProcessInJob)( HANDLE process, HANDLE job );
|
NTSTATUS (WINAPI *NtIsProcessInJob)( HANDLE process, HANDLE job );
|
||||||
|
@ -154,6 +155,8 @@ struct unix_funcs
|
||||||
void *info, ULONG len, ULONG *ret_len );
|
void *info, ULONG len, ULONG *ret_len );
|
||||||
NTSTATUS (WINAPI *NtQueryInformationProcess)( HANDLE handle, PROCESSINFOCLASS class, void *info,
|
NTSTATUS (WINAPI *NtQueryInformationProcess)( HANDLE handle, PROCESSINFOCLASS class, void *info,
|
||||||
ULONG size, ULONG *ret_len );
|
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,
|
NTSTATUS (WINAPI *NtQueryIoCompletion)( HANDLE handle, IO_COMPLETION_INFORMATION_CLASS class,
|
||||||
void *buffer, ULONG len, ULONG *ret_len );
|
void *buffer, ULONG len, ULONG *ret_len );
|
||||||
NTSTATUS (WINAPI *NtQueryMutant)( HANDLE handle, MUTANT_INFORMATION_CLASS class,
|
NTSTATUS (WINAPI *NtQueryMutant)( HANDLE handle, MUTANT_INFORMATION_CLASS class,
|
||||||
|
@ -202,6 +205,8 @@ struct unix_funcs
|
||||||
void *info, ULONG len );
|
void *info, ULONG len );
|
||||||
NTSTATUS (WINAPI *NtSetInformationProcess)( HANDLE handle, PROCESSINFOCLASS class,
|
NTSTATUS (WINAPI *NtSetInformationProcess)( HANDLE handle, PROCESSINFOCLASS class,
|
||||||
void *info, ULONG size );
|
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 (WINAPI *NtSetIoCompletion)( HANDLE handle, ULONG_PTR key, ULONG_PTR value,
|
||||||
NTSTATUS status, SIZE_T count );
|
NTSTATUS status, SIZE_T count );
|
||||||
NTSTATUS (WINAPI *NtSetLdtEntries)( ULONG sel1, LDT_ENTRY entry1, ULONG sel2, LDT_ENTRY entry2 );
|
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 );
|
BOOL *suspend, unsigned int *cpus, BOOL *wow64, timeout_t *start_time );
|
||||||
void (CDECL *exit_thread)( int status );
|
void (CDECL *exit_thread)( int status );
|
||||||
void (CDECL *exit_process)( 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 );
|
NTSTATUS (CDECL *exec_process)( UNICODE_STRING *path, UNICODE_STRING *cmdline, NTSTATUS status );
|
||||||
|
|
||||||
/* server functions */
|
/* server functions */
|
||||||
|
|
Loading…
Reference in New Issue