Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- This decreases CPU usage by wineserver from about 65% to about 45% for me in Street Fighter V, which for some reason calls this 15-20 times per second.
dlls/ntdll/unix/system.c | 177 ++++++++++++++++----------------------- server/process.c | 56 +++++++++++++ server/protocol.def | 30 +++++++ server/trace.c | 34 ++++++++ 4 files changed, 191 insertions(+), 106 deletions(-)
diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c index 7045bc1550b..f89208997e2 100644 --- a/dlls/ntdll/unix/system.c +++ b/dlls/ntdll/unix/system.c @@ -2083,132 +2083,97 @@ 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; + const struct process_info *server_process; + void *buffer = NULL;
- 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; - - wlen = (wcslen(exename) + 1) * sizeof(WCHAR); - procstructlen = sizeof(*spi) + wlen + ((reply->threads - 1) * sizeof(SYSTEM_THREAD_INFORMATION)); + wine_server_set_reply( req, buffer, size ); + ret = wine_server_call( req ); + len = reply->user_len; + process_count = reply->process_count; + } + SERVER_END_REQ;
- if (size >= len + procstructlen) - { - /* ftCreationTime, ftUserTime, ftKernelTime; - * vmCounters, ioCounters - */ - memset(spi, 0, sizeof(*spi)); + if (ret) + { + RtlFreeHeap( GetProcessHeap(), 0, buffer ); + break; + }
- spi->NextEntryOffset = procstructlen - wlen; - spi->dwThreadCount = reply->threads; + server_process = buffer; + len = 0;
- /* spi->pszProcessName will be set later on */ + for (i = 0; i < process_count; i++) + { + const WCHAR *server_name = (const WCHAR *)(server_process + 1); + SYSTEM_PROCESS_INFORMATION *nt_process = (SYSTEM_PROCESS_INFORMATION *)((char *)info + len); + const struct thread_info *server_thread; + const WCHAR *file_part; + ULONG proc_len; + ULONG name_len = 0;
- spi->dwBasePriority = reply->priority; - spi->UniqueProcessId = UlongToHandle(reply->pid); - spi->ParentProcessId = UlongToHandle(reply->ppid); - spi->HandleCount = reply->handles; + file_part = server_name + (server_process->name_len / sizeof(WCHAR)); + 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) + server_thread = (const struct thread_info *)((const char *)server_name + server_process->name_len); + for (j = 0; j < server_process->thread_count; j++) { - int i, j; - - 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); + + 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; + } + + server_process = (const struct process_info *)server_thread; } - 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..452861491f8 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,58 @@ DECL_HANDLER(resume_process) release_object( process ); } } + +/* Get a list of processes and threads currently running */ +DECL_HANDLER(list_processes) +{ + struct process_info *process_info; + struct process *process; + struct thread *thread; + + reply->process_count = 0; + reply->user_len = 0; + + LIST_FOR_EACH_ENTRY( process, &process_list, struct process, entry ) + { + struct process_dll *exe = get_process_exe_module( process ); + reply->user_len += sizeof(struct process_info) + exe->namelen; + reply->user_len += process->running_threads * sizeof(struct thread_info); + reply->process_count++; + } + + if (reply->user_len > get_reply_max_size()) + { + set_error( STATUS_INFO_LENGTH_MISMATCH ); + return; + } + + process_info = set_reply_data_size( reply->user_len ); + if (!process_info) return; + + LIST_FOR_EACH_ENTRY( process, &process_list, struct process, entry ) + { + struct process_dll *exe = get_process_exe_module( process ); + WCHAR *name = (WCHAR *)(process_info + 1); + struct thread_info *thread_info = (struct thread_info *)((char *)name + exe->namelen); + + 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; + memcpy( name, exe->filename, exe->namelen ); + + LIST_FOR_EACH_ENTRY( thread, &process->thread_list, struct thread, proc_entry ) + { + 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; + thread_info++; + } + + process_info = (struct process_info *)thread_info; + } +} diff --git a/server/protocol.def b/server/protocol.def index 6416306c0a1..bd531a1a727 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 user_len; /* length needed to store user */ + unsigned int process_count; + VARARG(data,process_info); +@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..f39c7402d41 100644 --- a/server/trace.c +++ b/server/trace.c @@ -1115,6 +1115,40 @@ 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 ) +{ + const struct process_info *process = cur_data; + const struct thread_info *thread; + data_size_t pos = 0; + unsigned int i; + + fprintf( stderr,"%s{", prefix ); + + while (size - pos >= sizeof(*process)) + { + 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 ); + fprintf( stderr, "",threads={" ); + thread = (const struct thread_info *)((const char *)cur_data + pos); + for (i = 0; i < process->thread_count; i++) + { + 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); + thread++; + } + fprintf( stderr, "}," ); + + process = (const struct process_info *)thread; + } + + fputc( '}', stderr ); +} + static void dump_varargs_object_attributes( const char *prefix, data_size_t size ) { const struct object_attributes *objattr = cur_data;
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- dlls/iphlpapi/ipstats.c | 81 +++++++++++++++++++++++------------------ 1 file changed, 45 insertions(+), 36 deletions(-)
diff --git a/dlls/iphlpapi/ipstats.c b/dlls/iphlpapi/ipstats.c index 11d52d4d651..e858c1ace24 100644 --- a/dlls/iphlpapi/ipstats.c +++ b/dlls/iphlpapi/ipstats.c @@ -1887,56 +1887,65 @@ struct pid_map
static struct pid_map *get_pid_map( unsigned int *num_entries ) { - HANDLE snapshot = NULL; struct pid_map *map; - unsigned int i = 0, count = 16, size = count * sizeof(*map); + unsigned int i = 0, map_count = 16, buffer_len = 4096, process_count; NTSTATUS ret; + void *buffer = NULL, *new_buffer; + const struct process_info *process;
- if (!(map = HeapAlloc( GetProcessHeap(), 0, size ))) return NULL; + if (!(buffer = HeapAlloc( GetProcessHeap(), 0, buffer_len ))) return NULL;
- SERVER_START_REQ( create_snapshot ) + for (;;) + { + SERVER_START_REQ( list_processes ) + { + wine_server_set_reply( req, buffer, buffer_len ); + ret = wine_server_call( req ); + buffer_len = reply->user_len; + process_count = reply->process_count; + } + SERVER_END_REQ; + + if (ret != STATUS_INFO_LENGTH_MISMATCH) break; + + if (!(new_buffer = HeapReAlloc( GetProcessHeap(), 0, buffer, buffer_len ))) + { + HeapFree( GetProcessHeap(), 0, buffer ); + return NULL; + } + } + + if (!(map = HeapAlloc( GetProcessHeap(), 0, map_count * sizeof(*map) ))) { - req->flags = SNAP_PROCESS; - req->attributes = 0; - if (!(ret = wine_server_call( req ))) - snapshot = wine_server_ptr_handle( reply->handle ); + HeapFree( GetProcessHeap(), 0, buffer ); + return NULL; } - SERVER_END_REQ;
- *num_entries = 0; - while (ret == STATUS_SUCCESS) + process = buffer; + for (i = 0; i < process_count; ++i) { - SERVER_START_REQ( next_process ) + if (i >= map_count) { - req->handle = wine_server_obj_handle( snapshot ); - req->reset = (i == 0); - if (!(ret = wine_server_call( req ))) + struct pid_map *new_map; + map_count *= 2; + if (!(new_map = HeapReAlloc( GetProcessHeap(), 0, map, map_count * sizeof(*map)))) { - if (i >= count) - { - struct pid_map *new_map; - count *= 2; - size = count * sizeof(*new_map); - - if (!(new_map = HeapReAlloc( GetProcessHeap(), 0, map, size ))) - { - HeapFree( GetProcessHeap(), 0, map ); - map = NULL; - goto done; - } - map = new_map; - } - map[i].pid = reply->pid; - map[i].unix_pid = reply->unix_pid; - (*num_entries)++; - i++; + HeapFree( GetProcessHeap(), 0, map ); + HeapFree( GetProcessHeap(), 0, buffer ); + return NULL; } + map = new_map; } - SERVER_END_REQ; + + map[i].pid = process->pid; + map[i].unix_pid = process->unix_pid; + + process = (const struct process_info *)((char *)(process + 1) + process->name_len + + process->thread_count * sizeof(struct thread_info)); }
-done: - NtClose( snapshot ); + HeapFree( GetProcessHeap(), 0, buffer ); + *num_entries = process_count; return map; }
Signed-off-by: Zebediah Figura zfigura@codeweavers.com --- server/Makefile.in | 1 - server/process.c | 30 ------ server/process.h | 10 -- server/protocol.def | 41 -------- server/snapshot.c | 223 -------------------------------------------- server/thread.c | 24 ----- server/thread.h | 8 -- 7 files changed, 337 deletions(-) delete mode 100644 server/snapshot.c
diff --git a/server/Makefile.in b/server/Makefile.in index 3f3761faab6..e90c5d1336c 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -33,7 +33,6 @@ C_SRCS = \ semaphore.c \ serial.c \ signal.c \ - snapshot.c \ sock.c \ symlink.c \ thread.c \ diff --git a/server/process.c b/server/process.c index 452861491f8..774dd20dc8d 100644 --- a/server/process.c +++ b/server/process.c @@ -1086,36 +1086,6 @@ int set_process_debug_flag( struct process *process, int flag ) return write_process_memory( process, process->peb + 2, 1, &data ); }
-/* take a snapshot of currently running processes */ -struct process_snapshot *process_snap( int *count ) -{ - struct process_snapshot *snapshot, *ptr; - struct process *process; - - if (!running_processes) return NULL; - if (!(snapshot = mem_alloc( sizeof(*snapshot) * running_processes ))) - return NULL; - ptr = snapshot; - LIST_FOR_EACH_ENTRY( process, &process_list, struct process, entry ) - { - if (!process->running_threads) continue; - ptr->process = process; - ptr->threads = process->running_threads; - ptr->count = process->obj.refcount; - ptr->priority = process->priority; - ptr->handles = get_handle_table_count(process); - grab_object( process ); - ptr++; - } - - if (!(*count = ptr - snapshot)) - { - free( snapshot ); - snapshot = NULL; - } - return snapshot; -} - /* create a new process */ DECL_HANDLER(new_process) { diff --git a/server/process.h b/server/process.h index 5b83e111a6f..fb29f21cb12 100644 --- a/server/process.h +++ b/server/process.h @@ -100,15 +100,6 @@ struct process struct list kernel_object; /* list of kernel object pointers */ };
-struct process_snapshot -{ - struct process *process; /* process ptr */ - int count; /* process refcount */ - int threads; /* number of threads */ - int priority; /* priority class */ - int handles; /* number of handles */ -}; - #define CPU_FLAG(cpu) (1 << (cpu)) #define CPU_64BIT_MASK (CPU_FLAG(CPU_x86_64) | CPU_FLAG(CPU_ARM64))
@@ -137,7 +128,6 @@ extern void kill_process( struct process *process, int violent_death ); extern void kill_console_processes( struct thread *renderer, int exit_code ); extern void kill_debugged_processes( struct thread *debugger, int exit_code ); extern void detach_debugged_processes( struct thread *debugger ); -extern struct process_snapshot *process_snap( int *count ); extern void enum_processes( int (*cb)(struct process*, void*), void *user);
/* console functions */ diff --git a/server/protocol.def b/server/protocol.def index bd531a1a727..01d8fd41883 100644 --- a/server/protocol.def +++ b/server/protocol.def @@ -1878,47 +1878,6 @@ enum char_info_mode @END
-#define SNAP_PROCESS 0x00000001 -#define SNAP_THREAD 0x00000002 -/* Create a snapshot */ -@REQ(create_snapshot) - unsigned int attributes; /* object attributes */ - unsigned int flags; /* snapshot flags (SNAP_*) */ -@REPLY - obj_handle_t handle; /* handle to the snapshot */ -@END - - -/* Get the next process from a snapshot */ -@REQ(next_process) - obj_handle_t handle; /* handle to the snapshot */ - int reset; /* reset snapshot position? */ -@REPLY - int count; /* process usage count */ - process_id_t pid; /* process id */ - process_id_t ppid; /* parent process id */ - int threads; /* number of threads */ - int priority; /* process priority */ - int handles; /* number of handles */ - int unix_pid; /* Unix pid */ - VARARG(filename,unicode_str); /* file name of main exe */ -@END - - -/* Get the next thread from a snapshot */ -@REQ(next_thread) - obj_handle_t handle; /* handle to the snapshot */ - int reset; /* reset snapshot position? */ -@REPLY - int count; /* thread usage count */ - process_id_t pid; /* process id */ - thread_id_t tid; /* thread id */ - int base_pri; /* base priority */ - int delta_pri; /* delta priority */ - int unix_tid; /* thread native pid */ -@END - - struct thread_info { thread_id_t tid; diff --git a/server/snapshot.c b/server/snapshot.c deleted file mode 100644 index bdceaef5302..00000000000 --- a/server/snapshot.c +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Server-side snapshots - * - * Copyright (C) 1999 Alexandre Julliard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - * - * FIXME: heap snapshots not implemented - */ - -#include "config.h" -#include "wine/port.h" - -#include <assert.h> -#include <stdio.h> -#include <stdlib.h> -#include <stdarg.h> - -#include "ntstatus.h" -#define WIN32_NO_STATUS -#include "windef.h" -#include "winternl.h" - -#include "handle.h" -#include "process.h" -#include "thread.h" -#include "request.h" - - -struct snapshot -{ - struct object obj; /* object header */ - struct process_snapshot *processes; /* processes snapshot */ - int process_count; /* count of processes */ - int process_pos; /* current position in proc snapshot */ - struct thread_snapshot *threads; /* threads snapshot */ - int thread_count; /* count of threads */ - int thread_pos; /* current position in thread snapshot */ -}; - -static void snapshot_dump( struct object *obj, int verbose ); -static void snapshot_destroy( struct object *obj ); - -static const struct object_ops snapshot_ops = -{ - sizeof(struct snapshot), /* size */ - snapshot_dump, /* dump */ - no_get_type, /* get_type */ - no_add_queue, /* add_queue */ - NULL, /* remove_queue */ - NULL, /* signaled */ - NULL, /* satisfied */ - no_signal, /* signal */ - no_get_fd, /* get_fd */ - no_map_access, /* map_access */ - default_get_sd, /* get_sd */ - default_set_sd, /* set_sd */ - no_lookup_name, /* lookup_name */ - no_link_name, /* link_name */ - NULL, /* unlink_name */ - no_open_file, /* open_file */ - no_kernel_obj_list, /* get_kernel_obj_list */ - no_close_handle, /* close_handle */ - snapshot_destroy /* destroy */ -}; - - -/* create a new snapshot */ -static struct snapshot *create_snapshot( unsigned int flags ) -{ - struct snapshot *snapshot; - - if (!(snapshot = alloc_object( &snapshot_ops ))) return NULL; - - snapshot->process_pos = 0; - snapshot->process_count = 0; - if (flags & SNAP_PROCESS) - snapshot->processes = process_snap( &snapshot->process_count ); - - snapshot->thread_pos = 0; - snapshot->thread_count = 0; - if (flags & SNAP_THREAD) - snapshot->threads = thread_snap( &snapshot->thread_count ); - - return snapshot; -} - -/* get the next process in the snapshot */ -static int snapshot_next_process( struct snapshot *snapshot, struct next_process_reply *reply ) -{ - struct process_snapshot *ptr; - struct process_dll *exe_module; - - if (!snapshot->process_count) - { - set_error( STATUS_INVALID_PARAMETER ); /* FIXME */ - return 0; - } - if (snapshot->process_pos >= snapshot->process_count) - { - set_error( STATUS_NO_MORE_FILES ); - return 0; - } - ptr = &snapshot->processes[snapshot->process_pos++]; - reply->count = ptr->count; - reply->pid = get_process_id( ptr->process ); - reply->ppid = ptr->process->parent_id; - reply->threads = ptr->threads; - reply->priority = ptr->priority; - reply->handles = ptr->handles; - reply->unix_pid = ptr->process->unix_pid; - if ((exe_module = get_process_exe_module( ptr->process )) && exe_module->filename) - { - data_size_t len = min( exe_module->namelen, get_reply_max_size() ); - set_reply_data( exe_module->filename, len ); - } - return 1; -} - -/* get the next thread in the snapshot */ -static int snapshot_next_thread( struct snapshot *snapshot, struct next_thread_reply *reply ) -{ - struct thread_snapshot *ptr; - - if (!snapshot->thread_count) - { - set_error( STATUS_INVALID_PARAMETER ); /* FIXME */ - return 0; - } - if (snapshot->thread_pos >= snapshot->thread_count) - { - set_error( STATUS_NO_MORE_FILES ); - return 0; - } - ptr = &snapshot->threads[snapshot->thread_pos++]; - reply->count = ptr->count; - reply->pid = get_process_id( ptr->thread->process ); - reply->tid = get_thread_id( ptr->thread ); - reply->base_pri = ptr->priority; - reply->delta_pri = 0; /* FIXME */ - reply->unix_tid = ptr->thread->unix_tid; - return 1; -} - -static void snapshot_dump( struct object *obj, int verbose ) -{ - struct snapshot *snapshot = (struct snapshot *)obj; - assert( obj->ops == &snapshot_ops ); - fprintf( stderr, "Snapshot: %d procs %d threads\n", - snapshot->process_count, snapshot->thread_count ); -} - -static void snapshot_destroy( struct object *obj ) -{ - int i; - struct snapshot *snapshot = (struct snapshot *)obj; - assert( obj->ops == &snapshot_ops ); - if (snapshot->process_count) - { - for (i = 0; i < snapshot->process_count; i++) - release_object( snapshot->processes[i].process ); - free( snapshot->processes ); - } - if (snapshot->thread_count) - { - for (i = 0; i < snapshot->thread_count; i++) - release_object( snapshot->threads[i].thread ); - free( snapshot->threads ); - } -} - -/* create a snapshot */ -DECL_HANDLER(create_snapshot) -{ - struct snapshot *snapshot; - - reply->handle = 0; - if ((snapshot = create_snapshot( req->flags ))) - { - reply->handle = alloc_handle( current->process, snapshot, 0, req->attributes ); - release_object( snapshot ); - } -} - -/* get the next process from a snapshot */ -DECL_HANDLER(next_process) -{ - struct snapshot *snapshot; - - if ((snapshot = (struct snapshot *)get_handle_obj( current->process, req->handle, - 0, &snapshot_ops ))) - { - if (req->reset) snapshot->process_pos = 0; - snapshot_next_process( snapshot, reply ); - release_object( snapshot ); - } -} - -/* get the next thread from a snapshot */ -DECL_HANDLER(next_thread) -{ - struct snapshot *snapshot; - - if ((snapshot = (struct snapshot *)get_handle_obj( current->process, req->handle, - 0, &snapshot_ops ))) - { - if (req->reset) snapshot->thread_pos = 0; - snapshot_next_thread( snapshot, reply ); - release_object( snapshot ); - } -} diff --git a/server/thread.c b/server/thread.c index d55af204bda..9b14174578e 100644 --- a/server/thread.c +++ b/server/thread.c @@ -1299,30 +1299,6 @@ static unsigned int get_context_system_regs( enum cpu_type cpu ) return 0; }
-/* take a snapshot of currently running threads */ -struct thread_snapshot *thread_snap( int *count ) -{ - struct thread_snapshot *snapshot, *ptr; - struct thread *thread; - int total = 0; - - LIST_FOR_EACH_ENTRY( thread, &thread_list, struct thread, entry ) - if (thread->state != TERMINATED) total++; - if (!total || !(snapshot = mem_alloc( sizeof(*snapshot) * total ))) return NULL; - ptr = snapshot; - LIST_FOR_EACH_ENTRY( thread, &thread_list, struct thread, entry ) - { - if (thread->state == TERMINATED) continue; - ptr->thread = thread; - ptr->count = thread->obj.refcount; - ptr->priority = thread->priority; - grab_object( thread ); - ptr++; - } - *count = total; - return snapshot; -} - /* gets the current impersonation token */ struct token *thread_get_impersonation_token( struct thread *thread ) { diff --git a/server/thread.h b/server/thread.h index 183f6baa0f2..650bc44628d 100644 --- a/server/thread.h +++ b/server/thread.h @@ -93,13 +93,6 @@ struct thread WCHAR *desc; /* thread description string */ };
-struct thread_snapshot -{ - struct thread *thread; /* thread ptr */ - int count; /* thread refcount */ - int priority; /* priority class */ -}; - extern struct thread *current;
/* thread functions */ @@ -125,7 +118,6 @@ extern int thread_queue_apc( struct process *process, struct thread *thread, str extern void thread_cancel_apc( struct thread *thread, struct object *owner, enum apc_type type ); extern int thread_add_inflight_fd( struct thread *thread, int client, int server ); extern int thread_get_inflight_fd( struct thread *thread, int client ); -extern struct thread_snapshot *thread_snap( int *count ); extern struct token *thread_get_impersonation_token( struct thread *thread ); extern int set_thread_affinity( struct thread *thread, affinity_t affinity ); extern int is_cpu_supported( enum cpu_type cpu );
Zebediah Figura z.figura12@gmail.com writes:
- {
struct process_dll *exe = get_process_exe_module( process );
WCHAR *name = (WCHAR *)(process_info + 1);
struct thread_info *thread_info = (struct thread_info *)((char *)name + exe->namelen);
You can't append thread_info right after the string, it needs to be properly aligned.
On 2020-07-02 05:18, Zebediah Figura wrote:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
This decreases CPU usage by wineserver from about 65% to about 45% for me in Street Fighter V, which for some reason calls this 15-20 times per second.
dlls/ntdll/unix/system.c | 177 ++++++++++++++++----------------------- server/process.c | 56 +++++++++++++ server/protocol.def | 30 +++++++ server/trace.c | 34 ++++++++ 4 files changed, 191 insertions(+), 106 deletions(-)
diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c index 7045bc1550b..f89208997e2 100644 --- a/dlls/ntdll/unix/system.c +++ b/dlls/ntdll/unix/system.c @@ -2083,132 +2083,97 @@ 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;
const struct process_info *server_process;
void *buffer = NULL;
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;
Shouldn't the allocated buffer size depend on the data to be read? If there's some very long paths there, the application buffer size may not be large enough, although it would have been enough to store the process infos with just their basename. Or the server has to return only basenames, and assert that the client structures are larger than server request structures.
On 7/2/20 11:24 AM, Rémi Bernon wrote:
On 2020-07-02 05:18, Zebediah Figura wrote:
Signed-off-by: Zebediah Figura zfigura@codeweavers.com
This decreases CPU usage by wineserver from about 65% to about 45% for me in Street Fighter V, which for some reason calls this 15-20 times per second.
dlls/ntdll/unix/system.c | 177 ++++++++++++++++----------------------- server/process.c | 56 +++++++++++++ server/protocol.def | 30 +++++++ server/trace.c | 34 ++++++++ 4 files changed, 191 insertions(+), 106 deletions(-)
diff --git a/dlls/ntdll/unix/system.c b/dlls/ntdll/unix/system.c index 7045bc1550b..f89208997e2 100644 --- a/dlls/ntdll/unix/system.c +++ b/dlls/ntdll/unix/system.c @@ -2083,132 +2083,97 @@ 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; + const struct process_info *server_process; + void *buffer = NULL; - 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;
Shouldn't the allocated buffer size depend on the data to be read? If there's some very long paths there, the application buffer size may not be large enough, although it would have been enough to store the process infos with just their basename.
Maybe, though I doubt it matters in practice. SystemProcessInformation is by nature never going to have a stable length. In any case I wanted to avoid having to make even two server calls where one would suffice.
Or the server has to return only basenames, and assert that the client structures are larger than server request structures.
I guess stripping the rest of the path on the server side isn't a bad idea anyway, though.