mirror of
https://github.com/latentPrion/libspinscale.git
synced 2026-06-24 11:58:33 +00:00
Boost.ASIO: update io_service=>io_context
This commit is contained in:
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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; }
|
||||
|
||||
Reference in New Issue
Block a user