Skip to content

Commit c2b19ed

Browse files
committed
Merge branch 'jazzy-rmw-wrapper' into emerson/jazzy-latest
2 parents 23fe893 + 3574c0f commit c2b19ed

File tree

4 files changed

+164
-12
lines changed

4 files changed

+164
-12
lines changed

.github/workflows/build.yml

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
---
2+
name: Build and test
3+
"on":
4+
pull_request:
5+
push:
6+
branches:
7+
- jazzy-rmw-wrapper
8+
9+
jobs:
10+
build_and_test:
11+
runs-on: ubuntu-latest
12+
strategy:
13+
fail-fast: false
14+
matrix:
15+
include:
16+
- ros: jazzy
17+
ubuntu: noble
18+
name: ROS 2 ${{ matrix.ros }}
19+
container:
20+
image: ghcr.io/ros-tooling/setup-ros-docker/setup-ros-docker-ubuntu-${{ matrix.ubuntu }}:latest
21+
env:
22+
ROS_DISTRO: ${{ matrix.ros }}
23+
RMW_IMPLEMENTATION: rmw_cyclonedds_cpp
24+
RMW_IMPLEMENTATION_WRAPPER: rmw_stats_shim
25+
DISABLE_GROUPS_WORKAROUND: 1
26+
steps:
27+
- uses: actions/checkout@v4
28+
- shell: bash
29+
run: |
30+
apt-get update && apt-get install -y -q --no-install-recommends ros-${{ matrix.ros }}-rmw-cyclonedds-cpp
31+
- uses: ros-tooling/[email protected]
32+
with:
33+
target-ros2-distro: ${{ matrix.ros }}
34+
package-name: rmw_implementation test_rmw_implementation
35+
- uses: actions/upload-artifact@v4
36+
with:
37+
name: colcon-logs-${{ matrix.ros }}
38+
path: ros_ws/log

README.md

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
# RMW Implementation Fork for RMW Wrapper
2+
3+
This repository is a fork of https://github.com/ros2/rmw_implementation , maintained to provide an extra feature of a `RMW_IMPLEMENTATION_WRAPPER` shim library that can be loaded in addition to the `RMW_IMPLEMENTATION` (DDS, etc.).
4+
5+
This enables e.g. the https://github.com/ros-tooling/graph-monitor/tree/main/rmw_stats_shim to intercept calls to RMW and provide statistics about every node/subscription/publisher in the system.
6+
7+
8+
## Development
9+
10+
1. All live rosdistros are supported
11+
1. Branches are called `${ROS_DISTRO}-rmw-wrapper`
12+
2. As few modifications are added here as possible
13+
3. All changes here are backported to all live distros
14+
4. Upstream branches are periodically merged in
15+
16+
17+
### Updating to latest from upstream
18+
19+
Get sources set up
20+
21+
```bash
22+
git clone https://github.com/robograph-project/rmw_implementation
23+
cd rmw_implementation
24+
git remote add ros2 https://github.com/ros2/rmw_implementation
25+
```
26+
27+
Merge in latest and open PR
28+
29+
```bash
30+
git checkout ${ROS_DISTRO}-rmw-wrapper
31+
git checkout -b ${ROS_DISTRO}-merge-latest
32+
git fetch ros2
33+
git merge ros2/${ROS_DISTRO}
34+
# push that branch and open PR
35+
```
36+
37+
Perform for every distro.

rmw_implementation/package.xml

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -21,15 +21,12 @@
2121
<depend>rcpputils</depend>
2222
<depend>rcutils</depend>
2323
<build_depend>rmw</build_depend>
24-
<!--
25-
Bloom does not support group_depend so entries below duplicate the group rmw_implementation_packages.
26-
This ensures that binary packages have support for all of these rmw impl. enabled.
27-
-->
28-
<build_depend>rmw_connextdds</build_depend>
29-
<build_depend>rmw_cyclonedds_cpp</build_depend>
30-
<build_depend>rmw_fastrtps_cpp</build_depend>
31-
<build_depend>rmw_fastrtps_dynamic_cpp</build_depend>
32-
<!-- end of group dependencies added for bloom -->
24+
25+
<!-- Explicit group resolution - see ros-infrastructure/catkin_pkg#369 -->
26+
<build_depend condition="$DISABLE_GROUPS_WORKAROUND != 1">rmw_connextdds</build_depend>
27+
<build_depend condition="$DISABLE_GROUPS_WORKAROUND != 1">rmw_cyclonedds_cpp</build_depend>
28+
<build_depend condition="$DISABLE_GROUPS_WORKAROUND != 1">rmw_fastrtps_cpp</build_depend>
29+
<build_depend condition="$DISABLE_GROUPS_WORKAROUND != 1">rmw_fastrtps_dynamic_cpp</build_depend>
3330

