.. SPDX-FileCopyrightText: 2023-2024 Sony Semiconductor Solutions Corporation .. .. SPDX-License-Identifier: Apache-2.0 Detailed usage ************** Gracefully exit module instances ================================ The process in which the Agent stops a module is not trivial. The EVP Agent first needs to set a status on the module instance that it needs to exit. After some amount of time, if the module did not exit gracefully (by calling ``exit(3)`` or returning from ``main``), the agent will forcefully stop and kill the module. This is implemented within the module instance “supervisor”. All events in a module instance are processed by :c:func:`EVP_processEvent`. If the agent wants the module instance to exit, :c:func:`EVP_processEvent` would still dispatch any pending events. The agent would then notify the module via the event callback when an event is generated by: - :c:func:`EVP_sendState` would have :c:enumerator:`~EVP_STATE_CALLBACK_REASON.EVP_STATE_CALLBACK_REASON_EXIT` as its ``reason`` on the event callback. - :c:func:`EVP_sendTelemetry` would have :c:enumerator:`~EVP_TELEMETRY_CALLBACK_REASON.EVP_TELEMETRY_CALLBACK_REASON_EXIT` as its ``reason`` on the event callback. - :c:func:`EVP_sendMessage` would have :c:enumerator:`~EVP_MESSAGE_SENT_CALLBACK_REASON.EVP_MESSAGE_SENT_CALLBACK_REASON_EXIT` as its ``reason`` on the event callback. - :c:func:`EVP_sendRpcResponse` would have :c:enumerator:`~EVP_RPC_RESPONSE_CALLBACK_REASON.EVP_RPC_RESPONSE_CALLBACK_REASON_EXIT` as its ``reason`` on the event callback. - :c:func:`EVP_blobOperation` would have :c:enumerator:`~EVP_BLOB_CALLBACK_REASON.EVP_BLOB_CALLBACK_REASON_EXIT` as its ``reason`` on the event callback. :c:func:`EVP_processEvent` would still return ``EVP_SHOULD_EXIT`` only if there are no more events pending on the input queue to the module. When any of the ``*_REASON_EXIT`` error codes is received, the module instance must stop generating any new events, and keep calling :c:func:`EVP_processEvent` until ``EVP_SHOULD_EXIT`` is returned. This is done for the module to be able to process all the pending events before it actually exits. Some examples of functions that generate events are :c:func:`EVP_sendState`, :c:func:`EVP_sendTelemetry` and :c:func:`EVP_sendMessage`. Sample module ------------- A correct implementation of the module would be (includes and some details are omitted for clarity): .. code:: C static int stopping = 0; static void telemetry_cb(EVP_TELEMETRY_CALLBACK_REASON reason, void *userData) { static int counter = 0; if (reason == EVP_TELEMETRY_CALLBACK_REASON_EXIT) { stopping = 1; printf("Telemetry not sent, the module was requested to stop.\n"); } else { printf("Telemetry sent %d\n", counter++); } } int main() { struct EVP_telemetry_entry entries[1]; entries.key = "myKey"; entries.value = "myValue"; struct EVP_client *h = EVP_initialize(); for(;;) { // Don't add more event if the module is stopping if (!stopping) { EVP_sendTelemetry(h, entries, 1, telemetry_callback, NULL); } int ret = EVP_processEvent(h, 1000); if (ret == EVP_SHOULD_EXIT) { break; } } return 0; } When the module instance is requested to stop, :c:enumerator:`~EVP_TELEMETRY_CALLBACK_REASON.EVP_TELEMETRY_CALLBACK_REASON_EXIT` is signalled by ``telemetry_cb``, so that the module instance does not call :c:func:`EVP_sendTelemetry` anymore. Then, the module instance flushes all the events in the queue, until :c:func:`EVP_processEvent` returns ``EVP_SHOULD_EXIT``, so the module instance ``break``s and finally ``return``s from ``main``.