Orocos Real-Time Toolkit  2.8.3
FunctionGraph.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  tag: Peter Soetens Tue Dec 21 22:43:07 CET 2004 FunctionGraph.cxx
3 
4  FunctionGraph.cxx - description
5  -------------------
6  begin : Tue December 21 2004
7  copyright : (C) 2004 Peter Soetens
8  email : peter.soetens@mech.kuleuven.ac.be
9 
10  ***************************************************************************
11  * This library is free software; you can redistribute it and/or *
12  * modify it under the terms of the GNU General Public *
13  * License as published by the Free Software Foundation; *
14  * version 2 of the License. *
15  * *
16  * As a special exception, you may use this file as part of a free *
17  * software library without restriction. Specifically, if other files *
18  * instantiate templates or use macros or inline functions from this *
19  * file, or you compile this file and link it with other files to *
20  * produce an executable, this file does not by itself cause the *
21  * resulting executable to be covered by the GNU General Public *
22  * License. This exception does not however invalidate any other *
23  * reasons why the executable file might be covered by the GNU General *
24  * Public License. *
25  * *
26  * This library is distributed in the hope that it will be useful, *
27  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
28  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
29  * Lesser General Public License for more details. *
30  * *
31  * You should have received a copy of the GNU General Public *
32  * License along with this library; if not, write to the Free Software *
33  * Foundation, Inc., 59 Temple Place, *
34  * Suite 330, Boston, MA 02111-1307 USA *
35  * *
36  ***************************************************************************/
37 
38 
39 #include "FunctionGraph.hpp"
40 #include "GraphCopier.hpp"
41 #include "../base/AttributeBase.hpp"
42 #include "ProgramService.hpp"
43 #include "TaskContext.hpp"
44 #include "../Service.hpp"
45 
46 #include "CommandNOP.hpp"
47 #include "ConditionFalse.hpp"
48 #include "ConditionTrue.hpp"
49 #include <boost/graph/copy.hpp>
50 #include <utility>
51 
52 namespace RTT {
53  using namespace detail;
54  using namespace boost;
55  using namespace std;
56 
57 
58 
59  FunctionGraph::FunctionGraph(const std::string& _name, bool unload_on_stop)
60  : myName(_name), retn(0), pausing(false), mstep(false), munload_on_stop(unload_on_stop)
61  {
62  // the start vertex of our function graph
63  startv = add_vertex( program );
65  exitv = add_vertex( program );
67  }
68 
70  : program( orig.getGraph() ), myName( orig.getName() )
71  {
72  // The nodes are copied, which causes a clone of their contents.
73  graph_traits<Graph>::vertex_iterator v1,v2, it;
74  tie(v1,v2) = vertices(program);
75  for ( it=v1; it != v2; ++it)
76  if ( get( vertex_exec, program, *it) == VertexNode::func_start_node )
77  break;
78  startv = *v1;
79  for ( it=v1; it != v2; ++it)
80  if ( get( vertex_exec, program, *it) == VertexNode::func_exit_node )
81  break;
82  exitv = *v1;
83 
84  // Copy-clone over the TAB pointers.
85  std::vector<AttributeBase*> argsvect = orig.getArguments();
86  std::vector<AttributeBase*>::iterator ita = argsvect.begin();
87  for ( ; ita != argsvect.end(); ++ita)
88  this->args.push_back( (*ita)->clone() );
89  if (orig.retn)
90  retn = orig.retn->clone();
91  this->finish();
92  }
93 
95  {
98 
99  // Because we use listS, we need to re-index the map :-(
100  // If we do not do this, it can not be copied by the copy_graph
101  // function.
102  property_map<Graph, vertex_index_t>::type
103  index = get(vertex_index, program);
104 
105  // initialize the vertex_index property values
106  // so that it can be copied into other graphs.
107  graph_traits<Graph>::vertex_iterator vi, vend;
108  graph_traits<Graph>::vertices_size_type cnt = 0;
109  for(tie(vi,vend) = vertices(program); vi != vend; ++vi)
110  put(index, *vi, cnt++);
111  this->reset();
112  }
113 
115  {
116  //log(Debug) << "Destroying program '" << getName() << "'" <<endlog();
117  if ( this->isLoaded() ){
118  getEngine()->removeFunction(this);
119  }
120  std::vector<AttributeBase*>::iterator it = args.begin();
121  for ( ; it != args.end(); ++it)
122  delete *it;
123 
124  }
125 
127  {
128  context = myservice;
129  }
130 
131  void FunctionGraph::setUnloadOnStop(bool unload_on_stop)
132  {
133  munload_on_stop = unload_on_stop;
134  }
135 
137  {
138  // we need to auto-start, or we would be unloaded right away.
139  if (munload_on_stop)
140  this->start();
141  }
142 
144  {
145  // this function is called in a real-time context when execute() returns false.
146  // for functions that have a context object, these should never return false
147  // in execute(). See the munload_on_stop flag.
148  if ( !context )
149  return; // plain function
150  // The case for program scripts: they are managed by the ScriptingService, which will
151  // take care of unloading.
152  if (context->getParent() ) {
153  context->getParent()->removeService(context->getName());
154  }
155  context.reset();
156  }
157 
158 
160  {
161  if ( !isLoaded() )
162  return false;
163  if ( pStatus == Status::stopped ) {
164  this->reset();
165  }
168  return true;
169  }
170  return false;
171  }
172 
174  {
175  if ( isLoaded() ) {
176  if ( pStatus == Status::stopped ) {
177  this->reset();
178  }
179  pausing = true;
180  return true;
181  }
182  return false;
183  }
184 
186  {
187  if ( isLoaded() && (pStatus == Status::paused) && mstep == false) {
188  mstep = true;
189  return true;
190  }
191  return false;
192  }
193 
195  {
196  return mstep == false;
197  }
198 
200  {
201  if (pausing) {
203  pausing = false;
204  return true;
205  }
206  switch (pStatus) {
207  case Status::running:
208  return this->executeUntil();
209  break;
210  case Status::paused:
211  if (mstep) {
212  mstep = false;
213  this->executeStep();
214  return true;
215  } else
216  return true;
217  break;
218  case Status::error:
219  case Status::unknown:
220  case Status::stopped:
221  return !munload_on_stop;
222  break;
223  }
224  return false;
225  }
226 
227 
229  {
230  graph_traits<Graph>::out_edge_iterator ei, ei_end;
231  // the map contains _references_ to all vertex_command properties
232  boost::property_map<Graph, vertex_command_t>::type
233  cmap = get(vertex_command, program);
234  boost::property_map<Graph, edge_condition_t>::type
235  emap = get(edge_condition, program);
236 
237  do {
238  // Check this always on entry of executeUntil :
239  // initialise current node if needed and reset all its out_edges
240  // if previous == current, we DO NOT RESET, because we want to check
241  // if previous command has completed !
242  if ( previous != current )
243  {
244  for ( tie(ei, ei_end) = boost::out_edges( current, program ); ei != ei_end; ++ei)
245  emap[*ei].reset();
246  try {
247  cmap[current].startExecution();
248  } catch(...) {
250  return false;
251  }
252  }
253 
254  // initial conditions :
255  previous = current;
256  // execute the current command.
257  try {
258  cmap[current].execute();
259  } catch(...) {
261  return false;
262  }
263 
264  // Branch selecting Logic :
265  if ( cmap[current].isValid() ) {
266  for ( tie(ei, ei_end) = boost::out_edges( current, program ); ei != ei_end; ++ei) {
267  try {
268  if ( emap[*ei].evaluate() ) {
269  current = boost::target(*ei, program);
270  // a new node has been found ...
271  // so continue
272  break; // exit from for loop.
273  }
274  } catch(...) {
276  return false;
277  }
278  }
279  }
280  } while ( previous != current && pStatus == Status::running && !pausing); // keep going if we found a new node
281 
282  // check finished state
283  if (current == exitv) {
284  this->stop();
285  return !munload_on_stop;
286  }
287  return true; // we need to wait.
288  }
289 
291  {
292  graph_traits<Graph>::out_edge_iterator ei, ei_end;
293  // the map contains _references_ to all vertex_command properties
294  boost::property_map<Graph, vertex_command_t>::type
295  cmap = get(vertex_command, program);
296  boost::property_map<Graph, edge_condition_t>::type
297  emap = get(edge_condition, program);
298 
299  // initialise current node if needed and reset all its out_edges
300  if ( previous != current )
301  {
302  for ( tie(ei, ei_end) = boost::out_edges( current, program ); ei != ei_end; ++ei)
303  emap[*ei].reset();
304  try {
305  cmap[current].startExecution();
306  } catch(...) {
308  return false;
309  }
310  previous = current;
311  }
312 
313  // execute the current command.
314  try {
315  cmap[current].execute();
316  } catch(...) {
318  return false;
319  }
320 
321  // Branch selecting Logic :
322  if ( cmap[current].isValid() ) {
323  for ( tie(ei, ei_end) = boost::out_edges( current, program ); ei != ei_end; ++ei) {
324  try {
325  if ( emap[*ei].evaluate() ) {
326  current = boost::target(*ei, program);
327  if (current == exitv)
328  this->stop();
329  // a new node has been found ...
330  // it will be executed in the next step.
331  return true;
332  }
333  } catch(...) {
335  return false;
336  }
337  }
338  }
339  // check finished state
340  if (current == exitv)
341  this->stop();
342  return true; // no new branch found yet !
343  }
344 
346  current = startv;
347  previous = exitv;
348  this->stop();
349  }
350 
352  {
353  // stop even works if no pp is present
355  return true;
356  }
357 
358  const std::string& FunctionGraph::getName() const
359  {
360  return myName;
361  }
362 
363  void FunctionGraph::setName(const std::string& name)
364  {
365  myName = name;
366  }
367 
368  std::string FunctionGraph::getText() const
369  {
370  return _text;
371  }
372 
373  void FunctionGraph::setText(const std::string& text)
374  {
375  _text = text;
376  }
377 
379  {
380  return get(vertex_command, program)[current].getLineNumber();
381  }
382 
383  FunctionGraph* FunctionGraph::copy( std::map<const DataSourceBase*, DataSourceBase*>& replacementdss ) const
384  {
385  typedef boost::property_map<Graph, vertex_index_t>::const_type indexmap_t;
386  typedef boost::graph_traits<Graph>::vertex_descriptor vd_t;
387  typedef std::vector<vd_t> o2cvect_t;
388  typedef boost::iterator_property_map<o2cvect_t::iterator, indexmap_t, vd_t, vd_t&> o2cmap_t;
390 
391  // clear out unneccessary vertices ( we will copy new ones below )
392  remove_vertex( ret->startv, ret->program );
393  remove_vertex( ret->exitv, ret->program );
394 
395  indexmap_t indexmap = get( vertex_index, program );
396  // here we assume that the indexing of program is set properly...
397  o2cvect_t o2cvect( num_vertices( program ) );
398  o2cmap_t o2cmap( o2cvect.begin(), indexmap );
399 
400 // std::cerr << "Start copy of " <<std::endl;
401 // this->debugPrintout();
402 // std::cerr << "Empty ret: " <<std::endl;
403 // ret->debugPrintout();
404  // The replacementdss map contains mappings from this->datasource to copy->datasource,
405  // thus we can rebuild a vector<AttributeBase*>, which will be automagically be
406  // found by copy_graph.
407  // func args are never instantiated, so that we can keep making copies.
408  for (unsigned int i=0; i < args.size(); ++i)
409  ret->addArgument( args[i]->copy( replacementdss, false ) );
410  if (retn)
411  ret->setResult( retn->copy(replacementdss, false) );
412 
413  boost::copy_graph( program, ret->program,
414  boost::vertex_copy( GraphVertexCopier( program, ret->program, replacementdss ) ).
415  edge_copy( GraphEdgeCopier( program, ret->program, replacementdss ) ).
416  orig_to_copy( o2cmap ) );
417 
418  ret->startv = o2cmap[startv];
419  ret->exitv = o2cmap[exitv];
420  ret->current = o2cmap[current];
421  ret->previous = o2cmap[previous];
422 
423  // so that ret itself can be copied again :
424  ret->finish();
425 
426 // std::cerr << "Resulted in :" <<std::endl;
427 // ret->debugPrintout();
428 
429  return ret;
430  }
431 
433  {
434  return new FunctionGraph(*this);
435  }
436 
438 #if 0
439  graph_traits<Graph>::vertex_iterator v,vend;
440  tie(v,vend) = vertices(program);
441  boost::property_map<Graph, vertex_command_t>::const_type
442  cmap = get(vertex_command, program);
443  boost::property_map<Graph, vertex_index_t>::const_type
444  imap = get(vertex_index, program);
445  std::cerr << "program " << getName() << std::endl;
446  std::cerr << " number of vertices: " << boost::num_vertices(program) << std::endl;
447  for ( ; v != vend; ++v )
448  {
449  int index = get( imap, *v );
450  ActionInterface* cmd = get( cmap, *v ).getCommand();
451  if ( cmd )
452  std::cerr << " " << index << " " << typeid( *cmd ).name() << std::endl;
453  else
454  std::cerr << " " << index << " (null)" << std::endl;
455  }
456 #endif
457  }
458 
460  for (std::vector<AttributeBase*>::iterator it = args.begin(); it != args.end(); ++it)
461  delete *it;
462  args.clear();
463  }
464 
465 }
466 
virtual bool stepDone() const
const Graph & getGraph() const
void setUnloadOnStop(bool unload_on_stop)
Sets the unloading policy on stop or error.
virtual AttributeBase * copy(std::map< const DataSourceBase *, DataSourceBase * > &replacements, bool instantiate)=0
Returns a copy of this AttributeBase.
Graph program
The graph containing this function.
virtual bool removeFunction(base::ExecutableInterface *f)
Remove a running function added with runFunction.
virtual AttributeBase * clone() const =0
Returns a clone of this AttributeBase.
std::vector< base::AttributeBase * > args
Ordered arguments (are also in the repository).
bool isLoaded()
Returns true if this object is loaded in an ExecutionEngine.
virtual FunctionGraph * clone() const
STL namespace.
virtual bool stop()
Stop the execution of this program.
void setResult(base::AttributeBase *r)
Will store the result in this attribute.
virtual const std::string & getName() const
Programs can be refered to by name.
base::AttributeBase * retn
virtual void loading()
Informs this object that it got loaded in an ExecutionEngine.
virtual void reset()
Identical to stop();.
void clearArguments()
Clear the arguments vector and release all base::AttributeBase resources.
virtual bool start()
Start the execution of this program.
basic_ostreams & endl(basic_ostreams &s)
Flush and newline.
Definition: rtstreams.cpp:110
std::string _text
Program text.
boost::shared_ptr< Service > shared_ptr
Definition: Service.hpp:101
std::string getText() const
Return the program text to which getLineNumber() refers.
std::string myName
The (unique) name of this program.
virtual int getLineNumber() const
Return the current &#39;line number&#39; of the program.
The program was running but is now paused.
Based on the software pattern &#39;command&#39;, this interface allows execution of action objects...
std::vector< base::AttributeBase * > getArguments() const
Return an ordered list of this funcion&#39;s arguments.
void setProgramService(ServicePtr myservice)
Set a service that manages this script.
virtual bool pause()
Pause or start-and-pause the execution of this program.
void finish()
To be called after a function is constructed.
ExecutionEngine * getEngine()
Returns the ExecutionEngine this object is loaded into or null otherwise.
void setName(const std::string &_name)
Set the name of this program.
virtual FunctionGraph * copy(std::map< const base::DataSourceBase *, base::DataSourceBase * > &replacementdss) const
Clone this Program.
virtual bool execute()
Execute as much actions until the program needs to wait on a condition to become true.
This program is currently not loaded in an ExecutionEngine.
FunctionGraph(const std::string &name, bool unload_on_stop)
Create a FunctionGraph with a given name.
void addArgument(base::AttributeBase *a)
Contains TaskContext, Activity, OperationCaller, Operation, Property, InputPort, OutputPort, Attribute.
Definition: Activity.cpp:51
virtual void unloading()
Informs this object that it got unloaded from an ExecutionEngine.
This class represents a function.
virtual bool step()
Execute a single action when paused.
void setText(const std::string &t)
Set the program text.