From 05f4e7360886e36b221ef5c3af4426625a3de686 Mon Sep 17 00:00:00 2001 From: Michael Lutz Date: Mon, 11 Mar 2019 00:45:39 +0100 Subject: [PATCH] Codechange: Replace custom mutex code with C++11 mutex'es. A conforming compiler with a valid -header is expected. Most parts of the code assume that locking a mutex will never fail unexpectedly, which is generally true on all common platforms that don't just pretend to be C++11. The use of condition variables in driver code is checked. --- src/core/smallstack_type.hpp | 17 +++---- src/genworld.cpp | 21 ++++---- src/genworld_gui.cpp | 8 +-- src/gfx.cpp | 8 +-- src/music/dmusic.cpp | 10 ++-- src/network/network_gamelist.cpp | 10 ++-- src/network/network_server.cpp | 36 +++++-------- src/network/network_udp.cpp | 23 ++++----- src/newgrf_config.cpp | 28 +++++----- src/openttd.cpp | 14 ++++- src/progress.cpp | 8 +-- src/progress.h | 16 ++++-- src/thread/thread.h | 67 ------------------------ src/thread/thread_none.cpp | 5 -- src/thread/thread_os2.cpp | 56 -------------------- src/thread/thread_pthread.cpp | 81 ----------------------------- src/thread/thread_win32.cpp | 56 -------------------- src/video/sdl_v.cpp | 62 ++++++++++++++--------- src/video/win32_v.cpp | 87 ++++++++++++++++++-------------- 19 files changed, 187 insertions(+), 426 deletions(-) diff --git a/src/core/smallstack_type.hpp b/src/core/smallstack_type.hpp index c273fdec46..6aded5a759 100644 --- a/src/core/smallstack_type.hpp +++ b/src/core/smallstack_type.hpp @@ -13,7 +13,7 @@ #define SMALLSTACK_TYPE_HPP #include "smallvec_type.hpp" -#include "../thread/thread.h" +#include /** * A simplified pool which stores values instead of pointers and doesn't @@ -23,15 +23,14 @@ template class SimplePool { public: - inline SimplePool() : first_unused(0), first_free(0), mutex(ThreadMutex::New()) {} - inline ~SimplePool() { delete this->mutex; } + inline SimplePool() : first_unused(0), first_free(0) {} /** * Get the mutex. We don't lock the mutex in the pool methods as the * SmallStack isn't necessarily in a consistent state after each method. * @return Mutex. */ - inline ThreadMutex *GetMutex() { return this->mutex; } + inline std::mutex &GetMutex() { return this->mutex; } /** * Get the item at position index. @@ -86,7 +85,7 @@ private: Tindex first_unused; Tindex first_free; - ThreadMutex *mutex; + std::mutex mutex; std::vector data; }; @@ -196,7 +195,7 @@ public: inline void Push(const Titem &item) { if (this->value != Tinvalid) { - ThreadMutexLocker lock(SmallStack::GetPool().GetMutex()); + std::lock_guard lock(SmallStack::GetPool().GetMutex()); Tindex new_item = SmallStack::GetPool().Create(); if (new_item != Tmax_size) { PooledSmallStack &pushed = SmallStack::GetPool().Get(new_item); @@ -219,7 +218,7 @@ public: if (this->next == Tmax_size) { this->value = Tinvalid; } else { - ThreadMutexLocker lock(SmallStack::GetPool().GetMutex()); + std::lock_guard lock(SmallStack::GetPool().GetMutex()); PooledSmallStack &popped = SmallStack::GetPool().Get(this->next); this->value = popped.value; if (popped.branch_count == 0) { @@ -258,7 +257,7 @@ public: { if (item == Tinvalid || item == this->value) return true; if (this->next != Tmax_size) { - ThreadMutexLocker lock(SmallStack::GetPool().GetMutex()); + std::lock_guard lock(SmallStack::GetPool().GetMutex()); const SmallStack *in_list = this; do { in_list = static_cast( @@ -282,7 +281,7 @@ protected: inline void Branch() { if (this->next != Tmax_size) { - ThreadMutexLocker lock(SmallStack::GetPool().GetMutex()); + std::lock_guard lock(SmallStack::GetPool().GetMutex()); ++(SmallStack::GetPool().Get(this->next).branch_count); } } diff --git a/src/genworld.cpp b/src/genworld.cpp index 25d6a7bd9d..64caf3b89a 100644 --- a/src/genworld.cpp +++ b/src/genworld.cpp @@ -34,6 +34,7 @@ #include "game/game.hpp" #include "game/game_instance.hpp" #include "string_func.h" +#include "thread/thread.h" #include "safeguards.h" @@ -98,9 +99,10 @@ static void _GenerateWorld(void *) /* Make sure everything is done via OWNER_NONE. */ Backup _cur_company(_current_company, OWNER_NONE, FILE_LINE); + std::unique_lock lock(_modal_progress_work_mutex, std::defer_lock); try { _generating_world = true; - _modal_progress_work_mutex->BeginCritical(); + lock.lock(); if (_network_dedicated) DEBUG(net, 1, "Generating map, please wait..."); /* Set the Random() seed to generation_seed so we produce the same map with the same seed */ if (_settings_game.game_creation.generation_seed == GENERATE_NEW_SEED) _settings_game.game_creation.generation_seed = _settings_newgame.game_creation.generation_seed = InteractiveRandom(); @@ -194,7 +196,7 @@ static void _GenerateWorld(void *) IncreaseGeneratingWorldProgress(GWP_GAME_START); CleanupGeneration(); - _modal_progress_work_mutex->EndCritical(); + lock.unlock(); ShowNewGRFError(); @@ -210,7 +212,6 @@ static void _GenerateWorld(void *) BasePersistentStorageArray::SwitchMode(PSM_LEAVE_GAMELOOP, true); if (_cur_company.IsValid()) _cur_company.Restore(); _generating_world = false; - _modal_progress_work_mutex->EndCritical(); throw; } } @@ -243,15 +244,15 @@ void WaitTillGeneratedWorld() { if (_gw.thread == NULL) return; - _modal_progress_work_mutex->EndCritical(); - _modal_progress_paint_mutex->EndCritical(); + _modal_progress_work_mutex.unlock(); + _modal_progress_paint_mutex.unlock(); _gw.quit_thread = true; _gw.thread->Join(); delete _gw.thread; _gw.thread = NULL; _gw.threaded = false; - _modal_progress_work_mutex->BeginCritical(); - _modal_progress_paint_mutex->BeginCritical(); + _modal_progress_work_mutex.lock(); + _modal_progress_paint_mutex.lock(); } /** @@ -331,12 +332,12 @@ void GenerateWorld(GenWorldMode mode, uint size_x, uint size_y, bool reset_setti _gw.thread = NULL; } - if (!VideoDriver::GetInstance()->HasGUI() || !ThreadObject::New(&_GenerateWorld, NULL, &_gw.thread, "ottd:genworld")) { + if (!UseThreadedModelProgress() || !VideoDriver::GetInstance()->HasGUI() || !ThreadObject::New(&_GenerateWorld, NULL, &_gw.thread, "ottd:genworld")) { DEBUG(misc, 1, "Cannot create genworld thread, reverting to single-threaded mode"); _gw.threaded = false; - _modal_progress_work_mutex->EndCritical(); + _modal_progress_work_mutex.unlock(); _GenerateWorld(NULL); - _modal_progress_work_mutex->BeginCritical(); + _modal_progress_work_mutex.lock(); return; } diff --git a/src/genworld_gui.cpp b/src/genworld_gui.cpp index d4aad62211..697ce382d7 100644 --- a/src/genworld_gui.cpp +++ b/src/genworld_gui.cpp @@ -1321,10 +1321,10 @@ static void _SetGeneratingWorldProgress(GenWorldProgress cls, uint progress, uin * paint thread. The 'other' thread already has the paint thread rights so * this ensures us that we are waiting until the paint thread is done * before we reacquire the mapgen rights */ - _modal_progress_work_mutex->EndCritical(); - _modal_progress_paint_mutex->BeginCritical(); - _modal_progress_work_mutex->BeginCritical(); - _modal_progress_paint_mutex->EndCritical(); + _modal_progress_work_mutex.unlock(); + _modal_progress_paint_mutex.lock(); + _modal_progress_work_mutex.lock(); + _modal_progress_paint_mutex.unlock(); _gws.timer = _realtime_tick; } diff --git a/src/gfx.cpp b/src/gfx.cpp index 72d3fcd67b..b7e31a3845 100644 --- a/src/gfx.cpp +++ b/src/gfx.cpp @@ -1308,8 +1308,8 @@ void DrawDirtyBlocks() if (HasModalProgress()) { /* We are generating the world, so release our rights to the map and * painting while we are waiting a bit. */ - _modal_progress_paint_mutex->EndCritical(); - _modal_progress_work_mutex->EndCritical(); + _modal_progress_paint_mutex.unlock(); + _modal_progress_work_mutex.unlock(); /* Wait a while and update _realtime_tick so we are given the rights */ if (!IsFirstModalProgressLoop()) CSleep(MODAL_PROGRESS_REDRAW_TIMEOUT); @@ -1317,9 +1317,9 @@ void DrawDirtyBlocks() /* Modal progress thread may need blitter access while we are waiting for it. */ VideoDriver::GetInstance()->ReleaseBlitterLock(); - _modal_progress_paint_mutex->BeginCritical(); + _modal_progress_paint_mutex.lock(); VideoDriver::GetInstance()->AcquireBlitterLock(); - _modal_progress_work_mutex->BeginCritical(); + _modal_progress_work_mutex.lock(); /* When we ended with the modal progress, do not draw the blocks. * Simply let the next run do so, otherwise we would be loading diff --git a/src/music/dmusic.cpp b/src/music/dmusic.cpp index 241ab191bf..4b9a22c724 100644 --- a/src/music/dmusic.cpp +++ b/src/music/dmusic.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include "../safeguards.h" @@ -142,7 +143,7 @@ static ThreadObject *_dmusic_thread = NULL; /** Event to signal the thread that it should look at a state change. */ static HANDLE _thread_event = NULL; /** Lock access to playback data that is not thread-safe. */ -static ThreadMutex *_thread_mutex = NULL; +static std::mutex _thread_mutex; /** The direct music object manages buffers and ports. */ static IDirectMusic *_music = NULL; @@ -655,7 +656,7 @@ static void MidiThreadProc(void *) DEBUG(driver, 2, "DMusic thread: Starting playback"); { /* New scope to limit the time the mutex is locked. */ - ThreadMutexLocker lock(_thread_mutex); + std::lock_guard lock(_thread_mutex); current_file.MoveFrom(_playback.next_file); std::swap(_playback.next_segment, current_segment); @@ -1167,8 +1168,6 @@ const char *MusicDriver_DMusic::Start(const char * const *parm) /* Create playback thread and synchronization primitives. */ _thread_event = CreateEvent(NULL, FALSE, FALSE, NULL); if (_thread_event == NULL) return "Can't create thread shutdown event"; - _thread_mutex = ThreadMutex::New(); - if (_thread_mutex == NULL) return "Can't create thread mutex"; if (!ThreadObject::New(&MidiThreadProc, this, &_dmusic_thread, "ottd:dmusic")) return "Can't create MIDI output thread"; @@ -1223,7 +1222,6 @@ void MusicDriver_DMusic::Stop() } CloseHandle(_thread_event); - delete _thread_mutex; CoUninitialize(); } @@ -1231,7 +1229,7 @@ void MusicDriver_DMusic::Stop() void MusicDriver_DMusic::PlaySong(const MusicSongInfo &song) { - ThreadMutexLocker lock(_thread_mutex); + std::lock_guard lock(_thread_mutex); if (!_playback.next_file.LoadSong(song)) return; diff --git a/src/network/network_gamelist.cpp b/src/network/network_gamelist.cpp index 6c65c52c98..c67fba5ec3 100644 --- a/src/network/network_gamelist.cpp +++ b/src/network/network_gamelist.cpp @@ -15,17 +15,17 @@ #include "../stdafx.h" #include "../debug.h" #include "../window_func.h" -#include "../thread/thread.h" #include "network_internal.h" #include "network_udp.h" #include "network_gamelist.h" +#include #include "../safeguards.h" NetworkGameList *_network_game_list = NULL; /** Mutex for handling delayed insertion/querying of servers. */ -static ThreadMutex *_network_game_list_mutex = ThreadMutex::New(); +static std::mutex _network_game_list_mutex; /** The games to insert when the GUI thread has time for us. */ static NetworkGameList *_network_game_delayed_insertion_list = NULL; @@ -36,16 +36,15 @@ static NetworkGameList *_network_game_delayed_insertion_list = NULL; */ void NetworkGameListAddItemDelayed(NetworkGameList *item) { - _network_game_list_mutex->BeginCritical(); + std::lock_guard lock(_network_game_list_mutex); item->next = _network_game_delayed_insertion_list; _network_game_delayed_insertion_list = item; - _network_game_list_mutex->EndCritical(); } /** Perform the delayed (thread safe) insertion into the game list */ static void NetworkGameListHandleDelayedInsert() { - _network_game_list_mutex->BeginCritical(); + std::lock_guard lock(_network_game_list_mutex); while (_network_game_delayed_insertion_list != NULL) { NetworkGameList *ins_item = _network_game_delayed_insertion_list; _network_game_delayed_insertion_list = ins_item->next; @@ -66,7 +65,6 @@ static void NetworkGameListHandleDelayedInsert() } free(ins_item); } - _network_game_list_mutex->EndCritical(); } /** diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp index 1bcd7ca127..97da64bd3b 100644 --- a/src/network/network_server.cpp +++ b/src/network/network_server.cpp @@ -30,6 +30,8 @@ #include "../core/pool_func.hpp" #include "../core/random_func.hpp" #include "../rev.h" +#include +#include #include "../safeguards.h" @@ -58,7 +60,8 @@ struct PacketWriter : SaveFilter { Packet *current; ///< The packet we're currently writing to. size_t total_size; ///< Total size of the compressed savegame. Packet *packets; ///< Packet queue of the savegame; send these "slowly" to the client. - ThreadMutex *mutex; ///< Mutex for making threaded saving safe. + std::mutex mutex; ///< Mutex for making threaded saving safe. + std::condition_variable exit_sig; ///< Signal for threaded destruction of this packet writer. /** * Create the packet writer. @@ -66,17 +69,14 @@ struct PacketWriter : SaveFilter { */ PacketWriter(ServerNetworkGameSocketHandler *cs) : SaveFilter(NULL), cs(cs), current(NULL), total_size(0), packets(NULL) { - this->mutex = ThreadMutex::New(); } /** Make sure everything is cleaned up. */ ~PacketWriter() { - if (this->mutex != NULL) this->mutex->BeginCritical(); + std::unique_lock lock(this->mutex); - if (this->cs != NULL && this->mutex != NULL) { - this->mutex->WaitForSignal(); - } + if (this->cs != NULL) this->exit_sig.wait(lock); /* This must all wait until the Destroy function is called. */ @@ -87,11 +87,6 @@ struct PacketWriter : SaveFilter { } delete this->current; - - if (this->mutex != NULL) this->mutex->EndCritical(); - - delete this->mutex; - this->mutex = NULL; } /** @@ -106,13 +101,12 @@ struct PacketWriter : SaveFilter { */ void Destroy() { - if (this->mutex != NULL) this->mutex->BeginCritical(); + std::unique_lock lock(this->mutex); this->cs = NULL; - if (this->mutex != NULL) this->mutex->SendSignal(); - - if (this->mutex != NULL) this->mutex->EndCritical(); + this->exit_sig.notify_all(); + lock.unlock(); /* Make sure the saving is completely cancelled. Yes, * we need to handle the save finish as well as the @@ -138,14 +132,12 @@ struct PacketWriter : SaveFilter { */ Packet *PopPacket() { - if (this->mutex != NULL) this->mutex->BeginCritical(); + std::lock_guard lock(this->mutex); Packet *p = this->packets; this->packets = p->next; p->next = NULL; - if (this->mutex != NULL) this->mutex->EndCritical(); - return p; } @@ -170,7 +162,7 @@ struct PacketWriter : SaveFilter { if (this->current == NULL) this->current = new Packet(PACKET_SERVER_MAP_DATA); - if (this->mutex != NULL) this->mutex->BeginCritical(); + std::lock_guard lock(this->mutex); byte *bufe = buf + size; while (buf != bufe) { @@ -185,8 +177,6 @@ struct PacketWriter : SaveFilter { } } - if (this->mutex != NULL) this->mutex->EndCritical(); - this->total_size += size; } @@ -195,7 +185,7 @@ struct PacketWriter : SaveFilter { /* We want to abort the saving when the socket is closed. */ if (this->cs == NULL) SlError(STR_NETWORK_ERROR_LOSTCONNECTION); - if (this->mutex != NULL) this->mutex->BeginCritical(); + std::lock_guard lock(this->mutex); /* Make sure the last packet is flushed. */ this->AppendQueue(); @@ -208,8 +198,6 @@ struct PacketWriter : SaveFilter { Packet *p = new Packet(PACKET_SERVER_MAP_SIZE); p->Send_uint32((uint32)this->total_size); this->cs->NetworkTCPSocketHandler::SendPacket(p); - - if (this->mutex != NULL) this->mutex->EndCritical(); } }; diff --git a/src/network/network_udp.cpp b/src/network/network_udp.cpp index 2d7ee2d3cf..df8c59aac6 100644 --- a/src/network/network_udp.cpp +++ b/src/network/network_udp.cpp @@ -29,13 +29,14 @@ #include "../newgrf_text.h" #include "../strings_func.h" #include "table/strings.h" +#include #include "core/udp.h" #include "../safeguards.h" /** Mutex for all out threaded udp resolution and such. */ -static ThreadMutex *_network_udp_mutex = ThreadMutex::New(); +static std::mutex _network_udp_mutex; /** Session key to register ourselves to the master server */ static uint64 _session_key = 0; @@ -80,11 +81,11 @@ static void NetworkUDPQueryServer(NetworkAddress *address, bool needs_mutex, boo item->manually = manually; NetworkGameListAddItemDelayed(item); - if (needs_mutex) _network_udp_mutex->BeginCritical(); + std::unique_lock lock(_network_udp_mutex, std::defer_lock); + if (needs_mutex) lock.lock(); /* Init the packet */ Packet p(PACKET_UDP_CLIENT_FIND_SERVER); if (_udp_client_socket != NULL) _udp_client_socket->SendPacket(&p, address); - if (needs_mutex) _network_udp_mutex->EndCritical(); } /** @@ -549,9 +550,8 @@ static void NetworkUDPRemoveAdvertiseThread(void *pntr) p.Send_uint8 (NETWORK_MASTER_SERVER_VERSION); p.Send_uint16(_settings_client.network.server_port); - _network_udp_mutex->BeginCritical(); + std::lock_guard lock(_network_udp_mutex); if (_udp_master_socket != NULL) _udp_master_socket->SendPacket(&p, &out_addr, true); - _network_udp_mutex->EndCritical(); } /** @@ -603,9 +603,8 @@ static void NetworkUDPAdvertiseThread(void *pntr) p.Send_uint16(_settings_client.network.server_port); p.Send_uint64(_session_key); - _network_udp_mutex->BeginCritical(); + std::lock_guard lock(_network_udp_mutex); if (_udp_master_socket != NULL) _udp_master_socket->SendPacket(&p, &out_addr, true); - _network_udp_mutex->EndCritical(); } /** @@ -660,7 +659,7 @@ void NetworkUDPInitialize() DEBUG(net, 1, "[udp] initializing listeners"); assert(_udp_client_socket == NULL && _udp_server_socket == NULL && _udp_master_socket == NULL); - _network_udp_mutex->BeginCritical(); + std::lock_guard lock(_network_udp_mutex); _udp_client_socket = new ClientNetworkUDPSocketHandler(); @@ -674,13 +673,12 @@ void NetworkUDPInitialize() _network_udp_server = false; _network_udp_broadcast = 0; - _network_udp_mutex->EndCritical(); } /** Close all UDP related stuff. */ void NetworkUDPClose() { - _network_udp_mutex->BeginCritical(); + std::lock_guard lock(_network_udp_mutex); _udp_server_socket->Close(); _udp_master_socket->Close(); _udp_client_socket->Close(); @@ -690,7 +688,6 @@ void NetworkUDPClose() _udp_client_socket = NULL; _udp_server_socket = NULL; _udp_master_socket = NULL; - _network_udp_mutex->EndCritical(); _network_udp_server = false; _network_udp_broadcast = 0; @@ -700,7 +697,7 @@ void NetworkUDPClose() /** Receive the UDP packets. */ void NetworkBackgroundUDPLoop() { - _network_udp_mutex->BeginCritical(); + std::lock_guard lock(_network_udp_mutex); if (_network_udp_server) { _udp_server_socket->ReceivePackets(); @@ -709,6 +706,4 @@ void NetworkBackgroundUDPLoop() _udp_client_socket->ReceivePackets(); if (_network_udp_broadcast > 0) _network_udp_broadcast--; } - - _network_udp_mutex->EndCritical(); } diff --git a/src/newgrf_config.cpp b/src/newgrf_config.cpp index e346a4a823..feb23648a9 100644 --- a/src/newgrf_config.cpp +++ b/src/newgrf_config.cpp @@ -21,6 +21,7 @@ #include "video/video_driver.hpp" #include "strings_func.h" #include "textfile_gui.h" +#include "thread/thread.h" #include "fileio_func.h" #include "fios.h" @@ -682,18 +683,18 @@ bool GRFFileScanner::AddFile(const char *filename, size_t basepath_length, const this->num_scanned++; if (this->next_update <= _realtime_tick) { - _modal_progress_work_mutex->EndCritical(); - _modal_progress_paint_mutex->BeginCritical(); + _modal_progress_work_mutex.unlock(); + _modal_progress_paint_mutex.lock(); const char *name = NULL; if (c->name != NULL) name = GetGRFStringFromGRFText(c->name->text); if (name == NULL) name = c->filename; UpdateNewGRFScanStatus(this->num_scanned, name); - _modal_progress_work_mutex->BeginCritical(); - _modal_progress_paint_mutex->EndCritical(); + _modal_progress_work_mutex.lock(); + _modal_progress_paint_mutex.unlock(); - this->next_update = _realtime_tick + 200; + this->next_update = _realtime_tick + MODAL_PROGRESS_REDRAW_TIMEOUT; } if (!added) { @@ -725,7 +726,7 @@ static int CDECL GRFSorter(GRFConfig * const *p1, GRFConfig * const *p2) */ void DoScanNewGRFFiles(void *callback) { - _modal_progress_work_mutex->BeginCritical(); + std::unique_lock lock_work(_modal_progress_work_mutex); ClearGRFConfigList(&_all_grfs); TarScanner::DoScan(TarScanner::NEWGRF); @@ -760,8 +761,8 @@ void DoScanNewGRFFiles(void *callback) NetworkAfterNewGRFScan(); } - _modal_progress_work_mutex->EndCritical(); - _modal_progress_paint_mutex->BeginCritical(); + lock_work.unlock(); + std::lock_guard lock_paint(_modal_progress_paint_mutex); /* Yes... these are the NewGRF windows */ InvalidateWindowClassesData(WC_SAVELOAD, 0, true); @@ -771,7 +772,6 @@ void DoScanNewGRFFiles(void *callback) DeleteWindowByClass(WC_MODAL_PROGRESS); SetModalProgress(false); MarkWholeScreenDirty(); - _modal_progress_paint_mutex->EndCritical(); } /** @@ -785,12 +785,12 @@ void ScanNewGRFFiles(NewGRFScanCallback *callback) /* Only then can we really start, especially by marking the whole screen dirty. Get those other windows hidden!. */ MarkWholeScreenDirty(); - if (!VideoDriver::GetInstance()->HasGUI() || !ThreadObject::New(&DoScanNewGRFFiles, callback, NULL, "ottd:newgrf-scan")) { - _modal_progress_work_mutex->EndCritical(); - _modal_progress_paint_mutex->EndCritical(); + if (!UseThreadedModelProgress() || !VideoDriver::GetInstance()->HasGUI() || !ThreadObject::New(&DoScanNewGRFFiles, callback, NULL, "ottd:newgrf-scan")) { + _modal_progress_work_mutex.unlock(); + _modal_progress_paint_mutex.unlock(); DoScanNewGRFFiles(callback); - _modal_progress_paint_mutex->BeginCritical(); - _modal_progress_work_mutex->BeginCritical(); + _modal_progress_paint_mutex.lock(); + _modal_progress_work_mutex.lock(); } else { UpdateNewGRFScanStatus(0, NULL); } diff --git a/src/openttd.cpp b/src/openttd.cpp index 29319236af..180de64b0d 100644 --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -68,6 +68,7 @@ #include "linkgraph/linkgraphschedule.h" #include +#include #include "safeguards.h" @@ -547,6 +548,9 @@ int openttd_main(int argc, char *argv[]) extern bool _dedicated_forks; _dedicated_forks = false; + std::unique_lock modal_work_lock(_modal_progress_work_mutex, std::defer_lock); + std::unique_lock modal_paint_lock(_modal_progress_paint_mutex, std::defer_lock); + _game_mode = GM_MENU; _switch_mode = SM_MENU; _config_file = NULL; @@ -830,8 +834,14 @@ int openttd_main(int argc, char *argv[]) free(musicdriver); /* Take our initial lock on whatever we might want to do! */ - _modal_progress_paint_mutex->BeginCritical(); - _modal_progress_work_mutex->BeginCritical(); + try { + modal_work_lock.lock(); + modal_paint_lock.lock(); + } catch (const std::system_error&) { + /* If there is some error we assume that threads aren't usable on the system we run. */ + extern bool _use_threaded_modal_progress; // From progress.cpp + _use_threaded_modal_progress = false; + } GenerateWorld(GWM_EMPTY, 64, 64); // Make the viewport initialization happy WaitTillGeneratedWorld(); diff --git a/src/progress.cpp b/src/progress.cpp index b498be109b..923f1ef83f 100644 --- a/src/progress.cpp +++ b/src/progress.cpp @@ -10,17 +10,19 @@ /** @file progress.cpp Functions for modal progress windows. */ #include "stdafx.h" -#include "thread/thread.h" +#include "progress.h" #include "safeguards.h" /** Are we in a modal progress or not? */ bool _in_modal_progress = false; bool _first_in_modal_loop = false; +/** Threading usable for modal progress? */ +bool _use_threaded_modal_progress = true; /** Rights for the performing work. */ -ThreadMutex *_modal_progress_work_mutex = ThreadMutex::New(); +std::mutex _modal_progress_work_mutex; /** Rights for the painting. */ -ThreadMutex *_modal_progress_paint_mutex = ThreadMutex::New(); +std::mutex _modal_progress_paint_mutex; /** * Set the modal progress state. diff --git a/src/progress.h b/src/progress.h index eec369b23c..2a9d73b038 100644 --- a/src/progress.h +++ b/src/progress.h @@ -12,7 +12,7 @@ #ifndef PROGRESS_H #define PROGRESS_H -#include "thread/thread.h" +#include static const uint MODAL_PROGRESS_REDRAW_TIMEOUT = 200; ///< Timeout between redraws @@ -26,10 +26,20 @@ static inline bool HasModalProgress() return _in_modal_progress; } +/** + * Check if we can use a thread for modal progress. + * @return Threading usable? + */ +static inline bool UseThreadedModelProgress() +{ + extern bool _use_threaded_modal_progress; + return _use_threaded_modal_progress; +} + bool IsFirstModalProgressLoop(); void SetModalProgress(bool state); -extern class ThreadMutex *_modal_progress_work_mutex; -extern class ThreadMutex *_modal_progress_paint_mutex; +extern std::mutex _modal_progress_work_mutex; +extern std::mutex _modal_progress_paint_mutex; #endif /* PROGRESS_H */ diff --git a/src/thread/thread.h b/src/thread/thread.h index 07831bb4ba..eca825e25e 100644 --- a/src/thread/thread.h +++ b/src/thread/thread.h @@ -50,73 +50,6 @@ public: static bool New(OTTDThreadFunc proc, void *param, ThreadObject **thread = NULL, const char *name = NULL); }; -/** - * Cross-platform Mutex - */ -class ThreadMutex { -public: - /** - * Create a new mutex. - */ - static ThreadMutex *New(); - - /** - * Virtual Destructor to avoid compiler warnings. - */ - virtual ~ThreadMutex() {}; - - /** - * Begin the critical section - * @param allow_recursive Whether recursive locking is intentional. - * If false, NOT_REACHED() will be called when the mutex is already locked - * by the current thread. - */ - virtual void BeginCritical(bool allow_recursive = false) = 0; - - /** - * End of the critical section - * @param allow_recursive Whether recursive unlocking is intentional. - * If false, NOT_REACHED() will be called when the mutex was locked more - * than once by the current thread. - */ - virtual void EndCritical(bool allow_recursive = false) = 0; - - /** - * Wait for a signal to be send. - * @pre You must be in the critical section. - * @note While waiting the critical section is left. - * @post You will be in the critical section. - */ - virtual void WaitForSignal() = 0; - - /** - * Send a signal and wake the 'thread' that was waiting for it. - */ - virtual void SendSignal() = 0; -}; - -/** - * Simple mutex locker to keep a mutex locked until the locker goes out of scope. - */ -class ThreadMutexLocker { -public: - /** - * Lock the mutex and keep it locked for the life time of this object. - * @param mutex Mutex to be locked. - */ - ThreadMutexLocker(ThreadMutex *mutex) : mutex(mutex) { mutex->BeginCritical(); } - - /** - * Unlock the mutex. - */ - ~ThreadMutexLocker() { this->mutex->EndCritical(); } - -private: - ThreadMutexLocker(const ThreadMutexLocker &) { NOT_REACHED(); } - ThreadMutexLocker &operator=(const ThreadMutexLocker &) { NOT_REACHED(); return *this; } - ThreadMutex *mutex; -}; - /** * Get number of processor cores in the system, including HyperThreading or similar. * @return Total number of processor cores. diff --git a/src/thread/thread_none.cpp b/src/thread/thread_none.cpp index 91eb50b113..83ae52d460 100644 --- a/src/thread/thread_none.cpp +++ b/src/thread/thread_none.cpp @@ -28,8 +28,3 @@ public: virtual void WaitForSignal() {} virtual void SendSignal() {} }; - -/* static */ ThreadMutex *ThreadMutex::New() -{ - return new ThreadMutex_None(); -} diff --git a/src/thread/thread_os2.cpp b/src/thread/thread_os2.cpp index 976283f231..72ee080d6d 100644 --- a/src/thread/thread_os2.cpp +++ b/src/thread/thread_os2.cpp @@ -89,59 +89,3 @@ private: if (thread != NULL) *thread = to; return true; } - -/** - * OS/2 version of ThreadMutex. - */ -class ThreadMutex_OS2 : public ThreadMutex { -private: - HMTX mutex; ///< The mutex. - HEV event; ///< Event for waiting. - uint recursive_count; ///< Recursive lock count. - -public: - ThreadMutex_OS2() : recursive_count(0) - { - DosCreateMutexSem(NULL, &mutex, 0, FALSE); - DosCreateEventSem(NULL, &event, 0, FALSE); - } - - ~ThreadMutex_OS2() override - { - DosCloseMutexSem(mutex); - DosCloseEventSem(event); - } - - void BeginCritical(bool allow_recursive = false) override - { - /* os2 mutex is recursive by itself */ - DosRequestMutexSem(mutex, (unsigned long) SEM_INDEFINITE_WAIT); - this->recursive_count++; - if (!allow_recursive && this->recursive_count != 1) NOT_REACHED(); - } - - void EndCritical(bool allow_recursive = false) override - { - if (!allow_recursive && this->recursive_count != 1) NOT_REACHED(); - this->recursive_count--; - DosReleaseMutexSem(mutex); - } - - void WaitForSignal() override - { - assert(this->recursive_count == 1); // Do we need to call Begin/EndCritical multiple times otherwise? - this->EndCritical(); - DosWaitEventSem(event, SEM_INDEFINITE_WAIT); - this->BeginCritical(); - } - - void SendSignal() override - { - DosPostEventSem(event); - } -}; - -/* static */ ThreadMutex *ThreadMutex::New() -{ - return new ThreadMutex_OS2(); -} diff --git a/src/thread/thread_pthread.cpp b/src/thread/thread_pthread.cpp index afb259183e..50fefb5311 100644 --- a/src/thread/thread_pthread.cpp +++ b/src/thread/thread_pthread.cpp @@ -108,84 +108,3 @@ private: if (thread != NULL) *thread = to; return true; } - -/** - * POSIX pthread version of ThreadMutex. - */ -class ThreadMutex_pthread : public ThreadMutex { -private: - pthread_mutex_t mutex; ///< The actual mutex. - pthread_cond_t condition; ///< Data for conditional waiting. - pthread_mutexattr_t attr; ///< Attributes set for the mutex. - pthread_t owner; ///< Owning thread of the mutex. - uint recursive_count; ///< Recursive lock count. - -public: - ThreadMutex_pthread() : owner(0), recursive_count(0) - { - pthread_mutexattr_init(&this->attr); - pthread_mutexattr_settype(&this->attr, PTHREAD_MUTEX_ERRORCHECK); - pthread_mutex_init(&this->mutex, &this->attr); - pthread_cond_init(&this->condition, NULL); - } - - ~ThreadMutex_pthread() override - { - int err = pthread_cond_destroy(&this->condition); - assert(err != EBUSY); - err = pthread_mutex_destroy(&this->mutex); - assert(err != EBUSY); - } - - bool IsOwnedByCurrentThread() const - { - return this->owner == pthread_self(); - } - - void BeginCritical(bool allow_recursive = false) override - { - /* pthread mutex is not recursive by itself */ - if (this->IsOwnedByCurrentThread()) { - if (!allow_recursive) NOT_REACHED(); - } else { - int err = pthread_mutex_lock(&this->mutex); - assert(err == 0); - assert(this->recursive_count == 0); - this->owner = pthread_self(); - } - this->recursive_count++; - } - - void EndCritical(bool allow_recursive = false) override - { - assert(this->IsOwnedByCurrentThread()); - if (!allow_recursive && this->recursive_count != 1) NOT_REACHED(); - this->recursive_count--; - if (this->recursive_count != 0) return; - this->owner = 0; - int err = pthread_mutex_unlock(&this->mutex); - assert(err == 0); - } - - void WaitForSignal() override - { - uint old_recursive_count = this->recursive_count; - this->recursive_count = 0; - this->owner = 0; - int err = pthread_cond_wait(&this->condition, &this->mutex); - assert(err == 0); - this->owner = pthread_self(); - this->recursive_count = old_recursive_count; - } - - void SendSignal() override - { - int err = pthread_cond_signal(&this->condition); - assert(err == 0); - } -}; - -/* static */ ThreadMutex *ThreadMutex::New() -{ - return new ThreadMutex_pthread(); -} diff --git a/src/thread/thread_win32.cpp b/src/thread/thread_win32.cpp index 506faa069e..fc7a85a91c 100644 --- a/src/thread/thread_win32.cpp +++ b/src/thread/thread_win32.cpp @@ -109,59 +109,3 @@ private: if (thread != NULL) *thread = to; return true; } - -/** - * Win32 thread version of ThreadMutex. - */ -class ThreadMutex_Win32 : public ThreadMutex { -private: - CRITICAL_SECTION critical_section; ///< The critical section we would enter. - HANDLE event; ///< Event for signalling. - uint recursive_count; ///< Recursive lock count. - -public: - ThreadMutex_Win32() : recursive_count(0) - { - InitializeCriticalSection(&this->critical_section); - this->event = CreateEvent(NULL, FALSE, FALSE, NULL); - } - - ~ThreadMutex_Win32() override - { - DeleteCriticalSection(&this->critical_section); - CloseHandle(this->event); - } - - void BeginCritical(bool allow_recursive = false) override - { - /* windows mutex is recursive by itself */ - EnterCriticalSection(&this->critical_section); - this->recursive_count++; - if (!allow_recursive && this->recursive_count != 1) NOT_REACHED(); - } - - void EndCritical(bool allow_recursive = false) override - { - if (!allow_recursive && this->recursive_count != 1) NOT_REACHED(); - this->recursive_count--; - LeaveCriticalSection(&this->critical_section); - } - - void WaitForSignal() override - { - assert(this->recursive_count == 1); // Do we need to call Begin/EndCritical multiple times otherwise? - this->EndCritical(); - WaitForSingleObject(this->event, INFINITE); - this->BeginCritical(); - } - - void SendSignal() override - { - SetEvent(this->event); - } -}; - -/* static */ ThreadMutex *ThreadMutex::New() -{ - return new ThreadMutex_Win32(); -} diff --git a/src/video/sdl_v.cpp b/src/video/sdl_v.cpp index 62bbb33012..b1609f7b37 100644 --- a/src/video/sdl_v.cpp +++ b/src/video/sdl_v.cpp @@ -25,6 +25,8 @@ #include "../framerate_type.h" #include "sdl_v.h" #include +#include +#include #include "../safeguards.h" @@ -39,7 +41,9 @@ static bool _draw_threaded; /** Thread used to 'draw' to the screen, i.e. push data to the screen. */ static ThreadObject *_draw_thread = NULL; /** Mutex to keep the access to the shared memory controlled. */ -static ThreadMutex *_draw_mutex = NULL; +static std::recursive_mutex *_draw_mutex = NULL; +/** Signal to draw the next frame. */ +static std::condition_variable_any *_draw_signal = NULL; /** Should we keep continue drawing? */ static volatile bool _draw_continue; static Palette _local_palette; @@ -172,20 +176,19 @@ static void DrawSurfaceToScreen() static void DrawSurfaceToScreenThread(void *) { /* First tell the main thread we're started */ - _draw_mutex->BeginCritical(); - _draw_mutex->SendSignal(); + std::unique_lock lock(*_draw_mutex); + _draw_signal->notify_one(); /* Now wait for the first thing to draw! */ - _draw_mutex->WaitForSignal(); + _draw_signal->wait(*_draw_mutex); while (_draw_continue) { CheckPaletteAnim(); /* Then just draw and wait till we stop */ DrawSurfaceToScreen(); - _draw_mutex->WaitForSignal(); + _draw_signal->wait(lock); } - _draw_mutex->EndCritical(); _draw_thread->Exit(); } @@ -668,26 +671,31 @@ void VideoDriver_SDL::MainLoop() CheckPaletteAnim(); + std::unique_lock draw_lock; if (_draw_threaded) { /* Initialise the mutex first, because that's the thing we *need* * directly in the newly created thread. */ - _draw_mutex = ThreadMutex::New(); + _draw_mutex = new std::recursive_mutex(); if (_draw_mutex == NULL) { _draw_threaded = false; } else { - _draw_mutex->BeginCritical(); + draw_lock = std::unique_lock(*_draw_mutex); + _draw_signal = new std::condition_variable_any(); _draw_continue = true; _draw_threaded = ThreadObject::New(&DrawSurfaceToScreenThread, NULL, &_draw_thread, "ottd:draw-sdl"); /* Free the mutex if we won't be able to use it. */ if (!_draw_threaded) { - _draw_mutex->EndCritical(); + draw_lock.unlock(); + draw_lock.release(); delete _draw_mutex; + delete _draw_signal; _draw_mutex = NULL; + _draw_signal = NULL; } else { /* Wait till the draw mutex has started itself. */ - _draw_mutex->WaitForSignal(); + _draw_signal->wait(*_draw_mutex); } } } @@ -752,19 +760,19 @@ void VideoDriver_SDL::MainLoop() /* The gameloop is the part that can run asynchronously. The rest * except sleeping can't. */ - if (_draw_mutex != NULL) _draw_mutex->EndCritical(); + if (_draw_mutex != NULL) draw_lock.unlock(); GameLoop(); - if (_draw_mutex != NULL) _draw_mutex->BeginCritical(); + if (_draw_mutex != NULL) draw_lock.lock(); UpdateWindows(); _local_palette = _cur_palette; } else { /* Release the thread while sleeping */ - if (_draw_mutex != NULL) _draw_mutex->EndCritical(); + if (_draw_mutex != NULL) draw_lock.unlock(); CSleep(1); - if (_draw_mutex != NULL) _draw_mutex->BeginCritical(); + if (_draw_mutex != NULL) draw_lock.lock(); NetworkDrawChatMessage(); DrawMouseCursor(); @@ -772,7 +780,7 @@ void VideoDriver_SDL::MainLoop() /* End of the critical part. */ if (_draw_mutex != NULL && !HasModalProgress()) { - _draw_mutex->SendSignal(); + _draw_signal->notify_one(); } else { /* Oh, we didn't have threads, then just draw unthreaded */ CheckPaletteAnim(); @@ -784,29 +792,34 @@ void VideoDriver_SDL::MainLoop() _draw_continue = false; /* Sending signal if there is no thread blocked * is very valid and results in noop */ - _draw_mutex->SendSignal(); - _draw_mutex->EndCritical(); + _draw_signal->notify_one(); + if (draw_lock.owns_lock()) draw_lock.unlock(); + draw_lock.release(); _draw_thread->Join(); delete _draw_mutex; + delete _draw_signal; delete _draw_thread; _draw_mutex = NULL; + _draw_signal = NULL; _draw_thread = NULL; } } bool VideoDriver_SDL::ChangeResolution(int w, int h) { - if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); - bool ret = CreateMainSurface(w, h); - if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); - return ret; + std::unique_lock lock; + if (_draw_mutex != NULL) lock = std::unique_lock(*_draw_mutex); + + return CreateMainSurface(w, h); } bool VideoDriver_SDL::ToggleFullscreen(bool fullscreen) { - if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); + std::unique_lock lock; + if (_draw_mutex != NULL) lock = std::unique_lock(*_draw_mutex); + _fullscreen = fullscreen; GetVideoModes(); // get the list of available video modes bool ret = _num_resolutions != 0 && CreateMainSurface(_cur_resolution.width, _cur_resolution.height); @@ -816,7 +829,6 @@ bool VideoDriver_SDL::ToggleFullscreen(bool fullscreen) _fullscreen ^= true; } - if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); return ret; } @@ -827,12 +839,12 @@ bool VideoDriver_SDL::AfterBlitterChange() void VideoDriver_SDL::AcquireBlitterLock() { - if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); + if (_draw_mutex != NULL) _draw_mutex->lock(); } void VideoDriver_SDL::ReleaseBlitterLock() { - if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); + if (_draw_mutex != NULL) _draw_mutex->unlock(); } #endif /* WITH_SDL */ diff --git a/src/video/win32_v.cpp b/src/video/win32_v.cpp index 6cee4fef28..ef7bc89e2c 100644 --- a/src/video/win32_v.cpp +++ b/src/video/win32_v.cpp @@ -27,6 +27,8 @@ #include "win32_v.h" #include #include +#include +#include #include "../safeguards.h" @@ -68,9 +70,9 @@ static bool _draw_threaded; /** Thread used to 'draw' to the screen, i.e. push data to the screen. */ static ThreadObject *_draw_thread = NULL; /** Mutex to keep the access to the shared memory controlled. */ -static ThreadMutex *_draw_mutex = NULL; -/** Event that is signaled when the drawing thread has finished initializing. */ -static HANDLE _draw_thread_initialized = NULL; +static std::recursive_mutex *_draw_mutex = NULL; +/** Signal to draw the next frame. */ +static std::condition_variable_any *_draw_signal = NULL; /** Should we keep continue drawing? */ static volatile bool _draw_continue; /** Local copy of the palette for use in the drawing thread. */ @@ -396,11 +398,11 @@ static void PaintWindow(HDC dc) static void PaintWindowThread(void *) { /* First tell the main thread we're started */ - _draw_mutex->BeginCritical(); - SetEvent(_draw_thread_initialized); + std::unique_lock lock(*_draw_mutex); + _draw_signal->notify_one(); /* Now wait for the first thing to draw! */ - _draw_mutex->WaitForSignal(); + _draw_signal->wait(*_draw_mutex); while (_draw_continue) { /* Convert update region from logical to device coordinates. */ @@ -422,10 +424,9 @@ static void PaintWindowThread(void *) /* Flush GDI buffer to ensure drawing here doesn't conflict with any GDI usage in the main WndProc. */ GdiFlush(); - _draw_mutex->WaitForSignal(); + _draw_signal->wait(*_draw_mutex); } - _draw_mutex->EndCritical(); _draw_thread->Exit(); } @@ -658,7 +659,7 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP /* Mark the window as updated, otherwise Windows would send more WM_PAINT messages. */ ValidateRect(hwnd, NULL); - _draw_mutex->SendSignal(); + _draw_signal->notify_one(); } else { PAINTSTRUCT ps; @@ -1189,28 +1190,36 @@ void VideoDriver_Win32::MainLoop() uint32 last_cur_ticks = cur_ticks; uint32 next_tick = cur_ticks + MILLISECONDS_PER_TICK; + std::unique_lock draw_lock; + if (_draw_threaded) { /* Initialise the mutex first, because that's the thing we *need* * directly in the newly created thread. */ - _draw_mutex = ThreadMutex::New(); - _draw_thread_initialized = CreateEvent(NULL, FALSE, FALSE, NULL); - if (_draw_mutex == NULL || _draw_thread_initialized == NULL) { + try { + _draw_signal = new std::condition_variable_any(); + _draw_mutex = new std::recursive_mutex(); + } catch (...) { _draw_threaded = false; - } else { + } + + if (_draw_threaded) { + draw_lock = std::unique_lock(*_draw_mutex); + _draw_continue = true; _draw_threaded = ThreadObject::New(&PaintWindowThread, NULL, &_draw_thread, "ottd:draw-win32"); /* Free the mutex if we won't be able to use it. */ if (!_draw_threaded) { + draw_lock.unlock(); + draw_lock.release(); delete _draw_mutex; + delete _draw_signal; _draw_mutex = NULL; - CloseHandle(_draw_thread_initialized); - _draw_thread_initialized = NULL; + _draw_signal = NULL; } else { DEBUG(driver, 1, "Threaded drawing enabled"); /* Wait till the draw thread has started itself. */ - WaitForSingleObject(_draw_thread_initialized, INFINITE); - _draw_mutex->BeginCritical(); + _draw_signal->wait(*_draw_mutex); } } } @@ -1227,7 +1236,7 @@ void VideoDriver_Win32::MainLoop() if (EditBoxInGlobalFocus()) TranslateMessage(&mesg); DispatchMessage(&mesg); } - if (_exit_game) return; + if (_exit_game) break; #if defined(_DEBUG) if (_wnd.has_focus && GetAsyncKeyState(VK_SHIFT) < 0 && @@ -1270,9 +1279,9 @@ void VideoDriver_Win32::MainLoop() /* The game loop is the part that can run asynchronously. * The rest except sleeping can't. */ - if (_draw_threaded) _draw_mutex->EndCritical(); + if (_draw_threaded) draw_lock.unlock(); GameLoop(); - if (_draw_threaded) _draw_mutex->BeginCritical(); + if (_draw_threaded) draw_lock.lock(); if (_force_full_redraw) MarkWholeScreenDirty(); @@ -1283,9 +1292,9 @@ void VideoDriver_Win32::MainLoop() GdiFlush(); /* Release the thread while sleeping */ - if (_draw_threaded) _draw_mutex->EndCritical(); + if (_draw_threaded) draw_lock.unlock(); Sleep(1); - if (_draw_threaded) _draw_mutex->BeginCritical(); + if (_draw_threaded) draw_lock.lock(); NetworkDrawChatMessage(); DrawMouseCursor(); @@ -1296,35 +1305,38 @@ void VideoDriver_Win32::MainLoop() _draw_continue = false; /* Sending signal if there is no thread blocked * is very valid and results in noop */ - _draw_mutex->SendSignal(); - _draw_mutex->EndCritical(); + _draw_signal->notify_all(); + if (draw_lock.owns_lock()) draw_lock.unlock(); + draw_lock.release(); _draw_thread->Join(); - CloseHandle(_draw_thread_initialized); delete _draw_mutex; + delete _draw_signal; delete _draw_thread; + + _draw_mutex = NULL; } } bool VideoDriver_Win32::ChangeResolution(int w, int h) { - if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); + std::unique_lock lock; + if (_draw_mutex != NULL) lock = std::unique_lock(*_draw_mutex); + if (_window_maximize) ShowWindow(_wnd.main_wnd, SW_SHOWNORMAL); _wnd.width = _wnd.width_org = w; _wnd.height = _wnd.height_org = h; - bool ret = this->MakeWindow(_fullscreen); // _wnd.fullscreen screws up ingame resolution switching - if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); - return ret; + return this->MakeWindow(_fullscreen); // _wnd.fullscreen screws up ingame resolution switching } bool VideoDriver_Win32::ToggleFullscreen(bool full_screen) { - if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); - bool ret = this->MakeWindow(full_screen); - if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); - return ret; + std::unique_lock lock; + if (_draw_mutex != NULL) lock = std::unique_lock(*_draw_mutex); + + return this->MakeWindow(full_screen); } bool VideoDriver_Win32::AfterBlitterChange() @@ -1334,19 +1346,20 @@ bool VideoDriver_Win32::AfterBlitterChange() void VideoDriver_Win32::AcquireBlitterLock() { - if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); + if (_draw_mutex != NULL) _draw_mutex->lock(); } void VideoDriver_Win32::ReleaseBlitterLock() { - if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); + if (_draw_mutex != NULL) _draw_mutex->unlock(); } void VideoDriver_Win32::EditBoxLostFocus() { - if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true); + std::unique_lock lock; + if (_draw_mutex != NULL) lock = std::unique_lock(*_draw_mutex); + CancelIMEComposition(_wnd.main_wnd); SetCompositionPos(_wnd.main_wnd); SetCandidatePos(_wnd.main_wnd); - if (_draw_mutex != NULL) _draw_mutex->EndCritical(true); }