Requisiti di durata dell'oggetto NDKPI
Modalità di creazione, utilizzo e chiusura degli oggetti NDK
Un consumer NDK avvia una richiesta di creazione per un oggetto NDK chiamando la funzione di creazione del provider NDK per tale oggetto.
Quando il consumer chiama una funzione create, passa un oggetto NdkCreateCompletion (NDK_FN_CREATE_COMPLETION) come parametro.
Il consumer avvia varie richieste chiamando le funzioni del provider nella tabella dispatch dell'oggetto, passando un callback di completamento NdkRequestCompletion (NDK_FN_REQUEST_COMPLETION) come parametro.
Quando un oggetto non è più necessario, il consumer chiama la funzione NdkCloseObject (NDK_FN_CLOSE_OBJECT) del provider per avviare una richiesta di chiusura per l'oggetto, passando un callback NdkCloseCompletion (NDK_FN_CLOSE_COMPLETION) come parametro.
Il provider chiama la funzione di callback del consumer per completare la richiesta in modo asincrono. Questa chiamata indica al consumer che il provider ha completato l'operazione (ad esempio, chiudendo l'oggetto) e restituendo il controllo al consumer. Se il provider completa la richiesta di chiusura in modo sincrono, correttamente o in errore, non chiamerà la funzione di callback del consumer.
Regole per i callback di completamento
Quando un provider ha creato un oggetto alla richiesta di un consumer, il provider chiama il callback NdkCreateCompletion del consumer per indicare che l'oggetto è pronto per l'uso.
Il consumer può chiamare altre funzioni del provider per lo stesso oggetto senza attendere che venga restituito il primo callback.
Il consumer non chiamerà la funzione NdkCloseObject per un oggetto finché non vengono restituite tutte le funzioni del provider per tale oggetto.
Tuttavia, se la funzione provider avvia una richiesta di completamento, il consumer è libero di chiamare NdkCloseObject dall'interno del callback di completamento, anche se la funzione del provider non è stata restituita.
Una funzione del provider può avviare una richiesta di completamento prima di restituire da un callback eseguendo una delle operazioni seguenti:
- Chiamata diretta del callback di completamento
- Accodamento della richiesta di completamento a un altro thread
Avviando una richiesta di completamento, il provider restituisce effettivamente il controllo al consumer. Il provider deve presupporre che l'oggetto possa essere chiuso in qualsiasi momento dopo che il provider avvia la richiesta di completamento.
Nota Per evitare deadlock dopo l'avvio di una richiesta di completamento, il provider deve:
- Non eseguire altre operazioni sull'oggetto fino a quando non viene restituito il callback di completamento.
- Adottare le misure necessarie per mantenere intatto l'oggetto, se il provider deve assolutamente toccare l'oggetto.
Esempio: interazione Consumer-Provider
Si consideri lo scenario seguente:
- Il consumer crea un connettore (NDK_CONNECTOR) e quindi chiama NdkConnect (NDK_FN_CONNECT).
- Il provider elabora la richiesta di connessione, raggiunge un errore e chiama il callback di completamento del consumer nel contesto della chiamata NdkConnect (anziché restituire un errore inline a causa di una scelta di implementazione interna).
- Il consumer chiama NdkCloseObject nel contesto di questo callback di completamento, anche se la chiamata NdkConnect non è stata ancora restituita al consumer.
Per evitare deadlock, il provider non deve toccare l'oggetto connettore dopo il passaggio 2 (il punto in cui ha avviato il callback di completamento all'interno della chiamata a NdkConnect ).
Chiusura di oggetti antecedent e successori
Il provider deve essere preparato affinché il consumer chiami la funzione NdkCloseObject per chiudere un oggetto precedente prima che il consumer chiami NdkCloseObject per gli oggetti successori. Se il consumer esegue questa operazione, ecco cosa deve fare il provider:
- Il provider non deve chiudere l'oggetto precedente finché tutti gli oggetti successori non vengono chiusi, ad esempio, il provider deve restituire STATUS_PENDING dalla richiesta di chiusura e completarlo (chiamando la funzione NdkCloseCompletion registrata per la richiesta di chiusura) una volta chiusi tutti gli oggetti successori.
- Il consumer non userà l'oggetto precedente dopo aver chiamato NdkCloseObject su di esso, pertanto il provider non deve aggiungere alcuna gestione per l'esito negativo di ulteriori funzioni del provider nell'oggetto precedente , ma può essere se sceglie di.
- Il provider può trattare la richiesta di chiusura come una semplice dereferenziazione che non ha un altro effetto collaterale fino alla chiusura dell'ultimo oggetto successore, a meno che non sia necessario il caso di chiusura del listener NDK riportato di seguito con un effetto collaterale obbligatorio.
Il provider non deve completare la richiesta di chiusura su un oggetto precedente (incluso il NDK_ADAPTER richiesta di chiusura) prima che qualsiasi callback di completamento di chiusura in corso su qualsiasi oggetto successore restituisca al provider. Ciò consente ai consumer di NDK di scaricare in modo sicuro.
Un consumer NDK non chiamerà NdkCloseObject per un oggetto NDK_ADAPTER (che è una chiamata di blocco) dall'interno di una funzione di callback consumer.
Oggetti adapter di chiusura
Si consideri lo scenario seguente:
- Il consumer chiama NdkCloseObject su un oggetto CQ (Completion Queue).
- Il provider restituisce STATUS_PENDING e successivamente chiama il callback di completamento del consumer.
- All'interno di questo callback di completamento, il consumer segnala un evento che è ora OK per chiudere il NDK_ADAPTER.
- Un altro thread si sveglia su questo segnale e chiude il NDK_ADAPTER e continua a scaricare.
- Tuttavia, il thread in cui è stato chiamato il callback di completamento di chiusura CQ del consumer potrebbe ancora trovarsi all'interno della funzione di callback del consumer (ad esempio, l'epilogo della funzione), quindi non è sicuro che il driver consumer scarichi.
- Poiché il contesto di callback di completamento è l'unico contesto che il consumer può segnalare l'evento, il driver consumer non può risolvere il problema di scaricamento sicuro stesso.
Deve esserci un punto in cui il consumer può essere assicurato che tutti i relativi callback abbiano restituito il controllo. In NDKPI questo punto è quando la richiesta di chiusura in un NDK_ADAPTER restituisce il controllo . Si noti che NDK_ADAPTER richiesta di chiusura è una chiamata di blocco. Quando viene restituita una richiesta di chiusura NDK_ADAPTER , è garantito che tutti i callback in tutti gli oggetti che derivano da tale oggetto NDK_ADAPTER abbiano restituito il controllo al provider.
Completamento delle richieste di chiusura
Il provider non deve completare una richiesta di chiusura su un oggetto fino a quando:
- Tutte le richieste asincrone in sospeso sull'oggetto sono state completate( in altre parole, i callback di completamento sono stati restituiti al provider).
- Tutti i callback dell'evento del consumer (ad esempio , NdkCqNotificationCallback (NDK_FN_CQ_NOTIFICATION_CALLBACK) in un CQ, NdkConnectEventCallback (NDK_FN_CONNECT_EVENT_CALLBACK) in un listener) sono stati restituiti al provider.
Il provider deve garantire che non vengano eseguiti più callback dopo la chiamata al callback di completamento di chiusura o dopo che la richiesta di chiusura restituisce STATUS_SUCCESS. Si noti che una richiesta di chiusura deve anche avviare qualsiasi scaricamento o annullamento necessario di richieste asincrone in sospeso.
Nota Segue logicamente da quanto sopra riportato che un consumer NDK non deve chiamare NdkCloseObject per un oggetto NDK_ADAPTER (che è una chiamata di blocco) dall'interno di una funzione di callback del consumer.