Import Geant4 11.1.0.beta source tree
This commit is contained in:
+797
@@ -0,0 +1,797 @@
|
||||
//
|
||||
// MIT License
|
||||
// Copyright (c) 2020 Jonathan R. Madsen
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
|
||||
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// Backtrace
|
||||
//
|
||||
// Description:
|
||||
//
|
||||
// Prints backtraces after signals are caught. Available on Unix.
|
||||
//
|
||||
// Usage:
|
||||
// A standard set of signals are enabled by default:
|
||||
//
|
||||
// SIGQUIT, SIGILL, SIGABRT, SIGKILL, SIGBUS, SIGSEGV
|
||||
//
|
||||
// These should not interfere with debuggers and/or FPEDetection.
|
||||
// In order to turn off handling for one or more signals, one can do:
|
||||
//
|
||||
// BackTrace::DefaultSignals() = std::set<int>{};
|
||||
// BackTrace::DefaultSignals() = std::set<int>{ SIGSEGV };
|
||||
//
|
||||
// and so on, *before* creating the run-manager. After the run-manager
|
||||
// has been created, one should disable the signals:
|
||||
//
|
||||
// BackTrace::Disable(BackTrace::DefaultSignals());
|
||||
//
|
||||
// Additionally, at runtime, the environment variable "BACKTRACE" can
|
||||
// be set to select a specific set of signals or none, e.g. in bash:
|
||||
//
|
||||
// export BACKTRACE="SIGQUIT,SIGSEGV"
|
||||
// export BACKTRACE="none"
|
||||
//
|
||||
// The environment variable is case-insensitive and can use any of the
|
||||
// following delimiters: space, comma, semi-colon, colon
|
||||
//
|
||||
// Author: J.Madsen, 19 October 2020
|
||||
// --------------------------------------------------------------------
|
||||
|
||||
#ifndef PTL_Backtrace_hh
|
||||
#define PTL_Backtrace_hh 1
|
||||
|
||||
#include "Threading.hh"
|
||||
#include "Types.hh"
|
||||
|
||||
#if defined(PTL_UNIX)
|
||||
# include <cxxabi.h>
|
||||
# include <execinfo.h>
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(PTL_LINUX)
|
||||
# include <features.h>
|
||||
#endif
|
||||
|
||||
#include <cfenv>
|
||||
#include <csignal>
|
||||
#include <type_traits>
|
||||
|
||||
namespace PTL
|
||||
{
|
||||
template <typename FuncT>
|
||||
using ResultOf_t = typename std::result_of<FuncT>::type;
|
||||
}
|
||||
|
||||
// compatible OS and compiler
|
||||
#if defined(PTL_UNIX) && \
|
||||
(defined(__GNUC__) || defined(__clang__) || defined(_INTEL_COMPILER))
|
||||
# if !defined(PTL_SIGNAL_AVAILABLE)
|
||||
# define PTL_SIGNAL_AVAILABLE
|
||||
# endif
|
||||
# if !defined(PTL_DEMANGLE_AVAILABLE)
|
||||
# define PTL_DEMANGLE_AVAILABLE
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if !defined(PTL_PSIGINFO_AVAILABLE)
|
||||
# if _XOPEN_SOURCE >= 700 || _POSIX_C_SOURCE >= 200809L
|
||||
# define PTL_PSIGINFO_AVAILABLE 1
|
||||
# else
|
||||
# define PTL_PSIGINFO_AVAILABLE 0
|
||||
# endif
|
||||
#endif
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
namespace PTL
|
||||
{
|
||||
inline std::string
|
||||
Demangle(const char* _str)
|
||||
{
|
||||
#if defined(PTL_DEMANGLE_AVAILABLE)
|
||||
// demangling a string when delimiting
|
||||
int _status = 0;
|
||||
char* _ret = ::abi::__cxa_demangle(_str, nullptr, nullptr, &_status);
|
||||
if(_ret && _status == 0)
|
||||
return std::string(const_cast<const char*>(_ret));
|
||||
return _str;
|
||||
#else
|
||||
return _str;
|
||||
#endif
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
inline std::string
|
||||
Demangle(const std::string& _str)
|
||||
{
|
||||
return Demangle(_str.c_str());
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
template <typename Tp>
|
||||
inline std::string
|
||||
Demangle()
|
||||
{
|
||||
return Demangle(typeid(Tp).name());
|
||||
}
|
||||
} // namespace PTL
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
//
|
||||
// ONLY IF SIGNAL_AVAILABLE
|
||||
//
|
||||
//----------------------------------------------------------------------------//
|
||||
//
|
||||
#if defined(PTL_SIGNAL_AVAILABLE)
|
||||
//
|
||||
// these are not in the original POSIX.1-1990 standard so we are defining
|
||||
// them in case the OS hasn't
|
||||
// POSIX-1.2001
|
||||
# ifndef SIGTRAP
|
||||
# define SIGTRAP 5
|
||||
# endif
|
||||
// not specified in POSIX.1-2001, but nevertheless appears on most other
|
||||
// UNIX systems, where its default action is typically to terminate the
|
||||
// process with a core dump.
|
||||
# ifndef SIGEMT
|
||||
# define SIGEMT 7
|
||||
# endif
|
||||
// POSIX-1.2001
|
||||
# ifndef SIGURG
|
||||
# define SIGURG 16
|
||||
# endif
|
||||
// POSIX-1.2001
|
||||
# ifndef SIGXCPU
|
||||
# define SIGXCPU 24
|
||||
# endif
|
||||
// POSIX-1.2001
|
||||
# ifndef SIGXFSZ
|
||||
# define SIGXFSZ 25
|
||||
# endif
|
||||
// POSIX-1.2001
|
||||
# ifndef SIGVTALRM
|
||||
# define SIGVTALRM 26
|
||||
# endif
|
||||
// POSIX-1.2001
|
||||
# ifndef SIGPROF
|
||||
# define SIGPROF 27
|
||||
# endif
|
||||
// POSIX-1.2001
|
||||
# ifndef SIGINFO
|
||||
# define SIGINFO 29
|
||||
# endif
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
# include <algorithm>
|
||||
# include <array>
|
||||
# include <cstdio>
|
||||
# include <cstdlib>
|
||||
# include <functional>
|
||||
# include <iomanip>
|
||||
# include <iostream>
|
||||
# include <map>
|
||||
# include <regex>
|
||||
# include <set>
|
||||
# include <sstream>
|
||||
# include <string>
|
||||
# include <tuple>
|
||||
# include <vector>
|
||||
|
||||
// PTL header
|
||||
# include "Threading.hh"
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
namespace PTL
|
||||
{
|
||||
class Backtrace
|
||||
{
|
||||
public:
|
||||
using sigaction_t = struct sigaction;
|
||||
using exit_action_t = std::function<void(int)>;
|
||||
using frame_func_t = std::function<std::string(const char*)>;
|
||||
using signal_set_t = std::set<int>;
|
||||
|
||||
public:
|
||||
struct actions
|
||||
{
|
||||
using id_entry_t = std::tuple<std::string, int, std::string>;
|
||||
using id_list_t = std::vector<id_entry_t>;
|
||||
|
||||
std::map<int, bool> is_active = {};
|
||||
std::map<int, sigaction_t> current = {};
|
||||
std::map<int, sigaction_t> previous = {};
|
||||
std::vector<exit_action_t> exit_actions = {};
|
||||
const id_list_t identifiers = {
|
||||
id_entry_t("SIGHUP", SIGHUP, "terminal line hangup"),
|
||||
id_entry_t("SIGINT", SIGINT, "interrupt program"),
|
||||
id_entry_t("SIGQUIT", SIGQUIT, "quit program"),
|
||||
id_entry_t("SIGILL", SIGILL, "illegal instruction"),
|
||||
id_entry_t("SIGTRAP", SIGTRAP, "trace trap"),
|
||||
id_entry_t("SIGABRT", SIGABRT, "abort program (formerly SIGIOT)"),
|
||||
id_entry_t("SIGEMT", SIGEMT, "emulate instruction executed"),
|
||||
id_entry_t("SIGFPE", SIGFPE, "floating-point exception"),
|
||||
id_entry_t("SIGKILL", SIGKILL, "kill program"),
|
||||
id_entry_t("SIGBUS", SIGBUS, "bus error"),
|
||||
id_entry_t("SIGSEGV", SIGSEGV, "segmentation violation"),
|
||||
id_entry_t("SIGSYS", SIGSYS, "non-existent system call invoked"),
|
||||
id_entry_t("SIGPIPE", SIGPIPE, "write on a pipe with no reader"),
|
||||
id_entry_t("SIGALRM", SIGALRM, "real-time timer expired"),
|
||||
id_entry_t("SIGTERM", SIGTERM, "software termination signal"),
|
||||
id_entry_t("SIGURG", SIGURG, "urgent condition present on socket"),
|
||||
id_entry_t("SIGSTOP", SIGSTOP, "stop (cannot be caught or ignored)"),
|
||||
id_entry_t("SIGTSTP", SIGTSTP, "stop signal generated from keyboard"),
|
||||
id_entry_t("SIGCONT", SIGCONT, "continue after stop"),
|
||||
id_entry_t("SIGCHLD", SIGCHLD, "child status has changed"),
|
||||
id_entry_t("SIGTTIN", SIGTTIN,
|
||||
"background read attempted from control terminal"),
|
||||
id_entry_t("SIGTTOU", SIGTTOU,
|
||||
"background write attempted to control terminal"),
|
||||
id_entry_t("SIGIO ", SIGIO, "I/O is possible on a descriptor"),
|
||||
id_entry_t("SIGXCPU", SIGXCPU, "cpu time limit exceeded"),
|
||||
id_entry_t("SIGXFSZ", SIGXFSZ, "file size limit exceeded"),
|
||||
id_entry_t("SIGVTALRM", SIGVTALRM, "virtual time alarm"),
|
||||
id_entry_t("SIGPROF", SIGPROF, "profiling timer alarm"),
|
||||
id_entry_t("SIGWINCH", SIGWINCH, "Window size change"),
|
||||
id_entry_t("SIGINFO", SIGINFO, "status request from keyboard"),
|
||||
id_entry_t("SIGUSR1", SIGUSR1, "User defined signal 1"),
|
||||
id_entry_t("SIGUSR2", SIGUSR2, "User defined signal 2")
|
||||
};
|
||||
};
|
||||
|
||||
public:
|
||||
// a functor called for each frame in the backtrace
|
||||
static frame_func_t& FrameFunctor();
|
||||
// default set of signals
|
||||
static signal_set_t& DefaultSignals();
|
||||
// the signal handler
|
||||
static void Handler(int sig, siginfo_t* sinfo, void* context);
|
||||
// information message about the signal, performs exit-actions
|
||||
// and prints back-trace
|
||||
static void Message(int sig, siginfo_t* sinfo, std::ostream&);
|
||||
// calls user-provided functions after signal is caught but before abort
|
||||
static void ExitAction(int sig);
|
||||
// enable signals via a string (which is tokenized)
|
||||
static int Enable(const std::string&);
|
||||
// enable signals via set of integers, anything less than zero is ignored
|
||||
static int Enable(const signal_set_t& _signals = DefaultSignals());
|
||||
// disable signals
|
||||
static int Disable(signal_set_t _signals = {});
|
||||
// gets the numeric value for a signal name
|
||||
static int GetSignal(const std::string&);
|
||||
// provides a description of the signal
|
||||
static std::string Description(int sig);
|
||||
|
||||
// adds an exit action
|
||||
template <typename FuncT>
|
||||
static void AddExitAction(FuncT&& func);
|
||||
|
||||
// gets a backtrace of "Depth" frames. The offset parameter is used
|
||||
// to ignore initial frames (such as this function). A callback
|
||||
// can be provided to inspect and/or tweak the frame string
|
||||
template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
|
||||
static std::array<ResultOf_t<FuncT(const char*)>, Depth> GetMangled(
|
||||
FuncT&& func = FrameFunctor());
|
||||
|
||||
// gets a demangled backtrace of "Depth" frames. The offset parameter is
|
||||
// used to ignore initial frames (such as this function). A callback
|
||||
// can be provided to inspect and/or tweak the frame string
|
||||
template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
|
||||
static std::array<ResultOf_t<FuncT(const char*)>, Depth> GetDemangled(
|
||||
FuncT&& func = FrameFunctor());
|
||||
|
||||
private:
|
||||
static actions& GetData()
|
||||
{
|
||||
static auto _instance = actions{};
|
||||
return _instance;
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
// a functor called for each frame in the backtrace
|
||||
inline Backtrace::frame_func_t&
|
||||
Backtrace::FrameFunctor()
|
||||
{
|
||||
static frame_func_t _instance = [](const char* inp) { return std::string(inp); };
|
||||
return _instance;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
// default set of signals
|
||||
inline Backtrace::signal_set_t&
|
||||
Backtrace::DefaultSignals()
|
||||
{
|
||||
static signal_set_t _instance = {
|
||||
SIGQUIT, SIGILL, SIGABRT, SIGKILL, SIGBUS, SIGSEGV
|
||||
};
|
||||
return _instance;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
template <typename FuncT>
|
||||
inline void
|
||||
Backtrace::AddExitAction(FuncT&& func)
|
||||
{
|
||||
GetData().exit_actions.emplace_back(std::forward<FuncT>(func));
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
inline void
|
||||
Backtrace::ExitAction(int sig)
|
||||
{
|
||||
for(auto& itr : GetData().exit_actions)
|
||||
itr(sig);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
template <size_t Depth, size_t Offset, typename FuncT>
|
||||
inline std::array<ResultOf_t<FuncT(const char*)>, Depth>
|
||||
Backtrace::GetMangled(FuncT&& func)
|
||||
{
|
||||
static_assert((Depth - Offset) >= 1, "Error Depth - Offset should be >= 1");
|
||||
|
||||
using type = ResultOf_t<FuncT(const char*)>;
|
||||
// destination
|
||||
std::array<type, Depth> btrace;
|
||||
btrace.fill((std::is_pointer<type>::value) ? nullptr : type{});
|
||||
|
||||
// plus one for this stack-frame
|
||||
std::array<void*, Depth + Offset> buffer;
|
||||
// size of returned buffer
|
||||
auto sz = backtrace(buffer.data(), Depth + Offset);
|
||||
// size of relevant data
|
||||
auto n = sz - Offset;
|
||||
|
||||
// skip ahead (Offset + 1) stack frames
|
||||
char** bsym = backtrace_symbols(buffer.data() + Offset, n);
|
||||
|
||||
// report errors
|
||||
if(bsym == nullptr)
|
||||
perror("backtrace_symbols");
|
||||
else
|
||||
{
|
||||
for(decltype(n) i = 0; i < n; ++i)
|
||||
btrace[i] = func(bsym[i]);
|
||||
free(bsym);
|
||||
}
|
||||
return btrace;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
template <size_t Depth, size_t Offset, typename FuncT>
|
||||
inline std::array<ResultOf_t<FuncT(const char*)>, Depth>
|
||||
Backtrace::GetDemangled(FuncT&& func)
|
||||
{
|
||||
auto demangle_bt = [&](const char* cstr) {
|
||||
auto _trim = [](std::string& _sub, size_t& _len) {
|
||||
size_t _pos = 0;
|
||||
while((_pos = _sub.find_first_of(' ')) == 0)
|
||||
{
|
||||
_sub = _sub.erase(_pos, 1);
|
||||
--_len;
|
||||
}
|
||||
while((_pos = _sub.find_last_of(' ')) == _sub.length() - 1)
|
||||
{
|
||||
_sub = _sub.substr(0, _sub.length() - 1);
|
||||
--_len;
|
||||
}
|
||||
return _sub;
|
||||
};
|
||||
|
||||
auto str = Demangle(std::string(cstr));
|
||||
auto beg = str.find("(");
|
||||
if(beg == std::string::npos)
|
||||
{
|
||||
beg = str.find("_Z");
|
||||
if(beg != std::string::npos)
|
||||
beg -= 1;
|
||||
}
|
||||
auto end = str.find("+", beg);
|
||||
if(beg != std::string::npos && end != std::string::npos)
|
||||
{
|
||||
auto len = end - (beg + 1);
|
||||
auto sub = str.substr(beg + 1, len);
|
||||
auto dem = Demangle(_trim(sub, len));
|
||||
str = str.replace(beg + 1, len, dem);
|
||||
}
|
||||
else if(beg != std::string::npos)
|
||||
{
|
||||
auto len = str.length() - (beg + 1);
|
||||
auto sub = str.substr(beg + 1, len);
|
||||
auto dem = Demangle(_trim(sub, len));
|
||||
str = str.replace(beg + 1, len, dem);
|
||||
}
|
||||
else if(end != std::string::npos)
|
||||
{
|
||||
auto len = end;
|
||||
auto sub = str.substr(beg, len);
|
||||
auto dem = Demangle(_trim(sub, len));
|
||||
str = str.replace(beg, len, dem);
|
||||
}
|
||||
return func(str.c_str());
|
||||
};
|
||||
return GetMangled<Depth, Offset>(demangle_bt);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
inline void
|
||||
Backtrace::Message(int sig, siginfo_t* sinfo, std::ostream& os)
|
||||
{
|
||||
// try to avoid as many dynamic allocations as possible here to avoid
|
||||
// overflowing the signal stack
|
||||
|
||||
// ignore future signals of this type
|
||||
sigignore(sig);
|
||||
|
||||
os << "\n### CAUGHT SIGNAL: " << sig << " ### ";
|
||||
if(sinfo)
|
||||
os << "address: " << sinfo->si_addr << ", ";
|
||||
os << Description(sig) << ". ";
|
||||
|
||||
if(sig == SIGSEGV)
|
||||
{
|
||||
if(sinfo)
|
||||
{
|
||||
switch(sinfo->si_code)
|
||||
{
|
||||
case SEGV_MAPERR: os << "Address not mapped to object."; break;
|
||||
case SEGV_ACCERR: os << "Invalid permissions for mapped object."; break;
|
||||
default:
|
||||
os << "Unknown segmentation fault error: " << sinfo->si_code << ".";
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
os << "Segmentation fault (unknown).";
|
||||
}
|
||||
}
|
||||
else if(sig == SIGFPE)
|
||||
{
|
||||
if(sinfo)
|
||||
{
|
||||
switch(sinfo->si_code)
|
||||
{
|
||||
case FE_DIVBYZERO: os << "Floating point divide by zero."; break;
|
||||
case FE_OVERFLOW: os << "Floating point overflow."; break;
|
||||
case FE_UNDERFLOW: os << "Floating point underflow."; break;
|
||||
case FE_INEXACT: os << "Floating point inexact result."; break;
|
||||
case FE_INVALID: os << "Floating point invalid operation."; break;
|
||||
default:
|
||||
os << "Unknown floating point exception error: " << sinfo->si_code
|
||||
<< ".";
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
os << "Unknown floating point exception";
|
||||
if(sinfo)
|
||||
os << ": " << sinfo->si_code;
|
||||
os << ". ";
|
||||
}
|
||||
}
|
||||
|
||||
os << '\n';
|
||||
|
||||
auto bt = GetMangled<256, 3>([](const char* _s) { return _s; });
|
||||
char prefix[64];
|
||||
snprintf(prefix, 64, "[PID=%i, TID=%i]", (int) getpid(),
|
||||
(int) Threading::GetThreadId());
|
||||
size_t sz = 0;
|
||||
for(auto& itr : bt)
|
||||
{
|
||||
if(!itr)
|
||||
break;
|
||||
if(strlen(itr) == 0)
|
||||
break;
|
||||
++sz;
|
||||
}
|
||||
os << "\nBacktrace:\n";
|
||||
auto _w = std::log10(sz) + 1;
|
||||
for(size_t i = 0; i < sz; ++i)
|
||||
{
|
||||
os << prefix << "[" << std::setw(_w) << std::right << i << '/' << std::setw(_w)
|
||||
<< std::right << sz << "]> " << std::left << bt.at(i) << '\n';
|
||||
}
|
||||
os << std::flush;
|
||||
|
||||
// exit action could cause more signals to be raise so make sure this is done
|
||||
// after the message has been printed
|
||||
try
|
||||
{
|
||||
ExitAction(sig);
|
||||
} catch(std::exception& e)
|
||||
{
|
||||
std::cerr << "ExitAction(" << sig << ") threw an exception" << std::endl;
|
||||
std::cerr << e.what() << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
inline void
|
||||
Backtrace::Handler(int sig, siginfo_t* sinfo, void*)
|
||||
{
|
||||
Message(sig, sinfo, std::cerr);
|
||||
|
||||
char msg[1024];
|
||||
snprintf(msg, 1024, "%s", "\n");
|
||||
|
||||
if(sinfo && PTL_PSIGINFO_AVAILABLE > 0)
|
||||
{
|
||||
# if PTL_PSIGINFO_AVAILABLE > 0
|
||||
psiginfo(sinfo, msg);
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
# endif
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << msg << std::flush;
|
||||
}
|
||||
|
||||
// ignore any termination signals
|
||||
sigignore(SIGKILL);
|
||||
sigignore(SIGTERM);
|
||||
sigignore(SIGABRT);
|
||||
abort();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
inline int
|
||||
Backtrace::Enable(const signal_set_t& _signals)
|
||||
{
|
||||
static bool _first = true;
|
||||
if(_first)
|
||||
{
|
||||
std::string _msg = "!!! Backtrace is activated !!!";
|
||||
std::stringstream _filler;
|
||||
std::stringstream _spacer;
|
||||
_filler.fill('#');
|
||||
_filler << std::setw(_msg.length()) << "";
|
||||
_spacer << std::setw(10) << "";
|
||||
std::cout << "\n\n"
|
||||
<< _spacer.str() << _filler.str() << "\n"
|
||||
<< _spacer.str() << _msg << "\n"
|
||||
<< _spacer.str() << _filler.str() << "\n\n"
|
||||
<< std::flush;
|
||||
}
|
||||
_first = false;
|
||||
int cnt = 0;
|
||||
for(auto& itr : _signals)
|
||||
{
|
||||
if(itr < 0)
|
||||
continue;
|
||||
if(GetData().is_active[itr])
|
||||
continue;
|
||||
++cnt;
|
||||
sigfillset(&(GetData().current[itr].sa_mask));
|
||||
sigdelset(&(GetData().current[itr].sa_mask), itr);
|
||||
GetData().current[itr].sa_sigaction = &Handler;
|
||||
GetData().current[itr].sa_flags = SA_SIGINFO;
|
||||
sigaction(itr, &(GetData().current[itr]), &(GetData().previous[itr]));
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
inline int
|
||||
Backtrace::Enable(const std::string& _signals)
|
||||
{
|
||||
if(_signals.empty())
|
||||
return 0;
|
||||
|
||||
auto _add_signal = [](std::string sig, signal_set_t& _targ) {
|
||||
if(!sig.empty())
|
||||
{
|
||||
for(auto& itr : sig)
|
||||
itr = toupper(itr);
|
||||
_targ.insert(Backtrace::GetSignal(sig));
|
||||
}
|
||||
};
|
||||
|
||||
const std::regex wsp_re("[ ,;:\t\n]+");
|
||||
auto _maxid = GetData().identifiers.size();
|
||||
auto _result = std::vector<std::string>(_maxid, "");
|
||||
std::copy(std::sregex_token_iterator(_signals.begin(), _signals.end(), wsp_re, -1),
|
||||
std::sregex_token_iterator(), _result.begin());
|
||||
signal_set_t _sigset{};
|
||||
for(auto& itr : _result)
|
||||
_add_signal(itr, _sigset);
|
||||
return Enable(_sigset);
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
inline int
|
||||
Backtrace::Disable(signal_set_t _signals)
|
||||
{
|
||||
if(_signals.empty())
|
||||
{
|
||||
for(auto& itr : GetData().is_active)
|
||||
_signals.insert(itr.first);
|
||||
}
|
||||
|
||||
int cnt = 0;
|
||||
for(auto& itr : _signals)
|
||||
{
|
||||
if(itr < 0)
|
||||
continue;
|
||||
if(!GetData().is_active[itr])
|
||||
continue;
|
||||
++cnt;
|
||||
sigaction(itr, &(GetData().previous[itr]), nullptr);
|
||||
GetData().current.erase(itr);
|
||||
GetData().is_active[itr] = false;
|
||||
}
|
||||
return cnt;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
inline int
|
||||
Backtrace::GetSignal(const std::string& sid)
|
||||
{
|
||||
for(auto&& itr : GetData().identifiers)
|
||||
{
|
||||
if(std::get<0>(itr) == sid)
|
||||
return std::get<1>(itr);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
inline std::string
|
||||
Backtrace::Description(int sig)
|
||||
{
|
||||
for(auto&& itr : GetData().identifiers)
|
||||
{
|
||||
if(std::get<1>(itr) == sig)
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << " signal = " << std::setw(8) << std::get<0>(itr)
|
||||
<< ", value = " << std::setw(4) << std::get<1>(itr)
|
||||
<< ", description = " << std::get<2>(itr);
|
||||
return ss.str();
|
||||
}
|
||||
}
|
||||
std::stringstream ss;
|
||||
ss << " signal = " << std::setw(8) << "unknown"
|
||||
<< ", value = " << std::setw(4) << sig;
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
} // namespace PTL
|
||||
|
||||
#else
|
||||
|
||||
# include <array>
|
||||
# include <functional>
|
||||
# include <map>
|
||||
# include <set>
|
||||
# include <string>
|
||||
# include <tuple>
|
||||
# include <vector>
|
||||
|
||||
namespace PTL
|
||||
{
|
||||
// dummy implementation
|
||||
class Backtrace
|
||||
{
|
||||
public:
|
||||
struct fake_siginfo
|
||||
{};
|
||||
struct fake_sigaction
|
||||
{};
|
||||
|
||||
using siginfo_t = fake_siginfo;
|
||||
using sigaction_t = fake_sigaction;
|
||||
using exit_action_t = std::function<void(int)>;
|
||||
using frame_func_t = std::function<std::string(const char*)>;
|
||||
using signal_set_t = std::set<int>;
|
||||
|
||||
public:
|
||||
struct actions
|
||||
{
|
||||
using id_entry_t = std::tuple<std::string, int, std::string>;
|
||||
using id_list_t = std::vector<id_entry_t>;
|
||||
|
||||
std::map<int, bool> is_active = {};
|
||||
std::map<int, sigaction_t> current = {};
|
||||
std::map<int, sigaction_t> previous = {};
|
||||
std::vector<exit_action_t> exit_actions = {};
|
||||
const id_list_t identifiers = {};
|
||||
};
|
||||
|
||||
public:
|
||||
static void Handler(int, siginfo_t*, void*) {}
|
||||
static void Message(int, siginfo_t*, std::ostream&) {}
|
||||
static void ExitAction(int) {}
|
||||
static int Enable(const std::string&) { return 0; }
|
||||
static int Enable(const signal_set_t& = DefaultSignals()) { return 0; }
|
||||
static int Disable(signal_set_t = {}) { return 0; }
|
||||
static int GetSignal(const std::string&) { return -1; }
|
||||
static std::string Description(int) { return std::string{}; }
|
||||
|
||||
template <typename FuncT>
|
||||
static void AddExitAction(FuncT&&)
|
||||
{}
|
||||
|
||||
template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
|
||||
static std::array<ResultOf_t<FuncT(const char*)>, Depth> GetMangled(
|
||||
FuncT&& func = FrameFunctor())
|
||||
{
|
||||
using type = ResultOf_t<FuncT(const char*)>;
|
||||
auto ret = std::array<type, Depth>{};
|
||||
ret.fill(func(""));
|
||||
return ret;
|
||||
}
|
||||
|
||||
template <size_t Depth, size_t Offset = 0, typename FuncT = frame_func_t>
|
||||
static std::array<ResultOf_t<FuncT(const char*)>, Depth> GetDemangled(
|
||||
FuncT&& func = FrameFunctor())
|
||||
{
|
||||
using type = ResultOf_t<FuncT(const char*)>;
|
||||
auto ret = std::array<type, Depth>{};
|
||||
ret.fill(func(""));
|
||||
return ret;
|
||||
}
|
||||
|
||||
// a functor called for each frame in the backtrace
|
||||
static frame_func_t& FrameFunctor()
|
||||
{
|
||||
static frame_func_t _instance = [](const char* _s) { return std::string(_s); };
|
||||
return _instance;
|
||||
}
|
||||
|
||||
// default set of signals
|
||||
static signal_set_t& DefaultSignals()
|
||||
{
|
||||
static signal_set_t _instance = {};
|
||||
return _instance;
|
||||
}
|
||||
|
||||
static actions& GetData()
|
||||
{
|
||||
static auto _instance = actions{};
|
||||
return _instance;
|
||||
}
|
||||
};
|
||||
|
||||
//----------------------------------------------------------------------------//
|
||||
|
||||
} // namespace PTL
|
||||
|
||||
#endif // SIGNAL_AVAILABLE
|
||||
#endif // Backtrace_hh
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
//
|
||||
// MIT License
|
||||
// Copyright (c) 2020 Jonathan R. Madsen
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
|
||||
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PTL/AutoLock.hh"
|
||||
#include "PTL/Backtrace.hh"
|
||||
#include "PTL/Globals.hh"
|
||||
#include "PTL/TBBTaskGroup.hh"
|
||||
#include "PTL/Task.hh"
|
||||
#include "PTL/TaskGroup.hh"
|
||||
#include "PTL/TaskManager.hh"
|
||||
#include "PTL/TaskRunManager.hh"
|
||||
#include "PTL/ThreadData.hh"
|
||||
#include "PTL/ThreadPool.hh"
|
||||
#include "PTL/Threading.hh"
|
||||
#include "PTL/Timer.hh"
|
||||
#include "PTL/Types.hh"
|
||||
#include "PTL/UserTaskQueue.hh"
|
||||
#include "PTL/Utility.hh"
|
||||
#include "PTL/VTask.hh"
|
||||
#include "PTL/VUserTaskQueue.hh"
|
||||
+5
-2
@@ -35,6 +35,7 @@
|
||||
#include "PTL/Task.hh"
|
||||
#include "PTL/ThreadData.hh"
|
||||
#include "PTL/ThreadPool.hh"
|
||||
#include "PTL/Utility.hh"
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
@@ -62,6 +63,7 @@ get_default_threadpool();
|
||||
intmax_t
|
||||
get_task_depth();
|
||||
} // namespace internal
|
||||
|
||||
template <typename Tp, typename Arg = Tp, intmax_t MaxDepth = 0>
|
||||
class TaskGroup
|
||||
{
|
||||
@@ -112,9 +114,9 @@ public:
|
||||
// define move-construct
|
||||
TaskGroup(this_type&& rhs) = default;
|
||||
// delete copy-assign
|
||||
this_type& operator=(const this_type& rhs) = delete;
|
||||
TaskGroup& operator=(const this_type& rhs) = delete;
|
||||
// define move-assign
|
||||
this_type& operator=(this_type&& rhs) = default;
|
||||
TaskGroup& operator=(this_type&& rhs) = default;
|
||||
|
||||
public:
|
||||
template <typename Up>
|
||||
@@ -156,6 +158,7 @@ public:
|
||||
|
||||
void notify();
|
||||
void notify_all();
|
||||
|
||||
void reserve(size_t _n)
|
||||
{
|
||||
m_task_list.reserve(_n);
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
// ---------------------------------------------------------------
|
||||
|
||||
#include "PTL/Types.hh"
|
||||
#include "PTL/Utility.hh"
|
||||
|
||||
namespace PTL
|
||||
{
|
||||
@@ -102,6 +103,7 @@ TaskGroup<Tp, Arg, MaxDepth>::wait()
|
||||
ThreadData* data = ThreadData::GetInstance();
|
||||
if(!data)
|
||||
return;
|
||||
|
||||
// if no pool was initially present at creation
|
||||
if(!m_pool)
|
||||
{
|
||||
|
||||
+30
-9
@@ -42,6 +42,7 @@
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <iomanip>
|
||||
#include <stdexcept>
|
||||
|
||||
namespace PTL
|
||||
{
|
||||
@@ -55,13 +56,13 @@ public:
|
||||
|
||||
public:
|
||||
// Constructor and Destructors
|
||||
explicit TaskManager(ThreadPool*);
|
||||
explicit TaskManager(ThreadPool*, bool _manage_pool = true);
|
||||
virtual ~TaskManager();
|
||||
|
||||
TaskManager(const this_type&) = delete;
|
||||
TaskManager(this_type&&) = default;
|
||||
this_type& operator=(const this_type&) = delete;
|
||||
this_type& operator=(this_type&&) = default;
|
||||
TaskManager(const TaskManager&) = delete;
|
||||
TaskManager(TaskManager&&) = default;
|
||||
TaskManager& operator=(const TaskManager&) = delete;
|
||||
TaskManager& operator=(TaskManager&&) = default;
|
||||
|
||||
public:
|
||||
/// get the singleton pointer
|
||||
@@ -76,11 +77,18 @@ public:
|
||||
|
||||
//------------------------------------------------------------------------//
|
||||
// return the number of threads in the thread pool
|
||||
inline size_type size() const { return m_pool->size(); }
|
||||
inline size_type size() const { return (m_pool) ? m_pool->size() : 0; }
|
||||
|
||||
//------------------------------------------------------------------------//
|
||||
// kill all the threads
|
||||
inline void finalize() { m_pool->destroy_threadpool(); }
|
||||
inline void finalize()
|
||||
{
|
||||
if(m_is_finalized)
|
||||
return;
|
||||
m_is_finalized = true;
|
||||
if(m_pool)
|
||||
m_pool->destroy_threadpool();
|
||||
}
|
||||
//------------------------------------------------------------------------//
|
||||
|
||||
public:
|
||||
@@ -90,6 +98,8 @@ public:
|
||||
template <typename... Args>
|
||||
void exec(Task<Args...>* _task)
|
||||
{
|
||||
if(!m_pool)
|
||||
throw std::runtime_error("Nullptr to thread-pool");
|
||||
m_pool->add_task(_task);
|
||||
}
|
||||
|
||||
@@ -101,6 +111,9 @@ public:
|
||||
{
|
||||
typedef PackagedTask<RetT, Args...> task_type;
|
||||
|
||||
if(!m_pool)
|
||||
throw std::runtime_error("Nullptr to thread-pool");
|
||||
|
||||
auto _ptask = std::make_shared<task_type>(std::forward<FuncT>(func),
|
||||
std::forward<Args>(args)...);
|
||||
m_pool->add_task(_ptask);
|
||||
@@ -112,6 +125,9 @@ public:
|
||||
{
|
||||
typedef PackagedTask<RetT> task_type;
|
||||
|
||||
if(!m_pool)
|
||||
throw std::runtime_error("Nullptr to thread-pool");
|
||||
|
||||
auto _ptask = std::make_shared<task_type>(std::forward<FuncT>(func));
|
||||
m_pool->add_task(_ptask);
|
||||
return _ptask;
|
||||
@@ -124,6 +140,9 @@ public:
|
||||
using RetT = decay_t<decltype(func(args...))>;
|
||||
typedef PackagedTask<RetT, Args...> task_type;
|
||||
|
||||
if(!m_pool)
|
||||
throw std::runtime_error("Nullptr to thread-pool");
|
||||
|
||||
auto _ptask = std::make_shared<task_type>(std::forward<FuncT>(func),
|
||||
std::forward<Args>(args)...);
|
||||
m_pool->add_task(_ptask);
|
||||
@@ -193,7 +212,8 @@ public:
|
||||
|
||||
protected:
|
||||
// Protected variables
|
||||
ThreadPool* m_pool = nullptr;
|
||||
ThreadPool* m_pool = nullptr;
|
||||
bool m_is_finalized = false;
|
||||
|
||||
private:
|
||||
static TaskManager*& fgInstance();
|
||||
@@ -238,8 +258,9 @@ PTL::TaskManager::GetInstanceIfExists()
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
inline PTL::TaskManager::TaskManager(ThreadPool* _pool)
|
||||
inline PTL::TaskManager::TaskManager(ThreadPool* _pool, bool _manage_pool)
|
||||
: m_pool(_pool)
|
||||
, m_is_finalized(!_manage_pool)
|
||||
{
|
||||
if(!fgInstance())
|
||||
fgInstance() = this;
|
||||
|
||||
+2
-1
@@ -52,7 +52,7 @@ public:
|
||||
// useTBB: only relevant if PTL_USE_TBB defined
|
||||
// grainsize: 0 = auto
|
||||
explicit TaskRunManager(bool useTBB = false);
|
||||
virtual ~TaskRunManager() = default;
|
||||
virtual ~TaskRunManager();
|
||||
|
||||
public:
|
||||
virtual int GetNumberOfThreads() const
|
||||
@@ -80,6 +80,7 @@ public: // with description
|
||||
static TaskRunManager* GetMasterRunManager(bool useTBB = false);
|
||||
|
||||
private:
|
||||
static pointer& GetPrivateMasterRunManager();
|
||||
static pointer& GetPrivateMasterRunManager(bool init, bool useTBB = false);
|
||||
|
||||
protected:
|
||||
|
||||
@@ -25,6 +25,10 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef G4GMAKE
|
||||
#include "PTL/Config.hh"
|
||||
#endif
|
||||
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <deque>
|
||||
|
||||
+125
-69
@@ -33,6 +33,7 @@
|
||||
#include "PTL/AutoLock.hh"
|
||||
#include "PTL/ThreadData.hh"
|
||||
#include "PTL/Threading.hh"
|
||||
#include "PTL/Types.hh"
|
||||
#include "PTL/VTask.hh"
|
||||
#include "PTL/VUserTaskQueue.hh"
|
||||
|
||||
@@ -60,6 +61,7 @@
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <stack>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
@@ -84,27 +86,70 @@ public:
|
||||
using task_pointer = std::shared_ptr<task_type>;
|
||||
using task_queue_t = VUserTaskQueue;
|
||||
// containers
|
||||
typedef std::deque<ThreadId> thread_list_t;
|
||||
typedef std::vector<bool> bool_list_t;
|
||||
typedef std::map<ThreadId, uintmax_t> thread_id_map_t;
|
||||
typedef std::map<uintmax_t, ThreadId> thread_index_map_t;
|
||||
using thread_vec_t = std::vector<Thread>;
|
||||
using thread_data_t = std::vector<std::shared_ptr<ThreadData>>;
|
||||
using thread_list_t = std::deque<ThreadId>;
|
||||
using bool_list_t = std::vector<bool>;
|
||||
using thread_id_map_t = std::map<ThreadId, uintmax_t>;
|
||||
using thread_index_map_t = std::map<uintmax_t, ThreadId>;
|
||||
using thread_vec_t = std::vector<Thread>;
|
||||
using thread_data_t = std::vector<std::shared_ptr<ThreadData>>;
|
||||
// functions
|
||||
typedef std::function<void()> initialize_func_t;
|
||||
typedef std::function<intmax_t(intmax_t)> affinity_func_t;
|
||||
using initialize_func_t = std::function<void()>;
|
||||
using finalize_func_t = std::function<void()>;
|
||||
using affinity_func_t = std::function<intmax_t(intmax_t)>;
|
||||
|
||||
static affinity_func_t& affinity_functor()
|
||||
{
|
||||
static affinity_func_t _v = [](intmax_t) {
|
||||
static std::atomic<intmax_t> assigned;
|
||||
intmax_t _assign = assigned++;
|
||||
return _assign % Thread::hardware_concurrency();
|
||||
};
|
||||
return _v;
|
||||
}
|
||||
|
||||
static initialize_func_t& initialization_functor()
|
||||
{
|
||||
static initialize_func_t _v = []() {};
|
||||
return _v;
|
||||
}
|
||||
|
||||
static finalize_func_t& finalization_functor()
|
||||
{
|
||||
static finalize_func_t _v = []() {};
|
||||
return _v;
|
||||
}
|
||||
|
||||
struct Config
|
||||
{
|
||||
PTL_DEFAULT_OBJECT(Config)
|
||||
|
||||
Config(bool, bool, bool, int, int, size_type, VUserTaskQueue*, affinity_func_t,
|
||||
initialize_func_t, finalize_func_t);
|
||||
|
||||
bool init = true;
|
||||
bool use_tbb = f_use_tbb();
|
||||
bool use_affinity = f_use_cpu_affinity();
|
||||
int verbose = f_verbose();
|
||||
int priority = f_thread_priority();
|
||||
size_type pool_size = f_default_pool_size();
|
||||
VUserTaskQueue* task_queue = nullptr;
|
||||
affinity_func_t set_affinity = affinity_functor();
|
||||
initialize_func_t initializer = initialization_functor();
|
||||
finalize_func_t finalizer = finalization_functor();
|
||||
};
|
||||
|
||||
public:
|
||||
// Constructor and Destructors
|
||||
explicit ThreadPool(const Config&);
|
||||
ThreadPool(const size_type& pool_size, VUserTaskQueue* task_queue = nullptr,
|
||||
bool _use_affinity = GetEnv<bool>("PTL_CPU_AFFINITY", false),
|
||||
affinity_func_t = [](intmax_t) {
|
||||
static std::atomic<intmax_t> assigned;
|
||||
intmax_t _assign = assigned++;
|
||||
return _assign % Thread::hardware_concurrency();
|
||||
});
|
||||
// Virtual destructors are required by abstract classes
|
||||
// so add it by default, just in case
|
||||
bool _use_affinity = f_use_cpu_affinity(),
|
||||
affinity_func_t = affinity_functor(),
|
||||
initialize_func_t = initialization_functor(),
|
||||
finalize_func_t = finalization_functor());
|
||||
ThreadPool(const size_type& pool_size, initialize_func_t, finalize_func_t,
|
||||
bool _use_affinity = f_use_cpu_affinity(),
|
||||
affinity_func_t = affinity_functor(),
|
||||
VUserTaskQueue* task_queue = nullptr);
|
||||
virtual ~ThreadPool();
|
||||
ThreadPool(const ThreadPool&) = delete;
|
||||
ThreadPool(ThreadPool&&) = default;
|
||||
@@ -132,8 +177,30 @@ public:
|
||||
public:
|
||||
// Public functions related to TBB
|
||||
static bool using_tbb();
|
||||
// enable using TBB if available
|
||||
static void set_use_tbb(bool val);
|
||||
// enable using TBB if available - semi-deprecated
|
||||
static void set_use_tbb(bool _v);
|
||||
|
||||
/// set the default use of tbb
|
||||
static void set_default_use_tbb(bool _v) { set_use_tbb(_v); }
|
||||
/// set the default use of cpu affinity
|
||||
static void set_default_use_cpu_affinity(bool _v);
|
||||
/// set the default scheduling priority of threads in thread-pool
|
||||
static void set_default_scheduling_priority(int _v) { f_thread_priority() = _v; }
|
||||
/// set the default verbosity
|
||||
static void set_default_verbose(int _v) { f_verbose() = _v; }
|
||||
/// set the default pool size
|
||||
static void set_default_size(size_type _v) { f_default_pool_size() = _v; }
|
||||
|
||||
/// get the default use of tbb
|
||||
static bool get_default_use_tbb() { return f_use_tbb(); }
|
||||
/// get the default use of cpu affinity
|
||||
static bool get_default_use_cpu_affinity() { return f_use_cpu_affinity(); }
|
||||
/// get the default scheduling priority of threads in thread-pool
|
||||
static int get_default_scheduling_priority() { return f_thread_priority(); }
|
||||
/// get the default verbosity
|
||||
static int get_default_verbose() { return f_verbose(); }
|
||||
/// get the default pool size
|
||||
static size_type get_default_size() { return f_default_pool_size(); }
|
||||
|
||||
public:
|
||||
// add tasks for threads to process
|
||||
@@ -149,11 +216,16 @@ public:
|
||||
// only relevant when compiled with PTL_USE_TBB
|
||||
static tbb_global_control_t*& tbb_global_control();
|
||||
|
||||
void set_initialization(initialize_func_t f) { m_init_func = f; }
|
||||
void set_initialization(initialize_func_t f) { m_init_func = std::move(f); }
|
||||
void set_finalization(finalize_func_t f) { m_fini_func = std::move(f); }
|
||||
|
||||
void reset_initialization()
|
||||
{
|
||||
auto f = []() {};
|
||||
m_init_func = f;
|
||||
m_init_func = []() {};
|
||||
}
|
||||
void reset_finalization()
|
||||
{
|
||||
m_fini_func = []() {};
|
||||
}
|
||||
|
||||
public:
|
||||
@@ -175,8 +247,9 @@ public:
|
||||
return (m_thread_awake) ? m_thread_awake->load() : 0;
|
||||
}
|
||||
|
||||
void set_affinity(affinity_func_t f) { m_affinity_func = f; }
|
||||
void set_affinity(intmax_t i, Thread&);
|
||||
void set_affinity(affinity_func_t f) { m_affinity_func = std::move(f); }
|
||||
void set_affinity(intmax_t i, Thread&) const;
|
||||
void set_priority(int _prio, Thread&) const;
|
||||
|
||||
void set_verbose(int n) { m_verbose = n; }
|
||||
int get_verbose() const { return m_verbose; }
|
||||
@@ -187,21 +260,9 @@ public:
|
||||
public:
|
||||
// read FORCE_NUM_THREADS environment variable
|
||||
static const thread_id_map_t& get_thread_ids();
|
||||
static uintmax_t get_thread_id(ThreadId);
|
||||
static uintmax_t get_this_thread_id();
|
||||
static uintmax_t add_thread_id()
|
||||
{
|
||||
AutoLock lock(TypeMutex<ThreadPool>(), std::defer_lock);
|
||||
if(!lock.owns_lock())
|
||||
lock.lock();
|
||||
auto _tid = ThisThread::get_id();
|
||||
if(f_thread_ids.find(_tid) == f_thread_ids.end())
|
||||
{
|
||||
auto _idx = f_thread_ids.size();
|
||||
f_thread_ids[_tid] = _idx;
|
||||
Threading::SetThreadId(_idx);
|
||||
}
|
||||
return f_thread_ids.at(_tid);
|
||||
}
|
||||
static uintmax_t add_thread_id(ThreadId = ThisThread::get_id());
|
||||
|
||||
protected:
|
||||
void execute_thread(VUserTaskQueue*); // function thread sits in
|
||||
@@ -212,17 +273,8 @@ protected:
|
||||
// called in THREAD INIT
|
||||
static void start_thread(ThreadPool*, thread_data_t*, intmax_t = -1);
|
||||
|
||||
void record_entry()
|
||||
{
|
||||
if(m_thread_active)
|
||||
++(*m_thread_active);
|
||||
}
|
||||
|
||||
void record_exit()
|
||||
{
|
||||
if(m_thread_active)
|
||||
--(*m_thread_active);
|
||||
}
|
||||
void record_entry();
|
||||
void record_exit();
|
||||
|
||||
private:
|
||||
// Private variables
|
||||
@@ -230,7 +282,8 @@ private:
|
||||
bool m_use_affinity = false;
|
||||
bool m_tbb_tp = false;
|
||||
bool m_delete_task_queue = false;
|
||||
int m_verbose = GetEnv<int>("PTL_VERBOSE", 0);
|
||||
int m_verbose = f_verbose();
|
||||
int m_priority = f_thread_priority();
|
||||
size_type m_pool_size = 0;
|
||||
ThreadId m_main_tid = ThisThread::get_id();
|
||||
atomic_bool_type m_alive_flag = std::make_shared<std::atomic_bool>(false);
|
||||
@@ -244,12 +297,12 @@ private:
|
||||
condition_t m_task_cond = std::make_shared<Condition>();
|
||||
|
||||
// containers
|
||||
bool_list_t m_is_joined{}; // join list
|
||||
bool_list_t m_is_stopped{}; // lets thread know to stop
|
||||
thread_list_t m_main_threads{}; // storage for active threads
|
||||
thread_list_t m_stop_threads{}; // storage for stopped threads
|
||||
thread_vec_t m_threads{};
|
||||
thread_data_t m_thread_data{};
|
||||
bool_list_t m_is_joined = {}; // join list
|
||||
bool_list_t m_is_stopped = {}; // lets thread know to stop
|
||||
thread_list_t m_main_threads = {}; // storage for active threads
|
||||
thread_list_t m_stop_threads = {}; // storage for stopped threads
|
||||
thread_vec_t m_threads = {};
|
||||
thread_data_t m_thread_data = {};
|
||||
|
||||
// task queue
|
||||
task_queue_t* m_task_queue = nullptr;
|
||||
@@ -257,13 +310,17 @@ private:
|
||||
tbb_task_group_t* m_tbb_task_group = nullptr;
|
||||
|
||||
// functions
|
||||
initialize_func_t m_init_func = []() {};
|
||||
affinity_func_t m_affinity_func;
|
||||
initialize_func_t m_init_func = initialization_functor();
|
||||
finalize_func_t m_fini_func = finalization_functor();
|
||||
affinity_func_t m_affinity_func = affinity_functor();
|
||||
|
||||
private:
|
||||
// Private static variables
|
||||
PTL_DLL static thread_id_map_t f_thread_ids;
|
||||
PTL_DLL static bool f_use_tbb;
|
||||
static bool& f_use_tbb();
|
||||
static bool& f_use_cpu_affinity();
|
||||
static int& f_thread_priority();
|
||||
static int& f_verbose();
|
||||
static size_type& f_default_pool_size();
|
||||
static thread_id_map_t& f_thread_ids();
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
@@ -341,10 +398,9 @@ ThreadPool::get_task_arena()
|
||||
inline void
|
||||
ThreadPool::resize(size_type _n)
|
||||
{
|
||||
if(_n == m_pool_size)
|
||||
return;
|
||||
initialize_threadpool(_n);
|
||||
m_task_queue->resize(static_cast<intmax_t>(_n));
|
||||
if(m_task_queue)
|
||||
m_task_queue->resize(static_cast<intmax_t>(_n));
|
||||
}
|
||||
//--------------------------------------------------------------------------------------//
|
||||
inline int
|
||||
@@ -354,7 +410,7 @@ ThreadPool::run_on_this(task_pointer&& _task)
|
||||
|
||||
if(m_tbb_tp && m_tbb_task_group)
|
||||
{
|
||||
auto _arena = get_task_arena();
|
||||
auto* _arena = get_task_arena();
|
||||
_arena->execute([this, _func]() { this->m_tbb_task_group->run(_func); });
|
||||
}
|
||||
else
|
||||
@@ -457,13 +513,13 @@ ThreadPool::execute_on_all_threads(FuncT&& _func)
|
||||
size_t _maxp = tbb_global_control()->active_value(
|
||||
tbb::global_control::max_allowed_parallelism);
|
||||
// create a task arean
|
||||
auto _arena = get_task_arena();
|
||||
auto* _arena = get_task_arena();
|
||||
// size of the thread-pool
|
||||
size_t _sz = size();
|
||||
// number of cores
|
||||
size_t _ncore = Threading::GetNumberOfCores();
|
||||
// maximum depth for recursion
|
||||
size_t _dmax = std::max<size_t>(_ncore, 4);
|
||||
size_t _dmax = std::max<size_t>(_ncore, 8);
|
||||
// how many threads we need to initialize
|
||||
size_t _num = std::min(_maxp, std::min(_sz, _ncore));
|
||||
// this is the task passed to the task-group
|
||||
@@ -498,7 +554,7 @@ ThreadPool::execute_on_all_threads(FuncT&& _func)
|
||||
size_t nitr = 0;
|
||||
auto _fname = __FUNCTION__;
|
||||
auto _write_info = [&]() {
|
||||
std::cout << "[" << _fname << "]> Total initalized: " << _total_init
|
||||
std::cout << "[" << _fname << "]> Total initialized: " << _total_init
|
||||
<< ", expected: " << _num << ", max-parallel: " << _maxp
|
||||
<< ", size: " << _sz << ", ncore: " << _ncore << std::endl;
|
||||
};
|
||||
@@ -575,11 +631,11 @@ ThreadPool::execute_on_specific_threads(const std::set<std::thread::id>& _tids,
|
||||
// number of cores
|
||||
size_t _ncore = Threading::GetNumberOfCores();
|
||||
// maximum depth for recursion
|
||||
size_t _dmax = std::max<size_t>(_ncore, 4);
|
||||
size_t _dmax = std::max<size_t>(_ncore, 8);
|
||||
// how many threads we need to initialize
|
||||
size_t _num = _tids.size();
|
||||
// create a task arena
|
||||
auto _arena = get_task_arena();
|
||||
auto* _arena = get_task_arena();
|
||||
// this is the task passed to the task-group
|
||||
std::function<void()> _exec_task;
|
||||
_exec_task = [&]() {
|
||||
|
||||
+18
-8
@@ -125,18 +125,16 @@ TypeMutex(const unsigned int& _n = 0)
|
||||
//======================================================================================//
|
||||
|
||||
// global thread types
|
||||
typedef std::thread Thread;
|
||||
typedef std::thread::native_handle_type NativeThread;
|
||||
|
||||
using Thread = std::thread;
|
||||
using NativeThread = std::thread::native_handle_type;
|
||||
// std::thread::id does not cast to integer
|
||||
typedef std::thread::id Pid_t;
|
||||
using Pid_t = std::thread::id;
|
||||
|
||||
// Condition
|
||||
typedef std::condition_variable Condition;
|
||||
//
|
||||
using Condition = std::condition_variable;
|
||||
|
||||
// Thread identifier
|
||||
typedef Thread::id ThreadId;
|
||||
using ThreadId = Thread::id;
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
@@ -153,6 +151,9 @@ enum
|
||||
Pid_t
|
||||
GetPidId();
|
||||
|
||||
unsigned
|
||||
GetNumberOfPhysicalCpus();
|
||||
|
||||
unsigned
|
||||
GetNumberOfCores();
|
||||
|
||||
@@ -163,7 +164,16 @@ void
|
||||
SetThreadId(int aNewValue);
|
||||
|
||||
bool
|
||||
SetPinAffinity(int idx, NativeThread& at);
|
||||
SetPinAffinity(int idx);
|
||||
|
||||
bool
|
||||
SetThreadPriority(int _v);
|
||||
|
||||
bool
|
||||
SetPinAffinity(int idx, NativeThread& _t);
|
||||
|
||||
bool
|
||||
SetThreadPriority(int _v, NativeThread& _t);
|
||||
|
||||
} // namespace Threading
|
||||
} // namespace PTL
|
||||
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
//
|
||||
// MIT License
|
||||
// Copyright (c) 2019 Jonathan R. Madsen
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
|
||||
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// ----------------------------------------------------------------------
|
||||
// Class Timer
|
||||
//
|
||||
// Class description:
|
||||
//
|
||||
// Class for timer objects, able to measure elasped user/system process time.
|
||||
//
|
||||
// Note: Uses <sys/times.h> & <unistd.h> - POSIX.1 defined
|
||||
// If used, this header must be included in the source (.cc) file and it
|
||||
// must be the first header file to be included!
|
||||
//
|
||||
// Member functions:
|
||||
//
|
||||
// Timer()
|
||||
// Construct a timer object
|
||||
// Start()
|
||||
// Start timing
|
||||
// Stop()
|
||||
// Stop timing
|
||||
// bool IsValid()
|
||||
// Return true if have a valid time (ie start() and stop() called)
|
||||
// double GetRealElapsed()
|
||||
// Return the elapsed real time between last calling start() and stop()
|
||||
// double GetSystemElapsed()
|
||||
// Return the elapsed system time between last calling start() and stop()
|
||||
// double GetUserElapsed()
|
||||
// Return the elapsed user time between last calling start() and stop()
|
||||
//
|
||||
// Operators:
|
||||
//
|
||||
// std::ostream& operator << (std::ostream& os, const Timer& t);
|
||||
// Print the elapsed real,system and usertimes on os. Prints **s for times
|
||||
// if !IsValid
|
||||
//
|
||||
// Member data:
|
||||
//
|
||||
// bool fValidTimes
|
||||
// True after start and stop have both been called more than once and
|
||||
// an equal number of times
|
||||
// clock_t fStartRealTime,fEndRealTime
|
||||
// Real times (arbitrary time 0)
|
||||
// tms fStartTimes,fEndTimes
|
||||
// Timing structures (see times(2)) for start and end times
|
||||
|
||||
// History:
|
||||
// 23.08.96 P.Kent Updated to also computed real elapsed time
|
||||
// 21.08.95 P.Kent
|
||||
// 29.04.97 G.Cosmo Added timings for Windows/NT
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "PTL/Types.hh"
|
||||
|
||||
#include <chrono>
|
||||
#include <iomanip>
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
|
||||
#if !(defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64))
|
||||
# include <sys/times.h>
|
||||
# include <unistd.h>
|
||||
#else
|
||||
# include <ctime>
|
||||
# define _SC_CLK_TCK 1
|
||||
|
||||
extern "C"
|
||||
{
|
||||
int sysconf(int);
|
||||
};
|
||||
|
||||
// Structure returned by times()
|
||||
|
||||
struct tms
|
||||
{
|
||||
clock_t tms_utime; /* user time */
|
||||
clock_t tms_stime; /* system time */
|
||||
clock_t tms_cutime; /* user time, children */
|
||||
clock_t tms_cstime; /* system time, children */
|
||||
};
|
||||
|
||||
extern "C"
|
||||
{
|
||||
extern clock_t times(struct tms*);
|
||||
};
|
||||
#endif /* WIN32 */
|
||||
|
||||
namespace PTL
|
||||
{
|
||||
class Timer
|
||||
{
|
||||
typedef std::chrono::high_resolution_clock clock_type;
|
||||
|
||||
public:
|
||||
Timer();
|
||||
|
||||
public:
|
||||
inline void Start();
|
||||
inline void Stop();
|
||||
inline bool IsValid() const;
|
||||
inline const char* GetClockTime() const;
|
||||
double GetRealElapsed() const;
|
||||
double GetSystemElapsed() const;
|
||||
double GetUserElapsed() const;
|
||||
|
||||
public:
|
||||
friend std::ostream& operator<<(std::ostream& os, const Timer& t)
|
||||
{
|
||||
// so fixed doesn't propagate
|
||||
std::stringstream ss;
|
||||
ss << std::fixed;
|
||||
if(t.IsValid())
|
||||
{
|
||||
ss << "Real=" << t.GetRealElapsed() << "s User=" << t.GetUserElapsed()
|
||||
<< "s Sys=" << t.GetSystemElapsed() << "s";
|
||||
|
||||
// avoid possible FPE error
|
||||
if(t.GetRealElapsed() > 1.0e-6)
|
||||
{
|
||||
double cpu_util = (t.GetUserElapsed() + t.GetSystemElapsed()) /
|
||||
t.GetRealElapsed() * 100.0;
|
||||
ss << std::setprecision(1);
|
||||
ss << " [Cpu=" << std::setprecision(1) << cpu_util << "%]";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ss << "Real=****s User=****s Sys=****s";
|
||||
}
|
||||
os << ss.str();
|
||||
|
||||
return os;
|
||||
}
|
||||
|
||||
private:
|
||||
bool fValidTimes;
|
||||
std::chrono::time_point<clock_type> fStartRealTime, fEndRealTime;
|
||||
tms fStartTimes, fEndTimes;
|
||||
};
|
||||
|
||||
} // namespace PTL
|
||||
|
||||
#include "PTL/Timer.icc"
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
//
|
||||
// MIT License
|
||||
// Copyright (c) 2019 Jonathan R. Madsen
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED
|
||||
// "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
||||
// LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
||||
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
|
||||
// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
|
||||
// ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
//
|
||||
// ------------------------------------------------------------
|
||||
// class inline implementation
|
||||
// ------------------------------------------------------------
|
||||
|
||||
inline void
|
||||
PTL::Timer::Start()
|
||||
{
|
||||
fValidTimes = false;
|
||||
times(&fStartTimes);
|
||||
fStartRealTime = clock_type::now();
|
||||
}
|
||||
|
||||
inline void
|
||||
PTL::Timer::Stop()
|
||||
{
|
||||
times(&fEndTimes);
|
||||
fEndRealTime = clock_type::now();
|
||||
fValidTimes = true;
|
||||
}
|
||||
|
||||
inline bool
|
||||
PTL::Timer::IsValid() const
|
||||
{
|
||||
return fValidTimes;
|
||||
}
|
||||
|
||||
inline const char*
|
||||
PTL::Timer::GetClockTime() const
|
||||
{
|
||||
time_t rawtime;
|
||||
struct tm* timeinfo;
|
||||
|
||||
time(&rawtime);
|
||||
timeinfo = localtime(&rawtime);
|
||||
return asctime(timeinfo);
|
||||
}
|
||||
+40
-41
@@ -21,7 +21,41 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef G4GMAKE
|
||||
# include "PTL/Config.hh"
|
||||
#endif
|
||||
|
||||
#if defined(__APPLE__) || defined(__MACH__)
|
||||
# if !defined(PTL_MACOS)
|
||||
# define PTL_MACOS 1
|
||||
# endif
|
||||
# if !defined(PTL_UNIX)
|
||||
# define PTL_UNIX 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(WIN32) || defined(_WIN32) || defined(WIN64) || defined(_WIN64)
|
||||
# if !defined(PTL_WINDOWS)
|
||||
# define PTL_WINDOWS 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__)
|
||||
# if !defined(PTL_LINUX)
|
||||
# define PTL_LINUX 1
|
||||
# endif
|
||||
# if !defined(PTL_UNIX)
|
||||
# define PTL_UNIX 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(__unix__) || defined(__unix) || defined(unix)
|
||||
# if !defined(PTL_UNIX)
|
||||
# define PTL_UNIX 1
|
||||
# endif
|
||||
#endif
|
||||
|
||||
#if defined(PTL_WINDOWS)
|
||||
// Disable warning C4786 on WIN32 architectures:
|
||||
// identifier was truncated to '255' characters
|
||||
// in the debug information
|
||||
@@ -31,7 +65,7 @@
|
||||
// Define DLL export macro for WIN32 systems for
|
||||
// importing/exporting external symbols to DLLs
|
||||
//
|
||||
# if defined G4LIB_BUILD_DLL
|
||||
# if defined PTL_BUILD_DLL
|
||||
# define DLLEXPORT __declspec(dllexport)
|
||||
# define DLLIMPORT __declspec(dllimport)
|
||||
# else
|
||||
@@ -54,12 +88,12 @@
|
||||
|
||||
#if !defined(PTL_DEFAULT_OBJECT)
|
||||
# define PTL_DEFAULT_OBJECT(NAME) \
|
||||
NAME() = default; \
|
||||
~NAME() = default; \
|
||||
NAME(const NAME&) = default; \
|
||||
NAME(NAME&&) = default; \
|
||||
NAME() = default; \
|
||||
~NAME() = default; \
|
||||
NAME(const NAME&) = default; \
|
||||
NAME(NAME&&) = default; \
|
||||
NAME& operator=(const NAME&) = default; \
|
||||
NAME& operator=(NAME&&) = default;
|
||||
NAME& operator=(NAME&&) = default;
|
||||
#endif
|
||||
|
||||
#include <atomic>
|
||||
@@ -121,41 +155,6 @@ GetSharedPointerPairMasterInstance()
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
struct ScopeDestructor
|
||||
{
|
||||
template <typename FuncT>
|
||||
ScopeDestructor(FuncT&& _func)
|
||||
: m_functor(std::forward<FuncT>(_func))
|
||||
{}
|
||||
|
||||
// delete copy operations
|
||||
ScopeDestructor(const ScopeDestructor&) = delete;
|
||||
ScopeDestructor& operator=(const ScopeDestructor&) = delete;
|
||||
|
||||
// allow move operations
|
||||
ScopeDestructor(ScopeDestructor&& rhs) noexcept
|
||||
: m_functor(std::move(rhs.m_functor))
|
||||
{
|
||||
rhs.m_functor = []() {};
|
||||
}
|
||||
ScopeDestructor& operator=(ScopeDestructor&& rhs) noexcept
|
||||
{
|
||||
if(this != &rhs)
|
||||
{
|
||||
m_functor = std::move(rhs.m_functor);
|
||||
rhs.m_functor = []() {};
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~ScopeDestructor() { m_functor(); }
|
||||
|
||||
private:
|
||||
std::function<void()> m_functor = []() {};
|
||||
};
|
||||
|
||||
//======================================================================================//
|
||||
|
||||
} // namespace PTL
|
||||
|
||||
// Forward declation of void type argument for usage in direct object
|
||||
|
||||
+6
-6
@@ -102,12 +102,12 @@ private:
|
||||
bool m_is_clone;
|
||||
intmax_t m_thread_bin;
|
||||
mutable intmax_t m_insert_bin;
|
||||
std::atomic_bool* m_hold;
|
||||
std::atomic_uintmax_t* m_ntasks;
|
||||
Mutex* m_mutex;
|
||||
TaskSubQueueContainer* m_subqueues;
|
||||
std::vector<int> m_rand_list;
|
||||
std::vector<int>::iterator m_rand_itr;
|
||||
std::atomic_bool* m_hold = nullptr;
|
||||
std::atomic_uintmax_t* m_ntasks = nullptr;
|
||||
Mutex* m_mutex = nullptr;
|
||||
TaskSubQueueContainer* m_subqueues = nullptr;
|
||||
std::vector<int> m_rand_list = {};
|
||||
std::vector<int>::iterator m_rand_itr = {};
|
||||
};
|
||||
|
||||
} // namespace PTL
|
||||
|
||||
+38
-1
@@ -25,6 +25,7 @@
|
||||
|
||||
#include <chrono>
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
@@ -312,7 +313,7 @@ GetEnv(const std::string& env_id, const EnvChoiceList<Tp>& _choices, Tp _default
|
||||
|
||||
template <typename Tp>
|
||||
Tp
|
||||
GetChoice(const EnvChoiceList<Tp>& _choices, const std::string str_var)
|
||||
GetChoice(const EnvChoiceList<Tp>& _choices, const std::string& str_var)
|
||||
{
|
||||
auto asupper = [](std::string var) {
|
||||
for(auto& itr : var)
|
||||
@@ -363,4 +364,40 @@ PrintEnv(std::ostream& os = std::cout)
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
struct ScopeDestructor
|
||||
{
|
||||
template <typename FuncT>
|
||||
ScopeDestructor(FuncT&& _func)
|
||||
: m_functor(std::forward<FuncT>(_func))
|
||||
{}
|
||||
|
||||
// delete copy operations
|
||||
ScopeDestructor(const ScopeDestructor&) = delete;
|
||||
ScopeDestructor& operator=(const ScopeDestructor&) = delete;
|
||||
|
||||
// allow move operations
|
||||
ScopeDestructor(ScopeDestructor&& rhs) noexcept
|
||||
: m_functor(std::move(rhs.m_functor))
|
||||
{
|
||||
rhs.m_functor = []() {};
|
||||
}
|
||||
|
||||
ScopeDestructor& operator=(ScopeDestructor&& rhs) noexcept
|
||||
{
|
||||
if(this != &rhs)
|
||||
{
|
||||
m_functor = std::move(rhs.m_functor);
|
||||
rhs.m_functor = []() {};
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
~ScopeDestructor() { m_functor(); }
|
||||
|
||||
private:
|
||||
std::function<void()> m_functor = []() {};
|
||||
};
|
||||
|
||||
//--------------------------------------------------------------------------------------//
|
||||
|
||||
} // namespace PTL
|
||||
|
||||
Reference in New Issue
Block a user