mirror of https://github.com/OpenTTD/OpenTTD.git
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.
This commit is contained in:
parent
3b86f54fc7
commit
05f4e73608
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -28,8 +28,3 @@ public:
|
|||
virtual void WaitForSignal() {}
|
||||
virtual void SendSignal() {}
|
||||
};
|
||||
|
||||
/* static */ ThreadMutex *ThreadMutex::New()
|
||||
{
|
||||
return new ThreadMutex_None();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue