summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichael Lutz <michi@icosahedron.de>2019-03-11 00:45:39 +0100
committerMichael Lutz <michi@icosahedron.de>2019-04-06 11:27:39 +0200
commit05f4e7360886e36b221ef5c3af4426625a3de686 (patch)
tree27aed9756e80eca86ff95f5805901a80048b0fb1
parent3b86f54fc739510277f434c68e17a93ab6448ed4 (diff)
downloadopenttd-05f4e7360886e36b221ef5c3af4426625a3de686.tar.xz
Codechange: Replace custom mutex code with C++11 mutex'es.
A conforming compiler with a valid <mutex>-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.
-rw-r--r--src/core/smallstack_type.hpp17
-rw-r--r--src/genworld.cpp21
-rw-r--r--src/genworld_gui.cpp8
-rw-r--r--src/gfx.cpp8
-rw-r--r--src/music/dmusic.cpp10
-rw-r--r--src/network/network_gamelist.cpp10
-rw-r--r--src/network/network_server.cpp36
-rw-r--r--src/network/network_udp.cpp23
-rw-r--r--src/newgrf_config.cpp28
-rw-r--r--src/openttd.cpp14
-rw-r--r--src/progress.cpp8
-rw-r--r--src/progress.h16
-rw-r--r--src/thread/thread.h67
-rw-r--r--src/thread/thread_none.cpp5
-rw-r--r--src/thread/thread_os2.cpp56
-rw-r--r--src/thread/thread_pthread.cpp81
-rw-r--r--src/thread/thread_win32.cpp56
-rw-r--r--src/video/sdl_v.cpp62
-rw-r--r--src/video/win32_v.cpp87
19 files changed, 187 insertions, 426 deletions
diff --git a/src/core/smallstack_type.hpp b/src/core/smallstack_type.hpp
index c273fdec4..6aded5a75 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 <mutex>
/**
* A simplified pool which stores values instead of pointers and doesn't
@@ -23,15 +23,14 @@
template<typename Titem, typename Tindex, Tindex Tgrowth_step, Tindex Tmax_size>
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<SimplePoolPoolItem> data;
};
@@ -196,7 +195,7 @@ public:
inline void Push(const Titem &item)
{
if (this->value != Tinvalid) {
- ThreadMutexLocker lock(SmallStack::GetPool().GetMutex());
+ std::lock_guard<std::mutex> 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<std::mutex> 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<std::mutex> lock(SmallStack::GetPool().GetMutex());
const SmallStack *in_list = this;
do {
in_list = static_cast<const SmallStack *>(
@@ -282,7 +281,7 @@ protected:
inline void Branch()
{
if (this->next != Tmax_size) {
- ThreadMutexLocker lock(SmallStack::GetPool().GetMutex());
+ std::lock_guard<std::mutex> lock(SmallStack::GetPool().GetMutex());
++(SmallStack::GetPool().Get(this->next).branch_count);
}
}
diff --git a/src/genworld.cpp b/src/genworld.cpp
index 25d6a7bd9..64caf3b89 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<CompanyByte> _cur_company(_current_company, OWNER_NONE, FILE_LINE);
+ std::unique_lock<std::mutex> 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 d4aad6221..697ce382d 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 72d3fcd67..b7e31a384 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 241ab191b..4b9a22c72 100644
--- a/src/music/dmusic.cpp
+++ b/src/music/dmusic.cpp
@@ -30,6 +30,7 @@
#include <dmksctrl.h>
#include <dmusicc.h>
#include <algorithm>
+#include <mutex>
#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<std::mutex> 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<std::mutex> 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 6c65c52c9..c67fba5ec 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 <mutex>
#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<std::mutex> 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<std::mutex> 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 1bcd7ca12..97da64bd3 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 <mutex>
+#include <condition_variable>
#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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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 2d7ee2d3c..df8c59aac 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 <mutex>
#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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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<std::mutex> 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 e346a4a82..feb23648a 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<std::mutex> 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<std::mutex> 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 29319236a..180de64b0 100644
--- a/src/openttd.cpp
+++ b/src/openttd.cpp
@@ -68,6 +68,7 @@
#include "linkgraph/linkgraphschedule.h"
#include <stdarg.h>
+#include <system_error>
#include "safeguards.h"
@@ -547,6 +548,9 @@ int openttd_main(int argc, char *argv[])
extern bool _dedicated_forks;
_dedicated_forks = false;
+ std::unique_lock<std::mutex> modal_work_lock(_modal_progress_work_mutex, std::defer_lock);
+ std::unique_lock<std::mutex> 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 b498be109..923f1ef83 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 eec369b23..2a9d73b03 100644
--- a/src/progress.h
+++ b/src/progress.h
@@ -12,7 +12,7 @@
#ifndef PROGRESS_H
#define PROGRESS_H
-#include "thread/thread.h"
+#include <mutex>
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 07831bb4b..eca825e25 100644
--- a/src/thread/thread.h
+++ b/src/thread/thread.h
@@ -51,73 +51,6 @@ public:
};
/**
- * 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 91eb50b11..83ae52d46 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 976283f23..72ee080d6 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 afb259183..50fefb531 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 506faa069..fc7a85a91 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 62bbb3301..b1609f7b3 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 <SDL.h>
+#include <mutex>
+#include <condition_variable>
#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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex>(*_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<std::recursive_mutex> lock;
+ if (_draw_mutex != NULL) lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
+
+ return CreateMainSurface(w, h);
}
bool VideoDriver_SDL::ToggleFullscreen(bool fullscreen)
{
- if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true);
+ std::unique_lock<std::recursive_mutex> lock;
+ if (_draw_mutex != NULL) lock = std::unique_lock<std::recursive_mutex>(*_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 6cee4fef2..ef7bc89e2 100644
--- a/src/video/win32_v.cpp
+++ b/src/video/win32_v.cpp
@@ -27,6 +27,8 @@
#include "win32_v.h"
#include <windows.h>
#include <imm.h>
+#include <mutex>
+#include <condition_variable>
#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<std::recursive_mutex> 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<std::recursive_mutex> 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<std::recursive_mutex>(*_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<std::recursive_mutex> lock;
+ if (_draw_mutex != NULL) lock = std::unique_lock<std::recursive_mutex>(*_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<std::recursive_mutex> lock;
+ if (_draw_mutex != NULL) lock = std::unique_lock<std::recursive_mutex>(*_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<std::recursive_mutex> lock;
+ if (_draw_mutex != NULL) lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
+
CancelIMEComposition(_wnd.main_wnd);
SetCompositionPos(_wnd.main_wnd);
SetCandidatePos(_wnd.main_wnd);
- if (_draw_mutex != NULL) _draw_mutex->EndCritical(true);
}