server: Add an async_data_t structure to store parameters for async I/O requests.
[wine] / server / async.c
1 /*
2  * Server-side async I/O support
3  *
4  * Copyright (C) 2007 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <assert.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25
26 #include "ntstatus.h"
27 #define WIN32_NO_STATUS
28 #include "windef.h"
29 #include "winternl.h"
30
31 #include "object.h"
32 #include "file.h"
33 #include "request.h"
34
35 struct async
36 {
37     struct object        obj;             /* object header */
38     struct thread       *thread;          /* owning thread */
39     struct list          queue_entry;     /* entry in file descriptor queue */
40     struct timeout_user *timeout;
41     async_data_t         data;            /* data for async I/O call */
42 };
43
44 static void async_dump( struct object *obj, int verbose );
45 static void async_destroy( struct object *obj );
46
47 static const struct object_ops async_ops =
48 {
49     sizeof(struct async),      /* size */
50     async_dump,                /* dump */
51     no_add_queue,              /* add_queue */
52     NULL,                      /* remove_queue */
53     NULL,                      /* signaled */
54     NULL,                      /* satisfied */
55     no_signal,                 /* signal */
56     no_get_fd,                 /* get_fd */
57     no_map_access,             /* map_access */
58     no_lookup_name,            /* lookup_name */
59     no_close_handle,           /* close_handle */
60     async_destroy              /* destroy */
61 };
62
63 static void async_dump( struct object *obj, int verbose )
64 {
65     struct async *async = (struct async *)obj;
66     assert( obj->ops == &async_ops );
67     fprintf( stderr, "Async thread=%p\n", async->thread );
68 }
69
70 static void async_destroy( struct object *obj )
71 {
72     struct async *async = (struct async *)obj;
73     assert( obj->ops == &async_ops );
74
75     if (async->timeout) remove_timeout_user( async->timeout );
76     release_object( async->thread );
77 }
78
79 /* notifies client thread of new status of its async request */
80 /* destroys the server side of it */
81 static void async_terminate( struct async *async, unsigned int status )
82 {
83     apc_call_t data;
84
85     memset( &data, 0, sizeof(data) );
86     data.type            = APC_ASYNC_IO;
87     data.async_io.func   = async->data.callback;
88     data.async_io.user   = async->data.arg;
89     data.async_io.sb     = async->data.iosb;
90     data.async_io.status = status;
91     thread_queue_apc( async->thread, &async->obj, &data );
92
93     if (async->timeout) remove_timeout_user( async->timeout );
94     async->timeout = NULL;
95     list_remove( &async->queue_entry );
96     release_object( async );
97 }
98
99 /* callback for timeout on an async request */
100 static void async_timeout( void *private )
101 {
102     struct async *async = private;
103
104     async->timeout = NULL;
105     async_terminate( async, STATUS_TIMEOUT );
106 }
107
108 /* create an async on a given queue of a fd */
109 struct async *create_async( struct thread *thread, const struct timeval *timeout,
110                             struct list *queue, const async_data_t *data )
111 {
112     struct async *async = alloc_object( &async_ops );
113
114     if (!async) return NULL;
115
116     async->thread = (struct thread *)grab_object( thread );
117     async->data = *data;
118
119     list_add_tail( queue, &async->queue_entry );
120
121     if (timeout) async->timeout = add_timeout_user( timeout, async_timeout, async );
122     else async->timeout = NULL;
123
124     return async;
125 }
126
127 /* terminate the async operation at the head of the queue */
128 void async_terminate_head( struct list *queue, unsigned int status )
129 {
130     struct list *ptr = list_head( queue );
131     if (ptr) async_terminate( LIST_ENTRY( ptr, struct async, queue_entry ), status );
132 }
133
134 /* terminate all async operations on the queue */
135 void async_terminate_queue( struct list *queue, unsigned int status )
136 {
137     struct list *ptr, *next;
138
139     LIST_FOR_EACH_SAFE( ptr, next, queue )
140     {
141         struct async *async = LIST_ENTRY( ptr, struct async, queue_entry );
142         async_terminate( async, status );
143     }
144 }