From 53427df4056ee732df2aa6e472b481b3c9d7ee09 Mon Sep 17 00:00:00 2001 From: Casey Bodley Date: Wed, 11 Jan 2023 13:41:50 -0500 Subject: [PATCH] common/async: add service template for execution_context shutdown Signed-off-by: Casey Bodley --- src/common/async/detail/service.h | 75 +++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) create mode 100644 src/common/async/detail/service.h diff --git a/src/common/async/detail/service.h b/src/common/async/detail/service.h new file mode 100644 index 0000000000000..dc312d869d67b --- /dev/null +++ b/src/common/async/detail/service.h @@ -0,0 +1,75 @@ +// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- +// vim: ts=8 sw=2 smarttab +/* + * Ceph - scalable distributed file system + * + * Copyright (C) 2023 Red Hat + * + * This is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License version 2.1, as published by the Free Software + * Foundation. See file COPYING. + * + */ + +#pragma once + +#include +#include +#include + +namespace ceph::async::detail { + +struct service_tag {}; +using service_list_base_hook = boost::intrusive::list_base_hook< + boost::intrusive::tag>; + +/// Service for two-phase execution_context shutdown, which breaks ownership +/// cycles between completion handlers and their io objects. Tracks objects +/// which may have outstanding completion handlers, and calls their member +/// function service_shutdown() when the execution_context is shutting down. +/// This member function should destroy any memory associated with its +/// outstanding completion handlers. +/// +/// Requirements for IoObject: +/// * Inherits publicly from service_list_base_hook +/// * Has public member function service_shutdown() +/// * Calls add(*this) on construction and remove(*this) on destruction. +template +class service : public boost::asio::execution_context::service { + using base_hook = boost::intrusive::base_hook; + boost::intrusive::list entries; + std::mutex mutex; + + /// Called by the execution_context on shutdown + void shutdown() override { + while (!entries.empty()) { + auto& entry = entries.front(); + entries.pop_front(); + entry.service_shutdown(); + } + } + public: + using key_type = service; + static inline boost::asio::execution_context::id id; + + explicit service(boost::asio::execution_context& ctx) + : boost::asio::execution_context::service(ctx) {} + + /// Register an io object for notification of service_shutdown() + void add(IoObject& entry) { + auto lock = std::scoped_lock{mutex}; + entries.push_back(entry); + } + /// Unregister an object + void remove(IoObject& entry) { + auto lock = std::scoped_lock{mutex}; + if (entries.empty()) { + // already shut down + } else { + entries.erase(entries.iterator_to(entry)); + } + } +}; + +} // namespace ceph::async::detail -- 2.39.5