#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 }