NDKPI 对象生存期要求

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

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

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

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

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

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

完成回调的规则

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

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

使用者不会为对象调用 NdkCloseObject 函数,直到该对象的所有提供程序函数都已返回。

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

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

  • 直接调用完成回调
  • 将完成请求排队到另一个线程

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

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

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

示例:Consumer-Provider交互

假设出现了下面这种情景:

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

为了避免死锁,提供程序在步骤 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 对象下降的所有对象的所有回调都已将控制权返回到提供程序。

完成关闭请求

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

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

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

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

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