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 #define IOC_TAG TAG('I', 'O', 'C', 'T')
18 POBJECT_TYPE IoCompletionType
;
20 NPAGED_LOOKASIDE_LIST IoCompletionPacketLookaside
;
22 static GENERIC_MAPPING IopCompletionMapping
=
24 STANDARD_RIGHTS_READ
| IO_COMPLETION_QUERY_STATE
,
25 STANDARD_RIGHTS_WRITE
| IO_COMPLETION_MODIFY_STATE
,
26 STANDARD_RIGHTS_EXECUTE
| SYNCHRONIZE
| IO_COMPLETION_QUERY_STATE
,
27 IO_COMPLETION_ALL_ACCESS
30 static const INFORMATION_CLASS_INFO IoCompletionInfoClass
[] = {
32 /* IoCompletionBasicInformation */
33 ICI_SQ_SAME( sizeof(IO_COMPLETION_BASIC_INFORMATION
), sizeof(ULONG
), ICIF_QUERY
),
36 /* FUNCTIONS *****************************************************************/
40 IopFreeIoCompletionPacket(PIO_COMPLETION_PACKET Packet
)
42 PKPRCB Prcb
= KeGetCurrentPrcb();
43 PNPAGED_LOOKASIDE_LIST List
;
46 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[LookasideCompletionList
].P
;
49 /* Check if the Free was within the Depth or not */
50 if (ExQueryDepthSList(&List
->L
.ListHead
) >= List
->L
.Depth
)
52 /* Let the balancer know */
56 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[LookasideCompletionList
].L
;
59 /* Check if the Free was within the Depth or not */
60 if (ExQueryDepthSList(&List
->L
.ListHead
) >= List
->L
.Depth
)
62 /* All lists failed, use the pool */
68 /* The free was within dhe Depth */
69 InterlockedPushEntrySList(&List
->L
.ListHead
, (PSINGLE_LIST_ENTRY
)Packet
);
74 IopDeleteIoCompletion(PVOID ObjectBody
)
76 PKQUEUE Queue
= ObjectBody
;
77 PLIST_ENTRY FirstEntry
;
78 PLIST_ENTRY CurrentEntry
;
80 PIO_COMPLETION_PACKET Packet
;
82 DPRINT("IopDeleteIoCompletion()\n");
84 /* Rundown the Queue */
85 FirstEntry
= KeRundownQueue(Queue
);
87 /* Clean up the IRPs */
90 CurrentEntry
= FirstEntry
;
94 Packet
= CONTAINING_RECORD(CurrentEntry
, IO_COMPLETION_PACKET
, ListEntry
);
96 /* Go to next Entry */
97 CurrentEntry
= CurrentEntry
->Flink
;
99 /* Check if it's part of an IRP, or a separate packet */
100 if (Packet
->PacketType
== IrpCompletionPacket
)
102 /* Get the IRP and free it */
103 Irp
= CONTAINING_RECORD(Packet
, IRP
, Tail
.Overlay
.ListEntry
);
108 /* Use common routine */
109 IopFreeIoCompletionPacket(Packet
);
111 } while (FirstEntry
!= CurrentEntry
);
120 IoSetIoCompletion(IN PVOID IoCompletion
,
123 IN NTSTATUS IoStatus
,
124 IN ULONG_PTR IoStatusInformation
,
127 PKQUEUE Queue
= (PKQUEUE
)IoCompletion
;
128 PNPAGED_LOOKASIDE_LIST List
;
129 PKPRCB Prcb
= KeGetCurrentPrcb();
130 PIO_COMPLETION_PACKET Packet
;
133 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[LookasideCompletionList
].P
;
135 /* Try to allocate the Packet */
136 List
->L
.TotalAllocates
++;
137 Packet
= (PVOID
)InterlockedPopEntrySList(&List
->L
.ListHead
);
139 /* Check if that failed, use the L list if it did */
142 /* Let the balancer know */
143 List
->L
.AllocateMisses
++;
146 List
= (PNPAGED_LOOKASIDE_LIST
)Prcb
->PPLookasideList
[LookasideCompletionList
].L
;
148 /* Try to allocate the Packet */
149 List
->L
.TotalAllocates
++;
150 Packet
= (PVOID
)InterlockedPopEntrySList(&List
->L
.ListHead
);
153 /* Still failed, use pool */
156 /* Let the balancer know */
157 List
->L
.AllocateMisses
++;
159 /* Allocate from Nonpaged Pool */
160 Packet
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(*Packet
), IOC_TAG
);
163 /* Make sure we have one by now... */
166 /* Set up the Packet */
167 Packet
->PacketType
= IrpMiniCompletionPacket
;
168 Packet
->Key
= KeyContext
;
169 Packet
->Context
= ApcContext
;
170 Packet
->IoStatus
.Status
= IoStatus
;
171 Packet
->IoStatus
.Information
= IoStatusInformation
;
173 /* Insert the Queue */
174 KeInsertQueue(Queue
, &Packet
->ListEntry
);
178 return STATUS_INSUFFICIENT_RESOURCES
;
182 return STATUS_SUCCESS
;
190 IoSetCompletionRoutineEx(IN PDEVICE_OBJECT DeviceObject
,
192 IN PIO_COMPLETION_ROUTINE CompletionRoutine
,
194 IN BOOLEAN InvokeOnSuccess
,
195 IN BOOLEAN InvokeOnError
,
196 IN BOOLEAN InvokeOnCancel
)
199 return STATUS_NOT_IMPLEMENTED
;
204 IopInitIoCompletionImplementation(VOID
)
206 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
209 DPRINT1("Creating IoCompletion Object Type\n");
211 /* Initialize the Driver object type */
212 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
213 RtlInitUnicodeString(&Name
, L
"IoCompletion");
214 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
215 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(KQUEUE
);
216 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
217 ObjectTypeInitializer
.ValidAccessMask
= IO_COMPLETION_ALL_ACCESS
;
218 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
219 ObjectTypeInitializer
.GenericMapping
= IopCompletionMapping
;
220 ObjectTypeInitializer
.DeleteProcedure
= IopDeleteIoCompletion
;
221 ObpCreateTypeObject(&ObjectTypeInitializer
, &Name
, &IoCompletionType
);
226 NtCreateIoCompletion(OUT PHANDLE IoCompletionHandle
,
227 IN ACCESS_MASK DesiredAccess
,
228 IN POBJECT_ATTRIBUTES ObjectAttributes
,
229 IN ULONG NumberOfConcurrentThreads
)
232 HANDLE hIoCompletionHandle
;
233 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
234 NTSTATUS Status
= STATUS_SUCCESS
;
238 if (PreviousMode
!= KernelMode
) {
242 ProbeForWrite(IoCompletionHandle
,
247 Status
= _SEH_GetExceptionCode();
250 if (!NT_SUCCESS(Status
)) {
256 /* Create the Object */
257 Status
= ObCreateObject(PreviousMode
,
267 /* Check for success */
268 if (NT_SUCCESS(Status
)) {
270 /* Initialize the Queue */
271 KeInitializeQueue(Queue
, NumberOfConcurrentThreads
);
274 Status
= ObInsertObject(Queue
,
279 &hIoCompletionHandle
);
280 ObDereferenceObject(Queue
);
282 if (NT_SUCCESS(Status
)) {
286 *IoCompletionHandle
= hIoCompletionHandle
;
289 Status
= _SEH_GetExceptionCode();
300 NtOpenIoCompletion(OUT PHANDLE IoCompletionHandle
,
301 IN ACCESS_MASK DesiredAccess
,
302 IN POBJECT_ATTRIBUTES ObjectAttributes
)
304 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
305 HANDLE hIoCompletionHandle
;
306 NTSTATUS Status
= STATUS_SUCCESS
;
310 if(PreviousMode
!= KernelMode
) {
314 ProbeForWrite(IoCompletionHandle
,
319 Status
= _SEH_GetExceptionCode();
322 if(!NT_SUCCESS(Status
)) {
328 /* Open the Object */
329 Status
= ObOpenObjectByName(ObjectAttributes
,
335 &hIoCompletionHandle
);
337 if (NT_SUCCESS(Status
)) {
341 *IoCompletionHandle
= hIoCompletionHandle
;
344 Status
= _SEH_GetExceptionCode();
355 NtQueryIoCompletion(IN HANDLE IoCompletionHandle
,
356 IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass
,
357 OUT PVOID IoCompletionInformation
,
358 IN ULONG IoCompletionInformationLength
,
359 OUT PULONG ResultLength OPTIONAL
)
362 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
363 NTSTATUS Status
= STATUS_SUCCESS
;
367 /* Check buffers and parameters */
368 DefaultQueryInfoBufferCheck(IoCompletionInformationClass
,
369 IoCompletionInfoClass
,
370 IoCompletionInformation
,
371 IoCompletionInformationLength
,
375 if(!NT_SUCCESS(Status
)) {
377 DPRINT1("NtQueryMutant() failed, Status: 0x%x\n", Status
);
382 Status
= ObReferenceObjectByHandle(IoCompletionHandle
,
383 IO_COMPLETION_QUERY_STATE
,
389 /* Check for Success */
390 if (NT_SUCCESS(Status
)) {
395 ((PIO_COMPLETION_BASIC_INFORMATION
)IoCompletionInformation
)->Depth
= KeReadStateQueue(Queue
);
396 ObDereferenceObject(Queue
);
398 /* Return Result Length if needed */
401 *ResultLength
= sizeof(IO_COMPLETION_BASIC_INFORMATION
);
405 Status
= _SEH_GetExceptionCode();
414 * Dequeues an I/O completion message from an I/O completion object
418 NtRemoveIoCompletion(IN HANDLE IoCompletionHandle
,
419 OUT PVOID
*CompletionKey
,
420 OUT PVOID
*CompletionContext
,
421 OUT PIO_STATUS_BLOCK IoStatusBlock
,
422 IN PLARGE_INTEGER Timeout OPTIONAL
)
424 LARGE_INTEGER SafeTimeout
;
426 PIO_COMPLETION_PACKET Packet
;
427 PLIST_ENTRY ListEntry
;
428 KPROCESSOR_MODE PreviousMode
= ExGetPreviousMode();
429 NTSTATUS Status
= STATUS_SUCCESS
;
433 if (PreviousMode
!= KernelMode
) {
437 ProbeForWrite(CompletionKey
,
440 ProbeForWrite(CompletionContext
,
443 ProbeForWrite(IoStatusBlock
,
444 sizeof(IO_STATUS_BLOCK
),
446 if (Timeout
!= NULL
) {
448 ProbeForRead(Timeout
,
449 sizeof(LARGE_INTEGER
),
451 SafeTimeout
= *Timeout
;
452 Timeout
= &SafeTimeout
;
456 Status
= _SEH_GetExceptionCode();
459 if (!NT_SUCCESS(Status
)) {
465 /* Open the Object */
466 Status
= ObReferenceObjectByHandle(IoCompletionHandle
,
467 IO_COMPLETION_MODIFY_STATE
,
473 /* Check for success */
474 if (NT_SUCCESS(Status
)) {
477 ListEntry
= KeRemoveQueue(Queue
, PreviousMode
, Timeout
);
479 /* If we got a timeout or user_apc back, return the status */
480 if ((NTSTATUS
)ListEntry
== STATUS_TIMEOUT
|| (NTSTATUS
)ListEntry
== STATUS_USER_APC
) {
482 Status
= (NTSTATUS
)ListEntry
;
486 /* Get the Packet Data */
487 Packet
= CONTAINING_RECORD(ListEntry
, IO_COMPLETION_PACKET
, ListEntry
);
491 /* Check if this is piggybacked on an IRP */
492 if (Packet
->PacketType
== IrpCompletionPacket
)
496 Irp
= CONTAINING_RECORD(ListEntry
, IRP
, Tail
.Overlay
.ListEntry
);
498 /* Return values to user */
499 *CompletionKey
= Irp
->Tail
.CompletionKey
;
500 *CompletionContext
= Irp
->Overlay
.AsynchronousParameters
.UserApcContext
;
501 *IoStatusBlock
= Packet
->IoStatus
;
506 /* This is a user-mode generated or API generated mini-packet */
507 *CompletionKey
= Packet
->Key
;
508 *CompletionContext
= Packet
->Context
;
509 *IoStatusBlock
= Packet
->IoStatus
;
510 IopFreeIoCompletionPacket(Packet
);
515 Status
= _SEH_GetExceptionCode();
519 ExFreeToNPagedLookasideList(&IoCompletionPacketLookaside
, Packet
);
522 /* Dereference the Object */
523 ObDereferenceObject(Queue
);
531 * Queues an I/O completion message to an I/O completion object
535 NtSetIoCompletion(IN HANDLE IoCompletionPortHandle
,
536 IN PVOID CompletionKey
,
537 IN PVOID CompletionContext
,
538 IN NTSTATUS CompletionStatus
,
539 IN ULONG CompletionInformation
)
547 Status
= ObReferenceObjectByHandle(IoCompletionPortHandle
,
548 IO_COMPLETION_MODIFY_STATE
,
554 /* Check for Success */
555 if (NT_SUCCESS(Status
)) {
557 /* Set the Completion */
558 Status
= IoSetIoCompletion(Queue
,
562 CompletionInformation
,
564 ObDereferenceObject(Queue
);