de412e59036f25e737f0dad9087f96ea73c6a0bc
[reactos.git] / reactos / ntoskrnl / io / iocomp.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/io/iocomp.c
6 * PURPOSE: No purpose listed.
7 *
8 * PROGRAMMERS: David Welch (welch@mcmail.com)
9 */
10
11 /* INCLUDES *****************************************************************/
12
13 #include <ntoskrnl.h>
14 #define NDEBUG
15 #include <internal/debug.h>
16
17 #define IOC_TAG TAG('I', 'O', 'C', 'T')
18
19 POBJECT_TYPE ExIoCompletionType;
20
21 NPAGED_LOOKASIDE_LIST IoCompletionPacketLookaside;
22
23 static GENERIC_MAPPING ExIoCompletionMapping =
24 {
25 STANDARD_RIGHTS_READ | IO_COMPLETION_QUERY_STATE,
26 STANDARD_RIGHTS_WRITE | IO_COMPLETION_MODIFY_STATE,
27 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | IO_COMPLETION_QUERY_STATE,
28 IO_COMPLETION_ALL_ACCESS
29 };
30
31 /* FUNCTIONS *****************************************************************/
32
33 NTSTATUS
34 STDCALL
35 IopCreateIoCompletion(
36 PVOID ObjectBody,
37 PVOID Parent,
38 PWSTR RemainingPath,
39 POBJECT_ATTRIBUTES ObjectAttributes
40 )
41 {
42 DPRINT("IopCreateIoCompletion(ObjectBody %x, Parent %x, RemainingPath %S)\n",
43 ObjectBody, Parent, RemainingPath);
44
45 if (RemainingPath != NULL && wcschr(RemainingPath+1, '\\') != NULL)
46 {
47 return STATUS_UNSUCCESSFUL;
48 }
49
50 return STATUS_SUCCESS;
51 }
52
53 VOID STDCALL
54 IopDeleteIoCompletion(PVOID ObjectBody)
55 {
56 PKQUEUE Queue = ObjectBody;
57
58 DPRINT("IopDeleteIoCompletion()\n");
59
60 KeRundownQueue(Queue);
61 }
62
63
64 /*
65 * @unimplemented
66 */
67 NTSTATUS
68 STDCALL
69 IoSetCompletionRoutineEx(
70 IN PDEVICE_OBJECT DeviceObject,
71 IN PIRP Irp,
72 IN PIO_COMPLETION_ROUTINE CompletionRoutine,
73 IN PVOID Context,
74 IN BOOLEAN InvokeOnSuccess,
75 IN BOOLEAN InvokeOnError,
76 IN BOOLEAN InvokeOnCancel
77 )
78 {
79 UNIMPLEMENTED;
80 return STATUS_NOT_IMPLEMENTED;
81 }
82
83 /*
84 * @implemented
85 */
86 NTSTATUS
87 STDCALL
88 IoSetIoCompletion (
89 IN PVOID IoCompletion,
90 IN PVOID KeyContext,
91 IN PVOID ApcContext,
92 IN NTSTATUS IoStatus,
93 IN ULONG_PTR IoStatusInformation,
94 IN BOOLEAN Quota
95 )
96 {
97 PKQUEUE Queue = (PKQUEUE) IoCompletion;
98 PIO_COMPLETION_PACKET Packet;
99
100 Packet = ExAllocateFromNPagedLookasideList(&IoCompletionPacketLookaside);
101 if (NULL == Packet)
102 {
103 return STATUS_NO_MEMORY;
104 }
105
106 Packet->Key = KeyContext;
107 Packet->Context = ApcContext;
108 Packet->IoStatus.Status = IoStatus;
109 Packet->IoStatus.Information = IoStatusInformation;
110
111 KeInsertQueue(Queue, &Packet->ListEntry);
112
113 return STATUS_SUCCESS;
114 }
115
116 VOID
117 FASTCALL
118 IopInitIoCompletionImplementation(VOID)
119 {
120 ExIoCompletionType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
121
122 RtlpCreateUnicodeString(&ExIoCompletionType->TypeName, L"IoCompletion", NonPagedPool);
123
124 ExIoCompletionType->Tag = IOC_TAG;
125 ExIoCompletionType->PeakObjects = 0;
126 ExIoCompletionType->PeakHandles = 0;
127 ExIoCompletionType->TotalObjects = 0;
128 ExIoCompletionType->TotalHandles = 0;
129 ExIoCompletionType->PagedPoolCharge = 0;
130 ExIoCompletionType->NonpagedPoolCharge = sizeof(KQUEUE);
131 ExIoCompletionType->Mapping = &ExIoCompletionMapping;
132 ExIoCompletionType->Dump = NULL;
133 ExIoCompletionType->Open = NULL;
134 ExIoCompletionType->Close = NULL;
135 ExIoCompletionType->Delete = IopDeleteIoCompletion;
136 ExIoCompletionType->Parse = NULL;
137 ExIoCompletionType->Security = NULL;
138 ExIoCompletionType->QueryName = NULL;
139 ExIoCompletionType->OkayToClose = NULL;
140 ExIoCompletionType->Create = IopCreateIoCompletion;
141 ExIoCompletionType->DuplicationNotify = NULL;
142
143 ExInitializeNPagedLookasideList(&IoCompletionPacketLookaside,
144 NULL,
145 NULL,
146 0,
147 sizeof(IO_COMPLETION_PACKET),
148 IOC_TAG,
149 0);
150 }
151
152
153 NTSTATUS
154 STDCALL
155 NtCreateIoCompletion(
156 OUT PHANDLE IoCompletionHandle,
157 IN ACCESS_MASK DesiredAccess,
158 IN POBJECT_ATTRIBUTES ObjectAttributes,
159 IN ULONG NumberOfConcurrentThreads
160 )
161 {
162 PKQUEUE Queue;
163 NTSTATUS Status;
164
165 Status = ObCreateObject(ExGetPreviousMode(),
166 ExIoCompletionType,
167 ObjectAttributes,
168 ExGetPreviousMode(),
169 NULL,
170 sizeof(KQUEUE),
171 0,
172 0,
173 (PVOID*)&Queue);
174 if (!NT_SUCCESS(Status))
175 {
176 return Status;
177 }
178
179 Status = ObInsertObject ((PVOID)Queue,
180 NULL,
181 DesiredAccess,
182 0,
183 NULL,
184 IoCompletionHandle);
185 if (!NT_SUCCESS(Status))
186 {
187 ObDereferenceObject(Queue);
188 return Status;
189 }
190
191 KeInitializeQueue(Queue, NumberOfConcurrentThreads);
192 ObDereferenceObject(Queue);
193
194 return STATUS_SUCCESS;
195 /*
196
197 CompletionPort = NULL OR ExistingCompletionPort
198
199 */
200
201
202 }
203
204 /*
205 DesiredAccess:
206 ZERO
207 IO_COMPLETION_QUERY_STATE Query access
208 IO_COMPLETION_MODIFY_STATE Modify access
209 IO_COMPLETION_ALL_ACCESS All of the preceding + STANDARD_RIGHTS_ALL
210
211 ObjectAttributes
212 OBJ_OPENLINK and OBJ_PERMANENT are not valid attributes
213
214 Return Value
215 STATUS_SUCCESS or an error status, such as STATUS_ACCESS_DENIED or
216 STATUS_OBJECT_NAME_NOT_FOUND.
217 */
218 NTSTATUS
219 STDCALL
220 NtOpenIoCompletion(
221 OUT PHANDLE IoCompletionHandle,
222 IN ACCESS_MASK DesiredAccess,
223 IN POBJECT_ATTRIBUTES ObjectAttributes
224 )
225 {
226 NTSTATUS Status;
227
228 Status = ObOpenObjectByName(ObjectAttributes,
229 ExIoCompletionType,
230 NULL,
231 UserMode,
232 DesiredAccess,
233 NULL,
234 IoCompletionHandle); //<- ???
235
236 return Status;
237 }
238
239
240 NTSTATUS
241 STDCALL
242 NtQueryIoCompletion(
243 IN HANDLE IoCompletionHandle,
244 IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass,
245 OUT PVOID IoCompletionInformation,
246 IN ULONG IoCompletionInformationLength,
247 OUT PULONG ResultLength OPTIONAL
248 )
249 {
250 PKQUEUE Queue;
251 NTSTATUS Status;
252
253 if (IoCompletionInformationClass != IoCompletionBasicInformation)
254 {
255 return STATUS_INVALID_INFO_CLASS;
256 }
257 if (IoCompletionInformationLength < sizeof(IO_COMPLETION_BASIC_INFORMATION))
258 {
259 return STATUS_INFO_LENGTH_MISMATCH;
260 }
261
262 Status = ObReferenceObjectByHandle( IoCompletionHandle,
263 IO_COMPLETION_QUERY_STATE,
264 ExIoCompletionType,
265 UserMode,
266 (PVOID*)&Queue,
267 NULL);
268 if (NT_SUCCESS(Status))
269 {
270 ((PIO_COMPLETION_BASIC_INFORMATION)IoCompletionInformation)->Depth =
271 Queue->Header.SignalState;
272
273 ObDereferenceObject(Queue);
274
275 if (ResultLength) *ResultLength = sizeof(IO_COMPLETION_BASIC_INFORMATION);
276 }
277
278 return Status;
279 }
280
281
282 /*
283 * Dequeues an I/O completion message from an I/O completion object
284 */
285 NTSTATUS
286 STDCALL
287 NtRemoveIoCompletion(
288 IN HANDLE IoCompletionHandle,
289 OUT PVOID *CompletionKey,
290 OUT PVOID *CompletionContext,
291 OUT PIO_STATUS_BLOCK IoStatusBlock,
292 IN PLARGE_INTEGER Timeout OPTIONAL
293 )
294 {
295 PKQUEUE Queue;
296 NTSTATUS Status;
297 PIO_COMPLETION_PACKET Packet;
298 PLIST_ENTRY ListEntry;
299
300 Status = ObReferenceObjectByHandle( IoCompletionHandle,
301 IO_COMPLETION_MODIFY_STATE,
302 ExIoCompletionType,
303 UserMode,
304 (PVOID*)&Queue,
305 NULL);
306 if (!NT_SUCCESS(Status))
307 {
308 return Status;
309 }
310
311 /*
312 Try 2 remove packet from queue. Wait (optionaly) if
313 no packet in queue or max num of threads allready running.
314 */
315
316 do {
317
318 ListEntry = KeRemoveQueue(Queue, UserMode, Timeout );
319
320 /* Nebbets book says nothing about NtRemoveIoCompletion returning STATUS_USER_APC,
321 and the umode equivalent GetQueuedCompletionStatus says nothing about this either,
322 so my guess it we should restart the operation. Need further investigation. -Gunnar
323 */
324
325 } while((NTSTATUS)ListEntry == STATUS_USER_APC);
326
327 ObDereferenceObject(Queue);
328
329 if ((NTSTATUS)ListEntry == STATUS_TIMEOUT)
330 {
331 return STATUS_TIMEOUT;
332 }
333
334 ASSERT(ListEntry);
335
336 Packet = CONTAINING_RECORD(ListEntry, IO_COMPLETION_PACKET, ListEntry);
337
338 if (CompletionKey) *CompletionKey = Packet->Key;
339 if (CompletionContext) *CompletionContext = Packet->Context;
340 if (IoStatusBlock) *IoStatusBlock = Packet->IoStatus;
341
342 ExFreeToNPagedLookasideList(&IoCompletionPacketLookaside, Packet);
343
344 return STATUS_SUCCESS;
345 }
346
347
348 /*
349 ASSOSIERT MED FOB's IoCompletionContext
350
351 typedef struct _IO_COMPLETION_CONTEXT {
352 PVOID Port;
353 ULONG Key;
354 } IO_COMPLETION_CONTEXT, *PIO_COMPLETION_CONTEXT;
355
356 */
357
358
359 /*
360 * Queues an I/O completion message to an I/O completion object
361 */
362 NTSTATUS
363 STDCALL
364 NtSetIoCompletion(
365 IN HANDLE IoCompletionPortHandle,
366 IN PVOID CompletionKey,
367 IN PVOID CompletionContext,
368 IN NTSTATUS CompletionStatus,
369 IN ULONG CompletionInformation
370 )
371 {
372 NTSTATUS Status;
373 PKQUEUE Queue;
374
375 Status = ObReferenceObjectByHandle( IoCompletionPortHandle,
376 IO_COMPLETION_MODIFY_STATE,
377 ExIoCompletionType,
378 UserMode,
379 (PVOID*)&Queue,
380 NULL);
381 if (NT_SUCCESS(Status))
382 {
383 Status = IoSetIoCompletion(Queue, CompletionKey, CompletionContext,
384 CompletionStatus, CompletionInformation, TRUE);
385 ObDereferenceObject(Queue);
386 }
387
388 return Status;
389 }