Commit 67ab2449 authored by Martin Marinov's avatar Martin Marinov
Browse files

Add Progress::Context to consolidate functionality related to the Progress...

Add Progress::Context to consolidate functionality related to the Progress tracking and aborting features.
parent e2bdbb8c
...@@ -6,21 +6,21 @@ ...@@ -6,21 +6,21 @@
#ifdef PROGRESS_ON #ifdef PROGRESS_ON
#include "Base/Progress/ProgressNode.hh" #include "Base/Progress/ProgressNode.hh"
#else//PROGRESS_ON #else//PROGRESS_ON
#define PROGRESS_ACTIVE_TICK #define PROGRESS_TICK
#endif//PROGRESS_ON #endif//PROGRESS_ON
// DEB_ON is defined, or not, in CMakeLists.txt for primary project // DEB_ON is defined, or not, in CMakeLists.txt for primary project
#ifndef DEB_ON #ifndef DEB_ON
#define DEB_module(SS) #define DEB_module(SS)
#define DEB_enter_func PROGRESS_ACTIVE_TICK; #define DEB_enter_func PROGRESS_TICK;
#define DEB_only(CC) #define DEB_only(CC)
#define DEB_exec(LL, AA) { PROGRESS_ACTIVE_TICK; } #define DEB_exec(LL, AA) { PROGRESS_TICK; }
#define DEB_exec_if(CC, LL, AA) { PROGRESS_ACTIVE_TICK; } #define DEB_exec_if(CC, LL, AA) { PROGRESS_TICK; }
#define DEB_out(LL, AA) { PROGRESS_ACTIVE_TICK; } #define DEB_out(LL, AA) { PROGRESS_TICK; }
#define DEB_out_if(CC, LL, AA) { PROGRESS_ACTIVE_TICK; } #define DEB_out_if(CC, LL, AA) { PROGRESS_TICK; }
#define DEB_line(LL, AA) { PROGRESS_ACTIVE_TICK; } #define DEB_line(LL, AA) { PROGRESS_TICK; }
#define DEB_line_if(CC, LL, AA) { PROGRESS_ACTIVE_TICK; } #define DEB_line_if(CC, LL, AA) { PROGRESS_TICK; }
#define DEB_warning(LL, AA) {} #define DEB_warning(LL, AA) {}
#define DEB_warning_if(CC, LL, AA) {} #define DEB_warning_if(CC, LL, AA) {}
...@@ -136,7 +136,7 @@ std::string to_string(const T& _t) ...@@ -136,7 +136,7 @@ std::string to_string(const T& _t)
//TODO: This should use an atomic thread-safe static int(s) //TODO: This should use an atomic thread-safe static int(s)
#define DEB_enter_func \ #define DEB_enter_func \
PROGRESS_ACTIVE_TICK; \ PROGRESS_TICK; \
static int deb_nmbr = 0; \ static int deb_nmbr = 0; \
static int deb_lvl = Debug::INVALID_LEVEL; \ static int deb_lvl = Debug::INVALID_LEVEL; \
::Debug::Enter deb(__FILE__, __FUNCTION__, deb_nmbr, deb_lvl); ::Debug::Enter deb(__FILE__, __FUNCTION__, deb_nmbr, deb_lvl);
...@@ -144,15 +144,15 @@ std::string to_string(const T& _t) ...@@ -144,15 +144,15 @@ std::string to_string(const T& _t)
#define DEB_only(CC) CC #define DEB_only(CC) CC
#define DEB_exec(LL, AA) DEB_exec_if(true, LL, AA) #define DEB_exec(LL, AA) DEB_exec_if(true, LL, AA)
#define DEB_exec_if(CC, LL, AA) { PROGRESS_ACTIVE_TICK; \ #define DEB_exec_if(CC, LL, AA) { PROGRESS_TICK; \
{ if (deb.pass(LL) && (CC)) { AA; } } } { if (deb.pass(LL) && (CC)) { AA; } } }
#define DEB_out(LL, AA) DEB_out_if(true, LL, AA) #define DEB_out(LL, AA) DEB_out_if(true, LL, AA)
#define DEB_out_if(CC, LL, AA) { PROGRESS_ACTIVE_TICK; \ #define DEB_out_if(CC, LL, AA) { PROGRESS_TICK; \
{ if (deb.pass(LL) && (CC)) { deb.stream() << AA << ::Base::Command::END; } } } { if (deb.pass(LL) && (CC)) { deb.stream() << AA << ::Base::Command::END; } } }
#define DEB_line(LL, AA) DEB_line_if(true, LL, AA) #define DEB_line(LL, AA) DEB_line_if(true, LL, AA)
#define DEB_line_if(CC, LL, AA) { PROGRESS_ACTIVE_TICK; \ #define DEB_line_if(CC, LL, AA) { PROGRESS_TICK; \
{ if (deb.pass(LL) && (CC)) { deb.stream() << AA << ::Base::LF; } } } { if (deb.pass(LL) && (CC)) { deb.stream() << AA << ::Base::LF; } } }
#define DEB_warning(LL, AA) DEB_warning_if(true, LL, AA) #define DEB_warning(LL, AA) DEB_warning_if(true, LL, AA)
......
...@@ -4,12 +4,57 @@ ...@@ -4,12 +4,57 @@
#include "Base/Code/Quality.hh" #include "Base/Code/Quality.hh"
#include "ProgressNode.hh" #include "ProgressNode.hh"
#include "Base/Utils/BaseError.hh"
#ifdef PROGRESS_ON #ifdef PROGRESS_ON
namespace Progress { namespace Progress {
thread_local TrackFunction trck_fnct = nullptr; /// Context implementation
thread_local Node* actv_node; // active node void Context::begin_track(Node* _node, const TrackFunction _trck_fnct)
{
if (_node == nullptr || _trck_fnct == nullptr)
return;
actv_node_ = _node;
_node->enter(nullptr);
trck_fnct_ = _trck_fnct;
}
void Context::end_track()
{
if (!tracking())
return;
actv_node_->exit();
actv_node_ = nullptr;
trck_fnct_ = nullptr;
}
void Context::begin_abort()
{
abrt_ = true;
BASE_THROW_ERROR(PROGRESS_ABORTED);
}
void Context::resume_abort()
{
if (abrt_)
BASE_THROW_ERROR(PROGRESS_ABORTED);
}
void Context::end_abort()
{
abrt_ = false;
}
thread_local Context cntx;
/// Node implementation
Node::~Node()
{}
void Node::on_tick_number_max_exceeded()
{
tick_nmbr_max_ *= 2;
}
} //namespace Progress } //namespace Progress
#endif//PROGRESS_ON #endif//PROGRESS_ON
...@@ -6,14 +6,9 @@ ...@@ -6,14 +6,9 @@
#ifdef PROGRESS_ON #ifdef PROGRESS_ON
namespace Progress { namespace Progress {
//! Progress tick counter type
typedef unsigned long long TickNumber; typedef unsigned long long TickNumber;
class Node;
typedef void (*TrackFunction)(Node* _node,
const char* const _flnm, const char* const _fnct);
extern thread_local TrackFunction trck_fnct;
//! Represent an operational node in the progress graph //! Represent an operational node in the progress graph
class Node class Node
{ {
...@@ -23,75 +18,128 @@ public: ...@@ -23,75 +18,128 @@ public:
Node(const char* const _name, Node(const char* const _name,
Node* _next = nullptr, Node* _chld = nullptr) Node* _next = nullptr, Node* _chld = nullptr)
: name(_name), next_(_next), chld_(_chld), prnt_(nullptr), tick_nmbr_(0), : name(_name), next_(_next), chld_(_chld), prnt_(nullptr), tick_nmbr_(0),
tick_nmbr_max_(1), abrt_(false) tick_nmbr_max_(1)
{} {}
void enter(Node* _prnt) virtual ~Node();
const Node* next() const { return next_; };
const Node* child() const { return chld_; };
const Node* parent() const { return prnt_; };
TickNumber tick_number() const { return tick_nmbr_; }
TickNumber tick_number_max() const { return tick_nmbr_max_; }
void tick()
{ {
++tick_nmbr_;
if (tick_nmbr_ > tick_nmbr_max_)
on_tick_number_max_exceeded();
}
protected:
Node* next_; //!< next node on the same level, last if nullptr
Node* chld_; //!< first child node, leaf if nullptr
Node* prnt_; //!< parent node, set temporarily
protected:
TickNumber tick_nmbr_;
TickNumber tick_nmbr_max_;
protected:
virtual void on_tick_number_max_exceeded();
void enter(Node* _prnt)
{
prnt_ = _prnt; prnt_ = _prnt;
tick_nmbr_ = 0; tick_nmbr_ = 0;
} }
Node* exit() Node* exit()
{ {
auto prnt = prnt_; Node* prnt = prnt_;
prnt_ = nullptr; prnt_ = nullptr;
return prnt; return prnt;
} }
void tick(const char* const _flnm, const char* const _fnct) friend class Context;
{ };
++tick_nmbr_;
if (tick_nmbr_ > tick_nmbr_max_)
tick_nmbr_max_ *= 2;
if (trck_fnct != nullptr)
(*trck_fnct)(this, _flnm, _fnct);
}
TickNumber tick_number() const { return tick_nmbr_; } class Context
TickNumber tick_number_max() const { return tick_nmbr_max_; } {
double tick_percentage() const { return 100. * tick_nmbr_ / tick_nmbr_max_; } public:
//! Progress tracking function type
typedef void (*TrackFunction)(Node* _node,
const char* const _flnm, const char* const _fnct);
// set this flag to indicate that the operation is being aborted public:
void set_aborting(const bool _abrt) { abrt_ = _abrt; } /*!
Get if the Context is inactive, that is, the progress is being aborted, or
the progress is not being tracked.
*/
bool inactive() const { return abrt_ || actv_node_ == nullptr; }
void begin_track(Node* _node, const TrackFunction _trck_fnct);
bool tracking() const { return actv_node_ != nullptr; }
void end_track();
/*!
Throws PROGRESS_ABORTED to abort the Progress of the current operation.
*/
void begin_abort();
/*!
Resume an interrupted abort if the exception could be eaten unintentionally,
e.g., by a 3P library. This throws only if the progress is being aborted and
does nothing otherwise.
*/
void resume_abort();
/*!
Call this to finish the abort process and indicate that the thrown exception
has been handled.
*/
void end_abort();
Node* active_node() const { return actv_node_; }
void tick(const char* const _flnm, const char* const _fnct)
{
if (inactive())
return;
actv_node_->tick();
(*trck_fnct_)(actv_node_, _flnm, _fnct);
}
// check if the the node is being aborted, this allows us to adjust exception void enter_node(Node* _node)
// handling {
bool aborting() const { return abrt_; } if (!tracking())
return; // exit if not tracking
_node->enter(actv_node_);
actv_node_ = _node;
}
const Node* next() const { return next_; }; void exit_node()
const Node* child() const { return chld_; }; {
const Node* parent() const { return prnt_; }; if (tracking())
actv_node_ = actv_node_->exit();
}
protected: private:
Node* next_; //!< next node on the same level, last if nullptr bool abrt_ = false; // aborting flag
Node* chld_; //!< first child node, leaf if nullptr Node* actv_node_ = nullptr; // active node
Node* prnt_; //!< parent node, set temporarily TrackFunction trck_fnct_ = nullptr; //!< Progress current tracking function
private: private:
TickNumber tick_nmbr_;
TickNumber tick_nmbr_max_;
bool abrt_;
}; };
extern thread_local Node* actv_node; // active node //! the current thread Progress context
extern thread_local Context cntx;
struct ActiveScope struct ActiveScope
{ {
ActiveScope(Node* _node) ActiveScope(Node* _node) { cntx.enter_node(_node); }
{ ~ActiveScope() { cntx.exit_node(); }
if (_node == nullptr)
return;
_node->enter(actv_node);
actv_node = _node;
}
~ActiveScope()
{
if (actv_node == nullptr)
return;
actv_node = actv_node->exit();
}
}; };
typedef Node* (*MakeNodeFunction)(Node* _next); typedef Node* (*MakeNodeFunction)(Node* _next);
...@@ -135,18 +183,17 @@ inline Node* make_children_list(MakeNodeFunction _make_node_fnct, ...@@ -135,18 +183,17 @@ inline Node* make_children_list(MakeNodeFunction _make_node_fnct,
#define __PROGRESS_FUNCTION__ __PRETTY_FUNCTION__ // needed for gcc & xcode #define __PROGRESS_FUNCTION__ __PRETTY_FUNCTION__ // needed for gcc & xcode
#endif// _MSC_VER #endif// _MSC_VER
#define PROGRESS_TICK(NODE) { if ((NODE) != nullptr) \ #define PROGRESS_TICK { Progress::cntx.tick(__FILE__, __PROGRESS_FUNCTION__); }
(NODE)->tick(__FILE__, __PROGRESS_FUNCTION__); } #define PROGRESS_RESUME_ABORT { Progress::cntx.resume_abort(); }
#define PROGRESS_ACTIVE_TICK PROGRESS_TICK(Progress::actv_node) #define PROGRESS_END_ABORT { Progress::cntx.end_abort(); }
#define PROGRESS_ACTIVE_SCOPE(NAME, NODE) Progress::ActiveScope NAME = \
Progress::ActiveScope(Progress::PROGRESS_NODE_NAME(NODE))
#else #else
#define PROGRESS_DECLARE_NODE(OPRT) #define PROGRESS_DECLARE_NODE(OPRT)
#define PROGRESS_DEFINE_NODE(OPRT, ...) #define PROGRESS_DEFINE_NODE(OPRT, ...)
#define PROGRESS_ACTIVE_SCOPE(NAME, NODE) #define PROGRESS_TICK
#define PROGRESS_RESUME_ABORT
#define PROGRESS_END_ABORT
#endif// PROGRESS_ON #endif// PROGRESS_ON
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment