ntdll: Move the thread get/set information functions to the Unix library.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
44a230937b
commit
e84ec36a62
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.@]
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in New Issue