Требования к времени существования объекта 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 не будет вызывать NdkCloseObject для объекта NDK_ADAPTER (который является блокирующим вызовом) из функции обратного вызова потребителя.

Закрытие объектов адаптера

Рассмотрим следующий сценарий.

  1. Потребитель вызывает NdkCloseObject для объекта очереди завершения (CQ).
  2. Поставщик возвращает STATUS_PENDING, а затем вызывает обратный вызов завершения потребителя.
  3. Внутри этого обратного вызова завершения потребитель сообщает событию, что теперь можно закрыть NDK_ADAPTER.
  4. Другой поток просыпается после этого сигнала, закрывает NDK_ADAPTER и переходит к выгрузке.
  5. Тем не менее поток, в котором был вызван обратный вызов завершения CQ close, может по-прежнему находиться внутри функции обратного вызова потребителя (например, эпилог функции), поэтому драйвер потребителя не может выгрузить его.
  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 не должен вызывать NdkCloseObject для объекта NDK_ADAPTER (который является блокирующим вызовом) из функции обратного вызова потребителя.

Сетевой интерфейс поставщика ядра (NDKPI)