|
|
1.1 ! root 1: /*++ ! 2: ! 3: Copyright (c) 1989-1993 Microsoft Corporation ! 4: ! 5: Module Name: ! 6: ! 7: request.c ! 8: ! 9: Abstract: ! 10: ! 11: This module contains code which implements the TP_REQUEST object. ! 12: Routines are provided to create, destroy, reference, and dereference, ! 13: transport request objects. ! 14: ! 15: Environment: ! 16: ! 17: Kernel mode ! 18: ! 19: Revision History: ! 20: ! 21: ! 22: --*/ ! 23: ! 24: #include "st.h" ! 25: ! 26: ! 27: VOID ! 28: StTdiRequestTimeoutHandler( ! 29: IN PKDPC Dpc, ! 30: IN PVOID DeferredContext, ! 31: IN PVOID SystemArgument1, ! 32: IN PVOID SystemArgument2 ! 33: ) ! 34: ! 35: /*++ ! 36: ! 37: Routine Description: ! 38: ! 39: This routine is executed as a DPC at DISPATCH_LEVEL when a request ! 40: such as TdiSend, TdiReceive, TdiSendDatagram, TdiReceiveDatagram, etc., ! 41: encounters a timeout. This routine cleans up the activity and cancels it. ! 42: ! 43: Arguments: ! 44: ! 45: Dpc - Pointer to a system DPC object. ! 46: ! 47: DeferredContext - Pointer to the TP_REQUEST block representing the ! 48: request that has timed out. ! 49: ! 50: SystemArgument1 - Not used. ! 51: ! 52: SystemArgument2 - Not used. ! 53: ! 54: Return Value: ! 55: ! 56: none. ! 57: ! 58: --*/ ! 59: ! 60: { ! 61: KIRQL oldirql; ! 62: PTP_REQUEST Request; ! 63: PTP_CONNECTION Connection; ! 64: PIO_STACK_LOCATION IrpSp; ! 65: ! 66: UNREFERENCED_PARAMETER(Dpc); ! 67: UNREFERENCED_PARAMETER(SystemArgument1); ! 68: UNREFERENCED_PARAMETER(SystemArgument2); ! 69: ! 70: ! 71: Request = (PTP_REQUEST)DeferredContext; ! 72: ! 73: ACQUIRE_SPIN_LOCK (&Request->SpinLock, &oldirql); ! 74: Request->Flags &= ~REQUEST_FLAGS_TIMER; ! 75: if ((Request->Flags & REQUEST_FLAGS_STOPPING) == 0) { ! 76: ! 77: // ! 78: // find reason for timeout ! 79: // ! 80: ! 81: IrpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket); ! 82: if (IrpSp->MajorFunction == IRP_MJ_INTERNAL_DEVICE_CONTROL) { ! 83: switch (IrpSp->MinorFunction) { ! 84: ! 85: // ! 86: // none of these should time out. ! 87: // ! 88: ! 89: case TDI_SEND: ! 90: case TDI_ACCEPT: ! 91: case TDI_SET_INFORMATION: ! 92: case TDI_SET_EVENT_HANDLER: ! 93: case TDI_SEND_DATAGRAM: ! 94: case TDI_RECEIVE_DATAGRAM: ! 95: case TDI_RECEIVE: ! 96: ! 97: ASSERT (FALSE); ! 98: RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql); ! 99: StCompleteRequest (Request, STATUS_IO_TIMEOUT, 0); ! 100: break; ! 101: ! 102: ! 103: case TDI_LISTEN: ! 104: case TDI_CONNECT: ! 105: ! 106: Connection = (PTP_CONNECTION)(Request->Context); ! 107: RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql); ! 108: ! 109: // ! 110: // Since these requests are part of the connection ! 111: // itself, we just stop the connection and the ! 112: // request will get torn down then. If we get the ! 113: // situation where the request times out before ! 114: // it is queued to the connection, then the code ! 115: // that is about to queue it will check the STOPPING ! 116: // flag and complete it then. ! 117: // ! 118: ! 119: StStopConnection (Connection, STATUS_IO_TIMEOUT); ! 120: break; ! 121: ! 122: case TDI_DISCONNECT: ! 123: ! 124: // ! 125: // We don't create requests for TDI_DISCONNECT any more. ! 126: // ! 127: ! 128: ASSERT(FALSE); ! 129: break; ! 130: ! 131: default: ! 132: RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql); ! 133: break; ! 134: ! 135: } // end of switch ! 136: ! 137: } else { ! 138: ! 139: RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql); ! 140: ! 141: } ! 142: ! 143: StDereferenceRequest ("Timeout", Request); // for the timeout ! 144: ! 145: } else { ! 146: ! 147: RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql); ! 148: StDereferenceRequest ("Timeout: stopping", Request); // for the timeout ! 149: ! 150: } ! 151: ! 152: return; ! 153: ! 154: } /* RequestTimeoutHandler */ ! 155: ! 156: ! 157: VOID ! 158: StAllocateRequest( ! 159: IN PDEVICE_CONTEXT DeviceContext, ! 160: OUT PTP_REQUEST *TransportRequest ! 161: ) ! 162: ! 163: /*++ ! 164: ! 165: Routine Description: ! 166: ! 167: This routine allocates a request packet from nonpaged pool and initializes ! 168: it to a known state. ! 169: ! 170: NOTE: This routine is called with the device context spinlock ! 171: held, or at such a time as synchronization is unnecessary. ! 172: ! 173: Arguments: ! 174: ! 175: DeviceContext - Pointer to the device context (which is really just ! 176: the device object with its extension) to be associated with the ! 177: address. ! 178: ! 179: TransportRequest - Pointer to a place where this routine will return ! 180: a pointer to a transport request structure. It returns NULL if no ! 181: storage can be allocated. ! 182: ! 183: Return Value: ! 184: ! 185: None. ! 186: ! 187: --*/ ! 188: ! 189: { ! 190: PTP_REQUEST Request; ! 191: ! 192: if ((DeviceContext->MemoryLimit != 0) && ! 193: ((DeviceContext->MemoryUsage + sizeof(TP_REQUEST)) > ! 194: DeviceContext->MemoryLimit)) { ! 195: PANIC("ST: Could not allocate request: limit\n"); ! 196: StWriteResourceErrorLog (DeviceContext, sizeof(TP_REQUEST), 104); ! 197: *TransportRequest = NULL; ! 198: return; ! 199: } ! 200: ! 201: Request = (PTP_REQUEST)ExAllocatePool (NonPagedPool, sizeof (TP_REQUEST)); ! 202: if (Request == NULL) { ! 203: PANIC("ST: Could not allocate request: no pool\n"); ! 204: StWriteResourceErrorLog (DeviceContext, sizeof(TP_REQUEST), 204); ! 205: *TransportRequest = NULL; ! 206: return; ! 207: } ! 208: RtlZeroMemory (Request, sizeof(TP_REQUEST)); ! 209: ! 210: DeviceContext->MemoryUsage += sizeof(TP_REQUEST); ! 211: ++DeviceContext->RequestAllocated; ! 212: ! 213: Request->Type = ST_REQUEST_SIGNATURE; ! 214: Request->Size = sizeof (TP_REQUEST); ! 215: ! 216: Request->Provider = DeviceContext; ! 217: Request->ProviderInterlock = &DeviceContext->Interlock; ! 218: KeInitializeSpinLock (&Request->SpinLock); ! 219: KeInitializeDpc (&Request->Dpc, StTdiRequestTimeoutHandler, (PVOID)Request); ! 220: KeInitializeTimer (&Request->Timer); // set to not-signaled state. ! 221: ! 222: *TransportRequest = Request; ! 223: ! 224: } /* StAllocateRequest */ ! 225: ! 226: ! 227: VOID ! 228: StDeallocateRequest( ! 229: IN PDEVICE_CONTEXT DeviceContext, ! 230: IN PTP_REQUEST TransportRequest ! 231: ) ! 232: ! 233: /*++ ! 234: ! 235: Routine Description: ! 236: ! 237: This routine frees a request packet. ! 238: ! 239: NOTE: This routine is called with the device context spinlock ! 240: held, or at such a time as synchronization is unnecessary. ! 241: ! 242: Arguments: ! 243: ! 244: DeviceContext - Pointer to the device context (which is really just ! 245: the device object with its extension) to be associated with the ! 246: address. ! 247: ! 248: TransportRequest - Pointer to a transport request structure. ! 249: ! 250: Return Value: ! 251: ! 252: None. ! 253: ! 254: --*/ ! 255: ! 256: { ! 257: ! 258: ExFreePool (TransportRequest); ! 259: --DeviceContext->RequestAllocated; ! 260: DeviceContext->MemoryUsage -= sizeof(TP_REQUEST); ! 261: ! 262: } /* StDeallocateRequest */ ! 263: ! 264: ! 265: NTSTATUS ! 266: StCreateRequest( ! 267: IN PIRP Irp, ! 268: IN PVOID Context, ! 269: IN ULONG Flags, ! 270: IN PMDL Buffer2, ! 271: IN ULONG Buffer2Length, ! 272: IN LARGE_INTEGER Timeout, ! 273: OUT PTP_REQUEST * TpRequest ! 274: ) ! 275: ! 276: /*++ ! 277: ! 278: Routine Description: ! 279: ! 280: This routine creates a transport request and associates it with the ! 281: specified IRP, context, and queue. All major requests, including ! 282: TdiSend, TdiSendDatagram, TdiReceive, and TdiReceiveDatagram requests, ! 283: are composed in this manner. ! 284: ! 285: Arguments: ! 286: ! 287: Irp - Pointer to an IRP which was received by the transport for this ! 288: request. ! 289: ! 290: Context - Pointer to anything to associate this request with. This ! 291: value is not interpreted except at request cancelation time. ! 292: ! 293: Flags - A set of bitflags indicating the disposition of this request. ! 294: ! 295: Timeout - Timeout value (if non-zero) to start a timer for this request. ! 296: If zero, then no timer is activated for the request. ! 297: ! 298: TpRequest - If the function returns STATUS_SUCCESS, this will return ! 299: pointer to the TP_REQUEST structure allocated. ! 300: ! 301: Return Value: ! 302: ! 303: NTSTATUS - status of operation. ! 304: ! 305: --*/ ! 306: ! 307: { ! 308: KIRQL oldirql; ! 309: PDEVICE_CONTEXT DeviceContext; ! 310: PTP_REQUEST Request; ! 311: PLIST_ENTRY p; ! 312: PIO_STACK_LOCATION irpSp; ! 313: ! 314: ! 315: irpSp = IoGetCurrentIrpStackLocation(Irp); ! 316: DeviceContext = (PDEVICE_CONTEXT)irpSp->FileObject->DeviceObject; ! 317: ! 318: ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql); ! 319: ! 320: p = RemoveHeadList (&DeviceContext->RequestPool); ! 321: if (p == &DeviceContext->RequestPool) { ! 322: ! 323: if ((DeviceContext->RequestMaxAllocated == 0) || ! 324: (DeviceContext->RequestAllocated < DeviceContext->RequestMaxAllocated)) { ! 325: ! 326: StAllocateRequest (DeviceContext, &Request); ! 327: ! 328: } else { ! 329: ! 330: StWriteResourceErrorLog (DeviceContext, sizeof(TP_REQUEST), 404); ! 331: Request = NULL; ! 332: ! 333: } ! 334: ! 335: if (Request == NULL) { ! 336: ++DeviceContext->RequestExhausted; ! 337: RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql); ! 338: PANIC ("StCreateConnection: Could not allocate request object!\n"); ! 339: return STATUS_INSUFFICIENT_RESOURCES; ! 340: } ! 341: ! 342: } else { ! 343: ! 344: Request = CONTAINING_RECORD (p, TP_REQUEST, Linkage); ! 345: ! 346: } ! 347: ! 348: ++DeviceContext->RequestInUse; ! 349: if (DeviceContext->RequestInUse > DeviceContext->RequestMaxInUse) { ! 350: ++DeviceContext->RequestMaxInUse; ! 351: } ! 352: ! 353: DeviceContext->RequestTotal += DeviceContext->RequestInUse; ! 354: ++DeviceContext->RequestSamples; ! 355: ! 356: RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql); ! 357: ! 358: ! 359: // ! 360: // fill out the request. ! 361: // ! 362: ! 363: // Request->Provider = DeviceContext; ! 364: Request->IoRequestPacket = Irp; ! 365: Request->Buffer2 = Buffer2; ! 366: Request->Buffer2Length = Buffer2Length; ! 367: Request->Flags = Flags; ! 368: Request->Context = Context; ! 369: Request->ReferenceCount = 1; // initialize reference count. ! 370: ! 371: if ((Timeout.LowPart == 0) && (Timeout.HighPart == 0)) { ! 372: ! 373: // no timeout ! 374: } else { ! 375: ! 376: Request->Flags |= REQUEST_FLAGS_TIMER; // there is a timeout on this request. ! 377: KeInitializeTimer (&Request->Timer); // set to not-signaled state. ! 378: StReferenceRequest ("Create: timer", Request); // one for the timer ! 379: KeSetTimer (&Request->Timer, Timeout, &Request->Dpc); ! 380: } ! 381: ! 382: *TpRequest = Request; ! 383: ! 384: return STATUS_SUCCESS; ! 385: } /* StCreateRequest */ ! 386: ! 387: ! 388: VOID ! 389: StDestroyRequest( ! 390: IN PTP_REQUEST Request ! 391: ) ! 392: ! 393: /*++ ! 394: ! 395: Routine Description: ! 396: ! 397: This routine returns a request block to the free pool. ! 398: ! 399: Arguments: ! 400: ! 401: Request - Pointer to a TP_REQUEST block to return to the free pool. ! 402: ! 403: Return Value: ! 404: ! 405: NTSTATUS - status of operation. ! 406: ! 407: --*/ ! 408: ! 409: { ! 410: KIRQL oldirql; ! 411: PIO_STACK_LOCATION irpSp; ! 412: PDEVICE_CONTEXT DeviceContext; ! 413: ! 414: // ! 415: // Return the request to the caller with whatever status is in the IRP. ! 416: // ! 417: ! 418: // ! 419: // Now dereference the owner of this request so that we are safe when ! 420: // we finally tear down the {connection, address}. The problem we're ! 421: // facing here is that we can't allow the user to assume semantics; ! 422: // the end of life for a connection must truly be the real end of life. ! 423: // for that to occur, we reference the owning object when the request is ! 424: // created and we dereference it just before we return it to the pool. ! 425: // ! 426: ! 427: switch (Request->Owner) { ! 428: case ConnectionType: ! 429: if (!(Request->Flags & REQUEST_FLAGS_DELAY)) { ! 430: StDereferenceConnection ("Removing Connection",((PTP_CONNECTION)Request->Context)); ! 431: } ! 432: break; ! 433: ! 434: case AddressType: ! 435: StDereferenceAddress ("Removing Address", ((PTP_ADDRESS)Request->Context)); ! 436: break; ! 437: ! 438: case DeviceContextType: ! 439: StDereferenceDeviceContext ("Removing Address", ((PDEVICE_CONTEXT)Request->Context)); ! 440: break; ! 441: } ! 442: ! 443: irpSp = IoGetCurrentIrpStackLocation (Request->IoRequestPacket); ! 444: DeviceContext = Request->Provider; ! 445: ! 446: if (Request->Flags & REQUEST_FLAGS_DELAY) { ! 447: ! 448: ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql); ! 449: ! 450: InsertTailList( ! 451: &DeviceContext->IrpCompletionQueue, ! 452: &Request->IoRequestPacket->Tail.Overlay.ListEntry); ! 453: ! 454: } else { ! 455: ! 456: IoCompleteRequest (Request->IoRequestPacket, IO_NETWORK_INCREMENT); ! 457: ! 458: ACQUIRE_SPIN_LOCK (&DeviceContext->SpinLock, &oldirql); ! 459: ! 460: } ! 461: ! 462: // ! 463: // Put the request back on the free list. NOTE: we have the ! 464: // lock held here. ! 465: // ! 466: ! 467: ! 468: DeviceContext->RequestTotal += DeviceContext->RequestInUse; ! 469: ++DeviceContext->RequestSamples; ! 470: --DeviceContext->RequestInUse; ! 471: ! 472: if ((DeviceContext->RequestAllocated - DeviceContext->RequestInUse) > ! 473: DeviceContext->RequestInitAllocated) { ! 474: StDeallocateRequest (DeviceContext, Request); ! 475: } else { ! 476: InsertTailList (&DeviceContext->RequestPool, &Request->Linkage); ! 477: } ! 478: ! 479: RELEASE_SPIN_LOCK (&DeviceContext->SpinLock, oldirql); ! 480: ! 481: } /* StDestroyRequest */ ! 482: ! 483: ! 484: VOID ! 485: StRefRequest( ! 486: IN PTP_REQUEST Request ! 487: ) ! 488: ! 489: /*++ ! 490: ! 491: Routine Description: ! 492: ! 493: This routine increments the reference count on a transport request. ! 494: ! 495: Arguments: ! 496: ! 497: Request - Pointer to a TP_REQUEST block. ! 498: ! 499: Return Value: ! 500: ! 501: none. ! 502: ! 503: --*/ ! 504: ! 505: { ! 506: INTERLOCKED_RESULT result; ! 507: ! 508: ASSERT (Request->ReferenceCount > 0); ! 509: ! 510: result = ExInterlockedIncrementLong ( ! 511: &Request->ReferenceCount, ! 512: Request->ProviderInterlock); ! 513: ! 514: } /* StRefRequest */ ! 515: ! 516: ! 517: VOID ! 518: StDerefRequest( ! 519: IN PTP_REQUEST Request ! 520: ) ! 521: ! 522: /*++ ! 523: ! 524: Routine Description: ! 525: ! 526: This routine dereferences a transport request by decrementing the ! 527: reference count contained in the structure. If, after being ! 528: decremented, the reference count is zero, then this routine calls ! 529: StDestroyRequest to remove it from the system. ! 530: ! 531: Arguments: ! 532: ! 533: Request - Pointer to a transport request object. ! 534: ! 535: Return Value: ! 536: ! 537: none. ! 538: ! 539: --*/ ! 540: ! 541: { ! 542: INTERLOCKED_RESULT result; ! 543: ! 544: result = ExInterlockedDecrementLong ( ! 545: &Request->ReferenceCount, ! 546: Request->ProviderInterlock); ! 547: ! 548: ASSERT (result != ResultNegative); ! 549: ! 550: // ! 551: // If we have deleted all references to this request, then we can ! 552: // destroy the object. It is okay to have already released the spin ! 553: // lock at this point because there is no possible way that another ! 554: // stream of execution has access to the request any longer. ! 555: // ! 556: ! 557: if (result == ResultZero) { ! 558: StDestroyRequest (Request); ! 559: } ! 560: ! 561: } /* StDerefRequest */ ! 562: ! 563: ! 564: VOID ! 565: StCompleteRequest( ! 566: IN PTP_REQUEST Request, ! 567: IN NTSTATUS Status, ! 568: IN ULONG Information ! 569: ) ! 570: ! 571: /*++ ! 572: ! 573: Routine Description: ! 574: ! 575: This routine completes a transport request object, completing the I/O, ! 576: stopping the timeout, and freeing up the request object itself. ! 577: ! 578: Arguments: ! 579: ! 580: Request - Pointer to a transport request object. ! 581: ! 582: Status - Actual return status to be assigned to the request. This ! 583: value may be overridden if the timed-out bitflag is set in the request. ! 584: ! 585: Information - the information field for the I/O Status Block. ! 586: ! 587: Return Value: ! 588: ! 589: none. ! 590: ! 591: --*/ ! 592: ! 593: { ! 594: KIRQL oldirql; ! 595: PIRP Irp; ! 596: NTSTATUS FinalStatus = Status; ! 597: BOOLEAN TimerWasSet; ! 598: ! 599: ASSERT (Status != STATUS_PENDING); ! 600: ! 601: if (Request->Flags & REQUEST_FLAGS_SEND_RCV) { ! 602: ! 603: // ! 604: // Sends and receives we check for since we know ! 605: // they don't have timers and should only complete ! 606: // once. ! 607: // ! 608: ! 609: Request->Flags |= REQUEST_FLAGS_STOPPING; ! 610: Irp = Request->IoRequestPacket; ! 611: Irp->IoStatus.Status = FinalStatus; ! 612: Irp->IoStatus.Information = Information; ! 613: ! 614: StDereferenceRequest ("Complete", Request); // remove creation reference. ! 615: return; ! 616: } ! 617: ! 618: ! 619: ACQUIRE_SPIN_LOCK (&Request->SpinLock, &oldirql); ! 620: ! 621: if ((Request->Flags & REQUEST_FLAGS_STOPPING) == 0) { ! 622: Request->Flags |= REQUEST_FLAGS_STOPPING; ! 623: ! 624: // ! 625: // Cancel the pending timeout on this request. Not all requests ! 626: // have their timer set. If this request has the TIMER bit set, ! 627: // then the timer needs to be cancelled. If it cannot be cancelled, ! 628: // then the timer routine will be run, so we just return and let ! 629: // the timer routine worry about cleaning up this request. ! 630: // ! 631: ! 632: if ((Request->Flags & REQUEST_FLAGS_TIMER) != 0) { ! 633: Request->Flags &= ~REQUEST_FLAGS_TIMER; ! 634: RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql); ! 635: TimerWasSet = KeCancelTimer (&Request->Timer); ! 636: ! 637: if (TimerWasSet) { ! 638: StDereferenceRequest ("Complete: stop timer", Request); ! 639: } ! 640: ! 641: } else { ! 642: RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql); ! 643: } ! 644: ! 645: Irp = Request->IoRequestPacket; ! 646: ! 647: ! 648: // ! 649: // Install the return code in the IRP so that when we call StDestroyRequest, ! 650: // it will get completed with the proper return status. ! 651: // ! 652: ! 653: Irp->IoStatus.Status = FinalStatus; ! 654: Irp->IoStatus.Information = Information; ! 655: ! 656: // ! 657: // The entire transport is done with this request. ! 658: // ! 659: ! 660: StDereferenceRequest ("Complete", Request); // remove creation reference. ! 661: ! 662: } else { ! 663: ! 664: RELEASE_SPIN_LOCK (&Request->SpinLock, oldirql); ! 665: ! 666: } ! 667: ! 668: } /* StCompleteRequest */ ! 669: ! 670: ! 671: VOID ! 672: StRefSendIrp( ! 673: IN PIO_STACK_LOCATION IrpSp ! 674: ) ! 675: ! 676: /*++ ! 677: ! 678: Routine Description: ! 679: ! 680: This routine increments the reference count on a send IRP. ! 681: ! 682: Arguments: ! 683: ! 684: IrpSp - Pointer to the IRP's stack location. ! 685: ! 686: Return Value: ! 687: ! 688: none. ! 689: ! 690: --*/ ! 691: ! 692: { ! 693: INTERLOCKED_RESULT result; ! 694: ! 695: ASSERT (IRP_REFCOUNT(IrpSp) > 0); ! 696: ! 697: result = ExInterlockedIncrementLong ( ! 698: &IRP_REFCOUNT(IrpSp), ! 699: &(IRP_DEVICE_CONTEXT(IrpSp)->Interlock)); ! 700: ! 701: } /* StRefSendIrp */ ! 702: ! 703: ! 704: VOID ! 705: StDerefSendIrp( ! 706: IN PIO_STACK_LOCATION IrpSp ! 707: ) ! 708: ! 709: /*++ ! 710: ! 711: Routine Description: ! 712: ! 713: This routine dereferences a transport send IRP by decrementing the ! 714: reference count contained in the structure. If, after being ! 715: decremented, the reference count is zero, then this routine calls ! 716: IoCompleteRequest to actually complete the IRP. ! 717: ! 718: NOTE: This assume that IRP_CONNECTION(IrpSp) has been changed ! 719: to point to the IRP instead of the connection. ! 720: ! 721: Arguments: ! 722: ! 723: Request - Pointer to a transport send IRP's stack location. ! 724: ! 725: Return Value: ! 726: ! 727: none. ! 728: ! 729: --*/ ! 730: ! 731: { ! 732: INTERLOCKED_RESULT result; ! 733: ! 734: result = ExInterlockedDecrementLong ( ! 735: &IRP_REFCOUNT(IrpSp), ! 736: &(IRP_DEVICE_CONTEXT(IrpSp)->Interlock)); ! 737: ! 738: ASSERT (result != ResultNegative); ! 739: ! 740: // ! 741: // If we have deleted all references to this request, then we can ! 742: // destroy the object. It is okay to have already released the spin ! 743: // lock at this point because there is no possible way that another ! 744: // stream of execution has access to the request any longer. ! 745: // ! 746: ! 747: if (result == ResultZero) { ! 748: ! 749: PIRP Irp = (PIRP)IRP_CONNECTION(IrpSp); ! 750: ! 751: IRP_REFCOUNT(IrpSp) = 0; ! 752: IRP_CONNECTION (IrpSp) = NULL; ! 753: ! 754: IoCompleteRequest (Irp, IO_NETWORK_INCREMENT); ! 755: ! 756: } ! 757: ! 758: } /* StDerefSendIrp */ ! 759: ! 760: ! 761: VOID ! 762: StCompleteSendIrp( ! 763: IN PIRP Irp, ! 764: IN NTSTATUS Status, ! 765: IN ULONG Information ! 766: ) ! 767: ! 768: /*++ ! 769: ! 770: Routine Description: ! 771: ! 772: This routine completes a transport send IRP. ! 773: ! 774: Arguments: ! 775: ! 776: Irp - Pointer to a send IRP. ! 777: ! 778: Status - Actual return status to be assigned to the request. This ! 779: value may be overridden if the timed-out bitflag is set in the request. ! 780: ! 781: Information - the information field for the I/O Status Block. ! 782: ! 783: Return Value: ! 784: ! 785: none. ! 786: ! 787: --*/ ! 788: ! 789: { ! 790: PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp); ! 791: PTP_CONNECTION Connection; ! 792: ! 793: ASSERT (Status != STATUS_PENDING); ! 794: ! 795: Connection = IRP_CONNECTION(IrpSp); ! 796: ! 797: ! 798: // ! 799: // Sends and receives we check for since we know ! 800: // they don't have timers and should only complete ! 801: // once. ! 802: // ! 803: ! 804: Irp->IoStatus.Status = Status; ! 805: Irp->IoStatus.Information = Information; ! 806: ! 807: IRP_CONNECTION(IrpSp) = Irp; ! 808: ! 809: StDereferenceSendIrp ("Complete", IrpSp); // remove creation reference. ! 810: ! 811: StDereferenceConnection ("Removing Connection", Connection); ! 812: ! 813: } /* StCompleteSendIrp */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.