a long standing TODO to document the actual start-up sequence, which is implemented this way since a long time now. There was an unwritten section in the "Linking and Application Structure", which seems the apropriate place for this kind of intricate techincal details. Last week, Benny Lyons was here on visit in munich and he was pondering the idea of an experimental secondary build system, as a way to learn more about the source structure of Lumiera. This reminded me to fill some missing parts of the documentation. Possibly this is also the right moment to land the GTK-3 transition?
166 lines
10 KiB
Text
166 lines
10 KiB
Text
Startup and Shutdown of Subsystems
|
|
==================================
|
|
:Date: Dec 2008
|
|
:Author: Ichthyo
|
|
|
|
//MENU: label Subsystem start
|
|
|
|
.copied from 'pipapo.org'
|
|
NOTE: This page was moved from _Cehteh_'s MoinMoin-wiki,
|
|
which at that time was the first home of Lumiera development +
|
|
The design and techniques outlined here are in use without major
|
|
changes as of 2015 (and can be expected to remain this way). The
|
|
documentation needs rewording in a more neutral and descriptive
|
|
way and probably an introductory paragraph might be helpful [yellow-background]#TODO#
|
|
|
|
...There is now sort-of an ``application realm'', which doesn't belong strictly to
|
|
any one of the Layers. 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. Within the application, we find a small number of
|
|
_Subsystems_, which are more or less independent. These subsystems are
|
|
conceptual entities and don't correspond 1:1 to a layer, an interface, a class
|
|
or a plugin. These subsystems are _of no relevance_ outside the mentioned
|
|
"application realm". When the application is in normal operational mode, we have
|
|
the usual components, interfaces, services, aggregated into the three Layers.
|
|
|
|
__Currently I've identified the following subsystems:__
|
|
|
|
- Engine
|
|
- Builder
|
|
- Session
|
|
- Lumiera GUI
|
|
- Script runner
|
|
- Renderfarm node server
|
|
|
|
To deal with those subsystems, I've created an Interface to define the
|
|
operations and liabilities of a subsystem. Additionally, I assume that for each
|
|
subsystem there is a _Façade_, which the subsystem is free to implement 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.
|
|
|
|
TIP: The code from my `startup` branch has meanwhile been merged to master. Look
|
|
http://git.lumiera.org/gitweb?p=LUMIERA;a=tree;h=a0a0e456a5b149df81b25a08358cd488631639fb;hb=a0a0e456a5b149df81b25a08358cd488631639fb[here]
|
|
for the code referred in the following discussion.
|
|
|
|
- +common/subsys.hpp+ contains the subsystem interface mentioned above.
|
|
- +lumiera/main.cpp+ uses the subsystem instances provided by the facades, and
|
|
additionally the services of +lumiera::AppState+ (+common/appstate.hpp+)
|
|
- AppState represents the state as relevant for the "application realm", i.e.
|
|
it performs global initialisation and shutdown. See especially +AppState::init()+
|
|
- see +backend/enginefacade.hpp|cpp+ as an (unimplemented) façade skeleton. +backend::EngineFacade::getDescriptor()+
|
|
yields the subsystem interface
|
|
- the GuiFacade is somewhat special, because we want to load the GUI from a
|
|
shared library. This façade is basically completed and working, but it currently
|
|
just loads a dummy plugin. The implementation of the GuiFacade needs to be in
|
|
core (because it pulls the plugin); that's why I've put it into
|
|
+common/guifacade.cpp+, while the interface is in +gui/guifacade.hpp+ as usual.
|
|
- as an example for a _Layer separation interface_, I've implemented the
|
|
GuiNotificationFacade, which will be used by the lower layers to push
|
|
informations into the GUI (and finally to request the GUI to shut down). Layer
|
|
separation interfaces are considered part of the public Lumiera API, thus the
|
|
headers go into +src/include/**+
|
|
* include/guinotification.h (C/C++ combined header) defines an C++ interface (abstract class) and a CLI interface.
|
|
* embedded into the interface is a factory, i.e. by gui::GuiNotification::facade() you get an instance...
|
|
* which actually is a proxy and routes any call through the instance of the
|
|
accompanying CLI interface which is defined within the interface/plugin system
|
|
* this in turn forwards to the implementation class in
|
|
gui/guinotificationfacade.cpp, which is assumed to live within the GUI
|
|
(shared lib)
|
|
|
|
|
|
Parallelism
|
|
-----------
|
|
Actually this system builds on the assumption, that starting each subsystem
|
|
doesn't block the overall start/main/stop thread. I.e. any subsystem is supposed
|
|
to spawn its control/event threads if necessary. Not every subsystem needs to
|
|
spawn threads though (for example, the session doesn't). In the current
|
|
implementation _no spawning of threads happens_. Likewise, I've commented out
|
|
the synchronisation primitives. +
|
|
[yellow-background]#TODO 2015# _meanwhile we do spawn threads and perform synchronisation_
|
|
|
|
|
|
Initialisation and Lifecycle
|
|
----------------------------
|
|
Basically, everything workes as discussed last spring in the
|
|
link:{ldoc}/devel/rfc/GlobalInitialization.html[GlobalInitialisation]
|
|
design entry. I've considered to switch to simple functions +pre_init(), init(),
|
|
...+ as proposed by Cehteh, but I'm not happy with this idea, because it creates
|
|
a coupling between anything which needs to be done in a certain initialisation
|
|
function. Actually, I prefer the usual approach of lifecycle events (or signals)
|
|
used in many application frameworks, i.e. the publisher-subscriber model. This
|
|
allows to keep the registration immediately within the implementation of a
|
|
facility, and it allows to add an arbitrary number of additional lifecycle
|
|
events, like *ON_SESSION_CLOSE*, *ON_BUILD*, *ON_EMERGENCY_EXIT*.
|
|
|
|
Basically we have now the following steps and events happening
|
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
* *ON_BASIC_INIT* runs "somewhere" in the static initialisation phase before
|
|
main(). To schedule something there, you need to place a statc C++ variable.
|
|
This should be reserved for very basic initialisation tasks which need to be
|
|
done even prior to any global initialisation, e.g. the NOBUG_INIT is done this
|
|
way, the config system, maybe setting up a dispatcher table based on (compile
|
|
time) type information (for the rules engine).
|
|
* +AppState::init()+ cares for bringing up the plugin loader and opens the config-interface.
|
|
* ...followed by triggering *ON_GLOBAL_INIT*
|
|
* +main()+ pulls up the subsystems according to the command line options.
|
|
* within each subsystem, façade interfaces shall be opened with the interface
|
|
system. Any initialisation of components should be tied to these.
|
|
* as a rule and if possible, _any service should be written such as to come up on demand._
|
|
* shutdown or failure of _any given subsystem_ initiates the shutdown sequence
|
|
by requesting all other running subsystems to terminate
|
|
* there is an *ON_GLOBAL_SHUTDOWN* event, which can be used for normal cleanup.
|
|
In case of an emergency exit, this hook may be skipped
|
|
* alternatively, the *ON_EMERGENCY_EXIT* event is triggered. In case of nested
|
|
exceptions, this may happen twice.
|
|
* the AppState destructor tries to bring down the core systems (config-interface and pluginloader).
|
|
|
|
|
|
Demo Run
|
|
--------
|
|
* building with scons (default target) now yields a bin/guistart.so, besides the bin/lumiera exe the scons built created since day one.
|
|
* we need to set the LUMIERA_PLUGIN_PATH from the commandline to point to this bin directory, e.g.
|
|
* +++LUMIERA_PLUGIN_PATH=/home/hiv/devel/lumi/.libs NOBUG_LOG='test:TRACE,lumiera:TRACE,config:TRACE' bin/lumiera 2>&1 | egrep -v '(TODO)|(FIXME)'+++
|
|
------
|
|
00000392: configfacade.cpp:74: INFO: thread_1: Config: Config system ready.
|
|
00000394: main.cpp:55: NOTICE: thread_1: main: *** Lumiera NLE for Linux ***
|
|
00000395: appstate.cpp:114: TRACE: thread_1: init: initialising application core...
|
|
00000405: interface.c:54: TRACE: thread_1: lumiera_interface_open: lumieraorg_interface
|
|
00000406: interface.c:55: WARNING: thread_1: lumiera_interface_open: opening experimental interface: lumieraorg_interface_0_lumieraorg_interface
|
|
00000412: interface.c:168: TRACE: thread_1: lumiera_interface_open_interfacenode: lumieraorg_interface 0 ()
|
|
00000437: config.c:199: NOTICE: thread_1: lumiera_config_get: envvar override for config LUMIERA_PLUGIN_PATH = /home/hiv/devel/lumi/
|
|
00000444: config.c:199: NOTICE: thread_1: lumiera_config_get: envvar override for config LUMIERA_PLUGIN_PATH = /home/hiv/devel/lumi/
|
|
00000467: appstate.cpp:132: TRACE: thread_1: init: Lumiera core started successfully.
|
|
00000469: appstate.cpp:140: TRACE: thread_1: maybeStart: maybe startup Builder...?
|
|
00000472: appstate.cpp:140: TRACE: thread_1: maybeStart: maybe startup Renderfarm node...?
|
|
00000475: appstate.cpp:140: TRACE: thread_1: maybeStart: maybe startup Lumiera GTK GUI...?
|
|
00000476: subsystemrunner.hpp:144: INFO: thread_1: triggerStartup: Starting subsystem "Lumiera GTK GUI"
|
|
00000477: interface.c:54: TRACE: thread_1: lumiera_interface_open: lumieraorg_GuiStarterPlugin
|
|
00000483: interface.c:168: TRACE: thread_1: lumiera_interface_open_interfacenode: lumieraorg_GuiStarterPlugin 0 ()
|
|
*** Ha Ha Ha
|
|
this is the GuiStarterPlugin speaking!
|
|
now, the Lumiera GUI should be spawned....
|
|
but actually nothing happens!!!!!!!!!!!!!!
|
|
00000491: appstate.cpp:140: TRACE: thread_1: maybeStart: maybe startup Script runner...?
|
|
00000494: appstate.cpp:171: NOTICE: thread_1: maybeWait: Shutting down Lumiera...
|
|
00000495: interface.c:230: TRACE: thread_1: lumiera_interface_close:
|
|
00000498: interface.c:258: TRACE: thread_1: lumiera_interfacenode_close: lumieraorg_GuiStarterPlugin 1 ()
|
|
00000634: configfacade.cpp:83: TRACE: thread_1: ~Config: config system closed.
|
|
00000635: appstate.cpp:245: TRACE: thread_1: ~AppState: shutting down basic application layer...
|
|
00000643: interface.c:230: TRACE: thread_1: lumiera_interface_close:
|
|
00000646: interface.c:258: TRACE: thread_1: lumiera_interfacenode_close: lumieraorg_interface 1 ()
|
|
------
|
|
* incidentally, running... `lumiera --help` produces the following output
|
|
------
|
|
00000392: configfacade.cpp:74: INFO: thread_1: Config: Config system ready.
|
|
00000394: main.cpp:55: NOTICE: thread_1: main: *** Lumiera NLE for Linux ***
|
|
Lumiera, the non linear video editor. Supported parameters:
|
|
-h [ --help ] produce help message
|
|
-f [ --session ] arg session file to load (UNIMPLEMENTED)
|
|
-s [ --script ] arg execute the given LUA script (UNIMPLEMENTED)
|
|
--headless start without GUI
|
|
-p [ --port ] arg open renderfarm node at given port (UNIMPLEMENTED)
|
|
-d [ --define ] arg enter definition into config system (UNIMPLEMENTED)
|
|
------
|
|
|