initial work on I/O completion
[reactos.git] / reactos / ntoskrnl / io / iocomp.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/ke/iocomp.c
5 * PURPOSE:
6 * PROGRAMMER: David Welch (welch@mcmail.com)
7 * UPDATE HISTORY:
8 * Created 22/05/98
9 Changed NtQueryIoCompletion
10 */
11
12 /* INCLUDES *****************************************************************/
13
14 #include <limits.h>
15 #include <ddk/ntddk.h>
16 #include <ntos/synch.h>
17
18 #define NDEBUG
19 #include <internal/debug.h>
20
21 #define IOC_TAG TAG('I', 'O', 'C', 'T')
22
23 POBJECT_TYPE ExIoCompletionType;
24
25 NPAGED_LOOKASIDE_LIST IoCompletionPacketLookaside;
26
27 static GENERIC_MAPPING ExIoCompletionMapping =
28 {
29 STANDARD_RIGHTS_READ | IO_COMPLETION_QUERY_STATE,
30 STANDARD_RIGHTS_WRITE | IO_COMPLETION_MODIFY_STATE,
31 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | IO_COMPLETION_QUERY_STATE,
32 IO_COMPLETION_ALL_ACCESS
33 };
34
35 /* FUNCTIONS *****************************************************************/
36
37 NTSTATUS
38 STDCALL
39 NtpCreateIoCompletion(
40 PVOID ObjectBody,
41 PVOID Parent,
42 PWSTR RemainingPath,
43 POBJECT_ATTRIBUTES ObjectAttributes
44 )
45 {
46 DPRINT("NtpCreateIoCompletion(ObjectBody %x, Parent %x, RemainingPath %S)\n",
47 ObjectBody, Parent, RemainingPath);
48
49 if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL)
50 {
51 return STATUS_UNSUCCESSFUL;
52 }
53
54 return STATUS_SUCCESS;
55 }
56
57 VOID STDCALL
58 NtpDeleteIoCompletion(PVOID ObjectBody)
59 {
60 PKQUEUE Queue = ObjectBody;
61
62 DPRINT("NtpDeleteIoCompletion()\n");
63
64 KeRundownQueue(Queue);
65 }
66
67
68 VOID
69 NtInitializeIoCompletionImplementation(VOID)
70 {
71 ExIoCompletionType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
72
73 RtlCreateUnicodeString(&ExIoCompletionType->TypeName, L"IoCompletion");
74
75 ExIoCompletionType->Tag = IOC_TAG;
76 ExIoCompletionType->MaxObjects = ULONG_MAX;
77 ExIoCompletionType->MaxHandles = ULONG_MAX;
78 ExIoCompletionType->TotalObjects = 0;
79 ExIoCompletionType->TotalHandles = 0;
80 ExIoCompletionType->PagedPoolCharge = 0;
81 ExIoCompletionType->NonpagedPoolCharge = sizeof(KQUEUE);
82 ExIoCompletionType->Mapping = &ExIoCompletionMapping;
83 ExIoCompletionType->Dump = NULL;
84 ExIoCompletionType->Open = NULL;
85 ExIoCompletionType->Close = NULL;
86 ExIoCompletionType->Delete = NtpDeleteIoCompletion;
87 ExIoCompletionType->Parse = NULL;
88 ExIoCompletionType->Security = NULL;
89 ExIoCompletionType->QueryName = NULL;
90 ExIoCompletionType->OkayToClose = NULL;
91 ExIoCompletionType->Create = NtpCreateIoCompletion;
92 ExIoCompletionType->DuplicationNotify = NULL;
93
94 ExInitializeNPagedLookasideList(&IoCompletionPacketLookaside,
95 NULL,
96 NULL,
97 0,
98 sizeof(IO_COMPLETION_PACKET),
99 IOC_TAG,
100 0);
101 }
102
103
104 NTSTATUS
105 STDCALL
106 NtCreateIoCompletion(
107 OUT PHANDLE IoCompletionHandle,
108 IN ACCESS_MASK DesiredAccess,
109 IN POBJECT_ATTRIBUTES ObjectAttributes,
110 IN ULONG NumberOfConcurrentThreads
111 )
112 {
113 PKQUEUE Queue;
114 NTSTATUS Status;
115
116 Status = ObCreateObject(IoCompletionHandle,
117 DesiredAccess,
118 ObjectAttributes,
119 ExIoCompletionType,
120 (PVOID*)&Queue);
121
122 if (NT_SUCCESS(Status))
123 {
124 (void) KeInitializeQueue(Queue, NumberOfConcurrentThreads);
125 ObDereferenceObject(Queue);
126 }
127
128 return Status;
129 /*
130
131 CompletionPort = NULL OR ExistingCompletionPort
132
133 */
134
135
136 }
137
138 /*
139 DesiredAccess:
140 ZERO
141 IO_COMPLETION_QUERY_STATE Query access
142 IO_COMPLETION_MODIFY_STATE Modify access
143 IO_COMPLETION_ALL_ACCESS All of the preceding + STANDARD_RIGHTS_ALL
144
145 ObjectAttributes
146 OBJ_OPENLINK and OBJ_PERMANENT are not valid attributes
147
148 Return Value
149 STATUS_SUCCESS or an error status, such as STATUS_ACCESS_DENIED or
150 STATUS_OBJECT_NAME_NOT_FOUND.
151 */
152 NTSTATUS
153 STDCALL
154 NtOpenIoCompletion(
155 OUT PHANDLE IoCompletionHandle,
156 IN ACCESS_MASK DesiredAccess,
157 IN POBJECT_ATTRIBUTES ObjectAttributes
158 )
159 {
160 NTSTATUS Status;
161
162 Status = ObOpenObjectByName(ObjectAttributes,
163 ExIoCompletionType,
164 NULL,
165 UserMode,
166 DesiredAccess,
167 NULL,
168 IoCompletionHandle); //<- ???
169
170 return Status;
171 }
172
173
174 NTSTATUS
175 STDCALL
176 NtQueryIoCompletion(
177 IN HANDLE IoCompletionHandle,
178 IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass,
179 OUT PVOID IoCompletionInformation,
180 IN ULONG IoCompletionInformationLength,
181 OUT PULONG ResultLength OPTIONAL
182 )
183 {
184 PKQUEUE Queue;
185 NTSTATUS Status;
186
187 if (IoCompletionInformationClass != IoCompletionBasicInformation)
188 {
189 return STATUS_INVALID_INFO_CLASS;
190 }
191 if (IoCompletionInformationLength < sizeof(IO_COMPLETION_BASIC_INFORMATION))
192 {
193 return STATUS_INFO_LENGTH_MISMATCH;
194 }
195
196 Status = ObReferenceObjectByHandle( IoCompletionHandle,
197 IO_COMPLETION_QUERY_STATE,
198 ExIoCompletionType,
199 UserMode,
200 (PVOID*)&Queue,
201 NULL);
202 if (NT_SUCCESS(Status))
203 {
204 ((PIO_COMPLETION_BASIC_INFORMATION)IoCompletionInformation)->SignalState =
205 Queue->Header.SignalState;
206
207 ObDereferenceObject(Queue);
208
209 if (ResultLength) *ResultLength = sizeof(IO_COMPLETION_BASIC_INFORMATION);
210 }
211
212 return Status;
213 }
214
215
216 /*
217 * Dequeues an I/O completion message from an I/O completion object
218 */
219 NTSTATUS
220 STDCALL
221 NtRemoveIoCompletion(
222 IN HANDLE IoCompletionHandle,
223 OUT PULONG CompletionKey,
224 OUT PULONG CompletionValue,
225 OUT PIO_STATUS_BLOCK IoStatusBlock,
226 IN PLARGE_INTEGER Timeout OPTIONAL
227 )
228 {
229 PKQUEUE Queue;
230 NTSTATUS Status;
231
232 Status = ObReferenceObjectByHandle( IoCompletionHandle,
233 IO_COMPLETION_MODIFY_STATE,
234 ExIoCompletionType,
235 UserMode,
236 (PVOID*)&Queue,
237 NULL);
238 if (NT_SUCCESS(Status))
239 {
240 PIO_COMPLETION_PACKET Packet;
241 PLIST_ENTRY ListEntry;
242
243 /*
244 Try 2 remove packet from queue. Wait (optionaly) if
245 no packet in queue or max num of threads allready running.
246 */
247 ListEntry = KeRemoveQueue(Queue, UserMode, Timeout );
248
249 ObDereferenceObject(Queue);
250
251 Packet = CONTAINING_RECORD(ListEntry, IO_COMPLETION_PACKET, ListEntry);
252
253 if (CompletionKey) *CompletionKey = Packet->Key;
254 if (CompletionValue) *CompletionValue = Packet->Overlapped;
255 if (IoStatusBlock) *IoStatusBlock = Packet->IoStatus;
256
257 ExFreeToNPagedLookasideList(&IoCompletionPacketLookaside, Packet);
258 }
259
260 return Status;
261 }
262
263
264 /*
265 ASSOSIERT MED FOB's IoCompletionContext
266
267 typedef struct _IO_COMPLETION_CONTEXT {
268 PVOID Port;
269 ULONG Key;
270 } IO_COMPLETION_CONTEXT, *PIO_COMPLETION_CONTEXT;
271
272 */
273
274
275 /*
276 * Queues an I/O completion message to an I/O completion object
277 */
278 NTSTATUS
279 STDCALL
280 NtSetIoCompletion(
281 IN HANDLE IoCompletionPortHandle,
282 IN ULONG CompletionKey,
283 IN ULONG CompletionValue,
284 IN NTSTATUS CompletionStatus,
285 IN ULONG CompletionInformation
286 )
287 {
288 NTSTATUS Status;
289 PKQUEUE Queue;
290
291 Status = ObReferenceObjectByHandle( IoCompletionPortHandle,
292 IO_COMPLETION_MODIFY_STATE,
293 ExIoCompletionType,
294 UserMode,
295 (PVOID*)&Queue,
296 NULL);
297 if (NT_SUCCESS(Status))
298 {
299 PIO_COMPLETION_PACKET Packet;
300
301 Packet = ExAllocateFromNPagedLookasideList(&IoCompletionPacketLookaside);
302
303 Packet->Key = CompletionKey;
304 Packet->Overlapped = CompletionValue;
305 Packet->IoStatus.Status = CompletionStatus;
306 Packet->IoStatus.Information = CompletionInformation;
307
308 KeInsertQueue(Queue, &Packet->ListEntry);
309 ObDereferenceObject(Queue);
310 }
311
312 return Status;
313 }