ntdll: Reimplement NtQuerySystemInformation(SystemProcessInformation) using a single server call.

Signed-off-by: Zebediah Figura <zfigura@codeweavers.com>
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
Zebediah Figura 2020-07-06 21:06:00 -05:00 committed by Alexandre Julliard
parent 7ee7953c54
commit 8622eb326f
6 changed files with 274 additions and 109 deletions

View File

@ -2083,132 +2083,102 @@ NTSTATUS WINAPI NtQuerySystemInformation( SYSTEM_INFORMATION_CLASS class,
case SystemProcessInformation:
{
SYSTEM_PROCESS_INFORMATION *spi = info;
SYSTEM_PROCESS_INFORMATION *last = NULL;
HANDLE handle = 0;
WCHAR procname[1024];
WCHAR* exename;
DWORD wlen = 0;
DWORD procstructlen = 0;
unsigned int process_count, i, j;
char *buffer = NULL;
unsigned int pos = 0;
SERVER_START_REQ( create_snapshot )
if (size && !(buffer = RtlAllocateHeap( GetProcessHeap(), 0, size )))
{
req->flags = SNAP_PROCESS | SNAP_THREAD;
if (!(ret = wine_server_call( req ))) handle = wine_server_ptr_handle( reply->handle );
ret = STATUS_NO_MEMORY;
break;
}
SERVER_START_REQ( list_processes )
{
wine_server_set_reply( req, buffer, size );
ret = wine_server_call( req );
len = reply->info_size;
process_count = reply->process_count;
}
SERVER_END_REQ;
len = 0;
while (ret == STATUS_SUCCESS)
if (ret)
{
int unix_pid = -1;
SERVER_START_REQ( next_process )
RtlFreeHeap( GetProcessHeap(), 0, buffer );
break;
}
len = 0;
for (i = 0; i < process_count; i++)
{
SYSTEM_PROCESS_INFORMATION *nt_process = (SYSTEM_PROCESS_INFORMATION *)((char *)info + len);
const struct process_info *server_process;
const WCHAR *server_name, *file_part;
ULONG proc_len;
ULONG name_len = 0;
pos = (pos + 7) & ~7;
server_process = (const struct process_info *)(buffer + pos);
pos += sizeof(*server_process);
server_name = (const WCHAR *)(buffer + pos);
file_part = server_name + (server_process->name_len / sizeof(WCHAR));
pos += server_process->name_len;
while (file_part > server_name && file_part[-1] != '\\')
{
req->handle = wine_server_obj_handle( handle );
req->reset = (len == 0);
wine_server_set_reply( req, procname, sizeof(procname) - sizeof(WCHAR) );
if (!(ret = wine_server_call( req )))
{
unix_pid = reply->unix_pid;
/* Make sure procname is 0 terminated */
procname[wine_server_reply_size(reply) / sizeof(WCHAR)] = 0;
/* Get only the executable name, not the path */
if ((exename = wcsrchr(procname, '\\')) != NULL) exename++;
else exename = procname;
wlen = (wcslen(exename) + 1) * sizeof(WCHAR);
procstructlen = sizeof(*spi) + wlen + ((reply->threads - 1) * sizeof(SYSTEM_THREAD_INFORMATION));
if (size >= len + procstructlen)
{
/* ftCreationTime, ftUserTime, ftKernelTime;
* vmCounters, ioCounters
*/
memset(spi, 0, sizeof(*spi));
spi->NextEntryOffset = procstructlen - wlen;
spi->dwThreadCount = reply->threads;
/* spi->pszProcessName will be set later on */
spi->dwBasePriority = reply->priority;
spi->UniqueProcessId = UlongToHandle(reply->pid);
spi->ParentProcessId = UlongToHandle(reply->ppid);
spi->HandleCount = reply->handles;
/* spi->ti will be set later on */
}
len += procstructlen;
}
}
SERVER_END_REQ;
if (ret != STATUS_SUCCESS)
{
if (ret == STATUS_NO_MORE_FILES) ret = STATUS_SUCCESS;
break;
file_part--;
name_len++;
}
if (size >= len)
proc_len = sizeof(*nt_process) + server_process->thread_count * sizeof(SYSTEM_THREAD_INFORMATION)
+ (name_len + 1) * sizeof(WCHAR);
len += proc_len;
if (len <= size)
{
int i, j;
memset(nt_process, 0, sizeof(*nt_process));
if (i < process_count - 1)
nt_process->NextEntryOffset = proc_len;
nt_process->dwThreadCount = server_process->thread_count;
nt_process->dwBasePriority = server_process->priority;
nt_process->UniqueProcessId = UlongToHandle(server_process->pid);
nt_process->ParentProcessId = UlongToHandle(server_process->parent_pid);
nt_process->HandleCount = server_process->handle_count;
get_thread_times( server_process->unix_pid, -1, &nt_process->KernelTime, &nt_process->UserTime );
}
get_thread_times(unix_pid, -1, &spi->KernelTime, &spi->UserTime);
pos = (pos + 7) & ~7;
for (j = 0; j < server_process->thread_count; j++)
{
const struct thread_info *server_thread = (const struct thread_info *)(buffer + pos);
/* set thread info */
i = j = 0;
while (ret == STATUS_SUCCESS)
if (len <= size)
{
int unix_tid, pid, tid, base_pri, delta_pri;
SERVER_START_REQ( next_thread )
{
req->handle = wine_server_obj_handle( handle );
req->reset = (j == 0);
if (!(ret = wine_server_call( req )))
{
unix_tid = reply->unix_tid;
pid = reply->pid;
tid = reply->tid;
base_pri = reply->base_pri;
delta_pri = reply->delta_pri;
j++;
}
}
SERVER_END_REQ;
if (!ret)
{
if (UlongToHandle(pid) == spi->UniqueProcessId)
{
memset(&spi->ti[i], 0, sizeof(spi->ti));
spi->ti[i].CreateTime.QuadPart = 0xdeadbeef;
spi->ti[i].ClientId.UniqueProcess = UlongToHandle(pid);
spi->ti[i].ClientId.UniqueThread = UlongToHandle(tid);
spi->ti[i].dwCurrentPriority = base_pri + delta_pri;
spi->ti[i].dwBasePriority = base_pri;
get_thread_times(unix_pid, unix_tid, &spi->ti[i].KernelTime, &spi->ti[i].UserTime);
i++;
}
}
nt_process->ti[j].CreateTime.QuadPart = 0xdeadbeef;
nt_process->ti[j].ClientId.UniqueProcess = UlongToHandle(server_process->pid);
nt_process->ti[j].ClientId.UniqueThread = UlongToHandle(server_thread->tid);
nt_process->ti[j].dwCurrentPriority = server_thread->current_priority;
nt_process->ti[j].dwBasePriority = server_thread->base_priority;
get_thread_times( server_process->unix_pid, server_thread->unix_tid,
&nt_process->ti[j].KernelTime, &nt_process->ti[j].UserTime );
}
if (ret == STATUS_NO_MORE_FILES) ret = STATUS_SUCCESS;
/* now append process name */
spi->ProcessName.Buffer = (WCHAR*)((char*)spi + spi->NextEntryOffset);
spi->ProcessName.Length = wlen - sizeof(WCHAR);
spi->ProcessName.MaximumLength = wlen;
memcpy( spi->ProcessName.Buffer, exename, wlen );
spi->NextEntryOffset += wlen;
last = spi;
spi = (SYSTEM_PROCESS_INFORMATION*)((char*)spi + spi->NextEntryOffset);
pos += sizeof(*server_thread);
}
if (len <= size)
{
nt_process->ProcessName.Buffer = (WCHAR *)&nt_process->ti[server_process->thread_count];
nt_process->ProcessName.Length = name_len * sizeof(WCHAR);
nt_process->ProcessName.MaximumLength = (name_len + 1) * sizeof(WCHAR);
memcpy(nt_process->ProcessName.Buffer, file_part, name_len * sizeof(WCHAR));
nt_process->ProcessName.Buffer[name_len] = 0;
}
}
if (ret == STATUS_SUCCESS && last) last->NextEntryOffset = 0;
if (len > size) ret = STATUS_INFO_LENGTH_MISMATCH;
if (handle) NtClose( handle );
RtlFreeHeap( GetProcessHeap(), 0, buffer );
break;
}

View File

@ -2481,6 +2481,42 @@ struct next_thread_reply
};
struct thread_info
{
thread_id_t tid;
int base_priority;
int current_priority;
int unix_tid;
};
struct process_info
{
data_size_t name_len;
int thread_count;
int priority;
process_id_t pid;
process_id_t parent_pid;
int handle_count;
int unix_pid;
};
struct list_processes_request
{
struct request_header __header;
char __pad_12[4];
};
struct list_processes_reply
{
struct reply_header __header;
data_size_t info_size;
int process_count;
/* VARARG(data,process_info,info_size); */
};
struct wait_debug_event_request
{
@ -5893,6 +5929,7 @@ enum request
REQ_create_snapshot,
REQ_next_process,
REQ_next_thread,
REQ_list_processes,
REQ_wait_debug_event,
REQ_queue_exception_event,
REQ_get_exception_status,
@ -6196,6 +6233,7 @@ union generic_request
struct create_snapshot_request create_snapshot_request;
struct next_process_request next_process_request;
struct next_thread_request next_thread_request;
struct list_processes_request list_processes_request;
struct wait_debug_event_request wait_debug_event_request;
struct queue_exception_event_request queue_exception_event_request;
struct get_exception_status_request get_exception_status_request;
@ -6497,6 +6535,7 @@ union generic_reply
struct create_snapshot_reply create_snapshot_reply;
struct next_process_reply next_process_reply;
struct next_thread_reply next_thread_reply;
struct list_processes_reply list_processes_reply;
struct wait_debug_event_reply wait_debug_event_reply;
struct queue_exception_event_reply queue_exception_event_reply;
struct get_exception_status_reply get_exception_status_reply;
@ -6702,7 +6741,7 @@ union generic_reply
/* ### protocol_version begin ### */
#define SERVER_PROTOCOL_VERSION 614
#define SERVER_PROTOCOL_VERSION 615
/* ### protocol_version end ### */

View File

@ -22,6 +22,7 @@
#include "wine/port.h"
#include <assert.h>
#include <errno.h>
#include <limits.h>
#include <signal.h>
#include <string.h>
@ -1819,3 +1820,70 @@ DECL_HANDLER(resume_process)
release_object( process );
}
}
/* Get a list of processes and threads currently running */
DECL_HANDLER(list_processes)
{
struct process *process;
struct thread *thread;
unsigned int pos = 0;
char *buffer;
reply->process_count = 0;
reply->info_size = 0;
LIST_FOR_EACH_ENTRY( process, &process_list, struct process, entry )
{
struct process_dll *exe = get_process_exe_module( process );
reply->info_size = (reply->info_size + 7) & ~7;
reply->info_size += sizeof(struct process_info);
if (exe) reply->info_size += exe->namelen;
reply->info_size = (reply->info_size + 7) & ~7;
reply->info_size += process->running_threads * sizeof(struct thread_info);
reply->process_count++;
}
if (reply->info_size > get_reply_max_size())
{
set_error( STATUS_INFO_LENGTH_MISMATCH );
return;
}
if (!(buffer = set_reply_data_size( reply->info_size ))) return;
memset( buffer, 0, reply->info_size );
LIST_FOR_EACH_ENTRY( process, &process_list, struct process, entry )
{
struct process_info *process_info;
struct process_dll *exe = get_process_exe_module( process );
pos = (pos + 7) & ~7;
process_info = (struct process_info *)(buffer + pos);
process_info->name_len = exe ? exe->namelen : 0;
process_info->thread_count = process->running_threads;
process_info->priority = process->priority;
process_info->pid = process->id;
process_info->parent_pid = process->parent_id;
process_info->handle_count = get_handle_table_count(process);
process_info->unix_pid = process->unix_pid;
pos += sizeof(*process_info);
if (exe)
{
memcpy( buffer + pos, exe->filename, exe->namelen );
pos += exe->namelen;
}
pos = (pos + 7) & ~7;
LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry )
{
struct thread_info *thread_info = (struct thread_info *)(buffer + pos);
thread_info->tid = thread->id;
thread_info->base_priority = thread->priority;
thread_info->current_priority = thread->priority; /* FIXME */
thread_info->unix_tid = thread->unix_tid;
pos += sizeof(*thread_info);
}
}
}

