Implemented thread and (partial) module snapshots, based on the work
of Andreas Mohr <amohr@student.ei.uni-stuttgart.de>.
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",