Skip to content

Commit f2e70a9

Browse files
committed
Add the interface for pre-shutdown callback
Signed-off-by: Barry Xu <barry.xu@sony.com>
1 parent fb85190 commit f2e70a9

File tree

5 files changed

+265
-15
lines changed

5 files changed

+265
-15
lines changed

rclcpp/include/rclcpp/context.hpp

+66-4
Original file line numberDiff line numberDiff line change
@@ -48,17 +48,20 @@ class ContextAlreadyInitialized : public std::runtime_error
4848
/// Forward declare WeakContextsWrapper
4949
class WeakContextsWrapper;
5050

51-
class OnShutdownCallbackHandle
51+
class ShutdownCallbackHandle
5252
{
5353
friend class Context;
5454

5555
public:
56-
using OnShutdownCallbackType = std::function<void ()>;
56+
using ShutdownCallbackType = std::function<void ()>;
5757

5858
private:
59-
std::weak_ptr<OnShutdownCallbackType> callback;
59+
std::weak_ptr<ShutdownCallbackType> callback;
6060
};
6161

62+
using OnShutdownCallbackHandle = ShutdownCallbackHandle;
63+
using PreShutdownCallbackHandle = ShutdownCallbackHandle;
64+
6265
/// Context which encapsulates shared state between nodes and other similar entities.
6366
/**
6467
* A context also represents the lifecycle between init and shutdown of rclcpp.
@@ -189,7 +192,7 @@ class Context : public std::enable_shared_from_this<Context>
189192
bool
190193
shutdown(const std::string & reason);
191194

192-
using OnShutdownCallback = OnShutdownCallbackHandle::OnShutdownCallbackType;
195+
using OnShutdownCallback = OnShutdownCallbackHandle::ShutdownCallbackType;
193196

194197
/// Add a on_shutdown callback to be called when shutdown is called for this context.
195198
/**
@@ -249,6 +252,33 @@ class Context : public std::enable_shared_from_this<Context>
249252
bool
250253
remove_on_shutdown_callback(const OnShutdownCallbackHandle & callback_handle);
251254

255+
using PreShutdownCallback = PreShutdownCallbackHandle::ShutdownCallbackType;
256+
257+
/// Add a pre_shutdown callback to be called before shutdown is called for this context.
258+
/**
259+
* These callbacks will be called in the order they are added.
260+
*
261+
* When shutdown occurs due to the signal handler, these callbacks are run
262+
* asynchronously in the dedicated singal handling thread.
263+
*
264+
* \param[in] callback the pre_shutdown callback to be registered
265+
* \return the created callback handle
266+
*/
267+
RCLCPP_PUBLIC
268+
virtual
269+
PreShutdownCallbackHandle
270+
add_pre_shutdown_callback(PreShutdownCallback callback);
271+
272+
/// Remove an registered pre_shutdown callback.
273+
/**
274+
* \param[in] callback_handle the pre_shutdown callback handle to be removed.
275+
* \return true if the callback is found and removed, otherwise false.
276+
*/
277+
RCLCPP_PUBLIC
278+
virtual
279+
bool
280+
remove_pre_shutdown_callback(const PreShutdownCallbackHandle & callback_handle);
281+
252282
/// Return the shutdown callbacks.
253283
/**
254284
* Returned callbacks are a copy of the registered callbacks.
@@ -257,6 +287,14 @@ class Context : public std::enable_shared_from_this<Context>
257287
std::vector<OnShutdownCallback>
258288
get_on_shutdown_callbacks() const;
259289

290+
/// Return the pre-shutdown callbacks.
291+
/**
292+
* Returned callbacks are a copy of the registered callbacks.
293+
*/
294+
RCLCPP_PUBLIC
295+
std::vector<PreShutdownCallback>
296+
get_pre_shutdown_callbacks() const;
297+
260298
/// Return the internal rcl context.
261299
RCLCPP_PUBLIC
262300
std::shared_ptr<rcl_context_t>
@@ -338,13 +376,37 @@ class Context : public std::enable_shared_from_this<Context>
338376
std::unordered_set<std::shared_ptr<OnShutdownCallback>> on_shutdown_callbacks_;
339377
mutable std::mutex on_shutdown_callbacks_mutex_;
340378

379+
std::unordered_set<std::shared_ptr<PreShutdownCallback>> pre_shutdown_callbacks_;
380+
mutable std::mutex pre_shutdown_callbacks_mutex_;
381+
341382
/// Condition variable for timed sleep (see sleep_for).
342383
std::condition_variable interrupt_condition_variable_;
343384
/// Mutex for protecting the global condition variable.
344385
std::mutex interrupt_mutex_;
345386

346387
/// Keep shared ownership of global vector of weak contexts
347388
std::shared_ptr<WeakContextsWrapper> weak_contexts_;
389+
390+
enum class ShutdownType
391+
{
392+
pre_shutdown,
393+
on_shutdown
394+
};
395+
396+
using ShutdownCallback = ShutdownCallbackHandle::ShutdownCallbackType;
397+
398+
ShutdownCallbackHandle
399+
add_shutdown_callback(
400+
ShutdownType shutdown_type,
401+
ShutdownCallback callback);
402+
403+
bool
404+
remove_shutdown_callback(
405+
ShutdownType shutdown_type,
406+
const ShutdownCallbackHandle & callback_handle);
407+
408+
std::vector<rclcpp::Context::ShutdownCallback>
409+
get_shutdown_callback(ShutdownType shutdown_type) const;
348410
};
349411

