Made exception_event_request non-blocking, and added
get_exception_status to retrieve the exception result returned by the
debugger.

diff --git a/dlls/ntdll/exception.c b/dlls/ntdll/exception.c
index fea156d..611871c 100644
--- a/dlls/ntdll/exception.c
+++ b/dlls/ntdll/exception.c
@@ -107,22 +107,39 @@
  *
  * Send an EXCEPTION_DEBUG_EVENT event to the debugger.
  */
-static inline int send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *context )
+static int send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *context )
 {
     int ret;
+    HANDLE handle = 0;
+
     SERVER_START_REQ
     {
-        struct exception_event_request *req = server_alloc_req( sizeof(*req),
-                                                                sizeof(*rec)+sizeof(*context) );
+        struct queue_exception_event_request *req = server_alloc_req( sizeof(*req),
+                                                                      sizeof(*rec)+sizeof(*context) );
         CONTEXT *context_ptr = server_data_ptr(req);
         EXCEPTION_RECORD *rec_ptr = (EXCEPTION_RECORD *)(context_ptr + 1);
         req->first   = first_chance;
         *rec_ptr     = *rec;
         *context_ptr = *context;
-        if (!server_call_noerr( REQ_EXCEPTION_EVENT )) *context = *context_ptr;
+        if (!server_call_noerr( REQ_QUEUE_EXCEPTION_EVENT )) handle = req->handle;
+    }
+    SERVER_END_REQ;
+    if (!handle) return 0;  /* no debugger present or other error */
+
+    /* No need to wait on the handle since the process gets suspended
+     * once the event is passed to the debugger, so when we get back
+     * here the event has been continued already.
+     */
+    SERVER_START_REQ
+    {
+        struct get_exception_status_request *req = server_alloc_req( sizeof(*req), sizeof(*context) );
+        req->handle = handle;
+        if (!server_call_noerr( REQ_GET_EXCEPTION_STATUS ))
+            *context = *(CONTEXT *)server_data_ptr(req);
         ret = req->status;
     }
     SERVER_END_REQ;
+    NtClose( handle );
     return ret;
 }
 
diff --git a/include/server.h b/include/server.h
index a1fa6cd..77f394d 100644
--- a/include/server.h
+++ b/include/server.h
@@ -938,13 +938,22 @@
 };
 
 
-/* Send an exception event */
-struct exception_event_request
+/* Queue an exception event */
+struct queue_exception_event_request
 {
     REQUEST_HEADER;                /* request header */
     IN  int              first;    /* first chance exception? */
-    OUT int              status;   /* event continuation status */
+    OUT handle_t         handle;   /* handle to the queued event */
     IN  VARARG(record,exc_event);  /* thread context followed by exception record */
+};
+
+
+/* Retrieve the status of an exception event */
+struct get_exception_status_request
+{
+    REQUEST_HEADER;                /* request header */
+    OUT handle_t         handle;   /* handle to the queued event */
+    OUT int              status;   /* event continuation status */
     OUT VARARG(context,context);   /* modified thread context */
 };
 
@@ -1426,7 +1435,8 @@
     REQ_NEXT_THREAD,
     REQ_NEXT_MODULE,
     REQ_WAIT_DEBUG_EVENT,
-    REQ_EXCEPTION_EVENT,
+    REQ_QUEUE_EXCEPTION_EVENT,
+    REQ_GET_EXCEPTION_STATUS,
     REQ_OUTPUT_DEBUG_STRING,
     REQ_CONTINUE_DEBUG_EVENT,
     REQ_DEBUG_PROCESS,
@@ -1541,7 +1551,8 @@
     struct next_thread_request next_thread;
     struct next_module_request next_module;
     struct wait_debug_event_request wait_debug_event;
-    struct exception_event_request exception_event;
+    struct queue_exception_event_request queue_exception_event;
+    struct get_exception_status_request get_exception_status;
     struct output_debug_string_request output_debug_string;
     struct continue_debug_event_request continue_debug_event;
     struct debug_process_request debug_process;
@@ -1581,7 +1592,7 @@
     struct async_result_request async_result;
 };
 
