Add more flexibility to the queue_async server call by moving most
functionality into the object's queue_async method.

diff --git a/server/async.c b/server/async.c
index 9e44a0b..1b34483 100644
--- a/server/async.c
+++ b/server/async.c
@@ -150,42 +150,32 @@
 
 DECL_HANDLER(register_async)
 {
-    struct object *obj;
+    struct object *obj = get_handle_obj( current->process, req->handle, 0, NULL);
 
-    if (!(obj = get_handle_obj( current->process, req->handle, 0, NULL)) )
-        return;
-
-    if(obj->ops->queue_async)
+    if ( !(obj) || !obj->ops->queue_async )
     {
-        struct async_queue *q = obj->ops->queue_async(obj, NULL, req->type, 0);
-        struct async *async;
-
-        async = find_async(q, current, req->overlapped);
-        if(req->status==STATUS_PENDING)
-        {
-            if(!async)
-                async = create_async(obj, current, req->overlapped);
-
-            if(async)
-            {
-                async->status = req->status;
-                if(!obj->ops->queue_async(obj, async, req->type, req->count))
-                    destroy_async(async);
-            }
-        }
-        else
-        {
-            if(async)
-                destroy_async(async);
-            else
-                set_error(STATUS_INVALID_PARAMETER);
-        }
-
-        set_select_events(obj,obj->ops->get_poll_events(obj));
-    }
-    else
         set_error(STATUS_INVALID_HANDLE);
+        return;
+    }
 
+/*
+ * The queue_async method must do the following:
+ *
+ * 1. Get the async_queue for the request of given type.
+ * 2. Call find_async() to look for the specific client request in the queue (=> NULL if not found).
+ * 3. If status is STATUS_PENDING:
+ *      a) If no async request found in step 2 (new request): call create_async() to initialize one.
+ *      b) Set request's status to STATUS_PENDING.
+ *      c) If the "queue" field of the async request is NULL: call async_insert() to put it into the queue.
+ *    Otherwise:
+ *      If the async request was found in step 2, destroy it by calling destroy_async().
+ * 4. Carry out any operations necessary to adjust the object's poll events
+ *    Usually: set_elect_events (obj, obj->ops->get_poll_events()).
+ *
+ * See also the implementations in file.c, serial.c, and sock.c.
+*/
+
+    obj->ops->queue_async (obj, req->overlapped, req->status, req->type, req->count);
     release_object(obj);
 }
 
diff --git a/server/file.c b/server/file.c
index 9b1df3e..6908292 100644
--- a/server/file.c
+++ b/server/file.c
@@ -69,7 +69,7 @@
 static int file_flush( struct object *obj );
 static int file_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags );
 static void file_destroy( struct object *obj );
-static struct async_queue * file_queue_async(struct object *obj, struct async* async, int type, int count);
+static void file_queue_async(struct object *obj, void *ptr, unsigned int status, int type, int count);
 
 static const struct object_ops file_ops =
 {
@@ -358,9 +358,10 @@
     return FD_TYPE_DEFAULT;
 }
 
-static struct async_queue *file_queue_async(struct object *obj, struct async *async, int type, int count)
+static void file_queue_async(struct object *obj, void *ptr, unsigned int status, int type, int count)
 {
     struct file *file = (struct file *)obj;
+    struct async *async;
     struct async_queue *q;
 
     assert( obj->ops == &file_ops );
@@ -368,7 +369,7 @@
     if ( !(file->flags & FILE_FLAG_OVERLAPPED) )
     {
         set_error ( STATUS_INVALID_HANDLE );
-        return NULL;
+        return;
     }
 
     switch(type)
@@ -381,13 +382,26 @@
         break;
     default:
         set_error( STATUS_INVALID_PARAMETER );
-        return NULL;
+        return;
     }
 
-    if(async && !async->q)
-        async_insert(q, async);
+    async = find_async ( q, current, ptr );
 
-    return q;
+    if ( status == STATUS_PENDING )
+    {
+        if ( !async )
+            async = create_async ( obj, current, ptr );
+        if ( !async )
+            return;
+
+        async->status = STATUS_PENDING;
+        if ( !async->q )
+            async_insert( q, async );
+    }
+    else if ( async ) destroy_async ( async );
+    else set_error ( STATUS_INVALID_PARAMETER );
+
+    set_select_events ( obj, file_get_poll_events ( obj ));
 }
 
 static void file_destroy( struct object *obj )
diff --git a/server/object.h b/server/object.h
index 6ccbeaf..a904945 100644
--- a/server/object.h
+++ b/server/object.h
@@ -63,8 +63,8 @@
     int  (*flush)(struct object *);
     /* get file information */
     int  (*get_file_info)(struct object *,struct get_file_info_reply *, int *flags);
-    /* queue an async operation */
-    struct async_queue* (*queue_async)(struct object *, struct async *async, int type, int count);
+    /* queue an async operation - see register_async handler in async.c*/
+    void (*queue_async)(struct object *, void* ptr, unsigned int status, int type, int count);
     /* destroy on refcount == 0 */
     void (*destroy)(struct object *);
 };
diff --git a/server/serial.c b/server/serial.c
index 8fdce64..173c8c3 100644
--- a/server/serial.c
+++ b/server/serial.c
@@ -51,7 +51,7 @@
 static int serial_get_fd( struct object *obj );
 static int serial_get_info( struct object *obj, struct get_file_info_reply *reply, int *flags );
 static int serial_get_poll_events( struct object *obj );
-static struct async_queue * serial_queue_async(struct object *obj, struct async* async, int type, int count);
+static void serial_queue_async(struct object *obj, void *ptr, unsigned int status, int type, int count);
 static void destroy_serial(struct object *obj);
 static void serial_poll_event( struct object *obj, int event );
 
@@ -250,24 +250,11 @@
     set_select_events(obj,obj->ops->get_poll_events(obj));
 }
 
-/* 
- * This function is an abuse of overloading that deserves some explanation.
- *
- * It has three purposes:
- *
- * 1. get the queue for a type of async operation
- * 2. requeue an async operation
- * 3. queue a new async operation
- *
- * It is overloaded so that these three functions only take one function pointer
- *  in the object operations list.
- *
- * In all cases, it returns the async queue.
- */
-static struct async_queue *serial_queue_async(struct object *obj, struct async *async, int type, int count)
+static void serial_queue_async(struct object *obj, void *ptr, unsigned int status, int type, int count)
 {
     struct serial *serial = (struct serial *)obj;
     struct async_queue *q;
+    struct async *async;
     int timeout;
 
     assert(obj->ops == &serial_ops);
@@ -288,19 +275,29 @@
         break;
     default:
         set_error(STATUS_INVALID_PARAMETER);
-        return NULL;
+        return;
     }
 
-    if(async)
+    async = find_async ( q, current, ptr );
+
+    if ( status == STATUS_PENDING )
     {
+        if ( !async )
+            async = create_async ( obj, current, ptr );
+        if ( !async )
+            return;
+
+        async->status = STATUS_PENDING;
         if(!async->q)
         {
             async_add_timeout(async,timeout);
             async_insert(q, async);
+        }
     }
-}
+    else if ( async ) destroy_async ( async );
+    else set_error ( STATUS_INVALID_PARAMETER );
 
-    return q;
+    set_select_events ( obj, serial_get_poll_events ( obj ));
 }
 
 /* create a serial */