Boost.ASIO: update io_service=>io_context

This commit is contained in:
2026-05-30 11:57:57 -04:00
parent 0afa3e16b8
commit 6df9407e65
16 changed files with 116 additions and 101 deletions
+9 -9
View File
@@ -8,7 +8,7 @@
#include <memory>
#include <thread>
#include <boost/asio/io_service.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp>
#include <spinscale/componentThread.h>
@@ -31,7 +31,7 @@ public:
{
public:
explicit WaitingCoroutineBase(
boost::asio::io_service &callerIoContextIn) noexcept
boost::asio::io_context &callerIoContextIn) noexcept
: callerIoContext(callerIoContextIn)
{}
@@ -40,7 +40,7 @@ public:
virtual void post() noexcept = 0;
public:
boost::asio::io_service &callerIoContext;
boost::asio::io_context &callerIoContext;
};
template <typename Promise>
@@ -49,7 +49,7 @@ public:
{
public:
TypedWaitingCoroutine(
boost::asio::io_service &callerIoContextIn,
boost::asio::io_context &callerIoContextIn,
std::coroutine_handle<Promise> callerSchedHandleIn) noexcept
: WaitingCoroutineBase(callerIoContextIn),
callerSchedHandle(callerSchedHandleIn)
@@ -83,8 +83,8 @@ public:
template <typename Promise>
bool await_suspend(std::coroutine_handle<Promise> cvCallerSchedHandle) noexcept
{
boost::asio::io_service &cvCallerIoContext =
sscl::ComponentThread::getSelf()->getIoService();
boost::asio::io_context &cvCallerIoContext =
sscl::ComponentThread::getSelf()->getIoContext();
sscl::SpinLock::Guard guard(parentCv.spinLock);
if (parentCv.isSignaled) {
@@ -130,8 +130,8 @@ public:
template <typename Promise>
DecisionFactors awaitSuspend(std::coroutine_handle<Promise> cvCallerSchedHandle) noexcept
{
boost::asio::io_service &cvCallerIoContext =
sscl::ComponentThread::getSelf()->getIoService();
boost::asio::io_context &cvCallerIoContext =
sscl::ComponentThread::getSelf()->getIoContext();
parentCv.spinLock.acquire();
if (parentCv.isSignaled)
@@ -197,7 +197,7 @@ public:
template <typename Promise>
void enqueueWaitingCoroutine(
std::coroutine_handle<Promise> handle,
boost::asio::io_service &ctx) noexcept
boost::asio::io_context &ctx) noexcept
{
waitingCoroutines.push_back(
std::make_unique<TypedWaitingCoroutine<Promise>>(ctx, handle));
+4 -4
View File
@@ -14,7 +14,7 @@
#include <thread>
#endif
#include <boost/asio/io_service.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp>
#include <spinscale/componentThread.h>
@@ -56,7 +56,7 @@ public:
{
WaitingCoroutine(
std::coroutine_handle<void> _callerSchedHandle,
boost::asio::io_service &_callerIoContext,
boost::asio::io_context &_callerIoContext,
PromiseChainLink &_waitingPromise) noexcept
: callerSchedHandle(_callerSchedHandle),
callerIoContext(_callerIoContext),
@@ -64,7 +64,7 @@ public:
{}
std::coroutine_handle<void> callerSchedHandle;
boost::asio::io_service &callerIoContext;
boost::asio::io_context &callerIoContext;
PromiseChainLink &waitingPromise;
};
@@ -104,7 +104,7 @@ public:
}
coQutex.waitingCoroutines.emplace_back(
std::coroutine_handle<void>::from_address(callerSchedHandle.address()),
sscl::ComponentThread::getSelf()->getIoService(),
sscl::ComponentThread::getSelf()->getIoContext(),
*acquirerChainLink);
return true;
}
+3 -3
View File
@@ -15,7 +15,7 @@
#include <utility>
#include <vector>
#include <boost/asio/io_service.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp>
#include <spinscale/componentThread.h>
@@ -486,7 +486,7 @@ struct Group
* would be impossible.
*
* So we should be able to call resume() directly here without
* post()ing to ComponentThread::getSelf()->getIoService().
* post()ing to ComponentThread::getSelf()->getIoContext().
*
* EXPLANATION:
* However, in order to ensure that we keep this adapter coro
@@ -494,7 +494,7 @@ struct Group
* directly calling the handle.
*/
boost::asio::post(
sscl::ComponentThread::getSelf()->getIoService(),
sscl::ComponentThread::getSelf()->getIoContext(),
groupAwaiterSchedHandleToWake);
}
+8 -8
View File
@@ -11,7 +11,7 @@
#include <type_traits>
#include <utility>
#include <boost/asio/io_service.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp>
#include <spinscale/componentThread.h>
@@ -124,19 +124,19 @@ struct PostingPromise
: public std::suspend_always
{
InitialSuspendPostingInvoker(
boost::asio::io_service &targetIoServiceIn,
boost::asio::io_context &targetIoContextIn,
std::coroutine_handle<> targetSchedHandleIn) noexcept
: targetIoService(targetIoServiceIn),
: targetIoContext(targetIoContextIn),
targetSchedHandle(targetSchedHandleIn)
{}
bool await_suspend(std::coroutine_handle<> const) noexcept
{
boost::asio::post(targetIoService, targetSchedHandle);
boost::asio::post(targetIoContext, targetSchedHandle);
return true;
}
boost::asio::io_service &targetIoService;
boost::asio::io_context &targetIoContext;
std::coroutine_handle<> targetSchedHandle;
};
@@ -253,8 +253,8 @@ struct PostingPromise
ReturnValues<T> returnValues;
std::function<void()> callerLambda;
boost::asio::io_service &callerIoContext =
sscl::ComponentThread::getSelf()->getIoService();
boost::asio::io_context &callerIoContext =
sscl::ComponentThread::getSelf()->getIoContext();
std::coroutine_handle<> selfSchedHandle;
std::coroutine_handle<void> callerSchedHandle;
PromiseChainLink *callerChainLink = nullptr;
@@ -315,7 +315,7 @@ struct TaggedPostingPromise
std::cout << __func__ << ": " << std::this_thread::get_id() << " Returning InitialSuspendPostingInvoker.\n";
#endif
return typename PostingPromise<T>::InitialSuspendPostingInvoker(
ThreadTag::io_service(),
ThreadTag::io_context(),
this->selfSchedHandle);
}
};
+12 -9
View File
@@ -15,7 +15,7 @@
#include <coroutine>
#include <cstdint>
#include <string>
#include <boost/asio/io_service.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp>
#include <spinscale/cps/callback.h>
@@ -36,7 +36,8 @@ class ComponentThread
{
protected:
ComponentThread(ThreadId _id, std::string _name)
: id(_id), name(std::move(_name)), work(io_service), keepLooping(true)
: id(_id), name(std::move(_name)),
work(boost::asio::make_work_guard(io_context)), keepLooping(true)
{}
public:
@@ -44,7 +45,7 @@ public:
void cleanup(void);
boost::asio::io_service& getIoService(void) { return io_service; }
boost::asio::io_context& getIoContext(void) { return io_context; }
static const std::shared_ptr<ComponentThread> getSelf(void);
static bool tlsInitialized(void);
@@ -66,8 +67,9 @@ public:
public:
ThreadId id;
std::string name;
boost::asio::io_service io_service;
boost::asio::io_service::work work;
boost::asio::io_context io_context;
boost::asio::executor_work_guard<
boost::asio::io_context::executor_type> work;
std::atomic<bool> keepLooping;
};
@@ -153,7 +155,7 @@ public:
preJoltHookFn preJoltFn)
: ComponentThread(_id, std::move(name)),
pinnedCpuId(-1),
pause_work(pause_io_service),
pause_work(boost::asio::make_work_guard(pause_io_context)),
entryFnArguments(*this, component, preJoltFn),
thread(std::move(entryPoint), std::cref(entryFnArguments))
{}
@@ -198,7 +200,7 @@ public:
* coroutine state while the handler is still unwinding.
*/
boost::asio::post(
ComponentThread::getPptr()->getIoService(),
ComponentThread::getPptr()->getIoContext(),
[handle]() { handle.resume(); });
}}
{
@@ -296,8 +298,9 @@ public:
public:
int pinnedCpuId;
boost::asio::io_service pause_io_service;
boost::asio::io_service::work pause_work;
boost::asio::io_context pause_io_context;
boost::asio::executor_work_guard<
boost::asio::io_context::executor_type> pause_work;
public:
EntryFnArguments entryFnArguments;
+13 -12
View File
@@ -3,34 +3,35 @@
#include <boostAsioLinkageFix.h>
#include <atomic>
#include <boost/asio/io_service.hpp>
#include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp>
namespace sscl::cps {
class AsynchronousBridge
{
public:
AsynchronousBridge(boost::asio::io_service &io_service)
: isAsyncOperationComplete(false), io_service(io_service)
AsynchronousBridge(boost::asio::io_context &io_context)
: isAsyncOperationComplete(false), io_context(io_context)
{}
void setAsyncOperationComplete(void)
{
/** EXPLANATION:
* This empty post()ed message is necessary to ensure that the thread
* that's waiting on the io_service is signaled to wake up and check
* the io_service's queue.
* that's waiting on the io_context is signaled to wake up and check
* the io_context's queue.
*/
isAsyncOperationComplete.store(true);
io_service.post([]{});
boost::asio::post(io_context, []{});
}
void waitForAsyncOperationCompleteOrIoServiceStopped(void)
void waitForAsyncOperationCompleteOrIoContextStopped(void)
{
for (;;)
{
io_service.run_one();
if (isAsyncOperationComplete.load() || io_service.stopped())
io_context.run_one();
if (isAsyncOperationComplete.load() || io_context.stopped())
{ break; }
/** EXPLANATION:
@@ -45,12 +46,12 @@ public:
}
}
bool exitedBecauseIoServiceStopped(void) const
{ return io_service.stopped(); }
bool exitedBecauseIoContextStopped(void) const
{ return io_context.stopped(); }
private:
std::atomic<bool> isAsyncOperationComplete;
boost::asio::io_service &io_service;
boost::asio::io_context &io_context;
};
} // namespace sscl::cps
@@ -90,7 +90,7 @@ public:
* LockedNonPostedAsynchronousContinuation because the only way to implement
* non-posted locking would be via busy-spinning or sleeplocks. This would
* eliminate the throughput advantage from our Qspinning mechanism, which
* relies on re-posting to the io_service queue when locks are unavailable.
* relies on re-posting to the io_context queue when locks are unavailable.
*/
template <class OriginalCbFnT>
class NonPostedAsynchronousContinuation
@@ -141,7 +141,7 @@ public:
if (AsynchronousContinuation<OriginalCbFnT>::originalCallback
.callbackFn)
{
caller->getIoService().post(
boost::asio::post(caller->getIoContext(),
STC(std::bind(
AsynchronousContinuation<OriginalCbFnT>::originalCallback
.callbackFn,
+2 -2
View File
@@ -15,7 +15,7 @@ namespace sscl::cps {
*
* This class wraps any callable object with metadata (caller function name,
* line number, and return addresses) to help debug cases where callables
* posted to boost::asio::io_service have gone out of scope. The metadata
* posted to boost::asio::io_context have gone out of scope. The metadata
* can be accessed from the callable's address when debugging.
*/
class CallableTracer
@@ -100,7 +100,7 @@ private:
* - Fallback: nullptr for return addresses
*
* Usage:
* thread->getIoService().post(
* boost::asio::post(thread->getIoContext(),
* STC(std::bind(&SomeClass::method, this, arg1, arg2)));
*/
#ifdef CONFIG_DEBUG_TRACE_CALLABLES
+1 -1
View File
@@ -83,7 +83,7 @@ public:
* time it will leave the qutexQ is when the program terminates.
*
* I'm not sure we'll actually cancal all in-flight async sequences --
* and especially not all those that aren't even in any io_service queues.
* and especially not all those that aren't even in any io_context queues.
* To whatever extent these objects get cleaned up, they'll probably be
* cleaned up in the qutexQ's std::list destructor -- and that won't
* execute any fancy cleanup logic. It'll just clear() out the list.
+3 -3
View File
@@ -39,7 +39,7 @@ public:
virtual List::iterator getLockvokerIteratorForQutex(Qutex& qutex) const = 0;
/**
* @brief Awaken this lockvoker by posting it to its io_service
* @brief Awaken this lockvoker by posting it to its io_context
* @param forceAwaken If true, post even if already awake
*/
virtual void awaken(bool forceAwaken = false) = 0;
@@ -55,12 +55,12 @@ public:
*
* Compare by the address of the continuation objects. Why?
* Because there's no guarantee that the lockvoker object that was
* passed in by the io_service invocation is the same object as that
* passed in by the io_context invocation is the same object as that
* which is in the qutexQs. Especially because we make_shared() a
* copy when registerInQutexQueues()ing.
*
* Generally when we "wake" a lockvoker by enqueuing it, boost's
* io_service::post will copy the lockvoker object.
* io_context::post will copy the lockvoker object.
*/
bool operator==(const LockerAndInvokerBase &other) const
{
@@ -65,7 +65,7 @@ public:
* @brief LockerAndInvoker - Template class for lockvoking mechanism
*
* This class wraps a std::bind result and provides locking functionality.
* When locks cannot be acquired, the object re-posts itself to the io_service
* When locks cannot be acquired, the object re-posts itself to the io_context
* queue, implementing the "spinqueueing" pattern.
*/
template <class InvocationTargetT>
@@ -74,10 +74,10 @@ public:
{
public:
/**
* @brief Constructor that immediately posts to io_service
* @brief Constructor that immediately posts to io_context
* @param serializedContinuation Reference to the serialized continuation
* containing LockSet and target io_service
* @param target The ComponentThread whose io_service to post to
* containing LockSet and target io_context
* @param target The ComponentThread whose io_context to post to
* @param invocationTarget The std::bind result to invoke when locks are acquired
*/
LockerAndInvoker(
@@ -127,7 +127,7 @@ public:
}
/**
* @brief Awaken this lockvoker by posting it to its io_service
* @brief Awaken this lockvoker by posting it to its io_context
* @param forceAwaken If true, post even if already awake
*/
void awaken(bool forceAwaken = false) override
@@ -138,7 +138,7 @@ public:
if (prevVal == true && !forceAwaken)
{ return; }
target->getIoService().post(*this);
boost::asio::post(target->getIoContext(), *this);
}
size_t getLockSetSize() const override
@@ -161,14 +161,14 @@ public:
* the AsyncContinuation sh_ptr (which the Lockvoker contains within
* itself) alive without wasting too much memory.
*
* This way the io_service objects can remove the lockvoker from
* This way the io_context objects can remove the lockvoker from
* their queues and there'll be a copy of the lockvoker in each
* Qutex's queue.
*
* For non-serialized, posted continuations, they won't be removed
* from the io_service queue until they're executed, so there's no
* from the io_context queue until they're executed, so there's no
* need to create copies of them. Lockvokers are removed from their
* io_service, potentially without being executed if they fail to
* io_context, potentially without being executed if they fail to
* acquire all locks.
*/
void registerInLockSet()
@@ -185,7 +185,7 @@ public:
*
* Sets isAwake=true before calling awaken with forceAwaken to ensure
* that none of the locks we just registered with awaken()s a duplicate
* copy of this lockvoker on the io_service.
* copy of this lockvoker on the io_context.
*/
void firstWake()
{
@@ -213,8 +213,17 @@ public:
{ return isDeadlockLikely(); }
#ifdef CONFIG_ENABLE_DEBUG_LOCKS
struct obsolete {
bool traceContinuationHistoryForGridlockOn(Qutex &firstFailedQutex);
friend struct obsolete;
struct obsolete
{
explicit obsolete(LockerAndInvoker &_parent) : parent(_parent)
{}
bool traceContinuationHistoryForGridlockOn(
Qutex &firstFailedQutex);
LockerAndInvoker &parent;
};
bool traceContinuationHistoryForDeadlockOn(Qutex &firstFailedQutex);
@@ -435,7 +444,8 @@ SerializedAsynchronousContinuation<OriginalCbFnT>
* should eventually be able to acquire that lock.
*/
for (std::shared_ptr<AsynchronousContinuationChainLink> currContin =
this->serializedContinuation.getCallersContinuationShPtr();
parent.serializedContinuation
.getCallersContinuationShPtr();
currContin != nullptr;
currContin = currContin->getCallersContinuationShPtr())
{
@@ -484,7 +494,7 @@ void SerializedAsynchronousContinuation<OriginalCbFnT>
if (!serializedContinuation.requiredLocks.tryAcquireOrBackOff(
*this, firstFailedQutexRet))
{
// Just allow this lockvoker to be dropped from its io_service.
// Just allow this lockvoker to be dropped from its io_context.
allowAwakening();
if (!deadlockLikely && !gridlockLikely)
{ return; }