LivoxGen1: Use syncCancelerForAsyncWork in producer pipeline
This commit is contained in:
@@ -22,7 +22,6 @@
|
||||
#include <spinscale/cps/asynchronousBridge.h>
|
||||
#include <spinscale/cps/callback.h>
|
||||
#include <spinscale/cps/callableTracer.h>
|
||||
#include <spinscale/spinLock.h>
|
||||
#include "ioUringAssemblyEngine.h"
|
||||
#include "pcloudStimulusProducer.h"
|
||||
#include "livoxGen1.h"
|
||||
@@ -59,7 +58,6 @@ IoUringAssemblyEngine::IoUringAssemblyEngine(
|
||||
frameAssemblyDesc(nullptr), ring{},
|
||||
eventfdFd(-1), eventfdDesc(nullptr), eventfd_value(0),
|
||||
stallTimer(parent_.device->componentThread->getIoService()),
|
||||
shouldAcceptRequests(false),
|
||||
nDgramsPerStagingBufferFrame(nDgramsPerStagingBufferFrame_),
|
||||
assembledSlotsTracker(nDgramsPerStagingBufferFrame_),
|
||||
randomDevice(), randomGenerator(randomDevice())
|
||||
@@ -68,13 +66,10 @@ randomDevice(), randomGenerator(randomDevice())
|
||||
bool IoUringAssemblyEngine::setup()
|
||||
{
|
||||
// Defensive check to prevent double-calling
|
||||
if (!ioUringAssemblyEngnCanceler.isCancellationRequested())
|
||||
{
|
||||
sscl::SpinLock::Guard lock(shouldAcceptRequestsLock);
|
||||
if (shouldAcceptRequests)
|
||||
{
|
||||
throw std::runtime_error(std::string(__func__) + ": setup() called "
|
||||
"while already set up");
|
||||
}
|
||||
throw std::runtime_error(std::string(__func__) + ": setup() called "
|
||||
"while already set up");
|
||||
}
|
||||
|
||||
// Get FrameAssemblyDesc from staging buffer
|
||||
@@ -156,7 +151,7 @@ bool IoUringAssemblyEngine::setup()
|
||||
if (ret < 0)
|
||||
{ goto cleanup_eventfd; }
|
||||
|
||||
shouldAcceptRequests = true;
|
||||
ioUringAssemblyEngnCanceler.startAcceptingWork();
|
||||
return true;
|
||||
|
||||
cleanup_eventfd:
|
||||
@@ -229,7 +224,7 @@ void IoUringAssemblyEngine::resetAndAssembleFrame(
|
||||
+ ": onCqeReady callback is invalid");
|
||||
}
|
||||
|
||||
if (!shouldAcceptRequests)
|
||||
if (ioUringAssemblyEngnCanceler.isCancellationRequestedUnlocked())
|
||||
{
|
||||
throw std::runtime_error(std::string(__func__)
|
||||
+ ": engine is not accepting requests");
|
||||
@@ -321,11 +316,7 @@ void IoUringAssemblyEngine::resetAndAssembleFrame(
|
||||
|
||||
bool IoUringAssemblyEngine::stop()
|
||||
{
|
||||
// Acquire and release lock tightly around setting the flag
|
||||
sscl::SpinLock::Guard lock(shouldAcceptRequestsLock);
|
||||
bool wasAcceptingRequests = shouldAcceptRequests;
|
||||
shouldAcceptRequests = false;
|
||||
return wasAcceptingRequests;
|
||||
return ioUringAssemblyEngnCanceler.requestStop();
|
||||
}
|
||||
|
||||
void IoUringAssemblyEngine::assemblyCycleComplete()
|
||||
@@ -444,39 +435,44 @@ public:
|
||||
void assembleFrameReq1_posted(
|
||||
std::shared_ptr<AssembleFrameReq> context)
|
||||
{
|
||||
sscl::SpinLock::Guard lock(engine.shouldAcceptRequestsLock);
|
||||
auto& canceler = engine.ioUringAssemblyEngnCanceler;
|
||||
const bool started = canceler.execUncancelableSegmentOrAbort(
|
||||
[context, this]()
|
||||
{
|
||||
// Initialize loop with number of slots
|
||||
context->loop = sscl::AsynchronousLoop(
|
||||
engine.frameAssemblyDesc->numSlots);
|
||||
|
||||
if (!engine.shouldAcceptRequests)
|
||||
// Record assembly start time
|
||||
engine.assemblyStartTime =
|
||||
std::chrono::high_resolution_clock::now();
|
||||
|
||||
/** FIXME:
|
||||
* I'm suspicious of this std::bind return object here. What if us
|
||||
* setting it to null inside of stop() doesn't actually cause the
|
||||
* object to be destroyed? This would cause this contin's sh_ptr's
|
||||
* reference count to never reach 0, causing a memory leak.
|
||||
*/
|
||||
engine.resetAndAssembleFrame(
|
||||
std::bind(&AssembleFrameReq::assembleFrameReq2_2,
|
||||
context.get(), context,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
// Set up timeout timer for IOURINGASSM_ENGN_FRAME_ASSEM_TIMEOUT_MS ms
|
||||
engine.stallTimer.expires_from_now(
|
||||
boost::posix_time::milliseconds(
|
||||
IOURINGASSM_ENGN_FRAME_ASSEM_TIMEOUT_MS));
|
||||
engine.stallTimer.async_wait(
|
||||
std::bind(&AssembleFrameReq::assembleFrameReq2_1,
|
||||
context.get(), context,
|
||||
std::placeholders::_1));
|
||||
});
|
||||
|
||||
if (!started)
|
||||
{
|
||||
context->callOriginalCallback(false, sscl::AsynchronousLoop(0));
|
||||
return;
|
||||
}
|
||||
|
||||
// Initialize loop with number of slots
|
||||
context->loop = sscl::AsynchronousLoop(engine.frameAssemblyDesc->numSlots);
|
||||
|
||||
// Record assembly start time
|
||||
engine.assemblyStartTime = std::chrono::high_resolution_clock::now();
|
||||
|
||||
/** FIXME:
|
||||
* I'm suspicious of this std::bind return object here. What if us
|
||||
* setting it to null inside of stop() doesn't actually cause the
|
||||
* object to be destroyed? This would cause this contin's sh_ptr's
|
||||
* reference count to never reach 0, causing a memory leak.
|
||||
*/
|
||||
engine.resetAndAssembleFrame(
|
||||
std::bind(&AssembleFrameReq::assembleFrameReq2_2,
|
||||
context.get(), context,
|
||||
std::placeholders::_1, std::placeholders::_2));
|
||||
|
||||
// Set up timeout timer for IOURINGASSM_ENGN_FRAME_ASSEM_TIMEOUT_MS ms
|
||||
engine.stallTimer.expires_from_now(
|
||||
boost::posix_time::milliseconds(
|
||||
IOURINGASSM_ENGN_FRAME_ASSEM_TIMEOUT_MS));
|
||||
engine.stallTimer.async_wait(
|
||||
std::bind(&AssembleFrameReq::assembleFrameReq2_1,
|
||||
context.get(), context,
|
||||
std::placeholders::_1));
|
||||
}
|
||||
|
||||
void assembleFrameReq2_1(
|
||||
@@ -498,19 +494,22 @@ public:
|
||||
* indeed seen a SEGFAULT even in the current code with locking, so
|
||||
* I'm going to hold the lock here for now.
|
||||
*/
|
||||
sscl::SpinLock::Guard lock(context->engine.shouldAcceptRequestsLock);
|
||||
auto& canceler = context->engine.ioUringAssemblyEngnCanceler;
|
||||
const bool shouldContinue = canceler.execUncancelableSegmentOrAbort(
|
||||
[context]()
|
||||
{
|
||||
// Set timer fired flag
|
||||
context->timerFired.store(true);
|
||||
context->assembleFrameReq3(context);
|
||||
});
|
||||
|
||||
if (!context->engine.shouldAcceptRequests)
|
||||
if (!shouldContinue)
|
||||
{
|
||||
context->engine.assemblyCycleComplete();
|
||||
context->loop.setRemainingIterationsToFailure();
|
||||
context->callOriginalCallback(false, context->loop);
|
||||
return;
|
||||
}
|
||||
|
||||
// Set timer fired flag
|
||||
context->timerFired.store(true);
|
||||
context->assembleFrameReq3(context);
|
||||
}
|
||||
|
||||
void assembleFrameReq2_2(
|
||||
@@ -518,7 +517,8 @@ public:
|
||||
void *user_data, int cqe_result)
|
||||
{
|
||||
// NB: The lock was acquired by onEventFdRead before calling this func
|
||||
if (!context->engine.shouldAcceptRequests)
|
||||
if (context->engine.ioUringAssemblyEngnCanceler
|
||||
.isCancellationRequestedUnlocked())
|
||||
{
|
||||
context->engine.assemblyCycleComplete();
|
||||
context->loop.setRemainingIterationsToFailure();
|
||||
@@ -549,8 +549,8 @@ public:
|
||||
{
|
||||
/** EXPLANATION:
|
||||
* All branch paths that invoke this unifyig oracle function are
|
||||
* expected to already hold the shouldAcceptRequestsLock before calling
|
||||
* it.
|
||||
* expected to already hold ioUringAssemblyEngnCanceler's lock before
|
||||
* calling it.
|
||||
*/
|
||||
// Ensure we only execute once using atomic exchange
|
||||
if (context->handlerExecuted.exchange(true)) { return; }
|
||||
@@ -638,8 +638,7 @@ void IoUringAssemblyEngine::assembleFrameReq(
|
||||
sscl::cps::Callback<assembleFrameReqCbFn> cb)
|
||||
{
|
||||
{
|
||||
sscl::SpinLock::Guard lock(shouldAcceptRequestsLock);
|
||||
if (!shouldAcceptRequests)
|
||||
if (ioUringAssemblyEngnCanceler.isCancellationRequested())
|
||||
{
|
||||
cb.callbackFn(false, sscl::AsynchronousLoop(0));
|
||||
return;
|
||||
@@ -670,7 +669,7 @@ void IoUringAssemblyEngine::onEventfdRead(
|
||||
* IoUringAssemblyEngine's per-assembly state isn't destroyed while this
|
||||
* handler is running.
|
||||
*/
|
||||
sscl::SpinLock::Guard lock(shouldAcceptRequestsLock);
|
||||
sscl::SpinLock::Guard lock(ioUringAssemblyEngnCanceler.s.lock);
|
||||
/** EXPLANATION:
|
||||
* You'd think we should put check for shouldAcceptRequests here and
|
||||
* `return` here if !shouldAcceptRequests, but we shouldn't because
|
||||
@@ -722,7 +721,7 @@ void IoUringAssemblyEngine::onEventfdRead(
|
||||
* But we do put a `return` here because we know that at this point, the
|
||||
* caller's callback has already been invoked.
|
||||
*/
|
||||
if (!shouldAcceptRequests
|
||||
if (ioUringAssemblyEngnCanceler.isCancellationRequestedUnlocked()
|
||||
|| eventfdDesc == nullptr || !eventfdDesc->is_open())
|
||||
{
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user