-#define SERVER_PROTOCOL_VERSION 35
+#define SERVER_PROTOCOL_VERSION 36
 
 /* ### make_requests end ### */
 /* Everything above this line is generated automatically by tools/make_requests */
diff --git a/server/debugger.c b/server/debugger.c
index 5edee7f4..f68cdf2 100644
--- a/server/debugger.c
+++ b/server/debugger.c
@@ -28,6 +28,7 @@
     enum debug_event_state state;     /* event state */
     int                    status;    /* continuation status */
     debug_event_t          data;      /* event data */
+    CONTEXT                context;   /* register context */
 };
 
 /* debug context */
@@ -180,10 +181,8 @@
 
 static int fill_output_debug_string_event( struct debug_event *event, void *arg )
 {
-    struct output_debug_string_request *req = arg;
-    event->data.info.output_string.string  = req->string;
-    event->data.info.output_string.unicode = req->unicode;
-    event->data.info.output_string.length  = req->length;
+    struct debug_event_output_string *data = arg;
+    event->data.info.output_string = *data;
     return 1;
 }
 
@@ -217,8 +216,11 @@
 }
 
 /* link an event at the end of the queue */
-static void link_event( struct debug_ctx *debug_ctx, struct debug_event *event )
+static void link_event( struct debug_event *event )
 {
+    struct debug_ctx *debug_ctx = event->debugger->debug_ctx;
+
+    assert( debug_ctx );
     grab_object( event );
     event->next = NULL;
     event->prev = debug_ctx->event_tail;
@@ -241,16 +243,6 @@
     return event;
 }
 
-/* build a reply for the send_event request */
-static void build_exception_event_reply( struct thread *thread, struct object *obj, int signaled )
-{
-    struct exception_event_request *req = get_req_ptr( thread );
-    struct debug_event *event = (struct debug_event *)obj;
-    assert( obj->ops == &debug_event_ops );
-    req->status = event->status;
-    thread->context = NULL;
-}
-
 static void debug_event_dump( struct object *obj, int verbose )
 {
     struct debug_event *debug_event = (struct debug_event *)obj;
@@ -297,6 +289,7 @@
             break;
         }
     }
+    if (event->sender->context == &event->context) event->sender->context = NULL;
     release_object( event->sender );
     release_object( event->debugger );
 }
@@ -357,15 +350,14 @@
     return 0;
 }
 
-/* queue a debug event for a debugger */
-static struct debug_event *queue_debug_event( struct thread *thread, int code, void *arg )
+/* alloc a debug event for a debugger */
+static struct debug_event *alloc_debug_event( struct thread *thread, int code,
+                                              void *arg, CONTEXT *context )
 {
     struct thread *debugger = thread->process->debugger;
-    struct debug_ctx *debug_ctx = debugger->debug_ctx;
     struct debug_event *event;
 
     assert( code > 0 && code <= NB_DEBUG_EVENTS );
-    assert( debug_ctx );
     /* cannot queue a debug event for myself */
     assert( debugger->process != thread->process );
 
@@ -384,9 +376,11 @@
         release_object( event );
         return NULL;
     }
-
-    link_event( debug_ctx, event );
-    suspend_process( thread->process );
+    if (context)
+    {
+        memcpy( &event->context, context, sizeof(event->context) );
+        thread->context = &event->context;
+    }
     return event;
 }
 
@@ -395,8 +389,13 @@
 {
     if (thread->process->debugger)
     {
-        struct debug_event *event = queue_debug_event( thread, code, arg );
-        if (event) release_object( event );
+        struct debug_event *event = alloc_debug_event( thread, code, arg, NULL );
+        if (event)
+        {
+            link_event( event );
+            suspend_process( thread->process );
+            release_object( event );
+        }
     }
 }
 
@@ -535,7 +534,6 @@
 DECL_HANDLER(debug_process)
 {
     struct debug_event_exception data;
-    struct debug_event *event;
     struct process *process = get_process_from_id( req->pid );
     if (!process) return;
 
@@ -550,16 +548,15 @@
         data.record.ExceptionAddress = get_thread_ip( process->thread_list );
         data.record.NumberParameters = 0;
         data.first = 1;
-        if ((event = queue_debug_event( process->thread_list, EXCEPTION_DEBUG_EVENT, &data )))
-            release_object( event );
+        generate_debug_event( process->thread_list, EXCEPTION_DEBUG_EVENT, &data );
     }
     release_object( process );
 }
 
