mirror of https://github.com/OpenTTD/OpenTTD.git
Codechange: Replace custom thread code with C++11 thread objects.
We assume a conforming C++11 compiler environment that has a valid <thread>-header. Failure to run a real thread is handled gracefully.
This commit is contained in:
parent
05f4e73608
commit
05bc2ed7cb
|
@ -1334,8 +1334,7 @@
|
|||
<ResourceCompile Include="..\src\os\windows\ottdres.rc" />
|
||||
<ClCompile Include="..\src\os\windows\string_uniscribe.cpp" />
|
||||
<ClCompile Include="..\src\os\windows\win32.cpp" />
|
||||
<ClInclude Include="..\src\thread\thread.h" />
|
||||
<ClCompile Include="..\src\thread\thread_win32.cpp" />
|
||||
<ClInclude Include="..\src\thread.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\media\openttd.ico" />
|
||||
|
|
|
@ -3090,12 +3090,9 @@
|
|||
<ClCompile Include="..\src\os\windows\win32.cpp">
|
||||
<Filter>Windows files</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\src\thread\thread.h">
|
||||
<ClInclude Include="..\src\thread.h">
|
||||
<Filter>Threading</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\src\thread\thread_win32.cpp">
|
||||
<Filter>Threading</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\media\openttd.ico" />
|
||||
|
|
|
@ -1334,8 +1334,7 @@
|
|||
<ResourceCompile Include="..\src\os\windows\ottdres.rc" />
|
||||
<ClCompile Include="..\src\os\windows\string_uniscribe.cpp" />
|
||||
<ClCompile Include="..\src\os\windows\win32.cpp" />
|
||||
<ClInclude Include="..\src\thread\thread.h" />
|
||||
<ClCompile Include="..\src\thread\thread_win32.cpp" />
|
||||
<ClInclude Include="..\src\thread.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\media\openttd.ico" />
|
||||
|
|
|
@ -3090,12 +3090,9 @@
|
|||
<ClCompile Include="..\src\os\windows\win32.cpp">
|
||||
<Filter>Windows files</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\src\thread\thread.h">
|
||||
<ClInclude Include="..\src\thread.h">
|
||||
<Filter>Threading</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\src\thread\thread_win32.cpp">
|
||||
<Filter>Threading</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\media\openttd.ico" />
|
||||
|
|
|
@ -1334,8 +1334,7 @@
|
|||
<ResourceCompile Include="..\src\os\windows\ottdres.rc" />
|
||||
<ClCompile Include="..\src\os\windows\string_uniscribe.cpp" />
|
||||
<ClCompile Include="..\src\os\windows\win32.cpp" />
|
||||
<ClInclude Include="..\src\thread\thread.h" />
|
||||
<ClCompile Include="..\src\thread\thread_win32.cpp" />
|
||||
<ClInclude Include="..\src\thread.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\media\openttd.ico" />
|
||||
|
|
|
@ -3090,12 +3090,9 @@
|
|||
<ClCompile Include="..\src\os\windows\win32.cpp">
|
||||
<Filter>Windows files</Filter>
|
||||
</ClCompile>
|
||||
<ClInclude Include="..\src\thread\thread.h">
|
||||
<ClInclude Include="..\src\thread.h">
|
||||
<Filter>Threading</Filter>
|
||||
</ClInclude>
|
||||
<ClCompile Include="..\src\thread\thread_win32.cpp">
|
||||
<Filter>Threading</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="..\media\openttd.ico" />
|
||||
|
|
15
source.list
15
source.list
|
@ -1173,17 +1173,4 @@ sound/null_s.cpp
|
|||
#end
|
||||
|
||||
# Threading
|
||||
thread/thread.h
|
||||
#if USE_THREADS
|
||||
#if WIN32
|
||||
thread/thread_win32.cpp
|
||||
#else
|
||||
#if OS2
|
||||
thread/thread_os2.cpp
|
||||
#else
|
||||
thread/thread_pthread.cpp
|
||||
#end
|
||||
#end
|
||||
#else
|
||||
thread/thread_none.cpp
|
||||
#end
|
||||
thread.h
|
||||
|
|
|
@ -34,7 +34,7 @@
|
|||
#include "game/game.hpp"
|
||||
#include "game/game_instance.hpp"
|
||||
#include "string_func.h"
|
||||
#include "thread/thread.h"
|
||||
#include "thread.h"
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
|
@ -94,7 +94,7 @@ static void CleanupGeneration()
|
|||
/**
|
||||
* The internal, real, generate function.
|
||||
*/
|
||||
static void _GenerateWorld(void *)
|
||||
static void _GenerateWorld()
|
||||
{
|
||||
/* Make sure everything is done via OWNER_NONE. */
|
||||
Backup<CompanyByte> _cur_company(_current_company, OWNER_NONE, FILE_LINE);
|
||||
|
@ -242,14 +242,12 @@ void GenerateWorldSetAbortCallback(GWAbortProc *proc)
|
|||
*/
|
||||
void WaitTillGeneratedWorld()
|
||||
{
|
||||
if (_gw.thread == NULL) return;
|
||||
if (!_gw.thread.joinable()) return;
|
||||
|
||||
_modal_progress_work_mutex.unlock();
|
||||
_modal_progress_paint_mutex.unlock();
|
||||
_gw.quit_thread = true;
|
||||
_gw.thread->Join();
|
||||
delete _gw.thread;
|
||||
_gw.thread = NULL;
|
||||
_gw.thread.join();
|
||||
_gw.threaded = false;
|
||||
_modal_progress_work_mutex.lock();
|
||||
_modal_progress_paint_mutex.lock();
|
||||
|
@ -284,7 +282,7 @@ void HandleGeneratingWorldAbortion()
|
|||
|
||||
CleanupGeneration();
|
||||
|
||||
if (_gw.thread != NULL) _gw.thread->Exit();
|
||||
if (_gw.thread.joinable() && _gw.thread.get_id() == std::this_thread::get_id()) throw OTTDThreadExitSignal();
|
||||
|
||||
SwitchToMode(_switch_mode);
|
||||
}
|
||||
|
@ -326,17 +324,13 @@ void GenerateWorld(GenWorldMode mode, uint size_x, uint size_y, bool reset_setti
|
|||
SetupColoursAndInitialWindow();
|
||||
SetObjectToPlace(SPR_CURSOR_ZZZ, PAL_NONE, HT_NONE, WC_MAIN_WINDOW, 0);
|
||||
|
||||
if (_gw.thread != NULL) {
|
||||
_gw.thread->Join();
|
||||
delete _gw.thread;
|
||||
_gw.thread = NULL;
|
||||
}
|
||||
if (_gw.thread.joinable()) _gw.thread.join();
|
||||
|
||||
if (!UseThreadedModelProgress() || !VideoDriver::GetInstance()->HasGUI() || !ThreadObject::New(&_GenerateWorld, NULL, &_gw.thread, "ottd:genworld")) {
|
||||
if (!UseThreadedModelProgress() || !VideoDriver::GetInstance()->HasGUI() || !StartNewThread(&_gw.thread, "ottd:genworld", &_GenerateWorld)) {
|
||||
DEBUG(misc, 1, "Cannot create genworld thread, reverting to single-threaded mode");
|
||||
_gw.threaded = false;
|
||||
_modal_progress_work_mutex.unlock();
|
||||
_GenerateWorld(NULL);
|
||||
_GenerateWorld();
|
||||
_modal_progress_work_mutex.lock();
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
#define GENWORLD_H
|
||||
|
||||
#include "company_type.h"
|
||||
#include <thread>
|
||||
|
||||
/** Constants related to world generation */
|
||||
enum LandscapeGenerator {
|
||||
|
@ -61,7 +62,7 @@ struct GenWorldInfo {
|
|||
uint size_y; ///< Y-size of the map
|
||||
GWDoneProc *proc; ///< Proc that is called when done (can be NULL)
|
||||
GWAbortProc *abortp; ///< Proc that is called when aborting (can be NULL)
|
||||
class ThreadObject *thread; ///< The thread we are in (can be NULL)
|
||||
std::thread thread; ///< The thread we are in (joinable if a thread was created)
|
||||
};
|
||||
|
||||
/** Current stage of world generation process */
|
||||
|
|
|
@ -39,7 +39,6 @@ LinkGraphJob::LinkGraphJob(const LinkGraph &orig) :
|
|||
* This is on purpose. */
|
||||
link_graph(orig),
|
||||
settings(_settings_game.linkgraph),
|
||||
thread(NULL),
|
||||
join_date(_date + _settings_game.linkgraph.recalc_time)
|
||||
{
|
||||
}
|
||||
|
@ -61,8 +60,7 @@ void LinkGraphJob::EraseFlows(NodeID from)
|
|||
*/
|
||||
void LinkGraphJob::SpawnThread()
|
||||
{
|
||||
if (!ThreadObject::New(&(LinkGraphSchedule::Run), this, &this->thread, "ottd:linkgraph")) {
|
||||
this->thread = NULL;
|
||||
if (!StartNewThread(&this->thread, "ottd:linkgraph", &(LinkGraphSchedule::Run), this)) {
|
||||
/* Of course this will hang a bit.
|
||||
* On the other hand, if you want to play games which make this hang noticably
|
||||
* on a platform without threads then you'll probably get other problems first.
|
||||
|
@ -79,10 +77,8 @@ void LinkGraphJob::SpawnThread()
|
|||
*/
|
||||
void LinkGraphJob::JoinThread()
|
||||
{
|
||||
if (this->thread != NULL) {
|
||||
this->thread->Join();
|
||||
delete this->thread;
|
||||
this->thread = NULL;
|
||||
if (this->thread.joinable()) {
|
||||
this->thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#ifndef LINKGRAPHJOB_H
|
||||
#define LINKGRAPHJOB_H
|
||||
|
||||
#include "../thread/thread.h"
|
||||
#include "../thread.h"
|
||||
#include "linkgraph.h"
|
||||
#include <list>
|
||||
|
||||
|
@ -59,7 +59,7 @@ private:
|
|||
protected:
|
||||
const LinkGraph link_graph; ///< Link graph to by analyzed. Is copied when job is started and mustn't be modified later.
|
||||
const LinkGraphSettings settings; ///< Copy of _settings_game.linkgraph at spawn time.
|
||||
ThreadObject *thread; ///< Thread the job is running in or NULL if it's running in the main thread.
|
||||
std::thread thread; ///< Thread the job is running in or a default-constructed thread if it's running in the main thread.
|
||||
Date join_date; ///< Date when the job is to be joined.
|
||||
NodeAnnotationVector nodes; ///< Extra node data necessary for link graph calculation.
|
||||
EdgeAnnotationMatrix edges; ///< Extra edge data necessary for link graph calculation.
|
||||
|
@ -266,7 +266,7 @@ public:
|
|||
* Bare constructor, only for save/load. link_graph, join_date and actually
|
||||
* settings have to be brutally const-casted in order to populate them.
|
||||
*/
|
||||
LinkGraphJob() : settings(_settings_game.linkgraph), thread(NULL),
|
||||
LinkGraphJob() : settings(_settings_game.linkgraph),
|
||||
join_date(INVALID_DATE) {}
|
||||
|
||||
LinkGraphJob(const LinkGraph &orig);
|
||||
|
|
|
@ -69,13 +69,11 @@ void LinkGraphSchedule::JoinNext()
|
|||
}
|
||||
|
||||
/**
|
||||
* Run all handlers for the given Job. This method is tailored to
|
||||
* ThreadObject::New.
|
||||
* @param j Pointer to a link graph job.
|
||||
* Run all handlers for the given Job.
|
||||
* @param job Pointer to a link graph job.
|
||||
*/
|
||||
/* static */ void LinkGraphSchedule::Run(void *j)
|
||||
/* static */ void LinkGraphSchedule::Run(LinkGraphJob *job)
|
||||
{
|
||||
LinkGraphJob *job = (LinkGraphJob *)j;
|
||||
for (uint i = 0; i < lengthof(instance.handlers); ++i) {
|
||||
instance.handlers[i]->Run(*job);
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ public:
|
|||
static const uint SPAWN_JOIN_TICK = 21; ///< Tick when jobs are spawned or joined every day.
|
||||
static LinkGraphSchedule instance;
|
||||
|
||||
static void Run(void *j);
|
||||
static void Run(LinkGraphJob *job);
|
||||
static void Clear();
|
||||
|
||||
void SpawnNext();
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "../debug.h"
|
||||
#include "../os/windows/win32.h"
|
||||
#include "../core/mem_func.hpp"
|
||||
#include "../thread/thread.h"
|
||||
#include "../thread.h"
|
||||
#include "../fileio_func.h"
|
||||
#include "../base_media_base.h"
|
||||
#include "dmusic.h"
|
||||
|
@ -139,7 +139,7 @@ static struct {
|
|||
} _playback;
|
||||
|
||||
/** Handle to our worker thread. */
|
||||
static ThreadObject *_dmusic_thread = NULL;
|
||||
static std::thread _dmusic_thread;
|
||||
/** Event to signal the thread that it should look at a state change. */
|
||||
static HANDLE _thread_event = NULL;
|
||||
/** Lock access to playback data that is not thread-safe. */
|
||||
|
@ -597,7 +597,7 @@ static void TransmitNotesOff(IDirectMusicBuffer *buffer, REFERENCE_TIME block_ti
|
|||
Sleep(Clamp((block_time - cur_time) / MS_TO_REFTIME, 5, 1000));
|
||||
}
|
||||
|
||||
static void MidiThreadProc(void *)
|
||||
static void MidiThreadProc()
|
||||
{
|
||||
DEBUG(driver, 2, "DMusic: Entering playback thread");
|
||||
|
||||
|
@ -1169,7 +1169,7 @@ const char *MusicDriver_DMusic::Start(const char * const *parm)
|
|||
_thread_event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
if (_thread_event == NULL) return "Can't create thread shutdown event";
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -1183,10 +1183,10 @@ MusicDriver_DMusic::~MusicDriver_DMusic()
|
|||
|
||||
void MusicDriver_DMusic::Stop()
|
||||
{
|
||||
if (_dmusic_thread != NULL) {
|
||||
if (_dmusic_thread.joinable()) {
|
||||
_playback.shutdown = true;
|
||||
SetEvent(_thread_event);
|
||||
_dmusic_thread->Join();
|
||||
_dmusic_thread.join();
|
||||
}
|
||||
|
||||
/* Unloaded any instruments we loaded. */
|
||||
|
|
|
@ -63,7 +63,6 @@ public:
|
|||
*/
|
||||
class TCPConnecter {
|
||||
private:
|
||||
class ThreadObject *thread; ///< Thread used to create the TCP connection
|
||||
bool connected; ///< Whether we succeeded in making the connection
|
||||
bool aborted; ///< Whether we bailed out (i.e. connection making failed)
|
||||
bool killed; ///< Whether we got killed
|
||||
|
@ -71,7 +70,7 @@ private:
|
|||
|
||||
void Connect();
|
||||
|
||||
static void ThreadEntry(void *param);
|
||||
static void ThreadEntry(TCPConnecter *param);
|
||||
|
||||
protected:
|
||||
/** Address we're connecting to */
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
*/
|
||||
|
||||
#include "../../stdafx.h"
|
||||
#include "../../thread/thread.h"
|
||||
#include "../../thread.h"
|
||||
|
||||
#include "tcp.h"
|
||||
|
||||
|
@ -33,7 +33,7 @@ TCPConnecter::TCPConnecter(const NetworkAddress &address) :
|
|||
address(address)
|
||||
{
|
||||
_tcp_connecters.push_back(this);
|
||||
if (!ThreadObject::New(TCPConnecter::ThreadEntry, this, &this->thread, "ottd:tcp")) {
|
||||
if (!StartNewThread(NULL, "ottd:tcp", &TCPConnecter::ThreadEntry, this)) {
|
||||
this->Connect();
|
||||
}
|
||||
}
|
||||
|
@ -53,9 +53,9 @@ void TCPConnecter::Connect()
|
|||
* Entry point for the new threads.
|
||||
* @param param the TCPConnecter instance to call Connect on.
|
||||
*/
|
||||
/* static */ void TCPConnecter::ThreadEntry(void *param)
|
||||
/* static */ void TCPConnecter::ThreadEntry(TCPConnecter *param)
|
||||
{
|
||||
static_cast<TCPConnecter*>(param)->Connect();
|
||||
param->Connect();
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -14,7 +14,6 @@
|
|||
|
||||
#include "network_internal.h"
|
||||
#include "core/tcp_listen.h"
|
||||
#include "../thread/thread.h"
|
||||
|
||||
class ServerNetworkGameSocketHandler;
|
||||
/** Make the code look slightly nicer/simpler. */
|
||||
|
|
|
@ -24,7 +24,7 @@
|
|||
#include "network.h"
|
||||
#include "../core/endian_func.hpp"
|
||||
#include "../company_base.h"
|
||||
#include "../thread/thread.h"
|
||||
#include "../thread.h"
|
||||
#include "../rev.h"
|
||||
#include "../newgrf_text.h"
|
||||
#include "../strings_func.h"
|
||||
|
@ -49,35 +49,19 @@ NetworkUDPSocketHandler *_udp_client_socket = NULL; ///< udp client socket
|
|||
NetworkUDPSocketHandler *_udp_server_socket = NULL; ///< udp server socket
|
||||
NetworkUDPSocketHandler *_udp_master_socket = NULL; ///< udp master socket
|
||||
|
||||
/** Simpler wrapper struct for NetworkUDPQueryServerThread */
|
||||
struct NetworkUDPQueryServerInfo : NetworkAddress {
|
||||
bool manually; ///< Did we connect manually or not?
|
||||
|
||||
/**
|
||||
* Create the structure.
|
||||
* @param address The address of the server to query.
|
||||
* @param manually Whether the address was entered manually.
|
||||
*/
|
||||
NetworkUDPQueryServerInfo(const NetworkAddress &address, bool manually) :
|
||||
NetworkAddress(address),
|
||||
manually(manually)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function doing the actual work for querying the server.
|
||||
* @param address The address of the server.
|
||||
* @param needs_mutex Whether we need to acquire locks when sending the packet or not.
|
||||
* @param manually Whether the address was entered manually.
|
||||
*/
|
||||
static void NetworkUDPQueryServer(NetworkAddress *address, bool needs_mutex, bool manually)
|
||||
static void DoNetworkUDPQueryServer(NetworkAddress &address, bool needs_mutex, bool manually)
|
||||
{
|
||||
/* Clear item in gamelist */
|
||||
NetworkGameList *item = CallocT<NetworkGameList>(1);
|
||||
address->GetAddressAsString(item->info.server_name, lastof(item->info.server_name));
|
||||
strecpy(item->info.hostname, address->GetHostname(), lastof(item->info.hostname));
|
||||
item->address = *address;
|
||||
address.GetAddressAsString(item->info.server_name, lastof(item->info.server_name));
|
||||
strecpy(item->info.hostname, address.GetHostname(), lastof(item->info.hostname));
|
||||
item->address = address;
|
||||
item->manually = manually;
|
||||
NetworkGameListAddItemDelayed(item);
|
||||
|
||||
|
@ -85,19 +69,7 @@ static void NetworkUDPQueryServer(NetworkAddress *address, bool needs_mutex, boo
|
|||
if (needs_mutex) lock.lock();
|
||||
/* Init the packet */
|
||||
Packet p(PACKET_UDP_CLIENT_FIND_SERVER);
|
||||
if (_udp_client_socket != NULL) _udp_client_socket->SendPacket(&p, address);
|
||||
}
|
||||
|
||||
/**
|
||||
* Threaded part for resolving the IP of a server and querying it.
|
||||
* @param pntr the NetworkUDPQueryServerInfo.
|
||||
*/
|
||||
static void NetworkUDPQueryServerThread(void *pntr)
|
||||
{
|
||||
NetworkUDPQueryServerInfo *info = (NetworkUDPQueryServerInfo*)pntr;
|
||||
NetworkUDPQueryServer(info, true, info->manually);
|
||||
|
||||
delete info;
|
||||
if (_udp_client_socket != NULL) _udp_client_socket->SendPacket(&p, &address);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -107,9 +79,8 @@ static void NetworkUDPQueryServerThread(void *pntr)
|
|||
*/
|
||||
void NetworkUDPQueryServer(NetworkAddress address, bool manually)
|
||||
{
|
||||
NetworkUDPQueryServerInfo *info = new NetworkUDPQueryServerInfo(address, manually);
|
||||
if (address.IsResolved() || !ThreadObject::New(NetworkUDPQueryServerThread, info, NULL, "ottd:udp-query")) {
|
||||
NetworkUDPQueryServerThread(info);
|
||||
if (address.IsResolved() || !StartNewThread(NULL, "ottd:udp-query", &DoNetworkUDPQueryServer, std::move(address), true, std::move(manually))) {
|
||||
DoNetworkUDPQueryServer(address, true, manually);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -429,7 +400,7 @@ void ClientNetworkUDPSocketHandler::Receive_MASTER_RESPONSE_LIST(Packet *p, Netw
|
|||
/* Somehow we reached the end of the packet */
|
||||
if (this->HasClientQuit()) return;
|
||||
|
||||
NetworkUDPQueryServer(&addr, false, false);
|
||||
DoNetworkUDPQueryServer(addr, false, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -535,9 +506,8 @@ void NetworkUDPSearchGame()
|
|||
|
||||
/**
|
||||
* Thread entry point for de-advertising.
|
||||
* @param pntr unused.
|
||||
*/
|
||||
static void NetworkUDPRemoveAdvertiseThread(void *pntr)
|
||||
static void NetworkUDPRemoveAdvertiseThread()
|
||||
{
|
||||
DEBUG(net, 1, "[udp] removing advertise from master server");
|
||||
|
||||
|
@ -563,16 +533,15 @@ void NetworkUDPRemoveAdvertise(bool blocking)
|
|||
/* Check if we are advertising */
|
||||
if (!_networking || !_network_server || !_network_udp_server) return;
|
||||
|
||||
if (blocking || !ThreadObject::New(NetworkUDPRemoveAdvertiseThread, NULL, NULL, "ottd:udp-advert")) {
|
||||
NetworkUDPRemoveAdvertiseThread(NULL);
|
||||
if (blocking || !StartNewThread(NULL, "ottd:udp-advert", &NetworkUDPRemoveAdvertiseThread)) {
|
||||
NetworkUDPRemoveAdvertiseThread();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Thread entry point for advertising.
|
||||
* @param pntr unused.
|
||||
*/
|
||||
static void NetworkUDPAdvertiseThread(void *pntr)
|
||||
static void NetworkUDPAdvertiseThread()
|
||||
{
|
||||
/* Find somewhere to send */
|
||||
NetworkAddress out_addr(NETWORK_MASTER_SERVER_HOST, NETWORK_MASTER_SERVER_PORT);
|
||||
|
@ -645,8 +614,8 @@ void NetworkUDPAdvertise()
|
|||
if (_next_advertisement < _last_advertisement) _next_advertisement = UINT32_MAX;
|
||||
if (_next_retry < _last_advertisement) _next_retry = UINT32_MAX;
|
||||
|
||||
if (!ThreadObject::New(NetworkUDPAdvertiseThread, NULL, NULL, "ottd:udp-advert")) {
|
||||
NetworkUDPAdvertiseThread(NULL);
|
||||
if (!StartNewThread(NULL, "ottd:udp-advert", &NetworkUDPAdvertiseThread)) {
|
||||
NetworkUDPAdvertiseThread();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -21,7 +21,8 @@
|
|||
#include "video/video_driver.hpp"
|
||||
#include "strings_func.h"
|
||||
#include "textfile_gui.h"
|
||||
#include "thread/thread.h"
|
||||
#include "thread.h"
|
||||
#include "newgrf_config.h"
|
||||
|
||||
#include "fileio_func.h"
|
||||
#include "fios.h"
|
||||
|
@ -724,7 +725,7 @@ static int CDECL GRFSorter(GRFConfig * const *p1, GRFConfig * const *p2)
|
|||
* Really perform the scan for all NewGRFs.
|
||||
* @param callback The callback to call after the scanning is complete.
|
||||
*/
|
||||
void DoScanNewGRFFiles(void *callback)
|
||||
void DoScanNewGRFFiles(NewGRFScanCallback *callback)
|
||||
{
|
||||
std::unique_lock<std::mutex> lock_work(_modal_progress_work_mutex);
|
||||
|
||||
|
@ -767,7 +768,7 @@ void DoScanNewGRFFiles(void *callback)
|
|||
/* Yes... these are the NewGRF windows */
|
||||
InvalidateWindowClassesData(WC_SAVELOAD, 0, true);
|
||||
InvalidateWindowData(WC_GAME_OPTIONS, WN_GAME_OPTIONS_NEWGRF_STATE, GOID_NEWGRF_RESCANNED, true);
|
||||
if (callback != NULL) ((NewGRFScanCallback*)callback)->OnNewGRFsScanned();
|
||||
if (callback != NULL) callback->OnNewGRFsScanned();
|
||||
|
||||
DeleteWindowByClass(WC_MODAL_PROGRESS);
|
||||
SetModalProgress(false);
|
||||
|
@ -785,7 +786,7 @@ void ScanNewGRFFiles(NewGRFScanCallback *callback)
|
|||
/* Only then can we really start, especially by marking the whole screen dirty. Get those other windows hidden!. */
|
||||
MarkWholeScreenDirty();
|
||||
|
||||
if (!UseThreadedModelProgress() || !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.unlock();
|
||||
_modal_progress_paint_mutex.unlock();
|
||||
DoScanNewGRFFiles(callback);
|
||||
|
|
|
@ -857,6 +857,7 @@ int openttd_main(int argc, char *argv[])
|
|||
VideoDriver::GetInstance()->MainLoop();
|
||||
|
||||
WaitTillSaved();
|
||||
WaitTillGeneratedWorld(); // Make sure any generate world threads have been joined.
|
||||
|
||||
/* only save config if we have to */
|
||||
if (save_config) {
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "../../core/random_func.hpp"
|
||||
#include "../../string_func.h"
|
||||
#include "../../textbuf_gui.h"
|
||||
#include "../../thread.h"
|
||||
|
||||
#include "table/strings.h"
|
||||
|
||||
|
@ -226,3 +227,7 @@ void OSOpenBrowser(const char *url)
|
|||
// stub only
|
||||
DEBUG(misc, 0, "Failed to open url: %s", url);
|
||||
}
|
||||
|
||||
void SetCurrentThreadName(const char *)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include "../../debug.h"
|
||||
#include "../../string_func.h"
|
||||
#include "../../fios.h"
|
||||
#include "../../thread.h"
|
||||
|
||||
|
||||
#include <dirent.h>
|
||||
|
@ -43,11 +44,17 @@
|
|||
#include <sys/sysctl.h>
|
||||
#endif
|
||||
|
||||
#ifndef NO_THREADS
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#if defined(WITH_SDL)
|
||||
# if defined(WITH_SDL)
|
||||
/* the mac implementation needs this file included in the same file as main() */
|
||||
#include <SDL.h>
|
||||
#endif
|
||||
# include <SDL.h>
|
||||
# endif
|
||||
|
||||
# include "../macosx/macos.h"
|
||||
#endif
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
@ -317,4 +324,15 @@ void OSOpenBrowser(const char *url)
|
|||
DEBUG(misc, 0, "Failed to open url: %s", url);
|
||||
exit(0);
|
||||
}
|
||||
#endif
|
||||
#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__) */
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <errno.h>
|
||||
#include <sys/stat.h>
|
||||
#include "../../language.h"
|
||||
#include "../../thread.h"
|
||||
|
||||
#include "../../safeguards.h"
|
||||
|
||||
|
@ -816,12 +817,12 @@ PACK_N(struct THREADNAME_INFO {
|
|||
/**
|
||||
* Signal thread name to any attached debuggers.
|
||||
*/
|
||||
void SetWin32ThreadName(DWORD dwThreadID, const char* threadName)
|
||||
void SetCurrentThreadName(const char *threadName)
|
||||
{
|
||||
THREADNAME_INFO info;
|
||||
info.dwType = 0x1000;
|
||||
info.szName = threadName;
|
||||
info.dwThreadID = dwThreadID;
|
||||
info.dwThreadID = -1;
|
||||
info.dwFlags = 0;
|
||||
|
||||
#pragma warning(push)
|
||||
|
@ -832,4 +833,6 @@ void SetWin32ThreadName(DWORD dwThreadID, const char* threadName)
|
|||
}
|
||||
#pragma warning(pop)
|
||||
}
|
||||
#else
|
||||
void SetCurrentThreadName(const char *) {}
|
||||
#endif
|
||||
|
|
|
@ -39,12 +39,6 @@ HRESULT OTTDSHGetFolderPath(HWND, int, HANDLE, DWORD, LPTSTR);
|
|||
#define SHGFP_TYPE_CURRENT 0
|
||||
#endif /* __MINGW32__ */
|
||||
|
||||
#ifdef _MSC_VER
|
||||
void SetWin32ThreadName(DWORD dwThreadID, const char* threadName);
|
||||
#else
|
||||
static inline void SetWin32ThreadName(DWORD dwThreadID, const char* threadName) {}
|
||||
#endif
|
||||
|
||||
void Win32SetCurrentLocaleName(const char *iso_code);
|
||||
int OTTDStringCompare(const char *s1, const char *s2);
|
||||
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include "../stdafx.h"
|
||||
#include "../debug.h"
|
||||
#include "../station_base.h"
|
||||
#include "../thread/thread.h"
|
||||
#include "../thread.h"
|
||||
#include "../town.h"
|
||||
#include "../network/network.h"
|
||||
#include "../window_func.h"
|
||||
|
@ -372,7 +372,7 @@ void NORETURN SlErrorCorruptFmt(const char *format, ...)
|
|||
|
||||
typedef void (*AsyncSaveFinishProc)(); ///< Callback for when the savegame loading is finished.
|
||||
static AsyncSaveFinishProc _async_save_finish = NULL; ///< Callback to call when the savegame loading is finished.
|
||||
static ThreadObject *_save_thread; ///< The thread we're using to compress and write a savegame
|
||||
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.
|
||||
|
@ -397,10 +397,8 @@ void ProcessAsyncSaveFinish()
|
|||
|
||||
_async_save_finish = NULL;
|
||||
|
||||
if (_save_thread != NULL) {
|
||||
_save_thread->Join();
|
||||
delete _save_thread;
|
||||
_save_thread = NULL;
|
||||
if (_save_thread.joinable()) {
|
||||
_save_thread.join();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2486,19 +2484,11 @@ static SaveOrLoadResult SaveFileToDisk(bool threaded)
|
|||
}
|
||||
}
|
||||
|
||||
/** Thread run function for saving the file to disk. */
|
||||
static void SaveFileToDiskThread(void *arg)
|
||||
{
|
||||
SaveFileToDisk(true);
|
||||
}
|
||||
|
||||
void WaitTillSaved()
|
||||
{
|
||||
if (_save_thread == NULL) return;
|
||||
if (!_save_thread.joinable()) return;
|
||||
|
||||
_save_thread->Join();
|
||||
delete _save_thread;
|
||||
_save_thread = NULL;
|
||||
_save_thread.join();
|
||||
|
||||
/* Make sure every other state is handled properly as well. */
|
||||
ProcessAsyncSaveFinish();
|
||||
|
@ -2525,7 +2515,8 @@ static SaveOrLoadResult DoSave(SaveFilter *writer, bool threaded)
|
|||
SlSaveChunks();
|
||||
|
||||
SaveFileStart();
|
||||
if (!threaded || !ThreadObject::New(&SaveFileToDiskThread, NULL, &_save_thread, "ottd:savegame")) {
|
||||
|
||||
if (!threaded || !StartNewThread(&_save_thread, "ottd:savegame", &SaveFileToDisk, true)) {
|
||||
if (threaded) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
|
||||
|
||||
SaveOrLoadResult result = SaveFileToDisk(false);
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
#include <windows.h>
|
||||
#include <mmsystem.h>
|
||||
#include "../os/windows/win32.h"
|
||||
#include "../thread.h"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
|
@ -42,7 +43,7 @@ static void PrepareHeader(WAVEHDR *hdr)
|
|||
|
||||
static DWORD WINAPI SoundThread(LPVOID arg)
|
||||
{
|
||||
SetWin32ThreadName(-1, "ottd:win-sound");
|
||||
SetCurrentThreadName("ottd:win-sound");
|
||||
|
||||
do {
|
||||
for (WAVEHDR *hdr = _wave_hdr; hdr != endof(_wave_hdr); hdr++) {
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/* $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 { };
|
||||
|
||||
|
||||
/**
|
||||
* Get number of processor cores in the system, including HyperThreading or similar.
|
||||
* @return Total number of processor cores.
|
||||
*/
|
||||
uint GetCPUCoreCount();
|
||||
|
||||
/**
|
||||
* Name the thread this function is called on for the debugger.
|
||||
* @param name Name to set for the thread..
|
||||
*/
|
||||
void SetCurrentThreadName(const char *name);
|
||||
|
||||
|
||||
/**
|
||||
* 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,59 +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);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get number of processor cores in the system, including HyperThreading or similar.
|
||||
* @return Total number of processor cores.
|
||||
*/
|
||||
uint GetCPUCoreCount();
|
||||
|
||||
#endif /* THREAD_H */
|
|
@ -1,30 +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() {}
|
||||
};
|
|
@ -1,91 +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;
|
||||
}
|
|
@ -1,110 +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 <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;
|
||||
}
|
|
@ -1,111 +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 <stdlib.h>
|
||||
#include <windows.h>
|
||||
#include <process.h>
|
||||
#include "../os/windows/win32.h"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
/**
|
||||
* 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;
|
||||
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;
|
||||
}
|
|
@ -73,6 +73,7 @@ static void DedicatedSignalHandler(int sig)
|
|||
# include <time.h>
|
||||
# include <tchar.h>
|
||||
# include "../os/windows/win32.h"
|
||||
# include "../thread.h"
|
||||
static HANDLE _hInputReady, _hWaitForInputHandling;
|
||||
static HANDLE _hThread; // Thread to close
|
||||
static char _win_console_thread_buffer[200];
|
||||
|
@ -80,7 +81,7 @@ static char _win_console_thread_buffer[200];
|
|||
/* Windows Console thread. Just loop and signal when input has been received */
|
||||
static void WINAPI CheckForConsoleInput()
|
||||
{
|
||||
SetWin32ThreadName(-1, "ottd:win-console");
|
||||
SetCurrentThreadName("ottd:win-console");
|
||||
|
||||
DWORD nb;
|
||||
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
#include "../rev.h"
|
||||
#include "../blitter/factory.hpp"
|
||||
#include "../network/network.h"
|
||||
#include "../thread/thread.h"
|
||||
#include "../thread.h"
|
||||
#include "../progress.h"
|
||||
#include "../core/random_func.hpp"
|
||||
#include "../core/math_func.hpp"
|
||||
|
@ -38,8 +38,6 @@ static bool _all_modes;
|
|||
|
||||
/** Whether the drawing is/may be done in a separate thread. */
|
||||
static bool _draw_threaded;
|
||||
/** Thread used to 'draw' to the screen, i.e. push data to the screen. */
|
||||
static ThreadObject *_draw_thread = NULL;
|
||||
/** Mutex to keep the access to the shared memory controlled. */
|
||||
static std::recursive_mutex *_draw_mutex = NULL;
|
||||
/** Signal to draw the next frame. */
|
||||
|
@ -173,7 +171,7 @@ static void DrawSurfaceToScreen()
|
|||
}
|
||||
}
|
||||
|
||||
static void DrawSurfaceToScreenThread(void *)
|
||||
static void DrawSurfaceToScreenThread()
|
||||
{
|
||||
/* First tell the main thread we're started */
|
||||
std::unique_lock<std::recursive_mutex> lock(*_draw_mutex);
|
||||
|
@ -188,8 +186,6 @@ static void DrawSurfaceToScreenThread(void *)
|
|||
DrawSurfaceToScreen();
|
||||
_draw_signal->wait(lock);
|
||||
}
|
||||
|
||||
_draw_thread->Exit();
|
||||
}
|
||||
|
||||
static const Dimension _default_resolutions[] = {
|
||||
|
@ -671,6 +667,7 @@ void VideoDriver_SDL::MainLoop()
|
|||
|
||||
CheckPaletteAnim();
|
||||
|
||||
std::thread draw_thread;
|
||||
std::unique_lock<std::recursive_mutex> draw_lock;
|
||||
if (_draw_threaded) {
|
||||
/* Initialise the mutex first, because that's the thing we *need*
|
||||
|
@ -683,7 +680,7 @@ void VideoDriver_SDL::MainLoop()
|
|||
_draw_signal = new std::condition_variable_any();
|
||||
_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. */
|
||||
if (!_draw_threaded) {
|
||||
|
@ -795,15 +792,13 @@ void VideoDriver_SDL::MainLoop()
|
|||
_draw_signal->notify_one();
|
||||
if (draw_lock.owns_lock()) draw_lock.unlock();
|
||||
draw_lock.release();
|
||||
_draw_thread->Join();
|
||||
draw_thread.join();
|
||||
|
||||
delete _draw_mutex;
|
||||
delete _draw_signal;
|
||||
delete _draw_thread;
|
||||
|
||||
_draw_mutex = NULL;
|
||||
_draw_signal = NULL;
|
||||
_draw_thread = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#include "../core/math_func.hpp"
|
||||
#include "../core/random_func.hpp"
|
||||
#include "../texteff.hpp"
|
||||
#include "../thread/thread.h"
|
||||
#include "../thread.h"
|
||||
#include "../progress.h"
|
||||
#include "../window_gui.h"
|
||||
#include "../window_func.h"
|
||||
|
@ -67,8 +67,6 @@ DWORD _imm_props;
|
|||
|
||||
/** Whether the drawing is/may be done in a separate thread. */
|
||||
static bool _draw_threaded;
|
||||
/** Thread used to 'draw' to the screen, i.e. push data to the screen. */
|
||||
static ThreadObject *_draw_thread = NULL;
|
||||
/** Mutex to keep the access to the shared memory controlled. */
|
||||
static std::recursive_mutex *_draw_mutex = NULL;
|
||||
/** Signal to draw the next frame. */
|
||||
|
@ -395,7 +393,7 @@ static void PaintWindow(HDC dc)
|
|||
DeleteDC(dc2);
|
||||
}
|
||||
|
||||
static void PaintWindowThread(void *)
|
||||
static void PaintWindowThread()
|
||||
{
|
||||
/* First tell the main thread we're started */
|
||||
std::unique_lock<std::recursive_mutex> lock(*_draw_mutex);
|
||||
|
@ -426,8 +424,6 @@ static void PaintWindowThread(void *)
|
|||
|
||||
_draw_signal->wait(*_draw_mutex);
|
||||
}
|
||||
|
||||
_draw_thread->Exit();
|
||||
}
|
||||
|
||||
/** Forward key presses to the window system. */
|
||||
|
@ -1190,6 +1186,7 @@ void VideoDriver_Win32::MainLoop()
|
|||
uint32 last_cur_ticks = cur_ticks;
|
||||
uint32 next_tick = cur_ticks + MILLISECONDS_PER_TICK;
|
||||
|
||||
std::thread draw_thread;
|
||||
std::unique_lock<std::recursive_mutex> draw_lock;
|
||||
|
||||
if (_draw_threaded) {
|
||||
|
@ -1206,7 +1203,7 @@ void VideoDriver_Win32::MainLoop()
|
|||
draw_lock = std::unique_lock<std::recursive_mutex>(*_draw_mutex);
|
||||
|
||||
_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. */
|
||||
if (!_draw_threaded) {
|
||||
|
@ -1308,11 +1305,10 @@ void VideoDriver_Win32::MainLoop()
|
|||
_draw_signal->notify_all();
|
||||
if (draw_lock.owns_lock()) draw_lock.unlock();
|
||||
draw_lock.release();
|
||||
_draw_thread->Join();
|
||||
draw_thread.join();
|
||||
|
||||
delete _draw_mutex;
|
||||
delete _draw_signal;
|
||||
delete _draw_thread;
|
||||
|
||||
_draw_mutex = NULL;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue