- CoSetState info should be thread local.
[wine] / include / async.h
1 /*
2  * Structures and static functions for handling asynchronous I/O.
3  *
4  * Copyright (C) 2002 Mike McCormack,  Martin Wilck
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 /*
22  * This file declares static functions.
23  * It should only be included by those source files that implement async I/O requests.
24  */
25
26 #ifndef __WINE_ASYNC_H
27 #define __WINE_ASYNC_H
28
29 #include <thread.h>
30 #include <ntstatus.h>
31 #include <wine/server.h>
32 #include <winternl.h>
33
34 struct async_private;
35
36 typedef void (*async_handler)(struct async_private *ovp);
37 typedef void (CALLBACK *async_call_completion_func)(ULONG_PTR data);
38 typedef DWORD (*async_get_count)(const struct async_private *ovp);
39 typedef void (*async_cleanup)(struct async_private *ovp);
40
41 typedef struct async_ops
42 {
43     async_get_count             get_count;
44     async_call_completion_func  call_completion;
45     async_cleanup               cleanup;
46 } async_ops;
47
48 typedef struct async_private
49 {
50     struct async_ops*   ops;
51     HANDLE              handle;
52     HANDLE              event;
53     int                 fd;
54     async_handler       func;
55     int                 type;
56     IO_STATUS_BLOCK*    iosb;
57     struct async_private* next;
58     struct async_private* prev;
59 } async_private;
60
61 /* All functions declared static for Dll separation purposes */
62 static void CALLBACK call_user_apc( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3 )
63 {
64     PAPCFUNC func = (PAPCFUNC)arg1;
65     func( arg2 );
66 }
67
68 inline static void finish_async( async_private *ovp )
69 {
70     if (ovp->prev)
71         ovp->prev->next = ovp->next;
72     else
73         NtCurrentTeb()->pending_list = ovp->next;
74
75     if (ovp->next)
76         ovp->next->prev = ovp->prev;
77
78     ovp->next = ovp->prev = NULL;
79
80     wine_server_release_fd( ovp->handle, ovp->fd );
81     if ( ovp->event != INVALID_HANDLE_VALUE )
82         NtSetEvent( ovp->event, NULL );
83
84     if ( ovp->ops->call_completion )
85         NtQueueApcThread( GetCurrentThread(), call_user_apc, 
86                           (ULONG_PTR)ovp->ops->call_completion, (ULONG_PTR)ovp, 0 );
87     else
88         ovp->ops->cleanup( ovp );
89 }
90
91 inline static NTSTATUS __register_async( async_private *ovp, const DWORD status )
92 {
93     NTSTATUS    ret;
94
95     SERVER_START_REQ( register_async )
96     {
97         req->handle = ovp->handle;
98         req->overlapped = ovp;
99         req->type = ovp->type;
100         req->count = ovp->ops->get_count( ovp );
101         req->status = status;
102         ret = wine_server_call( req );
103     }
104     SERVER_END_REQ;
105
106     if (ret) ovp->iosb->u.Status = ret;
107
108     if ( ovp->iosb->u.Status != STATUS_PENDING )
109         finish_async(ovp);
110
111     return ret;
112 }
113
114 #define register_old_async(ovp) \
115     __register_async(ovp, ovp->iosb->u.Status);
116
117 inline static NTSTATUS register_new_async( async_private *ovp )
118 {
119     ovp->iosb->u.Status = STATUS_PENDING;
120
121     ovp->next = NtCurrentTeb()->pending_list;
122     ovp->prev = NULL;
123     if ( ovp->next ) ovp->next->prev = ovp;
124     NtCurrentTeb()->pending_list = ovp;
125
126     return __register_async( ovp, STATUS_PENDING );
127 }
128
129 inline static NTSTATUS cancel_async( async_private *ovp )
130 {
131      /* avoid multiple cancellations */
132      if ( ovp->iosb->u.Status != STATUS_PENDING )
133           return STATUS_SUCCESS;
134      ovp->iosb->u.Status = STATUS_CANCELLED;
135      return __register_async( ovp, STATUS_CANCELLED );
136 }
137
138 #endif /* __WINE_ASYNC_H */