Anforderungen an die Lebensdauer des NDKPI-Objekts
Erstellen, Verwenden und Schließen von NDK-Objekten
Ein NDK-Consumer initiiert eine Erstellungsanforderung für ein NDK-Objekt, indem er die Create-Funktion des NDK-Anbieters für dieses Objekt aufruft.
Wenn der Consumer eine create-Funktion aufruft, übergibt er einen NdkCreateCompletion (NDK_FN_CREATE_COMPLETION) als Parameter.
Der Consumer initiiert verschiedene Anforderungen, indem er Anbieterfunktionen in der Dispatchtabelle des Objekts aufruft und einen NdkRequestCompletion-Abschlussrückruf (NDK_FN_REQUEST_COMPLETION) als Parameter übergibt.
Wenn ein Objekt nicht mehr benötigt wird, ruft der Consumer die NdkCloseObject-Funktion (NDK_FN_CLOSE_OBJECT) des Anbieters auf, um eine Close-Anforderung für das Objekt zu initiieren, wobei ein NdkCloseCompletion-Rückruf (NDK_FN_CLOSE_COMPLETION) als Parameter übergeben wird.
Der Anbieter ruft die Rückruffunktion des Consumers auf, um die Anforderung asynchron abzuschließen. Dieser Aufruf gibt dem Consumer an, dass der Anbieter den Vorgang abgeschlossen hat (z. B. das Schließen des -Objekts) und die Steuerung an den Consumer zurückgibt. Wenn der Anbieter die Close-Anforderung entweder erfolgreich oder fehlerhaft synchron abschließt, ruft er die Rückruffunktion des Consumers nicht auf.
Die Regeln für Vervollständigungsrückrufe
Wenn ein Anbieter auf Anforderung eines Consumers ein Objekt erstellt hat, ruft der Anbieter den NdkCreateCompletion-Rückruf des Consumers auf, um anzugeben, dass das Objekt einsatzbereit ist.
Der Consumer kann andere Anbieterfunktionen für dasselbe Objekt aufrufen, ohne darauf zu warten, dass der erste Rückruf zurückgegeben wird.
Der Consumer ruft die NdkCloseObject-Funktion für ein Objekt erst auf, wenn alle Anbieterfunktionen für dieses Objekt zurückgegeben wurden.
Wenn die Anbieterfunktion jedoch eine Abschlussanforderung initiiert, kann der Consumer NdkCloseObject von innerhalb dieses Abschlussrückrufs aufrufen, auch wenn die Anbieterfunktion nicht zurückgegeben wurde.
Eine Anbieterfunktion kann eine Vervollständigungsanforderung initiieren, bevor sie von einem Rückruf zurückgegeben wird, indem Sie eine der folgenden Aktionen ausführen:
- Direktes Aufrufen des Abschlussrückrufs
- Warteschlangen für die Abschlussanforderung an einen anderen Thread
Durch das Initiieren einer Vervollständigungsanforderung gibt der Anbieter effektiv die Kontrolle an den Consumer zurück. Der Anbieter muss davon ausgehen, dass das Objekt jederzeit geschlossen werden kann, nachdem der Anbieter die Vervollständigungsanforderung initiiert hat.
Hinweis Um einen Deadlock nach dem Initiieren einer Abschlussanforderung zu verhindern, muss der Anbieter entweder:
- Führen Sie keine anderen Vorgänge für das Objekt aus, bis der Abschlussrückruf zurückgibt.
- Ergreifen Sie die erforderlichen Maßnahmen, um das Objekt intakt zu halten, wenn der Anbieter das Objekt unbedingt berühren muss.
Beispiel: Consumer-Provider Interaktion
Nehmen Sie das folgende Szenario als Beispiel:
- Der Consumer erstellt einen Connector (NDK_CONNECTOR) und ruft dann NdkConnect (NDK_FN_CONNECT) auf.
- Der Anbieter verarbeitet die Verbindungsanforderung, stößt auf einen Fehler und ruft den Abschlussrückruf des Consumers im Kontext des NdkConnect-Aufrufs auf (im Gegensatz zum Zurückgeben eines Inlinefehlers aufgrund einer internen Implementierungsauswahl).
- Der Consumer ruft NdkCloseObject im Kontext dieses Abschlussrückrufs auf, obwohl der NdkConnect-Aufruf noch nicht an den Consumer zurückgegeben wurde.
Um deadlocks zu vermeiden, darf der Anbieter das Connectorobjekt nach Schritt 2 (dem Zeitpunkt, an dem er den Abschlussrückruf innerhalb des NdkConnect-Aufrufs initiiert hat) nicht berühren.
Schließen von Vorgänger- und Nachfolgerobjekten
Der Anbieter muss darauf vorbereitet sein, dass der Consumer die NdkCloseObject-Funktion aufruft, um ein vorgängers Objekt zu schließen, bevor der Consumer NdkCloseObject für Nachfolgerobjekte aufruft. Wenn der Consumer dies tut, muss der Anbieter folgendes tun:
- Der Anbieter darf das Vorgängerobjekt erst schließen, wenn alle Nachfolgerobjekte geschlossen sind, d. h. der Anbieter muss STATUS_PENDING aus der Close-Anforderung zurückgeben und abschließen (durch Aufrufen der registrierten NdkCloseCompletion-Funktion für die Close-Anforderung), sobald alle Nachfolgerobjekte geschlossen wurden.
- Der Consumer verwendet das Vorgängerobjekt nicht, nachdem er NdkCloseObject aufgerufen hat, sodass der Anbieter keine Behandlung für fehlerhafte weitere Anbieterfunktionen für das vorgängernde Objekt hinzufügen muss (dies kann jedoch möglich sein, wenn dies der Fall ist).
- Der Anbieter kann die Close-Anforderung wie eine einfache Dereferenz behandeln, die keine andere Nebenwirkung hat, bis das letzte Nachfolgeobjekt geschlossen wird, sofern nicht anders erforderlich (siehe NDK-Listener close case unten, der einen erforderlichen Nebeneffekt hat).
Der Anbieter darf die Close-Anforderung für ein vorgängers Objekt (einschließlich der NDK_ADAPTER Schließen-Anforderung) nicht abschließen, bevor ein laufender Rückruf zum Schließen des Abschlusses für ein Nachfolgeobjekt an den Anbieter zurückgegeben wird. Dadurch können NDK-Consumer sicher entladen werden.
Ein NDK-Consumer ruft NdkCloseObject nicht für ein NDK_ADAPTER -Objekt (bei dem es sich um einen blockierenden Aufruf) innerhalb einer Consumerrückruffunktion handelt.
Schließen von Adapterobjekten
Nehmen Sie das folgende Szenario als Beispiel:
- Der Consumer ruft NdkCloseObject für ein CQ-Objekt (Completion Queue) auf.
- Der Anbieter gibt STATUS_PENDING zurück und ruft später den Abschlussrückruf des Consumers auf.
- Innerhalb dieses Abschlussrückrufs signalisiert der Consumer einem Ereignis, dass es nun IN ORDNUNG ist, die NDK_ADAPTER zu schließen.
- Ein anderer Thread wird bei diesem Signal aktiviert, schließt die NDK_ADAPTER und fährt mit dem Entladen fort.
- Der Thread, in dem der CQ-Abschlussrückruf des Consumers aufgerufen wurde, kann sich jedoch noch innerhalb der Rückruffunktion des Consumers befinden (z. B. das Funktionsepilog), sodass das Entladen des Consumertreibers nicht sicher ist.
- Da der Abschlussrückrufkontext der einzige Kontext ist, den der Consumer für das Ereignis signalisieren kann, kann der Consumertreiber das Problem mit dem sicheren Entladen nicht selbst lösen.
Es muss einen Punkt geben, an dem der Consumer sicher sein kann, dass alle Rückrufe die Kontrolle zurückgegeben haben. In NDKPI ist dieser Punkt, wenn die Close-Anforderung für eine NDK_ADAPTER die Steuerung zurückgibt. Beachten Sie, dass NDK_ADAPTER Schließen der Anforderung ein blockierende Aufruf ist. Wenn eine NDK_ADAPTER Schließen-Anforderung zurückgegeben wird, wird garantiert, dass alle Rückrufe für alle Objekte, die von diesem NDK_ADAPTER -Objekt abstammen, die Steuerung an den Anbieter zurückgegeben haben.
Abschließen von Close Requests
Der Anbieter darf eine Close-Anforderung für ein Objekt erst abschließen, wenn:
- Alle ausstehenden asynchronen Anforderungen für das Objekt wurden abgeschlossen (d. h. ihre Abschlussrückrufe wurden an den Anbieter zurückgegeben).
- Alle Ereignisrückrufe des Consumers (z. B. NdkCqNotificationCallback (NDK_FN_CQ_NOTIFICATION_CALLBACK) für einen CQ, NdkConnectEventCallback (NDK_FN_CONNECT_EVENT_CALLBACK) auf einem Listener) wurden an den Anbieter zurückgegeben.
Der Anbieter muss garantieren, dass nach dem Aufruf des Rückrufs zum Abschluss des Abschlusses oder nach dem Zurückgeben STATUS_SUCCESS durch die Schließenanforderung keine Rückrufe mehr erfolgen. Beachten Sie, dass eine close-Anforderung auch alle erforderlichen Leerungen oder Abbrüche von ausstehenden asynchronen Anforderungen initiieren muss.
Hinweis Logisch folgt aus dem obigen, dass ein NDK-Consumer NdkCloseObject nicht für ein NDK_ADAPTER-Objekt (bei dem es sich um einen blockierenden Aufruf) innerhalb einer Consumerrückruffunktion handelt.