3431
<depend>rmw_implementation_cmake</depend>
3532

rmw_implementation/src/functions.cpp

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,6 +136,29 @@ get_library()
136136
return g_rmw_lib;
137137
}
138138

139+
std::shared_ptr<rcpputils::SharedLibrary>
140+
get_wrap_library()
141+
{
142+
static bool tried_load = false;
143+
static std::shared_ptr<rcpputils::SharedLibrary> wrap_lib = nullptr;
144+
if (!wrap_lib && !tried_load) {
145+
tried_load = true;
146+
std::string wrapper_var;
147+
try {
148+
wrapper_var = rcpputils::get_env_var("RMW_IMPLEMENTATION_WRAPPER");
149+
} catch (const std::exception & e) {
150+
RMW_SET_ERROR_MSG_WITH_FORMAT_STRING(
151+
"failed to fetch RMW_IMPLEMENTATION_WRAPPER "
152+
"from environment due to %s", e.what());
153+
return nullptr;
154+
}
155+
if (!wrapper_var.empty()) {
156+
wrap_lib = attempt_to_load_one_rmw(wrapper_var);
157+
}
158+
}
159+
return wrap_lib;
160+
}
161+
139162
void *
140163
lookup_symbol(std::shared_ptr<rcpputils::SharedLibrary> lib, const std::string & symbol_name)
141164
{
@@ -175,6 +198,25 @@ get_symbol(const char * symbol_name)
175198
}
176199
}
177200

