Introduce replacement for getting and setting thread name: (#4312)

* In namespace ripple, introduces get_name function that takes a
  std:🧵:native_handle_type and returns a std::string.
* In namespace ripple, introduces get_name function that takes a
  std::thread or std::jthread and returns a std::string.
* In namespace ripple::this_thread, introduces get_name function
  that takes no parameters and returns the name of the current
  thread as a std::string.
* In namespace ripple::this_thread, introduces set_name function
  that takes a std::string_view and sets the name of the current
  thread.
* Intended to replace the beast utilities setCurrentThreadName
  and getCurrentThreadName.
This commit is contained in:
Howard Hinnant
2023-09-07 14:44:36 -04:00
committed by GitHub
parent 89780c8e4f
commit 36cb5f90e2
21 changed files with 208 additions and 207 deletions

View File

@@ -24,7 +24,6 @@ add_library(xrpl::libxrpl ALIAS libxrpl)
#]===============================]
target_sources (xrpl_core PRIVATE
src/ripple/beast/clock/basic_seconds_clock.cpp
src/ripple/beast/core/CurrentThreadName.cpp
src/ripple/beast/core/SemanticVersion.cpp
src/ripple/beast/hash/impl/xxhash.cpp
src/ripple/beast/insight/impl/Collector.cpp
@@ -56,6 +55,7 @@ target_sources (xrpl_core PRIVATE
src/ripple/basics/impl/Log.cpp
src/ripple/basics/impl/Number.cpp
src/ripple/basics/impl/StringUtilities.cpp
src/ripple/basics/impl/ThreadUtilities.cpp
#[===============================[
main sources:
subdir: json
@@ -200,6 +200,7 @@ install (
src/ripple/basics/TaggedCache.h
src/ripple/basics/tagged_integer.h
src/ripple/basics/ThreadSafetyAnalysis.h
src/ripple/basics/ThreadUtilities.h
src/ripple/basics/ToString.h
src/ripple/basics/UnorderedContainers.h
src/ripple/basics/UptimeClock.h
@@ -838,6 +839,7 @@ if (tests)
src/test/basics/Slice_test.cpp
src/test/basics/StringUtilities_test.cpp
src/test/basics/TaggedCache_test.cpp
src/test/basics/ThreadName_test.cpp
src/test/basics/XRPAmount_test.cpp
src/test/basics/base64_test.cpp
src/test/basics/base_uint_test.cpp
@@ -855,7 +857,6 @@ if (tests)
src/test/beast/LexicalCast_test.cpp
src/test/beast/SemanticVersion_test.cpp
src/test/beast/aged_associative_container_test.cpp
src/test/beast/beast_CurrentThreadName_test.cpp
src/test/beast/beast_Journal_test.cpp
src/test/beast/beast_PropertyStream_test.cpp
src/test/beast/beast_Zero_test.cpp

View File

@@ -21,7 +21,7 @@
#include <ripple/app/ledger/LedgerCleaner.h>
#include <ripple/app/ledger/LedgerMaster.h>
#include <ripple/app/misc/LoadFeeTrack.h>
#include <ripple/beast/core/CurrentThreadName.h>
#include <ripple/basics/ThreadUtilities.h>
#include <ripple/protocol/jss.h>
namespace ripple {
@@ -218,7 +218,7 @@ private:
void
run()
{
beast::setCurrentThreadName("LedgerCleaner");
this_thread::set_name("LedgerCleaner");
JLOG(j_.debug()) << "Started";
while (true)

View File

@@ -18,7 +18,7 @@
//==============================================================================
#include <ripple/app/main/BasicApp.h>
#include <ripple/beast/core/CurrentThreadName.h>
#include <ripple/basics/ThreadUtilities.h>
BasicApp::BasicApp(std::size_t numberOfThreads)
{
@@ -28,7 +28,7 @@ BasicApp::BasicApp(std::size_t numberOfThreads)
while (numberOfThreads--)
{
threads_.emplace_back([this, numberOfThreads]() {
beast::setCurrentThreadName(
ripple::this_thread::set_name(
"io svc #" + std::to_string(numberOfThreads));
this->io_service_.run();
});

View File

@@ -19,7 +19,7 @@
#include <ripple/app/main/GRPCServer.h>
#include <ripple/app/reporting/P2pProxy.h>
#include <ripple/beast/core/CurrentThreadName.h>
#include <ripple/basics/ThreadUtilities.h>
#include <ripple/resource/Fees.h>
#include <ripple/beast/net/IPAddressConversion.h>
@@ -692,9 +692,8 @@ GRPCServer::start()
if (running_ = impl_.start(); running_)
{
thread_ = std::thread([this]() {
beast::setCurrentThreadName("rippled : GRPCServer");
// Start the event loop and begin handling requests
beast::setCurrentThreadName("rippled: grpc");
this_thread::set_name("rippled: grpc");
this->impl_.handleRpcs();
});
}

View File

@@ -21,8 +21,8 @@
#include <ripple/app/main/LoadManager.h>
#include <ripple/app/misc/LoadFeeTrack.h>
#include <ripple/app/misc/NetworkOPs.h>
#include <ripple/basics/ThreadUtilities.h>
#include <ripple/basics/UptimeClock.h>
#include <ripple/beast/core/CurrentThreadName.h>
#include <ripple/json/to_string.h>
#include <memory>
#include <mutex>
@@ -99,7 +99,7 @@ LoadManager::stop()
void
LoadManager::run()
{
beast::setCurrentThreadName("LoadManager");
this_thread::set_name("LoadManager");
using namespace std::chrono_literals;
using clock_type = std::chrono::steady_clock;

View File

@@ -22,9 +22,9 @@
#include <ripple/app/rdb/Vacuum.h>
#include <ripple/basics/Log.h>
#include <ripple/basics/StringUtilities.h>
#include <ripple/basics/ThreadUtilities.h>
#include <ripple/basics/contract.h>
#include <ripple/beast/clock/basic_seconds_clock.h>
#include <ripple/beast/core/CurrentThreadName.h>
#include <ripple/core/Config.h>
#include <ripple/core/ConfigSections.h>
#include <ripple/core/TimeKeeper.h>
@@ -348,8 +348,7 @@ run(int argc, char** argv)
{
using namespace std;
beast::setCurrentThreadName(
"rippled: main " + BuildInfo::getVersionString());
this_thread::set_name("main " + BuildInfo::getVersionString());
po::variables_map vm;
@@ -777,7 +776,7 @@ run(int argc, char** argv)
}
// We have an RPC command to process:
beast::setCurrentThreadName("rippled: rpc");
this_thread::set_name("rippled: rpc");
return RPCCall::fromCommandLine(
*config, vm["parameters"].as<std::vector<std::string>>(), *logs);
}

View File

@@ -23,7 +23,7 @@
#include <ripple/app/misc/NetworkOPs.h>
#include <ripple/app/rdb/State.h>
#include <ripple/app/rdb/backend/SQLiteDatabase.h>
#include <ripple/beast/core/CurrentThreadName.h>
#include <ripple/basics/ThreadUtilities.h>
#include <ripple/core/ConfigSections.h>
#include <ripple/core/Pg.h>
#include <ripple/nodestore/Scheduler.h>
@@ -286,7 +286,7 @@ SHAMapStoreImp::run()
"Reporting does not support online_delete. Remove "
"online_delete info from config");
}
beast::setCurrentThreadName("SHAMapStore");
this_thread::set_name("SHAMapStore");
LedgerIndex lastRotated = state_db_.getState().lastRotated;
netOPs_ = &app_.getOPs();
ledgerMaster_ = &app_.getLedgerMaster();

View File

@@ -19,7 +19,6 @@
#include <ripple/app/reporting/ETLSource.h>
#include <ripple/app/reporting/ReportingETL.h>
#include <ripple/beast/core/CurrentThreadName.h>
#include <ripple/json/json_reader.h>
#include <ripple/json/json_writer.h>

View File

@@ -19,8 +19,7 @@
#include <ripple/app/rdb/backend/PostgresDatabase.h>
#include <ripple/app/reporting/ReportingETL.h>
#include <ripple/beast/core/CurrentThreadName.h>
#include <ripple/basics/ThreadUtilities.h>
#include <ripple/json/json_reader.h>
#include <ripple/json/json_writer.h>
#include <boost/asio/connect.hpp>
@@ -510,7 +509,7 @@ ReportingETL::runETLPipeline(uint32_t startSequence)
&startSequence,
&writeConflict,
&transformQueue]() {
beast::setCurrentThreadName("rippled: ReportingETL extract");
this_thread::set_name("ETL extract");
uint32_t currentSequence = startSequence;
// there are two stopping conditions here.
@@ -562,7 +561,7 @@ ReportingETL::runETLPipeline(uint32_t startSequence)
&writeConflict,
&loadQueue,
&transformQueue]() {
beast::setCurrentThreadName("rippled: ReportingETL transform");
this_thread::set_name("ETL transform");
assert(parent);
parent = std::make_shared<Ledger>(*parent, NetClock::time_point{});
@@ -601,7 +600,7 @@ ReportingETL::runETLPipeline(uint32_t startSequence)
&lastPublishedSequence,
&loadQueue,
&writeConflict]() {
beast::setCurrentThreadName("rippled: ReportingETL load");
this_thread::set_name("ETL load");
size_t totalTransactions = 0;
double totalTime = 0;
while (!writeConflict)
@@ -825,7 +824,7 @@ void
ReportingETL::doWork()
{
worker_ = std::thread([this]() {
beast::setCurrentThreadName("rippled: ReportingETL worker");
this_thread::set_name("ETL worker");
if (readOnly_)
monitorReadOnly();
else

View File

@@ -1,11 +1,7 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2022 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@@ -21,31 +17,34 @@
*/
//==============================================================================
#ifndef BEAST_CORE_CURRENT_THREAD_NAME_H_INCLUDED
#define BEAST_CORE_CURRENT_THREAD_NAME_H_INCLUDED
#ifndef RIPPLE_BASICS_THREADUTILITIES_H_INCLUDED
#define RIPPLE_BASICS_THREADUTILITIES_H_INCLUDED
#include <string>
#include <string_view>
#include <thread>
namespace beast {
namespace ripple {
/** Changes the name of the caller thread.
Different OSes may place different length or content limits on this name.
*/
void
setCurrentThreadName(std::string_view newThreadName);
/** Returns the name of the caller thread.
The name returned is the name as set by a call to setCurrentThreadName().
If the thread name is set by an external force, then that name change
will not be reported.
If no name has ever been set, then the empty string is returned.
*/
std::string
getCurrentThreadName();
get_name(std::thread::native_handle_type t);
} // namespace beast
template <class Thread>
inline auto
get_name(Thread& t) -> decltype(t.native_handle(), t.join(), std::string{})
{
return get_name(t.native_handle());
}
namespace this_thread {
std::string
get_name();
void
set_name(std::string s);
} // namespace this_thread
} // namespace ripple
#endif

View File

@@ -0,0 +1,140 @@
//------------------------------------------------------------------------------
/*
This file is part of rippled: https://github.com/ripple/rippled
Copyright (c) 2022 Ripple Labs Inc.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/basics/ThreadUtilities.h>
#include <stdexcept>
namespace ripple {
#ifdef __APPLE__
#include <pthread.h>
std::string
get_name(std::thread::native_handle_type t)
{
char buffer[64];
if (pthread_getname_np(t, buffer, sizeof(buffer)) != 0)
throw std::runtime_error("get_name failed\n");
return buffer;
}
namespace this_thread {
std::string
get_name()
{
return ripple::get_name(pthread_self());
}
void
set_name(std::string s)
{
s.resize(15);
if (pthread_setname_np(s.data()) != 0)
throw std::runtime_error("this_thread::set_name failed\n");
}
} // namespace this_thread
#endif // __APPLE__
#ifdef __linux__
#include <pthread.h>
std::string
get_name(std::thread::native_handle_type t)
{
char buffer[64];
if (pthread_getname_np(t, buffer, sizeof(buffer)) != 0)
throw std::runtime_error("get_name failed\n");
return buffer;
}
namespace this_thread {
std::string
get_name()
{
return ripple::get_name(pthread_self());
}
void
set_name(std::string s)
{
s.resize(15);
if (pthread_setname_np(pthread_self(), s.data()) != 0)
throw std::runtime_error("this_thread::set_name failed\n");
}
} // namespace this_thread
#endif // __linux__
#ifdef _WIN64
#define WIN32_LEAN_AND_MEAN
#include <memory>
#include <processthreadsapi.h>
#include <windows.h>
std::string
get_name(std::thread::native_handle_type t)
{
wchar_t* unhandled_data{};
HRESULT r = GetThreadDescription(t, &unhandled_data);
std::unique_ptr<wchar_t, HLOCAL (*)(HLOCAL)> data{
unhandled_data, LocalFree};
if (FAILED(r))
throw std::runtime_error("get_name failed\n");
std::string s;
auto p = data.get();
while (*p)
s.push_back(static_cast<char>(*p++));
return s;
}
namespace this_thread {
std::string
get_name()
{
return ripple::get_name(GetCurrentThread());
}
void
set_name(std::string s)
{
assert(s.size() <= 15);
s.resize(15);
std::wstring ws;
for (auto c : s)
ws += c;
HRESULT r = SetThreadDescription(GetCurrentThread(), ws.data());
if (FAILED(r))
throw std::runtime_error("this_thread::set_name failed\n");
}
} // namespace this_thread
#endif // __WINDOWS__
} // namespace ripple

View File

@@ -1,125 +0,0 @@
//------------------------------------------------------------------------------
/*
This file is part of Beast: https://github.com/vinniefalco/Beast
Copyright 2013, Vinnie Falco <vinnie.falco@gmail.com>
Portions of this file are from JUCE.
Copyright (c) 2013 - Raw Material Software Ltd.
Please visit http://www.juce.com
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
copyright notice and this permission notice appear in all copies.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
//==============================================================================
#include <ripple/beast/core/CurrentThreadName.h>
#include <boost/predef.h>
//------------------------------------------------------------------------------
#if BOOST_OS_WINDOWS
#include <process.h>
#include <windows.h>
namespace beast::detail {
inline void
setCurrentThreadNameImpl(std::string_view name)
{
#if DEBUG && BOOST_COMP_MSVC
// This technique is documented by Microsoft and works for all versions
// of Windows and Visual Studio provided that the process is being run
// under the Visual Studio debugger. For more details, see:
// https://docs.microsoft.com/en-us/visualstudio/debugger/how-to-set-a-thread-name-in-native-code
#pragma pack(push, 8)
struct THREADNAME_INFO
{
DWORD dwType;
LPCSTR szName;
DWORD dwThreadID;
DWORD dwFlags;
};
#pragma pack(pop)
THREADNAME_INFO ni;
ni.dwType = 0x1000;
ni.szName = name.data();
ni.dwThreadID = GetCurrentThreadId();
ni.dwFlags = 0;
#pragma warning(push)
#pragma warning(disable : 6320 6322)
__try
{
RaiseException(
0x406d1388, 0, sizeof(ni) / sizeof(ULONG_PTR), (ULONG_PTR*)&ni);
}
__except (EXCEPTION_CONTINUE_EXECUTION)
{
}
#pragma warning(pop)
#endif
}
} // namespace beast::detail
#endif // BOOST_OS_WINDOWS
#if BOOST_OS_MACOS
#include <pthread.h>
namespace beast::detail {
inline void
setCurrentThreadNameImpl(std::string_view name)
{
pthread_setname_np(name.data());
}
} // namespace beast::detail
#endif // BOOST_OS_MACOS
#if BOOST_OS_LINUX
#include <pthread.h>
namespace beast::detail {
inline void
setCurrentThreadNameImpl(std::string_view name)
{
pthread_setname_np(pthread_self(), name.data());
}
} // namespace beast::detail
#endif // BOOST_OS_LINUX
namespace beast {
namespace detail {
thread_local std::string threadName;
} // namespace detail
std::string
getCurrentThreadName()
{
return detail::threadName;
}
void
setCurrentThreadName(std::string_view name)
{
detail::threadName = name;
detail::setCurrentThreadNameImpl(name);
}
} // namespace beast

View File

@@ -17,7 +17,7 @@
*/
//==============================================================================
#include <ripple/beast/core/CurrentThreadName.h>
#include <ripple/basics/ThreadUtilities.h>
#include <ripple/core/Job.h>
#include <cassert>
@@ -61,7 +61,7 @@ Job::queue_time() const
void
Job::doJob()
{
beast::setCurrentThreadName("doJob: " + mName);
this_thread::set_name("doJob: " + mName);
m_loadEvent->start();
m_loadEvent->setName(mName);

View File

@@ -18,8 +18,8 @@
//==============================================================================
#include <ripple/basics/Log.h>
#include <ripple/basics/ThreadUtilities.h>
#include <ripple/basics/random.h>
#include <ripple/beast/core/CurrentThreadName.h>
#include <ripple/core/impl/SNTPClock.h>
#include <boost/asio.hpp>
#include <cmath>
@@ -193,7 +193,7 @@ public:
void
doRun()
{
beast::setCurrentThreadName("rippled: SNTPClock");
this_thread::set_name("SNTPClock");
io_service_.run();
}

View File

@@ -18,7 +18,7 @@
//==============================================================================
#include <ripple/basics/PerfLog.h>
#include <ripple/beast/core/CurrentThreadName.h>
#include <ripple/basics/ThreadUtilities.h>
#include <ripple/core/impl/Workers.h>
#include <cassert>
@@ -206,7 +206,7 @@ Workers::Worker::run()
for (;;)
{
// Put the name back in case the callback changed it
beast::setCurrentThreadName(threadName_);
this_thread::set_name(threadName_);
// Acquire a task or "internal task."
//
@@ -259,7 +259,7 @@ Workers::Worker::run()
}
// Set inactive thread name.
beast::setCurrentThreadName("(" + threadName_ + ")");
this_thread::set_name("(" + threadName_ + ")");
// [1] We will be here when the paused list is popped
//

View File

@@ -22,9 +22,9 @@
#if RIPPLE_ROCKSDB_AVAILABLE
#include <ripple/basics/ByteUtilities.h>
#include <ripple/basics/ThreadUtilities.h>
#include <ripple/basics/contract.h>
#include <ripple/basics/safe_cast.h>
#include <ripple/beast/core/CurrentThreadName.h>
#include <ripple/core/Config.h> // VFALCO Bad dependency
#include <ripple/nodestore/Factory.h>
#include <ripple/nodestore/Manager.h>
@@ -67,7 +67,7 @@ public:
std::size_t const id(++n);
std::stringstream ss;
ss << "rocksdb #" << id;
beast::setCurrentThreadName(ss.str());
this_thread::set_name(ss.str());
(*f)(a);
}

View File

@@ -18,8 +18,8 @@
//==============================================================================
#include <ripple/app/ledger/Ledger.h>
#include <ripple/basics/ThreadUtilities.h>
#include <ripple/basics/chrono.h>
#include <ripple/beast/core/CurrentThreadName.h>
#include <ripple/json/json_value.h>
#include <ripple/nodestore/Database.h>
#include <ripple/protocol/HashPrefix.h>
@@ -63,8 +63,7 @@ Database::Database(
[this](int i) {
runningThreads_++;
beast::setCurrentThreadName(
"db prefetch #" + std::to_string(i));
this_thread::set_name("prefetch " + std::to_string(i));
decltype(read_) read;

View File

@@ -20,7 +20,7 @@
#include <ripple/perflog/impl/PerfLogImp.h>
#include <ripple/basics/BasicConfig.h>
#include <ripple/beast/core/CurrentThreadName.h>
#include <ripple/basics/ThreadUtilities.h>
#include <ripple/beast/utility/Journal.h>
#include <ripple/core/JobTypes.h>
#include <ripple/json/json_writer.h>
@@ -255,7 +255,7 @@ PerfLogImp::openLog()
void
PerfLogImp::run()
{
beast::setCurrentThreadName("perflog");
this_thread::set_name("perflog");
lastLog_ = system_clock::now();
while (true)

View File

@@ -18,8 +18,8 @@
//==============================================================================
#include <ripple/basics/Log.h>
#include <ripple/basics/ThreadUtilities.h>
#include <ripple/basics/chrono.h>
#include <ripple/beast/core/CurrentThreadName.h>
#include <ripple/beast/net/IPAddressConversion.h>
#include <ripple/resource/ResourceManager.h>
#include <ripple/resource/impl/Logic.h>
@@ -149,7 +149,7 @@ private:
void
run()
{
beast::setCurrentThreadName("Resource::Manager");
this_thread::set_name("Resrc::Manager");
for (;;)
{
logic_.periodicActivity();

View File

@@ -17,15 +17,13 @@
*/
//==============================================================================
#include <ripple/beast/core/CurrentThreadName.h>
#include <ripple/basics/ThreadUtilities.h>
#include <ripple/beast/unit_test.h>
#include <atomic>
#include <thread>
namespace ripple {
namespace test {
class CurrentThreadName_test : public beast::unit_test::suite
class ThreadName_test : public beast::unit_test::suite
{
private:
static void
@@ -34,26 +32,19 @@ private:
std::atomic<bool>* stop,
std::atomic<int>* state)
{
// Verify that upon creation a thread has no name.
auto const initialThreadName = beast::getCurrentThreadName();
// Set the new name.
beast::setCurrentThreadName(myName);
this_thread::set_name(myName);
// Indicate to caller that the name is set.
*state = 1;
// If there is an initial thread name then we failed.
if (!initialThreadName.empty())
return;
// Wait until all threads have their names.
while (!*stop)
;
// Make sure the thread name that we set before is still there
// (not overwritten by, for instance, another thread).
if (beast::getCurrentThreadName() == myName)
if (this_thread::get_name() == myName)
*state = 2;
}
@@ -86,7 +77,7 @@ public:
}
};
BEAST_DEFINE_TESTSUITE(CurrentThreadName, core, beast);
BEAST_DEFINE_TESTSUITE(ThreadName, basics, ripple);
} // namespace test
} // namespace ripple

View File

@@ -17,8 +17,8 @@
*/
//==============================================================================
#include <ripple/basics/ThreadUtilities.h>
#include <ripple/basics/make_SSLContext.h>
#include <ripple/beast/core/CurrentThreadName.h>
#include <ripple/beast/unit_test.h>
#include <test/jtx/envconfig.h>
@@ -630,7 +630,7 @@ public:
short_read_test()
: work_(io_context_.get_executor())
, thread_(std::thread([this]() {
beast::setCurrentThreadName("io_context");
this_thread::set_name("io_context");
this->io_context_.run();
}))
, context_(make_SSLContext(""))