Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Singleton backend/device-watcher #12243

Merged
merged 3 commits into from
Oct 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ target_sources(${LRS_TARGET}
"${CMAKE_CURRENT_LIST_DIR}/api.h"
"${CMAKE_CURRENT_LIST_DIR}/archive.h"
"${CMAKE_CURRENT_LIST_DIR}/backend.h"
"${CMAKE_CURRENT_LIST_DIR}/backend-device.h"
"${CMAKE_CURRENT_LIST_DIR}/platform/backend-device-group.h"
"${CMAKE_CURRENT_LIST_DIR}/platform/platform-device-info.h"
"${CMAKE_CURRENT_LIST_DIR}/platform/device-watcher.h"
Expand Down
146 changes: 111 additions & 35 deletions src/backend-device-factory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,24 @@
#include "platform/platform-device-info.h"
#include "platform/device-watcher.h"

#include "backend-device.h"
#include "ds/d400/d400-info.h"
#include "ds/d500/d500-info.h"
#include "fw-update/fw-update-factory.h"
#include "platform-camera.h"

#include <rsutils/shared-ptr-singleton.h>
#include <rsutils/signal.h>
#include <rsutils/json.h>


namespace librealsense {
namespace platform {
std::shared_ptr< backend > create_backend();
} // namespace platform
} // namespace librealsense


namespace {


Expand Down Expand Up @@ -77,56 +87,122 @@ subtract_sets( const std::vector< std::shared_ptr< librealsense::platform::platf
namespace librealsense {


backend_device_factory::backend_device_factory( context & ctx, callback && cb )
: _device_watcher( ctx.get_backend().create_device_watcher() )
, _context( ctx )
// This singleton creates the actual backend; as long as someone holds it, the backend will stay alive.
// The instance is held below by the device-watcher. I.e., the device-watcher triggers creation of the
// backend!
//
class backend_singleton
{
assert( _device_watcher->is_stopped() );
_device_watcher->start(
[this, cb = std::move( cb )]( platform::backend_device_group const & old,
platform::backend_device_group const & curr )
{
auto old_list = create_devices_from_group( old, RS2_PRODUCT_LINE_ANY );
auto new_list = create_devices_from_group( curr, RS2_PRODUCT_LINE_ANY );
std::shared_ptr< platform::backend > const _backend;

std::vector< rs2_device_info > devices_removed;
for( auto & device_removed : subtract_sets( old_list, new_list ) )
{
devices_removed.push_back( { _context.shared_from_this(), device_removed } );
LOG_DEBUG( "Device disconnected: " << device_removed->get_address() );
}
public:
backend_singleton()
: _backend( platform::create_backend() )
{
}

std::vector< rs2_device_info > devices_added;
for( auto & device_added : subtract_sets( new_list, old_list ) )
{
devices_added.push_back( { _context.shared_from_this(), device_added } );
LOG_DEBUG( "Device connected: " << device_added->get_address() );
}
std::shared_ptr< platform::backend > get() const { return _backend; }
};

if( devices_removed.size() + devices_added.size() )
{
cb( devices_removed, devices_added );
}
} );

static rsutils::shared_ptr_singleton< backend_singleton > the_backend;


// The device-watcher is also a singleton: we don't need multiple agents of notifications. It is held alive by the
// device-factory below, which is held per context. I.e., as long as the context is alive, we'll stay alive and the
// backend-singleton will stay alive.
//
// We are responsible for exposing the single notification from the platform-device-watcher to several subscribers:
// one device-watcher, but many contexts, each with further subscriptions.
//
class device_watcher_singleton
{
// The device-watcher keeps a direct pointer to the backend instance, so we have to make sure it stays alive!
std::shared_ptr< backend_singleton > const _backend;
std::shared_ptr< platform::device_watcher > const _device_watcher;
rsutils::signal< platform::backend_device_group const &, platform::backend_device_group const & > _callbacks;

public:
device_watcher_singleton()
: _backend( the_backend.instance() )
, _device_watcher( _backend->get()->create_device_watcher() )
{
assert( _device_watcher->is_stopped() );
_device_watcher->start(
[this]( platform::backend_device_group const & old, platform::backend_device_group const & curr )
{ _callbacks.raise( old, curr ); } );
}

rsutils::subscription subscribe( platform::device_changed_callback && cb )
{
return _callbacks.subscribe( std::move( cb ) );
}

std::shared_ptr< platform::backend > const get_backend() const { return _backend->get(); }
};


static rsutils::shared_ptr_singleton< device_watcher_singleton > backend_device_watcher;


std::shared_ptr< platform::backend > backend_device::get_backend()
{
auto singleton = the_backend.get();
if( ! singleton )
// Whoever is calling us, they are expecting a backend to exist, but it does not!
throw std::runtime_error( "backend not created yet!" );

return singleton->get();
}


backend_device_factory::backend_device_factory( context & ctx, callback && cb )
: _context( 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 )
{
auto old_list = create_devices_from_group( old, RS2_PRODUCT_LINE_ANY );
auto new_list = create_devices_from_group( curr, RS2_PRODUCT_LINE_ANY );

std::vector< rs2_device_info > devices_removed;
for( auto & device_removed : subtract_sets( old_list, new_list ) )
{
devices_removed.push_back( { _context.shared_from_this(), device_removed } );
LOG_DEBUG( "Device disconnected: " << device_removed->get_address() );
}

std::vector< rs2_device_info > devices_added;
for( auto & device_added : subtract_sets( new_list, old_list ) )
{
devices_added.push_back( { _context.shared_from_this(), device_added } );
LOG_DEBUG( "Device connected: " << device_added->get_address() );
}

if( devices_removed.size() + devices_added.size() )
{
cb( devices_removed, devices_added );
}
} ) )
{
}


backend_device_factory::~backend_device_factory()
{
if( _device_watcher )
_device_watcher->stop();
}


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) )
if( ( requested_mask & RS2_PRODUCT_LINE_SW_ONLY ) || ( _context.get_device_mask() & RS2_PRODUCT_LINE_SW_ONLY ) )
return {}; // We don't carry any software devices

