Skip to content

Commit

Permalink
Add asio::config.
Browse files Browse the repository at this point in the history
The asio::config class provides access to configuration variables that
are associated with an execution context. The class is intended for use
by asio internals, or by libraries or user-provided abstractions that
build on top of asio. These configuration variables will typically be
used to fine tune behaviour, such as enabling or disabling certain
optimisations.

When constructing an execution context, such as an io_context, the
caller may optionally pass a service_maker to install a concrete
configuration service into the context. For example:

  asio::io_context ctx{asio::config_from_env{}};

The configuration variables' values are accessed by using the
asio::config class, passing a section, key and default value:

  asio::config cfg{ctx};
  bool enable_locking = cfg.get("scheduler", "locking", true);

The initial set of configuration variables recognised by the asio
internals correspond to the concurrency hint and its special values:

  "scheduler" / "concurrency_hint" (int)
  "scheduler" / "locking" (bool)
  "reactor" / "registration_locking" (bool)
  "reactor" / "io_locking" (bool)
  • Loading branch information
chriskohlhoff committed Oct 30, 2024
1 parent 387aa3b commit 79163e4
Show file tree
Hide file tree
Showing 30 changed files with 750 additions and 66 deletions.
3 changes: 3 additions & 0 deletions asio/include/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ nobase_include_HEADERS = \
asio/completion_condition.hpp \
asio/compose.hpp \
asio/composed.hpp \
asio/config.hpp \
asio/connect.hpp \
asio/connect_pipe.hpp \
asio/consign.hpp \
Expand Down Expand Up @@ -426,6 +427,8 @@ nobase_include_HEADERS = \
asio/impl/cancel_at.hpp \
asio/impl/cancellation_signal.ipp \
asio/impl/co_spawn.hpp \
asio/impl/config.hpp \
asio/impl/config.ipp \
asio/impl/connect.hpp \
asio/impl/connect_pipe.hpp \
asio/impl/connect_pipe.ipp \
Expand Down
1 change: 1 addition & 0 deletions asio/include/asio.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@
#include "asio/completion_condition.hpp"
#include "asio/compose.hpp"
#include "asio/composed.hpp"
#include "asio/config.hpp"
#include "asio/connect.hpp"
#include "asio/connect_pipe.hpp"
#include "asio/consign.hpp"
Expand Down
193 changes: 193 additions & 0 deletions asio/include/asio/config.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,193 @@
//
// config.hpp
// ~~~~~~~~~~
//
// Copyright (c) 2003-2024 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef ASIO_CONFIG_HPP
#define ASIO_CONFIG_HPP

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)

#include "asio/detail/config.hpp"
#include "asio/detail/throw_exception.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/execution_context.hpp"
#include <cstddef>
#include <string>

#include "asio/detail/push_options.hpp"

namespace asio {

/// Base class for configuration implementations.
class config_service :
#if defined(GENERATING_DOCUMENTATION)
public execution_context::service
#else // defined(GENERATING_DOCUMENTATION)
public detail::execution_context_service_base<config_service>
#endif // defined(GENERATING_DOCUMENTATION)
{
public:
#if defined(GENERATING_DOCUMENTATION)
typedef config_service key_type;
#endif // defined(GENERATING_DOCUMENTATION)

/// Constructor.
ASIO_DECL explicit config_service(execution_context& ctx);

/// Shutdown the service.
ASIO_DECL void shutdown() override;

/// Retrieve a configuration value.
ASIO_DECL virtual const char* get_value(const char* section,
const char* key, char* value, std::size_t value_len) const;
};

/// Provides access to the configuration values associated with an execution
/// context.
class config
{
public:
/// Constructor.
/**
* This constructor initialises a @c config object to retrieve configuration
* values associated with the specified execution context.
*/
explicit config(execution_context& context)
: service_(use_service<config_service>(context))
{
}

/// Copy constructor.
config(const config& other) noexcept
: service_(other.service_)
{
}

/// Retrieve an integral configuration value.
template <typename T>
constraint_t<is_integral<T>::value, T>
get(const char* section, const char* key, T default_value) const;

private:
config_service& service_;
};

/// Configures an execution context based on a concurrency hint.
/**
* This configuration service is provided for backwards compatibility with
* the existing concurrency hint mechanism.
*
* @par Example
* @code asio::io_context my_io_context{
* asio::config_from_concurrency_hint{1}}; @endcode
*/
class config_from_concurrency_hint : public execution_context::service_maker
{
public:
/// Construct with a default concurrency hint.
ASIO_DECL config_from_concurrency_hint();

/// Construct with a specified concurrency hint.
explicit config_from_concurrency_hint(int concurrency_hint)
: concurrency_hint_(concurrency_hint)
{
}

/// Add a concrete service to the specified execution context.
ASIO_DECL void make(execution_context& ctx) const override;

private:
int concurrency_hint_;
};

/// Configures an execution context by reading variables from a string.
/**
* Each variable must be on a line of its own, and of the form:
*
* <tt>section.key=value</tt>
*
* or, if an optional prefix is specified:
*
* <tt>prefix.section.key=value</tt>
*
* Blank lines and lines starting with <tt>#</tt> are ignored. It is also
* permitted to include a comment starting with <tt>#</tt> after the value.
*
* @par Example
* @code asio::io_context my_io_context{
* asio::config_from_string{
* "scheduler.concurrency_hint=10\n
* "scheduler.locking=1"}}; @endcode
*/
class config_from_string : public execution_context::service_maker
{
public:
/// Construct with the default prefix "asio".
explicit config_from_string(std::string s)
: string_(static_cast<std::string&&>(s)),
prefix_()
{
}

/// Construct with a specified prefix.
config_from_string(std::string s, std::string prefix)
: string_(static_cast<std::string&&>(s)),
prefix_(static_cast<std::string&&>(prefix))
{
}

/// Add a concrete service to the specified execution context.
ASIO_DECL void make(execution_context& ctx) const override;

private:
std::string string_;
std::string prefix_;
};

/// Configures an execution context by reading environment variables.
/**
* The environment variable names are formed by concatenating the prefix,
* section, and key, with underscore as delimiter, and then converting the
* resulting string to upper case.
*
* @par Example
* @code asio::io_context my_io_context{
* asio::config_from_env{"my_app"}}; @endcode
*/
class config_from_env : public execution_context::service_maker
{
public:
/// Construct with the default prefix "asio".
ASIO_DECL config_from_env();

/// Construct with a specified prefix.
explicit config_from_env(std::string prefix)
: prefix_(static_cast<std::string&&>(prefix))
{
}

/// Add a concrete service to the specified execution context.
ASIO_DECL void make(execution_context& ctx) const override;

private:
std::string prefix_;
};

} // namespace asio

