livoxGen1🐛 Call stop() on all producers before deleting in _exit

This commit is contained in:
2026-06-14 15:34:07 -04:00
parent 24eee2d240
commit acb684ad35
5 changed files with 204 additions and 109 deletions
+130 -78
View File
@@ -20,7 +20,7 @@ const SmoCallbacks *smoHooksPtr = nullptr;
SmoThreadingModelDesc smoThreadingModelDesc;
// Local collection of stimulus producers
std::vector<std::shared_ptr<StimulusProducer>> attachedStimulusProducers;
std::vector<std::shared_ptr<StimulusProducer>> managedStimulusProducers;
LivoxProto1DllState::LivoxProto1DllState()
: dlopenHandle(nullptr, DlCloser),
@@ -46,7 +46,7 @@ LivoxProto1DllState livoxProto1;
std::shared_ptr<StimulusProducer> getStimulusProducer(
const std::shared_ptr<device::DeviceAttachmentSpec> &spec)
{
for (const auto &stimProducer : attachedStimulusProducers)
for (const auto &stimProducer : managedStimulusProducers)
{
if (livoxProto1::comms::deviceIdentifiersEqual(
stimProducer->deviceAttachmentSpec->deviceSelector,
@@ -189,6 +189,8 @@ LivoxProviderParams parseLivoxProviderParams(
return params;
}
constexpr size_t MAX_STIM_PRODUCERS_PER_DEVICE = 2;
// Helper method to ensure StimBuffer is attached
// Returns true if successful, false on error
bool ensureStimBufferAttachedWithoutDuplicates(
@@ -224,9 +226,125 @@ bool ensureStimBufferAttachedWithoutDuplicates(
return true;
}
void addManagedStimulusProducer(
const std::shared_ptr<PcloudStimulusProducer> &producer,
const std::shared_ptr<livoxProto1::Device> &device)
{
if (!producer || !device) {
throw std::runtime_error(
std::string(__func__) + ": producer and device must be non-null");
}
device->nAttachedStimulusProducers++;
if (device->nAttachedStimulusProducers > MAX_STIM_PRODUCERS_PER_DEVICE)
{
device->nAttachedStimulusProducers--;
throw std::runtime_error(
std::string(__func__) + ": Each LivoxGen1 device can only have "
"at most two StimulusProducers attached to it. Found "
+ std::to_string(device->nAttachedStimulusProducers + 1) + ".");
}
managedStimulusProducers.push_back(producer);
if (false
/*managedStimulusProducers.size() >= 2*nDevicesKnownToGen1Lib */)
{
/** TODO:
* It would be nice to add an nDevicesKnownToGen1Lib counter, and
* then add a check here to ensure that
* managedStimulusProducers.size() is always less than or equal to
* 2*nDevicesKnownToGen1Lib.
*
* (2 stim producers per device).
*/
#if 0
throw std::runtime_error(
std::string(__func__) + ": Number of StimulusProducers attached "
"to LivoxGen1 devices known to the library ("
+ std::to_string(managedStimulusProducers.size())
+ ") is greater than "
"expected. Lib knows about "
+ std::to_string(nDevicesKnownToGen1Lib) + " devices, "
"so there should be at most "
+ std::to_string(2*nDevicesKnownToGen1Lib)
+ " StimulusProducers attached to devices.");
#endif
}
producer->start();
}
sscl::co::ViralNonPostingInvoker<bool> removeManagedStimulusProducerIfUnused(
const std::shared_ptr<PcloudStimulusProducer> &producer,
const std::shared_ptr<sscl::ComponentThread> &/*componentThread*/)
{
if (!producer) {
co_return true;
}
if (!producer->attachedStimulusBuffers.empty()) {
co_return true;
}
// No other buffers - stop and remove StimProducer
producer->stop();
auto it = std::find_if(
managedStimulusProducers.begin(),
managedStimulusProducers.end(),
[&producer](const std::shared_ptr<StimulusProducer> &candidate)
{
/** FIXME:
* When we implement the ImuStimulusProducer, we need to make
* sure we handle that properly here.
*/
auto pcloudProducer =
std::dynamic_pointer_cast<PcloudStimulusProducer>(candidate);
return pcloudProducer && pcloudProducer == producer;
});
if (it != managedStimulusProducers.end()) {
managedStimulusProducers.erase(it);
}
if (!producer->device) {
co_return true;
}
if (producer->device->nAttachedStimulusProducers > 0) {
producer->device->nAttachedStimulusProducers--;
}
if (producer->device->nAttachedStimulusProducers > 0) {
co_return true;
}
const bool destroyed = co_await (*livoxProto1.livoxProto1_destroyDeviceCReq)(
producer->device);
if (!destroyed)
{
std::cerr << __func__ << ": Failed to destroy dev "
"device " << producer->deviceAttachmentSpec->deviceSelector
<< " for stim producer.\n";
co_return false;
}
co_return true;
}
namespace {
constexpr size_t MAX_STIM_PRODUCERS_PER_DEVICE = 2;
void stopAllManagedProducersBeforeFinalize()
{
for (const auto &producer : managedStimulusProducers)
{
if (!producer) {
continue;
}
producer->stop();
}
}
bool validateAttachRequest(
const std::shared_ptr<device::DeviceAttachmentSpec> &desc)
@@ -458,44 +576,7 @@ attachByCreatingProducer(
desc, deviceResult.device,
formatDesc, nDgramsPerFrame);
deviceResult.device->nAttachedStimulusProducers++;
if (deviceResult.device->nAttachedStimulusProducers
> MAX_STIM_PRODUCERS_PER_DEVICE)
{
throw std::runtime_error(
std::string(__func__) + ": Each LivoxGen1 device can only have "
"at most two StimulusProducers attached to it. Found "
+ std::to_string(deviceResult.device->nAttachedStimulusProducers)
+ ".");
}
attachedStimulusProducers.push_back(pcloudDataProducer);
if (false
/*attachedStimulusProducers.size() >= 2*nDevicesKnownToGen1Lib */)
{
/** TODO:
* It would be nice to add an nDevicesKnownToGen1Lib counter, and
* then add a check here to ensure that
* attachedStimulusProducers.size() is always less than or equal to
* 2*nDevicesKnownToGen1Lib.
*
* (2 stim producers per device).
*/
#if 0
throw std::runtime_error(
std::string(__func__) + ": Number of StimulusProducers attached "
"to LivoxGen1 devices known to the library ("
+ std::to_string(attachedStimulusProducers.size())
+ ") is greater than "
"expected. Lib knows about "
+ std::to_string(nDevicesKnownToGen1Lib) + " devices, "
"so there should be at most "
+ std::to_string(2*nDevicesKnownToGen1Lib)
+ " StimulusProducers attached to devices.");
#endif
}
pcloudDataProducer->start();
addManagedStimulusProducer(pcloudDataProducer, deviceResult.device);
// Ensure StimBuffer is attached
co_return co_await attachBufferAndEnablePcloud(
@@ -592,8 +673,8 @@ livoxGen1_detachDeviceCReq(
// Add 5ms delay before destroying device
// Helper method to delay and then call destroyDeviceReq
// Initialize timer with LivoxGen1 metadata io_context
// Helper method to delay and then call destroyDeviceReq
// Initialize timer with LivoxGen1 metadata io_context
boost::asio::deadline_timer commandDelayTimer(
requestComponentThread->getIoContext());
co_await adapters::boostAsio::getDeadlineTimerAReqAwaiter(
@@ -601,40 +682,9 @@ livoxGen1_detachDeviceCReq(
commandDelayTimer,
boost::posix_time::milliseconds(LIVOX_GEN1_DEVICE_COMMAND_DELAY_MS));
// No other buffers - stop and remove StimProducer
stimProducer->stop();
// Remove stimulus producer from collection before destroying device
stimProducer->device->nAttachedStimulusProducers--;
// Find and remove the producer from the collection by comparing device
auto it = std::find_if(
attachedStimulusProducers.begin(),
attachedStimulusProducers.end(),
[&stimProducer](const std::shared_ptr<StimulusProducer> &producer)
{
/** FIXME:
* When we implement the ImuStimulusProducer, we need to make
* sure we handle that properly here.
*/
auto pcloudProducer =
std::dynamic_pointer_cast<PcloudStimulusProducer>(producer);
return pcloudProducer && pcloudProducer->device == stimProducer->device;
});
if (it != attachedStimulusProducers.end()) {
attachedStimulusProducers.erase(it);
}
const bool destroyed = co_await (*livoxProto1.livoxProto1_destroyDeviceCReq)(
stimProducer->device);
if (!destroyed) {
std::cerr << __func__ << ": Failed to destroy dev "
"device " << desc->deviceSelector << " for stim "
"producer.\n";
/** NOTE:
* There's a decent argument for falling through here and still
* removing the stimulus producer from attachedStimulusProducers.
*/
const bool removedOk = co_await removeManagedStimulusProducerIfUnused(
stimProducer, requestComponentThread);
if (!removedOk) {
co_return StimBuffDeviceOpResult{false, desc};
}
@@ -723,7 +773,9 @@ sscl::co::ViralNonPostingInvoker<int> livoxGen1_initializeCInd()
sscl::co::ViralNonPostingInvoker<int> livoxGen1_finalizeCInd()
{
attachedStimulusProducers.clear();
stopAllManagedProducersBeforeFinalize();
managedStimulusProducers.clear();
if (livoxProto1.livoxProto1_exit) {
(*livoxProto1.livoxProto1_exit)();
}
+9 -1
View File
@@ -29,7 +29,15 @@ struct LivoxProviderParams
extern const SmoCallbacks *smoHooksPtr;
extern SmoThreadingModelDesc smoThreadingModelDesc;
extern std::vector<std::shared_ptr<StimulusProducer>> attachedStimulusProducers;
extern std::vector<std::shared_ptr<StimulusProducer>> managedStimulusProducers;
void addManagedStimulusProducer(
const std::shared_ptr<PcloudStimulusProducer> &producer,
const std::shared_ptr<livoxProto1::Device> &device);
sscl::co::ViralNonPostingInvoker<bool> removeManagedStimulusProducerIfUnused(
const std::shared_ptr<PcloudStimulusProducer> &producer,
const std::shared_ptr<sscl::ComponentThread> &componentThread);
std::shared_ptr<StimulusProducer> getStimulusProducer(
const std::shared_ptr<device::DeviceAttachmentSpec> &spec);