more eol-style

git-svn-id: svn://svn.icculus.org/gtkradiant/GtkRadiant/branches/ZeroRadiant.ab@187 8a3a26a2-13c4-0310-b231-cf6edde360e5
This commit is contained in:
TTimo
2007-11-04 03:57:33 +00:00
parent b1bfb19ecd
commit 2b5ef55c7c
53 changed files with 3141 additions and 3141 deletions

View File

@@ -1,190 +1,190 @@
synapse code design documentation
=================================
Objective:
----------
Provide a simple cross platform layer to use dynamically loaded code
inside a core application. Portability intended to win32 / linux / MacOS (?)
Main features are:
- designed for single process only, no remote clients, no asynchronous processes
- a client/server architecture, based on configuration files: a main binary,
loading a set of shared objects
Constraints:
------------
- large existing plugin code in Radiant!
must be compatible with minimal changes, specially for plugins (i.e. clients)
- make things as much transparent as possible
(ideally, no real difference between a static linkage and dynamic linkage,
cf usage of #define macros to wrap a function call onto a code pointer)
Features:
---------
Gather as much generic code as possible in a static .lib with minimal dependencies
(only dependency should be configuration files parser)
NOTE: current effective dependency is STL / glib / xml
Main executable implemented as a server, all others as clients. What has to
be done for a server / what has to be done for a client needs to be documented.
Provide as much scripts and tools and guidelines as needed (scripted generation of
some .h files?)
Proposed implementation:
------------------------
- have linux/ and win32/ subdirectories with OS-specific implementations
(such as dynamically loading shared objects, and doing the initial query?)
- reduce the API of a client to the minimum: one exported function?
provide a squeleton to make new clients easily?
Server use case:
1) build information about location of the modules (from code and config files)
2) load all modules and query information about their APIs
NOTE: could read the APIs from some XML description files instead of
querying it from the modules?
3) build information about the required function tables
i.e.: setup a list with the function tables to be filled in, and what they
need to be filled in with.
4) resolve the function table
NOTE: is this iterative? will some plugins request more APIs as they get filled
up?
NOTE: do we have optional tables?
5) unload unreferences modules
NOTE: we don't expect to be unloading a LOT of modules, otherwise we would
setup a solution that allows exploring of the APIs a given module provides
from a file description. Or you could 'cache' that (md5-checksum the file, and
maintain an XML list).
Client use case:
1) dynamically loaded
2) prompted for the interfaces it provides
2) prompted for the interfaces it requires
3) either unloaded, or told what interfaces have been filled in
The client module exports an Synapse_EnumerateInterfaces entry point
This returns an ISynapseClient, which lists what the plugin provides, and what it requires
The APIs:
An interface is a function table, GUID / major string / minor string
GUID is a shortcut to reference a major string (i.e. the human readable thing)
the GUID / major string is unique for a given interface
minor string is used to reference a particular version of an API
(for instance when talking about image loading functionality, tga and jpg etc.)
The GUID scheme is handy because it provides easy tests. They are not strictly
necessary but we will probably want to keep them. Should we extend to GUIDs
for minor too?
Roadmap:
--------
Need to convert the core (as server) and the required modules. Will have
clearer view of what's to be done along the way.
Implementation design:
----------------------
There is a client and server side to synapse. Typically server is in Radiant or q3map,
client is in any module. For implementation, we have one server class and one client class.
It would be possible to have two seperate libraries, synapse-client and synapse-server. But
that only brings down the statically linked stuff to make things more complicated build-sysem
wise.
Initial implementation has been using isynapse.h and synapse.h, to provide a pure virtual
base class for server and client. But that doesn't bring any major functionality, it's easier
if both sides see the full API of the client and server classes.
A side problem is the diagnostic printing functionality. For easy debugging we require that
the synapse code can have access to a Sys_Printf or similar function at all times (that is for
client and server implementation). On client we will pipe through the main API to the server
as soon as we can in most cases. Using Sys_Printf would bring us to a dead end situation, since
when synapse is used as the server, the main code implements it's own Sys_Printf stuff.
Instead we introduce a local Syn_Printf implementation, which can be overriden in the server
to point to the appropriate print functions.
Runtime config:
---------------
Something that has not been looked upon a lot yet, runtime configuration. What interfaces
are loaded etc. Ideally, from an XML config file. A client explicitely requests the
server to load all the interfaces it requires (in this case, the client is radiant or
q3map).
Plugins are somewhat out of the 'required interfaces' frame, since they are loaded
whenever they are found. It is possible however that some plugins would not want to be
loaded in if the game doesn't match etc. in case they would need to access the global
config?
In most cases a given API is only required once for editor functionality. (VFS for
instance), so our #define strategy for easy mapping of the functions should still work.
Version checks, reference counting:
------------------------------------
Need version checking at several levels. A version string (major/minor) on the main API
entry point (straight in the exported function to save as much as possible for
compatibility). For individual APIs, we have been feeding the struct size into the first
int of the struct so far, and it has worked very well.
Reference counting: we introduced class based APIs to solve the ref counting issues,
which are not easy to solve on C function tables. That problem would arise in plugin
situations where we might want to 'reload' or 'unload' some plugins. The server could
keep track of the ref count.
Caching?
--------
We are going to load every shared object we find and query it for it's interfaces. Then
we will unload the stuff we don't want. This is going to slow down the startup process.
We could extract the API information in a cache to avoid the loading step.
Interfaces with multiple minors against I* objects?
---------------------------------------------------
Looking at the iimage.h API, why not having instead something that enumerates C++ objects
directly? Mainly because we want to be able to spread several minors accross multiple modules
and still use them together. And straight laid out function tables in C structs are only
one indirection when the table is static.
This raises a broader topic, instead of requesting APIs, we could request objects directly.
Would that be of any use?
Loading interfaces / resolving interdependencies strategy
---------------------------------------------------------
Some notes about how we load the modules and resolve interdependencies:
We want to avoid requesting a module for an API it provides before all the APIs it requires
have been filled in (mostly stability concerns, a module may be doing whatever internally
when we request something from it). The exception being the module we are trying to resolve
for (since we need a start point for resolution). But in all likelyness we resolve for radiant
or q3map for instance.
With this approach, it is possible that some situations could not be resolved, for instance:
Radiant
requires A
provides B
module 1
requires C
provides A
module 2
requires A
provides C
if we start by resolving Radiant, we will get stuck
if we are ready to ask module to provide the API even though the required is not meant, it would work
but that kind of situation is very unlikely, so sticking to safer strategy
Configuration
-------------
the config info needs to go down to the clients too
synapse code design documentation
=================================
Objective:
----------
Provide a simple cross platform layer to use dynamically loaded code
inside a core application. Portability intended to win32 / linux / MacOS (?)
Main features are:
- designed for single process only, no remote clients, no asynchronous processes
- a client/server architecture, based on configuration files: a main binary,
loading a set of shared objects
Constraints:
------------
- large existing plugin code in Radiant!
must be compatible with minimal changes, specially for plugins (i.e. clients)
- make things as much transparent as possible
(ideally, no real difference between a static linkage and dynamic linkage,
cf usage of #define macros to wrap a function call onto a code pointer)
Features:
---------
Gather as much generic code as possible in a static .lib with minimal dependencies
(only dependency should be configuration files parser)
NOTE: current effective dependency is STL / glib / xml
Main executable implemented as a server, all others as clients. What has to
be done for a server / what has to be done for a client needs to be documented.
Provide as much scripts and tools and guidelines as needed (scripted generation of
some .h files?)
Proposed implementation:
------------------------
- have linux/ and win32/ subdirectories with OS-specific implementations
(such as dynamically loading shared objects, and doing the initial query?)
- reduce the API of a client to the minimum: one exported function?
provide a squeleton to make new clients easily?
Server use case:
1) build information about location of the modules (from code and config files)
2) load all modules and query information about their APIs
NOTE: could read the APIs from some XML description files instead of
querying it from the modules?
3) build information about the required function tables
i.e.: setup a list with the function tables to be filled in, and what they
need to be filled in with.
4) resolve the function table
NOTE: is this iterative? will some plugins request more APIs as they get filled
up?
NOTE: do we have optional tables?
5) unload unreferences modules
NOTE: we don't expect to be unloading a LOT of modules, otherwise we would
setup a solution that allows exploring of the APIs a given module provides
from a file description. Or you could 'cache' that (md5-checksum the file, and
maintain an XML list).
Client use case:
1) dynamically loaded
2) prompted for the interfaces it provides
2) prompted for the interfaces it requires
3) either unloaded, or told what interfaces have been filled in
The client module exports an Synapse_EnumerateInterfaces entry point
This returns an ISynapseClient, which lists what the plugin provides, and what it requires
The APIs:
An interface is a function table, GUID / major string / minor string
GUID is a shortcut to reference a major string (i.e. the human readable thing)
the GUID / major string is unique for a given interface
minor string is used to reference a particular version of an API
(for instance when talking about image loading functionality, tga and jpg etc.)
The GUID scheme is handy because it provides easy tests. They are not strictly
necessary but we will probably want to keep them. Should we extend to GUIDs
for minor too?
Roadmap:
--------
Need to convert the core (as server) and the required modules. Will have
clearer view of what's to be done along the way.
Implementation design:
----------------------
There is a client and server side to synapse. Typically server is in Radiant or q3map,
client is in any module. For implementation, we have one server class and one client class.
It would be possible to have two seperate libraries, synapse-client and synapse-server. But
that only brings down the statically linked stuff to make things more complicated build-sysem
wise.
Initial implementation has been using isynapse.h and synapse.h, to provide a pure virtual
base class for server and client. But that doesn't bring any major functionality, it's easier
if both sides see the full API of the client and server classes.
A side problem is the diagnostic printing functionality. For easy debugging we require that
the synapse code can have access to a Sys_Printf or similar function at all times (that is for
client and server implementation). On client we will pipe through the main API to the server
as soon as we can in most cases. Using Sys_Printf would bring us to a dead end situation, since
when synapse is used as the server, the main code implements it's own Sys_Printf stuff.
Instead we introduce a local Syn_Printf implementation, which can be overriden in the server
to point to the appropriate print functions.
Runtime config:
---------------
Something that has not been looked upon a lot yet, runtime configuration. What interfaces
are loaded etc. Ideally, from an XML config file. A client explicitely requests the
server to load all the interfaces it requires (in this case, the client is radiant or
q3map).
Plugins are somewhat out of the 'required interfaces' frame, since they are loaded
whenever they are found. It is possible however that some plugins would not want to be
loaded in if the game doesn't match etc. in case they would need to access the global
config?
In most cases a given API is only required once for editor functionality. (VFS for
instance), so our #define strategy for easy mapping of the functions should still work.
Version checks, reference counting:
------------------------------------
Need version checking at several levels. A version string (major/minor) on the main API
entry point (straight in the exported function to save as much as possible for
compatibility). For individual APIs, we have been feeding the struct size into the first
int of the struct so far, and it has worked very well.
Reference counting: we introduced class based APIs to solve the ref counting issues,
which are not easy to solve on C function tables. That problem would arise in plugin
situations where we might want to 'reload' or 'unload' some plugins. The server could
keep track of the ref count.
Caching?
--------
We are going to load every shared object we find and query it for it's interfaces. Then
we will unload the stuff we don't want. This is going to slow down the startup process.
We could extract the API information in a cache to avoid the loading step.
Interfaces with multiple minors against I* objects?
---------------------------------------------------
Looking at the iimage.h API, why not having instead something that enumerates C++ objects
directly? Mainly because we want to be able to spread several minors accross multiple modules
and still use them together. And straight laid out function tables in C structs are only
one indirection when the table is static.
This raises a broader topic, instead of requesting APIs, we could request objects directly.
Would that be of any use?
Loading interfaces / resolving interdependencies strategy
---------------------------------------------------------
Some notes about how we load the modules and resolve interdependencies:
We want to avoid requesting a module for an API it provides before all the APIs it requires
have been filled in (mostly stability concerns, a module may be doing whatever internally
when we request something from it). The exception being the module we are trying to resolve
for (since we need a start point for resolution). But in all likelyness we resolve for radiant
or q3map for instance.
With this approach, it is possible that some situations could not be resolved, for instance:
Radiant
requires A
provides B
module 1
requires C
provides A
module 2
requires A
provides C
if we start by resolving Radiant, we will get stuck
if we are ready to ask module to provide the API even though the required is not meant, it would work
but that kind of situation is very unlikely, so sticking to safer strategy
Configuration
-------------
the config info needs to go down to the clients too
for instance, mapxml loaded for q3map or radiant, doesn't rely on the same major?

