Implement a new class, save_blocker,

...analogous to input_blocker and update_locker, which effectively
masks requests to save the game and processes them after the
save_blocker has been destructed.  Wrap one around
playsingle_controller::init_side(), fixing bug #9496.  See also bug
#13298.
This commit is contained in:
Daniel Franke 2009-04-06 08:53:08 +00:00
parent 14d928b2cd
commit 3e874fdb86
4 changed files with 94 additions and 11 deletions

View file

@ -27,7 +27,7 @@
#include "sound.hpp"
#include "unit_id.hpp"
#include "terrain_filter.hpp"
#include "savegame.hpp"
#define LOG_NG LOG_STREAM(info, engine)
@ -286,15 +286,30 @@ void play_controller::status_table(){
}
void play_controller::save_game(){
menu_handler_.save_game("",gui::OK_CANCEL);
if(save_blocker::try_block()) {
save_blocker::save_unblocker unblocker;
menu_handler_.save_game("",gui::OK_CANCEL);
} else {
save_blocker::on_unblock(this,&play_controller::save_game);
}
}
void play_controller::save_replay(){
menu_handler_.save_replay("", gui::OK_CANCEL, false);
if(save_blocker::try_block()) {
save_blocker::save_unblocker unblocker;
menu_handler_.save_game("", gui::OK_CANCEL, false);
} else {
save_blocker::on_unblock(this,&play_controller::save_replay);
}
}
void play_controller::save_map(){
menu_handler_.save_map();
if(save_blocker::try_block()) {
save_blocker::save_unblocker unblocker;
menu_handler_.save_map();
} else {
save_blocker::on_unblock(this,&play_controller::save_map);
}
}
void play_controller::load_game(){

View file

@ -33,6 +33,7 @@
#include "upload_log.hpp"
#include "formula_string_utils.hpp"
#include "events.hpp"
#include "savegame.hpp"
#define ERR_NG LOG_STREAM(err, engine)
#define LOG_NG LOG_STREAM(info, engine)
@ -529,13 +530,7 @@ void playsingle_controller::play_turn(bool save)
skip_next_turn_ = false;
throw end_turn_exception();
}
/*
* Commented this out at dfranke's request,
* effectively reverting his commit 34278,
* because it introduced blocker bug #13298:
* reproducible hang in dialog code
*/
//input_blocker blocker;
save_blocker blocker;
init_side(player_number_ - 1);
} catch (end_turn_exception) {
if (current_team().is_network() == false) {

View file

@ -22,6 +22,51 @@
#define LOG_SAVE LOG_STREAM(info, engine)
play_controller* save_blocker::controller_ = NULL;
void (play_controller::*save_blocker::callback_)() = NULL;
SDL_sem* save_blocker::sem_ = SDL_CreateSemaphore(1);
save_blocker::save_blocker() {
block();
}
save_blocker::~save_blocker() {
unblock();
if(controller_ && callback_) {
(controller_->*callback_)();
controller_ = NULL;
callback_ = NULL;
}
}
void save_blocker::on_unblock(play_controller* controller, void (play_controller::*callback)()) {
if(try_block()) {
unblock();
(controller->*callback)();
} else {
controller_ = controller;
callback_ = callback;
}
}
bool save_blocker::saves_are_blocked() {
return SDL_SemValue(sem_) == 0;
}
void save_blocker::block() {
SDL_SemWait(sem_);
}
bool save_blocker::try_block() {
return SDL_SemTryWait(sem_) == 0;
}
void save_blocker::unblock() {
assert(SDL_SemValue(sem_) == 0);
SDL_SemPost(sem_);
}
// Prototypes
// Interactive replay save

View file

@ -18,9 +18,37 @@
#include "global.hpp"
#include "gamestatus.hpp"
#include "play_controller.hpp"
#include <string>
#include "SDL_mutex.h"
class save_blocker {
public:
save_blocker();
~save_blocker();
static bool saves_are_blocked();
static void on_unblock(play_controller* controller, void (play_controller::*callback)());
protected:
friend class play_controller;
static void block();
static bool try_block();
static void unblock();
class save_unblocker {
public:
save_unblocker() {}
~save_unblocker() { save_blocker::unblock(); }
};
private:
static play_controller *controller_;
static void (play_controller::*callback_)();
static SDL_sem* sem_;
};
/** Autosave */
std::string save_autosave(unsigned turn, const config& snapshot, game_state& gamestate);