-/* send an exception event */
-DECL_HANDLER(exception_event)
+/* queue an exception event */
+DECL_HANDLER(queue_exception_event)
 {
-    req->status = 0;
+    req->handle = 0;
     if (current->process->debugger)
     {
         struct debug_event_exception data;
@@ -574,22 +571,51 @@
         }
         data.record = *rec;
         data.first  = req->first;
-        if ((event = queue_debug_event( current, EXCEPTION_DEBUG_EVENT, &data )))
+        if ((event = alloc_debug_event( current, EXCEPTION_DEBUG_EVENT, &data, context )))
         {
-            struct object *obj = &event->obj;
-            current->context = context;
-            sleep_on( 1, &obj, 0, 0, 0, build_exception_event_reply );
+            if ((req->handle = alloc_handle( current->process, event, SYNCHRONIZE, FALSE )))
+            {
+                link_event( event );
+                suspend_process( current->process );
+            }
             release_object( event );
         }
     }
 }
 
+/* retrieve the status of an exception event */
+DECL_HANDLER(get_exception_status)
+{
+    struct debug_event *event;
+    size_t size = 0;
+
+    req->status = 0;
+    if ((event = (struct debug_event *)get_handle_obj( current->process, req->handle,
+                                                       0, &debug_event_ops )))
+    {
+        if (event->state == EVENT_CONTINUED)
+        {
+            req->status = event->status;
+            if (current->context == &event->context)
+            {
+                size = min( sizeof(CONTEXT), get_req_data_size(req) );
+                memcpy( get_req_data(req), &event->context, size );
+                current->context = NULL;
+            }
+        }
+        else set_error( STATUS_PENDING );
+        release_object( event );
+    }
+    set_req_data_size( req, size );
+}
+
 /* send an output string to the debugger */
 DECL_HANDLER(output_debug_string)
 {
-    if (current->process->debugger)
-    {
-        struct debug_event *event = queue_debug_event( current, OUTPUT_DEBUG_STRING_EVENT, req );
-        if (event) release_object( event );
-    }
+    struct debug_event_output_string data;
+
+    data.string  = req->string;
+    data.unicode = req->unicode;
+    data.length  = req->length;
+    generate_debug_event( current, OUTPUT_DEBUG_STRING_EVENT, &data );
 }
diff --git a/server/request.h b/server/request.h
index 4c627a8..6eeadea 100644
--- a/server/request.h
+++ b/server/request.h
@@ -140,7 +140,8 @@
 DECL_HANDLER(next_thread);
 DECL_HANDLER(next_module);
 DECL_HANDLER(wait_debug_event);
-DECL_HANDLER(exception_event);
+DECL_HANDLER(queue_exception_event);
+DECL_HANDLER(get_exception_status);
 DECL_HANDLER(output_debug_string);
 DECL_HANDLER(continue_debug_event);
 DECL_HANDLER(debug_process);
@@ -254,7 +255,8 @@
     (req_handler)req_next_thread,
     (req_handler)req_next_module,
     (req_handler)req_wait_debug_event,
-    (req_handler)req_exception_event,
+    (req_handler)req_queue_exception_event,
+    (req_handler)req_get_exception_status,
     (req_handler)req_output_debug_string,
     (req_handler)req_continue_debug_event,
     (req_handler)req_debug_process,
diff --git a/server/trace.c b/server/trace.c
index 6779601..6690578 100644
--- a/server/trace.c
+++ b/server/trace.c
@@ -1066,15 +1066,25 @@
     cur_pos += dump_varargs_debug_event( req );
 }
 
-static void dump_exception_event_request( const struct exception_event_request *req )
+static void dump_queue_exception_event_request( const struct queue_exception_event_request *req )
 {
     fprintf( stderr, " first=%d,", req->first );
     fprintf( stderr, " record=" );
     cur_pos += dump_varargs_exc_event( req );
 }
 