View File

@@ -1,59 +1,59 @@
XML config files for customized synapse initialization at runtime
-----------------------------------------------------------------
Objective:
----------
We have to assign the minors of the APIs to function tables
(and possibly to the API managers) at runtime from some config files.
For instance in Q3 or RTCW mode, we will want to fill in
g_FileSystemTable and g_ShadersTable with the "quake3" minor. Whereas
those tables will be filled in with a different minor for HL mode.
This affects SYN_REQUIRE for all the clients of the system, so that
config will need to be global and passed around to the clients.
Implementation:
---------------
an XML hierarchy to describe the APIs:
<client name="CORE">
<api name="vfs">
quake3
</api>
<api name="shaders">
quake3
</api>
..
</client>
<client name="SHADERS">
</client>
Each client will have to be identified by a specific name, if a name in the
config is not found in the client list, the init should fail. A client can
still be hardcoded and not appear in this list though.
(a GetName() function to synapse client)
SYN_REQUIRE_ANY support will work for strict API lists. Just the same way
we do the simple SYN_REQUIRE
Discussion:
-----------
We only deal with SYN_REQUIRE. It is possible that at some point we will want
to customize the SYN_PROVIDE too. For instance depending on the game mode, a
same module could provide two different minors. Couldn't provide the two minors
at the same time though, only one.
Implementation:
---------------
Default config file will be synapse.config in the gametools path. We can override
this later with a custom line in the .game file. Should Synapse be able to operate
without this config file though, as it is looked up by the main program and handed
over to synapse before init? Possibly .. we'll just pass a NULL config node ptr
Add the config file path to CSynpaseServer::Initialize, pass the loaded XML file to
XML config files for customized synapse initialization at runtime
-----------------------------------------------------------------
Objective:
----------
We have to assign the minors of the APIs to function tables
(and possibly to the API managers) at runtime from some config files.
For instance in Q3 or RTCW mode, we will want to fill in
g_FileSystemTable and g_ShadersTable with the "quake3" minor. Whereas
those tables will be filled in with a different minor for HL mode.
This affects SYN_REQUIRE for all the clients of the system, so that
config will need to be global and passed around to the clients.
Implementation:
---------------
an XML hierarchy to describe the APIs:
<client name="CORE">
<api name="vfs">
quake3
</api>
<api name="shaders">
quake3
</api>
..
</client>
<client name="SHADERS">
</client>
Each client will have to be identified by a specific name, if a name in the
config is not found in the client list, the init should fail. A client can
still be hardcoded and not appear in this list though.
(a GetName() function to synapse client)
SYN_REQUIRE_ANY support will work for strict API lists. Just the same way
we do the simple SYN_REQUIRE
Discussion:
-----------
We only deal with SYN_REQUIRE. It is possible that at some point we will want
to customize the SYN_PROVIDE too. For instance depending on the game mode, a
same module could provide two different minors. Couldn't provide the two minors
at the same time though, only one.
Implementation:
---------------
Default config file will be synapse.config in the gametools path. We can override
this later with a custom line in the .game file. Should Synapse be able to operate
without this config file though, as it is looked up by the main program and handed
over to synapse before init? Possibly .. we'll just pass a NULL config node ptr
Add the config file path to CSynpaseServer::Initialize, pass the loaded XML file to
the clients. Do we need to wrap in an object with some convenience functions?

