Fix tinythread memory leak in two ways:

1. update to tinythread version 1.1, which provides a detach method
2. move the thread disassociation to the join function, which allows
attached threads to be joined even after they finish (this was the main
leak)

Also update RemoteServer.cpp to detach threads and delete the thread
objects instead of leaking them (although they are much smaller than the
actual threads).
develop
Ben Lubar 2016-05-21 19:17:08 -05:00
parent dabf443260
commit 700392ba55
4 changed files with 98 additions and 42 deletions

@ -1,5 +1,5 @@
/*
Copyright (c) 2010 Marcus Geelnard
/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*-
Copyright (c) 2010-2012 Marcus Geelnard
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -47,7 +47,15 @@ freely, subject to the following restrictions:
#endif
#if defined(_TTHREAD_WIN32_)
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#define __UNDEF_LEAN_AND_MEAN
#endif
#include <windows.h>
#ifdef __UNDEF_LEAN_AND_MEAN
#undef WIN32_LEAN_AND_MEAN
#undef __UNDEF_LEAN_AND_MEAN
#endif
#else
#ifdef _FAST_MUTEX_ASM_
#include <sched.h>
@ -237,3 +245,4 @@ class fast_mutex {
}
#endif // _FAST_MUTEX_H_

@ -1,5 +1,5 @@
/*
Copyright (c) 2010 Marcus Geelnard
/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*-
Copyright (c) 2010-2012 Marcus Geelnard
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -171,13 +171,17 @@ void * thread::wrapper_function(void * aArg)
catch(...)
{
// Uncaught exceptions will terminate the application (default behavior
// according to the C++0x draft)
// according to C++11)
std::terminate();
}
#if 0
// DFHack fix: this code prevents join from freeing thread resources.
// The thread is no longer executing
lock_guard<mutex> guard(ti->mThread->mDataMutex);
ti->mThread->mNotAThread = true;
#endif
// The thread is responsible for freeing the startup information
delete ti;
@ -228,9 +232,16 @@ void thread::join()
{
#if defined(_TTHREAD_WIN32_)
WaitForSingleObject(mHandle, INFINITE);
CloseHandle(mHandle);
#elif defined(_TTHREAD_POSIX_)
pthread_join(mHandle, NULL);
#endif
#if 1
// DFHack patch: moved here from the wrapper function
lock_guard<mutex> guard(mDataMutex);
mNotAThread = true;
#endif
}
}
@ -242,6 +253,21 @@ bool thread::joinable() const
return result;
}
void thread::detach()
{
mDataMutex.lock();
if(!mNotAThread)
{
#if defined(_TTHREAD_WIN32_)
CloseHandle(mHandle);
#elif defined(_TTHREAD_POSIX_)
pthread_detach(mHandle);
#endif
mNotAThread = true;
}
mDataMutex.unlock();
}
thread::id thread::get_id() const
{
if(!joinable())

@ -1,5 +1,5 @@
/*
Copyright (c) 2010 Marcus Geelnard
/* -*- mode: c++; tab-width: 2; indent-tabs-mode: nil; -*-
Copyright (c) 2010-2012 Marcus Geelnard
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
@ -31,7 +31,7 @@ freely, subject to the following restrictions:
/// TinyThread++ is a minimal, portable implementation of basic threading
/// classes for C++.
///
/// They closely mimic the functionality and naming of the C++0x standard, and
/// They closely mimic the functionality and naming of the C++11 standard, and
/// should be easily replaceable with the corresponding std:: variants.
///
/// @section port_sec Portability
@ -39,7 +39,7 @@ freely, subject to the following restrictions:
/// classes, while for other systems, the POSIX threads API (pthread) is used.
///
/// @section class_sec Classes
/// In order to mimic the threading API of the C++0x standard, subsets of
/// In order to mimic the threading API of the C++11 standard, subsets of
/// several classes are provided. The fundamental classes are:
/// @li tthread::thread
/// @li tthread::mutex
@ -67,8 +67,15 @@ freely, subject to the following restrictions:
// Platform specific includes
#if defined(_TTHREAD_WIN32_)
#define NOMINMAX
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#define __UNDEF_LEAN_AND_MEAN
#endif
#include <windows.h>
#ifdef __UNDEF_LEAN_AND_MEAN
#undef WIN32_LEAN_AND_MEAN
#undef __UNDEF_LEAN_AND_MEAN
#endif
#else
#include <pthread.h>
#include <signal.h>
@ -82,22 +89,22 @@ freely, subject to the following restrictions:
/// TinyThread++ version (major number).
#define TINYTHREAD_VERSION_MAJOR 1
/// TinyThread++ version (minor number).
#define TINYTHREAD_VERSION_MINOR 0
#define TINYTHREAD_VERSION_MINOR 1
/// TinyThread++ version (full version).
#define TINYTHREAD_VERSION (TINYTHREAD_VERSION_MAJOR * 100 + TINYTHREAD_VERSION_MINOR)
// Do we have a fully featured C++0x compiler?
// Do we have a fully featured C++11 compiler?
#if (__cplusplus > 199711L) || (defined(__STDCXX_VERSION__) && (__STDCXX_VERSION__ >= 201001L))
#define _TTHREAD_CPP0X_
#define _TTHREAD_CPP11_
#endif
// ...at least partial C++0x?
#if defined(_TTHREAD_CPP0X_) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__)
#define _TTHREAD_CPP0X_PARTIAL_
// ...at least partial C++11?
#if defined(_TTHREAD_CPP11_) || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(__GXX_EXPERIMENTAL_CPP0X__)
#define _TTHREAD_CPP11_PARTIAL_
#endif
// Macro for disabling assignments of objects.
#ifdef _TTHREAD_CPP0X_PARTIAL_
#ifdef _TTHREAD_CPP11_PARTIAL_
#define _TTHREAD_DISABLE_ASSIGNMENT(name) \
name(const name&) = delete; \
name& operator=(const name&) = delete;
@ -109,18 +116,18 @@ freely, subject to the following restrictions:
/// @def thread_local
/// Thread local storage keyword.
/// A variable that is declared with the \c thread_local keyword makes the
/// A variable that is declared with the @c thread_local keyword makes the
/// value of the variable local to each thread (known as thread-local storage,
/// or TLS). Example usage:
/// @code
/// // This variable is local to each thread.
/// thread_local int variable;
/// @endcode
/// @note The \c thread_local keyword is a macro that maps to the corresponding
/// compiler directive (e.g. \c __declspec(thread)). While the C++0x standard
/// @note The @c thread_local keyword is a macro that maps to the corresponding
/// compiler directive (e.g. @c __declspec(thread)). While the C++11 standard
/// allows for non-trivial types (e.g. classes with constructors and
/// destructors) to be declared with the \c thread_local keyword, most pre-C++0x
/// compilers only allow for trivial types (e.g. \c int). So, to guarantee
/// destructors) to be declared with the @c thread_local keyword, most pre-C++11
/// compilers only allow for trivial types (e.g. @c int). So, to guarantee
/// portable code, only use trivial types for thread local storage.
/// @note This directive is currently not supported on Mac OS X (it will give
/// a compiler error), since compile-time TLS is not supported in the Mac OS X
@ -128,7 +135,7 @@ freely, subject to the following restrictions:
/// not support this directive.
/// @hideinitializer
#if !defined(_TTHREAD_CPP0X_) && !defined(thread_local)
#if !defined(_TTHREAD_CPP11_) && !defined(thread_local)
#if defined(__GNUC__) || defined(__INTEL_COMPILER) || defined(__SUNPRO_CC) || defined(__IBMCPP__)
#define thread_local __thread
#else
@ -138,8 +145,8 @@ freely, subject to the following restrictions:
/// Main name space for TinyThread++.
/// This namespace is more or less equivalent to the \c std namespace for the
/// C++0x thread classes. For instance, the tthread::mutex class corresponds to
/// This namespace is more or less equivalent to the @c std namespace for the
/// C++11 thread classes. For instance, the tthread::mutex class corresponds to
/// the std::mutex class.
namespace tthread {
@ -176,7 +183,7 @@ class mutex {
/// Lock the mutex.
/// The method will block the calling thread until a lock on the mutex can
/// be obtained. The mutex remains locked until \c unlock() is called.
/// be obtained. The mutex remains locked until @c unlock() is called.
/// @see lock_guard
inline void lock()
{
@ -192,7 +199,7 @@ class mutex {
/// Try to lock the mutex.
/// The method will try to lock the mutex. If it fails, the function will
/// return immediately (non-blocking).
/// @return \c true if the lock was acquired, or \c false if the lock could
/// @return @c true if the lock was acquired, or @c false if the lock could
/// not be acquired.
inline bool try_lock()
{
@ -268,7 +275,7 @@ class recursive_mutex {
/// Lock the mutex.
/// The method will block the calling thread until a lock on the mutex can
/// be obtained. The mutex remains locked until \c unlock() is called.
/// be obtained. The mutex remains locked until @c unlock() is called.
/// @see lock_guard
inline void lock()
{
@ -282,7 +289,7 @@ class recursive_mutex {
/// Try to lock the mutex.
/// The method will try to lock the mutex. If it fails, the function will
/// return immediately (non-blocking).
/// @return \c true if the lock was acquired, or \c false if the lock could
/// @return @c true if the lock was acquired, or @c false if the lock could
/// not be acquired.
inline bool try_lock()
{
@ -406,7 +413,7 @@ class condition_variable {
/// Wait for the condition.
/// The function will block the calling thread until the condition variable
/// is woken by \c notify_one(), \c notify_all() or a spurious wake up.
/// is woken by @c notify_one(), @c notify_all() or a spurious wake up.
/// @param[in] aMutex A mutex that will be unlocked when the wait operation
/// starts, an locked again as soon as the wait operation is finished.
template <class _mutexT>
@ -482,7 +489,7 @@ class thread {
class id;
/// Default constructor.
/// Construct a \c thread object without an associated thread of execution
/// Construct a @c thread object without an associated thread of execution
/// (i.e. non-joinable).
thread() : mHandle(0), mNotAThread(true)
#if defined(_TTHREAD_WIN32_)
@ -491,7 +498,7 @@ class thread {
{}
/// Thread starting constructor.
/// Construct a \c thread object with a new thread of execution.
/// Construct a @c thread object with a new thread of execution.
/// @param[in] aFunction A function pointer to a function of type:
/// <tt>void fun(void * arg)</tt>
/// @param[in] aArg Argument to the thread function.
@ -501,24 +508,34 @@ class thread {
thread(void (*aFunction)(void *), void * aArg);
/// Destructor.
/// @note If the thread is joinable upon destruction, \c std::terminate()
/// @note If the thread is joinable upon destruction, @c std::terminate()
/// will be called, which terminates the process. It is always wise to do
/// \c join() before deleting a thread object.
/// @c join() before deleting a thread object.
~thread();
/// Wait for the thread to finish (join execution flows).
/// After calling @c join(), the thread object is no longer associated with
/// a thread of execution (i.e. it is not joinable, and you may not join
/// with it nor detach from it).
void join();
/// Check if the thread is joinable.
/// A thread object is joinable if it has an associated thread of execution.
bool joinable() const;
/// Detach from the thread.
/// After calling @c detach(), the thread object is no longer assicated with
/// a thread of execution (i.e. it is not joinable). The thread continues
/// execution without the calling thread blocking, and when the thread
/// ends execution, any owned resources are released.
void detach();
/// Return the thread ID of a thread object.
id get_id() const;
/// Get the native handle for this thread.
/// @note Under Windows, this is a \c HANDLE, and under POSIX systems, this
/// is a \c pthread_t.
/// @note Under Windows, this is a @c HANDLE, and under POSIX systems, this
/// is a @c pthread_t.
inline native_handle_type native_handle()
{
return mHandle;
@ -613,18 +630,18 @@ class thread::id {
// Related to <ratio> - minimal to be able to support chrono.
typedef long long __intmax_t;
/// Minimal implementation of the \c ratio class. This class provides enough
/// functionality to implement some basic \c chrono classes.
/// Minimal implementation of the @c ratio class. This class provides enough
/// functionality to implement some basic @c chrono classes.
template <__intmax_t N, __intmax_t D = 1> class ratio {
public:
static double _as_double() { return double(N) / double(D); }
};
/// Minimal implementation of the \c chrono namespace.
/// The \c chrono namespace provides types for specifying time intervals.
/// Minimal implementation of the @c chrono namespace.
/// The @c chrono namespace provides types for specifying time intervals.
namespace chrono {
/// Duration template class. This class provides enough functionality to
/// implement \c this_thread::sleep_for().
/// implement @c this_thread::sleep_for().
template <class _Rep, class _Period = ratio<1> > class duration {
private:
_Rep rep_;
@ -652,7 +669,7 @@ namespace chrono {
typedef duration<__intmax_t, ratio<3600> > hours; ///< Duration with the unit hours.
}
/// The namespace \c this_thread provides methods for dealing with the
/// The namespace @c this_thread provides methods for dealing with the
/// calling thread.
namespace this_thread {
/// Return the thread ID of the calling thread.

@ -117,6 +117,7 @@ ServerConnection::ServerConnection(CActiveSocket *socket)
core_service->finalize(this, &functions);
thread = new tthread::thread(threadFn, (void*)this);
thread->detach();
}
ServerConnection::~ServerConnection()
@ -124,6 +125,7 @@ ServerConnection::~ServerConnection()
in_error = true;
socket->Close();
delete socket;
delete thread;
for (auto it = plugin_services.begin(); it != plugin_services.end(); ++it)
delete it->second;
@ -363,6 +365,7 @@ ServerMain::~ServerMain()
{
socket->Close();
delete socket;
delete thread;
}
bool ServerMain::listen(int port)
@ -376,6 +379,7 @@ bool ServerMain::listen(int port)
return false;
thread = new tthread::thread(threadFn, this);
thread->detach();
return true;
}