Improve kittens thread safety and shutdown with core

The bools could use acquire&release memory order or even relaxed but I
didn't think code was worth auditing for such low level optimizations.
Sequantial consistent is fast enough but much harder to use incorrectly.

The timeLast is protected by CoreSuspender lock. plugin_update is only
called when CoreSuspender lock is held.

The last_menu is protected by trackmenu_flg loads and stores.
develop
Pauli 2018-06-30 21:10:51 +03:00
parent 0727403ac1
commit 645ec0d591
2 changed files with 22 additions and 24 deletions

@ -26,6 +26,7 @@ distribution.
#include "Pragma.h" #include "Pragma.h"
#include "Export.h" #include "Export.h"
#include "ColorText.h" #include "ColorText.h"
#include <atomic>
#include <deque> #include <deque>
#include <fstream> #include <fstream>
#include <assert.h> #include <assert.h>
@ -163,6 +164,6 @@ namespace DFHack
private: private:
Private * d; Private * d;
tthread::recursive_mutex * wlock; tthread::recursive_mutex * wlock;
bool inited; std::atomic<bool> inited;
}; };
} }

@ -1,3 +1,4 @@
#include <atomic>
#include <vector> #include <vector>
#include <string> #include <string>
@ -24,13 +25,12 @@ DFHACK_PLUGIN_IS_ENABLED(is_enabled);
REQUIRE_GLOBAL(ui); REQUIRE_GLOBAL(ui);
REQUIRE_GLOBAL(world); REQUIRE_GLOBAL(world);
//FIXME: possible race conditions with calling kittens from the IO thread and shutdown from Core. std::atomic<bool> shutdown_flag{false};
volatile bool shutdown_flag = false; std::atomic<bool> final_flag{true};
volatile bool final_flag = true; std::atomic<bool> timering{false};
bool timering = false; std::atomic<bool> trackmenu_flg{false};
bool trackmenu_flg = false; std::atomic<uint8_t> trackpos_flg{0};
bool trackpos_flg = false; std::atomic<uint8_t> statetrack{0};
bool statetrack = false;
int32_t last_designation[3] = {-30000, -30000, -30000}; int32_t last_designation[3] = {-30000, -30000, -30000};
int32_t last_mouse[2] = {-1, -1}; int32_t last_mouse[2] = {-1, -1};
df::ui_sidebar_mode last_menu = df::ui_sidebar_mode::Default; df::ui_sidebar_mode last_menu = df::ui_sidebar_mode::Default;
@ -93,12 +93,10 @@ DFhackCExport command_result plugin_onstatechange(color_ostream &out, state_chan
DFhackCExport command_result plugin_onupdate ( color_ostream &out ) DFhackCExport command_result plugin_onupdate ( color_ostream &out )
{ {
if(timering == true) if(timering)
{ {
uint64_t time2 = GetTimeMs64(); uint64_t time2 = GetTimeMs64();
// harmless potential data race here...
uint64_t delta = time2-timeLast; uint64_t delta = time2-timeLast;
// harmless potential data race here...
timeLast = time2; timeLast = time2;
out.print("Time delta = %d ms\n", int(delta)); out.print("Time delta = %d ms\n", int(delta));
} }
@ -135,30 +133,30 @@ DFhackCExport command_result plugin_onupdate ( color_ostream &out )
command_result trackmenu (color_ostream &out, vector <string> & parameters) command_result trackmenu (color_ostream &out, vector <string> & parameters)
{ {
if(trackmenu_flg) bool is_running = trackmenu_flg.exchange(false);
if(is_running)
{ {
trackmenu_flg = false;
return CR_OK; return CR_OK;
} }
else else
{ {
trackmenu_flg = true;
is_enabled = true; is_enabled = true;
last_menu = ui->main.mode; last_menu = ui->main.mode;
out.print("Menu: %d\n",last_menu); out.print("Menu: %d\n",last_menu);
trackmenu_flg = true;
return CR_OK; return CR_OK;
} }
} }
command_result trackpos (color_ostream &out, vector <string> & parameters) command_result trackpos (color_ostream &out, vector <string> & parameters)
{ {
trackpos_flg = !trackpos_flg; trackpos_flg.fetch_xor(1);
is_enabled = true; is_enabled = true;
return CR_OK; return CR_OK;
} }
command_result trackstate ( color_ostream& out, vector< string >& parameters ) command_result trackstate ( color_ostream& out, vector< string >& parameters )
{ {
statetrack = !statetrack; statetrack.fetch_xor(1);
return CR_OK; return CR_OK;
} }
@ -180,20 +178,19 @@ command_result colormods (color_ostream &out, vector <string> & parameters)
command_result ktimer (color_ostream &out, vector <string> & parameters) command_result ktimer (color_ostream &out, vector <string> & parameters)
{ {
if(timering) bool is_running = timering.exchange(false);
if(is_running)
{ {
timering = false;
return CR_OK; return CR_OK;
} }
uint64_t timestart = GetTimeMs64(); uint64_t timestart = GetTimeMs64();
{ {
CoreSuspender suspend; CoreSuspender suspend;
uint64_t timeend = GetTimeMs64();
timeLast = timeend;
timering = true;
out.print("Time to suspend = %d ms\n", int(timeend - timestart));
} }
uint64_t timeend = GetTimeMs64();
out.print("Time to suspend = %d ms\n", int(timeend - timestart));
// harmless potential data race here...
timeLast = timeend;
timering = true;
is_enabled = true; is_enabled = true;
return CR_OK; return CR_OK;
} }
@ -255,7 +252,7 @@ command_result kittens (color_ostream &out, vector <string> & parameters)
Console::color_value color = COLOR_BLUE; Console::color_value color = COLOR_BLUE;
while(1) while(1)
{ {
if(shutdown_flag) if(shutdown_flag || !con.isInited())
{ {
final_flag = true; final_flag = true;
con.reset_color(); con.reset_color();