Added server snapshot support (processes only for now).
This commit is contained in:
parent
068a26e848
commit
fdc92bae07
|
@ -596,6 +596,32 @@ struct create_device_reply
|
|||
};
|
||||
|
||||
|
||||
/* Create a snapshot */
|
||||
struct create_snapshot_request
|
||||
{
|
||||
int inherit; /* inherit flag */
|
||||
int flags; /* snapshot flags (TH32CS_*) */
|
||||
};
|
||||
struct create_snapshot_reply
|
||||
{
|
||||
int handle; /* handle to the snapshot */
|
||||
};
|
||||
|
||||
|
||||
/* Get the next process from a snapshot */
|
||||
struct next_process_request
|
||||
{
|
||||
int handle; /* handle to the snapshot */
|
||||
int reset; /* reset snapshot position? */
|
||||
};
|
||||
struct next_process_reply
|
||||
{
|
||||
void* pid; /* process id */
|
||||
int threads; /* number of threads */
|
||||
int priority; /* process priority */
|
||||
};
|
||||
|
||||
|
||||
/* client-side functions */
|
||||
|
||||
#ifndef __WINE_SERVER__
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
struct object;
|
||||
struct object_name;
|
||||
struct thread;
|
||||
struct process;
|
||||
struct file;
|
||||
struct wait_queue_entry;
|
||||
|
||||
|
@ -119,42 +120,6 @@ extern void set_timeout( int client_fd, struct timeval *when );
|
|||
extern int send_reply_v( int client_fd, int type, int pass_fd,
|
||||
struct iovec *vec, int veclen );
|
||||
|
||||
/* process functions */
|
||||
|
||||
struct process;
|
||||
|
||||
extern struct process *create_process(void);
|
||||
extern struct process *get_process_from_id( void *id );
|
||||
extern struct process *get_process_from_handle( int handle, unsigned int access );
|
||||
extern void add_process_thread( struct process *process,
|
||||
struct thread *thread );
|
||||
extern void remove_process_thread( struct process *process,
|
||||
struct thread *thread );
|
||||
extern void kill_process( struct process *process, int exit_code );
|
||||
extern void get_process_info( struct process *process,
|
||||
struct get_process_info_reply *reply );
|
||||
extern void set_process_info( struct process *process,
|
||||
struct set_process_info_request *req );
|
||||
extern int alloc_console( struct process *process );
|
||||
extern int free_console( struct process *process );
|
||||
extern struct object *get_console( struct process *process, int output );
|
||||
|
||||
/* handle functions */
|
||||
|
||||
/* alloc_handle takes a void *obj for convenience, but you better make sure */
|
||||
/* that the thing pointed to starts with a struct object... */
|
||||
extern int alloc_handle( struct process *process, void *obj,
|
||||
unsigned int access, int inherit );
|
||||
extern int close_handle( struct process *process, int handle );
|
||||
extern int set_handle_info( struct process *process, int handle,
|
||||
int mask, int flags );
|
||||
extern struct object *get_handle_obj( struct process *process, int handle,
|
||||
unsigned int access, const struct object_ops *ops );
|
||||
extern int duplicate_handle( struct process *src, int src_handle, struct process *dst,
|
||||
int dst_handle, unsigned int access, int inherit, int options );
|
||||
extern int open_object( const char *name, const struct object_ops *ops,
|
||||
unsigned int access, int inherit );
|
||||
|
||||
/* event functions */
|
||||
|
||||
extern struct object *create_event( const char *name, int manual_reset, int initial_state );
|
||||
|
@ -232,6 +197,10 @@ extern int get_mapping_info( int handle, struct get_mapping_info_reply *reply );
|
|||
extern struct object *create_device( int id );
|
||||
|
||||
|
||||
/* snapshot functions */
|
||||
extern struct object *create_snapshot( int flags );
|
||||
extern int snapshot_next_process( int handle, int reset, struct next_process_reply *reply );
|
||||
|
||||
extern int debug_level;
|
||||
|
||||
#endif /* __WINE_SERVER_OBJECT_H */
|
||||
|
|
|
@ -53,6 +53,8 @@ enum request
|
|||
REQ_CREATE_MAPPING,
|
||||
REQ_GET_MAPPING_INFO,
|
||||
REQ_CREATE_DEVICE,
|
||||
REQ_CREATE_SNAPSHOT,
|
||||
REQ_NEXT_PROCESS,
|
||||
REQ_NB_REQUESTS
|
||||
};
|
||||
|
||||
|
@ -109,6 +111,8 @@ DECL_HANDLER(create_change_notification);
|
|||
DECL_HANDLER(create_mapping);
|
||||
DECL_HANDLER(get_mapping_info);
|
||||
DECL_HANDLER(create_device);
|
||||
DECL_HANDLER(create_snapshot);
|
||||
DECL_HANDLER(next_process);
|
||||
|
||||
static const struct handler {
|
||||
void (*handler)();
|
||||
|
@ -162,6 +166,8 @@ static const struct handler {
|
|||
{ (void(*)())req_create_mapping, sizeof(struct create_mapping_request) },
|
||||
{ (void(*)())req_get_mapping_info, sizeof(struct get_mapping_info_request) },
|
||||
{ (void(*)())req_create_device, sizeof(struct create_device_request) },
|
||||
{ (void(*)())req_create_snapshot, sizeof(struct create_snapshot_request) },
|
||||
{ (void(*)())req_next_process, sizeof(struct next_process_request) },
|
||||
};
|
||||
#endif /* WANT_REQUEST_HANDLERS */
|
||||
|
||||
|
|
368
misc/toolhelp.c
368
misc/toolhelp.c
|
@ -17,39 +17,15 @@
|
|||
#include "toolhelp.h"
|
||||
#include "heap.h"
|
||||
#include "k32obj.h"
|
||||
#include "server.h"
|
||||
#include "debug.h"
|
||||
|
||||
/*
|
||||
* Support for toolhelp's snapshots. They
|
||||
* are supposed to be Kernel32 Objects.
|
||||
* Only the Destroy() method is implemented
|
||||
*/
|
||||
|
||||
static void SNAPSHOT_Destroy( K32OBJ *obj );
|
||||
|
||||
const K32OBJ_OPS SNAPSHOT_Ops =
|
||||
{
|
||||
SNAPSHOT_Destroy /* destroy */
|
||||
};
|
||||
|
||||
/* The K32 snapshot object object */
|
||||
/* Process snapshot kernel32 object */
|
||||
typedef struct _Process32Snapshot
|
||||
typedef struct
|
||||
{
|
||||
K32OBJ header;
|
||||
|
||||
DWORD numProcs;
|
||||
DWORD arrayCounter;
|
||||
/*
|
||||
* Store a reference to the PDB list.
|
||||
* Insuure in the alloc and dealloc routines for this structure that
|
||||
* I increment and decrement the pdb->head.refcount, so that the
|
||||
* original pdb will stay around for as long as I use it, but it's
|
||||
* not locked forver into memory.
|
||||
*/
|
||||
PDB32 **processArray;
|
||||
}
|
||||
SNAPSHOT_OBJECT;
|
||||
K32OBJ header;
|
||||
} SNAPSHOT_OBJECT;
|
||||
|
||||
/* FIXME: to make this working, we have to callback all these registered
|
||||
* functions from all over the WINE code. Someone with more knowledge than
|
||||
|
@ -139,299 +115,93 @@ FARPROC16 tmp;
|
|||
return tmp;
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* SNAPSHOT_Destroy
|
||||
*
|
||||
* Deallocate K32 snapshot objects
|
||||
*/
|
||||
static void SNAPSHOT_Destroy (K32OBJ *obj)
|
||||
{
|
||||
int i;
|
||||
SNAPSHOT_OBJECT *snapshot = (SNAPSHOT_OBJECT *) obj;
|
||||
assert (obj->type == K32OBJ_CHANGE);
|
||||
|
||||
if (snapshot->processArray)
|
||||
{
|
||||
for (i = 0; snapshot->processArray[i] && i <snapshot->numProcs; i++)
|
||||
{
|
||||
K32OBJ_DecCount (&snapshot->processArray[i]->header);
|
||||
}
|
||||
HeapFree (GetProcessHeap (), 0, snapshot->processArray);
|
||||
snapshot->processArray = NULL;
|
||||
}
|
||||
|
||||
obj->type = K32OBJ_UNKNOWN;
|
||||
HeapFree (GetProcessHeap (), 0, snapshot);
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* CreateToolHelp32Snapshot (KERNEL32.179)
|
||||
* see "Undocumented Windows"
|
||||
*/
|
||||
HANDLE32 WINAPI CreateToolhelp32Snapshot(DWORD dwFlags, DWORD
|
||||
th32ProcessID)
|
||||
HANDLE32 WINAPI CreateToolhelp32Snapshot( DWORD flags, DWORD process )
|
||||
{
|
||||
HANDLE32 ssHandle;
|
||||
SNAPSHOT_OBJECT *snapshot;
|
||||
int numProcesses;
|
||||
int i;
|
||||
PDB32* pdb;
|
||||
SNAPSHOT_OBJECT *snapshot;
|
||||
struct create_snapshot_request req;
|
||||
struct create_snapshot_reply reply;
|
||||
|
||||
TRACE(toolhelp, "%lx & TH32CS_INHERIT (%x) = %lx %s\n", dwFlags,
|
||||
TH32CS_INHERIT,
|
||||
dwFlags & TH32CS_INHERIT,
|
||||
dwFlags & TH32CS_INHERIT ? "TRUE" : "FALSE");
|
||||
TRACE(toolhelp, "%lx & TH32CS_SNAPHEAPLIST (%x) = %lx %s\n", dwFlags,
|
||||
TH32CS_SNAPHEAPLIST,
|
||||
dwFlags & TH32CS_SNAPHEAPLIST,
|
||||
dwFlags & TH32CS_SNAPHEAPLIST ? "TRUE" : "FALSE");
|
||||
TRACE(toolhelp, "%lx & TH32CS_SNAPMODULE (%x) = %lx %s\n", dwFlags,
|
||||
TH32CS_SNAPMODULE,
|
||||
dwFlags & TH32CS_SNAPMODULE,
|
||||
dwFlags & TH32CS_SNAPMODULE ? "TRUE" : "FALSE");
|
||||
TRACE(toolhelp, "%lx & TH32CS_SNAPPROCESS (%x) = %lx %s\n", dwFlags,
|
||||
TH32CS_SNAPPROCESS,
|
||||
dwFlags & TH32CS_SNAPPROCESS,
|
||||
dwFlags & TH32CS_SNAPPROCESS ? "TRUE" : "FALSE");
|
||||
TRACE(toolhelp, "%lx & TH32CS_SNAPTHREAD (%x) = %lx %s\n", dwFlags,
|
||||
TH32CS_SNAPTHREAD,
|
||||
dwFlags & TH32CS_SNAPTHREAD,
|
||||
dwFlags & TH32CS_SNAPTHREAD ? "TRUE" : "FALSE");
|
||||
|
||||
/**** FIXME: Not implmented ***/
|
||||
if (dwFlags & TH32CS_INHERIT)
|
||||
TRACE( toolhelp, "%lx,%lx\n", flags, process );
|
||||
if (flags & (TH32CS_SNAPHEAPLIST|TH32CS_SNAPMODULE|TH32CS_SNAPTHREAD))
|
||||
FIXME( toolhelp, "flags %lx not implemented\n", flags );
|
||||
if (!(flags & TH32CS_SNAPPROCESS))
|
||||
{
|
||||
FIXME(toolhelp,"(0x%08lx (TH32CS_INHERIT),0x%08lx), stub!\n",
|
||||
dwFlags,th32ProcessID);
|
||||
|
||||
return INVALID_HANDLE_VALUE32;
|
||||
SetLastError( ERROR_CALL_NOT_IMPLEMENTED );
|
||||
return INVALID_HANDLE_VALUE32;
|
||||
}
|
||||
if (dwFlags & TH32CS_SNAPHEAPLIST)
|
||||
/* Now do the snapshot */
|
||||
if (!(snapshot = HeapAlloc( SystemHeap, 0, sizeof(*snapshot) )))
|
||||
return INVALID_HANDLE_VALUE32;
|
||||
snapshot->header.type = K32OBJ_TOOLHELP_SNAPSHOT;
|
||||
snapshot->header.refcount = 1;
|
||||
|
||||
req.flags = flags & ~TH32CS_INHERIT;
|
||||
req.inherit = (flags & TH32CS_INHERIT) != 0;
|
||||
CLIENT_SendRequest( REQ_CREATE_SNAPSHOT, -1, 1, &req, sizeof(req) );
|
||||
if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL ))
|
||||
{
|
||||
FIXME(toolhelp,"(0x%08lx (TH32CS_SNAPHEAPLIST),0x%08lx), stub!\n",
|
||||
dwFlags,th32ProcessID);
|
||||
return INVALID_HANDLE_VALUE32;
|
||||
HeapFree( SystemHeap, 0, snapshot );
|
||||
return INVALID_HANDLE_VALUE32;
|
||||
}
|
||||
if (dwFlags & TH32CS_SNAPMODULE)
|
||||
{
|
||||
FIXME(toolhelp,"(0x%08lx (TH32CS_SNAPMODULE),0x%08lx), stub!\n",
|
||||
dwFlags,th32ProcessID);
|
||||
return INVALID_HANDLE_VALUE32;
|
||||
}
|
||||
|
||||
if (dwFlags & TH32CS_SNAPPROCESS)
|
||||
{
|
||||
TRACE (toolhelp, "(0x%08lx (TH32CS_SNAPMODULE),0x%08lx)\n",
|
||||
dwFlags,th32ProcessID);
|
||||
snapshot = HeapAlloc (GetProcessHeap (), 0, sizeof
|
||||
(SNAPSHOT_OBJECT));
|
||||
if (!snapshot)
|
||||
{
|
||||
return INVALID_HANDLE_VALUE32;
|
||||
}
|
||||
|
||||
snapshot->header.type = K32OBJ_TOOLHELP_SNAPSHOT;
|
||||
snapshot->header.refcount = 1;
|
||||
snapshot->arrayCounter = 0;
|
||||
|
||||
/*
|
||||
* Lock here, to prevent processes from being created or
|
||||
* destroyed while the snapshot is gathered
|
||||
*/
|
||||
|
||||
SYSTEM_LOCK ();
|
||||
numProcesses = PROCESS_PDBList_Getsize ();
|
||||
|
||||
snapshot->processArray = (PDB32**)
|
||||
HeapAlloc (GetProcessHeap (), 0, sizeof (PDB32*) * numProcesses);
|
||||
|
||||
if (!snapshot->processArray)
|
||||
{
|
||||
HeapFree (GetProcessHeap (), 0, snapshot->processArray);
|
||||
SetLastError (INVALID_HANDLE_VALUE32);
|
||||
ERR (toolhelp, "Error allocating %d bytes for snapshot\n",
|
||||
sizeof (PDB32*) * numProcesses);
|
||||
return INVALID_HANDLE_VALUE32;
|
||||
}
|
||||
|
||||
snapshot->numProcs = numProcesses;
|
||||
|
||||
pdb = PROCESS_PDBList_Getfirst ();
|
||||
for (i = 0; pdb && i < numProcesses; i++)
|
||||
{
|
||||
TRACE (toolhelp, "Saving ref to pdb %ld\n", PDB_TO_PROCESS_ID(pdb));
|
||||
snapshot->processArray[i] = pdb;
|
||||
K32OBJ_IncCount (&pdb->header);
|
||||
pdb = PROCESS_PDBList_Getnext (pdb);
|
||||
}
|
||||
SYSTEM_UNLOCK ();
|
||||
|
||||
ssHandle = HANDLE_Alloc (PROCESS_Current (), &snapshot->header,
|
||||
FILE_ALL_ACCESS, TRUE, -1);
|
||||
if (ssHandle == INVALID_HANDLE_VALUE32)
|
||||
{
|
||||
/* HANDLE_Alloc is supposed to deallocate the
|
||||
* heap memory if it fails. This code doesn't need to.
|
||||
*/
|
||||
SetLastError (INVALID_HANDLE_VALUE32);
|
||||
ERR (toolhelp, "Error allocating handle\n");
|
||||
return INVALID_HANDLE_VALUE32;
|
||||
}
|
||||
|
||||
TRACE (toolhelp, "snapshotted %d processes, expected %d\n",
|
||||
i, numProcesses);
|
||||
return ssHandle;
|
||||
}
|
||||
|
||||
if (dwFlags & TH32CS_SNAPTHREAD)
|
||||
{
|
||||
FIXME(toolhelp,"(0x%08lx (TH32CS_SNAPMODULE),0x%08lx), stub!\n",
|
||||
dwFlags,th32ProcessID);
|
||||
return INVALID_HANDLE_VALUE32;
|
||||
}
|
||||
|
||||
return INVALID_HANDLE_VALUE32;
|
||||
return HANDLE_Alloc( PROCESS_Current(), &snapshot->header, 0, req.inherit, reply.handle );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* Process32First
|
||||
* TOOLHELP_Process32Next
|
||||
*
|
||||
* Implementation of Process32First/Next
|
||||
*/
|
||||
static BOOL32 TOOLHELP_Process32Next( HANDLE32 handle, LPPROCESSENTRY32 lppe, BOOL32 first )
|
||||
{
|
||||
struct next_process_request req;
|
||||
struct next_process_reply reply;
|
||||
|
||||
if (lppe->dwSize < sizeof (PROCESSENTRY32))
|
||||
{
|
||||
SetLastError( ERROR_INSUFFICIENT_BUFFER );
|
||||
ERR (toolhelp, "Result buffer too small\n");
|
||||
return FALSE;
|
||||
}
|
||||
if ((req.handle = HANDLE_GetServerHandle( PROCESS_Current(), handle,
|
||||
K32OBJ_TOOLHELP_SNAPSHOT, 0 )) == -1)
|
||||
return FALSE;
|
||||
req.reset = first;
|
||||
CLIENT_SendRequest( REQ_NEXT_PROCESS, -1, 1, &req, sizeof(req) );
|
||||
if (CLIENT_WaitSimpleReply( &reply, sizeof(reply), NULL )) return FALSE;
|
||||
lppe->cntUsage = 1;
|
||||
lppe->th32ProcessID = (DWORD)reply.pid;
|
||||
lppe->th32DefaultHeapID = 0; /* FIXME */
|
||||
lppe->th32ModuleID = 0; /* FIXME */
|
||||
lppe->cntThreads = reply.threads;
|
||||
lppe->th32ParentProcessID = 0; /* FIXME */
|
||||
lppe->pcPriClassBase = reply.priority;
|
||||
lppe->dwFlags = -1; /* FIXME */
|
||||
lppe->szExeFile[0] = 0; /* FIXME */
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* Process32First (KERNEL32.555)
|
||||
*
|
||||
* Return info about the first process in a toolhelp32 snapshot
|
||||
*/
|
||||
BOOL32 WINAPI Process32First(HANDLE32 hSnapshot, LPPROCESSENTRY32 lppe)
|
||||
{
|
||||
PDB32 *pdb;
|
||||
SNAPSHOT_OBJECT *snapshot;
|
||||
int i;
|
||||
|
||||
TRACE (toolhelp, "(0x%08lx,0x%08lx)\n", (DWORD) hSnapshot,
|
||||
(DWORD) lppe);
|
||||
|
||||
if (lppe->dwSize < sizeof (PROCESSENTRY32))
|
||||
{
|
||||
SetLastError (ERROR_INSUFFICIENT_BUFFER);
|
||||
ERR (toolhelp, "Result buffer too small\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
SYSTEM_LOCK ();
|
||||
snapshot = (SNAPSHOT_OBJECT*) HANDLE_GetObjPtr (PROCESS_Current (),
|
||||
hSnapshot,
|
||||
K32OBJ_UNKNOWN,
|
||||
FILE_ALL_ACCESS,
|
||||
NULL);
|
||||
if (!snapshot)
|
||||
{
|
||||
SYSTEM_UNLOCK ();
|
||||
SetLastError (ERROR_INVALID_HANDLE);
|
||||
ERR (toolhelp, "Error retreiving snapshot\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
snapshot->arrayCounter = i = 0;
|
||||
pdb = snapshot->processArray[i];
|
||||
|
||||
if (!pdb)
|
||||
{
|
||||
SetLastError (ERROR_NO_MORE_FILES);
|
||||
ERR (toolhelp, "End of snapshot array\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TRACE (toolhelp, "Returning info on process %d, id %ld\n",
|
||||
i, PDB_TO_PROCESS_ID (pdb));
|
||||
|
||||
lppe->cntUsage = 1;
|
||||
lppe->th32ProcessID = PDB_TO_PROCESS_ID (pdb);
|
||||
lppe->th32DefaultHeapID = (DWORD) pdb->heap;
|
||||
lppe->cntThreads = pdb->threads;
|
||||
lppe->th32ParentProcessID = PDB_TO_PROCESS_ID (pdb->parent);
|
||||
lppe->pcPriClassBase = 6; /* FIXME: this is a made-up value */
|
||||
lppe->dwFlags = -1; /* FIXME: RESERVED by Microsoft :-) */
|
||||
if (pdb->exe_modref)
|
||||
{
|
||||
lppe->th32ModuleID = (DWORD) pdb->exe_modref->module;
|
||||
strncpy (lppe->szExeFile, pdb->exe_modref->longname,
|
||||
sizeof (lppe->szExeFile));
|
||||
}
|
||||
else
|
||||
{
|
||||
lppe->th32ModuleID = (DWORD) 0;
|
||||
strcpy (lppe->szExeFile, "");
|
||||
}
|
||||
|
||||
SYSTEM_UNLOCK ();
|
||||
|
||||
return TRUE;
|
||||
return TOOLHELP_Process32Next( hSnapshot, lppe, TRUE );
|
||||
}
|
||||
|
||||
/***********************************************************************
|
||||
* Process32Next
|
||||
* Process32Next (KERNEL32.556)
|
||||
*
|
||||
* Return info about the "next" process in a toolhelp32 snapshot
|
||||
*/
|
||||
BOOL32 WINAPI Process32Next(HANDLE32 hSnapshot, LPPROCESSENTRY32 lppe)
|
||||
{
|
||||
PDB32 *pdb;
|
||||
SNAPSHOT_OBJECT *snapshot;
|
||||
int i;
|
||||
|
||||
TRACE (toolhelp, "(0x%08lx,0x%08lx)\n", (DWORD) hSnapshot,
|
||||
(DWORD) lppe);
|
||||
|
||||
if (lppe->dwSize < sizeof (PROCESSENTRY32))
|
||||
{
|
||||
SetLastError (ERROR_INSUFFICIENT_BUFFER);
|
||||
ERR (toolhelp, "Result buffer too small\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
SYSTEM_LOCK ();
|
||||
snapshot = (SNAPSHOT_OBJECT*) HANDLE_GetObjPtr (PROCESS_Current (),
|
||||
hSnapshot,
|
||||
K32OBJ_UNKNOWN,
|
||||
FILE_ALL_ACCESS,
|
||||
NULL);
|
||||
if (!snapshot)
|
||||
{
|
||||
SYSTEM_UNLOCK ();
|
||||
SetLastError (ERROR_INVALID_HANDLE);
|
||||
ERR (toolhelp, "Error retreiving snapshot\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
snapshot->arrayCounter ++;
|
||||
i = snapshot->arrayCounter;
|
||||
pdb = snapshot->processArray[i];
|
||||
|
||||
if (!pdb || snapshot->arrayCounter >= snapshot->numProcs)
|
||||
{
|
||||
SetLastError (ERROR_NO_MORE_FILES);
|
||||
ERR (toolhelp, "End of snapshot array\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
TRACE (toolhelp, "Returning info on process %d, id %ld\n",
|
||||
i, PDB_TO_PROCESS_ID (pdb));
|
||||
|
||||
lppe->cntUsage = 1;
|
||||
lppe->th32ProcessID = PDB_TO_PROCESS_ID (pdb);
|
||||
lppe->th32DefaultHeapID = (DWORD) pdb->heap;
|
||||
lppe->cntThreads = pdb->threads;
|
||||
lppe->th32ParentProcessID = PDB_TO_PROCESS_ID (pdb->parent);
|
||||
lppe->pcPriClassBase = 6; /* FIXME: this is a made-up value */
|
||||
lppe->dwFlags = -1; /* FIXME: RESERVED by Microsoft :-) */
|
||||
if (pdb->exe_modref)
|
||||
{
|
||||
lppe->th32ModuleID = (DWORD) pdb->exe_modref->module;
|
||||
strncpy (lppe->szExeFile, pdb->exe_modref->longname,
|
||||
sizeof (lppe->szExeFile));
|
||||
}
|
||||
else
|
||||
{
|
||||
lppe->th32ModuleID = (DWORD) 0;
|
||||
strcpy (lppe->szExeFile, "");
|
||||
}
|
||||
|
||||
SYSTEM_UNLOCK ();
|
||||
|
||||
return TRUE;
|
||||
return TOOLHELP_Process32Next( hSnapshot, lppe, FALSE );
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ C_SRCS = \
|
|||
pipe.c \
|
||||
process.c \
|
||||
request.c \
|
||||
snapshot.c \
|
||||
select.c \
|
||||
semaphore.c \
|
||||
socket.c \
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "winnt.h"
|
||||
|
||||
#include "server.h"
|
||||
#include "server/process.h"
|
||||
#include "server/thread.h"
|
||||
|
||||
/* reserved handle access rights */
|
||||
|
@ -60,6 +61,7 @@ struct process
|
|||
|
||||
static struct process *first_process;
|
||||
static struct process *initial_process;
|
||||
static int running_processes;
|
||||
|
||||
#define MIN_HANDLE_ENTRIES 32
|
||||
|
||||
|
@ -214,7 +216,7 @@ void add_process_thread( struct process *process, struct thread *thread )
|
|||
thread->proc_prev = NULL;
|
||||
if (thread->proc_next) thread->proc_next->proc_prev = thread;
|
||||
process->thread_list = thread;
|
||||
process->running_threads++;
|
||||
if (!process->running_threads++) running_processes++;
|
||||
grab_object( thread );
|
||||
}
|
||||
|
||||
|
@ -231,6 +233,7 @@ void remove_process_thread( struct process *process, struct thread *thread )
|
|||
if (!--process->running_threads)
|
||||
{
|
||||
/* we have removed the last running thread, exit the process */
|
||||
running_processes--;
|
||||
process_killed( process, thread->exit_code );
|
||||
}
|
||||
release_object( thread );
|
||||
|
@ -573,3 +576,25 @@ struct object *get_console( struct process *process, int output )
|
|||
return NULL;
|
||||
return grab_object( obj );
|
||||
}
|
||||
|
||||
/* 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;
|
||||
for (process = first_process; process; process = process->next)
|
||||
{
|
||||
if (!process->running_threads) continue;
|
||||
ptr->process = process;
|
||||
ptr->threads = process->running_threads;
|
||||
ptr->priority = process->priority;
|
||||
grab_object( process );
|
||||
ptr++;
|
||||
}
|
||||
*count = running_processes;
|
||||
return snapshot;
|
||||
}
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#define WANT_REQUEST_HANDLERS
|
||||
#include "server.h"
|
||||
#include "server/request.h"
|
||||
#include "server/process.h"
|
||||
#include "server/thread.h"
|
||||
|
||||
/* check that the string is NULL-terminated and that the len is correct */
|
||||
|
@ -754,3 +755,26 @@ DECL_HANDLER(create_device)
|
|||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* create a snapshot */
|
||||
DECL_HANDLER(create_snapshot)
|
||||
{
|
||||
struct object *obj;
|
||||
struct create_snapshot_reply reply = { -1 };
|
||||
|
||||
if ((obj = create_snapshot( req->flags )))
|
||||
{
|
||||
reply.handle = alloc_handle( current->process, obj, 0, req->inherit );
|
||||
release_object( obj );
|
||||
}
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
/* get the next process from a snapshot */
|
||||
DECL_HANDLER(next_process)
|
||||
{
|
||||
struct next_process_reply reply;
|
||||
snapshot_next_process( req->handle, req->reset, &reply );
|
||||
send_reply( current, -1, 1, &reply, sizeof(reply) );
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
/*
|
||||
* Server-side snapshots
|
||||
*
|
||||
* Copyright (C) 1999 Alexandre Julliard
|
||||
*
|
||||
* FIXME: only process snapshots implemented for now
|
||||
*/
|
||||
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "winerror.h"
|
||||
#include "winnt.h"
|
||||
#include "tlhelp32.h"
|
||||
#include "server/process.h"
|
||||
#include "server/thread.h"
|
||||
|
||||
|
||||
struct snapshot
|
||||
{
|
||||
struct object obj; /* object header */
|
||||
struct process_snapshot *process; /* processes snapshot */
|
||||
int process_count; /* count of processes */
|
||||
int process_pos; /* current position in proc snapshot */
|
||||
};
|
||||
|
||||
static void snapshot_dump( struct object *obj, int verbose );
|
||||
static void snapshot_destroy( struct object *obj );
|
||||
|
||||
static const struct object_ops snapshot_ops =
|
||||
{
|
||||
snapshot_dump,
|
||||
no_add_queue,
|
||||
NULL, /* should never get called */
|
||||
NULL, /* should never get called */
|
||||
NULL, /* should never get called */
|
||||
no_read_fd,
|
||||
no_write_fd,
|
||||
no_flush,
|
||||
no_get_file_info,
|
||||
snapshot_destroy
|
||||
};
|
||||
|
||||
|
||||
/* create a new snapshot */
|
||||
struct object *create_snapshot( int flags )
|
||||
{
|
||||
struct snapshot *snapshot;
|
||||
if (!(snapshot = mem_alloc( sizeof(*snapshot) ))) return NULL;
|
||||
init_object( &snapshot->obj, &snapshot_ops, NULL );
|
||||
if (flags & TH32CS_SNAPPROCESS)
|
||||
snapshot->process = process_snap( &snapshot->process_count );
|
||||
else
|
||||
snapshot->process_count = 0;
|
||||
|
||||
snapshot->process_pos = 0;
|
||||
return &snapshot->obj;
|
||||
}
|
||||
|
||||
/* get the next process in the snapshot */
|
||||
int snapshot_next_process( int handle, int reset, struct next_process_reply *reply )
|
||||
{
|
||||
struct snapshot *snapshot;
|
||||
struct process_snapshot *ptr;
|
||||
if (!(snapshot = (struct snapshot *)get_handle_obj( current->process, handle,
|
||||
0, &snapshot_ops )))
|
||||
return 0;
|
||||
if (!snapshot->process_count)
|
||||
{
|
||||
SET_ERROR( ERROR_INVALID_PARAMETER ); /* FIXME */
|
||||
release_object( snapshot );
|
||||
return 0;
|
||||
}
|
||||
if (reset) snapshot->process_pos = 0;
|
||||
else if (snapshot->process_pos >= snapshot->process_count)
|
||||
{
|
||||
SET_ERROR( ERROR_NO_MORE_FILES );
|
||||
release_object( snapshot );
|
||||
return 0;
|
||||
}
|
||||
ptr = &snapshot->process[snapshot->process_pos++];
|
||||
reply->pid = ptr->process;
|
||||
reply->threads = ptr->threads;
|
||||
reply->priority = ptr->priority;
|
||||
release_object( snapshot );
|
||||
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 );
|
||||
}
|
||||
|
||||
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->process[i].process );
|
||||
free( snapshot->process );
|
||||
}
|
||||
free( snapshot );
|
||||
}
|
|
@ -541,6 +541,34 @@ static int dump_create_device_reply( struct create_device_reply *req, int len )
|
|||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_create_snapshot_request( struct create_snapshot_request *req, int len )
|
||||
{
|
||||
fprintf( stderr, " inherit=%d,", req->inherit );
|
||||
fprintf( stderr, " flags=%d", req->flags );
|
||||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_create_snapshot_reply( struct create_snapshot_reply *req, int len )
|
||||
{
|
||||
fprintf( stderr, " handle=%d", req->handle );
|
||||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_next_process_request( struct next_process_request *req, int len )
|
||||
{
|
||||
fprintf( stderr, " handle=%d,", req->handle );
|
||||
fprintf( stderr, " reset=%d", req->reset );
|
||||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
static int dump_next_process_reply( struct next_process_reply *req, int len )
|
||||
{
|
||||
fprintf( stderr, " pid=%p,", req->pid );
|
||||
fprintf( stderr, " threads=%d,", req->threads );
|
||||
fprintf( stderr, " priority=%d", req->priority );
|
||||
return (int)sizeof(*req);
|
||||
}
|
||||
|
||||
struct dumper
|
||||
{
|
||||
int (*dump_req)( void *data, int len );
|
||||
|
@ -645,6 +673,10 @@ static const struct dumper dumpers[REQ_NB_REQUESTS] =
|
|||
(void(*)())dump_get_mapping_info_reply },
|
||||
{ (int(*)(void *,int))dump_create_device_request,
|
||||
(void(*)())dump_create_device_reply },
|
||||
{ (int(*)(void *,int))dump_create_snapshot_request,
|
||||
(void(*)())dump_create_snapshot_reply },
|
||||
{ (int(*)(void *,int))dump_next_process_request,
|
||||
(void(*)())dump_next_process_reply },
|
||||
};
|
||||
|
||||
static const char * const req_names[REQ_NB_REQUESTS] =
|
||||
|
@ -697,6 +729,8 @@ static const char * const req_names[REQ_NB_REQUESTS] =
|
|||
"create_mapping",
|
||||
"get_mapping_info",
|
||||
"create_device",
|
||||
"create_snapshot",
|
||||
"next_process",
|
||||
};
|
||||
|
||||
void trace_request( enum request req, void *data, int len, int fd )
|
||||
|
|
Loading…
Reference in New Issue