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.pull/88/head
parent
05f4e73608
commit
05bc2ed7cb
@ -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;
|
||||
}
|
Loading…
Reference in New Issue