Compare commits

...

3 Commits

17 changed files with 134 additions and 104 deletions
+1
View File
@@ -76,6 +76,7 @@ find_package(Threads REQUIRED)
# Create the library # Create the library
add_library(spinscale SHARED add_library(spinscale SHARED
src/boostAsioLinkageFix.cpp
src/qutex.cpp src/qutex.cpp
src/componentThread.cpp src/componentThread.cpp
src/component.cpp src/component.cpp
+9 -9
View File
@@ -8,7 +8,7 @@
#include <memory> #include <memory>
#include <thread> #include <thread>
#include <boost/asio/io_service.hpp> #include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp> #include <boost/asio/post.hpp>
#include <spinscale/componentThread.h> #include <spinscale/componentThread.h>
@@ -31,7 +31,7 @@ public:
{ {
public: public:
explicit WaitingCoroutineBase( explicit WaitingCoroutineBase(
boost::asio::io_service &callerIoContextIn) noexcept boost::asio::io_context &callerIoContextIn) noexcept
: callerIoContext(callerIoContextIn) : callerIoContext(callerIoContextIn)
{} {}
@@ -40,7 +40,7 @@ public:
virtual void post() noexcept = 0; virtual void post() noexcept = 0;
public: public:
boost::asio::io_service &callerIoContext; boost::asio::io_context &callerIoContext;
}; };
template <typename Promise> template <typename Promise>
@@ -49,7 +49,7 @@ public:
{ {
public: public:
TypedWaitingCoroutine( TypedWaitingCoroutine(
boost::asio::io_service &callerIoContextIn, boost::asio::io_context &callerIoContextIn,
std::coroutine_handle<Promise> callerSchedHandleIn) noexcept std::coroutine_handle<Promise> callerSchedHandleIn) noexcept
: WaitingCoroutineBase(callerIoContextIn), : WaitingCoroutineBase(callerIoContextIn),
callerSchedHandle(callerSchedHandleIn) callerSchedHandle(callerSchedHandleIn)
@@ -83,8 +83,8 @@ public:
template <typename Promise> template <typename Promise>
bool await_suspend(std::coroutine_handle<Promise> cvCallerSchedHandle) noexcept bool await_suspend(std::coroutine_handle<Promise> cvCallerSchedHandle) noexcept
{ {
boost::asio::io_service &cvCallerIoContext = boost::asio::io_context &cvCallerIoContext =
sscl::ComponentThread::getSelf()->getIoService(); sscl::ComponentThread::getSelf()->getIoContext();
sscl::SpinLock::Guard guard(parentCv.spinLock); sscl::SpinLock::Guard guard(parentCv.spinLock);
if (parentCv.isSignaled) { if (parentCv.isSignaled) {
@@ -130,8 +130,8 @@ public:
template <typename Promise> template <typename Promise>
DecisionFactors awaitSuspend(std::coroutine_handle<Promise> cvCallerSchedHandle) noexcept DecisionFactors awaitSuspend(std::coroutine_handle<Promise> cvCallerSchedHandle) noexcept
{ {
boost::asio::io_service &cvCallerIoContext = boost::asio::io_context &cvCallerIoContext =
sscl::ComponentThread::getSelf()->getIoService(); sscl::ComponentThread::getSelf()->getIoContext();
parentCv.spinLock.acquire(); parentCv.spinLock.acquire();
if (parentCv.isSignaled) if (parentCv.isSignaled)
@@ -197,7 +197,7 @@ public:
template <typename Promise> template <typename Promise>
void enqueueWaitingCoroutine( void enqueueWaitingCoroutine(
std::coroutine_handle<Promise> handle, std::coroutine_handle<Promise> handle,
boost::asio::io_service &ctx) noexcept boost::asio::io_context &ctx) noexcept
{ {
waitingCoroutines.push_back( waitingCoroutines.push_back(
std::make_unique<TypedWaitingCoroutine<Promise>>(ctx, handle)); std::make_unique<TypedWaitingCoroutine<Promise>>(ctx, handle));
+4 -4
View File
@@ -14,7 +14,7 @@
#include <thread> #include <thread>
#endif #endif
#include <boost/asio/io_service.hpp> #include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp> #include <boost/asio/post.hpp>
#include <spinscale/componentThread.h> #include <spinscale/componentThread.h>
@@ -56,7 +56,7 @@ public:
{ {
WaitingCoroutine( WaitingCoroutine(
std::coroutine_handle<void> _callerSchedHandle, std::coroutine_handle<void> _callerSchedHandle,
boost::asio::io_service &_callerIoContext, boost::asio::io_context &_callerIoContext,
PromiseChainLink &_waitingPromise) noexcept PromiseChainLink &_waitingPromise) noexcept
: callerSchedHandle(_callerSchedHandle), : callerSchedHandle(_callerSchedHandle),
callerIoContext(_callerIoContext), callerIoContext(_callerIoContext),
@@ -64,7 +64,7 @@ public:
{} {}
std::coroutine_handle<void> callerSchedHandle; std::coroutine_handle<void> callerSchedHandle;
boost::asio::io_service &callerIoContext; boost::asio::io_context &callerIoContext;
PromiseChainLink &waitingPromise; PromiseChainLink &waitingPromise;
}; };
@@ -104,7 +104,7 @@ public:
} }
coQutex.waitingCoroutines.emplace_back( coQutex.waitingCoroutines.emplace_back(
std::coroutine_handle<void>::from_address(callerSchedHandle.address()), std::coroutine_handle<void>::from_address(callerSchedHandle.address()),
sscl::ComponentThread::getSelf()->getIoService(), sscl::ComponentThread::getSelf()->getIoContext(),
*acquirerChainLink); *acquirerChainLink);
return true; return true;
} }
+3 -3
View File
@@ -15,7 +15,7 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <boost/asio/io_service.hpp> #include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp> #include <boost/asio/post.hpp>
#include <spinscale/componentThread.h> #include <spinscale/componentThread.h>
@@ -486,7 +486,7 @@ struct Group
* would be impossible. * would be impossible.
* *
* So we should be able to call resume() directly here without * So we should be able to call resume() directly here without
* post()ing to ComponentThread::getSelf()->getIoService(). * post()ing to ComponentThread::getSelf()->getIoContext().
* *
* EXPLANATION: * EXPLANATION:
* However, in order to ensure that we keep this adapter coro * However, in order to ensure that we keep this adapter coro
@@ -494,7 +494,7 @@ struct Group
* directly calling the handle. * directly calling the handle.
*/ */
boost::asio::post( boost::asio::post(
sscl::ComponentThread::getSelf()->getIoService(), sscl::ComponentThread::getSelf()->getIoContext(),
groupAwaiterSchedHandleToWake); groupAwaiterSchedHandleToWake);
} }
+8 -8
View File
@@ -11,7 +11,7 @@
#include <type_traits> #include <type_traits>
#include <utility> #include <utility>
#include <boost/asio/io_service.hpp> #include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp> #include <boost/asio/post.hpp>
#include <spinscale/componentThread.h> #include <spinscale/componentThread.h>
@@ -124,19 +124,19 @@ struct PostingPromise
: public std::suspend_always : public std::suspend_always
{ {
InitialSuspendPostingInvoker( InitialSuspendPostingInvoker(
boost::asio::io_service &targetIoServiceIn, boost::asio::io_context &targetIoContextIn,
std::coroutine_handle<> targetSchedHandleIn) noexcept std::coroutine_handle<> targetSchedHandleIn) noexcept
: targetIoService(targetIoServiceIn), : targetIoContext(targetIoContextIn),
targetSchedHandle(targetSchedHandleIn) targetSchedHandle(targetSchedHandleIn)
{} {}
bool await_suspend(std::coroutine_handle<> const) noexcept bool await_suspend(std::coroutine_handle<> const) noexcept
{ {
boost::asio::post(targetIoService, targetSchedHandle); boost::asio::post(targetIoContext, targetSchedHandle);
return true; return true;
} }
boost::asio::io_service &targetIoService; boost::asio::io_context &targetIoContext;
std::coroutine_handle<> targetSchedHandle; std::coroutine_handle<> targetSchedHandle;
}; };
@@ -253,8 +253,8 @@ struct PostingPromise
ReturnValues<T> returnValues; ReturnValues<T> returnValues;
std::function<void()> callerLambda; std::function<void()> callerLambda;
boost::asio::io_service &callerIoContext = boost::asio::io_context &callerIoContext =
sscl::ComponentThread::getSelf()->getIoService(); sscl::ComponentThread::getSelf()->getIoContext();
std::coroutine_handle<> selfSchedHandle; std::coroutine_handle<> selfSchedHandle;
std::coroutine_handle<void> callerSchedHandle; std::coroutine_handle<void> callerSchedHandle;
PromiseChainLink *callerChainLink = nullptr; PromiseChainLink *callerChainLink = nullptr;
@@ -315,7 +315,7 @@ struct TaggedPostingPromise
std::cout << __func__ << ": " << std::this_thread::get_id() << " Returning InitialSuspendPostingInvoker.\n"; std::cout << __func__ << ": " << std::this_thread::get_id() << " Returning InitialSuspendPostingInvoker.\n";
#endif #endif
return typename PostingPromise<T>::InitialSuspendPostingInvoker( return typename PostingPromise<T>::InitialSuspendPostingInvoker(
ThreadTag::io_service(), ThreadTag::io_context(),
this->selfSchedHandle); this->selfSchedHandle);
} }
}; };
+12 -10
View File
@@ -1,7 +1,6 @@
#ifndef COMPONENT_THREAD_H #ifndef COMPONENT_THREAD_H
#define COMPONENT_THREAD_H #define COMPONENT_THREAD_H
#include <boostAsioLinkageFix.h>
#include <atomic> #include <atomic>
#include <thread> #include <thread>
#include <unordered_map> #include <unordered_map>
@@ -15,7 +14,7 @@
#include <coroutine> #include <coroutine>
#include <cstdint> #include <cstdint>
#include <string> #include <string>
#include <boost/asio/io_service.hpp> #include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp> #include <boost/asio/post.hpp>
#include <spinscale/cps/callback.h> #include <spinscale/cps/callback.h>
@@ -36,7 +35,8 @@ class ComponentThread
{ {
protected: protected:
ComponentThread(ThreadId _id, std::string _name) 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: public:
@@ -44,7 +44,7 @@ public:
void cleanup(void); 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 const std::shared_ptr<ComponentThread> getSelf(void);
static bool tlsInitialized(void); static bool tlsInitialized(void);
@@ -66,8 +66,9 @@ public:
public: public:
ThreadId id; ThreadId id;
std::string name; std::string name;
boost::asio::io_service io_service; boost::asio::io_context io_context;
boost::asio::io_service::work work; boost::asio::executor_work_guard<
boost::asio::io_context::executor_type> work;
std::atomic<bool> keepLooping; std::atomic<bool> keepLooping;
}; };
@@ -153,7 +154,7 @@ public:
preJoltHookFn preJoltFn) preJoltHookFn preJoltFn)
: ComponentThread(_id, std::move(name)), : ComponentThread(_id, std::move(name)),
pinnedCpuId(-1), pinnedCpuId(-1),
pause_work(pause_io_service), pause_work(boost::asio::make_work_guard(pause_io_context)),
entryFnArguments(*this, component, preJoltFn), entryFnArguments(*this, component, preJoltFn),
thread(std::move(entryPoint), std::cref(entryFnArguments)) thread(std::move(entryPoint), std::cref(entryFnArguments))
{} {}
@@ -198,7 +199,7 @@ public:
* coroutine state while the handler is still unwinding. * coroutine state while the handler is still unwinding.
*/ */
boost::asio::post( boost::asio::post(
ComponentThread::getPptr()->getIoService(), ComponentThread::getPptr()->getIoContext(),
[handle]() { handle.resume(); }); [handle]() { handle.resume(); });
}} }}
{ {
@@ -296,8 +297,9 @@ public:
public: public:
int pinnedCpuId; int pinnedCpuId;
boost::asio::io_service pause_io_service; boost::asio::io_context pause_io_context;
boost::asio::io_service::work pause_work; boost::asio::executor_work_guard<
boost::asio::io_context::executor_type> pause_work;
public: public:
EntryFnArguments entryFnArguments; EntryFnArguments entryFnArguments;
+13 -13
View File
@@ -1,36 +1,36 @@
#ifndef ASYNCHRONOUS_BRIDGE_H #ifndef ASYNCHRONOUS_BRIDGE_H
#define ASYNCHRONOUS_BRIDGE_H #define ASYNCHRONOUS_BRIDGE_H
#include <boostAsioLinkageFix.h>
#include <atomic> #include <atomic>
#include <boost/asio/io_service.hpp> #include <boost/asio/io_context.hpp>
#include <boost/asio/post.hpp>
namespace sscl::cps { namespace sscl::cps {
class AsynchronousBridge class AsynchronousBridge
{ {
public: public:
AsynchronousBridge(boost::asio::io_service &io_service) AsynchronousBridge(boost::asio::io_context &io_context)
: isAsyncOperationComplete(false), io_service(io_service) : isAsyncOperationComplete(false), io_context(io_context)
{} {}
void setAsyncOperationComplete(void) void setAsyncOperationComplete(void)
{ {
/** EXPLANATION: /** EXPLANATION:
* This empty post()ed message is necessary to ensure that the thread * 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 * that's waiting on the io_context is signaled to wake up and check
* the io_service's queue. * the io_context's queue.
*/ */
isAsyncOperationComplete.store(true); isAsyncOperationComplete.store(true);
io_service.post([]{}); boost::asio::post(io_context, []{});
} }
void waitForAsyncOperationCompleteOrIoServiceStopped(void) void waitForAsyncOperationCompleteOrIoContextStopped(void)
{ {
for (;;) for (;;)
{ {
io_service.run_one(); io_context.run_one();
if (isAsyncOperationComplete.load() || io_service.stopped()) if (isAsyncOperationComplete.load() || io_context.stopped())
{ break; } { break; }
/** EXPLANATION: /** EXPLANATION:
@@ -45,12 +45,12 @@ public:
} }
} }
bool exitedBecauseIoServiceStopped(void) const bool exitedBecauseIoContextStopped(void) const
{ return io_service.stopped(); } { return io_context.stopped(); }
private: private:
std::atomic<bool> isAsyncOperationComplete; std::atomic<bool> isAsyncOperationComplete;
boost::asio::io_service &io_service; boost::asio::io_context &io_context;
}; };
} // namespace sscl::cps } // namespace sscl::cps
@@ -90,7 +90,7 @@ public:
* LockedNonPostedAsynchronousContinuation because the only way to implement * LockedNonPostedAsynchronousContinuation because the only way to implement
* non-posted locking would be via busy-spinning or sleeplocks. This would * non-posted locking would be via busy-spinning or sleeplocks. This would
* eliminate the throughput advantage from our Qspinning mechanism, which * 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> template <class OriginalCbFnT>
class NonPostedAsynchronousContinuation class NonPostedAsynchronousContinuation
@@ -141,7 +141,7 @@ public:
if (AsynchronousContinuation<OriginalCbFnT>::originalCallback if (AsynchronousContinuation<OriginalCbFnT>::originalCallback
.callbackFn) .callbackFn)
{ {
caller->getIoService().post( boost::asio::post(caller->getIoContext(),
STC(std::bind( STC(std::bind(
AsynchronousContinuation<OriginalCbFnT>::originalCallback AsynchronousContinuation<OriginalCbFnT>::originalCallback
.callbackFn, .callbackFn,
+2 -2
View File
@@ -15,7 +15,7 @@ namespace sscl::cps {
* *
* This class wraps any callable object with metadata (caller function name, * This class wraps any callable object with metadata (caller function name,
* line number, and return addresses) to help debug cases where callables * 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. * can be accessed from the callable's address when debugging.
*/ */
class CallableTracer class CallableTracer
@@ -100,7 +100,7 @@ private:
* - Fallback: nullptr for return addresses * - Fallback: nullptr for return addresses
* *
* Usage: * Usage:
* thread->getIoService().post( * boost::asio::post(thread->getIoContext(),
* STC(std::bind(&SomeClass::method, this, arg1, arg2))); * STC(std::bind(&SomeClass::method, this, arg1, arg2)));
*/ */
#ifdef CONFIG_DEBUG_TRACE_CALLABLES #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. * time it will leave the qutexQ is when the program terminates.
* *
* I'm not sure we'll actually cancal all in-flight async sequences -- * 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 * 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 * 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. * 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; 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 * @param forceAwaken If true, post even if already awake
*/ */
virtual void awaken(bool forceAwaken = false) = 0; virtual void awaken(bool forceAwaken = false) = 0;
@@ -55,12 +55,12 @@ public:
* *
* Compare by the address of the continuation objects. Why? * Compare by the address of the continuation objects. Why?
* Because there's no guarantee that the lockvoker object that was * 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 * which is in the qutexQs. Especially because we make_shared() a
* copy when registerInQutexQueues()ing. * copy when registerInQutexQueues()ing.
* *
* Generally when we "wake" a lockvoker by enqueuing it, boost's * 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 bool operator==(const LockerAndInvokerBase &other) const
{ {
@@ -65,7 +65,7 @@ public:
* @brief LockerAndInvoker - Template class for lockvoking mechanism * @brief LockerAndInvoker - Template class for lockvoking mechanism
* *
* This class wraps a std::bind result and provides locking functionality. * 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. * queue, implementing the "spinqueueing" pattern.
*/ */
template <class InvocationTargetT> template <class InvocationTargetT>
@@ -74,10 +74,10 @@ public:
{ {
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 * @param serializedContinuation Reference to the serialized continuation
* containing LockSet and target io_service * containing LockSet and target io_context
* @param target The ComponentThread whose io_service to post to * @param target The ComponentThread whose io_context to post to
* @param invocationTarget The std::bind result to invoke when locks are acquired * @param invocationTarget The std::bind result to invoke when locks are acquired
*/ */
LockerAndInvoker( 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 * @param forceAwaken If true, post even if already awake
*/ */
void awaken(bool forceAwaken = false) override void awaken(bool forceAwaken = false) override
@@ -138,7 +138,7 @@ public:
if (prevVal == true && !forceAwaken) if (prevVal == true && !forceAwaken)
{ return; } { return; }
target->getIoService().post(*this); boost::asio::post(target->getIoContext(), *this);
} }
size_t getLockSetSize() const override size_t getLockSetSize() const override
@@ -161,14 +161,14 @@ public:
* the AsyncContinuation sh_ptr (which the Lockvoker contains within * the AsyncContinuation sh_ptr (which the Lockvoker contains within
* itself) alive without wasting too much memory. * 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 * their queues and there'll be a copy of the lockvoker in each
* Qutex's queue. * Qutex's queue.
* *
* For non-serialized, posted continuations, they won't be removed * 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 * 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. * acquire all locks.
*/ */
void registerInLockSet() void registerInLockSet()
@@ -185,7 +185,7 @@ public:
* *
* Sets isAwake=true before calling awaken with forceAwaken to ensure * Sets isAwake=true before calling awaken with forceAwaken to ensure
* that none of the locks we just registered with awaken()s a duplicate * 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() void firstWake()
{ {
@@ -213,8 +213,17 @@ public:
{ return isDeadlockLikely(); } { return isDeadlockLikely(); }
#ifdef CONFIG_ENABLE_DEBUG_LOCKS #ifdef CONFIG_ENABLE_DEBUG_LOCKS
struct obsolete { friend struct obsolete;
bool traceContinuationHistoryForGridlockOn(Qutex &firstFailedQutex);
struct obsolete
{
explicit obsolete(LockerAndInvoker &_parent) : parent(_parent)
{}
bool traceContinuationHistoryForGridlockOn(
Qutex &firstFailedQutex);
LockerAndInvoker &parent;
}; };
bool traceContinuationHistoryForDeadlockOn(Qutex &firstFailedQutex); bool traceContinuationHistoryForDeadlockOn(Qutex &firstFailedQutex);
@@ -435,7 +444,8 @@ SerializedAsynchronousContinuation<OriginalCbFnT>
* should eventually be able to acquire that lock. * should eventually be able to acquire that lock.
*/ */
for (std::shared_ptr<AsynchronousContinuationChainLink> currContin = for (std::shared_ptr<AsynchronousContinuationChainLink> currContin =
this->serializedContinuation.getCallersContinuationShPtr(); parent.serializedContinuation
.getCallersContinuationShPtr();
currContin != nullptr; currContin != nullptr;
currContin = currContin->getCallersContinuationShPtr()) currContin = currContin->getCallersContinuationShPtr())
{ {
@@ -484,7 +494,7 @@ void SerializedAsynchronousContinuation<OriginalCbFnT>
if (!serializedContinuation.requiredLocks.tryAcquireOrBackOff( if (!serializedContinuation.requiredLocks.tryAcquireOrBackOff(
*this, firstFailedQutexRet)) *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(); allowAwakening();
if (!deadlockLikely && !gridlockLikely) if (!deadlockLikely && !gridlockLikely)
{ return; } { return; }
+18
View File
@@ -0,0 +1,18 @@
#include <boost/asio/detail/call_stack.hpp>
#include <boost/asio/detail/thread_context.hpp>
#include <boost/asio/detail/tss_ptr.hpp>
namespace boost {
namespace asio {
namespace detail {
/** Single translation-unit definition for Boost.Asio call_stack TLS.
* Other TUs include boostAsioLinkageFix.h first and use extern template.
*/
template
tss_ptr<call_stack<thread_context, thread_info_base>::context>
call_stack<thread_context, thread_info_base>::top_;
} // namespace detail
} // namespace asio
} // namespace boost
+7 -7
View File
@@ -27,10 +27,10 @@ void PuppetComponent::defaultPuppetMain(
if (args.preJoltHook) { args.preJoltHook(thr); } if (args.preJoltHook) { args.preJoltHook(thr); }
/** FIXME: /** FIXME:
* Figure out why we don't call reset() here, and then explicitly document * Figure out why we don't call restart() here, and then explicitly document
* it. * it.
*/ */
thr.getIoService().run(); thr.getIoContext().run();
thr.initializeTls(); thr.initializeTls();
comp.postJoltHook(); comp.postJoltHook();
@@ -52,15 +52,15 @@ void PuppetComponent::defaultPuppetMain(
/** EXPLANATION: /** EXPLANATION:
* This reset() call is crucial for async bridging patterns * This reset() call is crucial for async bridging patterns
* to work. * to work.
* When the outermost thread's io_service is stop()ped (e.g., * When the outermost thread's io_context is stop()ped (e.g.,
* from JOLT sequence), it won't process any new work until * from JOLT sequence), it won't process any new work until
* reset() is called, even if nested async operations try to * restart() is called, even if nested async operations try to
* post work to it. This means async bridges invoked from * post work to it. This means async bridges invoked from
* the outermost thread main sequence won't work until this * the outermost thread main sequence won't work until this
* reset() call. * restart() call.
*/ */
thr.getIoService().reset(); thr.getIoContext().restart();
thr.getIoService().run(); thr.getIoContext().run();
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
+16 -17
View File
@@ -1,10 +1,9 @@
#include <boostAsioLinkageFix.h>
#include <unistd.h> #include <unistd.h>
#include <iostream> #include <iostream>
#include <string> #include <string>
#include <pthread.h> #include <pthread.h>
#include <sched.h> #include <sched.h>
#include <boost/asio/io_service.hpp> #include <boost/asio/io_context.hpp>
#include <spinscale/cps/asynchronousContinuation.h> #include <spinscale/cps/asynchronousContinuation.h>
#include <spinscale/cps/callback.h> #include <spinscale/cps/callback.h>
#include <spinscale/cps/callableTracer.h> #include <spinscale/cps/callableTracer.h>
@@ -49,7 +48,7 @@ std::shared_ptr<PuppeteerThread> ComponentThread::getPptr()
void PuppeteerThread::exitLoop(void) void PuppeteerThread::exitLoop(void)
{ {
keepLooping = false; keepLooping = false;
getIoService().stop(); getIoContext().stop();
std::cout << name << ": Signaled main loop to exit." << "\n"; std::cout << name << ": Signaled main loop to exit." << "\n";
} }
@@ -104,7 +103,7 @@ public:
"JOLT request." "JOLT request."
<< "\n"; << "\n";
target->io_service.stop(); target->io_context.stop();
callOriginalCb(); callOriginalCb();
} }
@@ -130,7 +129,7 @@ public:
"exitThread (main queue)." << "\n"; "exitThread (main queue)." << "\n";
target->cleanup(); target->cleanup();
target->io_service.stop(); target->io_context.stop();
callOriginalCb(); callOriginalCb();
} }
@@ -142,8 +141,8 @@ public:
"exitThread (pause queue)."<< "\n"; "exitThread (pause queue)."<< "\n";
target->cleanup(); target->cleanup();
target->pause_io_service.stop(); target->pause_io_context.stop();
target->io_service.stop(); target->io_context.stop();
callOriginalCb(); callOriginalCb();
} }
@@ -159,8 +158,8 @@ public:
* have a chance to invoke the callback until it's unblocked. * have a chance to invoke the callback until it's unblocked.
*/ */
callOriginalCb(); callOriginalCb();
target->pause_io_service.reset(); target->pause_io_context.restart();
target->pause_io_service.run(); target->pause_io_context.run();
} }
void resumeThreadReq1_posted( void resumeThreadReq1_posted(
@@ -170,7 +169,7 @@ public:
std::cout << __func__ << ": Thread '" << target->name << "': handling " std::cout << __func__ << ": Thread '" << target->name << "': handling "
"resumeThread." << "\n"; "resumeThread." << "\n";
target->pause_io_service.stop(); target->pause_io_context.stop();
callOriginalCb(); callOriginalCb();
} }
}; };
@@ -210,7 +209,7 @@ void PuppetThread::joltThreadReq(
auto request = std::make_shared<ThreadLifetimeMgmtOp>( auto request = std::make_shared<ThreadLifetimeMgmtOp>(
puppeteer, selfPtr, callback); puppeteer, selfPtr, callback);
this->getIoService().post( boost::asio::post(this->getIoContext(),
STC(std::bind( STC(std::bind(
&ThreadLifetimeMgmtOp::joltThreadReq1_posted, &ThreadLifetimeMgmtOp::joltThreadReq1_posted,
request.get(), request))); request.get(), request)));
@@ -224,7 +223,7 @@ void PuppetThread::startThreadReq(cps::Callback<threadLifetimeMgmtOpCbFn> callba
caller, std::static_pointer_cast<PuppetThread>(shared_from_this()), caller, std::static_pointer_cast<PuppetThread>(shared_from_this()),
callback); callback);
this->getIoService().post( boost::asio::post(this->getIoContext(),
STC(std::bind( STC(std::bind(
&ThreadLifetimeMgmtOp::startThreadReq1_posted, &ThreadLifetimeMgmtOp::startThreadReq1_posted,
request.get(), request))); request.get(), request)));
@@ -237,12 +236,12 @@ void PuppetThread::exitThreadReq(cps::Callback<threadLifetimeMgmtOpCbFn> callbac
caller, std::static_pointer_cast<PuppetThread>(shared_from_this()), caller, std::static_pointer_cast<PuppetThread>(shared_from_this()),
callback); callback);
this->getIoService().post( boost::asio::post(this->getIoContext(),
STC(std::bind( STC(std::bind(
&ThreadLifetimeMgmtOp::exitThreadReq1_mainQueue_posted, &ThreadLifetimeMgmtOp::exitThreadReq1_mainQueue_posted,
request.get(), request))); request.get(), request)));
pause_io_service.post( boost::asio::post(pause_io_context,
STC(std::bind( STC(std::bind(
&ThreadLifetimeMgmtOp::exitThreadReq1_pauseQueue_posted, &ThreadLifetimeMgmtOp::exitThreadReq1_pauseQueue_posted,
request.get(), request))); request.get(), request)));
@@ -261,7 +260,7 @@ void PuppetThread::pauseThreadReq(cps::Callback<threadLifetimeMgmtOpCbFn> callba
caller, std::static_pointer_cast<PuppetThread>(shared_from_this()), caller, std::static_pointer_cast<PuppetThread>(shared_from_this()),
callback); callback);
this->getIoService().post( boost::asio::post(this->getIoContext(),
STC(std::bind( STC(std::bind(
&ThreadLifetimeMgmtOp::pauseThreadReq1_posted, &ThreadLifetimeMgmtOp::pauseThreadReq1_posted,
request.get(), request))); request.get(), request)));
@@ -275,13 +274,13 @@ void PuppetThread::resumeThreadReq(cps::Callback<threadLifetimeMgmtOpCbFn> callb
+ ": invoked on puppeteer thread"); + ": invoked on puppeteer thread");
} }
// Post to the pause_io_service to unblock the paused thread // Post to the pause_io_context to unblock the paused thread
std::shared_ptr<ComponentThread> caller = getSelf(); std::shared_ptr<ComponentThread> caller = getSelf();
auto request = std::make_shared<ThreadLifetimeMgmtOp>( auto request = std::make_shared<ThreadLifetimeMgmtOp>(
caller, std::static_pointer_cast<PuppetThread>(shared_from_this()), caller, std::static_pointer_cast<PuppetThread>(shared_from_this()),
callback); callback);
pause_io_service.post( boost::asio::post(pause_io_context,
STC(std::bind( STC(std::bind(
&ThreadLifetimeMgmtOp::resumeThreadReq1_posted, &ThreadLifetimeMgmtOp::resumeThreadReq1_posted,
request.get(), request))); request.get(), request)));
+8 -8
View File
@@ -16,8 +16,8 @@ void PuppeteerComponent::defaultPuppeteerMain(
if (args.preJoltHook) { args.preJoltHook(thr); } if (args.preJoltHook) { args.preJoltHook(thr); }
thr.getIoService().reset(); thr.getIoContext().restart();
thr.getIoService().run(); thr.getIoContext().run();
thr.initializeTls(); thr.initializeTls();
comp.postJoltHook(); comp.postJoltHook();
@@ -40,17 +40,17 @@ void PuppeteerComponent::defaultPuppeteerMain(
try { try {
/** EXPLANATION: /** EXPLANATION:
* This reset() call is crucial for async bridging * This restart() call is crucial for async bridging
* patterns to work. * patterns to work.
* When the outermost thread's io_service is stop()ped * When the outermost thread's io_context is stop()ped
* (e.g., from JOLT sequence), it won't process any new * (e.g., from JOLT sequence), it won't process any new
* work until reset() is called, even if nested async * work until restart() is called, even if nested async
* operations try to post work to it. This means async * operations try to post work to it. This means async
* bridges invoked from the outermost thread main sequence * bridges invoked from the outermost thread main sequence
* won't work until this reset() call. * won't work until this restart() call.
*/ */
thr.getIoService().reset(); thr.getIoContext().restart();
thr.getIoService().run(); thr.getIoContext().run();
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
+3 -3
View File
@@ -288,8 +288,8 @@ void Qutex::backoff(
* (Assume that Lv2 was not at the front of the common qutex's * (Assume that Lv2 was not at the front of the common qutex's
* internal queue -- it only needed to be in the top 66%.) * internal queue -- it only needed to be in the top 66%.)
* Lv1 tries to acquire the common lock and fails. It gets taken off of * Lv1 tries to acquire the common lock and fails. It gets taken off of
* its io_service. It's now asleep until it gets * its io_context. It's now asleep until it gets
* re-added into an io_service. * re-added into an io_context.
* Lv2 fails to acquire the other 2 locks it needs and backoff()s from * Lv2 fails to acquire the other 2 locks it needs and backoff()s from
* the common lock it shares with Lv1. * the common lock it shares with Lv1.
* *
@@ -357,7 +357,7 @@ void Qutex::release()
* Just before Lv1 can acquire the common lock, Lv2 acquires it now, * Just before Lv1 can acquire the common lock, Lv2 acquires it now,
* because it only needs to be in the top 66% to succeed. * because it only needs to be in the top 66% to succeed.
* Lv1 checks the currOwner and sees that it's owned. Lv1 is now * Lv1 checks the currOwner and sees that it's owned. Lv1 is now
* dequeued from its io_service. It won't be awakened until someone * dequeued from its io_context. It won't be awakened until someone
* awakens it. * awakens it.
* Lv2 finishes its critical section and releas()es the common lock. * Lv2 finishes its critical section and releas()es the common lock.
* Lv2 was not at the front of the qutexQ, so it does NOT awaken the * Lv2 was not at the front of the qutexQ, so it does NOT awaken the