350412
/// Return a copy of the list of context shared pointers.

rclcpp/include/rclcpp/utilities.hpp

+37
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,43 @@ RCLCPP_PUBLIC
182182
void
183183
on_shutdown(std::function<void()> callback, rclcpp::Context::SharedPtr context = nullptr);
184184

185+
/// Register a function to be called before shutdown is called on the context.
186+
/**
187+
* If nullptr is given for the context, then the global context is used, i.e.
188+
* the context initialized by rclcpp::init().
189+
*
190+
* These callbacks are called before the associated Context is shutdown.
191+
* When shutdown by the SIGINT handler, these callbacks are called asynchronously
192+
* from the dedicated signal handling thread, at some point after the SIGINT
193+
* signal is received.
194+
*
195+
* \sa rclcpp::Context::add_pre_shutdown_callback()
196+
* \param[in] callback to be called before the given context is shutdown
197+
* \param[in] context with which to associate the context
198+
* \return the created callback handle
199+
*/
200+
RCLCPP_PUBLIC
201+
PreShutdownCallbackHandle
202+
add_pre_shutdown_callback(
203+
rclcpp::PreShutdownCallbackHandle::ShutdownCallbackType callback,
204+
rclcpp::Context::SharedPtr context = nullptr);
205+
206+
/// Remove an registered pre_shutdown callback.
207+
/**
208+
* If nullptr is given for the context, then the global context is used, i.e.
209+
* the context initialized by rclcpp::init().
210+
*
211+
* \sa rclcpp::Context::remove_pre_shutdown_callback()
212+
* \param[in] callback_handle the pre_shutdown callback handle to be removed.
213+
* \param[in] context with which to associate the context
214+
* \return true if the callback is found and removed, otherwise false.
215+
*/
216+
RCLCPP_PUBLIC
217+
bool
218+
remove_pre_shutdown_callback(
219+
const rclcpp::PreShutdownCallbackHandle & callback_handle,
220+
rclcpp::Context::SharedPtr context = nullptr);
221+
185222
/// Use the global condition variable to block for the specified amount of time.
186223
/**
187224
* This function can be interrupted early if the associated context becomes

rclcpp/src/rclcpp/context.cpp

+103-11
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#include <sstream>
2020
#include <string>
2121
#include <vector>
22+
#include <unordered_set>
2223
#include <utility>
2324

2425
#include "rcl/init.h"
@@ -307,6 +308,15 @@ Context::shutdown(const std::string & reason)
307308
// if it is not valid, then it cannot be shutdown
308309
return false;
309310
}
311+
312+
// call each pre-shutdown callback
313+
{
314+
std::lock_guard<std::mutex> lock{pre_shutdown_callbacks_mutex_};
315+
for (const auto & callback : pre_shutdown_callbacks_) {
316+
(*callback)();
317+
}
318+
}
319+
310320
// rcl shutdown
311321
rcl_ret_t ret = rcl_shutdown(rcl_context_.get());
312322
if (RCL_RET_OK != ret) {
@@ -355,36 +365,118 @@ Context::on_shutdown(OnShutdownCallback callback)
355365
rclcpp::OnShutdownCallbackHandle
356366
Context::add_on_shutdown_callback(OnShutdownCallback callback)
357367
{
358-
auto callback_shared_ptr = std::make_shared<OnShutdownCallback>(callback);
359-
{
360-
std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
361-
on_shutdown_callbacks_.emplace(callback_shared_ptr);
368+
return add_shutdown_callback(ShutdownType::on_shutdown, callback);
369+
}
370+
371+
bool
372+
Context::remove_on_shutdown_callback(const OnShutdownCallbackHandle & callback_handle)
373+
{
374+
return remove_shutdown_callback(ShutdownType::on_shutdown, callback_handle);
375+
}
376+
377+
rclcpp::PreShutdownCallbackHandle
378+
Context::add_pre_shutdown_callback(PreShutdownCallback callback)
379+
{
380+
return add_shutdown_callback(ShutdownType::pre_shutdown, callback);
381+
}
382+
383+
bool
384+
Context::remove_pre_shutdown_callback(
385+
const PreShutdownCallbackHandle & callback_handle)
386+
{
387+
return remove_shutdown_callback(ShutdownType::pre_shutdown, callback_handle);
388+
}
389+
390+
rclcpp::ShutdownCallbackHandle
391+
Context::add_shutdown_callback(
392+
ShutdownType shutdown_type,
393+
ShutdownCallback callback)
394+
{
395+
auto callback_shared_ptr =
396+
std::make_shared<ShutdownCallbackHandle::ShutdownCallbackType>(callback);
397+
398+
switch (shutdown_type) {
399+
case ShutdownType::pre_shutdown:
400+
{
401+
std::lock_guard<std::mutex> lock(pre_shutdown_callbacks_mutex_);
402+
pre_shutdown_callbacks_.emplace(callback_shared_ptr);
403+
}
404+
break;
405+
case ShutdownType::on_shutdown:
406+
{
407+
std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
408+
on_shutdown_callbacks_.emplace(callback_shared_ptr);
409+
}
410+
break;
362411
}
363412

364-
OnShutdownCallbackHandle callback_handle;
413+
ShutdownCallbackHandle callback_handle;
365414
callback_handle.callback = callback_shared_ptr;
366415
return callback_handle;
367416
}
368417

369418
bool
370-
Context::remove_on_shutdown_callback(const OnShutdownCallbackHandle & callback_handle)
419+
Context::remove_shutdown_callback(
420+
ShutdownType shutdown_type,
421+
const ShutdownCallbackHandle & callback_handle)
371422
{
372-
std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
423+
std::mutex * mutex_ptr;
424+
std::unordered_set<
425+
std::shared_ptr<ShutdownCallbackHandle::ShutdownCallbackType>> * callback_list_ptr;
426+
427+
switch (shutdown_type) {
428+
case ShutdownType::pre_shutdown:
429+
mutex_ptr = &pre_shutdown_callbacks_mutex_;
430+
callback_list_ptr = &pre_shutdown_callbacks_;
431+
break;
432+
case ShutdownType::on_shutdown:
433+
mutex_ptr = &on_shutdown_callbacks_mutex_;
434+
callback_list_ptr = &on_shutdown_callbacks_;
435+
break;
436+
}
437+
438+
std::lock_guard<std::mutex> lock(*mutex_ptr);
373439
auto callback_shared_ptr = callback_handle.callback.lock();
374440
if (callback_shared_ptr == nullptr) {
375441
return false;
376442
}
377-
return on_shutdown_callbacks_.erase(callback_shared_ptr) == 1;
443+
return callback_list_ptr->erase(callback_shared_ptr) == 1;
378444
}
379445

380446
std::vector<rclcpp::Context::OnShutdownCallback>
381447
Context::get_on_shutdown_callbacks() const
382448
{
383-
std::vector<OnShutdownCallback> callbacks;
449+
return get_shutdown_callback(ShutdownType::on_shutdown);
450+
}
451+
452+
std::vector<rclcpp::Context::PreShutdownCallback>
453+
Context::get_pre_shutdown_callbacks() const
454+
{
455+
return get_shutdown_callback(ShutdownType::pre_shutdown);
456+
}
384457

458+
std::vector<rclcpp::Context::ShutdownCallback>
459+
Context::get_shutdown_callback(ShutdownType shutdown_type) const
460+
{
461+
std::mutex * mutex_ptr;
462+
const std::unordered_set<
463+
std::shared_ptr<ShutdownCallbackHandle::ShutdownCallbackType>> * callback_list_ptr;
464+
465+
switch (shutdown_type) {
466+
case ShutdownType::pre_shutdown:
467+
mutex_ptr = &pre_shutdown_callbacks_mutex_;
468+
callback_list_ptr = &pre_shutdown_callbacks_;
469+
break;
470+
case ShutdownType::on_shutdown:
471+
mutex_ptr = &on_shutdown_callbacks_mutex_;
472+
callback_list_ptr = &on_shutdown_callbacks_;
473+
break;
474+
}
475+
476+
std::vector<rclcpp::Context::ShutdownCallback> callbacks;
385477
{
386-
std::lock_guard<std::mutex> lock(on_shutdown_callbacks_mutex_);
387-
for (auto & iter : on_shutdown_callbacks_) {
478+
std::lock_guard<std::mutex> lock(*mutex_ptr);
479+
for (auto & iter : *callback_list_ptr) {
388480
callbacks.emplace_back(*iter);
389481
}
390482
}

rclcpp/src/rclcpp/utilities.cpp

+26
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,32 @@ on_shutdown(std::function<void()> callback, Context::SharedPtr context)
181181
context->on_shutdown(callback);
182182
}
183183

184+
rclcpp::PreShutdownCallbackHandle
185+
add_pre_shutdown_callback(
186+
rclcpp::PreShutdownCallbackHandle::ShutdownCallbackType callback,
187+
rclcpp::Context::SharedPtr context)
188+
{
189+
using rclcpp::contexts::get_global_default_context;
190+
if (nullptr == context) {
191+
context = get_global_default_context();
192+
}
193+
194+
return context->add_pre_shutdown_callback(callback);
195+
}
196+
197+
bool
198+
remove_pre_shutdown_callback(
199+
const rclcpp::PreShutdownCallbackHandle & callback_handle,
200+
rclcpp::Context::SharedPtr context)
201+
{
202+
using rclcpp::contexts::get_global_default_context;
203+
if (nullptr == context) {
204+
context = get_global_default_context();
205+
}
206+
207+
return context->remove_pre_shutdown_callback(callback_handle);
208+
}
209+
184210
bool
185211
sleep_for(const std::chrono::nanoseconds & nanoseconds, Context::SharedPtr context)
186212
{

0 commit comments

Comments
 (0)