ProgressNode.hh 5.51 KB
Newer Older
1
2
3
4
5
6
// (C) Copyright 2017 by Autodesk, Inc.

#ifndef BASE_PROGRESS_NODE_HH_INCLUDED
#define BASE_PROGRESS_NODE_HH_INCLUDED

#ifdef PROGRESS_ON
7
8
9

#include <Base/Utils/Thread.hh>

10
namespace Progress {
11
   
12
//! Progress tick counter type
13
14
typedef unsigned long long TickNumber;

15
16
17
//! Represent an operational node in the progress graph 
class Node
{
18
19
20
21
22
23
24
25
26
27
28
29
public:
  typedef Node* (*MakeNodeFunction)(Node* _next);

  static inline Node* make_child_list() { return nullptr; }

  template <typename... ArgT>
  static inline Node* make_child_list(MakeNodeFunction _make_node_fnct, 
    const ArgT&... _args)
  {
    return (*_make_node_fnct)(make_child_list(_args...));
  }

30
31
32
33
34
public:
  const char* const name;
  
  Node(const char* const _name, 
    Node* _next = nullptr, Node* _chld = nullptr) 
35
    : name(_name), next_(_next), chld_(_chld), prnt_(nullptr), tick_nmbr_(0)
36
37
  {}

38
39
40
41
42
43
  virtual ~Node();

  const Node* next() const { return next_; };
  const Node* child() const { return chld_; };

  TickNumber tick_number() const { return tick_nmbr_; }
44
  virtual TickNumber tick_number_max() const;
45

46
  void tick() { ++tick_nmbr_; }
47
48
49
50
51

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
52
  TickNumber tick_nmbr_; // number of ticks in the node
53

54
55
  friend class Context;
};
56

57
58
59
class Context
{
public:
60
61
62
63
64
65
66
67
  //! Default constructor
  Context();

  /*!
  Get if the progress is "faking" tracking, i.e., using a phony root node.
  Phony tracking is faster than checking if a root has been set. 
  */
  bool phony() const { return actv_node_ == &phny_root_; }
68

69
  /*! 
70
  Get the currently active node, only makes sense to use that if not phony().
71
  */
72
  const Node* active_node() const { return actv_node_; }
73

74
75
76
77
  /*! 
  Get the root node, only makes sense to use that if not phony().
  */
  const Node* root_node() const { return root_node_; }
78
79
80
81
82
  
  /*!
  Get if the context is active, i.e., there is an active operation in progress.
  */
  bool active() const { return actv_node_ != root_node_; }
83
84

  /*! 
85
86
87
  Request progress abort, intended to be called asynchronously from a "tracking" 
  thread.
  The abort will be triggered on the next \ref tick() in the context thread. 
88
  */
89
  void request_abort() { abrt_stte_ = AST_REQUEST; }
90
91
92
93
94
95
96
97
98
99
100
101
102
103

  /*! 
  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();

104
  void tick(const char* const /*_fnct*/)
105
106
  {
    actv_node_->tick();
107
108
    if (abrt_stte_ == AST_REQUEST)
      abort();
109
  }
110

111
112
  void enter_node(Node* _node);
  void exit_node();
113

114
115
116
  void set_abort_allowed(bool _abrt_alwd) { abrt_alwd_ = _abrt_alwd; }
  bool abort_allowed() const { return abrt_alwd_; }

117
118
private:
  enum AbortStateType
119
  {
120
121
122
123
    AST_NONE,
    AST_REQUEST,
    AST_PROCESSING
  };
124

125
private:
126
  AbortStateType abrt_stte_; //!< Abort state
127
  bool abrt_alwd_; //!< Abort allowed flag, ignores AST_REQUEST if false
128
129
130
  Node phny_root_; //!< "phony" root
  Node* root_node_; //!< Root node
  Node* actv_node_; //!< Active node
131
132

private:
133
134
  //! Throws PROGRESS_ABORTED to abort the current operation.
  void abort();
135
136
};

137
//! the current thread Progress context
138
extern BASE_THREAD_LOCAL Context cntx;
139

140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
/*! 
Enable (or disable) the Context::abort() processing, use to enable abort() 
processing which is disabled by default.

Use this to set up a scope in which the progress can be aborted. Such scope
should be exception-handled, unless exiting the application on abort is desired.
*/
class AbortAllowedSession
{
public:
  AbortAllowedSession(const bool _abrt_alwd)
    : abrt_alwd_bckp_(cntx.abort_allowed())
  {
    cntx.set_abort_allowed(_abrt_alwd);
  }

  ~AbortAllowedSession()
  {
    cntx.set_abort_allowed(abrt_alwd_bckp_);
  }

private:
  bool abrt_alwd_bckp_;
};

165
166
167
168
169
170
171
} //namespace Progress

#define PROGRESS_NODE_NAME(OPRT) OPRT##_node
#define PROGRESS_MAKE_NODE_NAME(OPRT) make_##OPRT##_node

#define PROGRESS_DECLARE_NODE(OPRT) \
  namespace Progress { \
172
  extern BASE_THREAD_LOCAL Node* PROGRESS_NODE_NAME(OPRT); \
173
174
175
  Node* PROGRESS_MAKE_NODE_NAME(OPRT)(Node* _next = nullptr); \
  } //namespace Progress {

176

177
#define PROGRESS_DEFINE_NODE_CUSTOM(TYPE, OPRT, ...) \
178
  BASE_THREAD_LOCAL Progress::Node* Progress::PROGRESS_NODE_NAME(OPRT) = nullptr; \
179
180
181
  Progress::Node* Progress::PROGRESS_MAKE_NODE_NAME(OPRT) \
    (Progress::Node* _next) \
  { \
182
    static BASE_THREAD_LOCAL TYPE node(#OPRT, _next, \
183
      Node::make_child_list( __VA_ARGS__ ));\
184
185
186
187
188
189
    return OPRT##_node = &node; \
  }

#define PROGRESS_DEFINE_NODE(OPRT, ...) \
  PROGRESS_DEFINE_NODE_CUSTOM(Node, OPRT, ##__VA_ARGS__)

190
191
192
193
194
195
#if defined(_MSC_VER)  
#define __PROGRESS_FUNCTION__ __FUNCTION__ // works in VC well 
#else 
#define __PROGRESS_FUNCTION__ __PRETTY_FUNCTION__ // needed for gcc & xcode
#endif// _MSC_VER

196
#define PROGRESS_TICK { Progress::cntx.tick(__PROGRESS_FUNCTION__); } 
197
198
#define PROGRESS_RESUME_ABORT { Progress::cntx.resume_abort(); }
#define PROGRESS_END_ABORT { Progress::cntx.end_abort(); }
199
#define PROGRESS_ALLOW_ABORT Progress::AbortAllowedSession abrt_alwd_sssn(true)
200

201
202
203
#else

#define PROGRESS_DECLARE_NODE(OPRT) 
204
#define PROGRESS_DEFINE_NODE_CUSTOM(TYPE, OPRT, ...)
205
#define PROGRESS_DEFINE_NODE(OPRT, ...) 
206
207
208
#define PROGRESS_TICK
#define PROGRESS_RESUME_ABORT
#define PROGRESS_END_ABORT
209
#define PROGRESS_ALLOW_ABORT
210

211
212
213
#endif// PROGRESS_ON

#endif//BASE_PROGRESS_NODE_HH_INCLUDED