-static void dump_exception_event_reply( const struct exception_event_request *req )
+static void dump_queue_exception_event_reply( const struct queue_exception_event_request *req )
 {
+    fprintf( stderr, " handle=%d", req->handle );
+}
+
+static void dump_get_exception_status_request( const struct get_exception_status_request *req )
+{
+}
+
+static void dump_get_exception_status_reply( const struct get_exception_status_request *req )
+{
+    fprintf( stderr, " handle=%d,", req->handle );
     fprintf( stderr, " status=%d,", req->status );
     fprintf( stderr, " context=" );
     cur_pos += dump_varargs_context( req );
@@ -1548,7 +1558,8 @@
     (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_queue_exception_event_request,
+    (dump_func)dump_get_exception_status_request,
     (dump_func)dump_output_debug_string_request,
     (dump_func)dump_continue_debug_event_request,
     (dump_func)dump_debug_process_request,
@@ -1659,7 +1670,8 @@
     (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)dump_queue_exception_event_reply,
+    (dump_func)dump_get_exception_status_reply,
     (dump_func)0,
     (dump_func)0,
     (dump_func)0,
@@ -1770,7 +1782,8 @@
     "next_thread",
     "next_module",
     "wait_debug_event",
-    "exception_event",
+    "queue_exception_event",
+    "get_exception_status",
     "output_debug_string",
     "continue_debug_event",
     "debug_process",
diff --git a/win32/except.c b/win32/except.c
index 88962c4..07e87e5 100644
--- a/win32/except.c
+++ b/win32/except.c
@@ -138,6 +138,48 @@
 }
 
 
+/**********************************************************************
+ *           send_debug_event
+ *
+ * Send an EXCEPTION_DEBUG_EVENT event to the debugger.
+ */
+static int send_debug_event( EXCEPTION_RECORD *rec, int first_chance, CONTEXT *context )
+{
+    int ret;
+    HANDLE handle = 0;
+
+    SERVER_START_REQ
+    {
+        struct queue_exception_event_request *req = server_alloc_req( sizeof(*req),
+                                                                      sizeof(*rec)+sizeof(*context) );
+        CONTEXT *context_ptr = server_data_ptr(req);
+        EXCEPTION_RECORD *rec_ptr = (EXCEPTION_RECORD *)(context_ptr + 1);
+        req->first   = first_chance;
+        *rec_ptr     = *rec;
+        *context_ptr = *context;
+        if (!server_call_noerr( REQ_QUEUE_EXCEPTION_EVENT )) handle = req->handle;
+    }
+    SERVER_END_REQ;
+    if (!handle) return 0;  /* no debugger present or other error */
+
+    /* No need to wait on the handle since the process gets suspended
+     * once the event is passed to the debugger, so when we get back
+     * here the event has been continued already.
+     */
+    SERVER_START_REQ
+    {
+        struct get_exception_status_request *req = server_alloc_req( sizeof(*req), sizeof(*context) );
+        req->handle = handle;
+        if (!server_call_noerr( REQ_GET_EXCEPTION_STATUS ))
+            *context = *(CONTEXT *)server_data_ptr(req);
+        ret = req->status;
+    }
+    SERVER_END_REQ;
+    NtClose( handle );
+    return ret;
+}
+
+
 /*******************************************************************
  *         UnhandledExceptionFilter   (KERNEL32.537)
  */
@@ -151,20 +193,7 @@
     int status;
 
     /* send a last chance event to the debugger */
-    SERVER_START_REQ
-    {
-        struct exception_event_request *req = server_alloc_req( sizeof(*req),
-                                                  sizeof(EXCEPTION_RECORD)+sizeof(CONTEXT) );
-        CONTEXT *context_ptr = server_data_ptr(req);
-        EXCEPTION_RECORD *rec_ptr = (EXCEPTION_RECORD *)(context_ptr + 1);
-        req->first   = 0;
-        *rec_ptr     = *epointers->ExceptionRecord;
-        *context_ptr = *epointers->ContextRecord;
-        if (!server_call_noerr( REQ_EXCEPTION_EVENT )) *epointers->ContextRecord = *context_ptr;
-        status = req->status;
-    }
-    SERVER_END_REQ;
-
+    status = send_debug_event( epointers->ExceptionRecord, FALSE, epointers->ContextRecord );
     switch (status)
     {
     case DBG_CONTINUE: