server: Make async I/O queues into real objects.
diff --git a/server/async.c b/server/async.c
index 440cb2e..8307e20 100644
--- a/server/async.c
+++ b/server/async.c
@@ -62,6 +62,35 @@
async_destroy /* destroy */
};
+
+struct async_queue
+{
+ struct object obj; /* object header */
+ struct fd *fd; /* file descriptor owning this queue */
+ struct list queue; /* queue of async objects */
+};
+
+static void async_queue_dump( struct object *obj, int verbose );
+static void async_queue_destroy( struct object *obj );
+
+static const struct object_ops async_queue_ops =
+{
+ sizeof(struct async_queue), /* size */
+ async_queue_dump, /* dump */
+ no_add_queue, /* add_queue */
+ NULL, /* remove_queue */
+ NULL, /* signaled */
+ NULL, /* satisfied */
+ no_signal, /* signal */
+ no_get_fd, /* get_fd */
+ no_map_access, /* map_access */
+ no_lookup_name, /* lookup_name */
+ no_open_file, /* open_file */
+ no_close_handle, /* close_handle */
+ async_queue_destroy /* destroy */
+};
+
+
static void async_dump( struct object *obj, int verbose )
{
struct async *async = (struct async *)obj;
@@ -79,6 +108,21 @@
release_object( async->thread );
}
+static void async_queue_dump( struct object *obj, int verbose )
+{
+ struct async_queue *async_queue = (struct async_queue *)obj;
+ assert( obj->ops == &async_queue_ops );
+ fprintf( stderr, "Async queue fd=%p\n", async_queue->fd );
+}
+
+static void async_queue_destroy( struct object *obj )
+{
+ struct async_queue *async_queue = (struct async_queue *)obj;
+ assert( obj->ops == &async_queue_ops );
+
+ async_wake_up( async_queue, STATUS_HANDLES_CLOSED );
+}
+
/* notifies client thread of new status of its async request */
/* destroys the server side of it */
static void async_terminate( struct async *async, unsigned int status )
@@ -108,9 +152,22 @@
async_terminate( async, STATUS_TIMEOUT );
}
+/* create a new async queue for a given fd */
+struct async_queue *create_async_queue( struct fd *fd )
+{
+ struct async_queue *queue = alloc_object( &async_queue_ops );
+
+ if (queue)
+ {
+ queue->fd = fd;
+ list_init( &queue->queue );
+ }
+ return queue;
+}
+
/* create an async on a given queue of a fd */
struct async *create_async( struct thread *thread, const struct timeval *timeout,
- struct list *queue, const async_data_t *data )
+ struct async_queue *queue, const async_data_t *data )
{
struct event *event = NULL;
struct async *async;
@@ -128,7 +185,7 @@
async->event = event;
async->data = *data;
- list_add_tail( queue, &async->queue_entry );
+ list_add_tail( &queue->queue, &async->queue_entry );
if (timeout) async->timeout = add_timeout_user( timeout, async_timeout, async );
else async->timeout = NULL;
@@ -164,21 +221,23 @@
}
}
-/* terminate the async operation at the head of the queue */
-void async_terminate_head( struct list *queue, unsigned int status )
+/* check if an async operation is waiting to be alerted */
+int async_waiting( struct async_queue *queue )
{
- struct list *ptr = list_head( queue );
- if (ptr) async_terminate( LIST_ENTRY( ptr, struct async, queue_entry ), status );
+ return queue && !list_empty( &queue->queue );
}
-/* terminate all async operations on the queue */
-void async_terminate_queue( struct list *queue, unsigned int status )
+/* wake up async operations on the queue */
+void async_wake_up( struct async_queue *queue, unsigned int status )
{
struct list *ptr, *next;
- LIST_FOR_EACH_SAFE( ptr, next, queue )
+ if (!queue) return;
+
+ LIST_FOR_EACH_SAFE( ptr, next, &queue->queue )
{
struct async *async = LIST_ENTRY( ptr, struct async, queue_entry );
async_terminate( async, status );
+ if (status == STATUS_ALERTED) break; /* only wake up the first one */
}
}