From 06db705238c8741e2de35016ea08af3ab454bd8f Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Tue, 20 Mar 2007 19:23:59 +0100 Subject: [PATCH] server: Make struct async into a real object, to keep it around while the APC is running. --- server/Makefile.in | 1 + server/async.c | 148 +++++++++++++++++++++++++++++++++++++++++++++ server/fd.c | 72 ---------------------- server/file.h | 8 +-- 4 files changed, 151 insertions(+), 78 deletions(-) create mode 100644 server/async.c diff --git a/server/Makefile.in b/server/Makefile.in index bfd5c31992..5e31826b93 100644 --- a/server/Makefile.in +++ b/server/Makefile.in @@ -7,6 +7,7 @@ MODULE = none EXTRALIBS = @LIBPOLL@ C_SRCS = \ + async.c \ atom.c \ change.c \ class.c \ diff --git a/server/async.c b/server/async.c new file mode 100644 index 0000000000..cb4675c974 --- /dev/null +++ b/server/async.c @@ -0,0 +1,148 @@ +/* + * Server-side async I/O support + * + * Copyright (C) 2007 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winternl.h" + +#include "object.h" +#include "file.h" +#include "request.h" + +struct async +{ + struct object obj; /* object header */ + struct thread *thread; /* owning thread */ + struct list queue_entry; /* entry in file descriptor queue */ + struct timeout_user *timeout; + void *apc; /* apc function to call when alerted */ + void *user; /* user-private argument for apc */ + void *sb; /* pointer to I/O status block in client addr space */ +}; + +static void async_dump( struct object *obj, int verbose ); +static void async_destroy( struct object *obj ); + +static const struct object_ops async_ops = +{ + sizeof(struct async), /* size */ + async_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_close_handle, /* close_handle */ + async_destroy /* destroy */ +}; + +static void async_dump( struct object *obj, int verbose ) +{ + struct async *async = (struct async *)obj; + assert( obj->ops == &async_ops ); + fprintf( stderr, "Async thread=%p\n", async->thread ); +} + +static void async_destroy( struct object *obj ) +{ + struct async *async = (struct async *)obj; + assert( obj->ops == &async_ops ); + + if (async->timeout) remove_timeout_user( async->timeout ); + release_object( async->thread ); +} + +/* 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 ) +{ + apc_call_t data; + + memset( &data, 0, sizeof(data) ); + data.type = APC_ASYNC_IO; + data.async_io.func = async->apc; + data.async_io.user = async->user; + data.async_io.sb = async->sb; + data.async_io.status = status; + thread_queue_apc( async->thread, &async->obj, &data ); + + if (async->timeout) remove_timeout_user( async->timeout ); + async->timeout = NULL; + list_remove( &async->queue_entry ); + release_object( async ); +} + +/* callback for timeout on an async request */ +static void async_timeout( void *private ) +{ + struct async *async = private; + + async->timeout = NULL; + async_terminate( async, STATUS_TIMEOUT ); +} + +/* create an async on a given queue of a fd */ +struct async *create_async( struct thread *thread, const struct timeval *timeout, + struct list *queue, void *io_apc, void *io_user, void *io_sb ) +{ + struct async *async = alloc_object( &async_ops ); + + if (!async) return NULL; + + async->thread = (struct thread *)grab_object( thread ); + async->apc = io_apc; + async->user = io_user; + async->sb = io_sb; + + list_add_tail( queue, &async->queue_entry ); + + if (timeout) async->timeout = add_timeout_user( timeout, async_timeout, async ); + else async->timeout = NULL; + + return async; +} + +/* terminate the async operation at the head of the queue */ +void async_terminate_head( struct list *queue, unsigned int status ) +{ + struct list *ptr = list_head( queue ); + if (ptr) async_terminate( LIST_ENTRY( ptr, struct async, queue_entry ), status ); +} + +/* terminate all async operations on the queue */ +void async_terminate_queue( struct list *queue, unsigned int status ) +{ + struct list *ptr, *next; + + LIST_FOR_EACH_SAFE( ptr, next, queue ) + { + struct async *async = LIST_ENTRY( ptr, struct async, queue_entry ); + async_terminate( async, status ); + } +} diff --git a/server/fd.c b/server/fd.c index f2f8e9b2f9..5e03c7bae2 100644 --- a/server/fd.c +++ b/server/fd.c @@ -1266,78 +1266,6 @@ void unlock_fd( struct fd *fd, file_pos_t start, file_pos_t count ) } -/****************************************************************/ -/* asynchronous operations support */ - -struct async -{ - struct thread *thread; - void *apc; - void *user; - void *sb; - struct timeout_user *timeout; - struct list entry; -}; - -/* notifies client thread of new status of its async request */ -/* destroys the server side of it */ -static void async_terminate( struct async *async, int status ) -{ - apc_call_t data; - - memset( &data, 0, sizeof(data) ); - data.type = APC_ASYNC_IO; - data.async_io.func = async->apc; - data.async_io.user = async->user; - data.async_io.sb = async->sb; - data.async_io.status = status; - thread_queue_apc( async->thread, NULL, &data ); - - if (async->timeout) remove_timeout_user( async->timeout ); - async->timeout = NULL; - list_remove( &async->entry ); - release_object( async->thread ); - free( async ); -} - -/* cb for timeout on an async request */ -static void async_callback(void *private) -{ - struct async *async = (struct async *)private; - - /* fprintf(stderr, "async timeout out %p\n", async); */ - async->timeout = NULL; - async_terminate( async, STATUS_TIMEOUT ); -} - -/* create an async on a given queue of a fd */ -struct async *create_async( struct thread *thread, const struct timeval *timeout, - struct list *queue, void *io_apc, void *io_user, void* io_sb ) -{ - struct async *async = mem_alloc( sizeof(struct async) ); - - if (!async) return NULL; - - async->thread = (struct thread *)grab_object(thread); - async->apc = io_apc; - async->user = io_user; - async->sb = io_sb; - - list_add_tail( queue, &async->entry ); - - if (timeout) async->timeout = add_timeout_user( timeout, async_callback, async ); - else async->timeout = NULL; - - return async; -} - -/* terminate the async operation at the head of the queue */ -void async_terminate_head( struct list *queue, int status ) -{ - struct list *ptr = list_head( queue ); - if (ptr) async_terminate( LIST_ENTRY( ptr, struct async, entry ), status ); -} - /****************************************************************/ /* file descriptor functions */ diff --git a/server/file.h b/server/file.h index 85af894471..6402d61ed8 100644 --- a/server/file.h +++ b/server/file.h @@ -124,12 +124,8 @@ extern struct object *create_serial( struct fd *fd, unsigned int options ); /* async I/O functions */ extern struct async *create_async( struct thread *thread, const struct timeval *timeout, struct list *queue, void *, void *, void *); -extern void async_terminate_head( struct list *queue, int status ); - -static inline void async_terminate_queue( struct list *queue, int status ) -{ - while (!list_empty( queue )) async_terminate_head( queue, status ); -} +extern void async_terminate_head( struct list *queue, unsigned int status ); +extern void async_terminate_queue( struct list *queue, unsigned int status ); /* access rights that require Unix read permission */ #define FILE_UNIX_READ_ACCESS (FILE_READ_DATA|FILE_READ_ATTRIBUTES|FILE_READ_EA)