auto & backend = _context.get_backend();
platform::backend_device_group group( backend.query_uvc_devices(),
backend.query_usb_devices(),
backend.query_hid_devices() );
auto backend = _device_watcher->get_backend();
platform::backend_device_group group( backend->query_uvc_devices(),
backend->query_usb_devices(),
backend->query_hid_devices() );
auto devices = create_devices_from_group( group, requested_mask );
return { devices.begin(), devices.end() };
}
Expand Down Expand Up @@ -169,4 +245,4 @@ backend_device_factory::create_devices_from_group( platform::backend_device_grou
}


} // namespace librealsense
} // namespace librealsense
9 changes: 5 additions & 4 deletions src/backend-device-factory.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@

#pragma once

#include <functional>
#include <rsutils/subscription.h>
#include <memory>
#include <vector>

Expand All @@ -16,10 +16,10 @@ namespace librealsense {

class device_info;
class context;
class device_watcher_singleton;


namespace platform {
class device_watcher;
struct backend_device_group;
class platform_device_info;
} // namespace platform
Expand All @@ -38,12 +38,13 @@ class platform_device_info;
class backend_device_factory
{
context & _context;
std::shared_ptr< platform::device_watcher > const _device_watcher;
std::shared_ptr< device_watcher_singleton > const _device_watcher;
rsutils::subscription const _dtor; // raii generic code, used to automatically unsubscribe our callback

public:
using callback = std::function< void( std::vector< rs2_device_info > & rs2_devices_info_removed,
std::vector< rs2_device_info > & rs2_devices_info_added ) >;

public:
backend_device_factory( context &, callback && );
~backend_device_factory();

Expand Down
13 changes: 10 additions & 3 deletions src/ds/ds-device.h → src/backend-device.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,32 @@
#pragma once

#include <src/device.h>
#include <memory>


namespace librealsense {


// Common base class for all Stereo devices
namespace platform {
class backend;
}


// Common base class for all backend devices (i.e., those that require a platform backend)
//
class ds_device : public virtual device
class backend_device : public virtual device
{
typedef device super;

protected:
ds_device( std::shared_ptr< const device_info > const & dev_info, bool device_changed_notifications = true )
backend_device( std::shared_ptr< const device_info > const & dev_info, bool device_changed_notifications = true )
: super( dev_info, device_changed_notifications )
{
}

public:
uint16_t get_pid() const { return _pid; }
std::shared_ptr< platform::backend > get_backend();

protected:
uint16_t _pid = 0;
Expand Down
2 changes: 0 additions & 2 deletions src/backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,6 @@ namespace librealsense
virtual ~backend() = default;
};

std::shared_ptr<backend> create_backend();

}

double monotonic_to_realtime(double monotonic);
Expand Down
12 changes: 5 additions & 7 deletions src/context.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,13 @@ using json = nlohmann::json;
namespace librealsense
{
context::context( json const & settings )
: _backend( platform::create_backend() )
, _settings( settings )
: _settings( settings )
, _device_mask( rsutils::json::get< unsigned >( settings, "device-mask", RS2_PRODUCT_LINE_ANY ) )
, _devices_changed_callback( nullptr, []( rs2_devices_changed_callback * ) {} )
, _backend_device_factory(
*this,
[this]( std::vector< rs2_device_info > & removed, std::vector< rs2_device_info > & added )
{ invoke_devices_changed_callbacks( removed, added ); } )
*this,
[this]( std::vector< rs2_device_info > & removed, std::vector< rs2_device_info > & added )
{ invoke_devices_changed_callbacks( removed, added ); } )
{
static bool version_logged = false;
if( ! version_logged )
Expand All @@ -58,7 +57,6 @@ namespace librealsense
LOG_DEBUG( "Librealsense VERSION: " << RS2_API_VERSION_STR );
}


#ifdef BUILD_WITH_DDS
nlohmann::json dds_settings
= rsutils::json::get< nlohmann::json >( settings, std::string( "dds", 3 ), nlohmann::json::object() );
Expand Down Expand Up @@ -116,7 +114,7 @@ namespace librealsense
// The normal bits enable, so enable only those that are on
mask &= mask_in_settings & ~RS2_PRODUCT_LINE_SW_ONLY;
// But the above turned off the SW-only bits, so turn them back on again
if( (mask_in_settings & RS2_PRODUCT_LINE_SW_ONLY) || (requested_mask & RS2_PRODUCT_LINE_SW_ONLY) )
if( ( mask_in_settings & RS2_PRODUCT_LINE_SW_ONLY ) || ( requested_mask & RS2_PRODUCT_LINE_SW_ONLY ) )
mask |= RS2_PRODUCT_LINE_SW_ONLY;
return mask;
}
Expand Down
14 changes: 1 addition & 13 deletions src/context.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,7 @@
#pragma once

#include "backend-device-factory.h"
#include "device-info.h"
#include "types.h"
#include "types.h" // devices_changed_callback_ptr

#include <rsutils/lazy.h>
#include <nlohmann/json.hpp>
Expand Down Expand Up @@ -49,19 +48,11 @@ namespace realdds {

namespace librealsense
{
class device;
class context;
class playback_device_info;
class stream_interface;

namespace platform {
class backend;
class device_watcher;
}

class context : public std::enable_shared_from_this<context>
{
context();
public:
explicit context( nlohmann::json const & );
explicit context( char const * json_settings );
Expand All @@ -81,7 +72,6 @@ namespace librealsense
static unsigned combine_device_masks( unsigned requested_mask, unsigned mask_in_settings );

std::vector<std::shared_ptr<device_info>> query_devices(int mask) const;
const platform::backend& get_backend() const { return *_backend; }

uint64_t register_internal_device_callback(devices_changed_callback_ptr callback);
void unregister_internal_device_callback(uint64_t cb_id);
Expand All @@ -101,8 +91,6 @@ namespace librealsense
std::vector<rs2_device_info> & rs2_devices_info_added );
void raise_devices_changed(const std::vector<rs2_device_info>& removed, const std::vector<rs2_device_info>& added);

std::shared_ptr<platform::backend> _backend;

std::map<std::string, std::weak_ptr<device_info>> _playback_devices;
std::map<uint64_t, devices_changed_callback_ptr> _devices_changed_callbacks;
#ifdef BUILD_WITH_DDS
Expand Down
3 changes: 2 additions & 1 deletion src/dds/rs-dds-device-info.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@

#pragma once

#include <src/context.h> // device_info, context
#include <src/context.h>
#include <src/device-info.h>

#include <memory>

Expand Down
1 change: 0 additions & 1 deletion src/ds/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,6 @@ target_sources(${LRS_TARGET}
"${CMAKE_CURRENT_LIST_DIR}/advanced_mode/advanced_mode.cpp"
"${CMAKE_CURRENT_LIST_DIR}/ds-calib-parsers.cpp"
"${CMAKE_CURRENT_LIST_DIR}/ds-device-common.h"
"${CMAKE_CURRENT_LIST_DIR}/ds-device.h"
"${CMAKE_CURRENT_LIST_DIR}/ds-motion-common.h"
"${CMAKE_CURRENT_LIST_DIR}/ds-color-common.h"
"${CMAKE_CURRENT_LIST_DIR}/ds-active-common.h"
Expand Down
3 changes: 1 addition & 2 deletions src/ds/d400/d400-color.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ namespace librealsense
void d400_color::create_color_device(std::shared_ptr<context> ctx, const platform::backend_device_group& group)
{
using namespace ds;
auto&& backend = ctx->get_backend();

_color_calib_table_raw = [this]()
{
Expand Down Expand Up @@ -82,7 +81,7 @@ namespace librealsense
info = color_devs_info[1];
else
info = color_devs_info.front();
auto uvcd = backend.create_uvc_device(info);
auto uvcd = get_backend()->create_uvc_device( info );
//auto ftr = std::unique_ptr<frame_timestamp_reader>(new global_timestamp_reader(std::move(d400_timestamp_reader_metadata), _tf_keeper, enable_global_time_option));
auto raw_color_ep = std::make_shared<uvc_sensor>("Raw RGB Camera",
uvcd,
Expand Down
Loading