FsRtlCancellableWaitForSingleObject 函数 (ntifs.h)

FsRtlCancellableWaitForSingleObject 例程执行可取消的等待操作 (可以在调度程序对象上) 终止的等待操作。

语法

NTSTATUS FsRtlCancellableWaitForSingleObject(
  [in]           PVOID          Object,
  [in, optional] PLARGE_INTEGER Timeout,
  [in, optional] PIRP           Irp
);

参数

[in] Object

指向已初始化的调度程序对象的指针, (调用方为其提供存储的事件、互斥体、信号灯、线程或计时器) 。

[in, optional] Timeout

指向可选超时值的指针。 此参数指定等待完成的绝对时间或相对时间(以 100 纳秒为单位)。

如果 Timeout 指向零值 (即 *Timeout == 0) ,则例程返回而不等待。 如果调用方提供 NULL 指针 (即 Timeout == NULL) ,则例程将无限期等待,直到对象设置为信号状态。

超时 值指定相对于 1601 年 1 月 1 日绝对时间。 负 超时 值指定相对于当前时间的间隔。 绝对过期时间跟踪系统时间中的任何更改。 相对过期时间不受系统时间更改的影响。

如果指定 了 Timeout ,则当给定间隔过期时,如果对象未设置为信号状态,则将自动满足等待。

一个零 (的超时值,即*Timeout == 0) 允许测试一组等待条件,并在可以立即满足等待条件的情况下有条件地执行任何其他操作,如获取互斥体。

[in, optional] Irp

指向原始 IRP 的指针,该指针对应于用户发出的、可由用户取消的 I/O 操作。 调用方必须确保 IRP 在此例程期间保持有效,并且 IRP 不得设置取消例程 (例如,不得在 IRP) 上调用 IoSetCancelRoutine 。 请注意,IRP 必须由调用方持有,不能传递给较低级别的驱动程序。

返回值

FsRtlCancellableWaitForSingleObject 可以返回以下值之一:

返回代码 说明
STATUS_SUCCESS Object 参数指定的调度程序对象满足等待。
STATUS_TIMEOUT 在对象设置为信号状态之前发生超时。 当无法立即满足指定的等待条件集并且 Timeout 设置为零时,可以返回此值。
STATUS_ABANDONED_WAIT_0 调用方试图等待已放弃的互斥体。
STATUS_CANCELLED 等待被指定 IRP 上的挂起的取消请求中断。 请注意,仅当有效的 IRP 传递给 FsRtlCancellableWaitForSingleObject 且 IRP 已被 CancelSynchronousIo 取消时,才会返回此值。
STATUS_THREAD_IS_TERMINATING 等待中断,因为线程已被应用程序或用户终止。

返回值仅指示等待状态。 如果适用,应直接从处理原始用户模式 IRP 过程中生成的另一个 IRP 获取 I/O 请求的实际状态。

请注意,NT_SUCCESS宏对STATUS_CANCELLED和STATUS_THREAD_IS_TERMINATING状态值返回 FALSE (“failure”) ,所有其他状态值返回 TRUE (“success”) 。

注解

FsRtlCancellableWaitForSingleObject 例程对调度程序对象执行可取消的等待操作。 如果用户或应用程序终止线程,或者 CancelSynchronousIo 在线程 IRP 上发布取消请求, (与该线程关联的同步 IRP) ,则取消等待。

FsRtlCancellableWaitForSingleObject 例程旨在支持从 Windows Vista 开始的 I/O 完成/取消指南。 这些准则的目的是允许用户 (或应用程序) 快速终止应用程序。 这反过来又要求应用程序能够快速终止正在执行 I/O 的线程以及任何当前 I/O 操作。 此例程为用户线程提供了一种阻止 (方法,即在内核中等待) I/O 完成、调度程序对象或同步变量,从而允许轻松取消等待。 如果线程被用户或应用程序终止,此例程还允许线程的等待终止。

例如,重定向程序可能需要创建一个或多个辅助 IRP 才能处理用户模式 IRP 并同步等待辅助 IRP 完成。 执行此操作的一种方法是设置一个事件,该事件将由辅助 IRP 的完成例程发出信号,然后等待事件发出信号。 然后,若要执行可取消的等待操作, FsRtlCancellableWaitForSingleObject 将调用传入与辅助 IRP 以及原始用户模式 IRP 关联的事件。 如果发生挂起的终止事件或取消原始用户模式 IRP,则线程等待事件发出信号将被取消。

请注意,终止等待不会自动取消调用方发出的任何 I/O 操作 -必须由调用方单独处理。

