New XP debugging APIs: implemented DebugActiveProcessStop,
DebugSetProcessKillOnExit, DebugBreakProcess.

diff --git a/server/debugger.c b/server/debugger.c
index e487eb0..42d7362 100644
--- a/server/debugger.c
+++ b/server/debugger.c
@@ -38,6 +38,7 @@
     struct object        obj;         /* object header */
     struct debug_event  *event_head;  /* head of pending events queue */
     struct debug_event  *event_tail;  /* tail of pending events queue */
+    int                  kill_on_exit;/* kill debuggees on debugger exit ? */
 };
 
 
@@ -422,11 +423,13 @@
 
     /* we must have been able to attach all threads */
     for (thread = process->thread_list; thread; thread = thread->proc_next)
+    {
         if (!thread->attached)
         {
             resume_process( process );
             goto error;
         }
+    }
 
     if (set_process_debugger( process, debugger )) return 1;
     resume_process( process );
@@ -437,6 +440,65 @@
     return 0;
 }
 
+
+/* detach a process from a debugger thread (and resume it ?) */
+int debugger_detach( struct process *process, struct thread *debugger )
+{
+    struct thread *thread;
+    struct debug_event *event;
+    struct debug_ctx *debug_ctx;
+
+    if (!process->debugger || process->debugger != debugger)
+        goto error;  /* not currently debugged, or debugged by another debugger */
+    if (!debugger->debug_ctx ) goto error; /* should be a debugger */
+    /* init should be done, otherwise wouldn't be attached */
+    assert(!process->init_event);
+
+    suspend_process( process );
+    /* send continue indication for all events */
+    debug_ctx = debugger->debug_ctx;
+
+    /* find the event in the queue
+     * FIXME: could loop on process' threads and look the debug_event field */
+    for (event = debug_ctx->event_head; event; event = event->next)
+    {
+        if (event->state != EVENT_QUEUED) continue;
+
+        if (event->sender->process == process)
+        {
+            assert( event->sender->debug_event == event );
+            event->status = DBG_CONTINUE;
+            event->state  = EVENT_CONTINUED;
+            wake_up( &event->obj, 0 );
+            unlink_event( debug_ctx, event );
+            /* from queued debug event */
+            resume_process( process );
+        }
+    }
+
+    /* remove relationships between process and its debugger */
+    process->debugger = NULL;
+    release_object( debugger->debug_ctx );
+    debugger->debug_ctx = NULL;
+
+    /* now detach all the threads */
+    for (thread = process->thread_list; thread; thread = thread->proc_next)
+    {
+        if (thread->attached)
+        {
+            detach_thread( thread, 0 );
+        }
+    }
+
+    /* from this function */
+    resume_process( process );
+    return 0;
+
+ error:
+    set_error( STATUS_ACCESS_DENIED );
+    return 0;
+}
+
 /* generate all startup events of a given process */
 void generate_startup_debug_events( struct process *process, void *entry )
 {
@@ -470,6 +532,7 @@
         if (!(debug_ctx = alloc_object( &debug_ctx_ops, -1 ))) return 0;
         debug_ctx->event_head = NULL;
         debug_ctx->event_tail = NULL;
+        debug_ctx->kill_on_exit = 1;
         debugger->debug_ctx = debug_ctx;
     }
     process->debugger = debugger;
@@ -481,8 +544,15 @@
 {
     if (thread->debug_ctx)  /* this thread is a debugger */
     {
-        /* kill all debugged processes */
-        kill_debugged_processes( thread, thread->exit_code );
+        if (thread->debug_ctx->kill_on_exit)
+        {
+            /* kill all debugged processes */
+            kill_debugged_processes( thread, thread->exit_code );
+        }
+        else
+        {
+            detach_debugged_processes( thread );
+        }
         release_object( thread->debug_ctx );
         thread->debug_ctx = NULL;
     }
@@ -538,12 +608,17 @@
 /* Start debugging an existing process */
 DECL_HANDLER(debug_process)
 {
-    struct debug_event_exception data;
     struct process *process = get_process_from_id( req->pid );
     if (!process) return;
 
-    if (debugger_attach( process, current ))
+    if (!req->attach)
     {
+        debugger_detach( process, current );
+    }
+    else if (debugger_attach( process, current ))
+    {
+        struct debug_event_exception data;
+
         generate_startup_debug_events( process, NULL );
         resume_process( process );
 
@@ -622,3 +697,14 @@
     data.length  = req->length;
     generate_debug_event( current, OUTPUT_DEBUG_STRING_EVENT, &data );
 }
+
+/* set debugger kill on exit flag */
+DECL_HANDLER(set_debugger_kill_on_exit)
+{
+    if (!current->debug_ctx)
+    {
+        set_error( STATUS_ACCESS_DENIED );
+        return;
+    }
+    current->debug_ctx->kill_on_exit = req->kill_on_exit;
+}