CARLA
Loading...
Searching...
No Matches
FastDDSSharedParticipant.cpp
Go to the documentation of this file.
1// Copyright (c) 2026 Computer Vision Center (CVC) at the Universitat Autonoma de Barcelona (UAB).
2// This work is licensed under the terms of the MIT license.
3// For a copy, see <https://opensource.org/licenses/MIT>.
4
5#ifndef CARLA_ROS2_MIDDLEWARE_TESTING
6
9#include "carla/Logging.h"
10
11#include <fastdds/dds/domain/DomainParticipantFactory.hpp>
12#include <fastdds/dds/domain/qos/DomainParticipantQos.hpp>
13#include <fastdds/rtps/attributes/BuiltinTransports.hpp>
14
15#include <cstdlib>
16
17namespace carla {
18namespace ros2 {
19
20namespace efd = eprosima::fastdds::dds;
21
22// Static member definitions
24efd::DomainParticipant* FastDDSSharedParticipant::_participant { nullptr };
26std::unordered_map<std::string, uint32_t> FastDDSSharedParticipant::_type_refcounts;
27
28efd::DomainParticipant* FastDDSSharedParticipant::acquire() {
29 std::lock_guard<std::mutex> lock(_mutex);
30 if (_refcount == 0u) {
31 // Load XML profiles (FASTRTPS_DEFAULT_PROFILES_FILE) before reading the
32 // factory default QoS, so a profile marked is_default_profile is already
33 // folded in. load_profiles() is idempotent. The default MUST be read via
34 // get_default_participant_qos(): PARTICIPANT_QOS_DEFAULT is a static
35 // constant that XML profiles never modify -- copying it silently discards
36 // any user-provided profile (transports included).
37 auto* factory = efd::DomainParticipantFactory::get_instance();
38 factory->load_profiles();
39 efd::DomainParticipantQos pqos = factory->get_default_participant_qos();
40 // Fast-DDS's builtin default is UDPv4 + shared memory, and SHM is
41 // preferred for any peer that looks same-host. SHM delivery silently
42 // drops every sample across a container, uid, or Fast-DDS-version
43 // boundary (discovery is UDP multicast, so topics stay visible while no
44 // data arrives), and Fast-DDS never falls back to the reader's UDP
45 // locator when the SHM path is unreachable. Default to UDPv4-only so any
46 // subscriber works out of the box; setting the standard
47 // FASTDDS_BUILTIN_TRANSPORTS environment variable (e.g. to DEFAULT)
48 // skips this override and restores SHM for same-host, same-uid setups.
49 //
50 // The override must also yield to an XML default profile that configured
51 // its own transports (user transports, or builtin transports disabled):
52 // setup_transports() would silently REPLACE a whitelisted transport with
53 // an unrestricted UDPv4 one bound to every interface, so e.g. camera
54 // multicast then leaks out physical NICs -- a saturated WiFi multicast
55 // queue backpressures the writers and collapses the tick rate.
56 const bool xml_configured_transports =
57 !pqos.transport().user_transports.empty() ||
58 !pqos.transport().use_builtin_transports;
59 if (std::getenv("FASTDDS_BUILTIN_TRANSPORTS") == nullptr &&
60 !xml_configured_transports) {
61 pqos.setup_transports(eprosima::fastdds::rtps::BuiltinTransports::UDPv4);
62 }
63 // Use the effective domain id resolved by the abstraction layer
64 // (--ros-domain-id, else ROS_DOMAIN_ID, else the default domain 0).
65 const uint32_t domain_id =
66 static_cast<uint32_t>(MiddlewareConfig::GetEffectiveDomainId());
68 efd::DomainParticipantFactory::get_instance()->create_participant(domain_id, pqos);
69 if (_participant == nullptr) {
70 log_error("FastDDSSharedParticipant: Failed to create DomainParticipant");
71 return nullptr;
72 }
73 }
74 ++_refcount;
75 return _participant;
76}
77
79 std::lock_guard<std::mutex> lock(_mutex);
80 if (_refcount == 0u) {
81 log_error("FastDDSSharedParticipant::release() called with refcount already 0");
82 return;
83 }
84 --_refcount;
85 if (_refcount == 0u && _participant != nullptr) {
86 // delete_contained_entities() drains all Topics and TypeSupports still
87 // owned by the participant before the participant itself is deleted.
88 // Without this call, TypeSupport objects registered with register_type()
89 // but not explicitly unregistered could be leaked or double-freed.
90 _participant->delete_contained_entities();
91 efd::DomainParticipantFactory::get_instance()->delete_participant(_participant);
92 _participant = nullptr;
93 _type_refcounts.clear();
94 }
95}
96
97void FastDDSSharedParticipant::retain_type(const std::string& type_name) {
98 std::lock_guard<std::mutex> lock(_mutex);
99 ++_type_refcounts[type_name];
100}
101
102void FastDDSSharedParticipant::release_type(const std::string& type_name) {
103 std::lock_guard<std::mutex> lock(_mutex);
104 auto it = _type_refcounts.find(type_name);
105 if (it == _type_refcounts.end() || it->second == 0u) {
106 return;
107 }
108 --it->second;
109 if (it->second == 0u) {
110 // Unregister the type from the shared participant so the TypeSupport
111 // refcount inside FastDDS reaches zero cleanly.
112 if (_participant != nullptr) {
113 _participant->unregister_type(type_name);
114 }
115 _type_refcounts.erase(it);
116 }
117}
118
119} // namespace ros2
120} // namespace carla
121
122#endif // !CARLA_ROS2_MIDDLEWARE_TESTING
static void release_type(const std::string &type_name)
Release one use of type_name.
static eprosima::fastdds::dds::DomainParticipant * _participant
static eprosima::fastdds::dds::DomainParticipant * acquire()
Increment the refcount and return the shared DomainParticipant.
static void retain_type(const std::string &type_name)
Notify the singleton that one more endpoint is using type_name so that unregister_type() is deferred ...
static std::unordered_map< std::string, uint32_t > _type_refcounts
static void release()
Decrement the refcount.
This file contains definitions of common data structures used in traffic manager.
static void log_error(Args &&... args)
Definition Logging.h:110