Changeset - r23586:11b470d4cee6
[Not reviewed]
master
0 19 0
Michael Lutz - 5 years ago 2019-03-10 23:45:39
michi@icosahedron.de
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.
19 files changed with 187 insertions and 426 deletions:
0 comments (0 inline, 0 general)
src/core/smallstack_type.hpp
Show inline comments
 
@@ -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);
 
		}
 
	}
src/genworld.cpp
Show inline comments
 
@@ -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, ui
 
		_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;
 
	}
 

	
src/genworld_gui.cpp
Show inline comments
 
@@ -1321,10 +1321,10 @@ static void _SetGeneratingWorldProgress(
 
	 * 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;
 
}
src/gfx.cpp
Show inline comments
 
@@ -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
src/music/dmusic.cpp
Show inline comments
 
@@ -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 = NU
 
/** 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(co
 
	/* 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;
 

	
src/network/network_gamelist.cpp
Show inline comments
 
@@ -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_de
 
 */
 
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 NetworkGameListHandleDelayed
 
		}
 
		free(ins_item);
 
	}
 
	_network_game_list_mutex->EndCritical();
 
}
 

	
 
/**
src/network/network_server.cpp
Show inline comments
 
@@ -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();
 
	}
 
};
 

	
src/network/network_udp.cpp
Show inline comments
 
@@ -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(Networ
 
	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 NetworkUDPRemoveAdvertiseThr
 
	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(vo
 
	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();
 
}
src/newgrf_config.cpp
Show inline comments
 
@@ -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 
 

	
 
	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 * c
 
 */
 
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 
 
	/* 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);
 
	}
src/openttd.cpp
Show inline comments
 
@@ -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();
src/progress.cpp
Show inline comments
 
@@ -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.
src/progress.h
Show inline comments
 
@@ -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 */
src/thread/thread.h
Show inline comments
 
@@ -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.
 
 */
src/thread/thread_none.cpp
Show inline comments
 
@@ -28,8 +28,3 @@ public:
 
	virtual void WaitForSignal() {}
 
	virtual void SendSignal() {}
 
};
 

	
 
/* static */ ThreadMutex *ThreadMutex::New()
 
{
 
	return new ThreadMutex_None();
 
}
src/thread/thread_os2.cpp
Show inline comments
 
@@ -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();
 
}
src/thread/thread_pthread.cpp
Show inline comments
 
@@ -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();
 
}
src/thread/thread_win32.cpp
Show inline comments
 
@@ -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();
 
}
src/video/sdl_v.cpp
Show inline comments
 
@@ -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(b
 
		_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 */
src/video/win32_v.cpp
Show inline comments
 
@@ -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 
 

	
 
				/* 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::AfterBlitterChan
 

	
 
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);
 
}
0 comments (0 inline, 0 general)