Merge branches 'crashlog_improvements', 'save_ext' into jgrpp
# Conflicts: # Makefile.src.in # projects/openttd_vs140.vcxproj # projects/openttd_vs140.vcxproj.filters # projects/openttd_vs141.vcxproj # projects/openttd_vs141.vcxproj.filters # projects/openttd_vs142.vcxproj # projects/openttd_vs142.vcxproj.filters # src/core/smallstack_type.hpp # src/linkgraph/linkgraphjob.cpp # src/linkgraph/linkgraphjob.h # src/misc.cpp # src/network/network_udp.cpp # src/openttd.cpp # src/saveload/saveload.cpp
This commit is contained 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)
|
$(OBJS_MM:%.o=%.d): %.d: $(SRC_DIR)/%.mm $(FILE_DEP)
|
||||||
$(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.mm=%.mm)'
|
$(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)
|
$(OBJS_RC:%.o=%.d): %.d: $(SRC_DIR)/%.rc $(FILE_DEP)
|
||||||
$(E) '$(STAGE) DEP $(<:$(SRC_DIR)/%.rc=%.rc)'
|
$(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)
|
$(OBJS_MM): %.o: $(SRC_DIR)/%.mm $(DEP_MASK) $(FILE_DEP)
|
||||||
$(E) '$(STAGE) Compiling $(<:$(SRC_DIR)/%.mm=%.mm)'
|
$(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)
|
$(OBJS_RC): %.o: $(SRC_DIR)/%.rc $(FILE_DEP)
|
||||||
$(E) '$(STAGE) Compiling resource $(<:$(SRC_DIR)/%.rc=%.rc)'
|
$(E) '$(STAGE) Compiling resource $(<:$(SRC_DIR)/%.rc=%.rc)'
|
||||||
@@ -277,7 +277,7 @@ endif
|
|||||||
|
|
||||||
# Revision files
|
# 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
|
$(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
|
$(SRC_DIR)/os/windows/ottdres.rc: $(CONFIG_CACHE_VERSION) $(SRC_DIR)/os/windows/ottdres.rc.in
|
||||||
|
@@ -10,7 +10,6 @@
|
|||||||
<ProjectName>generate</ProjectName>
|
<ProjectName>generate</ProjectName>
|
||||||
<ProjectGuid>{2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}</ProjectGuid>
|
<ProjectGuid>{2F31FD79-D1AC-43C4-89F3-B0D5E4E53E34}</ProjectGuid>
|
||||||
<RootNamespace>generate</RootNamespace>
|
<RootNamespace>generate</RootNamespace>
|
||||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
@@ -1389,8 +1389,7 @@
|
|||||||
<ResourceCompile Include="..\src\os\windows\ottdres.rc" />
|
<ResourceCompile Include="..\src\os\windows\ottdres.rc" />
|
||||||
<ClCompile Include="..\src\os\windows\string_uniscribe.cpp" />
|
<ClCompile Include="..\src\os\windows\string_uniscribe.cpp" />
|
||||||
<ClCompile Include="..\src\os\windows\win32.cpp" />
|
<ClCompile Include="..\src\os\windows\win32.cpp" />
|
||||||
<ClInclude Include="..\src\thread\thread.h" />
|
<ClInclude Include="..\src\thread.h" />
|
||||||
<ClCompile Include="..\src\thread\thread_win32.cpp" />
|
|
||||||
<ClInclude Include="..\src\tracerestrict.h" />
|
<ClInclude Include="..\src\tracerestrict.h" />
|
||||||
<ClCompile Include="..\src\tracerestrict.cpp" />
|
<ClCompile Include="..\src\tracerestrict.cpp" />
|
||||||
<ClCompile Include="..\src\tracerestrict_gui.cpp" />
|
<ClCompile Include="..\src\tracerestrict_gui.cpp" />
|
||||||
|
@@ -3258,12 +3258,9 @@
|
|||||||
<ClCompile Include="..\src\os\windows\win32.cpp">
|
<ClCompile Include="..\src\os\windows\win32.cpp">
|
||||||
<Filter>Windows files</Filter>
|
<Filter>Windows files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClInclude Include="..\src\thread\thread.h">
|
<ClInclude Include="..\src\thread.h">
|
||||||
<Filter>Threading</Filter>
|
<Filter>Threading</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClCompile Include="..\src\thread\thread_win32.cpp">
|
|
||||||
<Filter>Threading</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClInclude Include="..\src\tracerestrict.h">
|
<ClInclude Include="..\src\tracerestrict.h">
|
||||||
<Filter>Threading</Filter>
|
<Filter>Threading</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@@ -1389,8 +1389,7 @@
|
|||||||
<ResourceCompile Include="..\src\os\windows\ottdres.rc" />
|
<ResourceCompile Include="..\src\os\windows\ottdres.rc" />
|
||||||
<ClCompile Include="..\src\os\windows\string_uniscribe.cpp" />
|
<ClCompile Include="..\src\os\windows\string_uniscribe.cpp" />
|
||||||
<ClCompile Include="..\src\os\windows\win32.cpp" />
|
<ClCompile Include="..\src\os\windows\win32.cpp" />
|
||||||
<ClInclude Include="..\src\thread\thread.h" />
|
<ClInclude Include="..\src\thread.h" />
|
||||||
<ClCompile Include="..\src\thread\thread_win32.cpp" />
|
|
||||||
<ClInclude Include="..\src\tracerestrict.h" />
|
<ClInclude Include="..\src\tracerestrict.h" />
|
||||||
<ClCompile Include="..\src\tracerestrict.cpp" />
|
<ClCompile Include="..\src\tracerestrict.cpp" />
|
||||||
<ClCompile Include="..\src\tracerestrict_gui.cpp" />
|
<ClCompile Include="..\src\tracerestrict_gui.cpp" />
|
||||||
|
@@ -3258,12 +3258,9 @@
|
|||||||
<ClCompile Include="..\src\os\windows\win32.cpp">
|
<ClCompile Include="..\src\os\windows\win32.cpp">
|
||||||
<Filter>Windows files</Filter>
|
<Filter>Windows files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClInclude Include="..\src\thread\thread.h">
|
<ClInclude Include="..\src\thread.h">
|
||||||
<Filter>Threading</Filter>
|
<Filter>Threading</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClCompile Include="..\src\thread\thread_win32.cpp">
|
|
||||||
<Filter>Threading</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClInclude Include="..\src\tracerestrict.h">
|
<ClInclude Include="..\src\tracerestrict.h">
|
||||||
<Filter>Threading</Filter>
|
<Filter>Threading</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@@ -1389,8 +1389,7 @@
|
|||||||
<ResourceCompile Include="..\src\os\windows\ottdres.rc" />
|
<ResourceCompile Include="..\src\os\windows\ottdres.rc" />
|
||||||
<ClCompile Include="..\src\os\windows\string_uniscribe.cpp" />
|
<ClCompile Include="..\src\os\windows\string_uniscribe.cpp" />
|
||||||
<ClCompile Include="..\src\os\windows\win32.cpp" />
|
<ClCompile Include="..\src\os\windows\win32.cpp" />
|
||||||
<ClInclude Include="..\src\thread\thread.h" />
|
<ClInclude Include="..\src\thread.h" />
|
||||||
<ClCompile Include="..\src\thread\thread_win32.cpp" />
|
|
||||||
<ClInclude Include="..\src\tracerestrict.h" />
|
<ClInclude Include="..\src\tracerestrict.h" />
|
||||||
<ClCompile Include="..\src\tracerestrict.cpp" />
|
<ClCompile Include="..\src\tracerestrict.cpp" />
|
||||||
<ClCompile Include="..\src\tracerestrict_gui.cpp" />
|
<ClCompile Include="..\src\tracerestrict_gui.cpp" />
|
||||||
|
@@ -3258,12 +3258,9 @@
|
|||||||
<ClCompile Include="..\src\os\windows\win32.cpp">
|
<ClCompile Include="..\src\os\windows\win32.cpp">
|
||||||
<Filter>Windows files</Filter>
|
<Filter>Windows files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
<ClInclude Include="..\src\thread\thread.h">
|
<ClInclude Include="..\src\thread.h">
|
||||||
<Filter>Threading</Filter>
|
<Filter>Threading</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
<ClCompile Include="..\src\thread\thread_win32.cpp">
|
|
||||||
<Filter>Threading</Filter>
|
|
||||||
</ClCompile>
|
|
||||||
<ClInclude Include="..\src\tracerestrict.h">
|
<ClInclude Include="..\src\tracerestrict.h">
|
||||||
<Filter>Threading</Filter>
|
<Filter>Threading</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
@@ -10,7 +10,6 @@
|
|||||||
<ProjectName>settingsgen</ProjectName>
|
<ProjectName>settingsgen</ProjectName>
|
||||||
<ProjectGuid>{E9548DE9-F089-49B7-93A6-30BE2CC311C7}</ProjectGuid>
|
<ProjectGuid>{E9548DE9-F089-49B7-93A6-30BE2CC311C7}</ProjectGuid>
|
||||||
<RootNamespace>settings</RootNamespace>
|
<RootNamespace>settings</RootNamespace>
|
||||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
@@ -10,7 +10,6 @@
|
|||||||
<ProjectName>strgen</ProjectName>
|
<ProjectName>strgen</ProjectName>
|
||||||
<ProjectGuid>{A133A442-BD0A-4ADE-B117-AD7545E4BDD1}</ProjectGuid>
|
<ProjectGuid>{A133A442-BD0A-4ADE-B117-AD7545E4BDD1}</ProjectGuid>
|
||||||
<RootNamespace>strgen</RootNamespace>
|
<RootNamespace>strgen</RootNamespace>
|
||||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||||
|
15
source.list
15
source.list
@@ -1229,20 +1229,7 @@ sound/null_s.cpp
|
|||||||
#end
|
#end
|
||||||
|
|
||||||
# Threading
|
# Threading
|
||||||
thread/thread.h
|
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
|
|
||||||
|
|
||||||
tracerestrict.h
|
tracerestrict.h
|
||||||
tracerestrict.cpp
|
tracerestrict.cpp
|
||||||
|
@@ -1282,7 +1282,7 @@ struct AIDebugWindow : public Window {
|
|||||||
case WID_AID_RELOAD_TOGGLE:
|
case WID_AID_RELOAD_TOGGLE:
|
||||||
if (ai_debug_company == OWNER_DEITY) break;
|
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 */
|
/* 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);
|
DoCommandP(0, CCA_NEW_AI | ai_debug_company << 16, 0, CMD_COMPANY_CTRL);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@@ -815,10 +815,9 @@ void CompanyAdminRemove(CompanyID company_id, CompanyRemoveReason reason)
|
|||||||
* @param flags operation to perform
|
* @param flags operation to perform
|
||||||
* @param p1 various functionality
|
* @param p1 various functionality
|
||||||
* - bits 0..15: CompanyCtrlAction
|
* - bits 0..15: CompanyCtrlAction
|
||||||
* - bits 16..24: CompanyID
|
* - bits 16..23: CompanyID
|
||||||
* @param p2 various depending on CompanyCtrlAction
|
* - bits 24..31: CompanyRemoveReason (with CCA_DELETE)
|
||||||
* - bits 0..31: ClientID (with CCA_NEW)
|
* @param p2 ClientID
|
||||||
* - bits 0..1: CompanyRemoveReason (with CCA_DELETE)
|
|
||||||
* @param text unused
|
* @param text unused
|
||||||
* @return the cost of this operation or an error
|
* @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
|
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;
|
if (reason >= CRR_END) return CMD_ERROR;
|
||||||
|
|
||||||
Company *c = Company::GetIfValid(company_id);
|
Company *c = Company::GetIfValid(company_id);
|
||||||
|
@@ -828,7 +828,7 @@ DEF_CONSOLE_CMD(ConResetCompany)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* It is safe to remove this company */
|
/* 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.");
|
IConsolePrint(CC_DEFAULT, "Company deleted.");
|
||||||
|
|
||||||
return true;
|
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 */
|
/* 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);
|
DoCommandP(0, CCA_NEW_AI | company_id << 16, 0, CMD_COMPANY_CTRL);
|
||||||
IConsolePrint(CC_DEFAULT, "AI reloaded.");
|
IConsolePrint(CC_DEFAULT, "AI reloaded.");
|
||||||
|
|
||||||
@@ -1240,7 +1240,7 @@ DEF_CONSOLE_CMD(ConStopAI)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Now kill the company of the AI. */
|
/* 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.");
|
IConsolePrint(CC_DEFAULT, "AI stopped, company deleted.");
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@@ -31,7 +31,7 @@
|
|||||||
#include "news_gui.h"
|
#include "news_gui.h"
|
||||||
#include "scope_info.h"
|
#include "scope_info.h"
|
||||||
#include "command_func.h"
|
#include "command_func.h"
|
||||||
#include "thread/thread.h"
|
#include "thread.h"
|
||||||
|
|
||||||
#include "ai/ai_info.hpp"
|
#include "ai/ai_info.hpp"
|
||||||
#include "game/game.hpp"
|
#include "game/game.hpp"
|
||||||
@@ -394,7 +394,7 @@ char *CrashLog::FillCrashLog(char *buffer, const char *last) const
|
|||||||
|
|
||||||
if (IsNonMainThread()) {
|
if (IsNonMainThread()) {
|
||||||
buffer += seprintf(buffer, last, "Non-main thread (");
|
buffer += seprintf(buffer, last, "Non-main thread (");
|
||||||
buffer += GetThreadName(buffer, last);
|
buffer += GetCurrentThreadName(buffer, last);
|
||||||
buffer += seprintf(buffer, last, ")\n\n");
|
buffer += seprintf(buffer, last, ")\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -672,7 +672,7 @@ static void CompanyCheckBankrupt(Company *c)
|
|||||||
* that changing the current company is okay. In case of single
|
* that changing the current company is okay. In case of single
|
||||||
* player we are sure (the above check) that we are not the local
|
* player we are sure (the above check) that we are not the local
|
||||||
* company and thus we won't be moved. */
|
* 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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -34,6 +34,7 @@
|
|||||||
#include "game/game.hpp"
|
#include "game/game.hpp"
|
||||||
#include "game/game_instance.hpp"
|
#include "game/game_instance.hpp"
|
||||||
#include "string_func.h"
|
#include "string_func.h"
|
||||||
|
#include "thread.h"
|
||||||
|
|
||||||
#include "safeguards.h"
|
#include "safeguards.h"
|
||||||
|
|
||||||
@@ -93,14 +94,15 @@ static void CleanupGeneration()
|
|||||||
/**
|
/**
|
||||||
* The internal, real, generate function.
|
* The internal, real, generate function.
|
||||||
*/
|
*/
|
||||||
static void _GenerateWorld(void *)
|
static void _GenerateWorld()
|
||||||
{
|
{
|
||||||
/* Make sure everything is done via OWNER_NONE. */
|
/* Make sure everything is done via OWNER_NONE. */
|
||||||
Backup<CompanyByte> _cur_company(_current_company, OWNER_NONE, FILE_LINE);
|
Backup<CompanyByte> _cur_company(_current_company, OWNER_NONE, FILE_LINE);
|
||||||
|
|
||||||
|
std::unique_lock<std::mutex> lock(_modal_progress_work_mutex, std::defer_lock);
|
||||||
try {
|
try {
|
||||||
_generating_world = true;
|
_generating_world = true;
|
||||||
_modal_progress_work_mutex->BeginCritical();
|
lock.lock();
|
||||||
if (_network_dedicated) DEBUG(net, 1, "Generating map, please wait...");
|
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 */
|
/* 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();
|
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);
|
IncreaseGeneratingWorldProgress(GWP_GAME_START);
|
||||||
|
|
||||||
CleanupGeneration();
|
CleanupGeneration();
|
||||||
_modal_progress_work_mutex->EndCritical();
|
lock.unlock();
|
||||||
|
|
||||||
ShowNewGRFError();
|
ShowNewGRFError();
|
||||||
|
|
||||||
@@ -215,7 +217,6 @@ static void _GenerateWorld(void *)
|
|||||||
BasePersistentStorageArray::SwitchMode(PSM_LEAVE_GAMELOOP, true);
|
BasePersistentStorageArray::SwitchMode(PSM_LEAVE_GAMELOOP, true);
|
||||||
if (_cur_company.IsValid()) _cur_company.Restore();
|
if (_cur_company.IsValid()) _cur_company.Restore();
|
||||||
_generating_world = false;
|
_generating_world = false;
|
||||||
_modal_progress_work_mutex->EndCritical();
|
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -246,17 +247,15 @@ void GenerateWorldSetAbortCallback(GWAbortProc *proc)
|
|||||||
*/
|
*/
|
||||||
void WaitTillGeneratedWorld()
|
void WaitTillGeneratedWorld()
|
||||||
{
|
{
|
||||||
if (_gw.thread == NULL) return;
|
if (!_gw.thread.joinable()) return;
|
||||||
|
|
||||||
_modal_progress_work_mutex->EndCritical();
|
_modal_progress_work_mutex.unlock();
|
||||||
_modal_progress_paint_mutex->EndCritical();
|
_modal_progress_paint_mutex.unlock();
|
||||||
_gw.quit_thread = true;
|
_gw.quit_thread = true;
|
||||||
_gw.thread->Join();
|
_gw.thread.join();
|
||||||
delete _gw.thread;
|
|
||||||
_gw.thread = NULL;
|
|
||||||
_gw.threaded = false;
|
_gw.threaded = false;
|
||||||
_modal_progress_work_mutex->BeginCritical();
|
_modal_progress_work_mutex.lock();
|
||||||
_modal_progress_paint_mutex->BeginCritical();
|
_modal_progress_paint_mutex.lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -288,7 +287,7 @@ void HandleGeneratingWorldAbortion()
|
|||||||
|
|
||||||
CleanupGeneration();
|
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);
|
SwitchToMode(_switch_mode);
|
||||||
}
|
}
|
||||||
@@ -330,18 +329,14 @@ void GenerateWorld(GenWorldMode mode, uint size_x, uint size_y, bool reset_setti
|
|||||||
SetupColoursAndInitialWindow();
|
SetupColoursAndInitialWindow();
|
||||||
SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0);
|
SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0);
|
||||||
|
|
||||||
if (_gw.thread != NULL) {
|
if (_gw.thread.joinable()) _gw.thread.join();
|
||||||
_gw.thread->Join();
|
|
||||||
delete _gw.thread;
|
|
||||||
_gw.thread = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
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");
|
DEBUG(misc, 1, "Cannot create genworld thread, reverting to single-threaded mode");
|
||||||
_gw.threaded = false;
|
_gw.threaded = false;
|
||||||
_modal_progress_work_mutex->EndCritical();
|
_modal_progress_work_mutex.unlock();
|
||||||
_GenerateWorld(NULL);
|
_GenerateWorld();
|
||||||
_modal_progress_work_mutex->BeginCritical();
|
_modal_progress_work_mutex.lock();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
#define GENWORLD_H
|
#define GENWORLD_H
|
||||||
|
|
||||||
#include "company_type.h"
|
#include "company_type.h"
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
/** Constants related to world generation */
|
/** Constants related to world generation */
|
||||||
enum LandscapeGenerator {
|
enum LandscapeGenerator {
|
||||||
@@ -61,7 +62,7 @@ struct GenWorldInfo {
|
|||||||
uint size_y; ///< Y-size of the map
|
uint size_y; ///< Y-size of the map
|
||||||
GWDoneProc *proc; ///< Proc that is called when done (can be NULL)
|
GWDoneProc *proc; ///< Proc that is called when done (can be NULL)
|
||||||
GWAbortProc *abortp; ///< Proc that is called when aborting (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 */
|
/** Current stage of world generation process */
|
||||||
|
@@ -1377,10 +1377,10 @@ static void _SetGeneratingWorldProgress(GenWorldProgress cls, uint progress, uin
|
|||||||
* paint thread. The 'other' thread already has the paint thread rights so
|
* 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
|
* this ensures us that we are waiting until the paint thread is done
|
||||||
* before we reacquire the mapgen rights */
|
* before we reacquire the mapgen rights */
|
||||||
_modal_progress_work_mutex->EndCritical();
|
_modal_progress_work_mutex.unlock();
|
||||||
_modal_progress_paint_mutex->BeginCritical();
|
_modal_progress_paint_mutex.lock();
|
||||||
_modal_progress_work_mutex->BeginCritical();
|
_modal_progress_work_mutex.lock();
|
||||||
_modal_progress_paint_mutex->EndCritical();
|
_modal_progress_paint_mutex.unlock();
|
||||||
|
|
||||||
_gws.timer = _realtime_tick;
|
_gws.timer = _realtime_tick;
|
||||||
}
|
}
|
||||||
|
@@ -21,6 +21,7 @@
|
|||||||
#include "network/network_func.h"
|
#include "network/network_func.h"
|
||||||
#include "window_func.h"
|
#include "window_func.h"
|
||||||
#include "newgrf_debug.h"
|
#include "newgrf_debug.h"
|
||||||
|
#include "thread.h"
|
||||||
|
|
||||||
#include "table/palettes.h"
|
#include "table/palettes.h"
|
||||||
#include "table/string_colours.h"
|
#include "table/string_colours.h"
|
||||||
@@ -1311,8 +1312,8 @@ void DrawDirtyBlocks()
|
|||||||
if (HasModalProgress()) {
|
if (HasModalProgress()) {
|
||||||
/* We are generating the world, so release our rights to the map and
|
/* We are generating the world, so release our rights to the map and
|
||||||
* painting while we are waiting a bit. */
|
* painting while we are waiting a bit. */
|
||||||
_modal_progress_paint_mutex->EndCritical();
|
_modal_progress_paint_mutex.unlock();
|
||||||
_modal_progress_work_mutex->EndCritical();
|
_modal_progress_work_mutex.unlock();
|
||||||
|
|
||||||
/* Wait a while and update _realtime_tick so we are given the rights */
|
/* Wait a while and update _realtime_tick so we are given the rights */
|
||||||
if (!IsFirstModalProgressLoop()) CSleep(MODAL_PROGRESS_REDRAW_TIMEOUT);
|
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. */
|
/* Modal progress thread may need blitter access while we are waiting for it. */
|
||||||
VideoDriver::GetInstance()->ReleaseBlitterLock();
|
VideoDriver::GetInstance()->ReleaseBlitterLock();
|
||||||
_modal_progress_paint_mutex->BeginCritical();
|
_modal_progress_paint_mutex.lock();
|
||||||
VideoDriver::GetInstance()->AcquireBlitterLock();
|
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.
|
/* When we ended with the modal progress, do not draw the blocks.
|
||||||
* Simply let the next run do so, otherwise we would be loading
|
* Simply let the next run do so, otherwise we would be loading
|
||||||
|
@@ -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 HandleTextInput(const char *str, bool marked = false, const char *caret = NULL, const char *insert_location = NULL, const char *replacement_end = NULL);
|
||||||
void HandleCtrlChanged();
|
void HandleCtrlChanged();
|
||||||
void HandleMouseEvents();
|
void HandleMouseEvents();
|
||||||
void CSleep(int milliseconds);
|
|
||||||
void UpdateWindows();
|
void UpdateWindows();
|
||||||
|
|
||||||
void DrawMouseCursor();
|
void DrawMouseCursor();
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
#ifndef LINKGRAPHJOB_H
|
#ifndef LINKGRAPHJOB_H
|
||||||
#define LINKGRAPHJOB_H
|
#define LINKGRAPHJOB_H
|
||||||
|
|
||||||
#include "../thread/thread.h"
|
#include "../thread.h"
|
||||||
#include "../core/dyn_arena_alloc.hpp"
|
#include "../core/dyn_arena_alloc.hpp"
|
||||||
#include "linkgraph.h"
|
#include "linkgraph.h"
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@@ -142,13 +142,11 @@ void LinkGraphSchedule::JoinNext()
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Run all handlers for the given Job. This method is tailored to
|
* Run all handlers for the given Job.
|
||||||
* ThreadObject::New.
|
* @param job Pointer to a link graph job.
|
||||||
* @param j 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) {
|
for (uint i = 0; i < lengthof(instance.handlers); ++i) {
|
||||||
if (job->IsJobAborted()) return;
|
if (job->IsJobAborted()) return;
|
||||||
instance.handlers[i]->Run(*job);
|
instance.handlers[i]->Run(*job);
|
||||||
@@ -232,20 +230,17 @@ LinkGraphSchedule::~LinkGraphSchedule()
|
|||||||
LinkGraphJobGroup::LinkGraphJobGroup(constructor_token token, std::vector<LinkGraphJob *> jobs) :
|
LinkGraphJobGroup::LinkGraphJobGroup(constructor_token token, std::vector<LinkGraphJob *> jobs) :
|
||||||
jobs(std::move(jobs)) { }
|
jobs(std::move(jobs)) { }
|
||||||
|
|
||||||
void LinkGraphJobGroup::SpawnThread() {
|
void LinkGraphJobGroup::SpawnThread()
|
||||||
ThreadObject *t = nullptr;
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spawn a thread if possible and run the link graph job in the thread. If
|
* 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.
|
* that's not possible run the job right now in the current thread.
|
||||||
*/
|
*/
|
||||||
if (ThreadObject::New(&(LinkGraphJobGroup::Run), this, &t, "ottd:linkgraph")) {
|
if (StartNewThread(&this->thread, "ottd:linkgraph", &(LinkGraphJobGroup::Run), this)) {
|
||||||
this->thread.reset(t);
|
|
||||||
for (auto &it : this->jobs) {
|
for (auto &it : this->jobs) {
|
||||||
it->SetJobGroup(this->shared_from_this());
|
it->SetJobGroup(this->shared_from_this());
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
this->thread.reset();
|
|
||||||
/* Of course this will hang a bit.
|
/* Of course this will hang a bit.
|
||||||
* On the other hand, if you want to play games which make this hang noticably
|
* 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.
|
* on a platform without threads then you'll probably get other problems first.
|
||||||
@@ -257,10 +252,11 @@ void LinkGraphJobGroup::SpawnThread() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LinkGraphJobGroup::JoinThread() {
|
void LinkGraphJobGroup::JoinThread()
|
||||||
if (!this->thread || this->joined_thread) return;
|
{
|
||||||
this->thread->Join();
|
if (this->thread.joinable()) {
|
||||||
this->joined_thread = true;
|
this->thread.join();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
#ifndef LINKGRAPHSCHEDULE_H
|
#ifndef LINKGRAPHSCHEDULE_H
|
||||||
#define LINKGRAPHSCHEDULE_H
|
#define LINKGRAPHSCHEDULE_H
|
||||||
|
|
||||||
#include "../thread/thread.h"
|
#include "../thread.h"
|
||||||
#include "linkgraph.h"
|
#include "linkgraph.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
@@ -55,7 +55,7 @@ public:
|
|||||||
static const uint SPAWN_JOIN_TICK = 21; ///< Tick when jobs are spawned or joined every day.
|
static const uint SPAWN_JOIN_TICK = 21; ///< Tick when jobs are spawned or joined every day.
|
||||||
static LinkGraphSchedule instance;
|
static LinkGraphSchedule instance;
|
||||||
|
|
||||||
static void Run(void *j);
|
static void Run(LinkGraphJob *job);
|
||||||
static void Clear();
|
static void Clear();
|
||||||
|
|
||||||
void SpawnNext();
|
void SpawnNext();
|
||||||
@@ -85,8 +85,7 @@ class LinkGraphJobGroup : public std::enable_shared_from_this<LinkGraphJobGroup>
|
|||||||
friend LinkGraphJob;
|
friend LinkGraphJob;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool joined_thread = false; ///< True if thread has already been joined
|
std::thread thread; ///< Thread the job group is running in or NULL if it's running in the main thread.
|
||||||
std::unique_ptr<ThreadObject> thread; ///< Thread the job group is running in or NULL if it's running in the main thread.
|
|
||||||
const std::vector<LinkGraphJob *> jobs; ///< The set of jobs in this job set
|
const std::vector<LinkGraphJob *> jobs; ///< The set of jobs in this job set
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
#include "../debug.h"
|
#include "../debug.h"
|
||||||
#include "../os/windows/win32.h"
|
#include "../os/windows/win32.h"
|
||||||
#include "../core/mem_func.hpp"
|
#include "../core/mem_func.hpp"
|
||||||
#include "../thread/thread.h"
|
#include "../thread.h"
|
||||||
#include "../fileio_func.h"
|
#include "../fileio_func.h"
|
||||||
#include "../base_media_base.h"
|
#include "../base_media_base.h"
|
||||||
#include "dmusic.h"
|
#include "dmusic.h"
|
||||||
@@ -30,6 +30,7 @@
|
|||||||
#include <dmksctrl.h>
|
#include <dmksctrl.h>
|
||||||
#include <dmusicc.h>
|
#include <dmusicc.h>
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include "../safeguards.h"
|
#include "../safeguards.h"
|
||||||
|
|
||||||
@@ -138,11 +139,11 @@ static struct {
|
|||||||
} _playback;
|
} _playback;
|
||||||
|
|
||||||
/** Handle to our worker thread. */
|
/** 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. */
|
/** Event to signal the thread that it should look at a state change. */
|
||||||
static HANDLE _thread_event = NULL;
|
static HANDLE _thread_event = NULL;
|
||||||
/** Lock access to playback data that is not thread-safe. */
|
/** 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. */
|
/** The direct music object manages buffers and ports. */
|
||||||
static IDirectMusic *_music = NULL;
|
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));
|
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");
|
DEBUG(driver, 2, "DMusic: Entering playback thread");
|
||||||
|
|
||||||
@@ -655,7 +656,7 @@ static void MidiThreadProc(void *)
|
|||||||
DEBUG(driver, 2, "DMusic thread: Starting playback");
|
DEBUG(driver, 2, "DMusic thread: Starting playback");
|
||||||
{
|
{
|
||||||
/* New scope to limit the time the mutex is locked. */
|
/* 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);
|
current_file.MoveFrom(_playback.next_file);
|
||||||
std::swap(_playback.next_segment, current_segment);
|
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. */
|
/* Create playback thread and synchronization primitives. */
|
||||||
_thread_event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
_thread_event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||||
if (_thread_event == NULL) return "Can't create thread shutdown event";
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1184,10 +1183,10 @@ MusicDriver_DMusic::~MusicDriver_DMusic()
|
|||||||
|
|
||||||
void MusicDriver_DMusic::Stop()
|
void MusicDriver_DMusic::Stop()
|
||||||
{
|
{
|
||||||
if (_dmusic_thread != NULL) {
|
if (_dmusic_thread.joinable()) {
|
||||||
_playback.shutdown = true;
|
_playback.shutdown = true;
|
||||||
SetEvent(_thread_event);
|
SetEvent(_thread_event);
|
||||||
_dmusic_thread->Join();
|
_dmusic_thread.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unloaded any instruments we loaded. */
|
/* Unloaded any instruments we loaded. */
|
||||||
@@ -1223,7 +1222,6 @@ void MusicDriver_DMusic::Stop()
|
|||||||
}
|
}
|
||||||
|
|
||||||
CloseHandle(_thread_event);
|
CloseHandle(_thread_event);
|
||||||
delete _thread_mutex;
|
|
||||||
|
|
||||||
CoUninitialize();
|
CoUninitialize();
|
||||||
}
|
}
|
||||||
@@ -1231,7 +1229,7 @@ void MusicDriver_DMusic::Stop()
|
|||||||
|
|
||||||
void MusicDriver_DMusic::PlaySong(const MusicSongInfo &song)
|
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;
|
if (!_playback.next_file.LoadSong(song)) return;
|
||||||
|
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
#include "../gfx_func.h"
|
#include "../gfx_func.h"
|
||||||
#include "extmidi.h"
|
#include "extmidi.h"
|
||||||
#include "../base_media_base.h"
|
#include "../base_media_base.h"
|
||||||
|
#include "../thread.h"
|
||||||
#include "midifile.hpp"
|
#include "midifile.hpp"
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
|
@@ -63,7 +63,6 @@ public:
|
|||||||
*/
|
*/
|
||||||
class TCPConnecter {
|
class TCPConnecter {
|
||||||
private:
|
private:
|
||||||
class ThreadObject *thread; ///< Thread used to create the TCP connection
|
|
||||||
bool connected; ///< Whether we succeeded in making the connection
|
bool connected; ///< Whether we succeeded in making the connection
|
||||||
bool aborted; ///< Whether we bailed out (i.e. connection making failed)
|
bool aborted; ///< Whether we bailed out (i.e. connection making failed)
|
||||||
bool killed; ///< Whether we got killed
|
bool killed; ///< Whether we got killed
|
||||||
@@ -71,7 +70,7 @@ private:
|
|||||||
|
|
||||||
void Connect();
|
void Connect();
|
||||||
|
|
||||||
static void ThreadEntry(void *param);
|
static void ThreadEntry(TCPConnecter *param);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
/** Address we're connecting to */
|
/** Address we're connecting to */
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "../../stdafx.h"
|
#include "../../stdafx.h"
|
||||||
#include "../../thread/thread.h"
|
#include "../../thread.h"
|
||||||
|
|
||||||
#include "tcp.h"
|
#include "tcp.h"
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ TCPConnecter::TCPConnecter(const NetworkAddress &address) :
|
|||||||
address(address)
|
address(address)
|
||||||
{
|
{
|
||||||
_tcp_connecters.push_back(this);
|
_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();
|
this->Connect();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -53,9 +53,9 @@ void TCPConnecter::Connect()
|
|||||||
* Entry point for the new threads.
|
* Entry point for the new threads.
|
||||||
* @param param the TCPConnecter instance to call Connect on.
|
* @param param the TCPConnecter instance to call Connect on.
|
||||||
*/
|
*/
|
||||||
/* static */ void TCPConnecter::ThreadEntry(void *param)
|
/* static */ void TCPConnecter::ThreadEntry(TCPConnecter *param)
|
||||||
{
|
{
|
||||||
static_cast<TCPConnecter*>(param)->Connect();
|
param->Connect();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -30,6 +30,7 @@
|
|||||||
#include "network_base.h"
|
#include "network_base.h"
|
||||||
#include "network_client.h"
|
#include "network_client.h"
|
||||||
#include "../core/backup_type.hpp"
|
#include "../core/backup_type.hpp"
|
||||||
|
#include "../thread.h"
|
||||||
|
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
|
||||||
|
@@ -15,19 +15,17 @@
|
|||||||
#include "../stdafx.h"
|
#include "../stdafx.h"
|
||||||
#include "../debug.h"
|
#include "../debug.h"
|
||||||
#include "../window_func.h"
|
#include "../window_func.h"
|
||||||
#include "../thread/thread.h"
|
|
||||||
#include "network_internal.h"
|
#include "network_internal.h"
|
||||||
#include "network_udp.h"
|
#include "network_udp.h"
|
||||||
#include "network_gamelist.h"
|
#include "network_gamelist.h"
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
#include "../safeguards.h"
|
#include "../safeguards.h"
|
||||||
|
|
||||||
NetworkGameList *_network_game_list = NULL;
|
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. */
|
/** The games to insert when the GUI thread has time for us. */
|
||||||
static NetworkGameList *_network_game_delayed_insertion_list = NULL;
|
static std::atomic<NetworkGameList *> _network_game_delayed_insertion_list(NULL);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add a new item to the linked gamelist, but do it delayed in the next tick
|
* 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)
|
void NetworkGameListAddItemDelayed(NetworkGameList *item)
|
||||||
{
|
{
|
||||||
_network_game_list_mutex->BeginCritical();
|
item->next = _network_game_delayed_insertion_list.load(std::memory_order_relaxed);
|
||||||
item->next = _network_game_delayed_insertion_list;
|
while (!_network_game_delayed_insertion_list.compare_exchange_weak(item->next, item, std::memory_order_acq_rel)) {}
|
||||||
_network_game_delayed_insertion_list = item;
|
|
||||||
_network_game_list_mutex->EndCritical();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Perform the delayed (thread safe) insertion into the game list */
|
/** Perform the delayed (thread safe) insertion into the game list */
|
||||||
static void NetworkGameListHandleDelayedInsert()
|
static void NetworkGameListHandleDelayedInsert()
|
||||||
{
|
{
|
||||||
_network_game_list_mutex->BeginCritical();
|
while (true) {
|
||||||
while (_network_game_delayed_insertion_list != NULL) {
|
NetworkGameList *ins_item = _network_game_delayed_insertion_list.load(std::memory_order_relaxed);
|
||||||
NetworkGameList *ins_item = _network_game_delayed_insertion_list;
|
while (ins_item != NULL && !_network_game_delayed_insertion_list.compare_exchange_weak(ins_item, ins_item->next, std::memory_order_acq_rel)) {}
|
||||||
_network_game_delayed_insertion_list = ins_item->next;
|
if (ins_item == NULL) break; // No item left.
|
||||||
|
|
||||||
NetworkGameList *item = NetworkGameListAddItem(ins_item->address);
|
NetworkGameList *item = NetworkGameListAddItem(ins_item->address);
|
||||||
|
|
||||||
@@ -66,7 +62,6 @@ static void NetworkGameListHandleDelayedInsert()
|
|||||||
}
|
}
|
||||||
free(ins_item);
|
free(ins_item);
|
||||||
}
|
}
|
||||||
_network_game_list_mutex->EndCritical();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -30,6 +30,8 @@
|
|||||||
#include "../core/pool_func.hpp"
|
#include "../core/pool_func.hpp"
|
||||||
#include "../core/random_func.hpp"
|
#include "../core/random_func.hpp"
|
||||||
#include "../rev.h"
|
#include "../rev.h"
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
#include "../safeguards.h"
|
#include "../safeguards.h"
|
||||||
|
|
||||||
@@ -58,7 +60,8 @@ struct PacketWriter : SaveFilter {
|
|||||||
Packet *current; ///< The packet we're currently writing to.
|
Packet *current; ///< The packet we're currently writing to.
|
||||||
size_t total_size; ///< Total size of the compressed savegame.
|
size_t total_size; ///< Total size of the compressed savegame.
|
||||||
Packet *packets; ///< Packet queue of the savegame; send these "slowly" to the client.
|
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.
|
* 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)
|
PacketWriter(ServerNetworkGameSocketHandler *cs) : SaveFilter(NULL), cs(cs), current(NULL), total_size(0), packets(NULL)
|
||||||
{
|
{
|
||||||
this->mutex = ThreadMutex::New();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Make sure everything is cleaned up. */
|
/** Make sure everything is cleaned up. */
|
||||||
~PacketWriter()
|
~PacketWriter()
|
||||||
{
|
{
|
||||||
if (this->mutex != NULL) this->mutex->BeginCritical();
|
std::unique_lock<std::mutex> lock(this->mutex);
|
||||||
|
|
||||||
if (this->cs != NULL && this->mutex != NULL) {
|
if (this->cs != NULL) this->exit_sig.wait(lock);
|
||||||
this->mutex->WaitForSignal();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This must all wait until the Destroy function is called. */
|
/* This must all wait until the Destroy function is called. */
|
||||||
|
|
||||||
@@ -87,11 +87,6 @@ struct PacketWriter : SaveFilter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
delete this->current;
|
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()
|
void Destroy()
|
||||||
{
|
{
|
||||||
if (this->mutex != NULL) this->mutex->BeginCritical();
|
std::unique_lock<std::mutex> lock(this->mutex);
|
||||||
|
|
||||||
this->cs = NULL;
|
this->cs = NULL;
|
||||||
|
|
||||||
if (this->mutex != NULL) this->mutex->SendSignal();
|
this->exit_sig.notify_all();
|
||||||
|
lock.unlock();
|
||||||
if (this->mutex != NULL) this->mutex->EndCritical();
|
|
||||||
|
|
||||||
/* Make sure the saving is completely cancelled. Yes,
|
/* Make sure the saving is completely cancelled. Yes,
|
||||||
* we need to handle the save finish as well as the
|
* we need to handle the save finish as well as the
|
||||||
@@ -138,14 +132,12 @@ struct PacketWriter : SaveFilter {
|
|||||||
*/
|
*/
|
||||||
Packet *PopPacket()
|
Packet *PopPacket()
|
||||||
{
|
{
|
||||||
if (this->mutex != NULL) this->mutex->BeginCritical();
|
std::lock_guard<std::mutex> lock(this->mutex);
|
||||||
|
|
||||||
Packet *p = this->packets;
|
Packet *p = this->packets;
|
||||||
this->packets = p->next;
|
this->packets = p->next;
|
||||||
p->next = NULL;
|
p->next = NULL;
|
||||||
|
|
||||||
if (this->mutex != NULL) this->mutex->EndCritical();
|
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,7 +162,7 @@ struct PacketWriter : SaveFilter {
|
|||||||
|
|
||||||
if (this->current == NULL) this->current = new Packet(PACKET_SERVER_MAP_DATA);
|
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;
|
byte *bufe = buf + size;
|
||||||
while (buf != bufe) {
|
while (buf != bufe) {
|
||||||
@@ -185,8 +177,6 @@ struct PacketWriter : SaveFilter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->mutex != NULL) this->mutex->EndCritical();
|
|
||||||
|
|
||||||
this->total_size += size;
|
this->total_size += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -195,7 +185,7 @@ struct PacketWriter : SaveFilter {
|
|||||||
/* We want to abort the saving when the socket is closed. */
|
/* We want to abort the saving when the socket is closed. */
|
||||||
if (this->cs == NULL) SlError(STR_NETWORK_ERROR_LOSTCONNECTION);
|
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. */
|
/* Make sure the last packet is flushed. */
|
||||||
this->AppendQueue();
|
this->AppendQueue();
|
||||||
@@ -208,8 +198,6 @@ struct PacketWriter : SaveFilter {
|
|||||||
Packet *p = new Packet(PACKET_SERVER_MAP_SIZE);
|
Packet *p = new Packet(PACKET_SERVER_MAP_SIZE);
|
||||||
p->Send_uint32((uint32)this->total_size);
|
p->Send_uint32((uint32)this->total_size);
|
||||||
this->cs->NetworkTCPSocketHandler::SendPacket(p);
|
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? */
|
/* 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)) {
|
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 */
|
/* 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);
|
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? */
|
/* 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? */
|
/* 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) {
|
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 */
|
/* 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);
|
IConsolePrintF(CC_DEFAULT, "Auto-cleaned company #%d with no vehicles", c->index + 1);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@@ -14,7 +14,6 @@
|
|||||||
|
|
||||||
#include "network_internal.h"
|
#include "network_internal.h"
|
||||||
#include "core/tcp_listen.h"
|
#include "core/tcp_listen.h"
|
||||||
#include "../thread/thread.h"
|
|
||||||
|
|
||||||
class ServerNetworkGameSocketHandler;
|
class ServerNetworkGameSocketHandler;
|
||||||
/** Make the code look slightly nicer/simpler. */
|
/** Make the code look slightly nicer/simpler. */
|
||||||
|
@@ -24,11 +24,12 @@
|
|||||||
#include "network.h"
|
#include "network.h"
|
||||||
#include "../core/endian_func.hpp"
|
#include "../core/endian_func.hpp"
|
||||||
#include "../company_base.h"
|
#include "../company_base.h"
|
||||||
#include "../thread/thread.h"
|
#include "../thread.h"
|
||||||
#include "../rev.h"
|
#include "../rev.h"
|
||||||
#include "../newgrf_text.h"
|
#include "../newgrf_text.h"
|
||||||
#include "../strings_func.h"
|
#include "../strings_func.h"
|
||||||
#include "table/strings.h"
|
#include "table/strings.h"
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include "core/udp.h"
|
#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;
|
static const uint32 FIND_SERVER_EXTENDED_TOKEN = 0x2A49582A;
|
||||||
|
|
||||||
/** Mutex for all out threaded udp resolution and such. */
|
/** 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 */
|
/** Session key to register ourselves to the master server */
|
||||||
static uint64 _session_key = 0;
|
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_server_socket = NULL; ///< udp server socket
|
||||||
NetworkUDPSocketHandler *_udp_master_socket = NULL; ///< udp master 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()
|
static Packet PrepareUdpClientFindServerPacket()
|
||||||
{
|
{
|
||||||
Packet p(PACKET_UDP_CLIENT_FIND_SERVER);
|
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 needs_mutex Whether we need to acquire locks when sending the packet or not.
|
||||||
* @param manually Whether the address was entered manually.
|
* @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 */
|
/* Clear item in gamelist */
|
||||||
NetworkGameList *item = CallocT<NetworkGameList>(1);
|
NetworkGameList *item = CallocT<NetworkGameList>(1);
|
||||||
address->GetAddressAsString(item->info.server_name, lastof(item->info.server_name));
|
address.GetAddressAsString(item->info.server_name, lastof(item->info.server_name));
|
||||||
strecpy(item->info.hostname, address->GetHostname(), lastof(item->info.hostname));
|
strecpy(item->info.hostname, address.GetHostname(), lastof(item->info.hostname));
|
||||||
item->address = *address;
|
item->address = address;
|
||||||
item->manually = manually;
|
item->manually = manually;
|
||||||
NetworkGameListAddItemDelayed(item);
|
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 */
|
/* Init the packet */
|
||||||
Packet p = PrepareUdpClientFindServerPacket();
|
Packet p = PrepareUdpClientFindServerPacket();
|
||||||
if (_udp_client_socket != NULL) _udp_client_socket->SendPacket(&p, address);
|
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -120,9 +93,8 @@ static void NetworkUDPQueryServerThread(void *pntr)
|
|||||||
*/
|
*/
|
||||||
void NetworkUDPQueryServer(NetworkAddress address, bool manually)
|
void NetworkUDPQueryServer(NetworkAddress address, bool manually)
|
||||||
{
|
{
|
||||||
NetworkUDPQueryServerInfo *info = new NetworkUDPQueryServerInfo(address, manually);
|
if (address.IsResolved() || !StartNewThread(NULL, "ottd:udp-query", &DoNetworkUDPQueryServer, std::move(address), true, std::move(manually))) {
|
||||||
if (address.IsResolved() || !ThreadObject::New(NetworkUDPQueryServerThread, info, NULL, "ottd:udp-query")) {
|
DoNetworkUDPQueryServer(address, true, manually);
|
||||||
NetworkUDPQueryServerThread(info);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -510,7 +482,7 @@ void ClientNetworkUDPSocketHandler::Receive_MASTER_RESPONSE_LIST(Packet *p, Netw
|
|||||||
/* Somehow we reached the end of the packet */
|
/* Somehow we reached the end of the packet */
|
||||||
if (this->HasClientQuit()) return;
|
if (this->HasClientQuit()) return;
|
||||||
|
|
||||||
NetworkUDPQueryServer(&addr, false, false);
|
DoNetworkUDPQueryServer(addr, false, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -616,9 +588,8 @@ void NetworkUDPSearchGame()
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Thread entry point for de-advertising.
|
* 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");
|
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_uint8 (NETWORK_MASTER_SERVER_VERSION);
|
||||||
p.Send_uint16(_settings_client.network.server_port);
|
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);
|
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 */
|
/* Check if we are advertising */
|
||||||
if (!_networking || !_network_server || !_network_udp_server) return;
|
if (!_networking || !_network_server || !_network_udp_server) return;
|
||||||
|
|
||||||
if (blocking || !ThreadObject::New(NetworkUDPRemoveAdvertiseThread, NULL, NULL, "ottd:udp-advert")) {
|
if (blocking || !StartNewThread(NULL, "ottd:udp-advert", &NetworkUDPRemoveAdvertiseThread)) {
|
||||||
NetworkUDPRemoveAdvertiseThread(NULL);
|
NetworkUDPRemoveAdvertiseThread();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Thread entry point for advertising.
|
* Thread entry point for advertising.
|
||||||
* @param pntr unused.
|
|
||||||
*/
|
*/
|
||||||
static void NetworkUDPAdvertiseThread(void *pntr)
|
static void NetworkUDPAdvertiseThread()
|
||||||
{
|
{
|
||||||
/* Find somewhere to send */
|
/* Find somewhere to send */
|
||||||
NetworkAddress out_addr(NETWORK_MASTER_SERVER_HOST, NETWORK_MASTER_SERVER_PORT);
|
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_uint16(_settings_client.network.server_port);
|
||||||
p.Send_uint64(_session_key);
|
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);
|
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_advertisement < _last_advertisement) _next_advertisement = UINT32_MAX;
|
||||||
if (_next_retry < _last_advertisement) _next_retry = UINT32_MAX;
|
if (_next_retry < _last_advertisement) _next_retry = UINT32_MAX;
|
||||||
|
|
||||||
if (!ThreadObject::New(NetworkUDPAdvertiseThread, NULL, NULL, "ottd:udp-advert")) {
|
if (!StartNewThread(NULL, "ottd:udp-advert", &NetworkUDPAdvertiseThread)) {
|
||||||
NetworkUDPAdvertiseThread(NULL);
|
NetworkUDPAdvertiseThread();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -742,7 +710,7 @@ void NetworkUDPInitialize()
|
|||||||
DEBUG(net, 1, "[udp] initializing listeners");
|
DEBUG(net, 1, "[udp] initializing listeners");
|
||||||
assert(_udp_client_socket == NULL && _udp_server_socket == NULL && _udp_master_socket == NULL);
|
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();
|
_udp_client_socket = new ClientNetworkUDPSocketHandler();
|
||||||
|
|
||||||
@@ -756,13 +724,12 @@ void NetworkUDPInitialize()
|
|||||||
|
|
||||||
_network_udp_server = false;
|
_network_udp_server = false;
|
||||||
_network_udp_broadcast = 0;
|
_network_udp_broadcast = 0;
|
||||||
_network_udp_mutex->EndCritical();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Close all UDP related stuff. */
|
/** Close all UDP related stuff. */
|
||||||
void NetworkUDPClose()
|
void NetworkUDPClose()
|
||||||
{
|
{
|
||||||
_network_udp_mutex->BeginCritical();
|
std::lock_guard<std::mutex> lock(_network_udp_mutex);
|
||||||
_udp_server_socket->Close();
|
_udp_server_socket->Close();
|
||||||
_udp_master_socket->Close();
|
_udp_master_socket->Close();
|
||||||
_udp_client_socket->Close();
|
_udp_client_socket->Close();
|
||||||
@@ -772,7 +739,6 @@ void NetworkUDPClose()
|
|||||||
_udp_client_socket = NULL;
|
_udp_client_socket = NULL;
|
||||||
_udp_server_socket = NULL;
|
_udp_server_socket = NULL;
|
||||||
_udp_master_socket = NULL;
|
_udp_master_socket = NULL;
|
||||||
_network_udp_mutex->EndCritical();
|
|
||||||
|
|
||||||
_network_udp_server = false;
|
_network_udp_server = false;
|
||||||
_network_udp_broadcast = 0;
|
_network_udp_broadcast = 0;
|
||||||
@@ -782,7 +748,7 @@ void NetworkUDPClose()
|
|||||||
/** Receive the UDP packets. */
|
/** Receive the UDP packets. */
|
||||||
void NetworkBackgroundUDPLoop()
|
void NetworkBackgroundUDPLoop()
|
||||||
{
|
{
|
||||||
_network_udp_mutex->BeginCritical();
|
std::lock_guard<std::mutex> lock(_network_udp_mutex);
|
||||||
|
|
||||||
if (_network_udp_server) {
|
if (_network_udp_server) {
|
||||||
_udp_server_socket->ReceivePackets();
|
_udp_server_socket->ReceivePackets();
|
||||||
@@ -791,6 +757,4 @@ void NetworkBackgroundUDPLoop()
|
|||||||
_udp_client_socket->ReceivePackets();
|
_udp_client_socket->ReceivePackets();
|
||||||
if (_network_udp_broadcast > 0) _network_udp_broadcast--;
|
if (_network_udp_broadcast > 0) _network_udp_broadcast--;
|
||||||
}
|
}
|
||||||
|
|
||||||
_network_udp_mutex->EndCritical();
|
|
||||||
}
|
}
|
||||||
|
@@ -21,6 +21,8 @@
|
|||||||
#include "video/video_driver.hpp"
|
#include "video/video_driver.hpp"
|
||||||
#include "strings_func.h"
|
#include "strings_func.h"
|
||||||
#include "textfile_gui.h"
|
#include "textfile_gui.h"
|
||||||
|
#include "thread.h"
|
||||||
|
#include "newgrf_config.h"
|
||||||
|
|
||||||
#include "fileio_func.h"
|
#include "fileio_func.h"
|
||||||
#include "fios.h"
|
#include "fios.h"
|
||||||
@@ -684,18 +686,18 @@ bool GRFFileScanner::AddFile(const char *filename, size_t basepath_length, const
|
|||||||
|
|
||||||
this->num_scanned++;
|
this->num_scanned++;
|
||||||
if (this->next_update <= _realtime_tick) {
|
if (this->next_update <= _realtime_tick) {
|
||||||
_modal_progress_work_mutex->EndCritical();
|
_modal_progress_work_mutex.unlock();
|
||||||
_modal_progress_paint_mutex->BeginCritical();
|
_modal_progress_paint_mutex.lock();
|
||||||
|
|
||||||
const char *name = NULL;
|
const char *name = NULL;
|
||||||
if (c->name != NULL) name = GetGRFStringFromGRFText(c->name->text);
|
if (c->name != NULL) name = GetGRFStringFromGRFText(c->name->text);
|
||||||
if (name == NULL) name = c->filename;
|
if (name == NULL) name = c->filename;
|
||||||
UpdateNewGRFScanStatus(this->num_scanned, name);
|
UpdateNewGRFScanStatus(this->num_scanned, name);
|
||||||
|
|
||||||
_modal_progress_work_mutex->BeginCritical();
|
_modal_progress_work_mutex.lock();
|
||||||
_modal_progress_paint_mutex->EndCritical();
|
_modal_progress_paint_mutex.unlock();
|
||||||
|
|
||||||
this->next_update = _realtime_tick + 200;
|
this->next_update = _realtime_tick + MODAL_PROGRESS_REDRAW_TIMEOUT;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!added) {
|
if (!added) {
|
||||||
@@ -725,9 +727,9 @@ static int CDECL GRFSorter(GRFConfig * const *p1, GRFConfig * const *p2)
|
|||||||
* Really perform the scan for all NewGRFs.
|
* Really perform the scan for all NewGRFs.
|
||||||
* @param callback The callback to call after the scanning is complete.
|
* @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<std::mutex> lock_work(_modal_progress_work_mutex);
|
||||||
|
|
||||||
ClearGRFConfigList(&_all_grfs);
|
ClearGRFConfigList(&_all_grfs);
|
||||||
TarScanner::DoScan(TarScanner::NEWGRF);
|
TarScanner::DoScan(TarScanner::NEWGRF);
|
||||||
@@ -762,18 +764,17 @@ void DoScanNewGRFFiles(void *callback)
|
|||||||
NetworkAfterNewGRFScan();
|
NetworkAfterNewGRFScan();
|
||||||
}
|
}
|
||||||
|
|
||||||
_modal_progress_work_mutex->EndCritical();
|
lock_work.unlock();
|
||||||
_modal_progress_paint_mutex->BeginCritical();
|
std::lock_guard<std::mutex> lock_paint(_modal_progress_paint_mutex);
|
||||||
|
|
||||||
/* Yes... these are the NewGRF windows */
|
/* Yes... these are the NewGRF windows */
|
||||||
InvalidateWindowClassesData(WC_SAVELOAD, 0, true);
|
InvalidateWindowClassesData(WC_SAVELOAD, 0, true);
|
||||||
InvalidateWindowData(WC_GAME_OPTIONS, WN_GAME_OPTIONS_NEWGRF_STATE, GOID_NEWGRF_RESCANNED, 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);
|
DeleteWindowByClass(WC_MODAL_PROGRESS);
|
||||||
SetModalProgress(false);
|
SetModalProgress(false);
|
||||||
MarkWholeScreenDirty();
|
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!. */
|
/* Only then can we really start, especially by marking the whole screen dirty. Get those other windows hidden!. */
|
||||||
MarkWholeScreenDirty();
|
MarkWholeScreenDirty();
|
||||||
|
|
||||||
if (!VideoDriver::GetInstance()->HasGUI() || !ThreadObject::New(&DoScanNewGRFFiles, callback, NULL, "ottd:newgrf-scan")) {
|
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->EndCritical();
|
_modal_progress_work_mutex.unlock();
|
||||||
_modal_progress_paint_mutex->EndCritical();
|
_modal_progress_paint_mutex.unlock();
|
||||||
DoScanNewGRFFiles(callback);
|
DoScanNewGRFFiles(callback);
|
||||||
_modal_progress_paint_mutex->BeginCritical();
|
_modal_progress_paint_mutex.lock();
|
||||||
_modal_progress_work_mutex->BeginCritical();
|
_modal_progress_work_mutex.lock();
|
||||||
} else {
|
} else {
|
||||||
UpdateNewGRFScanStatus(0, NULL);
|
UpdateNewGRFScanStatus(0, NULL);
|
||||||
}
|
}
|
||||||
|
@@ -834,9 +834,10 @@ static void ChangeTileOwner_Object(TileIndex tile, Owner old_owner, Owner new_ow
|
|||||||
|
|
||||||
bool do_clear = false;
|
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);
|
SetTileOwner(tile, new_owner);
|
||||||
} else if (IsObjectType(tile, OBJECT_STATUE)) {
|
} else if (type == OBJECT_STATUE) {
|
||||||
Town *t = Object::GetByTile(tile)->town;
|
Town *t = Object::GetByTile(tile)->town;
|
||||||
ClrBit(t->statues, old_owner);
|
ClrBit(t->statues, old_owner);
|
||||||
if (new_owner != INVALID_OWNER && !HasBit(t->statues, new_owner)) {
|
if (new_owner != INVALID_OWNER && !HasBit(t->statues, new_owner)) {
|
||||||
|
@@ -68,7 +68,7 @@
|
|||||||
#include "programmable_signals.h"
|
#include "programmable_signals.h"
|
||||||
#include "smallmap_gui.h"
|
#include "smallmap_gui.h"
|
||||||
#include "viewport_func.h"
|
#include "viewport_func.h"
|
||||||
#include "thread/thread.h"
|
#include "thread.h"
|
||||||
#include "bridge_signal_map.h"
|
#include "bridge_signal_map.h"
|
||||||
#include "zoning.h"
|
#include "zoning.h"
|
||||||
#include "cargopacket.h"
|
#include "cargopacket.h"
|
||||||
@@ -77,6 +77,7 @@
|
|||||||
#include "tracerestrict.h"
|
#include "tracerestrict.h"
|
||||||
|
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
|
#include <system_error>
|
||||||
|
|
||||||
#include "safeguards.h"
|
#include "safeguards.h"
|
||||||
|
|
||||||
@@ -613,6 +614,9 @@ int openttd_main(int argc, char *argv[])
|
|||||||
extern bool _dedicated_forks;
|
extern bool _dedicated_forks;
|
||||||
_dedicated_forks = false;
|
_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;
|
_game_mode = GM_MENU;
|
||||||
_switch_mode = SM_MENU;
|
_switch_mode = SM_MENU;
|
||||||
_config_file = NULL;
|
_config_file = NULL;
|
||||||
@@ -897,8 +901,14 @@ int openttd_main(int argc, char *argv[])
|
|||||||
free(musicdriver);
|
free(musicdriver);
|
||||||
|
|
||||||
/* Take our initial lock on whatever we might want to do! */
|
/* Take our initial lock on whatever we might want to do! */
|
||||||
_modal_progress_paint_mutex->BeginCritical();
|
try {
|
||||||
_modal_progress_work_mutex->BeginCritical();
|
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
|
GenerateWorld(GWM_EMPTY, 64, 64); // Make the viewport initialization happy
|
||||||
WaitTillGeneratedWorld();
|
WaitTillGeneratedWorld();
|
||||||
@@ -916,6 +926,7 @@ int openttd_main(int argc, char *argv[])
|
|||||||
CrashLog::MainThreadExitCheckPendingCrashlog();
|
CrashLog::MainThreadExitCheckPendingCrashlog();
|
||||||
|
|
||||||
WaitTillSaved();
|
WaitTillSaved();
|
||||||
|
WaitTillGeneratedWorld(); // Make sure any generate world threads have been joined.
|
||||||
|
|
||||||
/* only save config if we have to */
|
/* only save config if we have to */
|
||||||
if (save_config) {
|
if (save_config) {
|
||||||
|
@@ -206,23 +206,6 @@ bool GetClipboardContents(char *buffer, const char *last)
|
|||||||
}
|
}
|
||||||
#endif
|
#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.
|
* Check if a font is a monospace font.
|
||||||
* @param name Name of the font.
|
* @param name Name of the font.
|
||||||
|
@@ -18,6 +18,7 @@
|
|||||||
#include "../../core/random_func.hpp"
|
#include "../../core/random_func.hpp"
|
||||||
#include "../../string_func.h"
|
#include "../../string_func.h"
|
||||||
#include "../../textbuf_gui.h"
|
#include "../../textbuf_gui.h"
|
||||||
|
#include "../../thread.h"
|
||||||
|
|
||||||
#include "table/strings.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 *FS2OTTD(const char *name) {return name;}
|
||||||
const char *OTTD2FS(const char *name) {return name;}
|
const char *OTTD2FS(const char *name) {return name;}
|
||||||
|
|
||||||
uint GetCPUCoreCount()
|
|
||||||
{
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OSOpenBrowser(const char *url)
|
void OSOpenBrowser(const char *url)
|
||||||
{
|
{
|
||||||
// stub only
|
// stub only
|
||||||
DEBUG(misc, 0, "Failed to open url: %s", url);
|
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; }
|
||||||
|
@@ -17,6 +17,7 @@
|
|||||||
#include "../../debug.h"
|
#include "../../debug.h"
|
||||||
#include "../../string_func.h"
|
#include "../../string_func.h"
|
||||||
#include "../../fios.h"
|
#include "../../fios.h"
|
||||||
|
#include "../../thread.h"
|
||||||
|
|
||||||
|
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
@@ -43,11 +44,17 @@
|
|||||||
#include <sys/sysctl.h>
|
#include <sys/sysctl.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifndef NO_THREADS
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
#if defined(WITH_SDL)
|
# if defined(WITH_SDL)
|
||||||
/* the mac implementation needs this file included in the same file as main() */
|
/* the mac implementation needs this file included in the same file as main() */
|
||||||
#include <SDL.h>
|
# include <SDL.h>
|
||||||
#endif
|
# endif
|
||||||
|
|
||||||
|
# include "../macosx/macos.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "../../safeguards.h"
|
#include "../../safeguards.h"
|
||||||
@@ -266,44 +273,7 @@ bool GetClipboardContents(char *buffer, const char *last)
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/* multi os compatible sleep function */
|
|
||||||
|
|
||||||
void CSleep(int milliseconds)
|
|
||||||
{
|
|
||||||
usleep(milliseconds * 1000);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef __APPLE__
|
#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)
|
void OSOpenBrowser(const char *url)
|
||||||
{
|
{
|
||||||
pid_t child_pid = fork();
|
pid_t child_pid = fork();
|
||||||
@@ -317,4 +287,56 @@ void OSOpenBrowser(const char *url)
|
|||||||
DEBUG(misc, 0, "Failed to open url: %s", url);
|
DEBUG(misc, 0, "Failed to open url: %s", url);
|
||||||
exit(0);
|
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
|
||||||
|
#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
|
||||||
|
}
|
||||||
|
@@ -30,6 +30,7 @@
|
|||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include "../../language.h"
|
#include "../../language.h"
|
||||||
|
#include "../../thread.h"
|
||||||
|
|
||||||
#include "../../safeguards.h"
|
#include "../../safeguards.h"
|
||||||
|
|
||||||
@@ -81,7 +82,7 @@ void ShowOSErrorBox(const char *buf, bool system)
|
|||||||
{
|
{
|
||||||
_in_event_loop_post_crash = true;
|
_in_event_loop_post_crash = true;
|
||||||
MyShowCursor(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)
|
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.
|
* Convert to OpenTTD's encoding from that of the local environment.
|
||||||
* When the project is built in UNICODE, the system codepage is irrelevant and
|
* When the project is built in UNICODE, the system codepage is irrelevant and
|
||||||
@@ -733,14 +728,6 @@ const char *GetCurrentLocale(const char *)
|
|||||||
return retbuf;
|
return retbuf;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint GetCPUCoreCount()
|
|
||||||
{
|
|
||||||
SYSTEM_INFO info;
|
|
||||||
|
|
||||||
GetSystemInfo(&info);
|
|
||||||
return info.dwNumberOfProcessors;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
static WCHAR _cur_iso_locale[16] = L"";
|
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);
|
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<DWORD, std::string> _thread_name_map;
|
||||||
|
static std::mutex _thread_name_map_mutex;
|
||||||
|
|
||||||
|
static void Win32SetThreadName(uint id, const char *name)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> lock(_thread_name_map_mutex);
|
||||||
|
_thread_name_map[id] = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
int GetCurrentThreadName(char *str, const char *last)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> 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
|
#ifdef _MSC_VER
|
||||||
/* Based on code from MSDN: https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */
|
/* Based on code from MSDN: https://msdn.microsoft.com/en-us/library/xcb2z8hs.aspx */
|
||||||
const DWORD MS_VC_EXCEPTION = 0x406D1388;
|
const DWORD MS_VC_EXCEPTION = 0x406D1388;
|
||||||
@@ -819,12 +842,14 @@ PACK_N(struct THREADNAME_INFO {
|
|||||||
/**
|
/**
|
||||||
* Signal thread name to any attached debuggers.
|
* 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;
|
THREADNAME_INFO info;
|
||||||
info.dwType = 0x1000;
|
info.dwType = 0x1000;
|
||||||
info.szName = threadName;
|
info.szName = threadName;
|
||||||
info.dwThreadID = dwThreadID;
|
info.dwThreadID = -1;
|
||||||
info.dwFlags = 0;
|
info.dwFlags = 0;
|
||||||
|
|
||||||
#pragma warning(push)
|
#pragma warning(push)
|
||||||
@@ -835,4 +860,9 @@ void SetWin32ThreadName(DWORD dwThreadID, const char* threadName)
|
|||||||
}
|
}
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
}
|
}
|
||||||
|
#else
|
||||||
|
void SetCurrentThreadName(const char *)
|
||||||
|
{
|
||||||
|
Win32SetThreadName(GetCurrentThreadId(), threadName);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@@ -39,12 +39,6 @@ HRESULT OTTDSHGetFolderPath(HWND, int, HANDLE, DWORD, LPTSTR);
|
|||||||
#define SHGFP_TYPE_CURRENT 0
|
#define SHGFP_TYPE_CURRENT 0
|
||||||
#endif /* __MINGW32__ */
|
#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);
|
void Win32SetCurrentLocaleName(const char *iso_code);
|
||||||
int OTTDStringCompare(const char *s1, const char *s2);
|
int OTTDStringCompare(const char *s1, const char *s2);
|
||||||
|
|
||||||
|
@@ -10,17 +10,19 @@
|
|||||||
/** @file progress.cpp Functions for modal progress windows. */
|
/** @file progress.cpp Functions for modal progress windows. */
|
||||||
|
|
||||||
#include "stdafx.h"
|
#include "stdafx.h"
|
||||||
#include "thread/thread.h"
|
#include "progress.h"
|
||||||
|
|
||||||
#include "safeguards.h"
|
#include "safeguards.h"
|
||||||
|
|
||||||
/** Are we in a modal progress or not? */
|
/** Are we in a modal progress or not? */
|
||||||
bool _in_modal_progress = false;
|
bool _in_modal_progress = false;
|
||||||
bool _first_in_modal_loop = false;
|
bool _first_in_modal_loop = false;
|
||||||
|
/** Threading usable for modal progress? */
|
||||||
|
bool _use_threaded_modal_progress = true;
|
||||||
/** Rights for the performing work. */
|
/** Rights for the performing work. */
|
||||||
ThreadMutex *_modal_progress_work_mutex = ThreadMutex::New();
|
std::mutex _modal_progress_work_mutex;
|
||||||
/** Rights for the painting. */
|
/** Rights for the painting. */
|
||||||
ThreadMutex *_modal_progress_paint_mutex = ThreadMutex::New();
|
std::mutex _modal_progress_paint_mutex;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the modal progress state.
|
* Set the modal progress state.
|
||||||
|
@@ -12,7 +12,7 @@
|
|||||||
#ifndef PROGRESS_H
|
#ifndef PROGRESS_H
|
||||||
#define PROGRESS_H
|
#define PROGRESS_H
|
||||||
|
|
||||||
#include "thread/thread.h"
|
#include <mutex>
|
||||||
|
|
||||||
static const uint MODAL_PROGRESS_REDRAW_TIMEOUT = 200; ///< Timeout between redraws
|
static const uint MODAL_PROGRESS_REDRAW_TIMEOUT = 200; ///< Timeout between redraws
|
||||||
|
|
||||||
@@ -26,10 +26,20 @@ static inline bool HasModalProgress()
|
|||||||
return _in_modal_progress;
|
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();
|
bool IsFirstModalProgressLoop();
|
||||||
void SetModalProgress(bool state);
|
void SetModalProgress(bool state);
|
||||||
|
|
||||||
extern class ThreadMutex *_modal_progress_work_mutex;
|
extern std::mutex _modal_progress_work_mutex;
|
||||||
extern class ThreadMutex *_modal_progress_paint_mutex;
|
extern std::mutex _modal_progress_paint_mutex;
|
||||||
|
|
||||||
#endif /* PROGRESS_H */
|
#endif /* PROGRESS_H */
|
||||||
|
@@ -26,7 +26,7 @@
|
|||||||
#include "../debug.h"
|
#include "../debug.h"
|
||||||
#include "../station_base.h"
|
#include "../station_base.h"
|
||||||
#include "../dock_base.h"
|
#include "../dock_base.h"
|
||||||
#include "../thread/thread.h"
|
#include "../thread.h"
|
||||||
#include "../town.h"
|
#include "../town.h"
|
||||||
#include "../network/network.h"
|
#include "../network/network.h"
|
||||||
#include "../window_func.h"
|
#include "../window_func.h"
|
||||||
@@ -46,6 +46,7 @@
|
|||||||
#include "../string_func_extra.h"
|
#include "../string_func_extra.h"
|
||||||
#include "../fios.h"
|
#include "../fios.h"
|
||||||
#include "../error.h"
|
#include "../error.h"
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
#include "../tbtr_template_vehicle.h"
|
#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);
|
SlError(STR_GAME_SAVELOAD_ERROR_BROKEN_SAVEGAME, str, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef void (*AsyncSaveFinishProc)(); ///< Callback for when the savegame loading is finished.
|
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 std::atomic<AsyncSaveFinishProc> _async_save_finish; ///< Callback to call when the savegame loading is finished.
|
||||||
static ThreadObject *_save_thread; ///< The thread we're using to compress and write a savegame
|
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.
|
* 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)
|
static void SetAsyncSaveFinish(AsyncSaveFinishProc proc)
|
||||||
{
|
{
|
||||||
if (_exit_game) return;
|
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()
|
void ProcessAsyncSaveFinish()
|
||||||
{
|
{
|
||||||
if (_async_save_finish == NULL) return;
|
AsyncSaveFinishProc proc = _async_save_finish.exchange(NULL, std::memory_order_acq_rel);
|
||||||
|
if (proc == NULL) return;
|
||||||
|
|
||||||
_async_save_finish();
|
proc();
|
||||||
|
|
||||||
_async_save_finish = NULL;
|
if (_save_thread.joinable()) {
|
||||||
|
_save_thread.join();
|
||||||
if (_save_thread != NULL) {
|
|
||||||
_save_thread->Join();
|
|
||||||
delete _save_thread;
|
|
||||||
_save_thread = NULL;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -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()
|
void WaitTillSaved()
|
||||||
{
|
{
|
||||||
if (_save_thread == NULL) return;
|
if (!_save_thread.joinable()) return;
|
||||||
|
|
||||||
_save_thread->Join();
|
_save_thread.join();
|
||||||
delete _save_thread;
|
|
||||||
_save_thread = NULL;
|
|
||||||
|
|
||||||
/* Make sure every other state is handled properly as well. */
|
/* Make sure every other state is handled properly as well. */
|
||||||
ProcessAsyncSaveFinish();
|
ProcessAsyncSaveFinish();
|
||||||
@@ -2799,7 +2789,8 @@ static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
|
|||||||
SlSaveChunks();
|
SlSaveChunks();
|
||||||
|
|
||||||
SaveFileStart();
|
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...");
|
if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
|
||||||
|
|
||||||
SaveOrLoadResult result = SaveFileToDisk(false);
|
SaveOrLoadResult result = SaveFileToDisk(false);
|
||||||
|
@@ -539,8 +539,6 @@ static inline TrackBits GetAvailShipTracks(TileIndex tile, DiagDirection dir, Tr
|
|||||||
{
|
{
|
||||||
TrackBits tracks = GetTileShipTrackStatus(tile) & DiagdirReachesTracks(dir);
|
TrackBits tracks = GetTileShipTrackStatus(tile) & DiagdirReachesTracks(dir);
|
||||||
|
|
||||||
if (_settings_game.pf.forbid_90_deg) tracks &= ~TrackCrossesTracks(TrackdirToTrack(trackdir));
|
|
||||||
|
|
||||||
return tracks;
|
return tracks;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <mmsystem.h>
|
#include <mmsystem.h>
|
||||||
#include "../os/windows/win32.h"
|
#include "../os/windows/win32.h"
|
||||||
|
#include "../thread.h"
|
||||||
|
|
||||||
#include "../safeguards.h"
|
#include "../safeguards.h"
|
||||||
|
|
||||||
@@ -42,7 +43,7 @@ static void PrepareHeader(WAVEHDR *hdr)
|
|||||||
|
|
||||||
static DWORD WINAPI SoundThread(LPVOID arg)
|
static DWORD WINAPI SoundThread(LPVOID arg)
|
||||||
{
|
{
|
||||||
SetWin32ThreadName(-1, "ottd:win-sound");
|
SetCurrentThreadName("ottd:win-sound");
|
||||||
|
|
||||||
do {
|
do {
|
||||||
for (WAVEHDR *hdr = _wave_hdr; hdr != endof(_wave_hdr); hdr++) {
|
for (WAVEHDR *hdr = _wave_hdr; hdr != endof(_wave_hdr); hdr++) {
|
||||||
|
@@ -2896,21 +2896,29 @@ bool SplitGroundSpriteForOverlay(const TileInfo *ti, SpriteID *ground, RailTrack
|
|||||||
bool snow_desert;
|
bool snow_desert;
|
||||||
switch (*ground) {
|
switch (*ground) {
|
||||||
case SPR_RAIL_TRACK_X:
|
case SPR_RAIL_TRACK_X:
|
||||||
|
case SPR_MONO_TRACK_X:
|
||||||
|
case SPR_MGLV_TRACK_X:
|
||||||
snow_desert = false;
|
snow_desert = false;
|
||||||
*overlay_offset = RTO_X;
|
*overlay_offset = RTO_X;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPR_RAIL_TRACK_Y:
|
case SPR_RAIL_TRACK_Y:
|
||||||
|
case SPR_MONO_TRACK_Y:
|
||||||
|
case SPR_MGLV_TRACK_Y:
|
||||||
snow_desert = false;
|
snow_desert = false;
|
||||||
*overlay_offset = RTO_Y;
|
*overlay_offset = RTO_Y;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPR_RAIL_TRACK_X_SNOW:
|
case SPR_RAIL_TRACK_X_SNOW:
|
||||||
|
case SPR_MONO_TRACK_X_SNOW:
|
||||||
|
case SPR_MGLV_TRACK_X_SNOW:
|
||||||
snow_desert = true;
|
snow_desert = true;
|
||||||
*overlay_offset = RTO_X;
|
*overlay_offset = RTO_X;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case SPR_RAIL_TRACK_Y_SNOW:
|
case SPR_RAIL_TRACK_Y_SNOW:
|
||||||
|
case SPR_MONO_TRACK_Y_SNOW:
|
||||||
|
case SPR_MGLV_TRACK_Y_SNOW:
|
||||||
snow_desert = true;
|
snow_desert = true;
|
||||||
*overlay_offset = RTO_Y;
|
*overlay_offset = RTO_Y;
|
||||||
break;
|
break;
|
||||||
|
@@ -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_EAST = 1091;
|
||||||
static const SpriteID SPR_MONO_SINGLE_WEST = 1092;
|
static const SpriteID SPR_MONO_SINGLE_WEST = 1092;
|
||||||
static const SpriteID SPR_MONO_TRACK_Y = 1093;
|
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_BASE = 1100;
|
||||||
static const SpriteID SPR_MONO_TRACK_N_S = 1117;
|
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_X = 1169;
|
||||||
static const SpriteID SPR_MGLV_SINGLE_Y = 1170;
|
static const SpriteID SPR_MGLV_SINGLE_Y = 1170;
|
||||||
static const SpriteID SPR_MGLV_SINGLE_NORTH = 1171;
|
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_EAST = 1173;
|
||||||
static const SpriteID SPR_MGLV_SINGLE_WEST = 1174;
|
static const SpriteID SPR_MGLV_SINGLE_WEST = 1174;
|
||||||
static const SpriteID SPR_MGLV_TRACK_Y = 1175;
|
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_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_MGLV_TRACK_N_S = 1199;
|
||||||
static const SpriteID SPR_WAYPOINT_X_1 = SPR_OPENTTD_BASE + 78;
|
static const SpriteID SPR_WAYPOINT_X_1 = SPR_OPENTTD_BASE + 78;
|
||||||
static const SpriteID SPR_WAYPOINT_X_2 = SPR_OPENTTD_BASE + 79;
|
static const SpriteID SPR_WAYPOINT_X_2 = SPR_OPENTTD_BASE + 79;
|
||||||
|
104
src/thread.h
Normal file
104
src/thread.h
Normal file
@@ -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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** @file thread.h Base of all threads. */
|
||||||
|
|
||||||
|
#ifndef THREAD_H
|
||||||
|
#define THREAD_H
|
||||||
|
|
||||||
|
#include "debug.h"
|
||||||
|
#include <system_error>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
/** 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<class TFn, class... TArgs>
|
||||||
|
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<TFn>(_Fx), std::forward<TArgs>(_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 */
|
@@ -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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @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 */
|
|
@@ -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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @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; }
|
|
@@ -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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @file thread_os2.cpp OS/2 implementation of Threads. */
|
|
||||||
|
|
||||||
#include "../stdafx.h"
|
|
||||||
#include "thread.h"
|
|
||||||
|
|
||||||
#define INCL_DOS
|
|
||||||
#include <os2.h>
|
|
||||||
#include <process.h>
|
|
||||||
|
|
||||||
#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; }
|
|
@@ -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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @file thread_pthread.cpp POSIX pthread implementation of Threads. */
|
|
||||||
|
|
||||||
#include "../stdafx.h"
|
|
||||||
#include "thread.h"
|
|
||||||
#include "../string_func.h"
|
|
||||||
#include <pthread.h>
|
|
||||||
#include <errno.h>
|
|
||||||
|
|
||||||
#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;
|
|
||||||
}
|
|
@@ -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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/** @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 <stdlib.h>
|
|
||||||
#include <windows.h>
|
|
||||||
#include <process.h>
|
|
||||||
#include "../os/windows/win32.h"
|
|
||||||
#include <map>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "../safeguards.h"
|
|
||||||
|
|
||||||
static void Win32SetThreadName(uint id, const char *name);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Win32 thread version for ThreadObject.
|
|
||||||
*/
|
|
||||||
class ThreadObject_Win32 : public ThreadObject {
|
|
||||||
private:
|
|
||||||
HANDLE thread; ///< System thread identifier.
|
|
||||||
uint id; ///< 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; ///< Thread name.
|
|
||||||
|
|
||||||
public:
|
|
||||||
/**
|
|
||||||
* Create a win32 thread and start it, calling proc(param).
|
|
||||||
*/
|
|
||||||
ThreadObject_Win32(OTTDThreadFunc proc, void *param, bool self_destruct, const char *name) :
|
|
||||||
thread(NULL),
|
|
||||||
id(0),
|
|
||||||
proc(proc),
|
|
||||||
param(param),
|
|
||||||
self_destruct(self_destruct),
|
|
||||||
name(name)
|
|
||||||
{
|
|
||||||
this->thread = (HANDLE)_beginthreadex(NULL, 0, &stThreadProc, this, CREATE_SUSPENDED, &this->id);
|
|
||||||
if (this->thread == NULL) return;
|
|
||||||
Win32SetThreadName(this->id, name);
|
|
||||||
ResumeThread(this->thread);
|
|
||||||
}
|
|
||||||
|
|
||||||
~ThreadObject_Win32() override
|
|
||||||
{
|
|
||||||
if (this->thread != NULL) {
|
|
||||||
CloseHandle(this->thread);
|
|
||||||
this->thread = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Exit() override
|
|
||||||
{
|
|
||||||
assert(GetCurrentThreadId() == this->id);
|
|
||||||
/* For now we terminate by throwing an error, gives much cleaner cleanup */
|
|
||||||
throw OTTDThreadExitSignal();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Join() override
|
|
||||||
{
|
|
||||||
/* You cannot join yourself */
|
|
||||||
assert(GetCurrentThreadId() != this->id);
|
|
||||||
WaitForSingleObject(this->thread, INFINITE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
/**
|
|
||||||
* On thread creation, this function is called, which calls the real startup
|
|
||||||
* function. This to get back into the correct instance again.
|
|
||||||
*/
|
|
||||||
static uint CALLBACK stThreadProc(void *thr)
|
|
||||||
{
|
|
||||||
((ThreadObject_Win32 *)thr)->ThreadProc();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A new thread is created, and this function is called. Call the custom
|
|
||||||
* function of the creator of the thread.
|
|
||||||
*/
|
|
||||||
void ThreadProc()
|
|
||||||
{
|
|
||||||
#ifdef _MSC_VER
|
|
||||||
/* Set thread name for debuggers. Has to be done from the thread due to a race condition in older MS debuggers. */
|
|
||||||
SetWin32ThreadName(-1, this->name);
|
|
||||||
#endif
|
|
||||||
try {
|
|
||||||
this->proc(this->param);
|
|
||||||
} catch (OTTDThreadExitSignal) {
|
|
||||||
} catch (...) {
|
|
||||||
NOT_REACHED();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (self_destruct) delete this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/* static */ bool ThreadObject::New(OTTDThreadFunc proc, void *param, ThreadObject **thread, const char *name)
|
|
||||||
{
|
|
||||||
ThreadObject *to = new ThreadObject_Win32(proc, param, thread == NULL, name);
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint 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<uint, std::string> _thread_name_map;
|
|
||||||
static ThreadMutex_Win32 _thread_name_map_mutex;
|
|
||||||
|
|
||||||
static void Win32SetThreadName(uint id, const char *name)
|
|
||||||
{
|
|
||||||
_thread_name_map_mutex.BeginCritical();
|
|
||||||
_thread_name_map[id] = name;
|
|
||||||
_thread_name_map_mutex.EndCritical();
|
|
||||||
}
|
|
||||||
|
|
||||||
int GetThreadName(char *str, const char *last)
|
|
||||||
{
|
|
||||||
_thread_name_map_mutex.BeginCritical();
|
|
||||||
auto guard = scope_guard([&]() {
|
|
||||||
_thread_name_map_mutex.EndCritical();
|
|
||||||
});
|
|
||||||
auto iter = _thread_name_map.find(GetCurrentThreadId());
|
|
||||||
if (iter != _thread_name_map.end()) {
|
|
||||||
return seprintf(str, last, "%s", iter->second.c_str());
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
@@ -25,6 +25,7 @@
|
|||||||
#include "../core/random_func.hpp"
|
#include "../core/random_func.hpp"
|
||||||
#include "../core/math_func.hpp"
|
#include "../core/math_func.hpp"
|
||||||
#include "../framerate_type.h"
|
#include "../framerate_type.h"
|
||||||
|
#include "../thread.h"
|
||||||
#include "allegro_v.h"
|
#include "allegro_v.h"
|
||||||
#include <allegro.h>
|
#include <allegro.h>
|
||||||
|
|
||||||
|
@@ -37,6 +37,7 @@
|
|||||||
#include "../../core/math_func.hpp"
|
#include "../../core/math_func.hpp"
|
||||||
#include "../../texteff.hpp"
|
#include "../../texteff.hpp"
|
||||||
#include "../../window_func.h"
|
#include "../../window_func.h"
|
||||||
|
#include "../../thread.h"
|
||||||
|
|
||||||
#import <sys/time.h> /* gettimeofday */
|
#import <sys/time.h> /* gettimeofday */
|
||||||
|
|
||||||
|
@@ -30,6 +30,7 @@
|
|||||||
#include "../../core/sort_func.hpp"
|
#include "../../core/sort_func.hpp"
|
||||||
#include "cocoa_v.h"
|
#include "cocoa_v.h"
|
||||||
#include "../../gfx_func.h"
|
#include "../../gfx_func.h"
|
||||||
|
#include "../../thread.h"
|
||||||
#include "../../os/macosx/macos.h"
|
#include "../../os/macosx/macos.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -174,7 +175,7 @@ class FullscreenSubdriver : public CocoaSubdriver {
|
|||||||
|
|
||||||
double adjustment = (target - position) / linesPerSecond;
|
double adjustment = (target - position) / linesPerSecond;
|
||||||
|
|
||||||
CSleep((uint32)(adjustment * 1000));
|
CSleep((uint32)adjustment * 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@@ -22,6 +22,7 @@
|
|||||||
#include "../company_func.h"
|
#include "../company_func.h"
|
||||||
#include "../core/random_func.hpp"
|
#include "../core/random_func.hpp"
|
||||||
#include "../saveload/saveload.h"
|
#include "../saveload/saveload.h"
|
||||||
|
#include "../thread.h"
|
||||||
#include "dedicated_v.h"
|
#include "dedicated_v.h"
|
||||||
|
|
||||||
#ifdef __OS2__
|
#ifdef __OS2__
|
||||||
@@ -73,6 +74,7 @@ static void DedicatedSignalHandler(int sig)
|
|||||||
# include <time.h>
|
# include <time.h>
|
||||||
# include <tchar.h>
|
# include <tchar.h>
|
||||||
# include "../os/windows/win32.h"
|
# include "../os/windows/win32.h"
|
||||||
|
# include "../thread.h"
|
||||||
static HANDLE _hInputReady, _hWaitForInputHandling;
|
static HANDLE _hInputReady, _hWaitForInputHandling;
|
||||||
static HANDLE _hThread; // Thread to close
|
static HANDLE _hThread; // Thread to close
|
||||||
static char _win_console_thread_buffer[200];
|
static char _win_console_thread_buffer[200];
|
||||||
@@ -80,7 +82,7 @@ static char _win_console_thread_buffer[200];
|
|||||||
/* Windows Console thread. Just loop and signal when input has been received */
|
/* Windows Console thread. Just loop and signal when input has been received */
|
||||||
static void WINAPI CheckForConsoleInput()
|
static void WINAPI CheckForConsoleInput()
|
||||||
{
|
{
|
||||||
SetWin32ThreadName(-1, "ottd:win-console");
|
SetCurrentThreadName("ottd:win-console");
|
||||||
|
|
||||||
DWORD nb;
|
DWORD nb;
|
||||||
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||||
|
@@ -17,7 +17,7 @@
|
|||||||
#include "../rev.h"
|
#include "../rev.h"
|
||||||
#include "../blitter/factory.hpp"
|
#include "../blitter/factory.hpp"
|
||||||
#include "../network/network.h"
|
#include "../network/network.h"
|
||||||
#include "../thread/thread.h"
|
#include "../thread.h"
|
||||||
#include "../progress.h"
|
#include "../progress.h"
|
||||||
#include "../core/random_func.hpp"
|
#include "../core/random_func.hpp"
|
||||||
#include "../core/math_func.hpp"
|
#include "../core/math_func.hpp"
|
||||||
@@ -25,6 +25,8 @@
|
|||||||
#include "../framerate_type.h"
|
#include "../framerate_type.h"
|
||||||
#include "sdl_v.h"
|
#include "sdl_v.h"
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
#include "../safeguards.h"
|
#include "../safeguards.h"
|
||||||
|
|
||||||
@@ -36,10 +38,10 @@ static bool _all_modes;
|
|||||||
|
|
||||||
/** Whether the drawing is/may be done in a separate thread. */
|
/** Whether the drawing is/may be done in a separate thread. */
|
||||||
static bool _draw_threaded;
|
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. */
|
/** 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? */
|
/** Should we keep continue drawing? */
|
||||||
static volatile bool _draw_continue;
|
static volatile bool _draw_continue;
|
||||||
static Palette _local_palette;
|
static Palette _local_palette;
|
||||||
@@ -169,24 +171,21 @@ static void DrawSurfaceToScreen()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void DrawSurfaceToScreenThread(void *)
|
static void DrawSurfaceToScreenThread()
|
||||||
{
|
{
|
||||||
/* First tell the main thread we're started */
|
/* First tell the main thread we're started */
|
||||||
_draw_mutex->BeginCritical();
|
std::unique_lock<std::recursive_mutex> lock(*_draw_mutex);
|
||||||
_draw_mutex->SendSignal();
|
_draw_signal->notify_one();
|
||||||
|
|
||||||
/* Now wait for the first thing to draw! */
|
/* Now wait for the first thing to draw! */
|
||||||
_draw_mutex->WaitForSignal();
|
_draw_signal->wait(*_draw_mutex);
|
||||||
|
|
||||||
while (_draw_continue) {
|
while (_draw_continue) {
|
||||||
CheckPaletteAnim();
|
CheckPaletteAnim();
|
||||||
/* Then just draw and wait till we stop */
|
/* Then just draw and wait till we stop */
|
||||||
DrawSurfaceToScreen();
|
DrawSurfaceToScreen();
|
||||||
_draw_mutex->WaitForSignal();
|
_draw_signal->wait(lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
_draw_mutex->EndCritical();
|
|
||||||
_draw_thread->Exit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static const Dimension _default_resolutions[] = {
|
static const Dimension _default_resolutions[] = {
|
||||||
@@ -668,26 +667,32 @@ void VideoDriver_SDL::MainLoop()
|
|||||||
|
|
||||||
CheckPaletteAnim();
|
CheckPaletteAnim();
|
||||||
|
|
||||||
|
std::thread draw_thread;
|
||||||
|
std::unique_lock<std::recursive_mutex> draw_lock;
|
||||||
if (_draw_threaded) {
|
if (_draw_threaded) {
|
||||||
/* Initialise the mutex first, because that's the thing we *need*
|
/* Initialise the mutex first, because that's the thing we *need*
|
||||||
* directly in the newly created thread. */
|
* directly in the newly created thread. */
|
||||||
_draw_mutex = ThreadMutex::New();
|
_draw_mutex = new std::recursive_mutex();
|
||||||
if (_draw_mutex == NULL) {
|
if (_draw_mutex == NULL) {
|
||||||
_draw_threaded = false;
|
_draw_threaded = false;
|
||||||
} else {
|
} 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_continue = true;
|
||||||
|
|
||||||
_draw_threaded = ThreadObject::New(&DrawSurfaceToScreenThread, NULL, &_draw_thread, "ottd:draw-sdl");
|
_draw_threaded = StartNewThread(&draw_thread, "ottd:draw-sdl", &DrawSurfaceToScreenThread);
|
||||||
|
|
||||||
/* Free the mutex if we won't be able to use it. */
|
/* Free the mutex if we won't be able to use it. */
|
||||||
if (!_draw_threaded) {
|
if (!_draw_threaded) {
|
||||||
_draw_mutex->EndCritical();
|
draw_lock.unlock();
|
||||||
|
draw_lock.release();
|
||||||
delete _draw_mutex;
|
delete _draw_mutex;
|
||||||
|
delete _draw_signal;
|
||||||
_draw_mutex = NULL;
|
_draw_mutex = NULL;
|
||||||
|
_draw_signal = NULL;
|
||||||
} else {
|
} else {
|
||||||
/* Wait till the draw mutex has started itself. */
|
/* Wait till the draw mutex has started itself. */
|
||||||
_draw_mutex->WaitForSignal();
|
_draw_signal->wait(*_draw_mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -752,19 +757,19 @@ void VideoDriver_SDL::MainLoop()
|
|||||||
|
|
||||||
/* The gameloop is the part that can run asynchronously. The rest
|
/* The gameloop is the part that can run asynchronously. The rest
|
||||||
* except sleeping can't. */
|
* except sleeping can't. */
|
||||||
if (_draw_mutex != NULL) _draw_mutex->EndCritical();
|
if (_draw_mutex != NULL) draw_lock.unlock();
|
||||||
|
|
||||||
GameLoop();
|
GameLoop();
|
||||||
|
|
||||||
if (_draw_mutex != NULL) _draw_mutex->BeginCritical();
|
if (_draw_mutex != NULL) draw_lock.lock();
|
||||||
|
|
||||||
UpdateWindows();
|
UpdateWindows();
|
||||||
_local_palette = _cur_palette;
|
_local_palette = _cur_palette;
|
||||||
} else {
|
} else {
|
||||||
/* Release the thread while sleeping */
|
/* Release the thread while sleeping */
|
||||||
if (_draw_mutex != NULL) _draw_mutex->EndCritical();
|
if (_draw_mutex != NULL) draw_lock.unlock();
|
||||||
CSleep(1);
|
CSleep(1);
|
||||||
if (_draw_mutex != NULL) _draw_mutex->BeginCritical();
|
if (_draw_mutex != NULL) draw_lock.lock();
|
||||||
|
|
||||||
NetworkDrawChatMessage();
|
NetworkDrawChatMessage();
|
||||||
DrawMouseCursor();
|
DrawMouseCursor();
|
||||||
@@ -772,7 +777,7 @@ void VideoDriver_SDL::MainLoop()
|
|||||||
|
|
||||||
/* End of the critical part. */
|
/* End of the critical part. */
|
||||||
if (_draw_mutex != NULL && !HasModalProgress()) {
|
if (_draw_mutex != NULL && !HasModalProgress()) {
|
||||||
_draw_mutex->SendSignal();
|
_draw_signal->notify_one();
|
||||||
} else {
|
} else {
|
||||||
/* Oh, we didn't have threads, then just draw unthreaded */
|
/* Oh, we didn't have threads, then just draw unthreaded */
|
||||||
CheckPaletteAnim();
|
CheckPaletteAnim();
|
||||||
@@ -784,29 +789,32 @@ void VideoDriver_SDL::MainLoop()
|
|||||||
_draw_continue = false;
|
_draw_continue = false;
|
||||||
/* Sending signal if there is no thread blocked
|
/* Sending signal if there is no thread blocked
|
||||||
* is very valid and results in noop */
|
* is very valid and results in noop */
|
||||||
_draw_mutex->SendSignal();
|
_draw_signal->notify_one();
|
||||||
_draw_mutex->EndCritical();
|
if (draw_lock.owns_lock()) draw_lock.unlock();
|
||||||
_draw_thread->Join();
|
draw_lock.release();
|
||||||
|
draw_thread.join();
|
||||||
|
|
||||||
delete _draw_mutex;
|
delete _draw_mutex;
|
||||||
delete _draw_thread;
|
delete _draw_signal;
|
||||||
|
|
||||||
_draw_mutex = NULL;
|
_draw_mutex = NULL;
|
||||||
_draw_thread = NULL;
|
_draw_signal = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VideoDriver_SDL::ChangeResolution(int w, int h)
|
bool VideoDriver_SDL::ChangeResolution(int w, int h)
|
||||||
{
|
{
|
||||||
if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true);
|
std::unique_lock<std::recursive_mutex> lock;
|
||||||
bool ret = CreateMainSurface(w, h);
|
if (_draw_mutex != NULL) lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
|
||||||
if (_draw_mutex != NULL) _draw_mutex->EndCritical(true);
|
|
||||||
return ret;
|
return CreateMainSurface(w, h);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VideoDriver_SDL::ToggleFullscreen(bool fullscreen)
|
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;
|
_fullscreen = fullscreen;
|
||||||
GetVideoModes(); // get the list of available video modes
|
GetVideoModes(); // get the list of available video modes
|
||||||
bool ret = _num_resolutions != 0 && CreateMainSurface(_cur_resolution.width, _cur_resolution.height);
|
bool ret = _num_resolutions != 0 && CreateMainSurface(_cur_resolution.width, _cur_resolution.height);
|
||||||
@@ -816,7 +824,6 @@ bool VideoDriver_SDL::ToggleFullscreen(bool fullscreen)
|
|||||||
_fullscreen ^= true;
|
_fullscreen ^= true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_draw_mutex != NULL) _draw_mutex->EndCritical(true);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -827,12 +834,12 @@ bool VideoDriver_SDL::AfterBlitterChange()
|
|||||||
|
|
||||||
void VideoDriver_SDL::AcquireBlitterLock()
|
void VideoDriver_SDL::AcquireBlitterLock()
|
||||||
{
|
{
|
||||||
if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true);
|
if (_draw_mutex != NULL) _draw_mutex->lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoDriver_SDL::ReleaseBlitterLock()
|
void VideoDriver_SDL::ReleaseBlitterLock()
|
||||||
{
|
{
|
||||||
if (_draw_mutex != NULL) _draw_mutex->EndCritical(true);
|
if (_draw_mutex != NULL) _draw_mutex->unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* WITH_SDL */
|
#endif /* WITH_SDL */
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
#include "../core/math_func.hpp"
|
#include "../core/math_func.hpp"
|
||||||
#include "../core/random_func.hpp"
|
#include "../core/random_func.hpp"
|
||||||
#include "../texteff.hpp"
|
#include "../texteff.hpp"
|
||||||
#include "../thread/thread.h"
|
#include "../thread.h"
|
||||||
#include "../progress.h"
|
#include "../progress.h"
|
||||||
#include "../window_gui.h"
|
#include "../window_gui.h"
|
||||||
#include "../window_func.h"
|
#include "../window_func.h"
|
||||||
@@ -27,6 +27,8 @@
|
|||||||
#include "win32_v.h"
|
#include "win32_v.h"
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#include <imm.h>
|
#include <imm.h>
|
||||||
|
#include <mutex>
|
||||||
|
#include <condition_variable>
|
||||||
|
|
||||||
#include "../safeguards.h"
|
#include "../safeguards.h"
|
||||||
|
|
||||||
@@ -65,12 +67,10 @@ DWORD _imm_props;
|
|||||||
|
|
||||||
/** Whether the drawing is/may be done in a separate thread. */
|
/** Whether the drawing is/may be done in a separate thread. */
|
||||||
static bool _draw_threaded;
|
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. */
|
/** Mutex to keep the access to the shared memory controlled. */
|
||||||
static ThreadMutex *_draw_mutex = NULL;
|
static std::recursive_mutex *_draw_mutex = NULL;
|
||||||
/** Event that is signaled when the drawing thread has finished initializing. */
|
/** Signal to draw the next frame. */
|
||||||
static HANDLE _draw_thread_initialized = NULL;
|
static std::condition_variable_any *_draw_signal = NULL;
|
||||||
/** Should we keep continue drawing? */
|
/** Should we keep continue drawing? */
|
||||||
static volatile bool _draw_continue;
|
static volatile bool _draw_continue;
|
||||||
/** Local copy of the palette for use in the drawing thread. */
|
/** Local copy of the palette for use in the drawing thread. */
|
||||||
@@ -393,14 +393,14 @@ static void PaintWindow(HDC dc)
|
|||||||
DeleteDC(dc2);
|
DeleteDC(dc2);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PaintWindowThread(void *)
|
static void PaintWindowThread()
|
||||||
{
|
{
|
||||||
/* First tell the main thread we're started */
|
/* First tell the main thread we're started */
|
||||||
_draw_mutex->BeginCritical();
|
std::unique_lock<std::recursive_mutex> lock(*_draw_mutex);
|
||||||
SetEvent(_draw_thread_initialized);
|
_draw_signal->notify_one();
|
||||||
|
|
||||||
/* Now wait for the first thing to draw! */
|
/* Now wait for the first thing to draw! */
|
||||||
_draw_mutex->WaitForSignal();
|
_draw_signal->wait(*_draw_mutex);
|
||||||
|
|
||||||
while (_draw_continue) {
|
while (_draw_continue) {
|
||||||
/* Convert update region from logical to device coordinates. */
|
/* Convert update region from logical to device coordinates. */
|
||||||
@@ -422,11 +422,8 @@ static void PaintWindowThread(void *)
|
|||||||
/* Flush GDI buffer to ensure drawing here doesn't conflict with any GDI usage in the main WndProc. */
|
/* Flush GDI buffer to ensure drawing here doesn't conflict with any GDI usage in the main WndProc. */
|
||||||
GdiFlush();
|
GdiFlush();
|
||||||
|
|
||||||
_draw_mutex->WaitForSignal();
|
_draw_signal->wait(*_draw_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
_draw_mutex->EndCritical();
|
|
||||||
_draw_thread->Exit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Forward key presses to the window system. */
|
/** Forward key presses to the window system. */
|
||||||
@@ -658,7 +655,7 @@ static LRESULT CALLBACK WndProcGdi(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lP
|
|||||||
|
|
||||||
/* Mark the window as updated, otherwise Windows would send more WM_PAINT messages. */
|
/* Mark the window as updated, otherwise Windows would send more WM_PAINT messages. */
|
||||||
ValidateRect(hwnd, NULL);
|
ValidateRect(hwnd, NULL);
|
||||||
_draw_mutex->SendSignal();
|
_draw_signal->notify_one();
|
||||||
} else {
|
} else {
|
||||||
PAINTSTRUCT ps;
|
PAINTSTRUCT ps;
|
||||||
|
|
||||||
@@ -1152,7 +1149,7 @@ const char *VideoDriver_Win32::Start(const char * const *parm)
|
|||||||
|
|
||||||
MarkWholeScreenDirty();
|
MarkWholeScreenDirty();
|
||||||
|
|
||||||
_draw_threaded = GetDriverParam(parm, "no_threads") == NULL && GetDriverParam(parm, "no_thread") == NULL && GetCPUCoreCount() > 1;
|
_draw_threaded = GetDriverParam(parm, "no_threads") == NULL && GetDriverParam(parm, "no_thread") == NULL && std::thread::hardware_concurrency() > 1;
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@@ -1189,28 +1186,37 @@ void VideoDriver_Win32::MainLoop()
|
|||||||
uint32 last_cur_ticks = cur_ticks;
|
uint32 last_cur_ticks = cur_ticks;
|
||||||
uint32 next_tick = cur_ticks + MILLISECONDS_PER_TICK;
|
uint32 next_tick = cur_ticks + MILLISECONDS_PER_TICK;
|
||||||
|
|
||||||
|
std::thread draw_thread;
|
||||||
|
std::unique_lock<std::recursive_mutex> draw_lock;
|
||||||
|
|
||||||
if (_draw_threaded) {
|
if (_draw_threaded) {
|
||||||
/* Initialise the mutex first, because that's the thing we *need*
|
/* Initialise the mutex first, because that's the thing we *need*
|
||||||
* directly in the newly created thread. */
|
* directly in the newly created thread. */
|
||||||
_draw_mutex = ThreadMutex::New();
|
try {
|
||||||
_draw_thread_initialized = CreateEvent(NULL, FALSE, FALSE, NULL);
|
_draw_signal = new std::condition_variable_any();
|
||||||
if (_draw_mutex == NULL || _draw_thread_initialized == NULL) {
|
_draw_mutex = new std::recursive_mutex();
|
||||||
|
} catch (...) {
|
||||||
_draw_threaded = false;
|
_draw_threaded = false;
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
if (_draw_threaded) {
|
||||||
|
draw_lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
|
||||||
|
|
||||||
_draw_continue = true;
|
_draw_continue = true;
|
||||||
_draw_threaded = ThreadObject::New(&PaintWindowThread, NULL, &_draw_thread, "ottd:draw-win32");
|
_draw_threaded = StartNewThread(&draw_thread, "ottd:draw-win32", &PaintWindowThread);
|
||||||
|
|
||||||
/* Free the mutex if we won't be able to use it. */
|
/* Free the mutex if we won't be able to use it. */
|
||||||
if (!_draw_threaded) {
|
if (!_draw_threaded) {
|
||||||
|
draw_lock.unlock();
|
||||||
|
draw_lock.release();
|
||||||
delete _draw_mutex;
|
delete _draw_mutex;
|
||||||
|
delete _draw_signal;
|
||||||
_draw_mutex = NULL;
|
_draw_mutex = NULL;
|
||||||
CloseHandle(_draw_thread_initialized);
|
_draw_signal = NULL;
|
||||||
_draw_thread_initialized = NULL;
|
|
||||||
} else {
|
} else {
|
||||||
DEBUG(driver, 1, "Threaded drawing enabled");
|
DEBUG(driver, 1, "Threaded drawing enabled");
|
||||||
/* Wait till the draw thread has started itself. */
|
/* Wait till the draw thread has started itself. */
|
||||||
WaitForSingleObject(_draw_thread_initialized, INFINITE);
|
_draw_signal->wait(*_draw_mutex);
|
||||||
_draw_mutex->BeginCritical();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1227,7 +1233,7 @@ void VideoDriver_Win32::MainLoop()
|
|||||||
if (EditBoxInGlobalFocus()) TranslateMessage(&mesg);
|
if (EditBoxInGlobalFocus()) TranslateMessage(&mesg);
|
||||||
DispatchMessage(&mesg);
|
DispatchMessage(&mesg);
|
||||||
}
|
}
|
||||||
if (_exit_game) return;
|
if (_exit_game) break;
|
||||||
|
|
||||||
#if defined(_DEBUG)
|
#if defined(_DEBUG)
|
||||||
if (_wnd.has_focus && GetAsyncKeyState(VK_SHIFT) < 0 &&
|
if (_wnd.has_focus && GetAsyncKeyState(VK_SHIFT) < 0 &&
|
||||||
@@ -1270,9 +1276,9 @@ void VideoDriver_Win32::MainLoop()
|
|||||||
|
|
||||||
/* The game loop is the part that can run asynchronously.
|
/* The game loop is the part that can run asynchronously.
|
||||||
* The rest except sleeping can't. */
|
* The rest except sleeping can't. */
|
||||||
if (_draw_threaded) _draw_mutex->EndCritical();
|
if (_draw_threaded) draw_lock.unlock();
|
||||||
GameLoop();
|
GameLoop();
|
||||||
if (_draw_threaded) _draw_mutex->BeginCritical();
|
if (_draw_threaded) draw_lock.lock();
|
||||||
|
|
||||||
if (_force_full_redraw) MarkWholeScreenDirty();
|
if (_force_full_redraw) MarkWholeScreenDirty();
|
||||||
|
|
||||||
@@ -1283,9 +1289,9 @@ void VideoDriver_Win32::MainLoop()
|
|||||||
GdiFlush();
|
GdiFlush();
|
||||||
|
|
||||||
/* Release the thread while sleeping */
|
/* Release the thread while sleeping */
|
||||||
if (_draw_threaded) _draw_mutex->EndCritical();
|
if (_draw_threaded) draw_lock.unlock();
|
||||||
Sleep(1);
|
Sleep(1);
|
||||||
if (_draw_threaded) _draw_mutex->BeginCritical();
|
if (_draw_threaded) draw_lock.lock();
|
||||||
|
|
||||||
NetworkDrawChatMessage();
|
NetworkDrawChatMessage();
|
||||||
DrawMouseCursor();
|
DrawMouseCursor();
|
||||||
@@ -1296,35 +1302,37 @@ void VideoDriver_Win32::MainLoop()
|
|||||||
_draw_continue = false;
|
_draw_continue = false;
|
||||||
/* Sending signal if there is no thread blocked
|
/* Sending signal if there is no thread blocked
|
||||||
* is very valid and results in noop */
|
* is very valid and results in noop */
|
||||||
_draw_mutex->SendSignal();
|
_draw_signal->notify_all();
|
||||||
_draw_mutex->EndCritical();
|
if (draw_lock.owns_lock()) draw_lock.unlock();
|
||||||
_draw_thread->Join();
|
draw_lock.release();
|
||||||
|
draw_thread.join();
|
||||||
|
|
||||||
CloseHandle(_draw_thread_initialized);
|
|
||||||
delete _draw_mutex;
|
delete _draw_mutex;
|
||||||
delete _draw_thread;
|
delete _draw_signal;
|
||||||
|
|
||||||
|
_draw_mutex = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VideoDriver_Win32::ChangeResolution(int w, int h)
|
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);
|
if (_window_maximize) ShowWindow(_wnd.main_wnd, SW_SHOWNORMAL);
|
||||||
|
|
||||||
_wnd.width = _wnd.width_org = w;
|
_wnd.width = _wnd.width_org = w;
|
||||||
_wnd.height = _wnd.height_org = h;
|
_wnd.height = _wnd.height_org = h;
|
||||||
|
|
||||||
bool ret = this->MakeWindow(_fullscreen); // _wnd.fullscreen screws up ingame resolution switching
|
return this->MakeWindow(_fullscreen); // _wnd.fullscreen screws up ingame resolution switching
|
||||||
if (_draw_mutex != NULL) _draw_mutex->EndCritical(true);
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VideoDriver_Win32::ToggleFullscreen(bool full_screen)
|
bool VideoDriver_Win32::ToggleFullscreen(bool full_screen)
|
||||||
{
|
{
|
||||||
if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true);
|
std::unique_lock<std::recursive_mutex> lock;
|
||||||
bool ret = this->MakeWindow(full_screen);
|
if (_draw_mutex != NULL) lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
|
||||||
if (_draw_mutex != NULL) _draw_mutex->EndCritical(true);
|
|
||||||
return ret;
|
return this->MakeWindow(full_screen);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool VideoDriver_Win32::AfterBlitterChange()
|
bool VideoDriver_Win32::AfterBlitterChange()
|
||||||
@@ -1334,19 +1342,20 @@ bool VideoDriver_Win32::AfterBlitterChange()
|
|||||||
|
|
||||||
void VideoDriver_Win32::AcquireBlitterLock()
|
void VideoDriver_Win32::AcquireBlitterLock()
|
||||||
{
|
{
|
||||||
if (_draw_mutex != NULL) _draw_mutex->BeginCritical(true);
|
if (_draw_mutex != NULL) _draw_mutex->lock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoDriver_Win32::ReleaseBlitterLock()
|
void VideoDriver_Win32::ReleaseBlitterLock()
|
||||||
{
|
{
|
||||||
if (_draw_mutex != NULL) _draw_mutex->EndCritical(true);
|
if (_draw_mutex != NULL) _draw_mutex->unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void VideoDriver_Win32::EditBoxLostFocus()
|
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);
|
CancelIMEComposition(_wnd.main_wnd);
|
||||||
SetCompositionPos(_wnd.main_wnd);
|
SetCompositionPos(_wnd.main_wnd);
|
||||||
SetCandidatePos(_wnd.main_wnd);
|
SetCandidatePos(_wnd.main_wnd);
|
||||||
if (_draw_mutex != NULL) _draw_mutex->EndCritical(true);
|
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user