Signed-off-by: Zebediah Figura <zfigura(a)codeweavers.com>
---
v3: clear the buffer first, thanks Alexandre.
dlls/ntdll/unix/system.c | 182 +++++++++++++++++----------------------
server/process.c | 69 +++++++++++++++
server/protocol.def | 30 +++++++
server/trace.c | 39 +++++++++
4 files changed, 216 insertions(+), 104 deletions(-)
diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c
index 7045bc1550b..3a53a764d03 100644
--- a/dlls/ntdll/unix/system.c
+++ b/dlls/ntdll/unix/system.c
@@ -1998,6 +1998,11 @@ static void get_timezone_info( RTL_DYNAMIC_TIME_ZONE_INFORMATION *tzi )
RtlLeaveCriticalSection( &TIME_tz_section );
}
+static unsigned int align_offset(unsigned int offset, unsigned int alignment)
+{
+ return (offset + (alignment - 1)) & ~(alignment - 1);
+}
+
/******************************************************************************
* NtQuerySystemInformation (NTDLL.@)
@@ -2083,132 +2088,101 @@ 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_END_REQ;
- len = 0;
- while (ret == STATUS_SUCCESS)
+ SERVER_START_REQ( list_processes )
{
- int unix_pid = -1;
- SERVER_START_REQ( next_process )
- {
- 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;
+ wine_server_set_reply( req, buffer, size );
+ ret = wine_server_call( req );
+ len = reply->info_size;
+ process_count = reply->process_count;
+ }
+ SERVER_END_REQ;
- wlen = (wcslen(exename) + 1) * sizeof(WCHAR);
- procstructlen = sizeof(*spi) + wlen + ((reply->threads - 1) * sizeof(SYSTEM_THREAD_INFORMATION));
+ if (ret)
+ {
+ RtlFreeHeap( GetProcessHeap(), 0, buffer );
+ break;
+ }
- if (size >= len + procstructlen)
- {
- /* ftCreationTime, ftUserTime, ftKernelTime;
- * vmCounters, ioCounters
- */
- memset(spi, 0, sizeof(*spi));
+ len = 0;
- spi->NextEntryOffset = procstructlen - wlen;
- spi->dwThreadCount = reply->threads;
+ 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;
- /* spi->pszProcessName will be set later on */
+ pos = align_offset( pos, TYPE_ALIGNMENT(struct process_info) );
+ server_process = (const struct process_info *)(buffer + pos);
+ pos += sizeof(*server_process);
- spi->dwBasePriority = reply->priority;
- spi->UniqueProcessId = UlongToHandle(reply->pid);
- spi->ParentProcessId = UlongToHandle(reply->ppid);
- spi->HandleCount = reply->handles;
+ 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] != '\\')
+ {
+ file_part--;
+ name_len++;
+ }
- /* spi->ti will be set later on */
+ proc_len = sizeof(*nt_process) + server_process->thread_count * sizeof(SYSTEM_THREAD_INFORMATION)
+ + (name_len + 1) * sizeof(WCHAR);
+ len += proc_len;
- }
- len += procstructlen;
- }
- }
- SERVER_END_REQ;
- if (ret != STATUS_SUCCESS)
+ if (len <= size)
{
- if (ret == STATUS_NO_MORE_FILES) ret = STATUS_SUCCESS;
- break;
+ 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 );
}
- if (size >= len)
+ pos = align_offset( pos, TYPE_ALIGNMENT(struct thread_info) );
+ for (j = 0; j < server_process->thread_count; j++)
{
- int i, j;
+ const struct thread_info *server_thread = (const struct thread_info *)(buffer + pos);
- get_thread_times(unix_pid, -1, &spi->KernelTime, &spi->UserTime);
-
- /* 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 );
break;
}
diff --git a/server/process.c b/server/process.c
index 283edc09c5e..e1af3c8ac5c 100644
--- a/server/process.c
+++ b/server/process.c
@@ -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,71 @@ DECL_HANDLER(resume_process)
release_object( process );
}
}
+
+static unsigned int align_offset(unsigned int offset, unsigned int alignment)
+{
+ return (offset + (alignment - 1)) & ~(alignment - 1);
+}
+
+/* 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 = align_offset( reply->info_size, TYPE_ALIGNMENT(struct process_info) );
+ reply->info_size += sizeof(struct process_info) + exe->namelen;
+ reply->info_size = align_offset( reply->info_size, TYPE_ALIGNMENT(struct thread_info) );
+ 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 = align_offset( pos, TYPE_ALIGNMENT(struct process_info) );
+ process_info = (struct process_info *)(buffer + pos);
+ process_info->name_len = exe->namelen;
+ 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);
+
+ memcpy( buffer + pos, exe->filename, exe->namelen );
+ pos += exe->namelen;
+
+ pos = align_offset( pos, TYPE_ALIGNMENT(struct thread_info) );
+ 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);
+ }
+ }
+}
diff --git a/server/protocol.def b/server/protocol.def
index 6416306c0a1..2737cd6fddd 100644
--- a/server/protocol.def
+++ b/server/protocol.def
@@ -1919,6 +1919,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;
+ unsigned int thread_count;
+ int priority;
+ process_id_t pid;
+ process_id_t parent_pid;
+ unsigned 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;
+ unsigned 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? */
diff --git a/server/trace.c b/server/trace.c
index 2fb5afd5ef1..d47e1260255 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1115,6 +1115,45 @@ static void dump_varargs_token_groups( const char *prefix, data_size_t size )
fputc( '}', stderr );
}
+static unsigned int align_offset(unsigned int offset, unsigned int alignment)
+{
+ return (offset + (alignment - 1)) & ~(alignment - 1);
+}
+
+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 = (const struct process_info *)((const char *)cur_data + pos);
+ pos = align_offset( pos, TYPE_ALIGNMENT(struct process_info) );
+ fprintf( stderr, "[thread_count=%u,priority=%d,pid=%04x,parent_pid=%04x,handle_count=%08x,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 = align_offset( pos, TYPE_ALIGNMENT(struct thread_info) );
+ 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;
+ 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 );
+}
+
static void dump_varargs_object_attributes( const char *prefix, data_size_t size )
{
const struct object_attributes *objattr = cur_data;
--
2.27.0