source: src/Actions/ActionQueue.hpp@ 91c409

Candidate_v1.7.0 stable
Last change on this file since 91c409 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
RevLine 
[628577]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
[29b52b]18#include "CodePatterns/Observer/Channels.hpp"
19#include "CodePatterns/Observer/Observable.hpp"
[74459a]20
21#ifdef HAVE_ACTION_THREAD
[415ddd]22#include <boost/thread.hpp>
[0427d1]23#include <boost/thread/recursive_mutex.hpp>
[74459a]24#endif
[690741]25#include <vector>
[1d3563]26
[f54cda]27#include "Actions/Action.hpp"
[b5b01e]28#include "Actions/ActionState.hpp"
[26b4eb4]29#include "Actions/ActionStatusList.hpp"
[628577]30
[74459a]31#ifdef HAVE_ACTION_THREAD
[415ddd]32void stopQueue();
33void waitQueue();
[74459a]34#endif
[415ddd]35
[11d433]36class CommandLineParser;
37
[628577]38namespace MoleCuilder {
39
[6367dd]40class ActionHistory;
[ed3944]41class ActionRegistry;
42class ActionTrait;
[f3db60]43class DryRunAdvocate;
[628577]44
[29b52b]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
[628577]53/** This class combines the whole handling of Actions into a single class.
54 *
[1d3563]55 * It spawns new Actions by its internal ActionRegistry. Spawned Actions are
56 * automatically queued and placed into a History after execution.
[628577]57 */
[29b52b]58class ActionQueue : public Singleton<ActionQueue>, public Observable
[628577]59{
60 friend class Singleton<ActionQueue>;
61public:
[690741]62 typedef std::vector<std::string> ActionTokens_t;
[af5384]63 typedef std::vector< Action * > ActionQueue_t;
[1d3563]64
[29b52b]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
[05c989]75 /** Queues the Action with \a name to be called.
76 *
[7fc447]77 * \param name token of Action to actionqueue
[f54cda]78 * \param state whether Actions needs to be filled via a Dialog or not
[05c989]79 */
[f54cda]80 void queueAction(const std::string &name, enum Action::QueryOptions state = Action::Interactive);
81
[1d3563]82 /** Returns the spawned action by token \a name.
83 *
[7fc447]84 * Action is checked into internal actionqueue.
[1d3563]85 *
[10aee4]86 * \return ref to newly spawned action
[1d3563]87 */
[10aee4]88 const Action& getActionByName(const std::string &name);
[1d3563]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 */
[a6ceab]95 bool isActionKnownByName(const std::string &name) const;
[1d3563]96
[126867]97 /** Register an Action with the ActionRegistry.
98 *
99 * \param _action action to add
100 */
101 void registerAction(Action *_action);
102
[690741]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 */
[a6ceab]114 const ActionTrait& getActionsTrait(const std::string &name) const;
[690741]115
[7fc447]116 /** Print the current contents of the actionqueue as CLI instantiated list of Actions.
[46b181]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
[7fc447]124 /** Print the current contents of the actionqueue as Python instantiated list of Actions.
[477012]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
[0ec9f5]132 /** Undoes last called Action.
[6367dd]133 *
134 */
135 void undoLast();
136
137 /** Redoes last undone Action.
138 *
139 */
140 void redoLast();
141
[0ec9f5]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
[c01fec]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
[a61dbb]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
[26b4eb4]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
[f3db60]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
[a87d1e2]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
[559293]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
[6367dd]223private:
224 //!> grant Action access to internal history functions.
225 friend class Action;
[11d433]226 //!> grant CommandLineParser access to stop and clearQueue()
227 friend class ::CommandLineParser;
[f3db60]228 //!> grant Advocate access to setting dryrun
229 friend class DryRunAdvocate;
[6367dd]230
[10aee4]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
[6367dd]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
[26b4eb4]245 /** Advocate function to add status message to the list.
246 *
247 */
248 void pushStatus(const std::string &_msg)
249 { StatusList.pushMessage(_msg); }
250
[6367dd]251 /** Wrapper function to clear ActionHistory.
252 *
253 */
254 void clear();
255
[601ef8]256 /** Clears all actions present in the actionqueues from \a _fromAction.
[7f1a1a]257 *
[601ef8]258 * @param _fromAction 0 if all Actions to clear or else
[7f1a1a]259 */
[601ef8]260 void clearQueue(const size_t _fromAction = 0);
[7f1a1a]261
[74459a]262#ifdef HAVE_ACTION_THREAD
[10aee4]263 boost::thread &getRunThread()
264 { return run_thread; }
[601ef8]265
[0427d1]266 /**
267 * Steps on to the next action by incrementing \a CurrentAction.
268 */
269 void stepOnToNextAction();
270
[601ef8]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
[415ddd]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();
[601ef8]300
301 /** Moves all action from tempqueue into real queue.
302 *
303 */
304 void insertTempQueue();
305
[74459a]306#endif
[415ddd]307
[975b83]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
[f3db60]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
[628577]330private:
[1d3563]331 /** Private cstor for ActionQueue.
332 *
333 * Must be private as is singleton.
334 *
335 */
[628577]336 ActionQueue();
[1d3563]337
338 /** Dstor for ActionQueue.
339 *
340 */
[628577]341 ~ActionQueue();
342
[29b52b]343private:
344 friend const Action *Queuedetail::lastChanged<Action>();
345 static const Action *_lastchangedaction;
346
[628577]347 //!> ActionRegistry to spawn new actions
[ed3944]348 ActionRegistry *AR;
[1d3563]349
[6367dd]350 //!> ActionHistory is for undoing and redoing actions, requires ActionRegistry fully initialized
351 ActionHistory *history;
352
[7fc447]353 //!> internal actionqueue of actions
354 ActionQueue_t actionqueue;
[af5384]355
[601ef8]356 //!> indicates that the last action has failed
357 bool lastActionOk;
358
[7fc447]359 //!> point to current action in actionqueue
[af5384]360 size_t CurrentAction;
[415ddd]361
[a87d1e2]362#ifdef HAVE_ACTION_THREAD
[415ddd]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
[0427d1]370 mutable boost::recursive_mutex mtx_queue;
[415ddd]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
[94232b]379 mutable boost::mutex mtx_idle;
[74459a]380#endif
[26b4eb4]381
382 //!> internal list of status messages from Actions for UIs to display
383 ActionStatusList StatusList;
[f3db60]384
385 //!> internal flag whether to call or skip actions (i.e. do a dry run)
386 bool dryrun_flag;
[628577]387};
[8859b5]388namespace Queuedetail {
389 template <> inline const Action* lastChanged<Action>() { return ActionQueue::_lastchangedaction; }
390}
[628577]391
392};
393
394#endif /* ACTIONQUEUE_HPP_ */
Note: See TracBrowser for help on using the repository browser.