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。 如果需要,调用方可以通过调用 KeEnterCriticalRegion 或 FsRtlEnterFileSystem 例程来禁用正常的内核 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) |