201+
void * get_wrap_symbol(const char * symbol_name)
202+
{
203+
try {
204+
auto lib = get_wrap_library();
205+
if (!lib) {
206+
return nullptr;
207+
}
208+
if (!lib->has_symbol(symbol_name)) {
209+
return nullptr;
210+
}
211+
return lib->get_symbol(symbol_name);
212+
} catch (const std::exception & e) {
213+
RMW_SET_ERROR_MSG_WITH_FORMAT_STRING(
214+
"failed to get wrapper symbol '%s' due to %s",
215+
symbol_name, e.what());
216+
return nullptr;
217+
}
218+
}
219+
178220
#ifdef __cplusplus
179221
extern "C"
180222
{
@@ -202,6 +244,27 @@ extern "C"
202244
#define ARGS_6(t6, ...) t6 v6, EXPAND(ARGS_5(__VA_ARGS__))
203245
#define ARGS_7(t7, ...) t7 v7, EXPAND(ARGS_6(__VA_ARGS__))
204246

247+
// Macros for "wrapped function" args, allow us to prepend one extra argument more than _NR value
248+
// "tX" params are "type" for the type declaration of the argument
249+
// "vX" params are "variable" for the variable name declaration
250+
#define WARGS_0(t0, tvoid) t0 v0
251+
#define WARGS_1(t1, t0) t1 v1, t0 v0
252+
#define WARGS_2(t2, ...) t2 v2, EXPAND(WARGS_1(__VA_ARGS__))
253+
#define WARGS_3(t3, ...) t3 v3, EXPAND(WARGS_2(__VA_ARGS__))
254+
#define WARGS_4(t4, ...) t4 v4, EXPAND(WARGS_3(__VA_ARGS__))
255+
#define WARGS_5(t5, ...) t5 v5, EXPAND(WARGS_4(__VA_ARGS__))
256+
#define WARGS_6(t6, ...) t6 v6, EXPAND(WARGS_5(__VA_ARGS__))
257+
#define WARGS_7(t7, ...) t7 v7, EXPAND(WARGS_6(__VA_ARGS__))
258+
259+
#define WARG_VALUES_0(impl, ...) impl
260+
#define WARG_VALUES_1(impl, ...) impl, EXPAND(ARG_VALUES_1(__VA_ARGS__))
261+
#define WARG_VALUES_2(impl, ...) impl, EXPAND(ARG_VALUES_2(__VA_ARGS__))
262+
#define WARG_VALUES_3(impl, ...) impl, EXPAND(ARG_VALUES_3(__VA_ARGS__))
263+
#define WARG_VALUES_4(impl, ...) impl, EXPAND(ARG_VALUES_4(__VA_ARGS__))
264+
#define WARG_VALUES_5(impl, ...) impl, EXPAND(ARG_VALUES_5(__VA_ARGS__))
265+
#define WARG_VALUES_6(impl, ...) impl, EXPAND(ARG_VALUES_6(__VA_ARGS__))
266+
#define WARG_VALUES_7(impl, ...) impl, EXPAND(ARG_VALUES_7(__VA_ARGS__))
267+
205268
#define CALL_SYMBOL(symbol_name, ReturnType, error_value, ArgTypes, arg_values) \
206269
if (!symbol_ ## symbol_name) { \
207270
/* only necessary for functions called before rmw_init */ \
@@ -218,8 +281,14 @@ extern "C"
218281
// cppcheck-suppress preprocessorErrorDirective
219282
#define RMW_INTERFACE_FN(name, ReturnType, error_value, _NR, ...) \
220283
void * symbol_ ## name = nullptr; \
284+
void * symbol_wrap_ ## name = nullptr; \
221285
ReturnType name(EXPAND(ARGS_ ## _NR(__VA_ARGS__))) \
222286
{ \
287+
if (symbol_wrap_ ## name) { \
288+
typedef ReturnType (* WrapFunctionSignature)(EXPAND (WARGS_ ## _NR(void *, __VA_ARGS__))); \
289+
auto wrap_func = reinterpret_cast<WrapFunctionSignature>(symbol_wrap_ ## name); \
290+
return wrap_func(EXPAND(WARG_VALUES_ ## _NR(symbol_ ## name, __VA_ARGS__))); \
291+
} \
223292
CALL_SYMBOL( \
224293
name, ReturnType, error_value, ARG_TYPES(__VA_ARGS__), \
225294
EXPAND(ARG_VALUES_ ## _NR(__VA_ARGS__))); \
@@ -788,8 +857,9 @@ RMW_INTERFACE_FN(
788857
3, ARG_TYPES(
789858
const char *, rcutils_allocator_t *, rosidl_dynamic_typesupport_serialization_support_t *))
790859

791-
792-
#define GET_SYMBOL(x) symbol_ ## x = get_symbol(#x);
860+
#define GET_SYMBOL(x) \
861+
symbol_ ## x = get_symbol(#x); \
862+
symbol_wrap_ ## x = get_wrap_symbol(STRINGIFY(wrap_ ## x));
793863

794864
void prefetch_symbols(void)
795865
{
@@ -891,6 +961,7 @@ void prefetch_symbols(void)
891961
}
892962

893963
void * symbol_rmw_init = nullptr;
964+
void * symbol_wrap_rmw_init = nullptr;
894965

895966
rmw_ret_t
896967
rmw_init(const rmw_init_options_t * options, rmw_context_t * context)
@@ -902,10 +973,19 @@ rmw_init(const rmw_init_options_t * options, rmw_context_t * context)
902973
if (!symbol_rmw_init) {
903974
return RMW_RET_ERROR;
904975
}
976+
if (!symbol_wrap_rmw_init) {
977+
symbol_wrap_rmw_init = get_wrap_symbol("wrap_rmw_init");
978+
}
979+
rmw_ret_t ret = RMW_RET_OK;
980+
if (symbol_wrap_rmw_init) {
981+
typedef rmw_ret_t (* WrapperInitSignature)(void *, const rmw_init_options_t *, rmw_context_t *);
982+
auto wrap_init_func = reinterpret_cast<WrapperInitSignature>(symbol_wrap_rmw_init);
983+
ret = wrap_init_func(get_library().get(), options, context);
984+
}
905985

906986
typedef rmw_ret_t (* FunctionSignature)(const rmw_init_options_t *, rmw_context_t *);
907987
FunctionSignature func = reinterpret_cast<FunctionSignature>(symbol_rmw_init);
908-
return func(options, context);
988+
return ret != RMW_RET_OK ? ret : func(options, context);
909989
}
910990

911991
#ifdef __cplusplus

0 commit comments

Comments
 (0)