Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygeniocomp.c
Go to the documentation of this file.
00001 /* 00002 * PROJECT: ReactOS Kernel 00003 * LICENSE: GPL - See COPYING in the top level directory 00004 * FILE: ntoskrnl/io/iocomp.c 00005 * PURPOSE: I/O Wrappers (called Completion Ports) for Kernel Queues 00006 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 00007 * Thomas Weidenmueller (w3seek@reactos.org) 00008 */ 00009 00010 /* INCLUDES *****************************************************************/ 00011 00012 #include <ntoskrnl.h> 00013 #define NDEBUG 00014 #include <debug.h> 00015 00016 POBJECT_TYPE IoCompletionType; 00017 00018 GENERAL_LOOKASIDE IoCompletionPacketLookaside; 00019 00020 GENERIC_MAPPING IopCompletionMapping = 00021 { 00022 STANDARD_RIGHTS_READ | IO_COMPLETION_QUERY_STATE, 00023 STANDARD_RIGHTS_WRITE | IO_COMPLETION_MODIFY_STATE, 00024 STANDARD_RIGHTS_EXECUTE | SYNCHRONIZE | IO_COMPLETION_QUERY_STATE, 00025 IO_COMPLETION_ALL_ACCESS 00026 }; 00027 00028 static const INFORMATION_CLASS_INFO IoCompletionInfoClass[] = 00029 { 00030 /* IoCompletionBasicInformation */ 00031 ICI_SQ_SAME(sizeof(IO_COMPLETION_BASIC_INFORMATION), sizeof(ULONG), ICIF_QUERY), 00032 }; 00033 00034 /* PRIVATE FUNCTIONS *********************************************************/ 00035 00036 NTSTATUS 00037 NTAPI 00038 IopUnloadSafeCompletion(IN PDEVICE_OBJECT DeviceObject, 00039 IN PIRP Irp, 00040 IN PVOID Context) 00041 { 00042 NTSTATUS Status; 00043 PIO_UNLOAD_SAFE_COMPLETION_CONTEXT UnsafeContext = Context; 00044 00045 /* Reference the device object */ 00046 ObReferenceObject(UnsafeContext->DeviceObject); 00047 00048 /* Call the completion routine */ 00049 Status= UnsafeContext->CompletionRoutine(DeviceObject, 00050 Irp, 00051 UnsafeContext->Context); 00052 00053 /* Dereference the device object */ 00054 ObDereferenceObject(UnsafeContext->DeviceObject); 00055 00056 /* Free our context */ 00057 ExFreePool(UnsafeContext); 00058 return Status; 00059 } 00060 00061 VOID 00062 NTAPI 00063 IopFreeMiniPacket(PIOP_MINI_COMPLETION_PACKET Packet) 00064 { 00065 PKPRCB Prcb = KeGetCurrentPrcb(); 00066 PNPAGED_LOOKASIDE_LIST List; 00067 00068 /* Use the P List */ 00069 List = (PNPAGED_LOOKASIDE_LIST)Prcb-> 00070 PPLookasideList[LookasideCompletionList].P; 00071 List->L.TotalFrees++; 00072 00073 /* Check if the Free was within the Depth or not */ 00074 if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth) 00075 { 00076 /* Let the balancer know */ 00077 List->L.FreeMisses++; 00078 00079 /* Use the L List */ 00080 List = (PNPAGED_LOOKASIDE_LIST)Prcb-> 00081 PPLookasideList[LookasideCompletionList].L; 00082 List->L.TotalFrees++; 00083 00084 /* Check if the Free was within the Depth or not */ 00085 if (ExQueryDepthSList(&List->L.ListHead) >= List->L.Depth) 00086 { 00087 /* All lists failed, use the pool */ 00088 List->L.FreeMisses++; 00089 ExFreePool(Packet); 00090 return; 00091 } 00092 } 00093 00094 /* The free was within dhe Depth */ 00095 InterlockedPushEntrySList(&List->L.ListHead, (PSLIST_ENTRY)Packet); 00096 } 00097 00098 VOID 00099 NTAPI 00100 IopDeleteIoCompletion(PVOID ObjectBody) 00101 { 00102 PKQUEUE Queue = ObjectBody; 00103 PLIST_ENTRY FirstEntry; 00104 PLIST_ENTRY CurrentEntry; 00105 PIRP Irp; 00106 PIOP_MINI_COMPLETION_PACKET Packet; 00107 00108 /* Rundown the Queue */ 00109 FirstEntry = KeRundownQueue(Queue); 00110 if (FirstEntry) 00111 { 00112 /* Loop the packets */ 00113 CurrentEntry = FirstEntry; 00114 do 00115 { 00116 /* Get the Packet */ 00117 Packet = CONTAINING_RECORD(CurrentEntry, 00118 IOP_MINI_COMPLETION_PACKET, 00119 ListEntry); 00120 00121 /* Go to next Entry */ 00122 CurrentEntry = CurrentEntry->Flink; 00123 00124 /* Check if it's part of an IRP, or a separate packet */ 00125 if (Packet->PacketType == IopCompletionPacketIrp) 00126 { 00127 /* Get the IRP and free it */ 00128 Irp = CONTAINING_RECORD(Packet, IRP, Tail.Overlay.ListEntry); 00129 IoFreeIrp(Irp); 00130 } 00131 else 00132 { 00133 /* Use common routine */ 00134 IopFreeMiniPacket(Packet); 00135 } 00136 } while (FirstEntry != CurrentEntry); 00137 } 00138 } 00139 00140 /* PUBLIC FUNCTIONS **********************************************************/ 00141 00142 /* 00143 * @implemented 00144 */ 00145 NTSTATUS 00146 NTAPI 00147 IoSetIoCompletion(IN PVOID IoCompletion, 00148 IN PVOID KeyContext, 00149 IN PVOID ApcContext, 00150 IN NTSTATUS IoStatus, 00151 IN ULONG_PTR IoStatusInformation, 00152 IN BOOLEAN Quota) 00153 { 00154 PKQUEUE Queue = (PKQUEUE)IoCompletion; 00155 PNPAGED_LOOKASIDE_LIST List; 00156 PKPRCB Prcb = KeGetCurrentPrcb(); 00157 PIOP_MINI_COMPLETION_PACKET Packet; 00158 00159 /* Get the P List */ 00160 List = (PNPAGED_LOOKASIDE_LIST)Prcb-> 00161 PPLookasideList[LookasideCompletionList].P; 00162 00163 /* Try to allocate the Packet */ 00164 List->L.TotalAllocates++; 00165 Packet = (PVOID)InterlockedPopEntrySList(&List->L.ListHead); 00166 00167 /* Check if that failed, use the L list if it did */ 00168 if (!Packet) 00169 { 00170 /* Let the balancer know */ 00171 List->L.AllocateMisses++; 00172 00173 /* Get L List */ 00174 List = (PNPAGED_LOOKASIDE_LIST)Prcb-> 00175 PPLookasideList[LookasideCompletionList].L; 00176 00177 /* Try to allocate the Packet */ 00178 List->L.TotalAllocates++; 00179 Packet = (PVOID)InterlockedPopEntrySList(&List->L.ListHead); 00180 } 00181 00182 /* Still failed, use pool */ 00183 if (!Packet) 00184 { 00185 /* Let the balancer know */ 00186 List->L.AllocateMisses++; 00187 00188 /* Allocate from Nonpaged Pool */ 00189 Packet = ExAllocatePoolWithTag(NonPagedPool, sizeof(*Packet), IOC_TAG); 00190 } 00191 00192 /* Make sure we have one by now... */ 00193 if (Packet) 00194 { 00195 /* Set up the Packet */ 00196 Packet->PacketType = IopCompletionPacketMini; 00197 Packet->KeyContext = KeyContext; 00198 Packet->ApcContext = ApcContext; 00199 Packet->IoStatus = IoStatus; 00200 Packet->IoStatusInformation = IoStatusInformation; 00201 00202 /* Insert the Queue */ 00203 KeInsertQueue(Queue, &Packet->ListEntry); 00204 } 00205 else 00206 { 00207 /* Out of memory, fail */ 00208 return STATUS_INSUFFICIENT_RESOURCES; 00209 } 00210 00211 /* Return Success */ 00212 return STATUS_SUCCESS; 00213 } 00214 00215 /* 00216 * @implemented 00217 */ 00218 NTSTATUS 00219 NTAPI 00220 IoSetCompletionRoutineEx(IN PDEVICE_OBJECT DeviceObject, 00221 IN PIRP Irp, 00222 IN PIO_COMPLETION_ROUTINE CompletionRoutine, 00223 IN PVOID Context, 00224 IN BOOLEAN InvokeOnSuccess, 00225 IN BOOLEAN InvokeOnError, 00226 IN BOOLEAN InvokeOnCancel) 00227 { 00228 PIO_UNLOAD_SAFE_COMPLETION_CONTEXT UnloadContext; 00229 00230 /* Allocate the context */ 00231 UnloadContext = ExAllocatePoolWithTag(NonPagedPool, 00232 sizeof(*UnloadContext), 00233 'sUoI'); 00234 if (!UnloadContext) return STATUS_INSUFFICIENT_RESOURCES; 00235 00236 /* Set up the context */ 00237 UnloadContext->DeviceObject = DeviceObject; 00238 UnloadContext->Context = Context; 00239 UnloadContext->CompletionRoutine = CompletionRoutine; 00240 00241 /* Now set the completion routine */ 00242 IoSetCompletionRoutine(Irp, 00243 IopUnloadSafeCompletion, 00244 UnloadContext, 00245 InvokeOnSuccess, 00246 InvokeOnError, 00247 InvokeOnCancel); 00248 return STATUS_SUCCESS; 00249 } 00250 00251 NTSTATUS 00252 NTAPI 00253 NtCreateIoCompletion(OUT PHANDLE IoCompletionHandle, 00254 IN ACCESS_MASK DesiredAccess, 00255 IN POBJECT_ATTRIBUTES ObjectAttributes, 00256 IN ULONG NumberOfConcurrentThreads) 00257 { 00258 PKQUEUE Queue; 00259 HANDLE hIoCompletionHandle; 00260 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00261 NTSTATUS Status; 00262 PAGED_CODE(); 00263 00264 /* Check if this was a user-mode call */ 00265 if (PreviousMode != KernelMode) 00266 { 00267 /* Wrap probing in SEH */ 00268 _SEH2_TRY 00269 { 00270 /* Probe the handle */ 00271 ProbeForWriteHandle(IoCompletionHandle); 00272 } 00273 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00274 { 00275 /* Return the exception code */ 00276 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00277 } 00278 _SEH2_END; 00279 } 00280 00281 /* Create the Object */ 00282 Status = ObCreateObject(PreviousMode, 00283 IoCompletionType, 00284 ObjectAttributes, 00285 PreviousMode, 00286 NULL, 00287 sizeof(KQUEUE), 00288 0, 00289 0, 00290 (PVOID*)&Queue); 00291 if (NT_SUCCESS(Status)) 00292 { 00293 /* Initialize the Queue */ 00294 KeInitializeQueue(Queue, NumberOfConcurrentThreads); 00295 00296 /* Insert it */ 00297 Status = ObInsertObject(Queue, 00298 NULL, 00299 DesiredAccess, 00300 0, 00301 NULL, 00302 &hIoCompletionHandle); 00303 if (NT_SUCCESS(Status)) 00304 { 00305 /* Protect writing the handle in SEH */ 00306 _SEH2_TRY 00307 { 00308 /* Write the handle back */ 00309 *IoCompletionHandle = hIoCompletionHandle; 00310 } 00311 _SEH2_EXCEPT(ExSystemExceptionFilter()) 00312 { 00313 /* Get the exception code */ 00314 Status = _SEH2_GetExceptionCode(); 00315 } 00316 _SEH2_END; 00317 } 00318 } 00319 00320 /* Return Status */ 00321 return Status; 00322 } 00323 00324 NTSTATUS 00325 NTAPI 00326 NtOpenIoCompletion(OUT PHANDLE IoCompletionHandle, 00327 IN ACCESS_MASK DesiredAccess, 00328 IN POBJECT_ATTRIBUTES ObjectAttributes) 00329 { 00330 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00331 HANDLE hIoCompletionHandle; 00332 NTSTATUS Status; 00333 PAGED_CODE(); 00334 00335 /* Check if this was a user-mode call */ 00336 if (PreviousMode != KernelMode) 00337 { 00338 /* Wrap probing in SEH */ 00339 _SEH2_TRY 00340 { 00341 /* Probe the handle */ 00342 ProbeForWriteHandle(IoCompletionHandle); 00343 } 00344 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00345 { 00346 /* Return the exception code */ 00347 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00348 } 00349 _SEH2_END; 00350 } 00351 00352 /* Open the Object */ 00353 Status = ObOpenObjectByName(ObjectAttributes, 00354 IoCompletionType, 00355 PreviousMode, 00356 NULL, 00357 DesiredAccess, 00358 NULL, 00359 &hIoCompletionHandle); 00360 if (NT_SUCCESS(Status)) 00361 { 00362 /* Protect writing the handle in SEH */ 00363 _SEH2_TRY 00364 { 00365 /* Write the handle back */ 00366 *IoCompletionHandle = hIoCompletionHandle; 00367 } 00368 _SEH2_EXCEPT(ExSystemExceptionFilter()) 00369 { 00370 /* Get the exception code */ 00371 Status = _SEH2_GetExceptionCode(); 00372 } 00373 _SEH2_END; 00374 } 00375 00376 /* Return Status */ 00377 return Status; 00378 } 00379 00380 NTSTATUS 00381 NTAPI 00382 NtQueryIoCompletion(IN HANDLE IoCompletionHandle, 00383 IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass, 00384 OUT PVOID IoCompletionInformation, 00385 IN ULONG IoCompletionInformationLength, 00386 OUT PULONG ResultLength OPTIONAL) 00387 { 00388 PKQUEUE Queue; 00389 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00390 NTSTATUS Status; 00391 PAGED_CODE(); 00392 00393 /* Check buffers and parameters */ 00394 Status = DefaultQueryInfoBufferCheck(IoCompletionInformationClass, 00395 IoCompletionInfoClass, 00396 sizeof(IoCompletionInfoClass) / 00397 sizeof(IoCompletionInfoClass[0]), 00398 IoCompletionInformation, 00399 IoCompletionInformationLength, 00400 ResultLength, 00401 NULL, 00402 PreviousMode); 00403 if (!NT_SUCCESS(Status)) return Status; 00404 00405 /* Get the Object */ 00406 Status = ObReferenceObjectByHandle(IoCompletionHandle, 00407 IO_COMPLETION_QUERY_STATE, 00408 IoCompletionType, 00409 PreviousMode, 00410 (PVOID*)&Queue, 00411 NULL); 00412 if (NT_SUCCESS(Status)) 00413 { 00414 /* Protect write in SEH */ 00415 _SEH2_TRY 00416 { 00417 /* Return Info */ 00418 ((PIO_COMPLETION_BASIC_INFORMATION)IoCompletionInformation)-> 00419 Depth = KeReadStateQueue(Queue); 00420 00421 /* Return Result Length if needed */ 00422 if (ResultLength) 00423 { 00424 *ResultLength = sizeof(IO_COMPLETION_BASIC_INFORMATION); 00425 } 00426 } 00427 _SEH2_EXCEPT(ExSystemExceptionFilter()) 00428 { 00429 /* Get exception code */ 00430 Status = _SEH2_GetExceptionCode(); 00431 } 00432 _SEH2_END; 00433 00434 /* Dereference the queue */ 00435 ObDereferenceObject(Queue); 00436 } 00437 00438 /* Return Status */ 00439 return Status; 00440 } 00441 00442 NTSTATUS 00443 NTAPI 00444 NtRemoveIoCompletion(IN HANDLE IoCompletionHandle, 00445 OUT PVOID *KeyContext, 00446 OUT PVOID *ApcContext, 00447 OUT PIO_STATUS_BLOCK IoStatusBlock, 00448 IN PLARGE_INTEGER Timeout OPTIONAL) 00449 { 00450 LARGE_INTEGER SafeTimeout; 00451 PKQUEUE Queue; 00452 PIOP_MINI_COMPLETION_PACKET Packet; 00453 PLIST_ENTRY ListEntry; 00454 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode(); 00455 NTSTATUS Status; 00456 PIRP Irp; 00457 PVOID Apc, Key; 00458 IO_STATUS_BLOCK IoStatus; 00459 PAGED_CODE(); 00460 00461 /* Check if the call was from user mode */ 00462 if (PreviousMode != KernelMode) 00463 { 00464 /* Protect probes in SEH */ 00465 _SEH2_TRY 00466 { 00467 /* Probe the pointers */ 00468 ProbeForWritePointer(KeyContext); 00469 ProbeForWritePointer(ApcContext); 00470 00471 /* Probe the I/O Status Block */ 00472 ProbeForWriteIoStatusBlock(IoStatusBlock); 00473 if (Timeout) 00474 { 00475 /* Probe and capture the timeout */ 00476 SafeTimeout = ProbeForReadLargeInteger(Timeout); 00477 Timeout = &SafeTimeout; 00478 } 00479 } 00480 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 00481 { 00482 /* Return the exception code */ 00483 _SEH2_YIELD(return _SEH2_GetExceptionCode()); 00484 } 00485 _SEH2_END; 00486 } 00487 00488 /* Open the Object */ 00489 Status = ObReferenceObjectByHandle(IoCompletionHandle, 00490 IO_COMPLETION_MODIFY_STATE, 00491 IoCompletionType, 00492 PreviousMode, 00493 (PVOID*)&Queue, 00494 NULL); 00495 if (NT_SUCCESS(Status)) 00496 { 00497 /* Remove queue */ 00498 ListEntry = KeRemoveQueue(Queue, PreviousMode, Timeout); 00499 00500 /* If we got a timeout or user_apc back, return the status */ 00501 if (((NTSTATUS)(ULONG_PTR)ListEntry == STATUS_TIMEOUT) || 00502 ((NTSTATUS)(ULONG_PTR)ListEntry == STATUS_USER_APC)) 00503 { 00504 /* Set this as the status */ 00505 Status = (NTSTATUS)(ULONG_PTR)ListEntry; 00506 } 00507 else 00508 { 00509 /* Get the Packet Data */ 00510 Packet = CONTAINING_RECORD(ListEntry, 00511 IOP_MINI_COMPLETION_PACKET, 00512 ListEntry); 00513 00514 /* Check if this is piggybacked on an IRP */ 00515 if (Packet->PacketType == IopCompletionPacketIrp) 00516 { 00517 /* Get the IRP */ 00518 Irp = CONTAINING_RECORD(ListEntry, 00519 IRP, 00520 Tail.Overlay.ListEntry); 00521 00522 /* Save values */ 00523 Key = Irp->Tail.CompletionKey; 00524 Apc = Irp->Overlay.AsynchronousParameters.UserApcContext; 00525 IoStatus = Irp->IoStatus; 00526 00527 /* Free the IRP */ 00528 IoFreeIrp(Irp); 00529 } 00530 else 00531 { 00532 /* Save values */ 00533 Key = Packet->KeyContext; 00534 Apc = Packet->ApcContext; 00535 IoStatus.Status = Packet->IoStatus; 00536 IoStatus.Information = Packet->IoStatusInformation; 00537 00538 /* Free the packet */ 00539 IopFreeMiniPacket(Packet); 00540 } 00541 00542 /* Enter SEH to write back the values */ 00543 _SEH2_TRY 00544 { 00545 /* Write the values to caller */ 00546 *ApcContext = Apc; 00547 *KeyContext = Key; 00548 *IoStatusBlock = IoStatus; 00549 } 00550 _SEH2_EXCEPT(ExSystemExceptionFilter()) 00551 { 00552 /* Get the exception code */ 00553 Status = _SEH2_GetExceptionCode(); 00554 } 00555 _SEH2_END; 00556 } 00557 00558 /* Dereference the Object */ 00559 ObDereferenceObject(Queue); 00560 } 00561 00562 /* Return status */ 00563 return Status; 00564 } 00565 00566 NTSTATUS 00567 NTAPI 00568 NtSetIoCompletion(IN HANDLE IoCompletionPortHandle, 00569 IN PVOID CompletionKey, 00570 IN PVOID CompletionContext, 00571 IN NTSTATUS CompletionStatus, 00572 IN ULONG CompletionInformation) 00573 { 00574 NTSTATUS Status; 00575 PKQUEUE Queue; 00576 PAGED_CODE(); 00577 00578 /* Get the Object */ 00579 Status = ObReferenceObjectByHandle(IoCompletionPortHandle, 00580 IO_COMPLETION_MODIFY_STATE, 00581 IoCompletionType, 00582 ExGetPreviousMode(), 00583 (PVOID*)&Queue, 00584 NULL); 00585 if (NT_SUCCESS(Status)) 00586 { 00587 /* Set the Completion */ 00588 Status = IoSetIoCompletion(Queue, 00589 CompletionKey, 00590 CompletionContext, 00591 CompletionStatus, 00592 CompletionInformation, 00593 TRUE); 00594 00595 /* Dereference the object */ 00596 ObDereferenceObject(Queue); 00597 } 00598 00599 /* Return status */ 00600 return Status; 00601 } Generated on Sun May 27 2012 04:37:16 for ReactOS by
1.7.6.1
|