当传递给 FsRtlCancellableWaitForSingleObject的 Object 参数是互斥体时,需要特别注意。 如果等待的调度程序对象是互斥体,则 APC 传递与等待期间所有其他调度程序对象的传递相同。 但是,一旦 FsRtlCancellableWaitForSingleObjects 返回STATUS_SUCCESS且线程实际持有互斥体,则仅传递特殊的内核模式 APC。 已禁用所有其他 APC(内核模式和用户模式)的传递。 在互斥释放之前,对 APC 的传递限制一直存在。

互斥体只能以递归方式获取 MINLONG 次。 如果超出此限制,则例程将引发STATUS_MUTANT_LIMIT_EXCEEDED异常。

下面是一个示例,说明如何使用 FsRtlCancellableWaitForSingleObject 来支持 I/O 完成/取消指南

//
// sample calling routine
//
NTSTATUS ProcessIrpFromUserMode( PIRP pOriginalIrp, ... )
{
NTSTATUS  Status;
NTSTATUS  WaitStatus;
KEVENT   Event;
LARGE_INTEGERTimeout;
PIRP   pAdditionalIrp;
BOOLEAN  Cancelled;

 //
 // Allocate the additional IRP here:
 //
KeInitializeEvent( &Event,
            SynchronizationEvent,
    FALSE );
pContext->pEvent = &Event; // Driver specific context structure.
 IoSetCompletionRoutine( pAdditionalIrp,
 FunctionCompletionRoutine,
 pContext,
 TRUE,
 TRUE,
 TRUE);
 Status = IoCallDriver( pDeviceObject, pAdditionalIrp );
  if (Status == STATUS_PENDING) {
   //
   // Initialize Timeout variable here. If no timeout is needed, pass NULL for 
   // that parameter instead.
   //
  WaitStatus = FsRtlCancellableWaitForSingleObject( &Event, 
          &Timeout,
               pOriginalIrp );
   if ((WaitStatus == STATUS_CANCELLED) || (WaitStatus == STATUS_THREAD_IS_TERMINATING)) {
    //
    // Thread is terminating. IRP was canceled.       
    // Cancel the additional IRP passed to the lower level driver, cleanup, and return quickly.
    //
   Cancelled = IoCancelIrp( pAdditionalIrp );
    if (!Cancelled || KeReadStateEvent( &Event ) == 0) {
     //
     //  Wait for the IRP to complete. 
     // If cancel was posted successfully on the IRP, this shouldn't take a long time.
     //
    (VOID) KeWaitForSingleObject( &Event,
             Executive,
             KernelMode,        // WaitMode
             FALSE,             // Alertable
             (PLARGE_INTEGER) NULL );
   }
  } else if (WaitStatus == STATUS_TIMEOUT) {
    //
    // Wait timed out. The IRP was canceled or the API 
    // waited for the I/O to complete.
    // 
  } else {
   ASSERT( WaitStatus == STATUS_SUCCESS );
    //
    // The wait completed without timeout
    // or being canceled.
    //
  }
}
 //
 // IRP is valid and needs to be handled here.
 // pAdditionalIrp->IoStatus.Status contains the status of the IRP.
 // Finally, pOriginal IRP needs to be completed appropriately as well.
 //
}

//
// Sample completion routine:
//
NTSTATUS
FunctionCompletionRoutine(
  IN PDEVICE_OBJECT  pDeviceObject,
  INOUT PIRP  pAdditionalIrp,
  IN PVOID  pContext)
{
 if (pAdditionalIrp->PendingReturned) {
 KeSetEvent( pContext->pEvent, 0, FALSE );
}

 //
 // Discontinue I/O completion.
 // Dispatch routine will deal with IRP.
 //
 return STATUS_MORE_PROCESSING_REQUIRED;
}

如果可选的 Irp 参数指向有效的 IRP,则必须在 IRQL PASSIVE_LEVEL调用 FsRtlCancellableWaitForSingleObject。 如果未使用 Irp 参数,则可以在 IRQL 中调用例程,或小于等于 APC_LEVEL。 如果需要,调用方可以通过调用 KeEnterCriticalRegionFsRtlEnterFileSystem 例程来禁用正常的内核 APC。 但是,不得禁用特殊内核 APC。

如果 IRQL 大于或等于 APC_LEVEL 并且可选的 Irp 参数指向有效的 IRP,FsRtlCancellableWaitForSingleObject 将在调试版本上断言。

要求

要求
最低受支持的客户端 Windows Vista
目标平台 通用
标头 ntifs.h (包括 Ntifs.h)
Library NtosKrnl.lib
DLL NtosKrnl.exe
IRQL 请参见“备注”部分。
DDI 符合性规则 HwStorPortProhibitedDDI (storport) SpNoWait (storport)

另请参阅

ExInitializeFastMutex

FsRtlCancellableWaitForMultipleObjects

KeInitializeEvent

KeInitializeMutex

KeInitializeSemaphore

KeInitializeTimer

KeWaitForMultipleObjects

KeWaitForSingleObject