2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * FILE: ntoskrnl/io/iocomp.c
5 * PURPOSE: No purpose listed.
7 * PROGRAMMERS: David Welch (welch@mcmail.com)
10 /* INCLUDES *****************************************************************/
14 #include <internal/debug.h>
16 POBJECT_TYPE IoCompletionType
;
18 NPAGED_LOOKASIDE_LIST IoCompletionPacketLookaside
;
20 static GENERIC_MAPPING IopCompletionMapping
=
22 STANDARD_RIGHTS_READ
| IO_COMPLETION_QUERY_STATE
,
23 STANDARD_RIGHTS_WRITE
| IO_COMPLETION_MODIFY_STATE
,
24 STANDARD_RIGHTS_EXECUTE
| SYNCHRONIZE
| IO_COMPLETION_QUERY_STATE
,
25 IO_COMPLETION_ALL_ACCESS
28 static const INFORMATION_CLASS_INFO IoCompletionInfoClass
[] = {
30 /* IoCompletionBasicInformation */
31 ICI_SQ_SAME( sizeof(IO_COMPLETION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
),
34 /* FUNCTIONS *****************************************************************/
38 IopFreeIoCompletionPacket(PIO_COMPLETION_PACKET Packet
)
40 PKPRCB Prcb
= KeGetCurrentPrcb();
41 PNPAGED_LOOKASIDE_LIST List
;
44 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[LookasideCompletionList
].P
;
47 /* Check if the Free was within the Depth or not */
48 if (ExQueryDepthSList(&List
->L
.ListHead
) >= List
->L
.Depth
)
50 /* Let the balancer know */
54 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[LookasideCompletionList
].L
;
57 /* Check if the Free was within the Depth or not */
58 if (ExQueryDepthSList(&List
->L
.ListHead
) >= List
->L
.Depth
)
60 /* All lists failed, use the pool */
66 /* The free was within dhe Depth */
67 InterlockedPushEntrySList(&List
->L
.ListHead
, (PSINGLE_LIST_ENTRY
)Packet
);
72 IopDeleteIoCompletion(PVOID ObjectBody
)
74 PKQUEUE Queue
= ObjectBody
;
75 PLIST_ENTRY FirstEntry
;
76 PLIST_ENTRY CurrentEntry
;
78 PIO_COMPLETION_PACKET Packet
;
80 DPRINT("IopDeleteIoCompletion()\n");
82 /* Rundown the Queue */
83 FirstEntry
= KeRundownQueue(Queue
);
85 /* Clean up the IRPs */
88 CurrentEntry
= FirstEntry
;
92 Packet
= CONTAINING_RECORD(CurrentEntry
, IO_COMPLETION_PACKET
, ListEntry
);
94 /* Go to next Entry */
95 CurrentEntry
= CurrentEntry
->Flink
;
97 /* Check if it's part of an IRP, or a separate packet */
98 if (Packet
->PacketType
== IrpCompletionPacket
)
100 /* Get the IRP and free it */
101 Irp
= CONTAINING_RECORD(Packet
, IRP
, Tail
.Overlay
.ListEntry
);
106 /* Use common routine */
107 IopFreeIoCompletionPacket(Packet
);
109 } while (FirstEntry
!= CurrentEntry
);
118 IoSetIoCompletion(IN PVOID IoCompletion
,
121 IN NTSTATUS IoStatus
,
122 IN ULONG_PTR IoStatusInformation
,
125 PKQUEUE Queue
= (PKQUEUE
)IoCompletion
;
126 PNPAGED_LOOKASIDE_LIST List
;
127 PKPRCB Prcb
= KeGetCurrentPrcb();
128 PIO_COMPLETION_PACKET Packet
;
131 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[LookasideCompletionList
].P
;
133 /* Try to allocate the Packet */
134 List
->L
.TotalAllocates
++;
135 Packet
= (PVOID
)InterlockedPopEntrySList(&List
->L
.ListHead
);
137 /* Check if that failed, use the L list if it did */
140 /* Let the balancer know */
141 List
->L
.AllocateMisses
++;
144 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[LookasideCompletionList
].L
;
146 /* Try to allocate the Packet */
147 List
->L
.TotalAllocates
++;
148 Packet
= (PVOID
)InterlockedPopEntrySList(&List
->L
.ListHead
);
151 /* Still failed, use pool */
154 /* Let the balancer know */
155 List
->L
.AllocateMisses
++;
157 /* Allocate from Nonpaged Pool */
158 Packet
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(*Packet
), IOC_TAG
);
161 /* Make sure we have one by now... */
164 /* Set up the Packet */
165 Packet
->PacketType
= IrpMiniCompletionPacket
;
166 Packet
->Key
= KeyContext
;
167 Packet
->Context
= ApcContext
;
168 Packet
->IoStatus
.Status
= IoStatus
;
169 Packet
->IoStatus
.Information
= IoStatusInformation
;
171 /* Insert the Queue */
172 KeInsertQueue(Queue
, &Packet
->ListEntry
);
176 return STATUS_INSUFFICIENT_RESOURCES
;
180 return STATUS_SUCCESS
;
188 IoSetCompletionRoutineEx(IN PDEVICE_OBJECT DeviceObject
,
190 IN PIO_COMPLETION_ROUTINE CompletionRoutine
,
192 IN BOOLEAN InvokeOnSuccess
,
193 IN BOOLEAN InvokeOnError
,
194 IN BOOLEAN InvokeOnCancel
)
197 return STATUS_NOT_IMPLEMENTED
;
202 IopInitIoCompletionImplementation(VOID
)
204 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
207 DPRINT("Creating IoCompletion Object Type\n");
209 /* Initialize the Driver object type */
210 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
211 RtlInitUnicodeString(&Name
, L
"IoCompletion");
212 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
213 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(KQUEUE
);
214 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
215 ObjectTypeInitializer
.ValidAccessMask
= IO_COMPLETION_ALL_ACCESS
;
216 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
217 ObjectTypeInitializer
.GenericMapping
= IopCompletionMapping
;
218 ObjectTypeInitializer
.DeleteProcedure
= IopDeleteIoCompletion
;
219 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &IoCompletionType
);
224 NtCreateIoCompletion(OUT PHANDLE IoCompletionHandle
,
225 IN ACCESS_MASK DesiredAccess
,
226 IN POBJECT_ATTRIBUTES ObjectAttributes
,
227 IN ULONG NumberOfConcurrentThreads
)
230 HANDLE hIoCompletionHandle
;
231 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
232 NTSTATUS Status
= STATUS_SUCCESS
;
236 if (PreviousMode
!= KernelMode
) {
240 ProbeForWriteHandle(IoCompletionHandle
);
243 Status
= _SEH_GetExceptionCode();
246 if (!NT_SUCCESS(Status
)) {
252 /* Create the Object */
253 Status
= ObCreateObject(PreviousMode
,
263 /* Check for success */
264 if (NT_SUCCESS(Status
)) {
266 /* Initialize the Queue */
267 KeInitializeQueue(Queue
, NumberOfConcurrentThreads
);
270 Status
= ObInsertObject(Queue
,
275 &hIoCompletionHandle
);
276 ObDereferenceObject(Queue
);
278 if (NT_SUCCESS(Status
)) {
282 *IoCompletionHandle
= hIoCompletionHandle
;
285 Status
= _SEH_GetExceptionCode();
296 NtOpenIoCompletion(OUT PHANDLE IoCompletionHandle
,
297 IN ACCESS_MASK DesiredAccess
,
298 IN POBJECT_ATTRIBUTES ObjectAttributes
)
300 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
301 HANDLE hIoCompletionHandle
;
302 NTSTATUS Status
= STATUS_SUCCESS
;
306 if(PreviousMode
!= KernelMode
) {
310 ProbeForWriteHandle(IoCompletionHandle
);
313 Status
= _SEH_GetExceptionCode();
316 if(!NT_SUCCESS(Status
)) {
322 /* Open the Object */
323 Status
= ObOpenObjectByName(ObjectAttributes
,
329 &hIoCompletionHandle
);
331 if (NT_SUCCESS(Status
)) {
335 *IoCompletionHandle
= hIoCompletionHandle
;
338 Status
= _SEH_GetExceptionCode();
349 NtQueryIoCompletion(IN HANDLE IoCompletionHandle
,
350 IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass
,
351 OUT PVOID IoCompletionInformation
,
352 IN ULONG IoCompletionInformationLength
,
353 OUT PULONG ResultLength OPTIONAL
)
356 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
357 NTSTATUS Status
= STATUS_SUCCESS
;
361 /* Check buffers and parameters */
362 Status
= DefaultQueryInfoBufferCheck(IoCompletionInformationClass
,
363 IoCompletionInfoClass
,
364 sizeof(IoCompletionInfoClass
) / sizeof(IoCompletionInfoClass
[0]),
365 IoCompletionInformation
,
366 IoCompletionInformationLength
,
369 if(!NT_SUCCESS(Status
)) {
371 DPRINT1("NtQueryMutant() failed, Status: 0x%x\n", Status
);
376 Status
= ObReferenceObjectByHandle(IoCompletionHandle
,
377 IO_COMPLETION_QUERY_STATE
,
383 /* Check for Success */
384 if (NT_SUCCESS(Status
)) {
389 ((PIO_COMPLETION_BASIC_INFORMATION
)IoCompletionInformation
)->Depth
= KeReadStateQueue(Queue
);
390 ObDereferenceObject(Queue
);
392 /* Return Result Length if needed */
395 *ResultLength
= sizeof(IO_COMPLETION_BASIC_INFORMATION
);
399 Status
= _SEH_GetExceptionCode();
408 * Dequeues an I/O completion message from an I/O completion object
412 NtRemoveIoCompletion(IN HANDLE IoCompletionHandle
,
413 OUT PVOID
*CompletionKey
,
414 OUT PVOID
*CompletionContext
,
415 OUT PIO_STATUS_BLOCK IoStatusBlock
,
416 IN PLARGE_INTEGER Timeout OPTIONAL
)
418 LARGE_INTEGER SafeTimeout
;
420 PIO_COMPLETION_PACKET Packet
;
421 PLIST_ENTRY ListEntry
;
422 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
423 NTSTATUS Status
= STATUS_SUCCESS
;
427 if (PreviousMode
!= KernelMode
) {
431 ProbeForWritePointer(CompletionKey
);
432 ProbeForWritePointer(CompletionContext
);
433 ProbeForWrite(IoStatusBlock
,
434 sizeof(IO_STATUS_BLOCK
),
436 if (Timeout
!= NULL
) {
438 SafeTimeout
= ProbeForReadLargeInteger(Timeout
);
439 Timeout
= &SafeTimeout
;
443 Status
= _SEH_GetExceptionCode();
446 if (!NT_SUCCESS(Status
)) {
452 /* Open the Object */
453 Status
= ObReferenceObjectByHandle(IoCompletionHandle
,
454 IO_COMPLETION_MODIFY_STATE
,
460 /* Check for success */
461 if (NT_SUCCESS(Status
)) {
464 ListEntry
= KeRemoveQueue(Queue
, PreviousMode
, Timeout
);
466 /* If we got a timeout or user_apc back, return the status */
467 if ((NTSTATUS
)ListEntry
== STATUS_TIMEOUT
|| (NTSTATUS
)ListEntry
== STATUS_USER_APC
) {
469 Status
= (NTSTATUS
)ListEntry
;
473 /* Get the Packet Data */
474 Packet
= CONTAINING_RECORD(ListEntry
, IO_COMPLETION_PACKET
, ListEntry
);
478 /* Check if this is piggybacked on an IRP */
479 if (Packet
->PacketType
== IrpCompletionPacket
)
483 Irp
= CONTAINING_RECORD(ListEntry
, IRP
, Tail
.Overlay
.ListEntry
);
485 /* Return values to user */
486 *CompletionKey
= Irp
->Tail
.CompletionKey
;
487 *CompletionContext
= Irp
->Overlay
.AsynchronousParameters
.UserApcContext
;
488 *IoStatusBlock
= Packet
->IoStatus
;
493 /* This is a user-mode generated or API generated mini-packet */
494 *CompletionKey
= Packet
->Key
;
495 *CompletionContext
= Packet
->Context
;
496 *IoStatusBlock
= Packet
->IoStatus
;
497 IopFreeIoCompletionPacket(Packet
);
502 Status
= _SEH_GetExceptionCode();
506 /* Dereference the Object */
507 ObDereferenceObject(Queue
);
515 * Queues an I/O completion message to an I/O completion object
519 NtSetIoCompletion(IN HANDLE IoCompletionPortHandle
,
520 IN PVOID CompletionKey
,
521 IN PVOID CompletionContext
,
522 IN NTSTATUS CompletionStatus
,
523 IN ULONG CompletionInformation
)
531 Status
= ObReferenceObjectByHandle(IoCompletionPortHandle
,
532 IO_COMPLETION_MODIFY_STATE
,
538 /* Check for Success */
539 if (NT_SUCCESS(Status
)) {
541 /* Set the Completion */
542 Status
= IoSetIoCompletion(Queue
,
546 CompletionInformation
,
548 ObDereferenceObject(Queue
);