diff --git a/include/zenoh/api.hxx b/include/zenoh/api.hxx index 9f9bd9f7..0ddbd5bb 100644 --- a/include/zenoh/api.hxx +++ b/include/zenoh/api.hxx @@ -33,6 +33,9 @@ #include "api/reply.hxx" #include "api/sample.hxx" #include "api/scout.hxx" +#if defined(ZENOHCXX_ZENOHC) && defined(Z_FEATURE_UNSTABLE_API) +#include "api/close.hxx" +#endif #include "api/session.hxx" #include "api/subscriber.hxx" #include "api/timestamp.hxx" diff --git a/include/zenoh/api/close.hxx b/include/zenoh/api/close.hxx new file mode 100644 index 00000000..9cb0c8b1 --- /dev/null +++ b/include/zenoh/api/close.hxx @@ -0,0 +1,38 @@ + +// +// Copyright (c) 2025 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, + +#pragma once + +#if defined(ZENOHCXX_ZENOHC) && defined(Z_FEATURE_UNSTABLE_API) + +namespace zenoh { + +/// A close operation handle. +class CloseHandle : public Owned<::zc_owned_concurrent_close_handle_t> { + friend class Session; + CloseHandle(zenoh::detail::null_object_t) : Owned(nullptr){}; + + public: + /// @brief Blocks until corresponding close operation completes. + /// @param err if not null, the result code will be written to this location, otherwise ZException exception will be + /// thrown in case of error. + void wait(ZResult* err = nullptr) { + __ZENOH_RESULT_CHECK(zc_concurrent_close_handle_wait(interop::as_moved_c_ptr(*this)), err, + "Failed to wait for close operation"); + } +}; + +} // namespace zenoh + +#endif diff --git a/include/zenoh/api/session.hxx b/include/zenoh/api/session.hxx index 3d52a7ab..bfb9d336 100644 --- a/include/zenoh/api/session.hxx +++ b/include/zenoh/api/session.hxx @@ -36,6 +36,9 @@ #if defined(ZENOHCXX_ZENOHC) && defined(Z_FEATURE_SHARED_MEMORY) && defined(Z_FEATURE_UNSTABLE_API) #include "shm/client_storage/client_storage.hxx" #endif +#if defined(ZENOHCXX_ZENOHC) && defined(Z_FEATURE_UNSTABLE_API) +#include "close.hxx" +#endif namespace zenoh { namespace ext { @@ -63,6 +66,14 @@ class Session : public Owned<::z_owned_session_t> { /// @brief Options to be passed when closing a ``Session``. struct SessionCloseOptions { +#if defined(ZENOHCXX_ZENOHC) && defined(Z_FEATURE_UNSTABLE_API) + /// The timeout for close operation in milliseconds. 0 means default close timeout which is 10 seconds. + uint32_t timeout_ms = 10000; + /// A function to receive close handle. If set, the close operation will be executed concurrently + /// in separate task, and this function will receive a handle to be used for controlling + /// close execution. + std::function out_concurrent = nullptr; +#endif /// @name Fields static SessionCloseOptions create_default() { return {}; } }; @@ -1129,8 +1140,23 @@ class Session : public Owned<::z_owned_session_t> { /// @param err if not null, the result code will be written to this location, otherwise ZException exception will be /// thrown in case of error. void close(SessionCloseOptions&& options = SessionCloseOptions::create_default(), ZResult* err = nullptr) { +#if defined(ZENOHCXX_ZENOHC) && defined(Z_FEATURE_UNSTABLE_API) + CloseHandle close_handle(zenoh::detail::null_object); + ::z_close_options_t close_opts; + ::z_close_options_default(&close_opts); + close_opts.internal_timeout_ms = options.timeout_ms; + if (options.out_concurrent) { + close_opts.internal_out_concurrent = &close_handle._0; + } + __ZENOH_RESULT_CHECK(::z_close(interop::as_loaned_c_ptr(*this), &close_opts), err, + "Failed to close the session"); + if (options.out_concurrent && (!err || *err == Z_OK)) { + options.out_concurrent(std::move(close_handle)); + } +#else (void)options; __ZENOH_RESULT_CHECK(::z_close(interop::as_loaned_c_ptr(*this), nullptr), err, "Failed to close the session"); +#endif } /// @brief Check if session is closed. diff --git a/tests/zenohc/close.cxx b/tests/zenohc/close.cxx new file mode 100644 index 00000000..1fc4791a --- /dev/null +++ b/tests/zenohc/close.cxx @@ -0,0 +1,54 @@ +// +// Copyright (c) 2022 ZettaScale Technology +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 +// which is available at https://www.apache.org/licenses/LICENSE-2.0. +// +// SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 +// +// Contributors: +// ZettaScale Zenoh Team, +// + +#include "zenoh.hxx" + +using namespace zenoh; + +#undef NDEBUG +#include + +void test_session_close_in_drop() { auto session = Session::open(Config::create_default()); } + +void test_session_close() { + auto session = Session::open(Config::create_default()); + session.close(); +} + +#if defined(ZENOHCXX_ZENOHC) && defined(Z_FEATURE_UNSTABLE_API) +void test_session_close_in_background() { + auto session = Session::open(Config::create_default()); + + bool close_called = false; + auto close_options = Session::SessionCloseOptions::create_default(); + close_options.out_concurrent = [&close_called](CloseHandle&& h) { + h.wait(); + close_called = true; + }; + + session.close(std::move(close_options)); + + if (!close_called) { + exit(-1); + } +} +#endif + +int main() { + test_session_close_in_drop(); + test_session_close(); +#if defined(ZENOHCXX_ZENOHC) && defined(Z_FEATURE_UNSTABLE_API) + test_session_close_in_background(); +#endif +} \ No newline at end of file diff --git a/zenoh-c b/zenoh-c index 94a4fe36..f035a112 160000 --- a/zenoh-c +++ b/zenoh-c @@ -1 +1 @@ -Subproject commit 94a4fe36c44c0f48acb797db50724adc85161d7e +Subproject commit f035a1121bff576c72bbc26a9c38a96eb568da21