source: src/Actions/ActionQueue.hpp@ 399c69

Candidate_v1.7.0 stable
Last change on this file since 399c69 was 0427d1, checked in by Frederik Heber <frederik.heber@…>, 20 months ago

FIX: ActionQueue no locked on CurrentAction access.

  • actionqueue[CurrentAction] without mutex locking.
  • getCurrentAction() without mutex locking.
  • extracted stepOnToNextAction().
  • using recursive_mutex instead of normal to allow nested locks.
  • Property mode set to 100644
File size: 10.1 KB
Line 
1/*
2 * ActionQueue.hpp
3 *
4 * Created on: Aug 16, 2013
5 * Author: heber
6 */
7
8#ifndef ACTIONQUEUE_HPP_
9#define ACTIONQUEUE_HPP_
10
11// include config.h
12#ifdef HAVE_CONFIG_H
13#include <config.h>
14#endif
15
16#include "CodePatterns/Singleton.hpp"
17
18#include "CodePatterns/Observer/Channels.hpp"
19#include "CodePatterns/Observer/Observable.hpp"
20
21#ifdef HAVE_ACTION_THREAD
22#include <boost/thread.hpp>
23#include <boost/thread/recursive_mutex.hpp>
24#endif
25#include <vector>
26
27#include "Actions/Action.hpp"
28#include "Actions/ActionState.hpp"
29#include "Actions/ActionStatusList.hpp"
30
31#ifdef HAVE_ACTION_THREAD
32void stopQueue();
33void waitQueue();
34#endif
35
36class CommandLineParser;
37
38namespace MoleCuilder {
39
40class ActionHistory;
41class ActionRegistry;
42class ActionTrait;
43class DryRunAdvocate;
44
45namespace Queuedetail {
46 template <class T> const T* lastChanged()
47 {
48 ASSERT(0, "Queuedetail::lastChanged() - only specializations may be used.");
49 return NULL;
50 }
51}
52
53/** This class combines the whole handling of Actions into a single class.
54 *
55 * It spawns new Actions by its internal ActionRegistry. Spawned Actions are
56 * automatically queued and placed into a History after execution.
57 */
58class ActionQueue : public Singleton<ActionQueue>, public Observable
59{
60 friend class Singleton<ActionQueue>;
61public:
62 typedef std::vector<std::string> ActionTokens_t;
63 typedef std::vector< Action * > ActionQueue_t;
64
65 //!> channels for this observable
66 enum NotificationType {
67 ActionQueued, // new action was queued
68 NotificationType_MAX // denotes the maximum of available notification types
69 };
70
71 //>! access to last changed element (atom or molecule)
72 template <class T> const T* lastChanged() const
73 { return Queuedetail::lastChanged<T>(); }
74
75 /** Queues the Action with \a name to be called.
76 *
77 * \param name token of Action to actionqueue
78 * \param state whether Actions needs to be filled via a Dialog or not
79 */
80 void queueAction(const std::string &name, enum Action::QueryOptions state = Action::Interactive);
81
82 /** Returns the spawned action by token \a name.
83 *
84 * Action is checked into internal actionqueue.
85 *
86 * \return ref to newly spawned action
87 */
88 const Action& getActionByName(const std::string &name);
89
90 /** Checks whether the Action is known by the given \a name.
91 *
92 * \param name token of action to check
93 * \return true - token is known, false - else
94 */
95 bool isActionKnownByName(const std::string &name) const;
96
97 /** Register an Action with the ActionRegistry.
98 *
99 * \param _action action to add
100 */
101 void registerAction(Action *_action);
102
103 /** Returns the vector with the tokens of all currently known Actions.
104 *
105 * \return list of all tokens
106 */
107 const ActionTokens_t getListOfActions() const;
108
109 /** Returns the trait to an Action.
110 *
111 * \param name name of Action
112 * \return const ref to its default Trait.
113 */
114 const ActionTrait& getActionsTrait(const std::string &name) const;
115
116 /** Print the current contents of the actionqueue as CLI instantiated list of Actions.
117 *
118 * This is useful for storing the current session.
119 *
120 * \param output output stream to print to
121 */
122 void outputAsCLI(std::ostream &output) const;
123
124 /** Print the current contents of the actionqueue as Python instantiated list of Actions.
125 *
126 * This is useful for storing the current session.
127 *
128 * \param output output stream to print to
129 */
130 void outputAsPython(std::ostream &output) const;
131
132 /** Undoes last called Action.
133 *
134 */
135 void undoLast();
136
137 /** Redoes last undone Action.
138 *
139 */
140 void redoLast();
141
142 /**
143 * Marks the current item of the action history to allow returning to that state lateron.
144 */
145 void setMark();
146
147 /**
148 * Resets any currently marked item in the action history.
149 */
150 void unsetMark();
151
152 /** Undoes actions till a set mark in the ActionHistory.
153 *
154 */
155 void undoTillMark();
156
157 /** Checks whether there is one completed Action stored in ActionHistory in the past.
158 *
159 * @return true - at least one Action to undo present, false - else
160 */
161 bool canUndo() const;
162
163 /** Checks whether there is one completed Action stored in ActionHistory in the future.
164 *
165 * @return true - at least one Action to redo present, false - else
166 */
167 bool canRedo() const;
168
169 /** Return status of last executed action.
170 *
171 * \return true - action executed correctly, false - else
172 */
173 bool getLastActionOk() const
174 { return lastActionOk; }
175
176 /** Getter to ref to list of status messages.
177 *
178 * This is meant for UIs to registers as Observables.
179 *
180 * \return ref to StatusList variable
181 */
182 ActionStatusList& getStatusList()
183 { return StatusList; }
184
185 /** Getter for isDryRun state flag.
186 *
187 * \return true - ActionQueue does not execute Actions but skips, false - else
188 */
189 bool getDryRun() const
190 { return dryrun_flag; }
191
192 /** States whether the ActionQueue is currently executing Actions or done executing.
193 *
194 * \return true - ActionQueue is done executing Actions.
195 */
196 bool isIdle() const;
197
198 /** States whether the current Action in the ActionQueue is a Process.
199 *
200 * \return true - ActionQueue is currently executing a process.
201 */
202 bool isProcess() const;
203
204 /** States whether the current Action in the ActionQueue is a MakroAction.
205 *
206 * \return true - ActionQueue is currently executing a MakroAction.
207 */
208 bool isMakroAction() const;
209
210 /** Getter to the current Action.
211 *
212 * \note Using this ref is only useful during the execution of the Action, e.g.
213 * when an Action inside the ActionSequence of a MakroAction needs access to the
214 * MakroAction itself (to signal stop). \sa MoleCuilder::ForceAnnealingAction::performCall()
215 *
216 * \warning Due to the multi-threaded nature of the ActionQueue this is very
217 * dangerous to use in other circumstances.
218 *
219 * \return const ref to the currently executed action
220 */
221 const Action& getCurrentAction() const;
222
223private:
224 //!> grant Action access to internal history functions.
225 friend class Action;
226 //!> grant CommandLineParser access to stop and clearQueue()
227 friend class ::CommandLineParser;
228 //!> grant Advocate access to setting dryrun
229 friend class DryRunAdvocate;
230
231 /** Queues the Action with \a name to be called.
232 *
233 * \param _action action to add
234 * \param state whether Actions needs to be filled via a Dialog or not
235 */
236 void queueAction(const Action * const _action, enum Action::QueryOptions state = Action::Interactive);
237
238 /** Wrapper function to add state to ActionHistory.
239 *
240 * \param _Action Action whose state to add
241 * \param _state state to add
242 */
243 void addElement(Action* _Action, ActionState::ptr _state);
244
245 /** Advocate function to add status message to the list.
246 *
247 */
248 void pushStatus(const std::string &_msg)
249 { StatusList.pushMessage(_msg); }
250
251 /** Wrapper function to clear ActionHistory.
252 *
253 */
254 void clear();
255
256 /** Clears all actions present in the actionqueues from \a _fromAction.
257 *
258 * @param _fromAction 0 if all Actions to clear or else
259 */
260 void clearQueue(const size_t _fromAction = 0);
261
262#ifdef HAVE_ACTION_THREAD
263 boost::thread &getRunThread()
264 { return run_thread; }
265
266 /**
267 * Steps on to the next action by incrementing \a CurrentAction.
268 */
269 void stepOnToNextAction();
270
271 /** Clears the temporary queue.
272 *
273 */
274 void clearTempQueue();
275
276 /** Sets the run_thread_isIdle flag.
277 *
278 * @param _flag state to set to
279 */
280 void setRunThreadIdle(const bool _flag);
281
282 /** Runs the ActionQueue.
283 *
284 */
285 void run();
286
287 friend void ::stopQueue();
288
289 /** Stops the internal thread.
290 *
291 */
292 void stop();
293
294 friend void ::waitQueue();
295
296 /** Wait till all currently queued actions are processed.
297 *
298 */
299 void wait();
300
301 /** Moves all action from tempqueue into real queue.
302 *
303 */
304 void insertTempQueue();
305
306#endif
307
308 /** Insert an action after CurrentAction.
309 *
310 * This is implemented only to allow action's COMMAND to work. If we
311 * were to use queueAction, actions would come after all other already
312 * present actions.
313 */
314 void insertAction(Action *_action, enum Action::QueryOptions state);
315
316 /** Sets the current state of the \a isDryRun flag.
317 *
318 * \param _dryrun true - Actions will not get executed anymore, false - else
319 */
320 void setDryRun(const bool _dryrun)
321 { dryrun_flag = _dryrun; }
322
323 /** Checks whether next Action should be skipped or not.
324 *
325 * \param _nextaction next action to execute to inspect whether it unsets dryrun_flag
326 * \return true - dryrun_flag set and \a _nextaction is not unsetting dry run
327 */
328 bool isDryRun(const Action *_nextaction) const;
329
330private:
331 /** Private cstor for ActionQueue.
332 *
333 * Must be private as is singleton.
334 *
335 */
336 ActionQueue();
337
338 /** Dstor for ActionQueue.
339 *
340 */
341 ~ActionQueue();
342
343private:
344 friend const Action *Queuedetail::lastChanged<Action>();
345 static const Action *_lastchangedaction;
346
347 //!> ActionRegistry to spawn new actions
348 ActionRegistry *AR;
349
350 //!> ActionHistory is for undoing and redoing actions, requires ActionRegistry fully initialized
351 ActionHistory *history;
352
353 //!> internal actionqueue of actions
354 ActionQueue_t actionqueue;
355
356 //!> indicates that the last action has failed
357 bool lastActionOk;
358
359 //!> point to current action in actionqueue
360 size_t CurrentAction;
361
362#ifdef HAVE_ACTION_THREAD
363 //!> internal temporary actionqueue of actions used by insertAction()
364 ActionQueue_t tempqueue;
365
366 //!> internal thread to call Actions
367 boost::thread run_thread;
368
369 //!> internal mutex to synchronize access to queue
370 mutable boost::recursive_mutex mtx_queue;
371
372 //!> conditional variable notifying when run_thread is idling
373 boost::condition_variable cond_idle;
374
375 //!> flag indicating whether run_thread is idle or not
376 bool run_thread_isIdle;
377
378 //!> internal mutex to synchronize access to run_thread_isIdle
379 mutable boost::mutex mtx_idle;
380#endif
381
382 //!> internal list of status messages from Actions for UIs to display
383 ActionStatusList StatusList;
384
385 //!> internal flag whether to call or skip actions (i.e. do a dry run)
386 bool dryrun_flag;
387};
388namespace Queuedetail {
389 template <> inline const Action* lastChanged<Action>() { return ActionQueue::_lastchangedaction; }
390}
391
392};
393
394#endif /* ACTIONQUEUE_HPP_ */
Note: See TracBrowser for help on using the repository browser.