RemoteServer and PluginManager side would need complete redesign to be
data race free and concurrent. But as that would be unlikely to be
required from DFHack I decided simpler solution that is fixing data
ownership to a thread and all ServerConnection share a single lock which
allows access to PluginManager and Core.
The initial run_dfhack_init loads shared state information that is used
by EventManager when state changes. There is a small risk that
EventManager can handle events while run_dfhack_init is still running.
Alter World to use Persistence instead of storing data in historical figures.
Fake historical figures will be converted to the new format when a world is loaded.
Added plugin_save and plugin_load functions to the plugin API.
Made the weird int7/int28 code that was in the old persistence API slightly safer.
Also modified Core/Console a bit to get this to actually produce output on
Travis (DFHACK_DISABLE_CONSOLE now allows console output, just not input)
Squashed merge from lethosor/tests
_exit seems to run dll unloading code which calls static destructors.
Standrd requires std::_Exit not to call destructors which makes using it
attractive in case MSVC actually follows the standard.
The old CoreSuspender requires processing from Core::Update to allow
commands execute. But that causes issues if Core::Shutdown wants
quarentee cleanup order with std:🧵:join. Fixing shutdown ordering
adds too many branches to already fairly complex code.
I decided to try to refactor CoreSuspender to use simpler locking
locking using a std::recusive_muted as primary synchronization
primitive.
To help control when Core::Update unlocks the primary mutex there is
std::contition_variable_any and std::atomic<size_t> queue lenght
counter.
The last state variable is std::atomic<std:🧵:id> that is used to
keep track of owner thread for Core::IsSuspended query.
This should be merged only just after a release to make sure that it
gets maximum testing in develop branch before next release.
Fixes#1066
There is a minor chance that console or init thread would access already
freed memory when core is shutting down and cleaning up state. To avoid
any danger of having random bugs caused by the potential data race I
decided to make sure the shutdown code waits for the thread to exit
first.
Windows change is completely untested. It is purely based on msdn
documentation.
I noticed that tthread is missing some c++11 features that make thread
handling code a bit easier. To be able to use those features I decided
to convert Core.cpp to use equivalent standard classes.
This patch has no functional changes.
This may help address issues where people forget to read the documentation,
don't run "git submodule update", and end up with a df-structures version
that's too old (which is somewhat common, it turns out).
This was previously done right before SC_VIEWSCREEN_CHANGED events
were handled, meaning that code handling earlier events that used
top_viewscreen (rather than getCurViewscreen()) could refer to an
invalid viewscreen, i.e. in the tick after it was deleted.
Fixes#747
* Several fatal errors that occurred during core initialization didn't
stop initialization or set 'errorstate' properly, which caused
update hooks and other code to crash later. This has been fixed and
should address crashes like the one mentioned in #470.
* Errors when loading dfhack.lua now cause Lua::Open() to fail, which
triggers a fatal error in Core::Init()
* Failure to initialize the console no longer results in a call to
fatal() (since it didn't actually stop initialization previously)
cur_savegame.save_dir can be populated when the save directory does
not yet exist after world generation (since the game can be aborted
at that stage without saving).
* GCC does not allow std::string instances or enums without a base
type to be passed as varargs
* Fixed path concatenation issue causing dfhack.init to not be loaded
* load/unload/reload are no longer restricted to plugins that exist
on startup
* Names passed to DFHACK_PLUGIN must match the plugin's filename
(remotefortressreader vs RemoteFortressReader, counters vs probe)
* "plug" output lists all plugins and state/command information
* Deleted plugins can be reloaded again if they are replaced
* load/unload/reload don't fail silently with broken plugins
* Built-in commands are recognized internally (e.g. "help help"
does not display "help is not a recognized command"), although help
for them is not yet implemented
* New command: "type" (bash-like) - shows where/how a command is
implemented
* "plug" can accept multiple plugin names
* "ls" displays more information about unloaded/unrecognized plugins
* "load all" changed to "load -all" (or "load --all", "load -a", ...)
git is run every time 'make' is run, but the generated include file
is only updated when necessary. Plugins will be loaded successfully
if their DFHack version matches core's (assuming OpenLibrary()
succeeds), but will produce a warning if their git commit doesn't
match core's.
Files from the "dfhack-config" source directory are now installed to
"dfhack-config/default" and copied to "dfhack-config" on startup if
they don't already exist. Previously, config files weren't available
at all unless they were manually installed (93c9a41).
SDL has been reporting the modifier key state incorrectly after alt-tabbing between the DF and DFHack windows.
Fixes issue #448, though more testing is warranted.
Saving a game in progress now goes through an extra viewscreen before reaching the condition that had been used to indicate whether the world was still valid, causing the core to emit bogus WORLD_LOADED, MAP_LOADED, MAP_UNLOADED, and WORLD_UNLOADED events. Adding that viewscreen to the list of loading/saving screens prevents those duplicate events from firing.
Granted, if the game_cleaner viewscreen ever gets hit in play, this fix will cause more bogus events...
During the loading or saving screen, consider the map and world as not
loaded, because they are likely only partially valid. This fixes errors
from the log-region script.
This class can cache the set of memory regions during its lifetime,
and make them writable only once. This avoids e.g. re-reading
/proc/*/maps once for every modified vtable in interpose code.