Added LGPL standard comment, and copyright notices where necessary.
[wine] / server / async.c
1 /*
2  * Server-side support for async i/o operations
3  *
4  * Copyright (C) 1998 Alexandre Julliard
5  * Copyright (C) 2000 Mike McCormack
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
20  */
21
22 #include "config.h"
23
24 #include <assert.h>
25 #include <string.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28 #include <stdio.h>
29
30 #include "handle.h"
31 #include "thread.h"
32 #include "request.h"
33
34 #include "async.h"
35
36 void destroy_async( struct async *async )
37 {
38     struct async_queue *aq = async->q;
39
40     /*fprintf(stderr,"destroyed async %p\n",async->overlapped); */
41
42     if(async->timeout)
43         remove_timeout_user(async->timeout);
44     async->timeout = NULL;
45
46     if(async->prev)
47         async->prev->next = async->next;
48     else
49         aq->head = async->next;
50
51     if(async->next)
52         async->next->prev = async->prev;
53     else
54         aq->tail = async->prev;
55
56     async->q = NULL;
57     async->next = NULL;
58     async->prev = NULL;
59
60     free(async);
61 }
62
63 void async_notify(struct async *async, int status)
64 {
65     /* fprintf(stderr,"notifying %p!\n",async->overlapped); */
66     async->status = status;
67     thread_queue_apc(async->thread, NULL, async->func, APC_ASYNC, 1, 2, async->overlapped, status);
68 }
69
70 void destroy_async_queue( struct async_queue *q )
71 {
72     while(q->head)
73     {
74         async_notify(q->head, STATUS_HANDLES_CLOSED);
75         destroy_async(q->head);
76     }
77 }
78
79 struct async *find_async(struct async_queue *q, struct thread *thread, void *overlapped)
80 {
81     struct async *async;
82
83     /* fprintf(stderr,"find_async: %p\n",overlapped); */
84
85     if(!q)
86         return NULL;
87
88     for(async = q->head; async; async = async->next)
89         if((async->overlapped==overlapped) && (async->thread == thread))
90              return async;
91
92     return NULL;
93 }
94
95 void async_insert(struct async_queue *q, struct async *async)
96 {
97     async->q = q;
98     async->prev = q->tail;
99     async->next = NULL;
100
101     if(q->tail)
102         q->tail->next = async;
103     else
104         q->head = async;
105
106     q->tail = async;
107 }
108
109 static void async_callback(void *private)
110 {
111     struct async *async = (struct async *)private;
112
113     /* fprintf(stderr,"%p timeout out\n",async->overlapped); */
114     async->timeout = NULL;
115     async_notify(async, STATUS_TIMEOUT);
116     destroy_async(async);
117 }
118
119 struct async *create_async(struct object *obj, struct thread *thread, void *func, 
120                            void *overlapped)
121 {
122     struct async *async = (struct async *) malloc(sizeof(struct async));
123     if(!async)
124     {
125         set_error(STATUS_NO_MEMORY);
126         return NULL;
127     }
128
129     async->obj = obj;
130     async->thread = thread;
131     async->func = func;
132     async->overlapped = overlapped;
133     async->next = NULL;
134     async->prev = NULL;
135     async->q = NULL;
136     async->status = STATUS_PENDING;
137     async->timeout = NULL;
138
139     return async;
140 }
141
142 void async_add_timeout(struct async *async, int timeout)
143 {
144     if(timeout)
145     {
146         gettimeofday( &async->when, 0 );
147         add_timeout( &async->when, timeout );
148         async->timeout = add_timeout_user( &async->when, async_callback, async );
149     }
150 }
151
152 DECL_HANDLER(register_async)
153 {
154     struct object *obj;
155
156     if (!(obj = get_handle_obj( current->process, req->handle, 0, NULL)) )
157         return;
158
159     if(obj->ops->queue_async)
160     {
161         struct async_queue *q = obj->ops->queue_async(obj, NULL, req->type, 0);
162         struct async *async;
163
164         async = find_async(q, current, req->overlapped);
165         if(req->status==STATUS_PENDING)
166         {
167             if(!async)
168                 async = create_async(obj, current, req->func, req->overlapped);
169
170             if(async)
171             {
172                 async->status = req->status;
173                 if(!obj->ops->queue_async(obj, async, req->type, req->count))
174                     destroy_async(async);
175             }
176         }
177         else
178         {
179             if(async)
180                 destroy_async(async);
181             else
182                 set_error(STATUS_INVALID_PARAMETER);
183         }
184
185         set_select_events(obj,obj->ops->get_poll_events(obj));
186     }
187     else
188         set_error(STATUS_INVALID_HANDLE);
189
190     release_object(obj);
191 }
192