|  | /* | 
|  | * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA | 
|  | * | 
|  | * FIXME: heap snapshots not implemented | 
|  | */ | 
|  |  | 
|  | #include "config.h" | 
|  | #include "wine/port.h" | 
|  |  | 
|  | #include <assert.h> | 
|  | #include <stdio.h> | 
|  | #include <stdlib.h> | 
|  |  | 
|  | #include "windef.h" | 
|  |  | 
|  | #include "handle.h" | 
|  | #include "process.h" | 
|  | #include "thread.h" | 
|  | #include "request.h" | 
|  |  | 
|  |  | 
|  | struct snapshot | 
|  | { | 
|  | struct object             obj;           /* object header */ | 
|  | 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 ); | 
|  | static void snapshot_destroy( struct object *obj ); | 
|  |  | 
|  | static const struct object_ops snapshot_ops = | 
|  | { | 
|  | sizeof(struct snapshot),      /* size */ | 
|  | snapshot_dump,                /* dump */ | 
|  | no_add_queue,                 /* add_queue */ | 
|  | NULL,                         /* remove_queue */ | 
|  | NULL,                         /* signaled */ | 
|  | NULL,                         /* satisfied */ | 
|  | no_signal,                    /* signal */ | 
|  | no_get_fd,                    /* get_fd */ | 
|  | no_close_handle,              /* close_handle */ | 
|  | snapshot_destroy              /* destroy */ | 
|  | }; | 
|  |  | 
|  |  | 
|  | /* create a new snapshot */ | 
|  | static struct snapshot *create_snapshot( process_id_t pid, int flags ) | 
|  | { | 
|  | struct process *process = NULL; | 
|  | struct snapshot *snapshot; | 
|  |  | 
|  | /* need a process for modules and heaps */ | 
|  | if (flags & (SNAP_MODULE|SNAP_HEAPLIST)) | 
|  | { | 
|  | 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 ))) | 
|  | { | 
|  | if (process) release_object( process ); | 
|  | return NULL; | 
|  | } | 
|  |  | 
|  | snapshot->process = process; | 
|  |  | 
|  | 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 ); | 
|  |  | 
|  | snapshot->module_pos = 0; | 
|  | snapshot->module_count = 0; | 
|  | if (flags & SNAP_MODULE) | 
|  | snapshot->modules = module_snap( process, &snapshot->module_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; | 
|  |  | 
|  | 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 ? get_process_id( ptr->process->parent ) : 0; | 
|  | reply->heap     = NULL;  /* FIXME */ | 
|  | reply->module   = NULL;  /* FIXME */ | 
|  | reply->threads  = ptr->threads; | 
|  | reply->priority = ptr->priority; | 
|  | reply->handles  = ptr->handles; | 
|  | if (ptr->process->exe.filename) | 
|  | { | 
|  | size_t len = min( ptr->process->exe.namelen, get_reply_max_size() ); | 
|  | set_reply_data( ptr->process->exe.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 */ | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | /* get the next module in the snapshot */ | 
|  | static int snapshot_next_module( struct snapshot *snapshot, struct next_module_reply *reply ) | 
|  | { | 
|  | struct module_snapshot *ptr; | 
|  |  | 
|  | if (!snapshot->module_count) | 
|  | { | 
|  | set_error( STATUS_INVALID_PARAMETER );  /* FIXME */ | 
|  | return 0; | 
|  | } | 
|  | if (snapshot->module_pos >= snapshot->module_count) | 
|  | { | 
|  | set_error( STATUS_NO_MORE_FILES ); | 
|  | return 0; | 
|  | } | 
|  | ptr = &snapshot->modules[snapshot->module_pos++]; | 
|  | reply->pid  = get_process_id( snapshot->process ); | 
|  | reply->base = ptr->base; | 
|  | reply->size = ptr->size; | 
|  | if (ptr->filename) | 
|  | { | 
|  | size_t len = min( ptr->namelen, get_reply_max_size() ); | 
|  | set_reply_data( ptr->filename, len ); | 
|  | } | 
|  | 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 %d modules\n", | 
|  | snapshot->process_count, snapshot->thread_count, snapshot->module_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 ); | 
|  | } | 
|  | if (snapshot->module_count) | 
|  | { | 
|  | for (i = 0; i < snapshot->module_count; i++) | 
|  | free( snapshot->modules[i].filename ); | 
|  | free( snapshot->modules ); | 
|  | } | 
|  | if (snapshot->process) release_object( snapshot->process ); | 
|  | } | 
|  |  | 
|  | /* create a snapshot */ | 
|  | DECL_HANDLER(create_snapshot) | 
|  | { | 
|  | struct snapshot *snapshot; | 
|  |  | 
|  | reply->handle = 0; | 
|  | if ((snapshot = create_snapshot( req->pid, req->flags ))) | 
|  | { | 
|  | reply->handle = alloc_handle( current->process, snapshot, 0, req->inherit ); | 
|  | 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 ); | 
|  | } | 
|  | } | 
|  |  | 
|  | /* 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 ))) | 
|  | { | 
|  | if (req->reset) snapshot->module_pos = 0; | 
|  | snapshot_next_module( snapshot, reply ); | 
|  | release_object( snapshot ); | 
|  | } | 
|  | } |