This function is the backbone for the DeviceReattacher daemon. It
assembles a list of all DA specs which are known to Mrntt, but which
haven't been successfully attached as yet, and attempts to attach
them.
This method wraps around attachAllUnattachedDevicesFromReq and supplies
it with a sh_ptr<> collection of all DASpecs parsed by the DAP parser
from the cmdline.
The initialization sequence now correctly initializes all DAP specs
given on the cmdline again.
This method now accepts a sh_ptr<vector<DeviceAttachmentSpec>> to
tell it specifically which specs to attempt to attach.
This enables us to implement different frontends that supply it
with collections of devices from different sources (GUI, cmdline,
previously failed-to-attach/hot-removed devices, etc).
SMO temporarily initializes none of the devices from the cmdline
during this commit as we transition to implementing the cmdline
collection frontend.
We've renamed these now to better reflect what they do.
* attachAllSenseDevicesFromSpecsReq=>attachAllUnattachedDevicesFromReq
* detachAllSenseDevicesReq=>detachAllAttachedDeviceRoles
This is also the first step in changing
attachAllUnattachedDevicesFrom to accept a sh_ptr<> to a collection
of DeviceAttachmentSpecs. This will enable us to unify the underlying
spec attachment logic and just create several front-ends for attaching
specs from multiple sources.
This performs a more complete device initialization and attachment
sequence. We'll do the corresponding teardown in the shutdown
sequence later.
We might probably do it as deviceRoleGoneAwayInd()
We've decided to add a separate notion of a DeviceRole to track attached
device roles now. We no longer use the collection of deviceSpecs to
track which roles have been attached. Rather, this list will simply
collate all known deviceAttachment specs which are expected to be
maintained in an attached state.
SMO can periodically scan through these and cross-reference this
collection with the collection of attachedDeviceRoles. Then it can
re-try to attach those which aren't currently attached at any given
moment. This will give resilience against device attachment failures
or device resets/malfunctions, at runtime.
This is logically cleaner and it begins preparing our next set
of restructuring changes. To wit: we're revamping the device
manager to distinguish between devices and their roles.
They are posted to Marionette.
* We also fixed callOriginCb invocations;
* Also made posted CBs use std::bind instead of greedily
early-invoking the CB on the servicing thread's stack.
We no longer need them because we now have
mrntt::mrntt.finalizeReq(), which does a more holistic job of
shutting down Marionette (and thus, ultimately, Salmanoff).
If even one step in Body.initializeReq was executed at all, then
whether or not it succeeded, we consider the body component to have
been initialized, at least with respect to whether finalizeReq
ought to run.
We now run body.finalizeReq even if body.init wasn't called. We'll
do a finer-grained check on each aspect of Body that needs to be
finalized now. This check was too large-grained.
This makes the initialization sequence much cleaner and conceptually
well encapsulated.
We also now dynamically allocate the Mind objects. They're allocated
dynamically by Mrntt inside of initializeReq. This means that we no
longer have to worry about jolting and cleaning up the running threads
of global mind object even when we never explicitly called
Mind.initializeReq.
Along with other conceptual improvements to our abstractions, this
patch also gets us to a real "end of program initialization" point
for the first time.
We now allocate globalMind locally inside of marionetteMain. Why?
Before now, we had an asymmetric threading situation where the
globalMind's threads were initialized at during global constructor
invocation and not on demand. This meant that we had to shut down
those threads even if we had never got to the point of calling
Mind::initializeReq.
This significantly complicated our shutdown sequence since we had
to factor in the lifetime of the std::thread objects inside of the
ComponentThreads which were inside of the globalMind object.
Now, if we hadn't called Mind::initializeReq, we don't have to
perform any Mind::finalizeReq or adjacent operations. Shutdown is
symmetrically mirrored against the operations we actually performed
during execution.
We introduced some complexity by splitting ComponentThreads into
two derivative types (MindThread and MarionetteThread) but I think
in the long term we'll be able to massage this split into a much
cleaner situation overall.
In Mrntt, we now initialize Mind:: object threads before calling
initializeSalmanoffReq().
We've also propagated the spinscale async pattern into the Mind
class.
This is the culmination of a lot of changes over the last week. We're
making SMO basically fully async in many areas, and then preparing to
implement the spinqueueing mechanism for locking.
Now we have modularized the Mind class to contain all of its
ComponentThreads. This enables us to run multiple mind instances
within the same SMO process, at least in theory.
We probably won't actually do this, but we want to ensure that the
design is clean enough to enable it.
Gave me some ideas about how things should be structured. Apparently
merely using region-data-locked threads doesn't eliminate the need
for synchronization/locking. It just means your synchronization is much
lighter, in the form of localized variables.
It seems we'll need to maintain boolean trackers for certain
operations that shouldn't be performed concomitantly, and deny
the caller access to those operations in order to preserve
data sanity.
I guess we still ended up using locking after all. Tbh, I'm not even
sure this will make things end up being lighter: we may have to bounce
requests off, or perhaps re-enqueue them into the queue?
So maybe instead of bouncing requests off, we could re-add them to the
rear of the queue when they conflict with an ongoing request.
This language is used broadly to specify how to attach (and thus
also how to detach) devices to/from Salmanoff. The next bit of work
we'll do is split off the DSL parsing from the management of the
list of parsed binary attached spec objects.
We'll be creating a PipeDeviceAttachmentParser, and later on when
we support URDF, we'll create a URDFDeviceAttachmentParser.
This is generally frowned upon but it makes this code 10x cleaner.
We handle commandLine usage msg printing by using exceptions for
control flow. This allows us to centralize the logic for killing
the Mind threads in one place. At least with respect to printing
the usage msg.