Orocos Real-Time Toolkit  2.9.0
CallFunction.hpp
Go to the documentation of this file.
1 /***************************************************************************
2  tag: The SourceWorks Tue Sep 7 00:55:18 CEST 2010 CallFunction.hpp
3 
4  CallFunction.hpp - description
5  -------------------
6  begin : Tue September 07 2010
7  copyright : (C) 2010 The SourceWorks
8  email : peter@thesourceworks.com
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 #ifndef ORO_CALL_FUNCTION_HPP
40 #define ORO_CALL_FUNCTION_HPP
41 
42 #include "../base/ActionInterface.hpp"
43 #include "../base/DisposableInterface.hpp"
44 #include "../internal/DataSources.hpp"
45 #include "ProgramInterface.hpp"
46 #include "../internal/DataSource.hpp"
47 #include "../ExecutionEngine.hpp"
48 #include "../Logger.hpp"
49 #include <boost/shared_ptr.hpp>
50 #include <boost/bind.hpp>
51 
52 namespace RTT
53 { namespace scripting {
54  using namespace detail;
55 
63  {
64  base::ActionInterface* minit;
65  ExecutionEngine* mrunner;
66  ExecutionEngine* mcaller;
67  boost::shared_ptr<ProgramInterface> _foo;
68  bool maccept;
69 
75  bool checkIfDoneOrYielded() {
76  return (!maccept || _foo->inError() || _foo->isStopped());
77  }
78 
84  bool checkIfDone() {
85  if ( _foo->inError() ) {
86  throw false;
87  } else if ( _foo->isStopped() ) {
88  return true;
89  } else {
90  return false;
91  }
92  }
93 
94  public:
103  boost::shared_ptr<ProgramInterface> foo,
104  ExecutionEngine* p, ExecutionEngine* caller
105  )
106  : minit(init_com),
107  mrunner(p), mcaller(caller),
108  _foo( foo ), maccept(false)
109  {
110  }
111 
113  this->reset();
114  delete minit;
115  }
116 
131  virtual bool execute() {
132  // prepare execution
133  if (!minit->execute()) return false;
134  _foo->loaded(mrunner);
135  // we ignore the ret value of start(). It could have been auto-started during loading() of the function.
136  if ( _foo->needsStart() )
137  _foo->start();
138 
139  if ( mrunner->isSelf() ) { // The calling thread is the same as the executor (synchronous function call).
140 
141  // 1. Inline the function (execute it immediately). Other than the
142  // following step 2, this does not give other operations the
143  // chance to execute.
144  //
145  // @sa analogous to OperationCallerInterface::isSend()
146  //
147  maccept = true;
148  this->executeAndDispose();
149  if ( checkIfDone() ) return true;
150  log(Warning) << "Execution of function '" << _foo->getName() << " did not finish in one cycle "
151  "and paused in line " << _foo->getLineNumber() << ", e.g. because of a yield statement." << nlog()
152  << "As it was called from the executing thread, execution will continue immediately to avoid a dead-lock." << nlog()
153  << "This behavior might be unexpected and can cause busy-wait loops." << endlog();
154 
155  // 2. While not done, enqueue as a message callback (for the callback step)
156  // ==> mrunner will call executeAndDispose() (see below)
157  //
158  // If the caller thread is the same as the executor and the
159  // funtion yields, loop and enqueue it again. So yielding in
160  // a function called from the same thread only gives other
161  // enqueued messages (operations) a chance to execute, but
162  // afterwards the function continues within the same update
163  // step and without a call to updateHook() in between.
164  //
165  do {
166  maccept = mrunner->process( this );
167  if ( !maccept ) return false;
168 
169  // block for the result: foo stopped or in error or yielded
170  mrunner->waitForMessages(boost::bind(&CallFunction::checkIfDoneOrYielded, this) );
171  } while( !checkIfDone() );
172 
173  return true;
174 
175  } else { // The caller thread is different from the executor (asynchronous function call).
176 
177  // 1. Enqueue as a message callback (for the callback step)
178  // ==> mrunner will call executeAndDispose() (see below)
179  //
180  maccept = mrunner->process( this );
181  if ( !maccept ) return false;
182 
183  // block for the result: foo stopped or in error or yielded
184  mrunner->waitForMessages(boost::bind(&CallFunction::checkIfDoneOrYielded, this) );
185  if ( checkIfDone() ) return true;
186 
187  // 2. If not yet done, enqueue as a function and wait for the next update step
188  // ==> mrunner will run _foo until it finishs
189  //
190  // Note: There is no guarantee that the function will not already execute again in the same cycle,
191  // once as a message and once as function. Not really a problem...
192  //
193  maccept = mrunner->runFunction( _foo.get() );
194  if ( !maccept ) return false;
195 
196  // block for the result: foo stopped or in error
197  mrunner->waitForMessages(boost::bind(&CallFunction::checkIfDone, this) );
198  if ( checkIfDone() ) return true;
199 
200  return false;
201  }
202  }
203 
214  virtual void executeAndDispose() {
215  if ( _foo->execute() == false ) {
216  _foo->unloaded();
217  } else {
218  // need to execute again
219  maccept = false;
220  }
221  // ExecutionEngine will eventually wake up the caller waiting in mrunner->waitForMessages().
222  }
223 
224  // we do not want to be disposed
225  virtual void dispose() {}
226 
227  virtual void reset() {
228  maccept = false;
229  }
230 
231  virtual bool valid() const {
232  return maccept;
233  }
234 
235  virtual void readArguments() {
236  // is called before runFunction is executed.
237  minit->readArguments();
238  }
239 
241  {
242  return new CallFunction( minit->clone(), _foo, mrunner, mcaller);
243  }
244 
245  base::ActionInterface* copy( std::map<const base::DataSourceBase*, base::DataSourceBase*>& alreadyCloned ) const
246  {
247  boost::shared_ptr<ProgramInterface> fcpy( _foo->copy(alreadyCloned) );
248  return new CallFunction( minit->copy(alreadyCloned), fcpy , mrunner, mcaller );
249  }
250 
251  };
252 
253 }}
254 
255 #endif
base::ActionInterface * clone() const
The Clone Software Pattern.
virtual void dispose()
Just free this object without executing it.
bool isSelf() const
Check if the thread that processes messages send to this engine is the same as the calling thread...
virtual bool execute()
Enqueue the function in the target engine (mrunner) and wait until it is finished or in error state...
void waitForMessages(const boost::function< bool(void)> &pred)
Call this if you wish to block on a message arriving in the Execution Engine.
#define RTT_SCRIPTING_API
An execution engine serialises (executes one after the other) the execution of all commands...
virtual void executeAndDispose()
Message callback that executes the function until it finishes or yields.
CallFunction(base::ActionInterface *init_com, boost::shared_ptr< ProgramInterface > foo, ExecutionEngine *p, ExecutionEngine *caller)
Create a Command to send a function to a ExecutionEngine.
virtual bool valid() const
Inspect if this action was executed and valid.
virtual void readArguments()
This is invoked some time before execute() at a time when the action may read its function arguments...
Based on the software pattern &#39;command&#39;, this interface allows execution of action objects...
base::ActionInterface * copy(std::map< const base::DataSourceBase *, base::DataSourceBase * > &alreadyCloned) const
When copying an Orocos program, we want identical internal::DataSource&#39;s to be mapped to identical Da...
An object that is executable and is freed after execution.
virtual void reset()
Reset this action.
Contains TaskContext, Activity, OperationCaller, Operation, Property, InputPort, OutputPort, Attribute.
Definition: Activity.cpp:52
An action which calls a FunctionFraph for execution in a ExecutionEngine.
virtual bool process(base::DisposableInterface *c)
Queue and execute (process) a given message.
virtual bool runFunction(base::ExecutableInterface *f)
Run a given function in step() or loop().