Implemented thread and (partial) module snapshots, based on the work of Andreas Mohr <amohr@student.ei.uni-stuttgart.de>.
diff --git a/include/server.h b/include/server.h index 3ccf97e..72b2442 100644 --- a/include/server.h +++ b/include/server.h
@@ -789,6 +789,7 @@ { IN int inherit; /* inherit flag */ IN int flags; /* snapshot flags (TH32CS_*) */ + IN void* pid; /* process id */ OUT int handle; /* handle to the snapshot */ }; @@ -798,9 +799,33 @@ { IN int handle; /* handle to the snapshot */ IN int reset; /* reset snapshot position? */ - OUT void* pid; /* process id */ - OUT int threads; /* number of threads */ - OUT int priority; /* process priority */ + OUT int count; /* process usage count */ + OUT void* pid; /* process id */ + OUT int threads; /* number of threads */ + OUT int priority; /* process priority */ +}; + + +/* Get the next thread from a snapshot */ +struct next_thread_request +{ + IN int handle; /* handle to the snapshot */ + IN int reset; /* reset snapshot position? */ + OUT int count; /* thread usage count */ + OUT void* pid; /* process id */ + OUT void* tid; /* thread id */ + OUT int base_pri; /* base priority */ + OUT int delta_pri; /* delta priority */ +}; + + +/* Get the next module from a snapshot */ +struct next_module_request +{ + IN int handle; /* handle to the snapshot */ + IN int reset; /* reset snapshot position? */ + OUT void* pid; /* process id */ + OUT void* base; /* module base address */ }; @@ -1184,6 +1209,8 @@ REQ_CREATE_DEVICE, REQ_CREATE_SNAPSHOT, REQ_NEXT_PROCESS, + REQ_NEXT_THREAD, + REQ_NEXT_MODULE, REQ_WAIT_DEBUG_EVENT, REQ_EXCEPTION_EVENT, REQ_OUTPUT_DEBUG_STRING, @@ -1219,7 +1246,7 @@ REQ_NB_REQUESTS }; -#define SERVER_PROTOCOL_VERSION 8 +#define SERVER_PROTOCOL_VERSION 9 /* ### make_requests end ### */ /* Everything above this line is generated automatically by tools/make_requests */
diff --git a/include/tlhelp32.h b/include/tlhelp32.h index 05e6fcb..797aa7f 100644 --- a/include/tlhelp32.h +++ b/include/tlhelp32.h
@@ -1,19 +1,13 @@ #ifndef __WINE_TLHELP32_H #define __WINE_TLHELP32_H -#include "windef.h" - #ifdef __cplusplus extern "C" { #endif - /*=================================================================== - * Arguments for Toolhelp routines - */ - - /* - * CreateToolhelp32Snapshot - */ +/* + * CreateToolhelp32Snapshot + */ #define TH32CS_SNAPHEAPLIST 0x00000001 #define TH32CS_SNAPPROCESS 0x00000002 @@ -22,6 +16,118 @@ #define TH32CS_SNAPALL (TH32CS_SNAPHEAPLIST | TH32CS_SNAPPROCESS | TH32CS_SNAPTHREAD | TH32CS_SNAPMODULE) #define TH32CS_INHERIT 0x80000000 +HANDLE WINAPI CreateToolhelp32Snapshot(DWORD,DWORD); + +/* + * thread entry list as created by CreateToolHelp32Snapshot + */ + +typedef struct tagTHREADENTRY32 +{ + DWORD dwSize; + DWORD cntUsage; + DWORD th32ThreadID; + DWORD th32OwnerProcessID; + LONG tbBasePri; + LONG tbDeltaPri; + DWORD dwFlags; +} THREADENTRY32, *PTHREADENTRY32, *LPTHREADENTRY32; + +BOOL WINAPI Thread32First(HANDLE,LPTHREADENTRY32); +BOOL WINAPI Thread32Next(HANDLE,LPTHREADENTRY32); + +/* + * Process entry list as created by CreateToolHelp32Snapshot + */ + +typedef struct tagPROCESSENTRY32 +{ + DWORD dwSize; + DWORD cntUsage; + DWORD th32ProcessID; + DWORD th32DefaultHeapID; + DWORD th32ModuleID; + DWORD cntThreads; + DWORD th32ParentProcessID; + LONG pcPriClassBase; + DWORD dwFlags; + char szExeFile[MAX_PATH]; +} PROCESSENTRY32, *PPROCESSENTRY32, *LPPROCESSENTRY32; + +typedef struct tagPROCESSENTRY32W +{ + DWORD dwSize; + DWORD cntUsage; + DWORD th32ProcessID; + DWORD th32DefaultHeapID; + DWORD th32ModuleID; + DWORD cntThreads; + DWORD th32ParentProcessID; + LONG pcPriClassBase; + DWORD dwFlags; + WCHAR szExeFile[MAX_PATH]; +} PROCESSENTRY32W, *PPROCESSENTRY32W, *LPPROCESSENTRY32W; + +BOOL WINAPI Process32First(HANDLE,LPPROCESSENTRY32); +BOOL WINAPI Process32FirstW(HANDLE,LPPROCESSENTRY32W); +BOOL WINAPI Process32Next(HANDLE,LPPROCESSENTRY32); +BOOL WINAPI Process32NextW(HANDLE,LPPROCESSENTRY32W); + +#ifdef UNICODE +#define Process32First Process32FirstW +#define Process32Next Process32NextW +#define PROCESSENTRY32 PROCESSENTRY32W +#define PPROCESSENTRY32 PPROCESSENTRY32W +#define LPPROCESSENTRY32 LPPROCESSENTRY32W +#endif + +/* + * Module entry list as created by CreateToolHelp32Snapshot + */ + +#define MAX_MODULE_NAME32 255 + +typedef struct tagMODULEENTRY32 +{ + DWORD dwSize; + DWORD th32ModuleID; + DWORD th32ProcessID; + DWORD GlblcntUsage; + DWORD ProccntUsage; + BYTE *modBaseAddr; + DWORD modBaseSize; + DWORD hModule; + char szModule[MAX_MODULE_NAME32 + 1]; + char szExePath[MAX_PATH]; +} MODULEENTRY32, *PMODULEENTRY32, *LPMODULEENTRY32; + +typedef struct tagMODULEENTRY32W +{ + DWORD dwSize; + DWORD th32ModuleID; + DWORD th32ProcessID; + DWORD GlblcntUsage; + DWORD ProccntUsage; + BYTE *modBaseAddr; + DWORD modBaseSize; + DWORD hModule; + WCHAR szModule[MAX_MODULE_NAME32 + 1]; + WCHAR szExePath[MAX_PATH]; +} MODULEENTRY32W, *PMODULEENTRY32W, *LPMODULEENTRY32W; + +BOOL WINAPI Module32First(HANDLE,LPMODULEENTRY32); +BOOL WINAPI Module32FirstW(HANDLE,LPMODULEENTRY32W); +BOOL WINAPI Module32Next(HANDLE,LPMODULEENTRY32); +BOOL WINAPI Module32NextW(HANDLE,LPMODULEENTRY32W); + +#ifdef UNICODE +#define Module32First Module32FirstW +#define Module32Next Module32NextW +#define MODULEENTRY32 MODULEENTRY32W +#define PMODULEENTRY32 PMODULEENTRY32W +#define LPMODULEENTRY32 LPMODULEENTRY32W +#endif + #ifdef __cplusplus } /* extern "C" */ #endif
diff --git a/include/toolhelp.h b/include/toolhelp.h index 1fef7cd..735c4bb 100644 --- a/include/toolhelp.h +++ b/include/toolhelp.h
@@ -2,7 +2,6 @@ #define __WINE_TOOLHELP_H #include "windef.h" -#include "tlhelp32.h" #define MAX_DATA 11 #define MAX_MODULE_NAME 9 @@ -397,44 +396,4 @@ #include "poppack.h" -/* - * Thread entry list as created by CreateToolHelp32Snapshot - */ - -typedef struct tagTHREADENTRY { - DWORD dwSize; - DWORD cntUsage; - DWORD th32ThreadID; - DWORD th32OwnerProcessID; - DWORD tbBasePri; - DWORD tbDeltaPri; - DWORD dwFlags; - DWORD th32AccessKey; - DWORD th32CurrentProcessID; -} THREADENTRY, *PTHREADENTRY, *LPTHREADENTRY; - -BOOL WINAPI Thread32First(HANDLE,LPTHREADENTRY); -BOOL WINAPI Thread32Next(HANDLE,LPTHREADENTRY); - -/* - * Process entry list as created by CreateToolHelp32Snapshot - */ - -typedef struct tagPROCESSENTRY { - DWORD dwSize; - DWORD cntUsage; - DWORD th32ProcessID; - DWORD th32DefaultHeapID; - DWORD th32ModuleID; - DWORD cntThreads; - DWORD th32ParentProcessID; - LONG pcPriClassBase; - DWORD dwFlags; - char szExeFile[MAX_PATH]; -} PROCESSENTRY, *PPROCESSENTRY, *LPPROCESSENTRY; - -BOOL WINAPI Process32First(HANDLE,LPPROCESSENTRY); -BOOL WINAPI Process32Next(HANDLE,LPPROCESSENTRY); - - #endif /* __WINE_TOOLHELP_H */
diff --git a/misc/toolhelp.c b/misc/toolhelp.c index 36097af..4fb9529 100644 --- a/misc/toolhelp.c +++ b/misc/toolhelp.c
@@ -19,7 +19,7 @@ #include "server.h" #include "debugtools.h" -DEFAULT_DEBUG_CHANNEL(toolhelp) +DEFAULT_DEBUG_CHANNEL(toolhelp); /* FIXME: to make this working, we have to callback all these registered @@ -150,10 +150,9 @@ struct create_snapshot_request *req = get_req_buffer(); TRACE("%lx,%lx\n", flags, process ); - if (flags & (TH32CS_SNAPHEAPLIST|TH32CS_SNAPMODULE|TH32CS_SNAPTHREAD)) - FIXME("flags %lx not implemented\n", flags ); - if (!(flags & TH32CS_SNAPPROCESS)) + if (!(flags & (TH32CS_SNAPPROCESS|TH32CS_SNAPTHREAD|TH32CS_SNAPMODULE))) { + FIXME("flags %lx not implemented\n", flags ); SetLastError( ERROR_CALL_NOT_IMPLEMENTED ); return INVALID_HANDLE_VALUE; } @@ -161,23 +160,47 @@ /* Now do the snapshot */ req->flags = flags & ~TH32CS_INHERIT; req->inherit = (flags & TH32CS_INHERIT) != 0; + req->pid = (void *)process; server_call( REQ_CREATE_SNAPSHOT ); return req->handle; } /*********************************************************************** + * TOOLHELP_Thread32Next + * + * Implementation of Thread32First/Next + */ +static BOOL TOOLHELP_Thread32Next( HANDLE handle, LPTHREADENTRY32 lpte, BOOL first ) +{ + struct next_thread_request *req = get_req_buffer(); + + if (lpte->dwSize < sizeof(THREADENTRY32)) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(THREADENTRY32), lpte->dwSize); + return FALSE; + } + req->handle = handle; + req->reset = first; + if (server_call( REQ_NEXT_THREAD )) return FALSE; + lpte->cntUsage = req->count; + lpte->th32ThreadID = (DWORD)req->tid; + lpte->th32OwnerProcessID = (DWORD)req->pid; + lpte->tbBasePri = req->base_pri; + lpte->tbDeltaPri = req->delta_pri; + lpte->dwFlags = 0; /* SDK: "reserved; do not use" */ + return TRUE; +} + +/*********************************************************************** * Thread32First (KERNEL32.686) * * Return info about the first thread in a toolhelp32 snapshot */ -BOOL WINAPI Thread32First(HANDLE hSnapshot, LPTHREADENTRY lpte) +BOOL WINAPI Thread32First(HANDLE hSnapshot, LPTHREADENTRY32 lpte) { - if (!lpte) - return FALSE; - - FIXME("(%d,%p),stub!\n",hSnapshot,lpte); - return FALSE; + return TOOLHELP_Thread32Next(hSnapshot, lpte, TRUE); } /*********************************************************************** @@ -185,13 +208,9 @@ * * Return info about the "next" thread in a toolhelp32 snapshot */ -BOOL WINAPI Thread32Next(HANDLE hSnapshot, LPTHREADENTRY lpte) +BOOL WINAPI Thread32Next(HANDLE hSnapshot, LPTHREADENTRY32 lpte) { - if (!lpte) - return FALSE; - - FIXME("(%d,%p),stub!\n",hSnapshot,lpte); - return FALSE; + return TOOLHELP_Thread32Next(hSnapshot, lpte, FALSE); } /*********************************************************************** @@ -199,20 +218,20 @@ * * Implementation of Process32First/Next */ -static BOOL TOOLHELP_Process32Next( HANDLE handle, LPPROCESSENTRY lppe, BOOL first ) +static BOOL TOOLHELP_Process32Next( HANDLE handle, LPPROCESSENTRY32 lppe, BOOL first ) { struct next_process_request *req = get_req_buffer(); - if (lppe->dwSize < sizeof (PROCESSENTRY)) + if (lppe->dwSize < sizeof(PROCESSENTRY32)) { SetLastError( ERROR_INSUFFICIENT_BUFFER ); - ERR("Result buffer too small\n"); + ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(PROCESSENTRY32), lppe->dwSize); return FALSE; } req->handle = handle; req->reset = first; if (server_call( REQ_NEXT_PROCESS )) return FALSE; - lppe->cntUsage = 1; + lppe->cntUsage = req->count; lppe->th32ProcessID = (DWORD)req->pid; lppe->th32DefaultHeapID = 0; /* FIXME */ lppe->th32ModuleID = 0; /* FIXME */ @@ -230,7 +249,7 @@ * * Return info about the first process in a toolhelp32 snapshot */ -BOOL WINAPI Process32First(HANDLE hSnapshot, LPPROCESSENTRY lppe) +BOOL WINAPI Process32First(HANDLE hSnapshot, LPPROCESSENTRY32 lppe) { return TOOLHELP_Process32Next( hSnapshot, lppe, TRUE ); } @@ -240,20 +259,50 @@ * * Return info about the "next" process in a toolhelp32 snapshot */ -BOOL WINAPI Process32Next(HANDLE hSnapshot, LPPROCESSENTRY lppe) +BOOL WINAPI Process32Next(HANDLE hSnapshot, LPPROCESSENTRY32 lppe) { return TOOLHELP_Process32Next( hSnapshot, lppe, FALSE ); } + +/*********************************************************************** + * TOOLHELP_Module32Next + * + * Implementation of Module32First/Next + */ +static BOOL TOOLHELP_Module32Next( HANDLE handle, LPMODULEENTRY32 lpme, BOOL first ) +{ + struct next_module_request *req = get_req_buffer(); + + if (lpme->dwSize < sizeof (MODULEENTRY32)) + { + SetLastError( ERROR_INSUFFICIENT_BUFFER ); + ERR("Result buffer too small (req: %d, was: %ld)\n", sizeof(MODULEENTRY32), lpme->dwSize); + return FALSE; + } + req->handle = handle; + req->reset = first; + if (server_call( REQ_NEXT_MODULE )) return FALSE; + lpme->th32ModuleID = 0; /* toolhelp internal id, never used */ + lpme->th32ProcessID = (DWORD)req->pid; + lpme->GlblcntUsage = 0; /* FIXME */ + lpme->ProccntUsage = 0; /* FIXME */ + lpme->modBaseAddr = req->base; + lpme->modBaseSize = 0; /* FIXME */ + lpme->hModule = (DWORD)req->base; + lpme->szModule[0] = 0; /* FIXME */ + lpme->szExePath[0] = 0; /* FIXME */ + return TRUE; +} + /*********************************************************************** * Module32First (KERNEL32.527) * * Return info about the "first" module in a toolhelp32 snapshot */ -BOOL WINAPI Module32First(HANDLE hSnapshot, LPMODULEENTRY lpme) +BOOL WINAPI Module32First(HANDLE hSnapshot, LPMODULEENTRY32 lpme) { - FIXME("(%d,%p),stub!\n",hSnapshot,lpme); - return FALSE; + return TOOLHELP_Module32Next( hSnapshot, lpme, TRUE ); } /*********************************************************************** @@ -261,10 +310,9 @@ * * Return info about the "next" module in a toolhelp32 snapshot */ -BOOL WINAPI Module32Next(HANDLE hSnapshot, LPMODULEENTRY lpme) +BOOL WINAPI Module32Next(HANDLE hSnapshot, LPMODULEENTRY32 lpme) { - FIXME("(%d,%p),stub!\n",hSnapshot,lpme); - return FALSE; + return TOOLHELP_Module32Next( hSnapshot, lpme, FALSE ); } /************************************************************************
diff --git a/server/process.c b/server/process.c index 3cc87f6..c84672d 100644 --- a/server/process.c +++ b/server/process.c
@@ -563,6 +563,7 @@ if (!process->running_threads) continue; ptr->process = process; ptr->threads = process->running_threads; + ptr->count = process->obj.refcount; ptr->priority = process->priority; grab_object( process ); ptr++; @@ -571,6 +572,25 @@ return snapshot; } +/* take a snapshot of the modules of a process */ +struct module_snapshot *module_snap( struct process *process, int *count ) +{ + struct module_snapshot *snapshot, *ptr; + struct process_dll *dll; + int total = 0; + + for (dll = &process->exe; dll; dll = dll->next) total++; + if (!(snapshot = mem_alloc( sizeof(*snapshot) * total ))) return NULL; + + for (ptr = snapshot, dll = &process->exe; dll; dll = dll->next, ptr++) + { + ptr->base = dll->base; + } + *count = total; + return snapshot; +} + + /* create a new process */ DECL_HANDLER(new_process) {
diff --git a/server/process.h b/server/process.h index 6cdbb6a..6e98a47 100644 --- a/server/process.h +++ b/server/process.h
@@ -55,10 +55,16 @@ { struct process *process; /* process ptr */ struct process *parent; /* process parent */ + int count; /* process refcount */ int threads; /* number of threads */ int priority; /* priority class */ }; +struct module_snapshot +{ + void *base; /* module base addr */ +}; + /* process functions */ extern struct thread *create_process( int fd, struct process *parent, @@ -75,6 +81,7 @@ extern void resume_process( struct process *process ); extern void kill_debugged_processes( struct thread *debugger, int exit_code ); extern struct process_snapshot *process_snap( int *count ); +extern struct module_snapshot *module_snap( struct process *process, int *count ); static inline void *get_process_id( struct process *process ) { return process; }
diff --git a/server/request.h b/server/request.h index 03943d9..c7b970b 100644 --- a/server/request.h +++ b/server/request.h
@@ -138,6 +138,8 @@ DECL_HANDLER(create_device); DECL_HANDLER(create_snapshot); DECL_HANDLER(next_process); +DECL_HANDLER(next_thread); +DECL_HANDLER(next_module); DECL_HANDLER(wait_debug_event); DECL_HANDLER(exception_event); DECL_HANDLER(output_debug_string); @@ -244,6 +246,8 @@ (req_handler)req_create_device, (req_handler)req_create_snapshot, (req_handler)req_next_process, + (req_handler)req_next_thread, + (req_handler)req_next_module, (req_handler)req_wait_debug_event, (req_handler)req_exception_event, (req_handler)req_output_debug_string,
diff --git a/server/snapshot.c b/server/snapshot.c index 2a16ac5..3f806be 100644 --- a/server/snapshot.c +++ b/server/snapshot.c
@@ -3,7 +3,7 @@ * * Copyright (C) 1999 Alexandre Julliard * - * FIXME: only process snapshots implemented for now + * FIXME: heap snapshots not implemented */ #include <assert.h> @@ -22,9 +22,16 @@ struct snapshot { struct object obj; /* object header */ - struct process_snapshot *process; /* processes snapshot */ + struct process *process; /* process of this snapshot (for modules and heaps) */ + 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 */ + struct module_snapshot *modules; /* modules snapshot */ + int module_count; /* count of modules */ + int module_pos; /* current position in module snapshot */ }; static void snapshot_dump( struct object *obj, int verbose ); @@ -49,18 +56,41 @@ /* create a new snapshot */ -static struct snapshot *create_snapshot( int flags ) +static struct snapshot *create_snapshot( void *pid, int flags ) { + struct process *process = NULL; struct snapshot *snapshot; - if ((snapshot = alloc_object( &snapshot_ops, -1 ))) + /* need a process for modules and heaps */ + if (flags & (TH32CS_SNAPMODULE|TH32CS_SNAPHEAPLIST)) { - if (flags & TH32CS_SNAPPROCESS) - snapshot->process = process_snap( &snapshot->process_count ); - else - snapshot->process_count = 0; - snapshot->process_pos = 0; + if (!pid) process = (struct process *)grab_object( current->process ); + else if (!(process = get_process_from_id( pid ))) return NULL; } + + if (!(snapshot = alloc_object( &snapshot_ops, -1 ))) + { + if (process) release_object( process ); + return NULL; + } + + snapshot->process = process; + + snapshot->process_pos = 0; + snapshot->process_count = 0; + if (flags & TH32CS_SNAPPROCESS) + snapshot->processes = process_snap( &snapshot->process_count ); + + snapshot->thread_pos = 0; + snapshot->thread_count = 0; + if (flags & TH32CS_SNAPTHREAD) + snapshot->threads = thread_snap( &snapshot->thread_count ); + + snapshot->module_pos = 0; + snapshot->module_count = 0; + if (flags & TH32CS_SNAPMODULE) + snapshot->modules = module_snap( process, &snapshot->module_count ); + return snapshot; } @@ -80,19 +110,67 @@ set_error( STATUS_NO_MORE_FILES ); return 0; } - ptr = &snapshot->process[snapshot->process_pos++]; - req->pid = ptr->process; + ptr = &snapshot->processes[snapshot->process_pos++]; + req->count = ptr->count; + req->pid = get_process_id( ptr->process ); req->threads = ptr->threads; req->priority = ptr->priority; return 1; } +/* get the next thread in the snapshot */ +static int snapshot_next_thread( struct snapshot *snapshot, struct next_thread_request *req ) +{ + struct thread_snapshot *ptr; + + if (!snapshot->thread_count) + { + set_error( STATUS_INVALID_PARAMETER ); /* FIXME */ + return 0; + } + if (req->reset) snapshot->thread_pos = 0; + else if (snapshot->thread_pos >= snapshot->thread_count) + { + set_error( STATUS_NO_MORE_FILES ); + return 0; + } + ptr = &snapshot->threads[snapshot->thread_pos++]; + req->count = ptr->count; + req->pid = get_process_id( ptr->thread->process ); + req->tid = get_thread_id( ptr->thread ); + req->base_pri = ptr->priority; + req->delta_pri = 0; /* FIXME */ + return 1; +} + +/* get the next module in the snapshot */ +static int snapshot_next_module( struct snapshot *snapshot, struct next_module_request *req ) +{ + struct module_snapshot *ptr; + + if (!snapshot->module_count) + { + set_error( STATUS_INVALID_PARAMETER ); /* FIXME */ + return 0; + } + if (req->reset) snapshot->module_pos = 0; + else if (snapshot->module_pos >= snapshot->module_count) + { + set_error( STATUS_NO_MORE_FILES ); + return 0; + } + ptr = &snapshot->modules[snapshot->module_pos++]; + req->pid = get_process_id( snapshot->process ); + req->base = ptr->base; + 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 processes\n", - snapshot->process_count ); + fprintf( stderr, "Snapshot: %d procs %d threads %d modules\n", + snapshot->process_count, snapshot->thread_count, snapshot->module_count ); } static void snapshot_destroy( struct object *obj ) @@ -103,9 +181,17 @@ if (snapshot->process_count) { for (i = 0; i < snapshot->process_count; i++) - release_object( snapshot->process[i].process ); - free( snapshot->process ); + 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 ); + } + if (snapshot->module_count) free( snapshot->modules ); + if (snapshot->process) release_object( snapshot->process ); } /* create a snapshot */ @@ -114,7 +200,7 @@ struct snapshot *snapshot; req->handle = -1; - if ((snapshot = create_snapshot( req->flags ))) + if ((snapshot = create_snapshot( req->pid, req->flags ))) { req->handle = alloc_handle( current->process, snapshot, 0, req->inherit ); release_object( snapshot ); @@ -133,3 +219,29 @@ 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 ))) + { + snapshot_next_thread( snapshot, req ); + release_object( snapshot ); + } +} + +/* get the next module from a snapshot */ +DECL_HANDLER(next_module) +{ + struct snapshot *snapshot; + + if ((snapshot = (struct snapshot *)get_handle_obj( current->process, req->handle, + 0, &snapshot_ops ))) + { + snapshot_next_module( snapshot, req ); + release_object( snapshot ); + } +}
diff --git a/server/thread.c b/server/thread.c index 3963f60..eeedd2b 100644 --- a/server/thread.c +++ b/server/thread.c
@@ -580,6 +580,30 @@ release_object( thread ); } +/* 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; + + for (thread = first_thread; thread; thread = thread->next) + if (thread->state != TERMINATED) total++; + if (!total || !(snapshot = mem_alloc( sizeof(*snapshot) * total ))) return NULL; + ptr = snapshot; + for (thread = first_thread; thread; thread = thread->next) + { + 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; +} + /* signal that we are finished booting on the client side */ DECL_HANDLER(boot_done) {
diff --git a/server/thread.h b/server/thread.h index 2913a42..6f836dc 100644 --- a/server/thread.h +++ b/server/thread.h
@@ -58,6 +58,13 @@ enum request last_req; /* last request received (for debugging) */ }; +struct thread_snapshot +{ + struct thread *thread; /* thread ptr */ + int count; /* thread refcount */ + int priority; /* priority class */ +}; + /* callback function for building the thread reply when sleep_on is finished */ typedef void (*sleep_reply)( struct thread *thread, struct object *obj, int signaled ); @@ -79,6 +86,7 @@ extern void wake_up( struct object *obj, int max ); extern int sleep_on( int count, struct object *objects[], int flags, int timeout, sleep_reply func ); +extern struct thread_snapshot *thread_snap( int *count ); /* ptrace functions */
diff --git a/server/trace.c b/server/trace.c index aeba409..66b48bd 100644 --- a/server/trace.c +++ b/server/trace.c
@@ -929,7 +929,8 @@ static void dump_create_snapshot_request( const struct create_snapshot_request *req ) { fprintf( stderr, " inherit=%d,", req->inherit ); - fprintf( stderr, " flags=%d", req->flags ); + fprintf( stderr, " flags=%d,", req->flags ); + fprintf( stderr, " pid=%p", req->pid ); } static void dump_create_snapshot_reply( const struct create_snapshot_request *req ) @@ -945,11 +946,39 @@ static void dump_next_process_reply( const struct next_process_request *req ) { + fprintf( stderr, " count=%d,", req->count ); fprintf( stderr, " pid=%p,", req->pid ); fprintf( stderr, " threads=%d,", req->threads ); fprintf( stderr, " priority=%d", req->priority ); } +static void dump_next_thread_request( const struct next_thread_request *req ) +{ + fprintf( stderr, " handle=%d,", req->handle ); + fprintf( stderr, " reset=%d", req->reset ); +} + +static void dump_next_thread_reply( const struct next_thread_request *req ) +{ + fprintf( stderr, " count=%d,", req->count ); + fprintf( stderr, " pid=%p,", req->pid ); + fprintf( stderr, " tid=%p,", req->tid ); + fprintf( stderr, " base_pri=%d,", req->base_pri ); + fprintf( stderr, " delta_pri=%d", req->delta_pri ); +} + +static void dump_next_module_request( const struct next_module_request *req ) +{ + fprintf( stderr, " handle=%d,", req->handle ); + fprintf( stderr, " reset=%d", req->reset ); +} + +static void dump_next_module_reply( const struct next_module_request *req ) +{ + fprintf( stderr, " pid=%p,", req->pid ); + fprintf( stderr, " base=%p", req->base ); +} + static void dump_wait_debug_event_request( const struct wait_debug_event_request *req ) { fprintf( stderr, " timeout=%d", req->timeout ); @@ -1364,6 +1393,8 @@ (dump_func)dump_create_device_request, (dump_func)dump_create_snapshot_request, (dump_func)dump_next_process_request, + (dump_func)dump_next_thread_request, + (dump_func)dump_next_module_request, (dump_func)dump_wait_debug_event_request, (dump_func)dump_exception_event_request, (dump_func)dump_output_debug_string_request, @@ -1467,6 +1498,8 @@ (dump_func)dump_create_device_reply, (dump_func)dump_create_snapshot_reply, (dump_func)dump_next_process_reply, + (dump_func)dump_next_thread_reply, + (dump_func)dump_next_module_reply, (dump_func)dump_wait_debug_event_reply, (dump_func)dump_exception_event_reply, (dump_func)0, @@ -1570,6 +1603,8 @@ "create_device", "create_snapshot", "next_process", + "next_thread", + "next_module", "wait_debug_event", "exception_event", "output_debug_string",