Robot Raconteur Companion C++ Library
Loading...
Searching...
No Matches
TaskGenerator.h
Go to the documentation of this file.
1
23
24#include <RobotRaconteur/Generator.h>
25
26#include "com__robotraconteur__action.h"
27
28#pragma once
29
30namespace RobotRaconteur
31{
32namespace Companion
33{
34namespace Util
35{
55template <typename StatusType>
56class AsyncTaskGenerator : public virtual RobotRaconteur::Generator<RR_INTRUSIVE_PTR<StatusType>, void>,
57 public RR_ENABLE_SHARED_FROM_THIS<AsyncTaskGenerator<StatusType> >
58{
59 public:
70 AsyncTaskGenerator(const RR_SHARED_PTR<RobotRaconteur::RobotRaconteurNode>& node, int32_t next_timeout,
71 int32_t watchdog_timeout)
72 : node(node), next_timeout(next_timeout), watchdog_timeout(watchdog_timeout)
73 {
74 started = false;
75 closed = false;
76 aborted = false;
77 completed = false;
78 task_completed = false;
79 send_update = false;
80 if (next_timeout < 0)
81 {
82 throw RobotRaconteur::InvalidArgumentException("next_timeout must be >= 0");
83 }
84
85 if (watchdog_timeout > 0 && watchdog_timeout < next_timeout)
86 {
87 throw RobotRaconteur::InvalidArgumentException("watchdog_timeout must be >= next_timeout");
88 }
89 }
90
91 RR_OVIRTUAL void AsyncNext(
92 boost::function<void(const RR_INTRUSIVE_PTR<StatusType>&, const RobotRaconteur::RobotRaconteurExceptionPtr&)>
93 handler,
94 int32_t timeout = RR_TIMEOUT_INFINITE) RR_OVERRIDE
95 {
96 RR_UNUSED(timeout);
97 boost::mutex::scoped_lock lock(this_lock);
98 if (watchdog_timer)
99 {
100 try
101 {
102 watchdog_timer->Stop();
103 }
104 catch (std::exception&)
105 {}
106 watchdog_timer.reset();
107 }
108 if (aborted)
109 {
110 throw RobotRaconteur::OperationAbortedException("Operation was aborted");
111 }
112 if ((closed && !started) || completed)
113 {
114 throw RobotRaconteur::StopIterationException("");
115 }
116
117 if (!started)
118 {
119 StartTask();
120 started = true;
121 RR_INTRUSIVE_PTR<StatusType> ret(new StatusType());
122 ret->action_status = com::robotraconteur::action::ActionStatusCode::running;
123 FillStatus(ret);
124 lock.unlock();
125 handler(ret, nullptr);
126 return;
127 }
128
129 if (next_handler)
130 {
131 throw RobotRaconteur::InvalidOperationException("Next call already in progress");
132 }
133
134 if (task_completed)
135 {
136 complete_gen(handler);
137 return;
138 }
139
140 if (send_update)
141 {
142 send_update = false;
143 RR_INTRUSIVE_PTR<StatusType> ret(new StatusType());
144 ret->action_status = com::robotraconteur::action::ActionStatusCode::running;
145 FillStatus(ret);
146 lock.unlock();
147 handler(ret, nullptr);
148 return;
149 }
150
151 next_handler = handler;
152
153 RR_WEAK_PTR<AsyncTaskGenerator<StatusType> > weak_this = this->shared_from_this();
154 next_timer = RobotRaconteur::RobotRaconteurNode::s()->CreateTimer(
155 boost::posix_time::milliseconds(next_timeout),
156 boost::bind(&AsyncTaskGenerator::next_timer_handler, weak_this, RR_BOOST_PLACEHOLDERS(_1)), true);
157 next_timer->Start();
158 if (watchdog_timeout > 0)
159 {
160 watchdog_timer = RobotRaconteur::RobotRaconteurNode::s()->CreateTimer(
161 boost::posix_time::milliseconds(watchdog_timeout),
162 boost::bind(&AsyncTaskGenerator::watchdog_timer_handler, weak_this, RR_BOOST_PLACEHOLDERS(_1)), true);
163 watchdog_timer->Start();
164 }
165 }
166
167 RR_OVIRTUAL void AsyncClose(boost::function<void(const RobotRaconteur::RobotRaconteurExceptionPtr& err)> handler,
168 int32_t timeout = RR_TIMEOUT_INFINITE) RR_OVERRIDE
169 {
170 RR_UNUSED(timeout);
171 boost::mutex::scoped_lock lock(this_lock);
172 if (closed || aborted)
173 {
174 lock.unlock();
175 handler(nullptr);
176 return;
177 }
178 closed = true;
179 if (started)
180 {
182 }
183 lock.unlock();
184 handler(nullptr);
185 }
186
187 RR_OVIRTUAL void AsyncAbort(boost::function<void(const RobotRaconteur::RobotRaconteurExceptionPtr& err)> handler,
188 int32_t timeout = RR_TIMEOUT_INFINITE) RR_OVERRIDE
189 {
190 RR_UNUSED(timeout);
191 boost::mutex::scoped_lock lock(this_lock);
192 if (closed || aborted)
193 {
194 lock.unlock();
195 handler(nullptr);
196 return;
197 }
198 aborted = true;
199 if (started)
200 {
202 }
203 lock.unlock();
204 handler(nullptr);
205 }
206
207 RR_OVIRTUAL RR_INTRUSIVE_PTR<StatusType> Next() RR_OVERRIDE
208 {
209 // This is never called
210 throw RobotRaconteur::NotImplementedException("Not implemented");
211 }
212 RR_OVIRTUAL void Close() RR_OVERRIDE
213 {
214 // This is never called
215 throw RobotRaconteur::NotImplementedException("Not implemented");
216 }
217 RR_OVIRTUAL void Abort() RR_OVERRIDE
218 {
219 // This is never called
220 throw RobotRaconteur::NotImplementedException("Not implemented");
221 }
222
223 protected:
232 virtual void SetResult(RR_INTRUSIVE_PTR<StatusType>& result)
233 {
234 boost::mutex::scoped_lock lock(this_lock);
235 if (task_completed)
236 return;
237 this->result = result;
238 do_result();
239 }
240
249 virtual void SetResultException(RR_SHARED_PTR<RobotRaconteur::RobotRaconteurException>& exp)
250 {
251 boost::mutex::scoped_lock lock(this_lock);
252 if (task_completed)
253 return;
254 this->exception_result = exp;
255 do_result();
256 }
257
258 void do_result()
259 {
260 task_completed = true;
261 auto h = next_handler;
262 next_handler.clear();
263 if (h)
264 {
265 try
266 {
267 next_timer->Stop();
268 }
269 catch (std::exception&)
270 {}
271
272 complete_gen(h);
273 return;
274 }
275 }
276
277 void complete_gen(
278 boost::function<void(const RR_INTRUSIVE_PTR<StatusType>&, const RobotRaconteur::RobotRaconteurExceptionPtr&)>
279 handler)
280 {
281 completed = true;
282
283 if (exception_result)
284 {
285 auto exp = exception_result;
286 exception_result.reset();
287 handler(nullptr, exp);
288 return;
289 }
290 RR_INTRUSIVE_PTR<StatusType> ret = result;
291 result.reset();
292 handler(ret, nullptr);
293 }
294
303 {
304 boost::mutex::scoped_lock lock(this_lock);
305 if (task_completed || aborted || closed)
306 return;
307 if (!next_handler)
308 {
309 send_update = true;
310 return;
311 }
312 try
313 {
314 next_timer->Stop();
315 }
316 catch (std::exception&)
317 {}
318 do_send_update();
319 }
320
328 virtual void StartTask() = 0;
329
333 virtual void CloseRequested() {}
334
338 virtual void AbortRequested() {}
339
348 virtual void FillStatus(RR_INTRUSIVE_PTR<StatusType>& status) {}
349
350 static void next_timer_handler(RR_WEAK_PTR<AsyncTaskGenerator> weak_this, const RobotRaconteur::TimerEvent& evt)
351 {
352 RR_UNUSED(evt);
353 RR_SHARED_PTR<AsyncTaskGenerator> shared_this = weak_this.lock();
354 if (!shared_this)
355 return;
356 boost::mutex::scoped_lock lock(shared_this->this_lock);
357 shared_this->do_send_update();
358 }
359
360 void do_send_update()
361 {
362 auto h = next_handler;
363 next_handler.clear();
364 if (h)
365 {
366 RR_INTRUSIVE_PTR<StatusType> ret(new StatusType());
367 ret->action_status = com::robotraconteur::action::ActionStatusCode::running;
368 FillStatus(ret);
369 h(ret, nullptr);
370 return;
371 }
372 }
373
374 static void watchdog_timer_handler(RR_WEAK_PTR<AsyncTaskGenerator> weak_this, const RobotRaconteur::TimerEvent& evt)
375 {
376 RR_SHARED_PTR<AsyncTaskGenerator> shared_this = weak_this.lock();
377 if (!shared_this)
378 return;
379 if (evt.stopped)
380 return;
381 boost::mutex::scoped_lock lock(shared_this->this_lock);
382 if (shared_this->task_completed)
383 return;
384 shared_this->aborted = true;
385 shared_this->AbortRequested();
386 }
387
388 RR_WEAK_PTR<RobotRaconteur::RobotRaconteurNode> node;
389 RR_SHARED_PTR<RobotRaconteur::Timer> next_timer;
390 RR_SHARED_PTR<RobotRaconteur::Timer> watchdog_timer;
391 bool started;
392 bool closed;
393 bool aborted;
394 bool completed;
395 bool task_completed;
396 bool send_update;
397 int32_t next_timeout;
398 int32_t watchdog_timeout;
399 boost::mutex this_lock;
400 boost::function<void(const RR_INTRUSIVE_PTR<StatusType>&, const RobotRaconteur::RobotRaconteurExceptionPtr&)>
401 next_handler;
402 RR_INTRUSIVE_PTR<StatusType> result;
403 RR_SHARED_PTR<RobotRaconteurException> exception_result;
404};
405
420template <typename StatusType>
421class SyncTaskGenerator : public AsyncTaskGenerator<StatusType>
422{
423 public:
431 SyncTaskGenerator(RR_SHARED_PTR<RobotRaconteur::RobotRaconteurNode> node, int32_t next_timeout,
432 int32_t watchdog_timeout)
433 : AsyncTaskGenerator<StatusType>(node, next_timeout, watchdog_timeout)
434 {}
435
436 protected:
444 virtual RR_INTRUSIVE_PTR<StatusType> RunTask() = 0;
445
446 void run_task_thread()
447 {
448 try
449 {
450 RR_INTRUSIVE_PTR<StatusType> ret = RunTask();
451 this->SetResult(ret);
452 }
453 catch (std::exception& exp)
454 {
455 RR_SHARED_PTR<RobotRaconteur::RobotRaconteurException> exp1 =
456 RobotRaconteur::RobotRaconteurExceptionUtil::ExceptionToSharedPtr(exp);
457 this->SetResultException(exp1);
458 }
459 }
460
461 RR_OVIRTUAL void StartTask() RR_OVERRIDE
462 {
463 RR_SHARED_PTR<SyncTaskGenerator> this_ = RR_DYNAMIC_POINTER_CAST<SyncTaskGenerator>(this->shared_from_this());
464 boost::thread(boost::bind(&SyncTaskGenerator::run_task_thread, this_));
465 }
466};
467} // namespace Util
468} // namespace Companion
469} // namespace RobotRaconteur
virtual void FillStatus(boost::intrusive_ptr< StatusType > &status)
This method is called to fill the next status report.
Definition TaskGenerator.h:348
virtual void CloseRequested()
This method is called when a close request is received.
Definition TaskGenerator.h:333
virtual void AbortRequested()
This method is called when an abort request is received.
Definition TaskGenerator.h:338
virtual void SetResult(boost::intrusive_ptr< StatusType > &result)
Set the result of the generator.
Definition TaskGenerator.h:232
virtual void SetResultException(boost::shared_ptr< RobotRaconteur::RobotRaconteurException > &exp)
Set the exception result of the generator.
Definition TaskGenerator.h:249
AsyncTaskGenerator(const boost::shared_ptr< RobotRaconteur::RobotRaconteurNode > &node, int32_t next_timeout, int32_t watchdog_timeout)
Represents an asynchronous task generator.
Definition TaskGenerator.h:70
void SendUpdate()
Send an update to the caller.
Definition TaskGenerator.h:302
virtual boost::intrusive_ptr< StatusType > RunTask()=0
Pure virtual function to be implemented by the user.
RR_OVIRTUAL void StartTask() RR_OVERRIDE
Start the task.
Definition TaskGenerator.h:461
SyncTaskGenerator(boost::shared_ptr< RobotRaconteur::RobotRaconteurNode > node, int32_t next_timeout, int32_t watchdog_timeout)
Constructor for SyncTaskGenerator.
Definition TaskGenerator.h:431