View File

@ -1909,6 +1909,36 @@ enum char_info_mode
@END
struct thread_info
{
thread_id_t tid;
int base_priority;
int current_priority;
int unix_tid;
};
struct process_info
{
data_size_t name_len;
int thread_count;
int priority;
process_id_t pid;
process_id_t parent_pid;
int handle_count;
int unix_pid;
/* VARARG(name,unicode_str,name_len); */
/* VARARG(threads,struct thread_info,thread_count); */
};
/* Get a list of processes and threads currently running */
@REQ(list_processes)
@REPLY
data_size_t info_size;
int process_count;
VARARG(data,process_info,info_size);
@END
/* Wait for a debug event */
@REQ(wait_debug_event)
int get_handle; /* should we alloc a handle for waiting? */

View File

@ -214,6 +214,7 @@ DECL_HANDLER(is_same_mapping);
DECL_HANDLER(create_snapshot);
DECL_HANDLER(next_process);
DECL_HANDLER(next_thread);
DECL_HANDLER(list_processes);
DECL_HANDLER(wait_debug_event);
DECL_HANDLER(queue_exception_event);
DECL_HANDLER(get_exception_status);
@ -516,6 +517,7 @@ static const req_handler req_handlers[REQ_NB_REQUESTS] =
(req_handler)req_create_snapshot,
(req_handler)req_next_process,
(req_handler)req_next_thread,
(req_handler)req_list_processes,
(req_handler)req_wait_debug_event,
(req_handler)req_queue_exception_event,
(req_handler)req_get_exception_status,
@ -1360,6 +1362,10 @@ C_ASSERT( FIELD_OFFSET(struct next_thread_reply, base_pri) == 20 );
C_ASSERT( FIELD_OFFSET(struct next_thread_reply, delta_pri) == 24 );
C_ASSERT( FIELD_OFFSET(struct next_thread_reply, unix_tid) == 28 );
C_ASSERT( sizeof(struct next_thread_reply) == 32 );
C_ASSERT( sizeof(struct list_processes_request) == 16 );
C_ASSERT( FIELD_OFFSET(struct list_processes_reply, info_size) == 8 );
C_ASSERT( FIELD_OFFSET(struct list_processes_reply, process_count) == 12 );
C_ASSERT( sizeof(struct list_processes_reply) == 16 );
C_ASSERT( FIELD_OFFSET(struct wait_debug_event_request, get_handle) == 12 );
C_ASSERT( sizeof(struct wait_debug_event_request) == 16 );
C_ASSERT( FIELD_OFFSET(struct wait_debug_event_reply, pid) == 8 );