#include "asio/detail/pop_options.hpp"

#include "asio/impl/config.hpp"
#if defined(ASIO_HEADER_ONLY)
# include "asio/impl/config.ipp"
#endif // defined(ASIO_HEADER_ONLY)

#endif // ASIO_CONFIG_HPP
3 changes: 3 additions & 0 deletions asio/include/asio/detail/epoll_reactor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,9 @@ class epoll_reactor
// Whether the service has been shut down.
bool shutdown_;

// Whether I/O locking is enabled.
const bool io_locking_;

// Mutex to protect access to the registered descriptors.
mutex registered_descriptors_mutex_;

Expand Down
8 changes: 4 additions & 4 deletions asio/include/asio/detail/impl/epoll_reactor.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

#include <cstddef>
#include <sys/epoll.h>
#include "asio/config.hpp"
#include "asio/detail/epoll_reactor.hpp"
#include "asio/detail/scheduler.hpp"
#include "asio/detail/throw_error.hpp"
Expand All @@ -38,12 +39,12 @@ namespace detail {
epoll_reactor::epoll_reactor(asio::execution_context& ctx)
: execution_context_service_base<epoll_reactor>(ctx),
scheduler_(use_service<scheduler>(ctx)),
mutex_(ASIO_CONCURRENCY_HINT_IS_LOCKING(
REACTOR_REGISTRATION, scheduler_.concurrency_hint())),
mutex_(config(ctx).get("reactor", "registration_locking", true)),
interrupter_(),
epoll_fd_(do_epoll_create()),
timer_fd_(do_timerfd_create()),
shutdown_(false),
io_locking_(config(ctx).get("reactor", "io_locking", true)),
registered_descriptors_mutex_(mutex_.enabled())
{
// Add the interrupter's descriptor to epoll.
Expand Down Expand Up @@ -663,8 +664,7 @@ int epoll_reactor::do_timerfd_create()
epoll_reactor::descriptor_state* epoll_reactor::allocate_descriptor_state()
{
mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
return registered_descriptors_.alloc(ASIO_CONCURRENCY_HINT_IS_LOCKING(
REACTOR_IO, scheduler_.concurrency_hint()));
return registered_descriptors_.alloc(io_locking_);
}

void epoll_reactor::free_descriptor_state(epoll_reactor::descriptor_state* s)
Expand Down
8 changes: 3 additions & 5 deletions asio/include/asio/detail/impl/io_uring_service.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,13 @@ namespace detail {
io_uring_service::io_uring_service(asio::execution_context& ctx)
: execution_context_service_base<io_uring_service>(ctx),
scheduler_(use_service<scheduler>(ctx)),
mutex_(ASIO_CONCURRENCY_HINT_IS_LOCKING(
REACTOR_REGISTRATION, scheduler_.concurrency_hint())),
mutex_(config(ctx).get("reactor", "registration_locking", true)),
outstanding_work_(0),
submit_sqes_op_(this),
pending_sqes_(0),
pending_submit_sqes_op_(false),
shutdown_(false),
io_locking_(config(ctx).get("reactor", "io_locking", true)),
timeout_(),
registration_mutex_(mutex_.enabled()),
reactor_(use_service<reactor>(ctx)),
Expand Down Expand Up @@ -612,9 +612,7 @@ void io_uring_service::register_with_reactor()
io_uring_service::io_object* io_uring_service::allocate_io_object()
{
mutex::scoped_lock registration_lock(registration_mutex_);
return registered_io_objects_.alloc(
ASIO_CONCURRENCY_HINT_IS_LOCKING(
REACTOR_IO, scheduler_.concurrency_hint()));
return registered_io_objects_.alloc(io_locking_);
}

void io_uring_service::free_io_object(io_uring_service::io_object* io_obj)
Expand Down
8 changes: 4 additions & 4 deletions asio/include/asio/detail/impl/kqueue_reactor.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

#if defined(ASIO_HAS_KQUEUE)

#include "asio/config.hpp"
#include "asio/detail/kqueue_reactor.hpp"
#include "asio/detail/scheduler.hpp"
#include "asio/detail/throw_error.hpp"
Expand All @@ -46,11 +47,11 @@ namespace detail {
kqueue_reactor::kqueue_reactor(asio::execution_context& ctx)
: execution_context_service_base<kqueue_reactor>(ctx),
scheduler_(use_service<scheduler>(ctx)),
mutex_(ASIO_CONCURRENCY_HINT_IS_LOCKING(
REACTOR_REGISTRATION, scheduler_.concurrency_hint())),
mutex_(config(ctx).get("reactor", "registration_locking", true)),
kqueue_fd_(do_kqueue_create()),
interrupter_(),
shutdown_(false),
io_locking_(config(ctx).get("reactor", "io_locking", true)),
registered_descriptors_mutex_(mutex_.enabled())
{
struct kevent events[1];
Expand Down Expand Up @@ -562,8 +563,7 @@ int kqueue_reactor::do_kqueue_create()
kqueue_reactor::descriptor_state* kqueue_reactor::allocate_descriptor_state()
{
mutex::scoped_lock descriptors_lock(registered_descriptors_mutex_);
return registered_descriptors_.alloc(ASIO_CONCURRENCY_HINT_IS_LOCKING(
REACTOR_IO, scheduler_.concurrency_hint()));
return registered_descriptors_.alloc(io_locking_);
}

void kqueue_reactor::free_descriptor_state(kqueue_reactor::descriptor_state* s)
Expand Down
9 changes: 5 additions & 4 deletions asio/include/asio/detail/impl/resolver_service_base.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)

#include "asio/detail/config.hpp"
#include "asio/config.hpp"
#include "asio/detail/resolver_service_base.hpp"

#include "asio/detail/push_options.hpp"
Expand Down Expand Up @@ -43,8 +44,9 @@ private:

resolver_service_base::resolver_service_base(execution_context& context)
: scheduler_(asio::use_service<scheduler_impl>(context)),
work_scheduler_(new scheduler_impl(context, -1, false)),
work_thread_(0)
work_scheduler_(new scheduler_impl(context, false)),
work_thread_(0),
scheduler_locking_(config(context).get("scheduler", "locking", true))
{
work_scheduler_->work_started();
}
Expand Down Expand Up @@ -126,8 +128,7 @@ void resolver_service_base::cancel(

void resolver_service_base::start_resolve_op(resolve_op* op)
{
if (ASIO_CONCURRENCY_HINT_IS_LOCKING(SCHEDULER,
scheduler_.concurrency_hint()))
if (scheduler_locking_)
{
start_work_thread();
scheduler_.work_started();
Expand Down
15 changes: 5 additions & 10 deletions asio/include/asio/detail/impl/scheduler.ipp
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

#include "asio/detail/config.hpp"

#include "asio/detail/concurrency_hint.hpp"
#include "asio/config.hpp"
#include "asio/detail/event.hpp"
#include "asio/detail/limits.hpp"
#include "asio/detail/scheduler.hpp"
Expand Down Expand Up @@ -109,22 +109,17 @@ struct scheduler::work_cleanup
};

scheduler::scheduler(asio::execution_context& ctx,
int concurrency_hint, bool own_thread, get_task_func_type get_task)
bool own_thread, get_task_func_type get_task)
: asio::detail::execution_context_service_base<scheduler>(ctx),
one_thread_(concurrency_hint == 1
|| !ASIO_CONCURRENCY_HINT_IS_LOCKING(
SCHEDULER, concurrency_hint)
|| !ASIO_CONCURRENCY_HINT_IS_LOCKING(
REACTOR_IO, concurrency_hint)),
mutex_(ASIO_CONCURRENCY_HINT_IS_LOCKING(
SCHEDULER, concurrency_hint)),
one_thread_(config(ctx).get("scheduler", "concurrency_hint", 0) == 1),
mutex_(config(ctx).get("scheduler", "locking", true)),
task_(0),
get_task_(get_task),
task_interrupted_(true),
outstanding_work_(0),
stopped_(false),
shutdown_(false),
concurrency_hint_(concurrency_hint),
concurrency_hint_(config(ctx).get("scheduler", "concurrency_hint", 0)),
thread_(0)
{
ASIO_HANDLER_TRACKING_INIT;
Expand Down
Loading

0 comments on commit 79163e4

Please sign in to comment.