Skip to content

Commit

Permalink
PR #12243 from Eran: singleton backend/device-watcher
Browse files Browse the repository at this point in the history
  • Loading branch information
maloel authored Oct 3, 2023
2 parents 54286c6 + c9f3718 commit 99c9420
Show file tree
Hide file tree
Showing 27 changed files with 228 additions and 144 deletions.
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

0 comments on commit 99c9420

Please sign in to comment.