diff --git a/src/context.cpp b/src/context.cpp index 69a364be74..926d84288d 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -30,6 +30,7 @@ #include #include #include +#include #include // We manage one participant and device-watcher per domain: @@ -168,7 +169,7 @@ namespace librealsense auto & domain = dds_domain_context_by_id[domain_id]; _dds_participant = domain.participant.instance(); if( ! _dds_participant->is_valid() ) - _dds_participant->init( domain_id, "librealsense" ); + _dds_participant->init( domain_id, rsutils::os::executable_name() ); _dds_watcher = domain.device_watcher.instance( _dds_participant ); } #endif //BUILD_WITH_DDS @@ -194,7 +195,8 @@ namespace librealsense if( rsutils::json::get< bool >( settings, "dds-discovery", true ) ) { realdds::dds_domain_id domain_id = rsutils::json::get< int >( settings, "dds-domain", 0 ); - std::string participant_name = rsutils::json::get< std::string >( settings, "dds-participant-name", "librealsense" ); + std::string participant_name + = rsutils::json::get< std::string >( settings, "dds-participant-name", rsutils::os::executable_name() ); auto & domain = dds_domain_context_by_id[domain_id]; _dds_participant = domain.participant.instance(); diff --git a/third-party/realdds/src/dds-participant.cpp b/third-party/realdds/src/dds-participant.cpp index 227b7a5cf0..2c81c97a2a 100644 --- a/third-party/realdds/src/dds-participant.cpp +++ b/third-party/realdds/src/dds-participant.cpp @@ -24,25 +24,38 @@ namespace { typedef int participant_id; participant_id last_participants_id = 0; + std::map< std::string, dds_guid_prefix > participant_by_name; + struct participant_info { std::string name; participant_id id; + dds_guid_prefix const prefix; - participant_info( char const * name_sz ) + participant_info( participant_info && ) = default; + participant_info( char const * name_sz, dds_guid_prefix const & prefix_ ) + : prefix( prefix_ ) { - { - std::lock_guard< std::mutex > lock( participants_mutex ); - id = ++last_participants_id; - } + id = ++last_participants_id; if( name_sz ) { name = name_sz; + bool needs_disambiguation = false; if( name_sz[0] == '/' && ! name_sz[1] ) { // This is likely a ROS participant, without an actual name. There will be one per ROS process at // least, so many could exist with the same name! - // To make it readable, we use the id, converting to '/' + needs_disambiguation = true; + } + else if( participant_by_name.find( name ) != participant_by_name.end() ) + { + // Sometimes multiple participants (e.g., of the same executable, or on different hosts) come up + // with the same name. We want to differentiate those, too... + needs_disambiguation = true; + } + if( needs_disambiguation ) + { + // To make it readable, we use the id, converting to '/.' // 010f58cfc2dd816201000000.1c1 -> /.1 // NOTE: // http://design.ros2.org/articles/topic_and_service_names.html#dds-topic-names @@ -53,8 +66,15 @@ namespace { name += '.'; name += std::to_string( id ); } + participant_by_name[name] = prefix; } } + ~participant_info() + { + auto it = participant_by_name.find( name ); + if( it != participant_by_name.end() && it->second == prefix ) + participant_by_name.erase( it ); + } }; std::map< dds_guid_prefix, participant_info > participants; @@ -77,13 +97,16 @@ struct dds_participant::listener_impl : public eprosima::fastdds::dds::DomainPar switch( info.status ) { case eprosima::fastrtps::rtps::ParticipantDiscoveryInfo::DISCOVERED_PARTICIPANT: { - participant_info pinfo( info.info.m_participantName ); - LOG_DEBUG( "+participant '" << pinfo.name << "' " << realdds::print( info.info.m_guid ) ); + std::string name; + std::string guid = realdds::print( info.info.m_guid ); // has to be outside the mutex { std::lock_guard< std::mutex > lock( participants_mutex ); - participants.emplace( info.info.m_guid.guidPrefix, pinfo ); + participant_info pinfo( info.info.m_participantName, info.info.m_guid.guidPrefix ); + name = pinfo.name; + LOG_DEBUG( "+participant '" << name << "' " << guid ); + participants.emplace( info.info.m_guid.guidPrefix, std::move( pinfo ) ); } - _owner.on_participant_added( info.info.m_guid, pinfo.name.c_str() ); + _owner.on_participant_added( info.info.m_guid, name.c_str() ); break; } case eprosima::fastrtps::rtps::ParticipantDiscoveryInfo::REMOVED_PARTICIPANT: diff --git a/third-party/rsutils/include/rsutils/os/executable-name.h b/third-party/rsutils/include/rsutils/os/executable-name.h new file mode 100644 index 0000000000..1a99816154 --- /dev/null +++ b/third-party/rsutils/include/rsutils/os/executable-name.h @@ -0,0 +1,20 @@ +// License: Apache 2.0. See LICENSE file in root directory. +// Copyright(c) 2023 Intel Corporation. All Rights Reserved. + +#pragma once + +#include + + +namespace rsutils { +namespace os { + + +// Returns the path to the executable currently running +std::string executable_path(); +// Returns the filename component of the executable currently running +std::string executable_name( bool with_extension = false ); + + +} +} diff --git a/third-party/rsutils/py/pyrsutils.cpp b/third-party/rsutils/py/pyrsutils.cpp index c209cc8f43..f5cbff3d77 100644 --- a/third-party/rsutils/py/pyrsutils.cpp +++ b/third-party/rsutils/py/pyrsutils.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #define NAME pyrsutils @@ -29,6 +30,8 @@ PYBIND11_MODULE(NAME, m) { py::arg( "logger" ) = LIBREALSENSE_ELPP_ID ); m.def( "split", &rsutils::string::split ); + m.def( "executable_path", &rsutils::os::executable_path ); + m.def( "executable_name", &rsutils::os::executable_name, py::arg( "with_extension" ) = false ); using rsutils::version; py::class_< version >( m, "version" ) diff --git a/third-party/rsutils/src/executable-name.cpp b/third-party/rsutils/src/executable-name.cpp new file mode 100644 index 0000000000..db0d456f56 --- /dev/null +++ b/third-party/rsutils/src/executable-name.cpp @@ -0,0 +1,68 @@ +// License: Apache 2.0. See LICENSE file in root directory. +// Copyright(c) 2023 Intel Corporation. All Rights Reserved. + +#include + +#if defined( PLATFORM_POSIX ) || defined( __linux__ ) +#include +#elif defined( _WIN32 ) +#include +#elif defined( __APPLE__ ) +#include +#include // PATH_MAX is POSIX, rather than MAXPATHLEN +#endif + + +namespace rsutils { +namespace os { + + +std::string executable_path() +{ +#if defined( PLATFORM_POSIX ) || defined( __linux__ ) + + std::string sp; + std::ifstream( "/proc/self/comm" ) >> sp; + return sp; + +#elif defined( _WIN32 ) + + char buf[MAX_PATH]; + GetModuleFileNameA( nullptr, buf, MAX_PATH ); + return buf; + +#elif defined( __APPLE__ ) + + // "With deep directories the total bufsize needed could be more than MAXPATHLEN." + uint32_t const max_size = PATH_MAX + 1; + char buf[max_size]; + uint32_t size = max_size; + _NSGetExecutablePath( buf, &size ); + return buf; + +#else + + static_assert( false, "unrecognized platform" ); + +#endif +} + + +std::string executable_name( bool with_extension ) +{ + auto path = executable_path(); + auto sep = path.find_last_of( "/\\" ); + if( sep != std::string::npos ) + path = path.substr( sep + 1 ); + if( ! with_extension ) + { + auto period = path.find_last_of( '.' ); + if( period != std::string::npos ) + path.resize( period ); + } + return path; +} + + +} // namespace os +} // namespace rsutils