Signed-off-by: Zebediah Figura zfigura@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;