View File

@@ -1,85 +1,85 @@
Release / Reload of modules
---------------------------
The 'not active' modules are unloaded after startup
Plugins should be allowed to be unloaded and reloaded on the fly
Modules too, when possible?
Don't want to 'force' all plugins to have unload capabilities
Just has to be something specified at compile time wether or not they can unload 'cleanly'
Dependency implications. When you release a module, you need to remove a number of interfaces.
If those interfaces are being used, can you explicitely ask for them to be unloaded?
Also, problem with plugins breaking the startup process:
http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=441
The most important is to provide a clean shutdown method
What's the != between unload and shutdown?
Means that the server proceeds to the shutdown, and nothing else is supposed to be making
calls through APIs post shutdown.
Should be done in 3 steps:
#1 prepare shutdown, all APIs are active, just release and save all the stuff you want
#2 tell the modules to shutdown, i.e. release the APIs they point to? (at this point they can't call through anymore)
#3 force all things to be unloaded, warn about reference count problems
What is different when we unload a module, and we want to keep the editor up?
All the interfaces obtained from this plugin need to be released
If some pure virtual classes have been obtained from this plugin, we need a mecanism to have them removed
Do we need a first path to check if the unload procedure is going to be allowed?
For instance, a plugin that provides custom entities rendering etc.
Need to unload first, then need to reload (scan the map again, rebuild)
Summing up, when doing a reload we need to keep track of the modules and let them know after the
module has been reloaded, so that the links can be rebuilt. When doing unload we need to do a
'check' pass prior to anything to know if the release is possible. Because it does not depend
on the module we unload, it depends on the other clients that use it.
Objectives:
-----------
- 'release check' of a module
walk through the interfaces this module has provided, and make sure the release will be possible
- 'release' of a module
actually drop all the interfaces. this should be done only after a 'release check'
if something fails here, we are in an unstable state and need to abort
- 'client shutdown' unused modules after initial startup
actual DLL unload / complete shutdown of the client interface
this comes after 'release check' and 'release'
- 'refresh' modules
'release check', 'release', 'shutdown' and then, reload and build the links again
- 'core shutdown'
'release' and force 'shutdown' of all clients
even if we encounter some interfaces that we are not able to release cleanly
force things and shutdown all clients
then the core process is ready to exit..
Constraints:
------------
- refresh and shutdown are sharing some code
- the 'release' part of a module refresh may not be always possible (that's what 'release check' is there for)
- 'core shutdown' has to be forced to happen, in the safest way possible obviously
Implementation:
---------------
- 'client shutdown' comes first
this is used after initial startup, since we don't have to do a prior 'release' on those
this will be used in the 'core shutdown' and 'refresh' too
- then 'core shutdown' procedure?
that's the most urgent thing we need
but 'release check' and 'release' have to be written in and used during 'core shutdown'
- 'refresh' takes an essential part of the design, but that's not something we need to have written right now?
(it mostly relies on 'release check' 'release' 'client shutdown', and then reload and rebuild the links)
'client shutdown':
this is server side code though, you tell the server 'shutdown this client'
we don't have to exchange anything with the client while we do that
(written initially for unload of unused modules after startup)
'core shutdown':
is a shutdown of all clients
Release / Reload of modules
---------------------------
The 'not active' modules are unloaded after startup
Plugins should be allowed to be unloaded and reloaded on the fly
Modules too, when possible?
Don't want to 'force' all plugins to have unload capabilities
Just has to be something specified at compile time wether or not they can unload 'cleanly'
Dependency implications. When you release a module, you need to remove a number of interfaces.
If those interfaces are being used, can you explicitely ask for them to be unloaded?
Also, problem with plugins breaking the startup process:
http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=441
The most important is to provide a clean shutdown method
What's the != between unload and shutdown?
Means that the server proceeds to the shutdown, and nothing else is supposed to be making
calls through APIs post shutdown.
Should be done in 3 steps:
#1 prepare shutdown, all APIs are active, just release and save all the stuff you want
#2 tell the modules to shutdown, i.e. release the APIs they point to? (at this point they can't call through anymore)
#3 force all things to be unloaded, warn about reference count problems
What is different when we unload a module, and we want to keep the editor up?
All the interfaces obtained from this plugin need to be released
If some pure virtual classes have been obtained from this plugin, we need a mecanism to have them removed
Do we need a first path to check if the unload procedure is going to be allowed?
For instance, a plugin that provides custom entities rendering etc.
Need to unload first, then need to reload (scan the map again, rebuild)
Summing up, when doing a reload we need to keep track of the modules and let them know after the
module has been reloaded, so that the links can be rebuilt. When doing unload we need to do a
'check' pass prior to anything to know if the release is possible. Because it does not depend
on the module we unload, it depends on the other clients that use it.
Objectives:
-----------
- 'release check' of a module
walk through the interfaces this module has provided, and make sure the release will be possible
- 'release' of a module
actually drop all the interfaces. this should be done only after a 'release check'
if something fails here, we are in an unstable state and need to abort
- 'client shutdown' unused modules after initial startup
actual DLL unload / complete shutdown of the client interface
this comes after 'release check' and 'release'
- 'refresh' modules
'release check', 'release', 'shutdown' and then, reload and build the links again
- 'core shutdown'
'release' and force 'shutdown' of all clients
even if we encounter some interfaces that we are not able to release cleanly
force things and shutdown all clients
then the core process is ready to exit..
Constraints:
------------
- refresh and shutdown are sharing some code
- the 'release' part of a module refresh may not be always possible (that's what 'release check' is there for)
- 'core shutdown' has to be forced to happen, in the safest way possible obviously
Implementation:
---------------
- 'client shutdown' comes first
this is used after initial startup, since we don't have to do a prior 'release' on those
this will be used in the 'core shutdown' and 'refresh' too
- then 'core shutdown' procedure?
that's the most urgent thing we need
but 'release check' and 'release' have to be written in and used during 'core shutdown'
- 'refresh' takes an essential part of the design, but that's not something we need to have written right now?
(it mostly relies on 'release check' 'release' 'client shutdown', and then reload and rebuild the links)
'client shutdown':
this is server side code though, you tell the server 'shutdown this client'
we don't have to exchange anything with the client while we do that
(written initially for unload of unused modules after startup)
'core shutdown':
is a shutdown of all clients