如何创建、使用和关闭 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 交互
请考虑以下方案:
- 使用者创建连接器(NDK_CONNECTOR),然后调用 NdkConnect (NDK_FN_CONNECT)。
- 提供程序处理连接请求、命中失败,并在 NdkConnect 调用的上下文中调用使用者的完成回调(而不是由于内部实现选择返回内联失败)。
- 即使 NdkConnect 调用尚未返回到使用者,使用者也会在此完成回调的上下文中调用 NdkCloseObject。
为了避免死锁,提供程序在步骤 2(在 NdkConnect 调用中启动完成回调时点)后不得触摸连接器对象。
关闭前面的对象和后续对象
在消费者调用 NdkCloseObject 来关闭后续对象之前,提供者必须做好准备以便消费者调用 NdkCloseObject 关闭先行对象。 如果消费者进行此操作,供应商必须执行以下操作:
- 在关闭所有后续对象之前,提供程序不得关闭先前的对象。也就是说,提供程序必须在关闭请求中返回 STATUS_PENDING,并在所有后续对象关闭后,完成关闭请求(通过调用已注册的NdkCloseCompletion 函数)。
- 使用者在调用 NdkCloseObject 后不会使用前置对象,因此提供方不必为进一步处理的失败在前置对象上添加任何处理(但可以选择这样做)。
- 除非另有需要(例如下面所述的 NDK 侦听器关闭的必需副作用),否则提供程序可以将关闭请求视为简单的取消引用,在最后一个后续对象关闭之前不会产生其他副作用。
在任何后续对象的关闭完成回调尚未返回到提供程序之前,提供程序不得在前置对象(包括 NDK_ADAPTER 关闭请求)上完成关闭请求。 这是允许 NDK 使用者安全卸载。
NDK 使用者不会从使用者回调函数内部为NDK_ADAPTER对象(这是阻止调用)调用 NdkCloseObject。
关闭适配器对象
请考虑以下方案:
- 使用者对完成队列 (CQ) 对象调用 NdkCloseObject 。
- 提供程序返回STATUS_PENDING,然后调用使用者的完成回调。
- 在此完成回调中,使用者发出一个事件信号,即现在可以关闭NDK_ADAPTER。
- 另一个线程在收到此信号后唤醒,关闭NDK_ADAPTER,然后继续卸载。
- 但是,调用使用者的 CQ 关闭完成回调的线程可能仍位于使用者的回调函数(例如函数 epilog)内,因此使用者驱动程序卸载不安全。
- 由于完成回调上下文是唯一使用者可以发出事件信号的上下文,因此使用者驱动程序无法自行解决安全卸载问题。
必须有一个点,使用者可以保证其所有回调都已返回控制权。 在 NDKPI 中,当 对NDK_ADAPTER 的关闭请求返回控件时,这一点。 请注意,NDK_ADAPTER 关闭请求是阻塞调用。 当NDK_ADAPTER关闭请求返回时,可以保证从该NDK_ADAPTER对象继承的所有对象上的所有回调已将控制权返回给提供程序。
完成关闭请求
在以下之前,提供程序不得在对象上完成关闭请求:
- 对象上所有挂起的异步请求都已完成(换句话说,它们的完成回调已返回到提供程序)。
- 所有使用者事件回调(例如,在 CQ 上的 NdkCqNotificationCallback (NDK_FN_CQ_NOTIFICATION_CALLBACK)、侦听器上的 NdkConnectEventCallback (NDK_FN_CONNECT_EVENT_CALLBACK))都返回到提供程序。
提供程序必须确保,在调用关闭完成回调函数或关闭请求返回 STATUS_SUCCESS 之后,不会再发生任何回调。 请注意,关闭请求还必须启动任何所需的刷新或取消挂起的异步请求。
注意从上述逻辑上讲,NDK 使用者不得从使用者回调函数内部调用 NDK_ADAPTER 对象(这是阻塞调用)的 NdkCloseObject。