Requisitos de duración del objeto NDKPI
Cómo se crean, usan y cierran los objetos NDK
Un consumidor de NDK inicia una solicitud de creación para un objeto NDK llamando a la función create del proveedor NDK para ese objeto.
Cuando el consumidor llama a una función create, pasa NdkCreateCompletion (NDK_FN_CREATE_COMPLETION) como parámetro.
El consumidor inicia varias solicitudes llamando a funciones de proveedor en la tabla de distribución del objeto, pasando una devolución de llamada de finalización de NdkRequestCompletion (NDK_FN_REQUEST_COMPLETION) como parámetro.
Cuando ya no se necesita un objeto, el consumidor llama a la función NdkCloseObject (NDK_FN_CLOSE_OBJECT) del proveedor para iniciar una solicitud de cierre para el objeto, pasando una devolución de llamada de NdkCloseCompletion (NDK_FN_CLOSE_COMPLETION) como parámetro.
El proveedor llama a la función de devolución de llamada del consumidor para completar la solicitud de forma asincrónica. Esta llamada indica al consumidor que el proveedor ha completado la operación (por ejemplo, cerrar el objeto) y que devuelve el control al consumidor. Si el proveedor completa la solicitud de cierre de forma sincrónica, ya sea correctamente o en error, no llamará a la función de devolución de llamada del consumidor.
Reglas para devoluciones de llamada de finalización
Cuando un proveedor ha creado un objeto a petición de un consumidor, el proveedor llama a la devolución de llamada NdkCreateCompletion del consumidor para indicar que el objeto está listo para su uso.
El consumidor puede llamar a otras funciones de proveedor para el mismo objeto sin esperar a que se devuelva la primera devolución de llamada.
El consumidor no llamará a la función NdkCloseObject para un objeto hasta que se hayan devuelto todas las funciones de proveedor de ese objeto.
Sin embargo, si la función de proveedor inicia una solicitud de finalización, el consumidor puede llamar a NdkCloseObject desde dentro de esa devolución de llamada de finalización, incluso si la función del proveedor no ha devuelto.
Una función de proveedor puede iniciar una solicitud de finalización antes de volver desde una devolución de llamada realizando una de las siguientes acciones:
- Llamar directamente a la devolución de llamada de finalización
- Puesta en cola de la solicitud de finalización a otro subproceso
Al iniciar una solicitud de finalización, el proveedor devuelve eficazmente el control al consumidor. El proveedor debe suponer que el objeto se puede cerrar en cualquier momento después de que el proveedor inicie la solicitud de finalización.
Nota Para evitar el interbloqueo después de iniciar una solicitud de finalización, el proveedor debe:
- No realice otras operaciones en el objeto hasta que se devuelva la devolución de llamada de finalización.
- Tome las medidas necesarias para mantener intacto el objeto, si el proveedor debe tocar absolutamente el objeto.
Ejemplo: interacción de Consumer-Provider
Considere el caso siguiente:
- El consumidor crea un conector (NDK_CONNECTOR) y, a continuación, llama a NdkConnect (NDK_FN_CONNECT).
- El proveedor procesa la solicitud de conexión, alcanza un error y llama a la devolución de llamada de finalización del consumidor en el contexto de la llamada a NdkConnect (en lugar de devolver un error en línea debido a una opción de implementación interna).
- El consumidor llama a NdkCloseObject en el contexto de esta devolución de llamada de finalización, aunque la llamada a NdkConnect aún no haya vuelto al consumidor.
Para evitar interbloqueos, el proveedor no debe tocar el objeto del conector después del paso 2 (el punto cuando inició la devolución de llamada de finalización dentro de la llamada a NdkConnect ).
Cerrar objetos antecedentes y sucesores
El proveedor debe estar preparado para que el consumidor llame a la función NdkCloseObject para cerrar un objeto antecedente antes de que el consumidor llame a NdkCloseObject para objetos sucesores. Si el consumidor hace esto, esto es lo que debe hacer el proveedor:
- El proveedor no debe cerrar el objeto antecedente hasta que se cierren todos los objetos sucesores, es decir, el proveedor debe devolver STATUS_PENDING de la solicitud de cierre y completarlo (llamando a la función NdkCloseCompletion registrada para la solicitud de cierre) una vez cerrados todos los objetos sucesores.
- El consumidor no usará el objeto antecedente después de llamar a NdkCloseObject en él, por lo que el proveedor no tiene que agregar ningún control para producir errores en las funciones de proveedor adicionales en el objeto antecedente (pero puede que lo elija).
- El proveedor puede tratar la solicitud de cierre como una desreferencia simple que no tiene ningún otro efecto secundario hasta que se cierre el último objeto sucesor, a menos que se requiera lo contrario (consulte el caso cercano del agente de escucha de NDK por debajo, que tiene un efecto secundario necesario).
El proveedor no debe completar la solicitud de cierre en un objeto antecedente (incluida la solicitud de cierre de NDK_ADAPTER ) antes de que cualquier devolución de llamada de finalización en curso cierre en cualquier objeto sucesor vuelva al proveedor. Esto es para permitir que los consumidores de NDK se descarguen de forma segura.
Un consumidor de NDK no llamará a NdkCloseObject para un objeto NDK_ADAPTER (que es una llamada de bloqueo) desde dentro de una función de devolución de llamada del consumidor.
Cerrar objetos de adaptador
Considere el caso siguiente:
- El consumidor llama a NdkCloseObject en un objeto de cola de finalización (CQ).
- El proveedor devuelve STATUS_PENDING y, posteriormente, llama a la devolución de llamada de finalización del consumidor.
- Dentro de esta devolución de llamada de finalización, el consumidor señala un evento que ahora está bien para cerrar el NDK_ADAPTER.
- Otro subproceso se activa sobre esta señal y cierra el NDK_ADAPTER y continúa con la descarga.
- Sin embargo, el subproceso en el que se llamó a la devolución de llamada de finalización de cierre de CQ del consumidor podría estar dentro de la función de devolución de llamada del consumidor (por ejemplo, el epílogo de función), por lo que no es seguro para que el controlador del consumidor se descargue.
- Dado que el contexto de devolución de llamada de finalización es el único contexto que el consumidor puede indicar el evento, el controlador del consumidor no puede resolver el problema de descarga segura.
Debe haber un punto en el que el consumidor pueda estar seguro de que todas sus devoluciones de llamada han devuelto el control. En NDKPI, este punto es cuando la solicitud de cierre en un NDK_ADAPTER devuelve el control . Tenga en cuenta que NDK_ADAPTER solicitud de cierre es una llamada de bloqueo. Cuando se devuelve una solicitud de cierre de NDK_ADAPTER , se garantiza que todas las devoluciones de llamada de todos los objetos que descienden de ese objeto NDK_ADAPTER hayan devuelto el control al proveedor.
Finalización de solicitudes de cierre
El proveedor no debe completar una solicitud de cierre en un objeto hasta que:
- Todas las solicitudes asincrónicas pendientes en el objeto se han completado (es decir, sus devoluciones de llamada de finalización se han devuelto al proveedor).
- Todas las devoluciones de llamada de eventos del consumidor (por ejemplo, NdkCqNotificationCallback (NDK_FN_CQ_NOTIFICATION_CALLBACK) en un CQ, NdkConnectEventCallback (NDK_FN_CONNECT_EVENT_CALLBACK) en un agente de escucha) han devuelto al proveedor.
El proveedor debe garantizar que no se producirán más devoluciones de llamada después de llamar a la devolución de llamada de finalización de cierre o después de que la solicitud de cierre devuelva STATUS_SUCCESS. Tenga en cuenta que una solicitud de cierre también debe iniciar cualquier vaciado o cancelación necesarios de solicitudes asincrónicas pendientes.
Nota Lógicamente sigue de lo anterior que un consumidor de NDK no debe llamar a NdkCloseObject para un objeto NDK_ADAPTER (que es una llamada de bloqueo) desde dentro de una función de devolución de llamada de consumidor.