Some sections of the Lumiera website document meeting minutes, discussion protocols and design proposals from the early days of the project; these pages were initially authored in the »Moin Moin Wiki« operated by Cehteh on pipapo.org at that time; this wiki backed the first publications of the »Cinelerra-3« initiative, which turned into the Lumiera project eventually. Some years later, those pages were transliterated into Asciidoc semi-automatically, resulting in a lot of broken markup and links. This is a long standing maintenance problem problem plaguing the Lumiera website, since those breakages cause a lot of warnings and flood the logs of any linkchecker run.
148 lines
8.7 KiB
Text
148 lines
8.7 KiB
Text
The Application : Start-up and Subsystems
|
|
=========================================
|
|
:Date: 2009
|
|
:Author: Ichthyo
|
|
|
|
//MENU: label Start-up
|
|
|
|
.the purpose of »Application-main«
|
|
Lumiera is envisioned as a heavyweight yet coherent »**Application**« -- not so much
|
|
as platform, framework or operating system. And, in accordance with this focus, we
|
|
place no emphasis on possible configuration changes and state transitions within
|
|
the running application _as a whole._ And, while in fact it is possible to close
|
|
and load a new Session, most of the time we assume the application just to be
|
|
``up and running'' -- all required services to be available and interfaces to
|
|
be accessible. Without doubt, these are simplifications, but serve us well
|
|
to cut down complexity -- yet still there needs to be one dedicated realm
|
|
to deal with these specific concerns of configuration, dependency and lifecyle.
|
|
|
|
|
|
The Application Realm
|
|
---------------------
|
|
So we treat all these concerns within a small and self contained structure, clearly
|
|
set apart from all the other layers, services and subsystems. This dedicated
|
|
_Application Realm_ is organised around the ``Application main object''.footnote:[
|
|
This is the singleton `lumiera::AppState`, which is triggered by the `main` function
|
|
of the Lumiera Application. The sourcecode is kept in a separate folder 'src/common'
|
|
and linked into the shared library 'liblumieracommon.so']
|
|
It serves the purpose of pulling up and tearing down the application in a controlled
|
|
fashion. And additionally, it provides the Interface and Config core services.
|
|
The act of building or tearing down this core realm and main object is what creates
|
|
the *Lifecycle* of the application. This is a succession of ``lifecycle phases'' --
|
|
and almost all activities happen within the _operational phase,_ when everything
|
|
is ``up and running'' or ``just available''.
|
|
|
|
Subsystems
|
|
~~~~~~~~~~
|
|
However, initially the application needs to be brought up, and at the end, all
|
|
parts need to be unwound cleanly. To organise this process, we identify a limited
|
|
number of *Subsystems* within the Application, which are more or less independent.
|
|
Each link:{ldoc}/design/architecture/Subsystems.html[Subsystem] is self contained
|
|
and groups some other parts and services, which typically work together and may
|
|
be mutually dependent. These subsystems represent a grouping, applied for the purpose
|
|
of starting and stopping the application in a regular way; they rather do not
|
|
correspond 1:1 to a layer, an interface, a class or a plugin. As a matter of fact,
|
|
they are _rather irrelevant_ outside the mentioned »Application realm«. A subsystem
|
|
may depend on other subsystems, which comprises a clear startup- and shutdown-ordering.
|
|
However, once the application is in normal operational mode, the subsystems turn
|
|
into a passive, guarding and managing role; the activities relevant for the
|
|
application's purpose rather rely on components, interfaces, services, all
|
|
aggregated into the three Layers »Stage«, »Steam« and »Vault«.
|
|
|
|
__We expect the following subsystems to be built eventually:__ +
|
|
Engine, Session, PlayOut, GUI, Script runner, Renderfarm node.
|
|
|
|
Organisation of Subsystems
|
|
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
Not all subsystems need to be started for any use of the application. A script-driven
|
|
use, or a renderfarm node does not need a GUI. So there is an overall global operation
|
|
mode of the application, controlled through the launching options, and determined during
|
|
the startup phase. It is the responsibility of the _Application main object_ to
|
|
pull up required functionality, which in turn might result in pulling up
|
|
further subsystems as dependencies.
|
|
|
|
Subsystems are defined by implementing the interface `lumiera::Subsys`, which acts
|
|
as façade to conduct the lifecycle, find out about dependencies and shut down
|
|
the subsystem in the end. So this interface, together with the _Subsystem Runner,_
|
|
define a lifecycle protocol; each subsystem is free to implement this as it
|
|
sees fit. Typically, this façade will load plugins, register and provide further
|
|
_business interfaces,_ and especially set up the _Layer separation interfaces_
|
|
which canalise any communication going on between the layers.
|
|
|
|
The *GUI Façade* is special, while in compliance with this protocol. The actual
|
|
UI is loaded from a plug-in at runtime,footnote:[This corresponds to the vision
|
|
to allow for different Lumiera UI's -- maybe to support different working styles
|
|
or target audiences. If such is actually feasible remains to be clarified as of
|
|
2020; even while decoupled on a technical level, the session still needs to make
|
|
a lot of assumptions regarding the UI's capabilities and needs.]
|
|
and so the implementation of this façade needs to reside in the application core
|
|
realm; it will start a `GuiRunner` to load and activate the GUI plug-in, which
|
|
then in turn has to open the public _GUI Notification_ façade. The latter is
|
|
one of the _Layer separation interfaces_ and comprises the actual way for the
|
|
lower layers to activate and interact with the user interface.
|
|
|
|
Parallelism
|
|
~~~~~~~~~~~
|
|
Actually this scheme builds on the assumption that starting each subsystem will
|
|
not block the overall start/main/shutdown thread. Any subsystem is supposed
|
|
to spawn its own control/event threads if necessary. The Lumiera application
|
|
works fundamentally asynchronous. The user interface operates single threaded,
|
|
in accordance to long established best practices of UI programming. However,
|
|
any user interaction is translated into commands, sent down into the session
|
|
and handled there one by one. The result of processing such commands will be
|
|
pushed back up into the UI later and detached from the immediate interaction.
|
|
Likewise, the re-rendering caused by changes in the session is carried out
|
|
within the engine independently, relying on worker jobs and a thread pool.
|
|
|
|
|
|
Initialisation and Lifecycle
|
|
----------------------------
|
|
After some discussion,footnote:[See the
|
|
link:{rfc}/GlobalInitialization.html[GlobalInitialisation] RfC
|
|
from spring 2008. In the beginning, we all agreed to ``keep matters simple''
|
|
and build an `init()` function within one central piece of code everyone knows
|
|
and hooks into. However, while the outline of the application emerged, there
|
|
was a tension between the concern about _over-engineering_ versus the concern
|
|
about _tangled and unmanageable complexity._ At some point, an alternative
|
|
implementation based on lifecycle callbacks was elaborated, which then turned
|
|
into the solution described here. Lumiera then ceased to be the typical UI
|
|
application started by GTK, and the existing GTK code was retrofitted to
|
|
launch from within a plug-in.]
|
|
the design leaned toward loosely coupled parts and a formal lifecycle; which
|
|
saves us from investigating and coding up the various interdependencies
|
|
explicitly. Rather, the parts of the application have to comply to
|
|
link:{ldoc}/design/architecture/Subsystems.html#lifecycle[Lifecycle Phases],
|
|
and each part has to care for its own state transitions, invoked through
|
|
_lifecycle callbacks._ We can distinguish two distinct models how to deal
|
|
with lifecycle, and both are equally acceptable:
|
|
|
|
- Assuming that operations happen in response to some client's request,
|
|
this activation should go through a _service interface._ Interfaces
|
|
can be opened and closed in Lumiera, and this is accomplished by
|
|
hooking them up below some subsystem.
|
|
- However, some parts carry out continuous activities, and in that case
|
|
a _lifecycle hook_ should be registered, to limit activities to the
|
|
appropriate lifecycle phase.
|
|
|
|
Application Start
|
|
~~~~~~~~~~~~~~~~~
|
|
* some fundamental language-level facilities will be prepared during
|
|
_static initialisation._ At some point, execution enters `main(argc,arvv)`.
|
|
* `AppState::init()` brings up the plugin loader and opens the config-interface.
|
|
* ...followed by triggering *ON_GLOBAL_INIT*
|
|
* the main thread then pulls up the subsystems (`AppState::maybeStart(subsystem)`),
|
|
according to the command line options.
|
|
* within each subsystem, façade interfaces will be opened through the
|
|
interface/plug-in system.
|
|
* At this point, the GUI plug-in is loaded and launched, the windows created,
|
|
the UI event loop starts and the application becomes live.
|
|
* shutdown or failure of _any given subsystem_ initiates the shutdown sequence
|
|
by requesting all other running subsystems to terminate. In the typical case,
|
|
the UI subsystem will trigger this shutdown sequence, in response to closing
|
|
the main window.
|
|
* there is an *ON_GLOBAL_SHUTDOWN* event, which can be used for normal cleanup;
|
|
In case of an emergency exit, the *ON_EMERGENCY_EXIT* event is triggered alternatively.
|
|
* the AppState destructor tears down the core systems (config-interface and pluginloader).
|
|
* we establish a policy to _prohibit any non-local and non-trivial activities_ during the
|
|
tear-down phase after leaving the `main()` function.
|
|
|