In the Lumiera code base, we use C-String constants as unique error-IDs.
Basically this allows to create new unique error IDs anywhere in the code.
However, definition of such IDs in arbitrary namespaces tends to create
slight confusion and ambiguities, while maintaining the proper use statements
requires some manual work.
Thus I introduce a new **standard scheme**
* Error-IDs for widespread use shall be defined _exclusively_ into `namespace lumiera::error`
* The shorthand-Macro `LERR_()` can now be used to simplify inclusion and referral
* (for local or single-usage errors, a local or even hidden definition is OK)
this is a (hopefully just temporary) workaround to deal with static initialisation
ordering problems. The original solution was cleaner from a code readability viewpoint,
however, when lib::Depend was used from static initialisation code, it could
be observed that the factory constructor was invoked after first use.
And while this did not interfer with the instance lifecycle management itself,
because the zero-initialisation of the instance (atomic) pointer did happen
beforehand, it would discard any special factory functions installed from such
a context (and this counts as bug for my taste).
Actually this is on the implementation side only.
Since Layer-Separation-Interfaces route each call through a binding layer,
we get two Service-"Instances" to manage
- on the client side we have to route into the Lumiera Interface system
- on the implementation side the C-Language calls from the Interface system
need to get to the actual service implementation. The latter is now
managed and exposed via DependInject::ServiceInstance
This is borderline yet acceptable;
A service might indeed depend on itself circularly
The concrete example is the Advice-System, which needs to push
the clean-up of AdviceProvicions into a static context. From there
the deleters need to call back into the AdviceSystem, since they have
no wey to find out, if this is an individual Advice being retracted,
or a mass-cleanup due to system shutdown.
Thus the DependencyFactory now invokes the actual deleter
prior to setting the instance-Ptr to NULL.
This sidesteps the whole issue with the ClassLock, which actually
must be already destroyed at that point, according to the C++ standard.
(since it was created on-demand, on first actual usage, *after* the
DependencyFactory was statically initialised). A workaround would be
to have the ctor of DependencyFactory actively pull and allocate the
Monitor for the ClassLock; however this seems a bit overingeneered
to deal with such a borderline issue
...and package the ZombieCheck as helper object.
Also rewrite the SyncClassLock_test to perform an
multithreaded contended test to prove the lock is shared and effective
Static initialisation and shutdown can be intricate; but in fact they
work quite precise and deterministic, once you understand the rules
of the game.
In the actual case at hand the ClassLock was already destroyed, and
it must be destroyed at that point, according to the standard. Simply
because it is created on-demand, *after* the initialisation of the
static DependencyFactory, which uses this lock, and so its destructor
must be called befor the dtor of DependencyFactory -- which is precisely
what happens.
So there is no need to establish a special secure "base runtime system",
and this whole idea is ill-guided. I'll thus close ticket #1133 as wontfix
Conflicts:
src/lib/dependable-base.hpp
- state-of-the-art implementation of access with Double Checked Locking + Atomics
- improved design for configuration of dependencies. Now at the provider, not the consumer
- support for exposing services with a lifecycle through the lib::Depend<SRV> front-end
Most dependencies within Lumiera are singletons and this approach remains adequate.
Singletons are not "EVIL" per se. But in some cases, there is an explicit
lifecycle, managed by some subsystem. E.g. some GUI services are only available
while the GTK event loop is running.
This special case can be integrated transparently into our lib::Depend<TY> front-end,
which defaults to creating a singleton otherwise.
- upgrade the configuration to a current version
- provide a frontpage with cross-links to other documentation
- define a set of modules; relevant classes and files can be
added to these, to create a exploration path for new readers
- fix a lot of errors in documentation comments
- use a custom configuration for the documentation pages
- tweak the navigation, the sections and further arrangements
We don't need this ability and it pushes us into using a
central registry. This solution turned out to be problematic
when loading dynamic libraries (plug-ins).
lib::Depend<TY> works as drop-in replacement for lib::Singleton<TY>
This changeset removes the convoluted special cases like
SingletonSub and MockInjector.