diff --git a/Makefile.src.in b/Makefile.src.in
index 01c298d9ba..dc3a5f48b3 100644
--- a/Makefile.src.in
+++ b/Makefile.src.in
@@ -143,7 +143,7 @@ $(OBJS_CPP:%.o=%.d): %.d: $(SRC_DIR)/%.cpp $(FILE_DEP)
$(OBJS_MM:%.o=%.d): %.d: $(SRC_DIR)/%.mm $(FILE_DEP)
$(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.mm=%.mm)'
- $(Q)$(CC_HOST) $(CFLAGS) -MM $< | sed 's@^$(@F:%.d=%.o):@$@ $(@:%.d=%.o):@' > $@
+ $(Q)$(CXX_HOST) $(CFLAGS) $(CXXFLAGS) -MM $< | sed 's@^$(@F:%.d=%.o):@$@ $(@:%.d=%.o):@' > $@
$(OBJS_RC:%.o=%.d): %.d: $(SRC_DIR)/%.rc $(FILE_DEP)
$(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.rc=%.rc)'
@@ -253,7 +253,7 @@ $(filter %sse4.o, $(OBJS_CPP)): %.o: $(SRC_DIR)/%.cpp $(DEP_MASK) $(FILE_DEP)
$(OBJS_MM): %.o: $(SRC_DIR)/%.mm $(DEP_MASK) $(FILE_DEP)
$(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.mm=%.mm)'
- $(Q)$(CC_HOST) $(CFLAGS) -c -o $@ $<
+ $(Q)$(CXX_HOST) $(CFLAGS) $(CXXFLAGS) -c -o $@ $<
$(OBJS_RC): %.o: $(SRC_DIR)/%.rc $(FILE_DEP)
$(E) '$(STAGE) Compiling resource $(<:$(SRC_DIR)/%.rc=%.rc)'
@@ -277,7 +277,7 @@ endif
# Revision files
-$(SRC_DIR)/rev.cpp: $(CONFIG_CACHE_VERSION) $(SRC_DIR)/rev.cpp.in
+$(SRC_DIR)/rev.cpp: $(CONFIG_CACHE_VERSION) $(CONFIG_CACHE_INVOCATION) $(SRC_DIR)/rev.cpp.in
$(Q)cat $(SRC_DIR)/rev.cpp.in | sed "s@\!\!ISODATE\!\!@$(ISODATE)@g;s@!!VERSION!!@$(VERSION)@g;s@!!MODIFIED!!@$(MODIFIED)@g;s@!!DATE!!@`date +%d.%m.%y`@g;s@!!GITHASH!!@$(GITHASH)@g;s@!!ISTAG!!@$(ISTAG)@g;s@!!ISSTABLETAG!!@$(ISSTABLETAG)@g;s@\!\!CONFIGURE_INVOCATION\!\!@$(CONFIGURE_INVOCATION)@g;" > $(SRC_DIR)/rev.cpp
$(SRC_DIR)/os/windows/ottdres.rc: $(CONFIG_CACHE_VERSION) $(SRC_DIR)/os/windows/ottdres.rc.in
diff --git a/projects/generate_vs142.vcxproj b/projects/generate_vs142.vcxproj
index 3e55d7a1d4..7230676cb5 100644
--- a/projects/generate_vs142.vcxproj
+++ b/projects/generate_vs142.vcxproj
@@ -10,7 +10,6 @@
generate
{2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}
generate
- 8.1
diff --git a/projects/openttd_vs140.vcxproj b/projects/openttd_vs140.vcxproj
index 95611a60a5..58f9ac3967 100644
--- a/projects/openttd_vs140.vcxproj
+++ b/projects/openttd_vs140.vcxproj
@@ -1389,8 +1389,7 @@
-
-
+
diff --git a/projects/openttd_vs140.vcxproj.filters b/projects/openttd_vs140.vcxproj.filters
index 67311daee0..fa42454573 100644
--- a/projects/openttd_vs140.vcxproj.filters
+++ b/projects/openttd_vs140.vcxproj.filters
@@ -3258,12 +3258,9 @@
Windows files
-
+
Threading
-
- Threading
-
Threading
diff --git a/projects/openttd_vs141.vcxproj b/projects/openttd_vs141.vcxproj
index 3d3c92b2d0..bd6ed6a3c8 100644
--- a/projects/openttd_vs141.vcxproj
+++ b/projects/openttd_vs141.vcxproj
@@ -1389,8 +1389,7 @@
-
-
+
diff --git a/projects/openttd_vs141.vcxproj.filters b/projects/openttd_vs141.vcxproj.filters
index 67311daee0..fa42454573 100644
--- a/projects/openttd_vs141.vcxproj.filters
+++ b/projects/openttd_vs141.vcxproj.filters
@@ -3258,12 +3258,9 @@
Windows files
-
+
Threading
-
- Threading
-
Threading
diff --git a/projects/openttd_vs142.vcxproj b/projects/openttd_vs142.vcxproj
index 89dd51ee6b..7293e5eb4c 100644
--- a/projects/openttd_vs142.vcxproj
+++ b/projects/openttd_vs142.vcxproj
@@ -1389,8 +1389,7 @@
-
-
+
diff --git a/projects/openttd_vs142.vcxproj.filters b/projects/openttd_vs142.vcxproj.filters
index 67311daee0..fa42454573 100644
--- a/projects/openttd_vs142.vcxproj.filters
+++ b/projects/openttd_vs142.vcxproj.filters
@@ -3258,12 +3258,9 @@
Windows files
-
+
Threading
-
- Threading
-
Threading
diff --git a/projects/settingsgen_vs142.vcxproj b/projects/settingsgen_vs142.vcxproj
index ca0418c15c..23a4e18562 100644
--- a/projects/settingsgen_vs142.vcxproj
+++ b/projects/settingsgen_vs142.vcxproj
@@ -10,7 +10,6 @@
settingsgen
{E9548DE9-F089-49B7-93A6-30BE2CC311C7}
settings
- 8.1
diff --git a/projects/strgen_vs142.vcxproj b/projects/strgen_vs142.vcxproj
index 5329d68daa..eb0657a30b 100644
--- a/projects/strgen_vs142.vcxproj
+++ b/projects/strgen_vs142.vcxproj
@@ -10,7 +10,6 @@
strgen
{A133A442-BD0A-4ADE-B117-AD7545E4BDD1}
strgen
- 8.1
diff --git a/source.list b/source.list
index 93d9ef6a07..b597abab24 100644
--- a/source.list
+++ b/source.list
@@ -1229,20 +1229,7 @@ sound/null_s.cpp
#end
# Threading
-thread/thread.h
-#if USE_THREADS
- #if WIN32
- thread/thread_win32.cpp
- #else
- #if OS2
- thread/thread_os2.cpp
- #else
- thread/thread_pthread.cpp
- #end
- #end
-#else
- thread/thread_none.cpp
-#end
+thread.h
tracerestrict.h
tracerestrict.cpp
diff --git a/src/ai/ai_gui.cpp b/src/ai/ai_gui.cpp
index 8b00de988e..2730070c32 100644
--- a/src/ai/ai_gui.cpp
+++ b/src/ai/ai_gui.cpp
@@ -1282,7 +1282,7 @@ struct AIDebugWindow : public Window {
case WID_AID_RELOAD_TOGGLE:
if (ai_debug_company == OWNER_DEITY) break;
/* First kill the company of the AI, then start a new one. This should start the current AI again */
- DoCommandP(0, CCA_DELETE | ai_debug_company << 16, CRR_MANUAL, CMD_COMPANY_CTRL);
+ DoCommandP(0, CCA_DELETE | ai_debug_company << 16 | CRR_MANUAL << 24, 0, CMD_COMPANY_CTRL);
DoCommandP(0, CCA_NEW_AI | ai_debug_company << 16, 0, CMD_COMPANY_CTRL);
break;
diff --git a/src/company_cmd.cpp b/src/company_cmd.cpp
index 432a4fc69d..f75685a2bd 100644
--- a/src/company_cmd.cpp
+++ b/src/company_cmd.cpp
@@ -815,10 +815,9 @@ void CompanyAdminRemove(CompanyID company_id, CompanyRemoveReason reason)
* @param flags operation to perform
* @param p1 various functionality
* - bits 0..15: CompanyCtrlAction
- * - bits 16..24: CompanyID
- * @param p2 various depending on CompanyCtrlAction
- * - bits 0..31: ClientID (with CCA_NEW)
- * - bits 0..1: CompanyRemoveReason (with CCA_DELETE)
+ * - bits 16..23: CompanyID
+ * - bits 24..31: CompanyRemoveReason (with CCA_DELETE)
+ * @param p2 ClientID
* @param text unused
* @return the cost of this operation or an error
*/
@@ -888,7 +887,7 @@ CommandCost CmdCompanyCtrl(TileIndex tile, DoCommandFlag flags, uint32 p1, uint3
}
case CCA_DELETE: { // Delete a company
- CompanyRemoveReason reason = (CompanyRemoveReason)GB(p2, 0, 2);
+ CompanyRemoveReason reason = (CompanyRemoveReason)GB(p1, 24, 8);
if (reason >= CRR_END) return CMD_ERROR;
Company *c = Company::GetIfValid(company_id);
diff --git a/src/console_cmds.cpp b/src/console_cmds.cpp
index 9ba7fdf29b..31c84d85e3 100644
--- a/src/console_cmds.cpp
+++ b/src/console_cmds.cpp
@@ -828,7 +828,7 @@ DEF_CONSOLE_CMD(ConResetCompany)
}
/* It is safe to remove this company */
- DoCommandP(0, CCA_DELETE | index << 16, CRR_MANUAL, CMD_COMPANY_CTRL);
+ DoCommandP(0, CCA_DELETE | index << 16 | CRR_MANUAL << 24, 0, CMD_COMPANY_CTRL);
IConsolePrint(CC_DEFAULT, "Company deleted.");
return true;
@@ -1203,7 +1203,7 @@ DEF_CONSOLE_CMD(ConReloadAI)
}
/* First kill the company of the AI, then start a new one. This should start the current AI again */
- DoCommandP(0, CCA_DELETE | company_id << 16, CRR_MANUAL, CMD_COMPANY_CTRL);
+ DoCommandP(0, CCA_DELETE | company_id << 16 | CRR_MANUAL << 24, 0,CMD_COMPANY_CTRL);
DoCommandP(0, CCA_NEW_AI | company_id << 16, 0, CMD_COMPANY_CTRL);
IConsolePrint(CC_DEFAULT, "AI reloaded.");
@@ -1240,7 +1240,7 @@ DEF_CONSOLE_CMD(ConStopAI)
}
/* Now kill the company of the AI. */
- DoCommandP(0, CCA_DELETE | company_id << 16, CRR_MANUAL, CMD_COMPANY_CTRL);
+ DoCommandP(0, CCA_DELETE | company_id << 16 | CRR_MANUAL << 24, 0, CMD_COMPANY_CTRL);
IConsolePrint(CC_DEFAULT, "AI stopped, company deleted.");
return true;
diff --git a/src/crashlog.cpp b/src/crashlog.cpp
index 379c8bd9e1..ea7cea70cb 100644
--- a/src/crashlog.cpp
+++ b/src/crashlog.cpp
@@ -31,7 +31,7 @@
#include "news_gui.h"
#include "scope_info.h"
#include "command_func.h"
-#include "thread/thread.h"
+#include "thread.h"
#include "ai/ai_info.hpp"
#include "game/game.hpp"
@@ -394,7 +394,7 @@ char *CrashLog::FillCrashLog(char *buffer, const char *last) const
if (IsNonMainThread()) {
buffer += seprintf(buffer, last, "Non-main thread (");
- buffer += GetThreadName(buffer, last);
+ buffer += GetCurrentThreadName(buffer, last);
buffer += seprintf(buffer, last, ")\n\n");
}
diff --git a/src/economy.cpp b/src/economy.cpp
index 49e0a48c16..4c11507854 100644
--- a/src/economy.cpp
+++ b/src/economy.cpp
@@ -672,7 +672,7 @@ static void CompanyCheckBankrupt(Company *c)
* that changing the current company is okay. In case of single
* player we are sure (the above check) that we are not the local
* company and thus we won't be moved. */
- if (!_networking || _network_server) DoCommandP(0, CCA_DELETE | (c->index << 16), CRR_BANKRUPT, CMD_COMPANY_CTRL);
+ if (!_networking || _network_server) DoCommandP(0, CCA_DELETE | (c->index << 16) | (CRR_BANKRUPT << 24), 0, CMD_COMPANY_CTRL);
break;
}
}
diff --git a/src/genworld.cpp b/src/genworld.cpp
index ed56a7034e..9bb2c75397 100644
--- a/src/genworld.cpp
+++ b/src/genworld.cpp
@@ -34,6 +34,7 @@
#include "game/game.hpp"
#include "game/game_instance.hpp"
#include "string_func.h"
+#include "thread.h"
#include "safeguards.h"
@@ -93,14 +94,15 @@ static void CleanupGeneration()
/**
* The internal, real, generate function.
*/
-static void _GenerateWorld(void *)
+static void _GenerateWorld()
{
/* Make sure everything is done via OWNER_NONE. */
Backup _cur_company(_current_company, OWNER_NONE, FILE_LINE);
+ std::unique_lock lock(_modal_progress_work_mutex, std::defer_lock);
try {
_generating_world = true;
- _modal_progress_work_mutex->BeginCritical();
+ lock.lock();
if (_network_dedicated) DEBUG(net, 1, "Generating map, please wait...");
/* Set the Random() seed to generation_seed so we produce the same map with the same seed */
if (_settings_game.game_creation.generation_seed == GENERATE_NEW_SEED) _settings_game.game_creation.generation_seed = _settings_newgame.game_creation.generation_seed = InteractiveRandom();
@@ -199,7 +201,7 @@ static void _GenerateWorld(void *)
IncreaseGeneratingWorldProgress(GWP_GAME_START);
CleanupGeneration();
- _modal_progress_work_mutex->EndCritical();
+ lock.unlock();
ShowNewGRFError();
@@ -215,7 +217,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;
}
}
@@ -246,17 +247,15 @@ void GenerateWorldSetAbortCallback(GWAbortProc *proc)
*/
void WaitTillGeneratedWorld()
{
- if (_gw.thread == NULL) return;
+ if (!_gw.thread.joinable()) 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.thread.join();
_gw.threaded = false;
- _modal_progress_work_mutex->BeginCritical();
- _modal_progress_paint_mutex->BeginCritical();
+ _modal_progress_work_mutex.lock();
+ _modal_progress_paint_mutex.lock();
}
/**
@@ -288,7 +287,7 @@ void HandleGeneratingWorldAbortion()
CleanupGeneration();
- if (_gw.thread != NULL) _gw.thread->Exit();
+ if (_gw.thread.joinable() && _gw.thread.get_id() == std::this_thread::get_id()) throw OTTDThreadExitSignal();
SwitchToMode(_switch_mode);
}
@@ -330,18 +329,14 @@ void GenerateWorld(GenWorldMode mode, uint size_x, uint size_y, bool reset_setti
SetupColoursAndInitialWindow();
SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0);
- if (_gw.thread != NULL) {
- _gw.thread->Join();
- delete _gw.thread;
- _gw.thread = NULL;
- }
+ if (_gw.thread.joinable()) _gw.thread.join();
- if (!VideoDriver::GetInstance()->HasGUI() || !ThreadObject::New(&_GenerateWorld, NULL, &_gw.thread, "ottd:genworld")) {
+ if (!UseThreadedModelProgress() || !VideoDriver::GetInstance()->HasGUI() || !StartNewThread(&_gw.thread, "ottd:genworld", &_GenerateWorld)) {
DEBUG(misc, 1, "Cannot create genworld thread, reverting to single-threaded mode");
_gw.threaded = false;
- _modal_progress_work_mutex->EndCritical();
- _GenerateWorld(NULL);
- _modal_progress_work_mutex->BeginCritical();
+ _modal_progress_work_mutex.unlock();
+ _GenerateWorld();
+ _modal_progress_work_mutex.lock();
return;
}
diff --git a/src/genworld.h b/src/genworld.h
index 1b1c806e09..ce6b39bd99 100644
--- a/src/genworld.h
+++ b/src/genworld.h
@@ -13,6 +13,7 @@
#define GENWORLD_H
#include "company_type.h"
+#include
/** Constants related to world generation */
enum LandscapeGenerator {
@@ -61,7 +62,7 @@ struct GenWorldInfo {
uint size_y; ///< Y-size of the map
GWDoneProc *proc; ///< Proc that is called when done (can be NULL)
GWAbortProc *abortp; ///< Proc that is called when aborting (can be NULL)
- class ThreadObject *thread; ///< The thread we are in (can be NULL)
+ std::thread thread; ///< The thread we are in (joinable if a thread was created)
};
/** Current stage of world generation process */
diff --git a/src/genworld_gui.cpp b/src/genworld_gui.cpp
index e10d68e86f..691a464ed4 100644
--- a/src/genworld_gui.cpp
+++ b/src/genworld_gui.cpp
@@ -1377,10 +1377,10 @@ static void _SetGeneratingWorldProgress(GenWorldProgress cls, uint progress, uin
* paint thread. The 'other' thread already has the paint thread rights so
* this ensures us that we are waiting until the paint thread is done
* before we reacquire the mapgen rights */
- _modal_progress_work_mutex->EndCritical();
- _modal_progress_paint_mutex->BeginCritical();
- _modal_progress_work_mutex->BeginCritical();
- _modal_progress_paint_mutex->EndCritical();
+ _modal_progress_work_mutex.unlock();
+ _modal_progress_paint_mutex.lock();
+ _modal_progress_work_mutex.lock();
+ _modal_progress_paint_mutex.unlock();
_gws.timer = _realtime_tick;
}
diff --git a/src/gfx.cpp b/src/gfx.cpp
index b83683cd0c..39cd93844c 100644
--- a/src/gfx.cpp
+++ b/src/gfx.cpp
@@ -21,6 +21,7 @@
#include "network/network_func.h"
#include "window_func.h"
#include "newgrf_debug.h"
+#include "thread.h"
#include "table/palettes.h"
#include "table/string_colours.h"
@@ -1311,8 +1312,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);
@@ -1320,9 +1321,9 @@ void DrawDirtyBlocks()
/* Modal progress thread may need blitter access while we are waiting for it. */
VideoDriver::GetInstance()->ReleaseBlitterLock();
- _modal_progress_paint_mutex->BeginCritical();
+ _modal_progress_paint_mutex.lock();
VideoDriver::GetInstance()->AcquireBlitterLock();
- _modal_progress_work_mutex->BeginCritical();
+ _modal_progress_work_mutex.lock();
/* When we ended with the modal progress, do not draw the blocks.
* Simply let the next run do so, otherwise we would be loading
diff --git a/src/gfx_func.h b/src/gfx_func.h
index 7a0c02c146..4a037d24c0 100644
--- a/src/gfx_func.h
+++ b/src/gfx_func.h
@@ -75,7 +75,6 @@ void HandleKeypress(uint keycode, WChar key);
void HandleTextInput(const char *str, bool marked = false, const char *caret = NULL, const char *insert_location = NULL, const char *replacement_end = NULL);
void HandleCtrlChanged();
void HandleMouseEvents();
-void CSleep(int milliseconds);
void UpdateWindows();
void DrawMouseCursor();
diff --git a/src/linkgraph/linkgraphjob.h b/src/linkgraph/linkgraphjob.h
index 0849f63cf2..59b48801f3 100644
--- a/src/linkgraph/linkgraphjob.h
+++ b/src/linkgraph/linkgraphjob.h
@@ -12,7 +12,7 @@
#ifndef LINKGRAPHJOB_H
#define LINKGRAPHJOB_H
-#include "../thread/thread.h"
+#include "../thread.h"
#include "../core/dyn_arena_alloc.hpp"
#include "linkgraph.h"
#include
diff --git a/src/linkgraph/linkgraphschedule.cpp b/src/linkgraph/linkgraphschedule.cpp
index 0be9c54278..63a87484f6 100644
--- a/src/linkgraph/linkgraphschedule.cpp
+++ b/src/linkgraph/linkgraphschedule.cpp
@@ -142,13 +142,11 @@ void LinkGraphSchedule::JoinNext()
}
/**
- * Run all handlers for the given Job. This method is tailored to
- * ThreadObject::New.
- * @param j Pointer to a link graph job.
+ * Run all handlers for the given Job.
+ * @param job Pointer to a link graph job.
*/
-/* static */ void LinkGraphSchedule::Run(void *j)
+/* static */ void LinkGraphSchedule::Run(LinkGraphJob *job)
{
- LinkGraphJob *job = (LinkGraphJob *)j;
for (uint i = 0; i < lengthof(instance.handlers); ++i) {
if (job->IsJobAborted()) return;
instance.handlers[i]->Run(*job);
@@ -232,20 +230,17 @@ LinkGraphSchedule::~LinkGraphSchedule()
LinkGraphJobGroup::LinkGraphJobGroup(constructor_token token, std::vector jobs) :
jobs(std::move(jobs)) { }
-void LinkGraphJobGroup::SpawnThread() {
- ThreadObject *t = nullptr;
-
+void LinkGraphJobGroup::SpawnThread()
+{
/**
* Spawn a thread if possible and run the link graph job in the thread. If
* that's not possible run the job right now in the current thread.
*/
- if (ThreadObject::New(&(LinkGraphJobGroup::Run), this, &t, "ottd:linkgraph")) {
- this->thread.reset(t);
+ if (StartNewThread(&this->thread, "ottd:linkgraph", &(LinkGraphJobGroup::Run), this)) {
for (auto &it : this->jobs) {
it->SetJobGroup(this->shared_from_this());
}
} else {
- this->thread.reset();
/* Of course this will hang a bit.
* On the other hand, if you want to play games which make this hang noticably
* on a platform without threads then you'll probably get other problems first.
@@ -257,10 +252,11 @@ void LinkGraphJobGroup::SpawnThread() {
}
}
-void LinkGraphJobGroup::JoinThread() {
- if (!this->thread || this->joined_thread) return;
- this->thread->Join();
- this->joined_thread = true;
+void LinkGraphJobGroup::JoinThread()
+{
+ if (this->thread.joinable()) {
+ this->thread.join();
+ }
}
/**
diff --git a/src/linkgraph/linkgraphschedule.h b/src/linkgraph/linkgraphschedule.h
index cebd974893..ab2ac201af 100644
--- a/src/linkgraph/linkgraphschedule.h
+++ b/src/linkgraph/linkgraphschedule.h
@@ -12,7 +12,7 @@
#ifndef LINKGRAPHSCHEDULE_H
#define LINKGRAPHSCHEDULE_H
-#include "../thread/thread.h"
+#include "../thread.h"
#include "linkgraph.h"
#include
@@ -55,7 +55,7 @@ public:
static const uint SPAWN_JOIN_TICK = 21; ///< Tick when jobs are spawned or joined every day.
static LinkGraphSchedule instance;
- static void Run(void *j);
+ static void Run(LinkGraphJob *job);
static void Clear();
void SpawnNext();
@@ -85,8 +85,7 @@ class LinkGraphJobGroup : public std::enable_shared_from_this
friend LinkGraphJob;
private:
- bool joined_thread = false; ///< True if thread has already been joined
- std::unique_ptr thread; ///< Thread the job group is running in or NULL if it's running in the main thread.
+ std::thread thread; ///< Thread the job group is running in or NULL if it's running in the main thread.
const std::vector jobs; ///< The set of jobs in this job set
private:
diff --git a/src/music/dmusic.cpp b/src/music/dmusic.cpp
index 241ab191bf..bf8657ef45 100644
--- a/src/music/dmusic.cpp
+++ b/src/music/dmusic.cpp
@@ -19,7 +19,7 @@
#include "../debug.h"
#include "../os/windows/win32.h"
#include "../core/mem_func.hpp"
-#include "../thread/thread.h"
+#include "../thread.h"
#include "../fileio_func.h"
#include "../base_media_base.h"
#include "dmusic.h"
@@ -30,6 +30,7 @@
#include
#include
#include
+#include
#include "../safeguards.h"
@@ -138,11 +139,11 @@ static struct {
} _playback;
/** Handle to our worker thread. */
-static ThreadObject *_dmusic_thread = NULL;
+static std::thread _dmusic_thread;
/** 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;
@@ -596,7 +597,7 @@ static void TransmitNotesOff(IDirectMusicBuffer *buffer, REFERENCE_TIME block_ti
Sleep(Clamp((block_time - cur_time) / MS_TO_REFTIME, 5, 1000));
}
-static void MidiThreadProc(void *)
+static void MidiThreadProc()
{
DEBUG(driver, 2, "DMusic: Entering playback thread");
@@ -655,7 +656,7 @@ static void MidiThreadProc(void *)
DEBUG(driver, 2, "DMusic thread: Starting playback");
{
/* New scope to limit the time the mutex is locked. */
- ThreadMutexLocker lock(_thread_mutex);
+ std::lock_guard lock(_thread_mutex);
current_file.MoveFrom(_playback.next_file);
std::swap(_playback.next_segment, current_segment);
@@ -1167,10 +1168,8 @@ 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";
+ if (!StartNewThread(&_dmusic_thread, "ottd:dmusic", &MidiThreadProc)) return "Can't create MIDI output thread";
return NULL;
}
@@ -1184,10 +1183,10 @@ MusicDriver_DMusic::~MusicDriver_DMusic()
void MusicDriver_DMusic::Stop()
{
- if (_dmusic_thread != NULL) {
+ if (_dmusic_thread.joinable()) {
_playback.shutdown = true;
SetEvent(_thread_event);
- _dmusic_thread->Join();
+ _dmusic_thread.join();
}
/* Unloaded any instruments we loaded. */
@@ -1223,7 +1222,6 @@ void MusicDriver_DMusic::Stop()
}
CloseHandle(_thread_event);
- delete _thread_mutex;
CoUninitialize();
}
@@ -1231,7 +1229,7 @@ void MusicDriver_DMusic::Stop()
void MusicDriver_DMusic::PlaySong(const MusicSongInfo &song)
{
- ThreadMutexLocker lock(_thread_mutex);
+ std::lock_guard lock(_thread_mutex);
if (!_playback.next_file.LoadSong(song)) return;
diff --git a/src/music/extmidi.cpp b/src/music/extmidi.cpp
index 9d07761b73..f7fc454dff 100644
--- a/src/music/extmidi.cpp
+++ b/src/music/extmidi.cpp
@@ -18,6 +18,7 @@
#include "../gfx_func.h"
#include "extmidi.h"
#include "../base_media_base.h"
+#include "../thread.h"
#include "midifile.hpp"
#include
#include
diff --git a/src/network/core/tcp.h b/src/network/core/tcp.h
index 243ec042d2..f9e1e00cbd 100644
--- a/src/network/core/tcp.h
+++ b/src/network/core/tcp.h
@@ -63,7 +63,6 @@ public:
*/
class TCPConnecter {
private:
- class ThreadObject *thread; ///< Thread used to create the TCP connection
bool connected; ///< Whether we succeeded in making the connection
bool aborted; ///< Whether we bailed out (i.e. connection making failed)
bool killed; ///< Whether we got killed
@@ -71,7 +70,7 @@ private:
void Connect();
- static void ThreadEntry(void *param);
+ static void ThreadEntry(TCPConnecter *param);
protected:
/** Address we're connecting to */
diff --git a/src/network/core/tcp_connect.cpp b/src/network/core/tcp_connect.cpp
index d76042821a..d923688b15 100644
--- a/src/network/core/tcp_connect.cpp
+++ b/src/network/core/tcp_connect.cpp
@@ -12,7 +12,7 @@
*/
#include "../../stdafx.h"
-#include "../../thread/thread.h"
+#include "../../thread.h"
#include "tcp.h"
@@ -33,7 +33,7 @@ TCPConnecter::TCPConnecter(const NetworkAddress &address) :
address(address)
{
_tcp_connecters.push_back(this);
- if (!ThreadObject::New(TCPConnecter::ThreadEntry, this, &this->thread, "ottd:tcp")) {
+ if (!StartNewThread(NULL, "ottd:tcp", &TCPConnecter::ThreadEntry, this)) {
this->Connect();
}
}
@@ -53,9 +53,9 @@ void TCPConnecter::Connect()
* Entry point for the new threads.
* @param param the TCPConnecter instance to call Connect on.
*/
-/* static */ void TCPConnecter::ThreadEntry(void *param)
+/* static */ void TCPConnecter::ThreadEntry(TCPConnecter *param)
{
- static_cast(param)->Connect();
+ param->Connect();
}
/**
diff --git a/src/network/network_client.cpp b/src/network/network_client.cpp
index 2cb588972f..6d0cc28e9e 100644
--- a/src/network/network_client.cpp
+++ b/src/network/network_client.cpp
@@ -30,6 +30,7 @@
#include "network_base.h"
#include "network_client.h"
#include "../core/backup_type.hpp"
+#include "../thread.h"
#include "table/strings.h"
diff --git a/src/network/network_gamelist.cpp b/src/network/network_gamelist.cpp
index 6c65c52c98..e9fc5f943e 100644
--- a/src/network/network_gamelist.cpp
+++ b/src/network/network_gamelist.cpp
@@ -15,19 +15,17 @@
#include "../stdafx.h"
#include "../debug.h"
#include "../window_func.h"
-#include "../thread/thread.h"
#include "network_internal.h"
#include "network_udp.h"
#include "network_gamelist.h"
+#include
#include "../safeguards.h"
NetworkGameList *_network_game_list = NULL;
-/** Mutex for handling delayed insertion/querying of servers. */
-static ThreadMutex *_network_game_list_mutex = ThreadMutex::New();
/** The games to insert when the GUI thread has time for us. */
-static NetworkGameList *_network_game_delayed_insertion_list = NULL;
+static std::atomic _network_game_delayed_insertion_list(NULL);
/**
* Add a new item to the linked gamelist, but do it delayed in the next tick
@@ -36,19 +34,17 @@ static NetworkGameList *_network_game_delayed_insertion_list = NULL;
*/
void NetworkGameListAddItemDelayed(NetworkGameList *item)
{
- _network_game_list_mutex->BeginCritical();
- item->next = _network_game_delayed_insertion_list;
- _network_game_delayed_insertion_list = item;
- _network_game_list_mutex->EndCritical();
+ item->next = _network_game_delayed_insertion_list.load(std::memory_order_relaxed);
+ while (!_network_game_delayed_insertion_list.compare_exchange_weak(item->next, item, std::memory_order_acq_rel)) {}
}
/** Perform the delayed (thread safe) insertion into the game list */
static void NetworkGameListHandleDelayedInsert()
{
- _network_game_list_mutex->BeginCritical();
- while (_network_game_delayed_insertion_list != NULL) {
- NetworkGameList *ins_item = _network_game_delayed_insertion_list;
- _network_game_delayed_insertion_list = ins_item->next;
+ while (true) {
+ NetworkGameList *ins_item = _network_game_delayed_insertion_list.load(std::memory_order_relaxed);
+ while (ins_item != NULL && !_network_game_delayed_insertion_list.compare_exchange_weak(ins_item, ins_item->next, std::memory_order_acq_rel)) {}
+ if (ins_item == NULL) break; // No item left.
NetworkGameList *item = NetworkGameListAddItem(ins_item->address);
@@ -66,7 +62,6 @@ static void NetworkGameListHandleDelayedInsert()
}
free(ins_item);
}
- _network_game_list_mutex->EndCritical();
}
/**
diff --git a/src/network/network_server.cpp b/src/network/network_server.cpp
index 194aae4a33..5091ec6b0e 100644
--- a/src/network/network_server.cpp
+++ b/src/network/network_server.cpp
@@ -30,6 +30,8 @@
#include "../core/pool_func.hpp"
#include "../core/random_func.hpp"
#include "../rev.h"
+#include
+#include
#include "../safeguards.h"
@@ -58,7 +60,8 @@ struct PacketWriter : SaveFilter {
Packet *current; ///< The packet we're currently writing to.
size_t total_size; ///< Total size of the compressed savegame.
Packet *packets; ///< Packet queue of the savegame; send these "slowly" to the client.
- ThreadMutex *mutex; ///< Mutex for making threaded saving safe.
+ std::mutex mutex; ///< Mutex for making threaded saving safe.
+ std::condition_variable exit_sig; ///< Signal for threaded destruction of this packet writer.
/**
* Create the packet writer.
@@ -66,17 +69,14 @@ struct PacketWriter : SaveFilter {
*/
PacketWriter(ServerNetworkGameSocketHandler *cs) : SaveFilter(NULL), cs(cs), current(NULL), total_size(0), packets(NULL)
{
- this->mutex = ThreadMutex::New();
}
/** Make sure everything is cleaned up. */
~PacketWriter()
{
- if (this->mutex != NULL) this->mutex->BeginCritical();
+ std::unique_lock lock(this->mutex);
- if (this->cs != NULL && this->mutex != NULL) {
- this->mutex->WaitForSignal();
- }
+ if (this->cs != NULL) this->exit_sig.wait(lock);
/* This must all wait until the Destroy function is called. */
@@ -87,11 +87,6 @@ struct PacketWriter : SaveFilter {
}
delete this->current;
-
- if (this->mutex != NULL) this->mutex->EndCritical();
-
- delete this->mutex;
- this->mutex = NULL;
}
/**
@@ -106,13 +101,12 @@ struct PacketWriter : SaveFilter {
*/
void Destroy()
{
- if (this->mutex != NULL) this->mutex->BeginCritical();
+ std::unique_lock lock(this->mutex);
this->cs = NULL;
- if (this->mutex != NULL) this->mutex->SendSignal();
-
- if (this->mutex != NULL) this->mutex->EndCritical();
+ this->exit_sig.notify_all();
+ lock.unlock();
/* Make sure the saving is completely cancelled. Yes,
* we need to handle the save finish as well as the
@@ -138,14 +132,12 @@ struct PacketWriter : SaveFilter {
*/
Packet *PopPacket()
{
- if (this->mutex != NULL) this->mutex->BeginCritical();
+ std::lock_guard lock(this->mutex);
Packet *p = this->packets;
this->packets = p->next;
p->next = NULL;
- if (this->mutex != NULL) this->mutex->EndCritical();
-
return p;
}
@@ -170,7 +162,7 @@ struct PacketWriter : SaveFilter {
if (this->current == NULL) this->current = new Packet(PACKET_SERVER_MAP_DATA);
- if (this->mutex != NULL) this->mutex->BeginCritical();
+ std::lock_guard lock(this->mutex);
byte *bufe = buf + size;
while (buf != bufe) {
@@ -185,8 +177,6 @@ struct PacketWriter : SaveFilter {
}
}
- if (this->mutex != NULL) this->mutex->EndCritical();
-
this->total_size += size;
}
@@ -195,7 +185,7 @@ struct PacketWriter : SaveFilter {
/* We want to abort the saving when the socket is closed. */
if (this->cs == NULL) SlError(STR_NETWORK_ERROR_LOSTCONNECTION);
- if (this->mutex != NULL) this->mutex->BeginCritical();
+ std::lock_guard lock(this->mutex);
/* Make sure the last packet is flushed. */
this->AppendQueue();
@@ -208,8 +198,6 @@ struct PacketWriter : SaveFilter {
Packet *p = new Packet(PACKET_SERVER_MAP_SIZE);
p->Send_uint32((uint32)this->total_size);
this->cs->NetworkTCPSocketHandler::SendPacket(p);
-
- if (this->mutex != NULL) this->mutex->EndCritical();
}
};
@@ -1681,7 +1669,7 @@ static void NetworkAutoCleanCompanies()
/* Is the company empty for autoclean_unprotected-months, and is there no protection? */
if (_settings_client.network.autoclean_unprotected != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_unprotected && StrEmpty(_network_company_states[c->index].password)) {
/* Shut the company down */
- DoCommandP(0, CCA_DELETE | c->index << 16, CRR_AUTOCLEAN, CMD_COMPANY_CTRL);
+ DoCommandP(0, CCA_DELETE | c->index << 16 | CRR_AUTOCLEAN << 24, 0, CMD_COMPANY_CTRL);
IConsolePrintF(CC_DEFAULT, "Auto-cleaned company #%d with no password", c->index + 1);
}
/* Is the company empty for autoclean_protected-months, and there is a protection? */
@@ -1695,7 +1683,7 @@ static void NetworkAutoCleanCompanies()
/* Is the company empty for autoclean_novehicles-months, and has no vehicles? */
if (_settings_client.network.autoclean_novehicles != 0 && _network_company_states[c->index].months_empty > _settings_client.network.autoclean_novehicles && vehicles_in_company[c->index] == 0) {
/* Shut the company down */
- DoCommandP(0, CCA_DELETE | c->index << 16, CRR_AUTOCLEAN, CMD_COMPANY_CTRL);
+ DoCommandP(0, CCA_DELETE | c->index << 16 | CRR_AUTOCLEAN << 24, 0, CMD_COMPANY_CTRL);
IConsolePrintF(CC_DEFAULT, "Auto-cleaned company #%d with no vehicles", c->index + 1);
}
} else {
diff --git a/src/network/network_server.h b/src/network/network_server.h
index fe98128b82..e985bd535c 100644
--- a/src/network/network_server.h
+++ b/src/network/network_server.h
@@ -14,7 +14,6 @@
#include "network_internal.h"
#include "core/tcp_listen.h"
-#include "../thread/thread.h"
class ServerNetworkGameSocketHandler;
/** Make the code look slightly nicer/simpler. */
diff --git a/src/network/network_udp.cpp b/src/network/network_udp.cpp
index 1e82bd5928..d323dfd156 100644
--- a/src/network/network_udp.cpp
+++ b/src/network/network_udp.cpp
@@ -24,11 +24,12 @@
#include "network.h"
#include "../core/endian_func.hpp"
#include "../company_base.h"
-#include "../thread/thread.h"
+#include "../thread.h"
#include "../rev.h"
#include "../newgrf_text.h"
#include "../strings_func.h"
#include "table/strings.h"
+#include
#include "core/udp.h"
@@ -40,7 +41,7 @@ extern const uint8 _out_of_band_grf_md5[16] { 0x00, 0xB0, 0xC0, 0xDE, 0x00, 0x00
static const uint32 FIND_SERVER_EXTENDED_TOKEN = 0x2A49582A;
/** 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;
@@ -53,22 +54,6 @@ NetworkUDPSocketHandler *_udp_client_socket = NULL; ///< udp client socket
NetworkUDPSocketHandler *_udp_server_socket = NULL; ///< udp server socket
NetworkUDPSocketHandler *_udp_master_socket = NULL; ///< udp master socket
-/** Simpler wrapper struct for NetworkUDPQueryServerThread */
-struct NetworkUDPQueryServerInfo : NetworkAddress {
- bool manually; ///< Did we connect manually or not?
-
- /**
- * Create the structure.
- * @param address The address of the server to query.
- * @param manually Whether the address was entered manually.
- */
- NetworkUDPQueryServerInfo(const NetworkAddress &address, bool manually) :
- NetworkAddress(address),
- manually(manually)
- {
- }
-};
-
static Packet PrepareUdpClientFindServerPacket()
{
Packet p(PACKET_UDP_CLIENT_FIND_SERVER);
@@ -84,33 +69,21 @@ static Packet PrepareUdpClientFindServerPacket()
* @param needs_mutex Whether we need to acquire locks when sending the packet or not.
* @param manually Whether the address was entered manually.
*/
-static void NetworkUDPQueryServer(NetworkAddress *address, bool needs_mutex, bool manually)
+static void DoNetworkUDPQueryServer(NetworkAddress &address, bool needs_mutex, bool manually)
{
/* Clear item in gamelist */
NetworkGameList *item = CallocT(1);
- address->GetAddressAsString(item->info.server_name, lastof(item->info.server_name));
- strecpy(item->info.hostname, address->GetHostname(), lastof(item->info.hostname));
- item->address = *address;
+ address.GetAddressAsString(item->info.server_name, lastof(item->info.server_name));
+ strecpy(item->info.hostname, address.GetHostname(), lastof(item->info.hostname));
+ item->address = address;
item->manually = manually;
NetworkGameListAddItemDelayed(item);
- if (needs_mutex) _network_udp_mutex->BeginCritical();
+ std::unique_lock lock(_network_udp_mutex, std::defer_lock);
+ if (needs_mutex) lock.lock();
/* Init the packet */
Packet p = PrepareUdpClientFindServerPacket();
- if (_udp_client_socket != NULL) _udp_client_socket->SendPacket(&p, address);
- if (needs_mutex) _network_udp_mutex->EndCritical();
-}
-
-/**
- * Threaded part for resolving the IP of a server and querying it.
- * @param pntr the NetworkUDPQueryServerInfo.
- */
-static void NetworkUDPQueryServerThread(void *pntr)
-{
- NetworkUDPQueryServerInfo *info = (NetworkUDPQueryServerInfo*)pntr;
- NetworkUDPQueryServer(info, true, info->manually);
-
- delete info;
+ if (_udp_client_socket != NULL) _udp_client_socket->SendPacket(&p, &address);
}
/**
@@ -120,9 +93,8 @@ static void NetworkUDPQueryServerThread(void *pntr)
*/
void NetworkUDPQueryServer(NetworkAddress address, bool manually)
{
- NetworkUDPQueryServerInfo *info = new NetworkUDPQueryServerInfo(address, manually);
- if (address.IsResolved() || !ThreadObject::New(NetworkUDPQueryServerThread, info, NULL, "ottd:udp-query")) {
- NetworkUDPQueryServerThread(info);
+ if (address.IsResolved() || !StartNewThread(NULL, "ottd:udp-query", &DoNetworkUDPQueryServer, std::move(address), true, std::move(manually))) {
+ DoNetworkUDPQueryServer(address, true, manually);
}
}
@@ -510,7 +482,7 @@ void ClientNetworkUDPSocketHandler::Receive_MASTER_RESPONSE_LIST(Packet *p, Netw
/* Somehow we reached the end of the packet */
if (this->HasClientQuit()) return;
- NetworkUDPQueryServer(&addr, false, false);
+ DoNetworkUDPQueryServer(addr, false, false);
}
}
}
@@ -616,9 +588,8 @@ void NetworkUDPSearchGame()
/**
* Thread entry point for de-advertising.
- * @param pntr unused.
*/
-static void NetworkUDPRemoveAdvertiseThread(void *pntr)
+static void NetworkUDPRemoveAdvertiseThread()
{
DEBUG(net, 1, "[udp] removing advertise from master server");
@@ -631,9 +602,8 @@ static void NetworkUDPRemoveAdvertiseThread(void *pntr)
p.Send_uint8 (NETWORK_MASTER_SERVER_VERSION);
p.Send_uint16(_settings_client.network.server_port);
- _network_udp_mutex->BeginCritical();
+ std::lock_guard lock(_network_udp_mutex);
if (_udp_master_socket != NULL) _udp_master_socket->SendPacket(&p, &out_addr, true);
- _network_udp_mutex->EndCritical();
}
/**
@@ -645,16 +615,15 @@ void NetworkUDPRemoveAdvertise(bool blocking)
/* Check if we are advertising */
if (!_networking || !_network_server || !_network_udp_server) return;
- if (blocking || !ThreadObject::New(NetworkUDPRemoveAdvertiseThread, NULL, NULL, "ottd:udp-advert")) {
- NetworkUDPRemoveAdvertiseThread(NULL);
+ if (blocking || !StartNewThread(NULL, "ottd:udp-advert", &NetworkUDPRemoveAdvertiseThread)) {
+ NetworkUDPRemoveAdvertiseThread();
}
}
/**
* Thread entry point for advertising.
- * @param pntr unused.
*/
-static void NetworkUDPAdvertiseThread(void *pntr)
+static void NetworkUDPAdvertiseThread()
{
/* Find somewhere to send */
NetworkAddress out_addr(NETWORK_MASTER_SERVER_HOST, NETWORK_MASTER_SERVER_PORT);
@@ -685,9 +654,8 @@ static void NetworkUDPAdvertiseThread(void *pntr)
p.Send_uint16(_settings_client.network.server_port);
p.Send_uint64(_session_key);
- _network_udp_mutex->BeginCritical();
+ std::lock_guard lock(_network_udp_mutex);
if (_udp_master_socket != NULL) _udp_master_socket->SendPacket(&p, &out_addr, true);
- _network_udp_mutex->EndCritical();
}
/**
@@ -728,8 +696,8 @@ void NetworkUDPAdvertise()
if (_next_advertisement < _last_advertisement) _next_advertisement = UINT32_MAX;
if (_next_retry < _last_advertisement) _next_retry = UINT32_MAX;
- if (!ThreadObject::New(NetworkUDPAdvertiseThread, NULL, NULL, "ottd:udp-advert")) {
- NetworkUDPAdvertiseThread(NULL);
+ if (!StartNewThread(NULL, "ottd:udp-advert", &NetworkUDPAdvertiseThread)) {
+ NetworkUDPAdvertiseThread();
}
}
@@ -742,7 +710,7 @@ void NetworkUDPInitialize()
DEBUG(net, 1, "[udp] initializing listeners");
assert(_udp_client_socket == NULL && _udp_server_socket == NULL && _udp_master_socket == NULL);
- _network_udp_mutex->BeginCritical();
+ std::lock_guard lock(_network_udp_mutex);
_udp_client_socket = new ClientNetworkUDPSocketHandler();
@@ -756,13 +724,12 @@ void NetworkUDPInitialize()
_network_udp_server = false;
_network_udp_broadcast = 0;
- _network_udp_mutex->EndCritical();
}
/** Close all UDP related stuff. */
void NetworkUDPClose()
{
- _network_udp_mutex->BeginCritical();
+ std::lock_guard lock(_network_udp_mutex);
_udp_server_socket->Close();
_udp_master_socket->Close();
_udp_client_socket->Close();
@@ -772,7 +739,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;
@@ -782,7 +748,7 @@ void NetworkUDPClose()
/** Receive the UDP packets. */
void NetworkBackgroundUDPLoop()
{
- _network_udp_mutex->BeginCritical();
+ std::lock_guard lock(_network_udp_mutex);
if (_network_udp_server) {
_udp_server_socket->ReceivePackets();
@@ -791,6 +757,4 @@ void NetworkBackgroundUDPLoop()
_udp_client_socket->ReceivePackets();
if (_network_udp_broadcast > 0) _network_udp_broadcast--;
}
-
- _network_udp_mutex->EndCritical();
}
diff --git a/src/newgrf_config.cpp b/src/newgrf_config.cpp
index e270634d37..3e61b1cd7a 100644
--- a/src/newgrf_config.cpp
+++ b/src/newgrf_config.cpp
@@ -21,6 +21,8 @@
#include "video/video_driver.hpp"
#include "strings_func.h"
#include "textfile_gui.h"
+#include "thread.h"
+#include "newgrf_config.h"
#include "fileio_func.h"
#include "fios.h"
@@ -684,18 +686,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,9 +727,9 @@ static int CDECL GRFSorter(GRFConfig * const *p1, GRFConfig * const *p2)
* Really perform the scan for all NewGRFs.
* @param callback The callback to call after the scanning is complete.
*/
-void DoScanNewGRFFiles(void *callback)
+void DoScanNewGRFFiles(NewGRFScanCallback *callback)
{
- _modal_progress_work_mutex->BeginCritical();
+ std::unique_lock lock_work(_modal_progress_work_mutex);
ClearGRFConfigList(&_all_grfs);
TarScanner::DoScan(TarScanner::NEWGRF);
@@ -762,18 +764,17 @@ void DoScanNewGRFFiles(void *callback)
NetworkAfterNewGRFScan();
}
- _modal_progress_work_mutex->EndCritical();
- _modal_progress_paint_mutex->BeginCritical();
+ lock_work.unlock();
+ std::lock_guard lock_paint(_modal_progress_paint_mutex);
/* Yes... these are the NewGRF windows */
InvalidateWindowClassesData(WC_SAVELOAD, 0, true);
InvalidateWindowData(WC_GAME_OPTIONS, WN_GAME_OPTIONS_NEWGRF_STATE, GOID_NEWGRF_RESCANNED, true);
- if (callback != NULL) ((NewGRFScanCallback*)callback)->OnNewGRFsScanned();
+ if (callback != NULL) callback->OnNewGRFsScanned();
DeleteWindowByClass(WC_MODAL_PROGRESS);
SetModalProgress(false);
MarkWholeScreenDirty();
- _modal_progress_paint_mutex->EndCritical();
}
/**
@@ -787,12 +788,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() || !StartNewThread(NULL, "ottd:newgrf-scan", &DoScanNewGRFFiles, (NewGRFScanCallback *)callback)) { // Without the seemingly superfluous cast, strange compiler errors ensue.
+ _modal_progress_work_mutex.unlock();
+ _modal_progress_paint_mutex.unlock();
DoScanNewGRFFiles(callback);
- _modal_progress_paint_mutex->BeginCritical();
- _modal_progress_work_mutex->BeginCritical();
+ _modal_progress_paint_mutex.lock();
+ _modal_progress_work_mutex.lock();
} else {
UpdateNewGRFScanStatus(0, NULL);
}
diff --git a/src/object_cmd.cpp b/src/object_cmd.cpp
index 4d7750491f..3e9ef8be60 100644
--- a/src/object_cmd.cpp
+++ b/src/object_cmd.cpp
@@ -834,9 +834,10 @@ static void ChangeTileOwner_Object(TileIndex tile, Owner old_owner, Owner new_ow
bool do_clear = false;
- if (IsObjectType(tile, OBJECT_OWNED_LAND) && new_owner != INVALID_OWNER) {
+ ObjectType type = GetObjectType(tile);
+ if ((type == OBJECT_OWNED_LAND || type >= NEW_OBJECT_OFFSET) && new_owner != INVALID_OWNER) {
SetTileOwner(tile, new_owner);
- } else if (IsObjectType(tile, OBJECT_STATUE)) {
+ } else if (type == OBJECT_STATUE) {
Town *t = Object::GetByTile(tile)->town;
ClrBit(t->statues, old_owner);
if (new_owner != INVALID_OWNER && !HasBit(t->statues, new_owner)) {
diff --git a/src/openttd.cpp b/src/openttd.cpp
index af851b0d4c..8b5621c9ad 100644
--- a/src/openttd.cpp
+++ b/src/openttd.cpp
@@ -68,7 +68,7 @@
#include "programmable_signals.h"
#include "smallmap_gui.h"
#include "viewport_func.h"
-#include "thread/thread.h"
+#include "thread.h"
#include "bridge_signal_map.h"
#include "zoning.h"
#include "cargopacket.h"
@@ -77,6 +77,7 @@
#include "tracerestrict.h"
#include
+#include
#include "safeguards.h"
@@ -613,6 +614,9 @@ int openttd_main(int argc, char *argv[])
extern bool _dedicated_forks;
_dedicated_forks = false;
+ std::unique_lock modal_work_lock(_modal_progress_work_mutex, std::defer_lock);
+ std::unique_lock modal_paint_lock(_modal_progress_paint_mutex, std::defer_lock);
+
_game_mode = GM_MENU;
_switch_mode = SM_MENU;
_config_file = NULL;
@@ -897,8 +901,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();
@@ -916,6 +926,7 @@ int openttd_main(int argc, char *argv[])
CrashLog::MainThreadExitCheckPendingCrashlog();
WaitTillSaved();
+ WaitTillGeneratedWorld(); // Make sure any generate world threads have been joined.
/* only save config if we have to */
if (save_config) {
diff --git a/src/os/macosx/macos.mm b/src/os/macosx/macos.mm
index 7fb71fe9ee..ae9d86ee8b 100644
--- a/src/os/macosx/macos.mm
+++ b/src/os/macosx/macos.mm
@@ -206,23 +206,6 @@ bool GetClipboardContents(char *buffer, const char *last)
}
#endif
-uint GetCPUCoreCount()
-{
- uint count = 1;
-#if (MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5)
- if (MacOSVersionIsAtLeast(10, 5, 0)) {
- count = (uint)[ [ NSProcessInfo processInfo ] activeProcessorCount ];
- } else
-#endif
- {
-#if (MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5)
- count = MPProcessorsScheduled();
-#endif
- }
-
- return count;
-}
-
/**
* Check if a font is a monospace font.
* @param name Name of the font.
diff --git a/src/os/os2/os2.cpp b/src/os/os2/os2.cpp
index 7b34f528a6..a77f6c325b 100644
--- a/src/os/os2/os2.cpp
+++ b/src/os/os2/os2.cpp
@@ -18,6 +18,7 @@
#include "../../core/random_func.hpp"
#include "../../string_func.h"
#include "../../textbuf_gui.h"
+#include "../../thread.h"
#include "table/strings.h"
@@ -204,25 +205,22 @@ bool GetClipboardContents(char *buffer, const char *last)
}
-void CSleep(int milliseconds)
-{
-#ifndef __INNOTEK_LIBC__
- delay(milliseconds);
-#else
- usleep(milliseconds * 1000);
-#endif
-}
-
const char *FS2OTTD(const char *name) {return name;}
const char *OTTD2FS(const char *name) {return name;}
-uint GetCPUCoreCount()
-{
- return 1;
-}
-
void OSOpenBrowser(const char *url)
{
// stub only
DEBUG(misc, 0, "Failed to open url: %s", url);
}
+
+void SetCurrentThreadName(const char *)
+{
+}
+
+int GetCurrentThreadName(char *str, const char *last) { return 0; }
+
+void SetSelfAsMainThread() { }
+
+bool IsMainThread() { return false; }
+bool IsNonMainThread() { return false; }
diff --git a/src/os/unix/unix.cpp b/src/os/unix/unix.cpp
index 2f982dea06..f9a2cd0028 100644
--- a/src/os/unix/unix.cpp
+++ b/src/os/unix/unix.cpp
@@ -17,6 +17,7 @@
#include "../../debug.h"
#include "../../string_func.h"
#include "../../fios.h"
+#include "../../thread.h"
#include
@@ -43,11 +44,17 @@
#include
#endif
+#ifndef NO_THREADS
+#include
+#endif
+
#if defined(__APPLE__)
- #if defined(WITH_SDL)
+# if defined(WITH_SDL)
/* the mac implementation needs this file included in the same file as main() */
- #include
- #endif
+# include
+# endif
+
+# include "../macosx/macos.h"
#endif
#include "../../safeguards.h"
@@ -266,44 +273,7 @@ bool GetClipboardContents(char *buffer, const char *last)
#endif
-/* multi os compatible sleep function */
-
-void CSleep(int milliseconds)
-{
- usleep(milliseconds * 1000);
-}
-
-
#ifndef __APPLE__
-uint GetCPUCoreCount()
-{
- uint count = 1;
-#ifdef HAS_SYSCTL
- int ncpu = 0;
- size_t len = sizeof(ncpu);
-
-#ifdef OPENBSD
- int name[2];
- name[0] = CTL_HW;
- name[1] = HW_NCPU;
- if (sysctl(name, 2, &ncpu, &len, NULL, 0) < 0) {
- ncpu = 0;
- }
-#else
- if (sysctlbyname("hw.availcpu", &ncpu, &len, NULL, 0) < 0) {
- sysctlbyname("hw.ncpu", &ncpu, &len, NULL, 0);
- }
-#endif /* #ifdef OPENBSD */
-
- if (ncpu > 0) count = ncpu;
-#elif defined(_SC_NPROCESSORS_ONLN)
- long res = sysconf(_SC_NPROCESSORS_ONLN);
- if (res > 0) count = res;
-#endif
-
- return count;
-}
-
void OSOpenBrowser(const char *url)
{
pid_t child_pid = fork();
@@ -317,4 +287,56 @@ void OSOpenBrowser(const char *url)
DEBUG(misc, 0, "Failed to open url: %s", url);
exit(0);
}
+#endif /* __APPLE__ */
+
+void SetCurrentThreadName(const char *threadName) {
+#if !defined(NO_THREADS) && defined(__GLIBC__)
+#if __GLIBC_PREREQ(2, 12)
+ if (threadName) pthread_setname_np(pthread_self(), threadName);
+#endif /* __GLIBC_PREREQ(2, 12) */
+#endif /* !defined(NO_THREADS) && defined(__GLIBC__) */
+#if defined(__APPLE__)
+ MacOSSetThreadName(threadName);
+#endif /* defined(__APPLE__) */
+}
+
+int GetCurrentThreadName(char *str, const char *last)
+{
+#if !defined(NO_THREADS) && defined(__GLIBC__)
+#if __GLIBC_PREREQ(2, 12)
+ char buffer[16];
+ int result = pthread_getname_np(pthread_self(), buffer, sizeof(buffer));
+ if (result == 0) {
+ return seprintf(str, last, "%s", buffer);
+ }
+#endif
+#endif
+ return 0;
+}
+
+static pthread_t main_thread;
+
+void SetSelfAsMainThread()
+{
+#if !defined(NO_THREADS)
+ main_thread = pthread_self();
#endif
+}
+
+bool IsMainThread()
+{
+#if !defined(NO_THREADS)
+ return main_thread == pthread_self();
+#else
+ return true;
+#endif
+}
+
+bool IsNonMainThread()
+{
+#if !defined(NO_THREADS)
+ return main_thread != pthread_self();
+#else
+ return false;
+#endif
+}
diff --git a/src/os/windows/win32.cpp b/src/os/windows/win32.cpp
index db2636e281..6fe8d6ebfa 100644
--- a/src/os/windows/win32.cpp
+++ b/src/os/windows/win32.cpp
@@ -30,6 +30,7 @@
#include
#include
#include "../../language.h"
+#include "../../thread.h"
#include "../../safeguards.h"
@@ -81,7 +82,7 @@ void ShowOSErrorBox(const char *buf, bool system)
{
_in_event_loop_post_crash = true;
MyShowCursor(true);
- MessageBox(GetActiveWindow(), OTTD2FS(buf), _T("Error!"), MB_ICONSTOP);
+ MessageBox(GetActiveWindow(), OTTD2FS(buf), _T("Error!"), MB_ICONSTOP | MB_TASKMODAL);
}
void OSOpenBrowser(const char *url)
@@ -546,12 +547,6 @@ bool GetClipboardContents(char *buffer, const char *last)
}
-void CSleep(int milliseconds)
-{
- Sleep(milliseconds);
-}
-
-
/**
* Convert to OpenTTD's encoding from that of the local environment.
* When the project is built in UNICODE, the system codepage is irrelevant and
@@ -733,14 +728,6 @@ const char *GetCurrentLocale(const char *)
return retbuf;
}
-uint GetCPUCoreCount()
-{
- SYSTEM_INFO info;
-
- GetSystemInfo(&info);
- return info.dwNumberOfProcessors;
-}
-
static WCHAR _cur_iso_locale[16] = L"";
@@ -805,6 +792,42 @@ int OTTDStringCompare(const char *s1, const char *s2)
return CompareString(MAKELCID(_current_language->winlangid, SORT_DEFAULT), NORM_IGNORECASE, s1_buf, -1, s2_buf, -1);
}
+static DWORD main_thread_id;
+
+void SetSelfAsMainThread()
+{
+ main_thread_id = GetCurrentThreadId();
+}
+
+bool IsMainThread()
+{
+ return main_thread_id == GetCurrentThreadId();
+}
+
+bool IsNonMainThread()
+{
+ return main_thread_id != GetCurrentThreadId();
+}
+
+static std::map _thread_name_map;
+static std::mutex _thread_name_map_mutex;
+
+static void Win32SetThreadName(uint id, const char *name)
+{
+ std::lock_guard lock(_thread_name_map_mutex);
+ _thread_name_map[id] = name;
+}
+
+int GetCurrentThreadName(char *str, const char *last)
+{
+ std::lock_guard lock(_thread_name_map_mutex);
+ auto iter = _thread_name_map.find(GetCurrentThreadId());
+ if (iter != _thread_name_map.end()) {
+ return seprintf(str, last, "%s", iter->second.c_str());
+ }
+ return 0;
+}
+
#ifdef _MSC_VER
/* Based on code from MSDN: https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */
const DWORD MS_VC_EXCEPTION = 0x406D1388;
@@ -819,12 +842,14 @@ PACK_N(struct THREADNAME_INFO {
/**
* Signal thread name to any attached debuggers.
*/
-void SetWin32ThreadName(DWORD dwThreadID, const char* threadName)
+void SetCurrentThreadName(const char *threadName)
{
+ Win32SetThreadName(GetCurrentThreadId(), threadName);
+
THREADNAME_INFO info;
info.dwType = 0x1000;
info.szName = threadName;
- info.dwThreadID = dwThreadID;
+ info.dwThreadID = -1;
info.dwFlags = 0;
#pragma warning(push)
@@ -835,4 +860,9 @@ void SetWin32ThreadName(DWORD dwThreadID, const char* threadName)
}
#pragma warning(pop)
}
+#else
+void SetCurrentThreadName(const char *)
+{
+ Win32SetThreadName(GetCurrentThreadId(), threadName);
+}
#endif
diff --git a/src/os/windows/win32.h b/src/os/windows/win32.h
index 4f813c4a6f..23e216762c 100644
--- a/src/os/windows/win32.h
+++ b/src/os/windows/win32.h
@@ -39,12 +39,6 @@ HRESULT OTTDSHGetFolderPath(HWND, int, HANDLE, DWORD, LPTSTR);
#define SHGFP_TYPE_CURRENT 0
#endif /* __MINGW32__ */
-#ifdef _MSC_VER
-void SetWin32ThreadName(DWORD dwThreadID, const char* threadName);
-#else
-static inline void SetWin32ThreadName(DWORD dwThreadID, const char* threadName) {}
-#endif
-
void Win32SetCurrentLocaleName(const char *iso_code);
int OTTDStringCompare(const char *s1, const char *s2);
diff --git a/src/progress.cpp b/src/progress.cpp
index b498be109b..923f1ef83f 100644
--- a/src/progress.cpp
+++ b/src/progress.cpp
@@ -10,17 +10,19 @@
/** @file progress.cpp Functions for modal progress windows. */
#include "stdafx.h"
-#include "thread/thread.h"
+#include "progress.h"
#include "safeguards.h"
/** Are we in a modal progress or not? */
bool _in_modal_progress = false;
bool _first_in_modal_loop = false;
+/** Threading usable for modal progress? */
+bool _use_threaded_modal_progress = true;
/** Rights for the performing work. */
-ThreadMutex *_modal_progress_work_mutex = ThreadMutex::New();
+std::mutex _modal_progress_work_mutex;
/** Rights for the painting. */
-ThreadMutex *_modal_progress_paint_mutex = ThreadMutex::New();
+std::mutex _modal_progress_paint_mutex;
/**
* Set the modal progress state.
diff --git a/src/progress.h b/src/progress.h
index eec369b23c..2a9d73b038 100644
--- a/src/progress.h
+++ b/src/progress.h
@@ -12,7 +12,7 @@
#ifndef PROGRESS_H
#define PROGRESS_H
-#include "thread/thread.h"
+#include
static const uint MODAL_PROGRESS_REDRAW_TIMEOUT = 200; ///< Timeout between redraws
@@ -26,10 +26,20 @@ static inline bool HasModalProgress()
return _in_modal_progress;
}
+/**
+ * Check if we can use a thread for modal progress.
+ * @return Threading usable?
+ */
+static inline bool UseThreadedModelProgress()
+{
+ extern bool _use_threaded_modal_progress;
+ return _use_threaded_modal_progress;
+}
+
bool IsFirstModalProgressLoop();
void SetModalProgress(bool state);
-extern class ThreadMutex *_modal_progress_work_mutex;
-extern class ThreadMutex *_modal_progress_paint_mutex;
+extern std::mutex _modal_progress_work_mutex;
+extern std::mutex _modal_progress_paint_mutex;
#endif /* PROGRESS_H */
diff --git a/src/saveload/saveload.cpp b/src/saveload/saveload.cpp
index 40a15834a1..7bae3154fb 100644
--- a/src/saveload/saveload.cpp
+++ b/src/saveload/saveload.cpp
@@ -26,7 +26,7 @@
#include "../debug.h"
#include "../station_base.h"
#include "../dock_base.h"
-#include "../thread/thread.h"
+#include "../thread.h"
#include "../town.h"
#include "../network/network.h"
#include "../window_func.h"
@@ -46,6 +46,7 @@
#include "../string_func_extra.h"
#include "../fios.h"
#include "../error.h"
+#include
#include "../tbtr_template_vehicle.h"
@@ -427,9 +428,9 @@ void NORETURN CDECL SlErrorCorruptFmt(const char *format, ...)
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, str, true);
}
-typedef void (*AsyncSaveFinishProc)(); ///< Callback for when the savegame loading is finished.
-static AsyncSaveFinishProc _async_save_finish = NULL; ///< Callback to call when the savegame loading is finished.
-static ThreadObject *_save_thread; ///< The thread we're using to compress and write a savegame
+typedef void (*AsyncSaveFinishProc)(); ///< Callback for when the savegame loading is finished.
+static std::atomic _async_save_finish; ///< Callback to call when the savegame loading is finished.
+static std::thread _save_thread; ///< The thread we're using to compress and write a savegame
/**
* Called by save thread to tell we finished saving.
@@ -438,9 +439,9 @@ static ThreadObject *_save_thread; ///< The thread we're usin
static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
{
if (_exit_game) return;
- while (_async_save_finish != NULL) CSleep(10);
+ while (_async_save_finish.load(std::memory_order_acquire) != NULL) CSleep(10);
- _async_save_finish = proc;
+ _async_save_finish.store(proc, std::memory_order_release);
}
/**
@@ -448,16 +449,13 @@ static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
*/
void ProcessAsyncSaveFinish()
{
- if (_async_save_finish == NULL) return;
-
- _async_save_finish();
+ AsyncSaveFinishProc proc = _async_save_finish.exchange(NULL, std::memory_order_acq_rel);
+ if (proc == NULL) return;
- _async_save_finish = NULL;
+ proc();
- if (_save_thread != NULL) {
- _save_thread->Join();
- delete _save_thread;
- _save_thread = NULL;
+ if (_save_thread.joinable()) {
+ _save_thread.join();
}
}
@@ -2759,19 +2757,11 @@ static SaveOrLoadResult SaveFileToDisk(bool threaded)
}
}
-/** Thread run function for saving the file to disk. */
-static void SaveFileToDiskThread(void *arg)
-{
- SaveFileToDisk(true);
-}
-
void WaitTillSaved()
{
- if (_save_thread == NULL) return;
+ if (!_save_thread.joinable()) return;
- _save_thread->Join();
- delete _save_thread;
- _save_thread = NULL;
+ _save_thread.join();
/* Make sure every other state is handled properly as well. */
ProcessAsyncSaveFinish();
@@ -2799,7 +2789,8 @@ static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
SlSaveChunks();
SaveFileStart();
- if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread, "ottd:savegame")) {
+
+ if (!threaded || !StartNewThread(&_save_thread, "ottd:savegame", &SaveFileToDisk, true)) {
if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
SaveOrLoadResult result = SaveFileToDisk(false);
diff --git a/src/ship_cmd.cpp b/src/ship_cmd.cpp
index da6e6fdd66..e79ec10734 100644
--- a/src/ship_cmd.cpp
+++ b/src/ship_cmd.cpp
@@ -539,8 +539,6 @@ static inline TrackBits GetAvailShipTracks(TileIndex tile, DiagDirection dir, Tr
{
TrackBits tracks = GetTileShipTrackStatus(tile) & DiagdirReachesTracks(dir);
- if (_settings_game.pf.forbid_90_deg) tracks &= ~TrackCrossesTracks(TrackdirToTrack(trackdir));
-
return tracks;
}
diff --git a/src/sound/win32_s.cpp b/src/sound/win32_s.cpp
index c9c1a8afdc..493ed7fc17 100644
--- a/src/sound/win32_s.cpp
+++ b/src/sound/win32_s.cpp
@@ -20,6 +20,7 @@
#include
#include
#include "../os/windows/win32.h"
+#include "../thread.h"
#include "../safeguards.h"
@@ -42,7 +43,7 @@ static void PrepareHeader(WAVEHDR *hdr)
static DWORD WINAPI SoundThread(LPVOID arg)
{
- SetWin32ThreadName(-1, "ottd:win-sound");
+ SetCurrentThreadName("ottd:win-sound");
do {
for (WAVEHDR *hdr = _wave_hdr; hdr != endof(_wave_hdr); hdr++) {
diff --git a/src/station_cmd.cpp b/src/station_cmd.cpp
index b3fa1499db..c77d0c7353 100644
--- a/src/station_cmd.cpp
+++ b/src/station_cmd.cpp
@@ -2896,21 +2896,29 @@ bool SplitGroundSpriteForOverlay(const TileInfo *ti, SpriteID *ground, RailTrack
bool snow_desert;
switch (*ground) {
case SPR_RAIL_TRACK_X:
+ case SPR_MONO_TRACK_X:
+ case SPR_MGLV_TRACK_X:
snow_desert = false;
*overlay_offset = RTO_X;
break;
case SPR_RAIL_TRACK_Y:
+ case SPR_MONO_TRACK_Y:
+ case SPR_MGLV_TRACK_Y:
snow_desert = false;
*overlay_offset = RTO_Y;
break;
case SPR_RAIL_TRACK_X_SNOW:
+ case SPR_MONO_TRACK_X_SNOW:
+ case SPR_MGLV_TRACK_X_SNOW:
snow_desert = true;
*overlay_offset = RTO_X;
break;
case SPR_RAIL_TRACK_Y_SNOW:
+ case SPR_MONO_TRACK_Y_SNOW:
+ case SPR_MGLV_TRACK_Y_SNOW:
snow_desert = true;
*overlay_offset = RTO_Y;
break;
diff --git a/src/table/sprites.h b/src/table/sprites.h
index 09d772c3ad..1f4f8caf84 100644
--- a/src/table/sprites.h
+++ b/src/table/sprites.h
@@ -435,8 +435,11 @@ static const SpriteID SPR_MONO_SINGLE_SOUTH = 1090;
static const SpriteID SPR_MONO_SINGLE_EAST = 1091;
static const SpriteID SPR_MONO_SINGLE_WEST = 1092;
static const SpriteID SPR_MONO_TRACK_Y = 1093;
+static const SpriteID SPR_MONO_TRACK_X = 1094;
static const SpriteID SPR_MONO_TRACK_BASE = 1100;
static const SpriteID SPR_MONO_TRACK_N_S = 1117;
+static const SpriteID SPR_MONO_TRACK_Y_SNOW = 1119;
+static const SpriteID SPR_MONO_TRACK_X_SNOW = 1120;
static const SpriteID SPR_MGLV_SINGLE_X = 1169;
static const SpriteID SPR_MGLV_SINGLE_Y = 1170;
static const SpriteID SPR_MGLV_SINGLE_NORTH = 1171;
@@ -444,7 +447,10 @@ static const SpriteID SPR_MGLV_SINGLE_SOUTH = 1172;
static const SpriteID SPR_MGLV_SINGLE_EAST = 1173;
static const SpriteID SPR_MGLV_SINGLE_WEST = 1174;
static const SpriteID SPR_MGLV_TRACK_Y = 1175;
+static const SpriteID SPR_MGLV_TRACK_X = 1176;
static const SpriteID SPR_MGLV_TRACK_BASE = 1182;
+static const SpriteID SPR_MGLV_TRACK_Y_SNOW = 1184;
+static const SpriteID SPR_MGLV_TRACK_X_SNOW = 1185;
static const SpriteID SPR_MGLV_TRACK_N_S = 1199;
static const SpriteID SPR_WAYPOINT_X_1 = SPR_OPENTTD_BASE + 78;
static const SpriteID SPR_WAYPOINT_X_2 = SPR_OPENTTD_BASE + 79;
diff --git a/src/thread.h b/src/thread.h
new file mode 100644
index 0000000000..6111cf1221
--- /dev/null
+++ b/src/thread.h
@@ -0,0 +1,104 @@
+/* $Id$ */
+
+/*
+ * This file is part of OpenTTD.
+ * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
+ * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+ * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see .
+ */
+
+/** @file thread.h Base of all threads. */
+
+#ifndef THREAD_H
+#define THREAD_H
+
+#include "debug.h"
+#include
+#include
+
+/** Signal used for signalling we knowingly want to end the thread. */
+class OTTDThreadExitSignal { };
+
+
+/**
+ * Sleep on the current thread for a defined time.
+ * @param milliseconds Time to sleep for in milliseconds.
+ */
+inline void CSleep(int milliseconds)
+{
+ std::this_thread::sleep_for(std::chrono::milliseconds(milliseconds));
+}
+
+/**
+ * Name the thread this function is called on for the debugger.
+ * @param name Name to set for the thread..
+ */
+void SetCurrentThreadName(const char *name);
+
+/**
+ * Get the name of the current thread, if any.
+ * @param str The start of the buffer.
+ * @param last The last char of the buffer.
+ * @return Number of chars written to str.
+ */
+int GetCurrentThreadName(char *str, const char *last);
+
+/**
+ * Set the current thread as the "main" thread
+ */
+void SetSelfAsMainThread();
+
+/**
+ * @return true if the current thread definitely the "main" thread. If in doubt returns false.
+ */
+bool IsMainThread();
+
+/**
+ * @return true if the current thread definitely a "non-main" thread. If in doubt returns false.
+ */
+bool IsNonMainThread();
+
+
+/**
+ * Start a new thread.
+ * @tparam TFn Type of the function to call on the thread.
+ * @tparam TArgs Type of the parameters of the thread function.
+ * @param thr Pointer to a thread object; may be \c NULL if a detached thread is wanted.
+ * @param name Name of the thread.
+ * @param _Fx Function to call on the thread.
+ * @param _Ax Arguments for the thread function.
+ * @return True if the thread was successfully started, false otherwise.
+ */
+template
+inline bool StartNewThread(std::thread *thr, const char *name, TFn&& _Fx, TArgs&&... _Ax)
+{
+#ifndef NO_THREADS
+ try {
+ std::thread t([] (const char *name, TFn&& F, TArgs&&... A) {
+ SetCurrentThreadName(name);
+ try {
+ /* Call user function with the given arguments. */
+ F(A...);
+ } catch (OTTDThreadExitSignal&) {
+ } catch (...) {
+ NOT_REACHED();
+ }
+ }, name, std::forward(_Fx), std::forward(_Ax)...);
+
+ if (thr != NULL) {
+ *thr = std::move(t);
+ } else {
+ t.detach();
+ }
+
+ return true;
+ } catch (const std::system_error& e) {
+ /* Something went wrong, the system we are running on might not support threads. */
+ DEBUG(misc, 1, "Can't create thread '%s': %s", name, e.what());
+ }
+#endif
+
+ return false;
+}
+
+#endif /* THREAD_H */
diff --git a/src/thread/thread.h b/src/thread/thread.h
deleted file mode 100644
index ecfd655fb6..0000000000
--- a/src/thread/thread.h
+++ /dev/null
@@ -1,149 +0,0 @@
-/* $Id$ */
-
-/*
- * This file is part of OpenTTD.
- * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
- * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see .
- */
-
-/** @file thread.h Base of all threads. */
-
-#ifndef THREAD_H
-#define THREAD_H
-
-/** Definition of all thread entry functions. */
-typedef void (*OTTDThreadFunc)(void *);
-
-/** Signal used for signalling we knowingly want to end the thread. */
-class OTTDThreadExitSignal { };
-
-/**
- * A Thread Object which works on all our supported OSes.
- */
-class ThreadObject {
-public:
- /**
- * Virtual destructor to allow 'delete' operator to work properly.
- */
- virtual ~ThreadObject() {};
-
- /**
- * Exit this thread.
- */
- virtual bool Exit() = 0;
-
- /**
- * Join this thread.
- */
- virtual void Join() = 0;
-
- /**
- * Create a thread; proc will be called as first function inside the thread,
- * with optional params.
- * @param proc The procedure to call inside the thread.
- * @param param The params to give with 'proc'.
- * @param thread Place to store a pointer to the thread in. May be NULL.
- * @param name A name for the thread. May be NULL.
- * @return True if the thread was started correctly.
- */
- 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.
- */
-uint GetCPUCoreCount();
-
-/**
- * Set the current thread as the "main" thread
- */
-void SetSelfAsMainThread();
-
-/**
- * @return true if the current thread definitely the "main" thread. If in doubt returns false.
- */
-bool IsMainThread();
-
-/**
- * @return true if the current thread definitely a "non-main" thread. If in doubt returns false.
- */
-bool IsNonMainThread();
-
-/**
- * Get the name of the current thread, if any.
- * @param str The start of the buffer.
- * @param last The last char of the buffer.
- * @return Number of chars written to str.
- */
-int GetThreadName(char *str, const char *last);
-
-#endif /* THREAD_H */
diff --git a/src/thread/thread_none.cpp b/src/thread/thread_none.cpp
deleted file mode 100644
index 175cf32015..0000000000
--- a/src/thread/thread_none.cpp
+++ /dev/null
@@ -1,42 +0,0 @@
-/* $Id$ */
-
-/*
- * This file is part of OpenTTD.
- * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
- * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see .
- */
-
-/** @file thread_none.cpp No-Threads-Available implementation of Threads */
-
-#include "../stdafx.h"
-#include "thread.h"
-
-#include "../safeguards.h"
-
-/* static */ bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread, const char *name)
-{
- if (thread != NULL) *thread = NULL;
- return false;
-}
-
-/** Mutex that doesn't do locking because it ain't needed when there're no threads */
-class ThreadMutex_None : public ThreadMutex {
-public:
- virtual void BeginCritical(bool allow_recursive = false) {}
- virtual void EndCritical(bool allow_recursive = false) {}
- virtual void WaitForSignal() {}
- virtual void SendSignal() {}
-};
-
-/* static */ ThreadMutex *ThreadMutex::New()
-{
- return new ThreadMutex_None();
-}
-
-void SetSelfAsMainThread() { }
-
-bool IsMainThread() { return true; }
-bool IsNonMainThread() { return false; }
-
-int GetThreadName(char *str, const char *last) { return 0; }
diff --git a/src/thread/thread_os2.cpp b/src/thread/thread_os2.cpp
deleted file mode 100644
index d2251a9462..0000000000
--- a/src/thread/thread_os2.cpp
+++ /dev/null
@@ -1,155 +0,0 @@
-/* $Id$ */
-
-/*
- * This file is part of OpenTTD.
- * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
- * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see .
- */
-
-/** @file thread_os2.cpp OS/2 implementation of Threads. */
-
-#include "../stdafx.h"
-#include "thread.h"
-
-#define INCL_DOS
-#include
-#include
-
-#include "../safeguards.h"
-
-/**
- * OS/2 version for ThreadObject.
- */
-class ThreadObject_OS2 : public ThreadObject {
-private:
- TID thread; ///< System thread identifier.
- OTTDThreadFunc proc; ///< External thread procedure.
- void *param; ///< Parameter for the external thread procedure.
- bool self_destruct; ///< Free ourselves when done?
-
-public:
- /**
- * Create a thread and start it, calling proc(param).
- */
- ThreadObject_OS2(OTTDThreadFunc proc, void *param, bool self_destruct) :
- thread(0),
- proc(proc),
- param(param),
- self_destruct(self_destruct)
- {
- thread = _beginthread(stThreadProc, NULL, 1048576, this);
- }
-
- bool Exit() override
- {
- _endthread();
- return true;
- }
-
- void Join() override
- {
- DosWaitThread(&this->thread, DCWW_WAIT);
- this->thread = 0;
- }
-private:
- /**
- * On thread creation, this function is called, which calls the real startup
- * function. This to get back into the correct instance again.
- */
- static void stThreadProc(void *thr)
- {
- ((ThreadObject_OS2 *)thr)->ThreadProc();
- }
-
- /**
- * A new thread is created, and this function is called. Call the custom
- * function of the creator of the thread.
- */
- void ThreadProc()
- {
- /* Call the proc of the creator to continue this thread */
- try {
- this->proc(this->param);
- } catch (OTTDThreadExitSignal e) {
- } catch (...) {
- NOT_REACHED();
- }
-
- if (self_destruct) {
- this->Exit();
- delete this;
- }
- }
-};
-
-/* static */ bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread, const char *name)
-{
- ThreadObject *to = new ThreadObject_OS2(proc, param, thread == NULL);
- 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();
-}
-
-void SetSelfAsMainThread() { }
-
-bool IsMainThread() { return false; }
-
-bool IsNonMainThread() { return false; }
-
-int GetThreadName(char *str, const char *last) { return 0; }
diff --git a/src/thread/thread_pthread.cpp b/src/thread/thread_pthread.cpp
deleted file mode 100644
index 44d3242d25..0000000000
--- a/src/thread/thread_pthread.cpp
+++ /dev/null
@@ -1,223 +0,0 @@
-/* $Id$ */
-
-/*
- * This file is part of OpenTTD.
- * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
- * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see .
- */
-
-/** @file thread_pthread.cpp POSIX pthread implementation of Threads. */
-
-#include "../stdafx.h"
-#include "thread.h"
-#include "../string_func.h"
-#include
-#include
-
-#if defined(__APPLE__)
-#include "../os/macosx/macos.h"
-#endif
-
-#include "../safeguards.h"
-
-/**
- * POSIX pthread version for ThreadObject.
- */
-class ThreadObject_pthread : public ThreadObject {
-private:
- pthread_t thread; ///< System thread identifier.
- OTTDThreadFunc proc; ///< External thread procedure.
- void *param; ///< Parameter for the external thread procedure.
- bool self_destruct; ///< Free ourselves when done?
- const char *name; ///< Name for the thread
-
-public:
- /**
- * Create a pthread and start it, calling proc(param).
- */
- ThreadObject_pthread(OTTDThreadFunc proc, void *param, bool self_destruct, const char *name) :
- thread(0),
- proc(proc),
- param(param),
- self_destruct(self_destruct),
- name(name)
- {
- pthread_create(&this->thread, NULL, &stThreadProc, this);
- }
-
- bool Exit() override
- {
- assert(pthread_self() == this->thread);
- /* For now we terminate by throwing an error, gives much cleaner cleanup */
- throw OTTDThreadExitSignal();
- }
-
- void Join() override
- {
- /* You cannot join yourself */
- assert(pthread_self() != this->thread);
- pthread_join(this->thread, NULL);
- this->thread = 0;
- }
-private:
- /**
- * On thread creation, this function is called, which calls the real startup
- * function. This to get back into the correct instance again.
- */
- static void *stThreadProc(void *thr)
- {
- ThreadObject_pthread *self = (ThreadObject_pthread *) thr;
-#if defined(__GLIBC__)
-#if __GLIBC_PREREQ(2, 12)
- if (self->name) {
- pthread_setname_np(pthread_self(), self->name);
- }
-#endif
-#endif
-#if defined(__APPLE__)
- MacOSSetThreadName(self->name);
-#endif
- self->ThreadProc();
- pthread_exit(NULL);
- }
-
- /**
- * A new thread is created, and this function is called. Call the custom
- * function of the creator of the thread.
- */
- void ThreadProc()
- {
- /* Call the proc of the creator to continue this thread */
- try {
- this->proc(this->param);
- } catch (OTTDThreadExitSignal) {
- } catch (...) {
- NOT_REACHED();
- }
-
- if (self_destruct) {
- pthread_detach(pthread_self());
- delete this;
- }
- }
-};
-
-/* static */ bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread, const char *name)
-{
- ThreadObject *to = new ThreadObject_pthread(proc, param, thread == NULL, name);
- 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();
-}
-
-static pthread_t main_thread;
-
-void SetSelfAsMainThread()
-{
- main_thread = pthread_self();
-}
-
-bool IsMainThread()
-{
- return main_thread == pthread_self();
-}
-
-bool IsNonMainThread()
-{
- return main_thread != pthread_self();
-}
-
-int GetThreadName(char *str, const char *last)
-{
-#if defined(__GLIBC__)
-#if __GLIBC_PREREQ(2, 12)
- char buffer[16];
- int result = pthread_getname_np(pthread_self(), buffer, sizeof(buffer));
- if (result == 0) {
- return seprintf(str, last, "%s", buffer);
- }
-#endif
-#endif
- return 0;
-}
diff --git a/src/thread/thread_win32.cpp b/src/thread/thread_win32.cpp
deleted file mode 100644
index 7f91cba6cd..0000000000
--- a/src/thread/thread_win32.cpp
+++ /dev/null
@@ -1,214 +0,0 @@
-/* $Id$ */
-
-/*
- * This file is part of OpenTTD.
- * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2.
- * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see .
- */
-
-/** @file thread_win32.cpp Win32 thread implementation of Threads. */
-
-#include "../stdafx.h"
-#include "thread.h"
-#include "../debug.h"
-#include "../core/alloc_func.hpp"
-#include "../scope.h"
-#include "../string_func.h"
-#include
-#include
-#include
-#include "../os/windows/win32.h"
-#include