Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

complete.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1994 Microsoft Corporation 00004 00005 Module Name: 00006 00007 complete.c 00008 00009 Abstract: 00010 00011 This module implements the executive I/O completion object. Functions are 00012 provided to create, open, query, and wait for I/O completion objects. 00013 00014 Author: 00015 00016 David N. Cutler (davec) 25-Feb-1994 00017 00018 Environment: 00019 00020 Kernel mode only. 00021 00022 Revision History: 00023 00024 --*/ 00025 00026 #include "iop.h" 00027 00028 // 00029 // Define forward referenced function prototypes. 00030 // 00031 00032 VOID 00033 IopFreeMiniPacket ( 00034 PIOP_MINI_COMPLETION_PACKET MiniPacket 00035 ); 00036 00037 // 00038 // Define section types for appropriate functions. 00039 // 00040 00041 #ifdef ALLOC_PRAGMA 00042 #pragma alloc_text(PAGE, NtCreateIoCompletion) 00043 #pragma alloc_text(PAGE, NtOpenIoCompletion) 00044 #pragma alloc_text(PAGE, NtQueryIoCompletion) 00045 #pragma alloc_text(PAGE, NtRemoveIoCompletion) 00046 #pragma alloc_text(PAGE, NtSetIoCompletion) 00047 #pragma alloc_text(PAGE, IoSetIoCompletion) 00048 #endif 00049 00050 NTSTATUS 00051 NtCreateIoCompletion ( 00052 IN PHANDLE IoCompletionHandle, 00053 IN ACCESS_MASK DesiredAccess, 00054 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 00055 IN ULONG Count OPTIONAL 00056 ) 00057 00058 /*++ 00059 00060 Routine Description: 00061 00062 This function creates an I/O completion object, sets the maximum 00063 target concurrent thread count to the specified value, and opens 00064 a handle to the object with the specified desired access. 00065 00066 Arguments: 00067 00068 IoCompletionHandle - Supplies a pointer to a variable that receives 00069 the I/O completion object handle. 00070 00071 DesiredAccess - Supplies the desired types of access for the I/O 00072 completion object. 00073 00074 ObjectAttributes - Supplies a pointer to an object attributes structure. 00075 00076 Count - Supplies the target maximum number of threads that should 00077 be concurrently active. If this parameter is not specified, then 00078 the number of processors is used. 00079 00080 Return Value: 00081 00082 STATUS_SUCCESS is returned if the function is success. Otherwise, an 00083 error status is returned. 00084 00085 --*/ 00086 00087 { 00088 00089 HANDLE Handle; 00090 KPROCESSOR_MODE PreviousMode; 00091 PVOID IoCompletion; 00092 NTSTATUS Status; 00093 00094 // 00095 // Establish an exception handler, probe the output handle address, and 00096 // attempt to create an I/O completion object. If the probe fails, then 00097 // return the exception code as the service status. Otherwise, return the 00098 // status value returned by the object insertion routine. 00099 // 00100 00101 try { 00102 00103 // 00104 // Get previous processor mode and probe output handle address if 00105 // necessary. 00106 // 00107 00108 PreviousMode = KeGetPreviousMode(); 00109 if (PreviousMode != KernelMode) { 00110 ProbeForWriteHandle(IoCompletionHandle); 00111 } 00112 00113 // 00114 // Allocate I/O completion object. 00115 // 00116 00117 Status = ObCreateObject(PreviousMode, 00118 IoCompletionObjectType, 00119 ObjectAttributes, 00120 PreviousMode, 00121 NULL, 00122 sizeof(KQUEUE), 00123 0, 00124 0, 00125 (PVOID *)&IoCompletion); 00126 00127 // 00128 // If the I/O completion object was successfully allocated, then 00129 // initialize the object and attempt to insert it in the handle 00130 // table of the current process. 00131 // 00132 00133 if (NT_SUCCESS(Status)) { 00134 KeInitializeQueue((PKQUEUE)IoCompletion, Count); 00135 Status = ObInsertObject(IoCompletion, 00136 NULL, 00137 DesiredAccess, 00138 0, 00139 (PVOID *)NULL, 00140 &Handle); 00141 00142 // 00143 // If the I/O completion object was successfully inserted in 00144 // the handle table of the current process, then attempt to 00145 // write the handle value. If the write attempt fails, then 00146 // do not report an error. When the caller attempts to access 00147 // the handle value, an access violation will occur. 00148 // 00149 00150 if (NT_SUCCESS(Status)) { 00151 try { 00152 *IoCompletionHandle = Handle; 00153 00154 } except(ExSystemExceptionFilter()) { 00155 NOTHING; 00156 } 00157 } 00158 } 00159 00160 // 00161 // If an exception occurs during the probe of the output handle address, 00162 // then always handle the exception and return the exception code as the 00163 // status value. 00164 // 00165 00166 } except(ExSystemExceptionFilter()) { 00167 Status = GetExceptionCode(); 00168 } 00169 00170 // 00171 // Return service status. 00172 // 00173 00174 return Status; 00175 } 00176 00177 NTSTATUS 00178 NtOpenIoCompletion ( 00179 OUT PHANDLE IoCompletionHandle, 00180 IN ACCESS_MASK DesiredAccess, 00181 IN POBJECT_ATTRIBUTES ObjectAttributes 00182 ) 00183 00184 /*++ 00185 00186 Routine Description: 00187 00188 This function opens a handle to an I/O completion object with the 00189 specified desired access. 00190 00191 Arguments: 00192 00193 IoCompletionHandle - Supplies a pointer to a variable that receives 00194 the completion object handle. 00195 00196 DesiredAccess - Supplies the desired types of access for the I/O 00197 completion object. 00198 00199 ObjectAttributes - Supplies a pointer to an object attributes structure. 00200 00201 Return Value: 00202 00203 STATUS_SUCCESS is returned if the function is success. Otherwise, an 00204 error status is returned. 00205 00206 --*/ 00207 00208 { 00209 00210 HANDLE Handle; 00211 KPROCESSOR_MODE PreviousMode; 00212 NTSTATUS Status; 00213 00214 // 00215 // Establish an exception handler, probe the output handle address, 00216 // and attempt to open an I/O completion object. If the probe fails, 00217 // then return the exception code as the service status. Otherwise, 00218 // return the status value returned by the object open routine. 00219 // 00220 00221 try { 00222 00223 // 00224 // Get previous processor mode and probe output handle address if 00225 // necessary. 00226 // 00227 00228 PreviousMode = KeGetPreviousMode(); 00229 if (PreviousMode != KernelMode) { 00230 ProbeForWriteHandle(IoCompletionHandle); 00231 } 00232 00233 // 00234 // Open handle to the completion object with the specified desired 00235 // access. 00236 // 00237 00238 Status = ObOpenObjectByName(ObjectAttributes, 00239 IoCompletionObjectType, 00240 PreviousMode, 00241 NULL, 00242 DesiredAccess, 00243 NULL, 00244 &Handle); 00245 00246 // 00247 // If the open was successful, then attempt to write the I/O 00248 // completion object handle value. If the write attempt fails, 00249 // then do not report an error. When the caller attempts to 00250 // access the handle value, an access violation will occur. 00251 // 00252 00253 if (NT_SUCCESS(Status)) { 00254 try { 00255 *IoCompletionHandle = Handle; 00256 00257 } except(ExSystemExceptionFilter()) { 00258 NOTHING; 00259 } 00260 } 00261 00262 // 00263 // If an exception occurs during the probe of the output handle address, 00264 // then always handle the exception and return the exception code as the 00265 // status value. 00266 // 00267 00268 } except(ExSystemExceptionFilter()) { 00269 Status = GetExceptionCode(); 00270 } 00271 00272 00273 // 00274 // Return service status. 00275 // 00276 00277 return Status; 00278 } 00279 00280 00281 NTSTATUS 00282 NtQueryIoCompletion ( 00283 IN HANDLE IoCompletionHandle, 00284 IN IO_COMPLETION_INFORMATION_CLASS IoCompletionInformationClass, 00285 OUT PVOID IoCompletionInformation, 00286 IN ULONG IoCompletionInformationLength, 00287 OUT PULONG ReturnLength OPTIONAL 00288 ) 00289 00290 /*++ 00291 00292 Routine Description: 00293 00294 This function queries the state of an I/O completion object and returns 00295 the requested information in the specified record structure. 00296 00297 Arguments: 00298 00299 IoCompletionHandle - Supplies a handle to an I/O completion object. 00300 00301 IoCompletionInformationClass - Supplies the class of information being 00302 requested. 00303 00304 IoCompletionInformation - Supplies a pointer to a record that receives 00305 the requested information. 00306 00307 IoCompletionInformationLength - Supplies the length of the record that 00308 receives the requested information. 00309 00310 ReturnLength - Supplies an optional pointer to a variable that receives 00311 the actual length of the information that is returned. 00312 00313 Return Value: 00314 00315 STATUS_SUCCESS is returned if the function is success. Otherwise, an 00316 error status is returned. 00317 00318 --*/ 00319 00320 { 00321 00322 PVOID IoCompletion; 00323 LONG Depth; 00324 KPROCESSOR_MODE PreviousMode; 00325 NTSTATUS Status; 00326 00327 // 00328 // Establish an exception handler, probe the output arguments, reference 00329 // the I/O completion object, and return the specified information. If 00330 // the probe fails, then return the exception code as the service status. 00331 // Otherwise return the status value returned by the reference object by 00332 // handle routine. 00333 // 00334 00335 try { 00336 00337 // 00338 // Get previous processor mode and probe output arguments if necessary. 00339 // 00340 00341 PreviousMode = KeGetPreviousMode(); 00342 if (PreviousMode != KernelMode) { 00343 ProbeForWrite(IoCompletionInformation, 00344 sizeof(IO_COMPLETION_BASIC_INFORMATION), 00345 sizeof(ULONG)); 00346 00347 if (ARGUMENT_PRESENT(ReturnLength)) { 00348 ProbeForWriteUlong(ReturnLength); 00349 } 00350 } 00351 00352 // 00353 // Check argument validity. 00354 // 00355 00356 if (IoCompletionInformationClass != IoCompletionBasicInformation) { 00357 return STATUS_INVALID_INFO_CLASS; 00358 } 00359 00360 if (IoCompletionInformationLength != sizeof(IO_COMPLETION_BASIC_INFORMATION)) { 00361 return STATUS_INFO_LENGTH_MISMATCH; 00362 } 00363 00364 // 00365 // Reference the I/O completion object by handle. 00366 // 00367 00368 Status = ObReferenceObjectByHandle(IoCompletionHandle, 00369 IO_COMPLETION_QUERY_STATE, 00370 IoCompletionObjectType, 00371 PreviousMode, 00372 &IoCompletion, 00373 NULL); 00374 00375 // 00376 // If the reference was successful, then read the current state of 00377 // the I/O completion object, dereference the I/O completion object, 00378 // fill in the information structure, and return the structure length 00379 // if specified. If the write of the I/O completion information or 00380 // the return length fails, then do not report an error. When the 00381 // caller accesses the information structure or length an access 00382 // violation will occur. 00383 // 00384 00385 if (NT_SUCCESS(Status)) { 00386 Depth = KeReadStateQueue((PKQUEUE)IoCompletion); 00387 ObDereferenceObject(IoCompletion); 00388 try { 00389 ((PIO_COMPLETION_BASIC_INFORMATION)IoCompletionInformation)->Depth = Depth; 00390 if (ARGUMENT_PRESENT(ReturnLength)) { 00391 *ReturnLength = sizeof(IO_COMPLETION_BASIC_INFORMATION); 00392 } 00393 00394 } except(ExSystemExceptionFilter()) { 00395 NOTHING; 00396 } 00397 } 00398 00399 // 00400 // If an exception occurs during the probe of the output arguments, then 00401 // always handle the exception and return the exception code as the status 00402 // value. 00403 // 00404 00405 } except(ExSystemExceptionFilter()) { 00406 Status = GetExceptionCode(); 00407 } 00408 00409 // 00410 // Return service status. 00411 // 00412 00413 return Status; 00414 } 00415 00416 NTSTATUS 00417 NtSetIoCompletion ( 00418 IN HANDLE IoCompletionHandle, 00419 IN PVOID KeyContext, 00420 IN PVOID ApcContext, 00421 IN NTSTATUS IoStatus, 00422 IN ULONG_PTR IoStatusInformation 00423 ) 00424 /*++ 00425 00426 Routine Description: 00427 00428 This function allows the caller to queue an Irp to an I/O completion 00429 port and specify all of the information that is returned out the other 00430 end using NtRemoveIoCompletion. 00431 00432 Arguments: 00433 00434 IoCompletionHandle - Supplies a handle to the io completion port 00435 that the caller intends to queue a completion packet to 00436 00437 KeyContext - Supplies the key context that is returned during a call 00438 to NtRemoveIoCompletion 00439 00440 ApcContext - Supplies the apc context that is returned during a call 00441 to NtRemoveIoCompletion 00442 00443 IoStatus - Supplies the IoStatus->Status data that is returned during 00444 a call to NtRemoveIoCompletion 00445 00446 IoStatusInformation - Supplies the IoStatus->Information data that 00447 is returned during a call to NtRemoveIoCompletion 00448 00449 Return Value: 00450 00451 STATUS_SUCCESS is returned if the function is success. Otherwise, an 00452 error status is returned. 00453 00454 --*/ 00455 00456 { 00457 PVOID IoCompletion; 00458 PIOP_MINI_COMPLETION_PACKET MiniPacket; 00459 NTSTATUS Status; 00460 00461 PAGED_CODE(); 00462 00463 Status = ObReferenceObjectByHandle(IoCompletionHandle, 00464 IO_COMPLETION_MODIFY_STATE, 00465 IoCompletionObjectType, 00466 KeGetPreviousMode(), 00467 &IoCompletion, 00468 NULL); 00469 00470 if (NT_SUCCESS(Status)) { 00471 Status = IoSetIoCompletion(IoCompletion, 00472 KeyContext, 00473 ApcContext, 00474 IoStatus, 00475 IoStatusInformation, 00476 TRUE); 00477 00478 ObDereferenceObject(IoCompletion); 00479 } 00480 return Status; 00481 00482 } 00483 00484 NTSTATUS 00485 NtRemoveIoCompletion ( 00486 IN HANDLE IoCompletionHandle, 00487 OUT PVOID *KeyContext, 00488 OUT PVOID *ApcContext, 00489 OUT PIO_STATUS_BLOCK IoStatusBlock, 00490 IN PLARGE_INTEGER Timeout OPTIONAL 00491 ) 00492 00493 /*++ 00494 00495 Routine Description: 00496 00497 This function removes an entry from an I/O completion object. If there 00498 are currently no entries available, then the calling thread waits for 00499 an entry. 00500 00501 Arguments: 00502 00503 Completion - Supplies a handle to an I/O completion object. 00504 00505 KeyContext - Supplies a pointer to a variable that receives the key 00506 context that was specified when the I/O completion object was 00507 assoicated with a file object. 00508 00509 ApcContext - Supplies a pointer to a variable that receives the 00510 context that was specified when the I/O operation was issued. 00511 00512 IoStatus - Supplies a pointer to a variable that receives the 00513 I/O completion status. 00514 00515 Timeout - Supplies a pointer to an optional time out value. 00516 00517 Return Value: 00518 00519 STATUS_SUCCESS is returned if the function is success. Otherwise, an 00520 error status is returned. 00521 00522 --*/ 00523 00524 { 00525 00526 PLARGE_INTEGER CapturedTimeout; 00527 PLIST_ENTRY Entry; 00528 PVOID IoCompletion; 00529 PIRP Irp; 00530 KPROCESSOR_MODE PreviousMode; 00531 NTSTATUS Status; 00532 LARGE_INTEGER TimeoutValue; 00533 PVOID LocalApcContext; 00534 PVOID LocalKeyContext; 00535 IO_STATUS_BLOCK LocalIoStatusBlock; 00536 PIOP_MINI_COMPLETION_PACKET MiniPacket; 00537 00538 // 00539 // Establish an exception handler, probe the I/O context, the I/O 00540 // status, and the optional timeout value if specified, reference 00541 // the I/O completion object, and attempt to remove an entry from 00542 // the I/O completion object. If the probe fails, then return the 00543 // exception code as the service status. Otherwise, return a value 00544 // dependent on the outcome of the queue removal. 00545 // 00546 00547 try { 00548 00549 // 00550 // Get previous processor mode and probe the I/O context, status, 00551 // and timeout if necessary. 00552 // 00553 00554 CapturedTimeout = NULL; 00555 PreviousMode = KeGetPreviousMode(); 00556 if (PreviousMode != KernelMode) { 00557 ProbeForWriteUlong_ptr((PULONG_PTR)ApcContext); 00558 ProbeForWriteUlong_ptr((PULONG_PTR)KeyContext); 00559 ProbeForWriteIoStatus(IoStatusBlock); 00560 if (ARGUMENT_PRESENT(Timeout)) { 00561 CapturedTimeout = &TimeoutValue; 00562 TimeoutValue = ProbeAndReadLargeInteger(Timeout); 00563 } 00564 00565 } else{ 00566 if (ARGUMENT_PRESENT(Timeout)) { 00567 CapturedTimeout = Timeout; 00568 } 00569 } 00570 00571 // 00572 // Reference the I/O completion object by handle. 00573 // 00574 00575 Status = ObReferenceObjectByHandle(IoCompletionHandle, 00576 IO_COMPLETION_MODIFY_STATE, 00577 IoCompletionObjectType, 00578 PreviousMode, 00579 &IoCompletion, 00580 NULL); 00581 00582 // 00583 // If the reference was successful, then attempt to remove an entry 00584 // from the I/O completion object. If an entry is removed from the 00585 // I/O completion object, then capture the completion information, 00586 // release the associated IRP, and attempt to write the completion 00587 // inforamtion. If the write of the completion infomation fails, 00588 // then do not report an error. When the caller attempts to access 00589 // the completion information, an access violation will occur. 00590 // 00591 00592 if (NT_SUCCESS(Status)) { 00593 Entry = KeRemoveQueue((PKQUEUE)IoCompletion, 00594 PreviousMode, 00595 CapturedTimeout); 00596 00597 // 00598 // N.B. The entry value returned can be the address of a list 00599 // entry, STATUS_USER_APC, or STATUS_TIMEOUT. 00600 // 00601 00602 if (((LONG_PTR)Entry == STATUS_TIMEOUT) || 00603 ((LONG_PTR)Entry == STATUS_USER_APC)) { 00604 Status = (NTSTATUS)((LONG_PTR)Entry); 00605 00606 } else { 00607 00608 // 00609 // Set the completion status, capture the completion 00610 // information, deallocate the associated IRP, and 00611 // attempt to write the completion information. 00612 // 00613 00614 Status = STATUS_SUCCESS; 00615 try { 00616 MiniPacket = CONTAINING_RECORD(Entry, 00617 IOP_MINI_COMPLETION_PACKET, 00618 ListEntry); 00619 00620 if ( MiniPacket->PacketType == IopCompletionPacketIrp ) { 00621 Irp = CONTAINING_RECORD(Entry, IRP, Tail.Overlay.ListEntry); 00622 LocalApcContext = Irp->Overlay.AsynchronousParameters.UserApcContext; 00623 LocalKeyContext = (PVOID)Irp->Tail.CompletionKey; 00624 LocalIoStatusBlock = Irp->IoStatus; 00625 IoFreeIrp(Irp); 00626 00627 } else { 00628 00629 LocalApcContext = MiniPacket->ApcContext; 00630 LocalKeyContext = (PVOID)MiniPacket->KeyContext; 00631 LocalIoStatusBlock.Status = MiniPacket->IoStatus; 00632 LocalIoStatusBlock.Information = MiniPacket->IoStatusInformation; 00633 IopFreeMiniPacket(MiniPacket); 00634 } 00635 00636 *ApcContext = LocalApcContext; 00637 *KeyContext = LocalKeyContext; 00638 *IoStatusBlock = LocalIoStatusBlock; 00639 00640 } except(ExSystemExceptionFilter()) { 00641 NOTHING; 00642 } 00643 } 00644 00645 // 00646 // Deference I/O completion object. 00647 // 00648 00649 ObDereferenceObject(IoCompletion); 00650 } 00651 00652 // 00653 // If an exception occurs during the probe of the previous count, then 00654 // always handle the exception and return the exception code as the status 00655 // value. 00656 // 00657 00658 } except(ExSystemExceptionFilter()) { 00659 Status = GetExceptionCode(); 00660 } 00661 00662 // 00663 // Return service status. 00664 // 00665 00666 return Status; 00667 } 00668 00669 NTKERNELAPI 00670 NTSTATUS 00671 IoSetIoCompletion ( 00672 IN PVOID IoCompletion, 00673 IN PVOID KeyContext, 00674 IN PVOID ApcContext, 00675 IN NTSTATUS IoStatus, 00676 IN ULONG_PTR IoStatusInformation, 00677 IN BOOLEAN Quota 00678 ) 00679 /*++ 00680 00681 Routine Description: 00682 00683 This function allows the caller to queue an Irp to an I/O completion 00684 port and specify all of the information that is returned out the other 00685 end using NtRemoveIoCompletion. 00686 00687 Arguments: 00688 00689 IoCompletion - Supplies a a pointer to the completion port that the caller 00690 intends to queue a completion packet to. 00691 00692 KeyContext - Supplies the key context that is returned during a call 00693 to NtRemoveIoCompletion. 00694 00695 ApcContext - Supplies the apc context that is returned during a call 00696 to NtRemoveIoCompletion. 00697 00698 IoStatus - Supplies the IoStatus->Status data that is returned during 00699 a call to NtRemoveIoCompletion. 00700 00701 IoStatusInformation - Supplies the IoStatus->Information data that 00702 is returned during a call to NtRemoveIoCompletion. 00703 00704 Return Value: 00705 00706 STATUS_SUCCESS is returned if the function is success. Otherwise, an 00707 error status is returned. 00708 00709 --*/ 00710 00711 { 00712 00713 PNPAGED_LOOKASIDE_LIST Lookaside; 00714 PIOP_MINI_COMPLETION_PACKET MiniPacket; 00715 ULONG PacketType; 00716 PKPRCB Prcb; 00717 NTSTATUS Status = STATUS_SUCCESS; 00718 00719 PAGED_CODE(); 00720 00721 // 00722 // Attempt to allocate the minpacket from the per processor lookaside list. 00723 // 00724 00725 PacketType = IopCompletionPacketMini; 00726 Prcb = KeGetCurrentPrcb(); 00727 Lookaside = Prcb->PPLookasideList[LookasideCompletionList].P; 00728 Lookaside->L.TotalAllocates += 1; 00729 MiniPacket = (PVOID)ExInterlockedPopEntrySList(&Lookaside->L.ListHead, 00730 &Lookaside->Lock); 00731 00732 // 00733 // If the per processor lookaside list allocation failed, then attempt to 00734 // allocate from the system lookaside list. 00735 // 00736 00737 if (MiniPacket == NULL) { 00738 Lookaside->L.AllocateMisses += 1; 00739 Lookaside = Prcb->PPLookasideList[LookasideCompletionList].L; 00740 Lookaside->L.TotalAllocates += 1; 00741 MiniPacket = (PVOID)ExInterlockedPopEntrySList(&Lookaside->L.ListHead, 00742 &Lookaside->Lock); 00743 } 00744 00745 // 00746 // If both lookaside allocation attempts failed, then attempt to allocate 00747 // from pool. 00748 // 00749 00750 if (MiniPacket == NULL) { 00751 Lookaside->L.AllocateMisses += 1; 00752 00753 // 00754 // If quota is specified, then allocate pool with quota charged. 00755 // Otherwise, allocate pool without quota. 00756 // 00757 00758 if (Quota != FALSE) { 00759 PacketType = IopCompletionPacketQuota; 00760 try { 00761 MiniPacket = ExAllocatePoolWithQuotaTag(NonPagedPool, 00762 sizeof(*MiniPacket), 00763 ' pcI'); 00764 00765 } except(EXCEPTION_EXECUTE_HANDLER) { 00766 NOTHING; 00767 } 00768 00769 } else { 00770 MiniPacket = ExAllocatePoolWithTag(NonPagedPool, 00771 sizeof(*MiniPacket), 00772 ' pcI'); 00773 } 00774 } 00775 00776 // 00777 // If a minipacket was successfully allocated, then initialize and 00778 // queue the packet to the specified I/O completion queue. 00779 // 00780 00781 if (MiniPacket != NULL) { 00782 MiniPacket->PacketType = PacketType; 00783 MiniPacket->KeyContext = KeyContext; 00784 MiniPacket->ApcContext = ApcContext; 00785 MiniPacket->IoStatus = IoStatus; 00786 MiniPacket->IoStatusInformation = IoStatusInformation; 00787 KeInsertQueue((PKQUEUE)IoCompletion, &MiniPacket->ListEntry); 00788 00789 } else { 00790 Status = STATUS_INSUFFICIENT_RESOURCES; 00791 } 00792 00793 return Status; 00794 } 00795 00796 VOID 00797 IopFreeMiniPacket ( 00798 PIOP_MINI_COMPLETION_PACKET MiniPacket 00799 ) 00800 00801 /*++ 00802 00803 Routine Description: 00804 00805 This function free the specefied I/O completion packet. 00806 00807 Arguments: 00808 00809 MiniPacket - Supplies a pointer to an I/O completion minipacket. 00810 00811 Return Value: 00812 00813 None. 00814 00815 --*/ 00816 00817 { 00818 00819 PNPAGED_LOOKASIDE_LIST Lookaside; 00820 PKPRCB Prcb; 00821 00822 // 00823 // If the minipacket cannot be returned to either the per processor or 00824 // system lookaside list, then free the minipacket to pool. Otherwise, 00825 // release the quota if quota was allocated and push the entry onto 00826 // one of the lookaside lists. 00827 // 00828 00829 Prcb = KeGetCurrentPrcb(); 00830 Lookaside = Prcb->PPLookasideList[LookasideCompletionList].P; 00831 Lookaside->L.TotalFrees += 1; 00832 if (ExQueryDepthSList(&Lookaside->L.ListHead) >= Lookaside->L.Depth) { 00833 Lookaside->L.FreeMisses += 1; 00834 Lookaside = Prcb->PPLookasideList[LookasideCompletionList].L; 00835 Lookaside->L.TotalFrees += 1; 00836 if (ExQueryDepthSList(&Lookaside->L.ListHead) >= Lookaside->L.Depth) { 00837 Lookaside->L.FreeMisses += 1; 00838 ExFreePool(MiniPacket); 00839 00840 } else { 00841 if (MiniPacket->PacketType == IopCompletionPacketQuota) { 00842 ExReturnPoolQuota(MiniPacket); 00843 } 00844 00845 ExInterlockedPushEntrySList(&Lookaside->L.ListHead, 00846 (PSINGLE_LIST_ENTRY)MiniPacket, 00847 &Lookaside->Lock); 00848 } 00849 00850 } else { 00851 if (MiniPacket->PacketType == IopCompletionPacketQuota) { 00852 ExReturnPoolQuota(MiniPacket); 00853 } 00854 00855 ExInterlockedPushEntrySList(&Lookaside->L.ListHead, 00856 (PSINGLE_LIST_ENTRY)MiniPacket, 00857 &Lookaside->Lock); 00858 } 00859 00860 return; 00861 } 00862 00863 VOID 00864 IopDeleteIoCompletion ( 00865 IN PVOID Object 00866 ) 00867 00868 /*++ 00869 00870 Routine Description: 00871 00872 This function is the delete routine for I/O completion objects. Its 00873 function is to release all the entries in the repsective completion 00874 queue and to rundown all threads that are current associated. 00875 00876 Arguments: 00877 00878 Object - Supplies a pointer to an executive I/O completion object. 00879 00880 Return Value: 00881 00882 None. 00883 00884 --*/ 00885 00886 { 00887 00888 PLIST_ENTRY FirstEntry; 00889 PIRP Irp; 00890 PLIST_ENTRY NextEntry; 00891 PIOP_MINI_COMPLETION_PACKET MiniPacket; 00892 00893 // 00894 // Rundown threads associated with the I/O completion object and get 00895 // the list of unprocessed I/O completion IRPs. 00896 // 00897 00898 FirstEntry = KeRundownQueue((PKQUEUE)Object); 00899 if (FirstEntry != NULL) { 00900 NextEntry = FirstEntry; 00901 do { 00902 MiniPacket = CONTAINING_RECORD(NextEntry, 00903 IOP_MINI_COMPLETION_PACKET, 00904 ListEntry); 00905 00906 NextEntry = NextEntry->Flink; 00907 if (MiniPacket->PacketType == IopCompletionPacketIrp) { 00908 Irp = CONTAINING_RECORD(MiniPacket, IRP, Tail.Overlay.ListEntry); 00909 IoFreeIrp(Irp); 00910 00911 } else { 00912 IopFreeMiniPacket(MiniPacket); 00913 } 00914 00915 } while (FirstEntry != NextEntry); 00916 } 00917 00918 return; 00919 }

Generated on Sat May 15 19:39:32 2004 for test by doxygen 1.3.7