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 ProbeForWrite(IoCompletionHandle
,
245 Status
= _SEH_GetExceptionCode();
248 if (!NT_SUCCESS(Status
)) {
254 /* Create the Object */
255 Status
= ObCreateObject(PreviousMode
,
265 /* Check for success */
266 if (NT_SUCCESS(Status
)) {
268 /* Initialize the Queue */
269 KeInitializeQueue(Queue
, NumberOfConcurrentThreads
);
272 Status
= ObInsertObject(Queue
,
277 &hIoCompletionHandle
);
278 ObDereferenceObject(Queue
);
280 if (NT_SUCCESS(Status
)) {
284 *IoCompletionHandle
= hIoCompletionHandle
;
287 Status
= _SEH_GetExceptionCode();
298 NtOpenIoCompletion(OUT PHANDLE IoCompletionHandle
,
299 IN ACCESS_MASK DesiredAccess
,
300 IN POBJECT_ATTRIBUTES ObjectAttributes
)
302 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
303 HANDLE hIoCompletionHandle
;
304 NTSTATUS Status
= STATUS_SUCCESS
;
308 if(PreviousMode
!= KernelMode
) {
312 ProbeForWrite(IoCompletionHandle
,
317 Status
= _SEH_GetExceptionCode();
320 if(!NT_SUCCESS(Status
)) {
326 /* Open the Object */
327 Status
= ObOpenObjectByName(ObjectAttributes
,
333 &hIoCompletionHandle
);
335 if (NT_SUCCESS(Status
)) {
339 *IoCompletionHandle
= hIoCompletionHandle
;
342 Status
= _SEH_GetExceptionCode();
353 NtQueryIoCompletion(IN HANDLE IoCompletionHandle
,
354 IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass
,
355 OUT PVOID IoCompletionInformation
,
356 IN ULONG IoCompletionInformationLength
,
357 OUT PULONG ResultLength OPTIONAL
)
360 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
361 NTSTATUS Status
= STATUS_SUCCESS
;
365 /* Check buffers and parameters */
366 DefaultQueryInfoBufferCheck(IoCompletionInformationClass
,
367 IoCompletionInfoClass
,
368 IoCompletionInformation
,
369 IoCompletionInformationLength
,
373 if(!NT_SUCCESS(Status
)) {
375 DPRINT1("NtQueryMutant() failed, Status: 0x%x\n", Status
);
380 Status
= ObReferenceObjectByHandle(IoCompletionHandle
,
381 IO_COMPLETION_QUERY_STATE
,
387 /* Check for Success */
388 if (NT_SUCCESS(Status
)) {
393 ((PIO_COMPLETION_BASIC_INFORMATION
)IoCompletionInformation
)->Depth
= KeReadStateQueue(Queue
);
394 ObDereferenceObject(Queue
);
396 /* Return Result Length if needed */
399 *ResultLength
= sizeof(IO_COMPLETION_BASIC_INFORMATION
);
403 Status
= _SEH_GetExceptionCode();
412 * Dequeues an I/O completion message from an I/O completion object
416 NtRemoveIoCompletion(IN HANDLE IoCompletionHandle
,
417 OUT PVOID
*CompletionKey
,
418 OUT PVOID
*CompletionContext
,
419 OUT PIO_STATUS_BLOCK IoStatusBlock
,
420 IN PLARGE_INTEGER Timeout OPTIONAL
)
422 LARGE_INTEGER SafeTimeout
;
424 PIO_COMPLETION_PACKET Packet
;
425 PLIST_ENTRY ListEntry
;
426 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
427 NTSTATUS Status
= STATUS_SUCCESS
;
431 if (PreviousMode
!= KernelMode
) {
435 ProbeForWrite(CompletionKey
,
438 ProbeForWrite(CompletionContext
,
441 ProbeForWrite(IoStatusBlock
,
442 sizeof(IO_STATUS_BLOCK
),
444 if (Timeout
!= NULL
) {
446 ProbeForRead(Timeout
,
447 sizeof(LARGE_INTEGER
),
449 SafeTimeout
= *Timeout
;
450 Timeout
= &SafeTimeout
;
454 Status
= _SEH_GetExceptionCode();
457 if (!NT_SUCCESS(Status
)) {
463 /* Open the Object */
464 Status
= ObReferenceObjectByHandle(IoCompletionHandle
,
465 IO_COMPLETION_MODIFY_STATE
,
471 /* Check for success */
472 if (NT_SUCCESS(Status
)) {
475 ListEntry
= KeRemoveQueue(Queue
, PreviousMode
, Timeout
);
477 /* If we got a timeout or user_apc back, return the status */
478 if ((NTSTATUS
)ListEntry
== STATUS_TIMEOUT
|| (NTSTATUS
)ListEntry
== STATUS_USER_APC
) {
480 Status
= (NTSTATUS
)ListEntry
;
484 /* Get the Packet Data */
485 Packet
= CONTAINING_RECORD(ListEntry
, IO_COMPLETION_PACKET
, ListEntry
);
489 /* Check if this is piggybacked on an IRP */
490 if (Packet
->PacketType
== IrpCompletionPacket
)
494 Irp
= CONTAINING_RECORD(ListEntry
, IRP
, Tail
.Overlay
.ListEntry
);
496 /* Return values to user */
497 *CompletionKey
= Irp
->Tail
.CompletionKey
;
498 *CompletionContext
= Irp
->Overlay
.AsynchronousParameters
.UserApcContext
;
499 *IoStatusBlock
= Packet
->IoStatus
;
504 /* This is a user-mode generated or API generated mini-packet */
505 *CompletionKey
= Packet
->Key
;
506 *CompletionContext
= Packet
->Context
;
507 *IoStatusBlock
= Packet
->IoStatus
;
508 IopFreeIoCompletionPacket(Packet
);
513 Status
= _SEH_GetExceptionCode();
517 /* Dereference the Object */
518 ObDereferenceObject(Queue
);
526 * Queues an I/O completion message to an I/O completion object
530 NtSetIoCompletion(IN HANDLE IoCompletionPortHandle
,
531 IN PVOID CompletionKey
,
532 IN PVOID CompletionContext
,
533 IN NTSTATUS CompletionStatus
,
534 IN ULONG CompletionInformation
)
542 Status
= ObReferenceObjectByHandle(IoCompletionPortHandle
,
543 IO_COMPLETION_MODIFY_STATE
,
549 /* Check for Success */
550 if (NT_SUCCESS(Status
)) {
552 /* Set the Completion */
553 Status
= IoSetIoCompletion(Queue
,
557 CompletionInformation
,
559 ObDereferenceObject(Queue
);