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

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 @@
#ifdef PROGRESS_ON
#include "Base/Progress/ProgressNode.hh"
#else//PROGRESS_ON
#define PROGRESS_ACTIVE_TICK
#define PROGRESS_TICK
#endif//PROGRESS_ON
// DEB_ON is defined, or not, in CMakeLists.txt for primary project
#ifndef DEB_ON
#define DEB_module(SS)
#define DEB_enter_func PROGRESS_ACTIVE_TICK;
#define DEB_enter_func PROGRESS_TICK;
#define DEB_only(CC)
#define DEB_exec(LL, AA) { PROGRESS_ACTIVE_TICK; }
#define DEB_exec_if(CC, LL, AA) { PROGRESS_ACTIVE_TICK; }
#define DEB_out(LL, AA) { PROGRESS_ACTIVE_TICK; }
#define DEB_out_if(CC, LL, AA) { PROGRESS_ACTIVE_TICK; }
#define DEB_line(LL, AA) { PROGRESS_ACTIVE_TICK; }
#define DEB_line_if(CC, LL, AA) { PROGRESS_ACTIVE_TICK; }
#define DEB_exec(LL, AA) { PROGRESS_TICK; }
#define DEB_exec_if(CC, LL, AA) { PROGRESS_TICK; }
#define DEB_out(LL, AA) { PROGRESS_TICK; }
#define DEB_out_if(CC, LL, AA) { PROGRESS_TICK; }
#define DEB_line(LL, AA) { PROGRESS_TICK; }
#define DEB_line_if(CC, LL, AA) { PROGRESS_TICK; }
#define DEB_warning(LL, AA) {}
#define DEB_warning_if(CC, LL, AA) {}
......@@ -136,7 +136,7 @@ std::string to_string(const T& _t)
//TODO: This should use an atomic thread-safe static int(s)
#define DEB_enter_func \
PROGRESS_ACTIVE_TICK; \
PROGRESS_TICK; \
static int deb_nmbr = 0; \
static int deb_lvl = Debug::INVALID_LEVEL; \
::Debug::Enter deb(__FILE__, __FUNCTION__, deb_nmbr, deb_lvl);
......@@ -144,15 +144,15 @@ std::string to_string(const T& _t)
#define DEB_only(CC) CC
#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; } } }
#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; } } }
#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; } } }
#define DEB_warning(LL, AA) DEB_warning_if(true, LL, AA)
......
......@@ -4,12 +4,57 @@
#include "Base/Code/Quality.hh"
#include "ProgressNode.hh"
#include "Base/Utils/BaseError.hh"
#ifdef PROGRESS_ON
namespace Progress {
thread_local TrackFunction trck_fnct = nullptr;
thread_local Node* actv_node; // active node
/// Context implementation
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
#endif//PROGRESS_ON
......@@ -6,14 +6,9 @@
#ifdef PROGRESS_ON
namespace Progress {
//! Progress tick counter type
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
class Node
{
......@@ -23,75 +18,128 @@ public:
Node(const char* const _name,
Node* _next = nullptr, Node* _chld = nullptr)
: 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;
tick_nmbr_ = 0;
}
Node* exit()
{
auto prnt = prnt_;
Node* prnt = prnt_;
prnt_ = nullptr;
return prnt;
}
void tick(const char* const _flnm, const char* const _fnct)
{
++tick_nmbr_;
if (tick_nmbr_ > tick_nmbr_max_)
tick_nmbr_max_ *= 2;
if (trck_fnct != nullptr)
(*trck_fnct)(this, _flnm, _fnct);
}
friend class Context;
};
TickNumber tick_number() const { return tick_nmbr_; }
TickNumber tick_number_max() const { return tick_nmbr_max_; }
double tick_percentage() const { return 100. * tick_nmbr_ / tick_nmbr_max_; }
class Context
{
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
void set_aborting(const bool _abrt) { abrt_ = _abrt; }
public:
/*!
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
// handling
bool aborting() const { return abrt_; }
void enter_node(Node* _node)
{
if (!tracking())
return; // exit if not tracking
_node->enter(actv_node_);
actv_node_ = _node;
}
const Node* next() const { return next_; };
const Node* child() const { return chld_; };
const Node* parent() const { return prnt_; };
void exit_node()
{
if (tracking())
actv_node_ = actv_node_->exit();
}
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
private:
bool abrt_ = false; // aborting flag
Node* actv_node_ = nullptr; // active node
TrackFunction trck_fnct_ = nullptr; //!< Progress current tracking function
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
{
ActiveScope(Node* _node)
{
if (_node == nullptr)
return;
_node->enter(actv_node);
actv_node = _node;
}
~ActiveScope()
{
if (actv_node == nullptr)
return;
actv_node = actv_node->exit();
}
ActiveScope(Node* _node) { cntx.enter_node(_node); }
~ActiveScope() { cntx.exit_node(); }
};
typedef Node* (*MakeNodeFunction)(Node* _next);
......@@ -135,18 +183,17 @@ inline Node* make_children_list(MakeNodeFunction _make_node_fnct,
#define __PROGRESS_FUNCTION__ __PRETTY_FUNCTION__ // needed for gcc & xcode
#endif// _MSC_VER
#define PROGRESS_TICK(NODE) { if ((NODE) != nullptr) \
(NODE)->tick(__FILE__, __PROGRESS_FUNCTION__); }
#define PROGRESS_ACTIVE_TICK PROGRESS_TICK(Progress::actv_node)
#define PROGRESS_ACTIVE_SCOPE(NAME, NODE) Progress::ActiveScope NAME = \
Progress::ActiveScope(Progress::PROGRESS_NODE_NAME(NODE))
#define PROGRESS_TICK { Progress::cntx.tick(__FILE__, __PROGRESS_FUNCTION__); }
#define PROGRESS_RESUME_ABORT { Progress::cntx.resume_abort(); }
#define PROGRESS_END_ABORT { Progress::cntx.end_abort(); }
#else
#define PROGRESS_DECLARE_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
......
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