NDKPI 对象生存期要求

如何创建、使用和关闭 NDK 对象

NDK 使用者通过为该对象调用 NDK 提供程序的 create 函数来启动 NDK 对象的创建请求。

当使用者调用 create 函数时,它将 NdkCreateCompletionNDK_FN_CREATE_COMPLETION) 作为参数传递。

使用者通过在对象的调度表中调用提供程序函数来启动各种请求,并将 NdkRequestCompletionNDK_FN_REQUEST_COMPLETION) 完成回调作为参数传递。

不再需要对象时,使用者调用提供程序的 NdkCloseObjectNDK_FN_CLOSE_OBJECT) 函数来启动对象的关闭请求,并将 NdkCloseCompletionNDK_FN_CLOSE_COMPLETION) 回调作为参数传递。

提供程序调用使用者的回调函数以异步完成请求。 此调用向使用者指示提供程序已完成作(例如关闭对象),并且正在向使用者返回控件。 如果提供程序以同步方式(成功或出错)完成关闭请求,则不会调用使用者的回调函数。

完成回调的规则

当提供程序在使用者请求中创建对象时,提供程序调用使用者的 NdkCreateCompletion 回调以指示该对象已准备好使用。

使用者可以调用同一对象的其他提供程序函数,而无需等待第一个回调返回。

在返回该对象的所有提供程序函数之前,使用者不会为对象调用 NdkCloseObject 函数。

但是,如果提供程序函数启动完成请求,则使用者可以从该完成回调内部自由调用 NdkCloseObject ,即使提供程序函数尚未返回也是如此。

提供程序函数可以通过执行以下之一方法,在从回调返回之前启动完成请求:

  • 直接调用完成回调函数
  • 将完成请求排入另一个线程的队列中

通过启动完成请求,提供程序有效地将控制权返回到使用者。 提供程序必须假定该对象可以在提供程序启动完成请求后随时关闭。

注意 若要在启动完成请求后防止死锁,提供程序必须:

  • 在完成回调返回之前,请不要对对象执行其他操作。
  • 如果提供程序绝对必须触摸对象,则采取必要的措施使对象保持不变。

示例:Consumer-Provider 交互

请考虑以下方案:

  1. 使用者创建连接器(NDK_CONNECTOR),然后调用 NdkConnectNDK_FN_CONNECT)。
  2. 提供程序处理连接请求、命中失败,并在 NdkConnect 调用的上下文中调用使用者的完成回调(而不是由于内部实现选择返回内联失败)。
  3. 即使 NdkConnect 调用尚未返回到使用者,使用者也会在此完成回调的上下文中调用 NdkCloseObject

为了避免死锁,提供程序在步骤 2(在 NdkConnect 调用中启动完成回调时点)后不得触摸连接器对象。

关闭前面的对象和后续对象

在消费者调用 NdkCloseObject 来关闭后续对象之前,提供者必须做好准备以便消费者调用 NdkCloseObject 关闭先行对象。 如果消费者进行此操作,供应商必须执行以下操作:

  • 在关闭所有后续对象之前,提供程序不得关闭先前的对象。也就是说,提供程序必须在关闭请求中返回 STATUS_PENDING,并在所有后续对象关闭后,完成关闭请求(通过调用已注册的NdkCloseCompletion 函数)。
  • 使用者在调用 NdkCloseObject 后不会使用前置对象,因此提供方不必为进一步处理的失败在前置对象上添加任何处理(但可以选择这样做)。
  • 除非另有需要(例如下面所述的 NDK 侦听器关闭的必需副作用),否则提供程序可以将关闭请求视为简单的取消引用,在最后一个后续对象关闭之前不会产生其他副作用。

在任何后续对象的关闭完成回调尚未返回到提供程序之前,提供程序不得在前置对象(包括 NDK_ADAPTER 关闭请求)上完成关闭请求。 这是允许 NDK 使用者安全卸载。

NDK 使用者不会从使用者回调函数内部为NDK_ADAPTER对象(这是阻止调用)调用 NdkCloseObject

关闭适配器对象

请考虑以下方案:

  1. 使用者对完成队列 (CQ) 对象调用 NdkCloseObject
  2. 提供程序返回STATUS_PENDING,然后调用使用者的完成回调。
  3. 在此完成回调中,使用者发出一个事件信号,即现在可以关闭NDK_ADAPTER。
  4. 另一个线程在收到此信号后唤醒,关闭NDK_ADAPTER,然后继续卸载。
  5. 但是,调用使用者的 CQ 关闭完成回调的线程可能仍位于使用者的回调函数(例如函数 epilog)内,因此使用者驱动程序卸载不安全。
  6. 由于完成回调上下文是唯一使用者可以发出事件信号的上下文,因此使用者驱动程序无法自行解决安全卸载问题。

必须有一个点,使用者可以保证其所有回调都已返回控制权。 在 NDKPI 中,当 对NDK_ADAPTER 的关闭请求返回控件时,这一点。 请注意,NDK_ADAPTER 关闭请求是阻塞调用。 当NDK_ADAPTER关闭请求返回时,可以保证从该NDK_ADAPTER对象继承的所有对象上的所有回调已将控制权返回给提供程序。

完成关闭请求

在以下之前,提供程序不得在对象上完成关闭请求:

  • 对象上所有挂起的异步请求都已完成(换句话说,它们的完成回调已返回到提供程序)。
  • 所有使用者事件回调(例如,在 CQ 上的 NdkCqNotificationCallbackNDK_FN_CQ_NOTIFICATION_CALLBACK)、侦听器上的 NdkConnectEventCallbackNDK_FN_CONNECT_EVENT_CALLBACK))都返回到提供程序。

提供程序必须确保,在调用关闭完成回调函数或关闭请求返回 STATUS_SUCCESS 之后,不会再发生任何回调。 请注意,关闭请求还必须启动任何所需的刷新或取消挂起的异步请求。

注意从上述逻辑上讲,NDK 使用者不得从使用者回调函数内部调用 NDK_ADAPTER 对象(这是阻塞调用)的 NdkCloseObject

网络直接内核提供者接口 (NDKPI)