diff --git a/src/backend-device-factory.cpp b/src/backend-device-factory.cpp index dcb4fb498ae..d033b95c955 100644 --- a/src/backend-device-factory.cpp +++ b/src/backend-device-factory.cpp @@ -126,13 +126,18 @@ std::shared_ptr< platform::backend > backend_device::get_backend() } -backend_device_factory::backend_device_factory( context & ctx, callback && cb ) +backend_device_factory::backend_device_factory( std::shared_ptr< context > const & ctx, callback && cb ) : super( ctx ) , _device_watcher( backend_device_watcher.instance() ) , _dtor( _device_watcher->subscribe( - [this, cb = std::move( cb )]( platform::backend_device_group const & old, - platform::backend_device_group const & curr ) + [this, liveliness = std::weak_ptr< context >( ctx ), cb = std::move( cb )]( + platform::backend_device_group const & old, platform::backend_device_group const & curr ) { + // the factory should be alive as long as the context is alive + auto live_ctx = liveliness.lock(); + if( ! live_ctx ) + return; + auto old_list = create_devices_from_group( old, RS2_PRODUCT_LINE_ANY ); auto new_list = create_devices_from_group( curr, RS2_PRODUCT_LINE_ANY ); @@ -166,7 +171,11 @@ backend_device_factory::~backend_device_factory() std::vector< std::shared_ptr< device_info > > backend_device_factory::query_devices( unsigned requested_mask ) const { - if( ( requested_mask & RS2_PRODUCT_LINE_SW_ONLY ) || ( _context.get_device_mask() & RS2_PRODUCT_LINE_SW_ONLY ) ) + auto ctx = get_context(); + if( ! ctx ) + return {}; + + if( ( requested_mask & RS2_PRODUCT_LINE_SW_ONLY ) || ( ctx->get_device_mask() & RS2_PRODUCT_LINE_SW_ONLY ) ) return {}; // We don't carry any software devices auto backend = _device_watcher->get_backend(); @@ -181,33 +190,34 @@ std::vector< std::shared_ptr< device_info > > backend_device_factory::query_devi std::vector< std::shared_ptr< platform::platform_device_info > > backend_device_factory::create_devices_from_group( platform::backend_device_group devices, int requested_mask ) const { + auto ctx = get_context(); std::vector< std::shared_ptr< platform::platform_device_info > > list; - unsigned const mask = context::combine_device_masks( requested_mask, _context.get_device_mask() ); + unsigned const mask = context::combine_device_masks( requested_mask, ctx->get_device_mask() ); if( ! ( mask & RS2_PRODUCT_LINE_SW_ONLY ) ) { if( mask & RS2_PRODUCT_LINE_D400 ) { - auto d400_devices = d400_info::pick_d400_devices( _context.shared_from_this(), devices ); + auto d400_devices = d400_info::pick_d400_devices( ctx, devices ); std::copy( std::begin( d400_devices ), end( d400_devices ), std::back_inserter( list ) ); } if( mask & RS2_PRODUCT_LINE_D500 ) { - auto d500_devices = d500_info::pick_d500_devices( _context.shared_from_this(), devices ); + auto d500_devices = d500_info::pick_d500_devices( ctx, devices ); std::copy( begin( d500_devices ), end( d500_devices ), std::back_inserter( list ) ); } // Supported recovery devices { auto recovery_devices - = fw_update_info::pick_recovery_devices( _context.shared_from_this(), devices.usb_devices, mask ); + = fw_update_info::pick_recovery_devices( ctx, devices.usb_devices, mask ); std::copy( begin( recovery_devices ), end( recovery_devices ), std::back_inserter( list ) ); } if( mask & RS2_PRODUCT_LINE_NON_INTEL ) { auto uvc_devices - = platform_camera_info::pick_uvc_devices( _context.shared_from_this(), devices.uvc_devices ); + = platform_camera_info::pick_uvc_devices( ctx, devices.uvc_devices ); std::copy( begin( uvc_devices ), end( uvc_devices ), std::back_inserter( list ) ); } } diff --git a/src/backend-device-factory.h b/src/backend-device-factory.h index 1b71faf922b..7bd52d35895 100644 --- a/src/backend-device-factory.h +++ b/src/backend-device-factory.h @@ -37,7 +37,7 @@ class backend_device_factory : public device_factory rsutils::subscription const _dtor; // raii generic code, used to automatically unsubscribe our callback public: - backend_device_factory( context &, callback && ); + backend_device_factory( std::shared_ptr< context > const &, callback && ); ~backend_device_factory(); // Query any subset of available devices and return them as device-info objects diff --git a/src/context.cpp b/src/context.cpp index e490c46babf..23d1c6adb45 100644 --- a/src/context.cpp +++ b/src/context.cpp @@ -67,16 +67,23 @@ namespace librealsense { version_logged = true; LOG_DEBUG( "Librealsense VERSION: " << RS2_API_FULL_VERSION_STR ); } + } + + + void context::create_factories() + { + // This can only get called once the constructor is done: + auto sptr = shared_from_this(); _factories.push_back( std::make_shared< backend_device_factory >( - *this, + sptr, [this]( std::vector< std::shared_ptr< device_info > > const & removed, std::vector< std::shared_ptr< device_info > > const & added ) { invoke_devices_changed_callbacks( removed, added ); } ) ); #ifdef BUILD_WITH_DDS _factories.push_back( std::make_shared< rsdds_device_factory >( - *this, + sptr, [this]( std::vector< std::shared_ptr< device_info > > const & removed, std::vector< std::shared_ptr< device_info > > const & added ) { invoke_devices_changed_callbacks( removed, added ); } ) ); @@ -84,9 +91,17 @@ namespace librealsense { } - context::context( char const * json_settings ) - : context( json_settings ? json::parse( json_settings ) : json::object() ) + /*static*/ std::shared_ptr< context > context::make( json const & settings ) + { + std::shared_ptr< context > ctx( new context( settings ) ); + ctx->create_factories(); + return ctx; + } + + + /*static*/ std::shared_ptr< context > context::make( char const * json_settings ) { + return make( json_settings ? json::parse( json_settings ) : json::object() ); } diff --git a/src/context.h b/src/context.h index 629bad3a3ad..5b8342ca82d 100644 --- a/src/context.h +++ b/src/context.h @@ -18,9 +18,13 @@ namespace librealsense class context : public std::enable_shared_from_this { + context( nlohmann::json const & ); // private! use make() + + void create_factories(); + public: - explicit context( nlohmann::json const & ); - explicit context( char const * json_settings ); + static std::shared_ptr< context > make( nlohmann::json const & ); + static std::shared_ptr< context > make( char const * json_settings ); ~context(); diff --git a/src/dds/rsdds-device-factory.cpp b/src/dds/rsdds-device-factory.cpp index 36bf2a7acfd..ec1a3ffde67 100644 --- a/src/dds/rsdds-device-factory.cpp +++ b/src/dds/rsdds-device-factory.cpp @@ -80,10 +80,10 @@ static std::map< realdds::dds_domain_id, domain_context > domain_context_by_id; static std::mutex domain_context_by_id_mutex; -rsdds_device_factory::rsdds_device_factory( context & ctx, callback && cb ) +rsdds_device_factory::rsdds_device_factory( std::shared_ptr< context > const & ctx, callback && cb ) : super( ctx ) { - nlohmann::json const & dds_settings = rsutils::json::nested( _context.get_settings(), std::string( "dds", 3 ) ); + nlohmann::json const & dds_settings = rsutils::json::nested( ctx->get_settings(), std::string( "dds", 3 ) ); if( dds_settings.is_object() && rsutils::json::get( dds_settings, std::string( "enabled", 7 ), true ) ) { auto domain_id = rsutils::json::get< realdds::dds_domain_id >( dds_settings, std::string( "domain", 6 ), 0 ); @@ -109,9 +109,11 @@ rsdds_device_factory::rsdds_device_factory( context & ctx, callback && cb ) _subscription = _watcher_singleton->subscribe( [this, cb = std::move( cb )]( std::shared_ptr< realdds::dds_device > const & dev, bool added ) { + auto ctx = get_context(); + if( ! ctx ) + return; std::vector< std::shared_ptr< device_info > > infos_added; std::vector< std::shared_ptr< device_info > > infos_removed; - auto ctx = _context.shared_from_this(); auto dev_info = std::make_shared< dds_device_info >( ctx, dev ); if( added ) infos_added.push_back( dev_info ); @@ -131,7 +133,7 @@ std::vector< std::shared_ptr< device_info > > rsdds_device_factory::query_device std::vector< std::shared_ptr< device_info > > list; if( _watcher_singleton ) { - unsigned const mask = context::combine_device_masks( requested_mask, _context.get_device_mask() ); + unsigned const mask = context::combine_device_masks( requested_mask, get_context()->get_device_mask() ); _watcher_singleton->get_device_watcher()->foreach_device( [&]( std::shared_ptr< realdds::dds_device > const & dev ) -> bool @@ -156,9 +158,11 @@ std::vector< std::shared_ptr< device_info > > rsdds_device_factory::query_device return true; } - std::shared_ptr< device_info > info - = std::make_shared< dds_device_info >( _context.shared_from_this(), dev ); - list.push_back( info ); + if( auto ctx = get_context() ) + { + std::shared_ptr< device_info > info = std::make_shared< dds_device_info >( ctx, dev ); + list.push_back( info ); + } return true; // continue iteration } ); } diff --git a/src/dds/rsdds-device-factory.h b/src/dds/rsdds-device-factory.h index 2fa2f053912..a5914350824 100644 --- a/src/dds/rsdds-device-factory.h +++ b/src/dds/rsdds-device-factory.h @@ -34,7 +34,7 @@ class rsdds_device_factory : public device_factory rsutils::subscription _subscription; public: - rsdds_device_factory( context &, callback && ); + rsdds_device_factory( std::shared_ptr< context > const &, callback && ); ~rsdds_device_factory(); // Query any subset of available devices and return them as device-info objects diff --git a/src/rs.cpp b/src/rs.cpp index 5bbff81fdd1..116d02af1f0 100644 --- a/src/rs.cpp +++ b/src/rs.cpp @@ -188,7 +188,7 @@ rs2_context* rs2_create_context(int api_version, rs2_error** error) BEGIN_API_CA verify_version_compatibility(api_version); nlohmann::json settings; - return new rs2_context{ std::make_shared< librealsense::context >( settings ) }; + return new rs2_context{ context::make( settings ) }; } HANDLE_EXCEPTIONS_AND_RETURN(nullptr, api_version) @@ -196,8 +196,7 @@ rs2_context* rs2_create_context_ex(int api_version, const char * json_settings, { verify_version_compatibility(api_version); - return new rs2_context{ - std::make_shared< librealsense::context >( json_settings ) }; + return new rs2_context{ context::make( json_settings ) }; } HANDLE_EXCEPTIONS_AND_RETURN(nullptr, api_version, json_settings) @@ -2652,7 +2651,7 @@ NOARGS_HANDLE_EXCEPTIONS_AND_RETURN(0) rs2_device* rs2_create_software_device(rs2_error** error) BEGIN_API_CALL { // We're not given a context... - auto ctx = std::make_shared< context >( nlohmann::json::object( { { "dds", false } } ) ); + auto ctx = context::make( nlohmann::json::object( { { "dds", false } } ) ); auto dev_info = std::make_shared< software_device_info >( ctx ); auto dev = std::make_shared< software_device >( dev_info ); dev_info->set_device( dev ); diff --git a/src/rscore/device-factory.h b/src/rscore/device-factory.h index 7705800a331..5378fbc5904 100644 --- a/src/rscore/device-factory.h +++ b/src/rscore/device-factory.h @@ -25,10 +25,10 @@ class context; class device_factory { -protected: - context & _context; + std::weak_ptr< context > _context; - device_factory( context & ctx ) +protected: + device_factory( std::shared_ptr< context > const & ctx ) : _context( ctx ) { } @@ -41,6 +41,8 @@ class device_factory virtual ~device_factory() = default; + std::shared_ptr< context > get_context() const { return _context.lock(); } + // Query any subset of available devices and return them as device-info objects from which actual devices can be // created as needed. //