Partially implement GetThreadTimes.
[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, NULL, APC_ASYNC_IO, 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_CANCELLED);
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,
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->overlapped = overlapped;
132     async->next = NULL;
133     async->prev = NULL;
134     async->q = NULL;
135     async->status = STATUS_PENDING;
136     async->timeout = NULL;
137
138     return async;
139 }
140
141 void async_add_timeout(struct async *async, int timeout)
142 {
143     if(timeout)
144     {
145         gettimeofday( &async->when, 0 );
146         add_timeout( &async->when, timeout );
147         async->timeout = add_timeout_user( &async->when, async_callback, async );
148     }
149 }
150
151 DECL_HANDLER(register_async)
152 {
153     struct object *obj = get_handle_obj( current->process, req->handle, 0, NULL);
154
155     if ( !(obj) || !obj->ops->queue_async )
156     {
157         set_error(STATUS_INVALID_HANDLE);
158         return;
159     }
160
161 /*
162  * The queue_async method must do the following:
163  *
164  * 1. Get the async_queue for the request of given type.
165  * 2. Call find_async() to look for the specific client request in the queue (=> NULL if not found).
166  * 3. If status is STATUS_PENDING:
167  *      a) If no async request found in step 2 (new request): call create_async() to initialize one.
168  *      b) Set request's status to STATUS_PENDING.
169  *      c) If the "queue" field of the async request is NULL: call async_insert() to put it into the queue.
170  *    Otherwise:
171  *      If the async request was found in step 2, destroy it by calling destroy_async().
172  * 4. Carry out any operations necessary to adjust the object's poll events
173  *    Usually: set_elect_events (obj, obj->ops->get_poll_events()).
174  *
175  * See also the implementations in file.c, serial.c, and sock.c.
176 */
177
178     obj->ops->queue_async (obj, req->overlapped, req->status, req->type, req->count);
179     release_object(obj);
180 }
181