View File

@ -1115,6 +1115,44 @@ static void dump_varargs_token_groups( const char *prefix, data_size_t size )
fputc( '}', stderr );
}
static void dump_varargs_process_info( const char *prefix, data_size_t size )
{
data_size_t pos = 0;
unsigned int i;
fprintf( stderr,"%s{", prefix );
while (size - pos >= sizeof(struct process_info))
{
const struct process_info *process;
pos = (pos + 7) & ~7;
process = (const struct process_info *)((const char *)cur_data + pos);
if (size - pos < sizeof(*process)) break;
if (pos) fputc( ',', stderr );
fprintf( stderr, "{thread_count=%u,priority=%d,pid=%04x,parent_pid=%04x,handle_count=%u,unix_pid=%d,",
process->thread_count, process->priority, process->pid,
process->parent_pid, process->handle_count, process->unix_pid );
pos += sizeof(*process);
pos = dump_inline_unicode_string( "name=L\"", pos, process->name_len, size );
pos = (pos + 7) & ~7;
fprintf( stderr, "\",threads={" );
for (i = 0; i < process->thread_count; i++)
{
const struct thread_info *thread = (const struct thread_info *)((const char *)cur_data + pos);
if (size - pos < sizeof(*thread)) break;
if (i) fputc( ',', stderr );
fprintf( stderr, "{tid=%04x,base_priority=%d,current_priority=%d,unix_tid=%d}",
thread->tid, thread->base_priority, thread->current_priority, thread->unix_tid );
pos += sizeof(*thread);
}
fprintf( stderr, "}}" );
}
fputc( '}', stderr );
remove_data( size );
}
static void dump_varargs_object_attributes( const char *prefix, data_size_t size )
{
const struct object_attributes *objattr = cur_data;
@ -2404,6 +2442,17 @@ static void dump_next_thread_reply( const struct next_thread_reply *req )
fprintf( stderr, ", unix_tid=%d", req->unix_tid );
}
static void dump_list_processes_request( const struct list_processes_request *req )
{
}
static void dump_list_processes_reply( const struct list_processes_reply *req )
{
fprintf( stderr, " info_size=%u", req->info_size );
fprintf( stderr, ", process_count=%d", req->process_count );
dump_varargs_process_info( ", data=", min(cur_size,req->info_size) );
}
static void dump_wait_debug_event_request( const struct wait_debug_event_request *req )
{
fprintf( stderr, " get_handle=%d", req->get_handle );
@ -4706,6 +4755,7 @@ static const dump_func req_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_create_snapshot_request,
(dump_func)dump_next_process_request,
(dump_func)dump_next_thread_request,
(dump_func)dump_list_processes_request,
(dump_func)dump_wait_debug_event_request,
(dump_func)dump_queue_exception_event_request,
(dump_func)dump_get_exception_status_request,
@ -5005,6 +5055,7 @@ static const dump_func reply_dumpers[REQ_NB_REQUESTS] = {
(dump_func)dump_create_snapshot_reply,
(dump_func)dump_next_process_reply,
(dump_func)dump_next_thread_reply,
(dump_func)dump_list_processes_reply,
(dump_func)dump_wait_debug_event_reply,
(dump_func)dump_queue_exception_event_reply,
NULL,
@ -5304,6 +5355,7 @@ static const char * const req_names[REQ_NB_REQUESTS] = {
"create_snapshot",
"next_process",
"next_thread",
"list_processes",
"wait_debug_event",
"queue_exception_event",
"get_exception_status",