From b17c9d6ee418750a5b7bdd31b08a7ce2f504f8bc Mon Sep 17 00:00:00 2001 From: Michael Haselton Date: Thu, 3 Apr 2025 21:43:29 -0400 Subject: [PATCH] ipc: Add IPC server client connection callbacks Part-of: --- src/xrt/ipc/server/ipc_server.h | 12 +++++++++ src/xrt/ipc/server/ipc_server_interface.h | 18 +++++++++++++ .../ipc/server/ipc_server_per_client_thread.c | 26 ++++++++++++++++--- src/xrt/ipc/server/ipc_server_process.c | 26 +++++++++++++++++-- .../targets/service-lib/service_target.cpp | 14 ++++++++++ 5 files changed, 91 insertions(+), 5 deletions(-) diff --git a/src/xrt/ipc/server/ipc_server.h b/src/xrt/ipc/server/ipc_server.h index 1dceaa95b..7bda606d3 100644 --- a/src/xrt/ipc/server/ipc_server.h +++ b/src/xrt/ipc/server/ipc_server.h @@ -24,6 +24,8 @@ #include "shared/ipc_protocol.h" #include "shared/ipc_message_channel.h" +#include "ipc_server_interface.h" + #include @@ -411,6 +413,16 @@ struct ipc_server struct os_mutex lock; } global_state; + + /*! + * Callbacks for server events. + */ + const struct ipc_server_callbacks *callbacks; + + /*! + * User data passed to callbacks. + */ + void *callback_data; }; /*! diff --git a/src/xrt/ipc/server/ipc_server_interface.h b/src/xrt/ipc/server/ipc_server_interface.h index d5883b098..b1572cb49 100644 --- a/src/xrt/ipc/server/ipc_server_interface.h +++ b/src/xrt/ipc/server/ipc_server_interface.h @@ -73,6 +73,24 @@ struct ipc_server_callbacks * @param[in] data User data given passed into the main function. */ void (*mainloop_leaving)(struct ipc_server *s, struct xrt_instance *xinst, void *data); + + /*! + * A new client has connected to the IPC server. + * + * param s The IPC server. + * param client_id The ID of the newly connected client. + * param data User data given passed into the main function. + */ + void (*client_connected)(struct ipc_server *s, uint32_t client_id, void *data); + + /*! + * A client has disconnected from the IPC server. + * + * param s The IPC server. + * param client_id The ID of the newly connected client. + * param data User data given passed into the main function. + */ + void (*client_disconnected)(struct ipc_server *s, uint32_t client_id, void *data); }; /*! diff --git a/src/xrt/ipc/server/ipc_server_per_client_thread.c b/src/xrt/ipc/server/ipc_server_per_client_thread.c index f2f447b26..b663c9e73 100644 --- a/src/xrt/ipc/server/ipc_server_per_client_thread.c +++ b/src/xrt/ipc/server/ipc_server_per_client_thread.c @@ -1,4 +1,5 @@ // Copyright 2020-2023, Collabora, Ltd. +// Copyright 2025, NVIDIA CORPORATION. // SPDX-License-Identifier: BSL-1.0 /*! * @file @@ -200,7 +201,11 @@ client_loop(volatile struct ipc_client_state *ics) { U_TRACE_SET_THREAD_NAME("IPC Client"); - IPC_INFO(ics->server, "Client %u connected", ics->client_state.id); + // Call the client connected callback. + ics->server->callbacks->client_connected( // + ics->server, // + ics->client_state.id, // + ics->server->callback_data); // // Claim the client fd. int epoll_fd = setup_epoll(ics); @@ -231,7 +236,6 @@ client_loop(volatile struct ipc_client_state *ics) // Detect clients disconnecting gracefully. if (ret > 0 && (event.events & EPOLLHUP) != 0) { - IPC_INFO(ics->server, "Client disconnected."); break; } @@ -274,6 +278,12 @@ client_loop(volatile struct ipc_client_state *ics) close(epoll_fd); epoll_fd = -1; + // Call the client disconnected callback. + ics->server->callbacks->client_disconnected( // + ics->server, // + ics->client_state.id, // + ics->server->callback_data); // + // Following code is same for all platforms. common_shutdown(ics); } @@ -297,7 +307,11 @@ client_loop(volatile struct ipc_client_state *ics) { U_TRACE_SET_THREAD_NAME("IPC Client"); - IPC_INFO(ics->server, "Client connected"); + // Call the client connected callback. + ics->server->callbacks->client_connected( // + ics->server, // + ics->client_state.id, // + ics->server->callback_data); // while (ics->server->running) { uint8_t buf[IPC_BUF_SIZE] = {0}; @@ -354,6 +368,12 @@ client_loop(volatile struct ipc_client_state *ics) } } + // Call the client disconnected callback. + ics->server->callbacks->client_disconnected( // + ics->server, // + ics->client_state.id, // + ics->server->callback_data); // + // Following code is same for all platforms. common_shutdown(ics); } diff --git a/src/xrt/ipc/server/ipc_server_process.c b/src/xrt/ipc/server/ipc_server_process.c index 96eadd01d..84277c58d 100644 --- a/src/xrt/ipc/server/ipc_server_process.c +++ b/src/xrt/ipc/server/ipc_server_process.c @@ -462,7 +462,11 @@ init_server_state(struct ipc_server *s) } static xrt_result_t -init_all(struct ipc_server *s, enum u_logging_level log_level, bool exit_on_disconnect) +init_all(struct ipc_server *s, + enum u_logging_level log_level, + const struct ipc_server_callbacks *callbacks, + void *callback_data, + bool exit_on_disconnect) { xrt_result_t xret = XRT_SUCCESS; int ret; @@ -470,6 +474,10 @@ init_all(struct ipc_server *s, enum u_logging_level log_level, bool exit_on_disc // First order of business set the log level. s->log_level = log_level; + // Store callbacks and data + s->callbacks = callbacks; + s->callback_data = callback_data; + // This should never fail. ret = os_mutex_init(&s->global_state.lock); if (ret < 0) { @@ -1074,7 +1082,7 @@ ipc_server_main_common(const struct ipc_server_main_info *ismi, */ u_debug_gui_create(&ismi->udgci, &s->debug_gui); - xret = init_all(s, log_level, ismi->exit_on_disconnect); + xret = init_all(s, log_level, callbacks, data, ismi->exit_on_disconnect); U_LOG_CHK_ONLY_PRINT(log_level, xret, "init_all"); if (xret != XRT_SUCCESS) { // Propegate the failure. @@ -1148,6 +1156,18 @@ mainloop_leaving(struct ipc_server *s, struct xrt_instance *xinst, void *data) // No-op } +void +client_connected(struct ipc_server *s, uint32_t client_id, void *data) +{ + IPC_INFO(s, "Client %u connected", client_id); +} + +void +client_disconnected(struct ipc_server *s, uint32_t client_id, void *data) +{ + IPC_INFO(s, "Client %u disconnected", client_id); +} + int ipc_server_main(int argc, char **argv, const struct ipc_server_main_info *ismi) { @@ -1155,6 +1175,8 @@ ipc_server_main(int argc, char **argv, const struct ipc_server_main_info *ismi) .init_failed = init_failed, .mainloop_entering = mainloop_entering, .mainloop_leaving = mainloop_leaving, + .client_connected = client_connected, + .client_disconnected = client_disconnected, }; return ipc_server_main_common(ismi, &callbacks, NULL); diff --git a/src/xrt/targets/service-lib/service_target.cpp b/src/xrt/targets/service-lib/service_target.cpp index 92d47d396..839e87c9f 100644 --- a/src/xrt/targets/service-lib/service_target.cpp +++ b/src/xrt/targets/service-lib/service_target.cpp @@ -78,6 +78,18 @@ public: // No-op } + static void + signalClientConnectedTrampoline(struct ipc_server *s, uint32_t client_id, void *data) + { + // No-op + } + + static void + signalClientDisconnectedTrampoline(struct ipc_server *s, uint32_t client_id, void *data) + { + // No-op + } + int32_t addClient(int fd) { @@ -140,6 +152,8 @@ private: .init_failed = signalInitFailed, .mainloop_entering = signalStartupCompleteTrampoline, .mainloop_leaving = signalShuttingDownTrampoline, + .client_connected = signalClientConnectedTrampoline, + .client_disconnected = signalClientDisconnectedTrampoline, }; //! Reference to the ipc_server, managed by ipc_server_process -- 2.51.2