ChimeraTK-DeviceAccess  03.18.00
MuxedInterruptDistributor.cc
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: Deutsches Elektronen-Synchrotron DESY, MSK, ChimeraTK Project <chimeratk-support@desy.de>
2 // SPDX-License-Identifier: LGPL-3.0-or-later
4 
7 #include "async/SubDomain.h"
9 #include <nlohmann/json.hpp>
10 
12 
13 #include <tuple>
14 
15 namespace ChimeraTK::async {
16 
17  /********************************************************************************************************************/
18 
19  MuxedInterruptDistributorFactory::MuxedInterruptDistributorFactory() {
20  // we already know about the build-in handlers
23  }
24 
25  /********************************************************************************************************************/
26 
28  static MuxedInterruptDistributorFactory instance;
29  return instance;
30  }
31 
32  /********************************************************************************************************************/
33 
34  std::pair<std::string, std::string> MuxedInterruptDistributorFactory::
36  std::vector<size_t> const& subdomainID, DeviceBackend& backend) {
37  for(auto const& metaDataEntry : backend.getMetadataCatalogue()) {
38  auto const& key = metaDataEntry.first;
39  if(key[0] == '!') {
40  try {
41  auto jkey = nlohmann::json::parse(std::string({++key.begin(), key.end()})); // key without the leading !
42  auto interruptId = jkey.get<std::vector<size_t>>();
43 
44  if(interruptId == subdomainID) {
45  auto jdescriptor = nlohmann::json::parse(metaDataEntry.second);
46  auto controllerType = jdescriptor.begin().key();
47  auto controllerDescription = jdescriptor.front().dump();
48  return {controllerType, controllerDescription};
49  }
50  }
51  catch(json::parse_error& e) {
52  throw ChimeraTK::logic_error("Json parse error in \"" + key + "\": " + e.what());
53  }
54  }
55  }
56  std::string subdomainIdString;
57  for(auto i : subdomainID) {
58  subdomainIdString += std::to_string(i) + ":";
59  }
60  subdomainIdString.pop_back();
61 
63  "No interrupt controller description for SubDomain " + subdomainIdString + " in MetadataCatalogue");
64  }
65 
66  /********************************************************************************************************************/
67 
68  boost::shared_ptr<MuxedInterruptDistributor> MuxedInterruptDistributorFactory::createMuxedInterruptDistributor(
69  boost::shared_ptr<SubDomain<std::nullptr_t>> parent) {
70  std::string name, description;
71  std::tie(name, description) =
72  getInterruptControllerNameAndDescriptionFromCatalogue(parent->getId(), *parent->getBackend());
73  auto creatorFunctionIter = _creatorFunctions.find(name);
74  if(creatorFunctionIter == _creatorFunctions.end()) {
75  throw ChimeraTK::logic_error("Unknown interrupt controller type \"" + name + "\"");
76  }
77  return creatorFunctionIter->second(description, std::move(parent));
78  }
79 
80  /********************************************************************************************************************/
82  : _backend(parent->getBackend()), _id(parent->getId()), _parent(std::move(parent)),
83  _asyncDomain(_parent->getDomain()) {}
84 
85  /********************************************************************************************************************/
86  template<typename DistributorType>
87  boost::shared_ptr<AsyncAccessorManager> MuxedInterruptDistributor::getAccessorManager(
88  std::vector<size_t> const& qualififedSubDomainId) {
89  // the qualified SubDomainId is relative. We need an absolute (fully qualified ID) in case we have to crate a SubDomain
90  assert(!qualififedSubDomainId.empty());
91  auto fullyQualifiedId = _id;
92  fullyQualifiedId.push_back(qualififedSubDomainId.front());
93 
94  // we can't use try_emplace because the map contains weak pointers
95  boost::shared_ptr<SubDomain<std::nullptr_t>> subDomain;
96  auto subDomainIter = _subDomains.find(qualififedSubDomainId.front());
97  if(subDomainIter != _subDomains.end()) {
98  subDomain = subDomainIter->second.lock();
99  }
100  if(!subDomain) {
101  subDomain =
102  boost::make_shared<SubDomain<std::nullptr_t>>(_backend, fullyQualifiedId, shared_from_this(), _asyncDomain);
103  _subDomains[qualififedSubDomainId.front()] = subDomain;
104  if(_asyncDomain->unsafeGetIsActive()) {
105  // Creating a new version here is correct. Nothing has been distributed to any accessor connected to this
106  // sub-interrupt yet because we just created this subDomain.
107  activateSubDomain(*subDomain, {});
108  }
109  }
110  return subDomain->getAccessorManager<DistributorType>(qualififedSubDomainId);
111  }
112 
113  /********************************************************************************************************************/
114 
115  template boost::shared_ptr<AsyncAccessorManager> MuxedInterruptDistributor::getAccessorManager<
116  TriggeredPollDistributor>(std::vector<size_t> const& qualififedSubDomainId);
117 
118  /********************************************************************************************************************/
119 
120  template boost::shared_ptr<AsyncAccessorManager> MuxedInterruptDistributor::getAccessorManager<
121  VariableDistributor<std::nullptr_t>>(std::vector<size_t> const& qualififedSubDomainId);
122 
123  /********************************************************************************************************************/
125  for(auto& subDomainIter : _subDomains) {
126  auto subDomain = subDomainIter.second.lock();
127  if(subDomain) {
128  activateSubDomain(*subDomain, version);
129  }
130  }
131  }
132 
133  /********************************************************************************************************************/
134  void MuxedInterruptDistributor::sendException(const std::exception_ptr& e) {
135  for(auto& subDomainIter : _subDomains) {
136  auto subDomain = subDomainIter.second.lock();
137  if(subDomain) {
138  subDomain->sendException(e);
139  }
140  }
141  }
142 
143  /********************************************************************************************************************/
145  SubDomain<std::nullptr_t>& subDomain, VersionNumber const& version) {
146  subDomain.activate(nullptr, version);
147  }
148 
149 } // namespace ChimeraTK::async
ChimeraTK::async::MuxedInterruptDistributorFactory
Definition: MuxedInterruptDistributor.h:28
ChimeraTK::async::MuxedInterruptDistributor::sendException
void sendException(const std::exception_ptr &e)
Definition: MuxedInterruptDistributor.cc:134
ChimeraTK::async::MuxedInterruptDistributorFactory::createMuxedInterruptDistributor
boost::shared_ptr< MuxedInterruptDistributor > createMuxedInterruptDistributor(boost::shared_ptr< SubDomain< std::nullptr_t >> parent)
Definition: MuxedInterruptDistributor.cc:68
ChimeraTK::async::SubDomain
Send backend-specific asynchronous data to different distributors:
Definition: MuxedInterruptDistributor.h:23
ChimeraTK::async::MuxedInterruptDistributorFactory::getInstance
static MuxedInterruptDistributorFactory & getInstance()
Definition: MuxedInterruptDistributor.cc:27
ChimeraTK::async::MuxedInterruptDistributor::MuxedInterruptDistributor
MuxedInterruptDistributor(boost::shared_ptr< SubDomain< std::nullptr_t >> parent)
MuxedInterruptDistributor classes must only be constructed inside and held by a DeviceBackend,...
Definition: MuxedInterruptDistributor.cc:81
ChimeraTK::async
Definition: design_AsyncNDRegisterAcessor_and_NumericAddressedBackend.dox:1
ChimeraTK::async::MuxedInterruptDistributor::_id
std::vector< size_t > _id
The ID of this controller handler.
Definition: MuxedInterruptDistributor.h:88
MuxedInterruptDistributor.h
json
nlohmann::json json
Definition: MuxedInterruptDistributor.cc:11
GenericMuxedInterruptDistributor.h
ChimeraTK::async::MuxedInterruptDistributor::getAccessorManager
boost::shared_ptr< AsyncAccessorManager > getAccessorManager(std::vector< size_t > const &qualififedSubDomainId)
Get an AsyncAccessorManager of type DistributorType from the matching SubDomain.
Definition: MuxedInterruptDistributor.cc:87
ChimeraTK::async::MuxedInterruptDistributorFactory::_creatorFunctions
std::map< std::string, std::function< std::unique_ptr< MuxedInterruptDistributor > std::string, boost::shared_ptr< SubDomain< std::nullptr_t > >)> > _creatorFunctions
Each controller type is registered via name and creator function.
Definition: MuxedInterruptDistributor.h:40
TriggeredPollDistributor.h
ChimeraTK::async::DummyMuxedInterruptDistributor::create
static std::unique_ptr< DummyMuxedInterruptDistributor > create(std::string const &desrciption, boost::shared_ptr< SubDomain< std::nullptr_t >> parent)
Definition: DummyMuxedInterruptDistributor.cc:48
ChimeraTK::DeviceBackend
The base class for backends providing IO functionality for the Device class.
Definition: DeviceBackend.h:28
ChimeraTK::async::TriggeredPollDistributor
The TriggeredPollDistributor has std::nullptr_t source data type and is polling the data for the Asyn...
Definition: TriggeredPollDistributor.h:17
ChimeraTK::async::MuxedInterruptDistributor::_asyncDomain
boost::shared_ptr< Domain > _asyncDomain
Definition: MuxedInterruptDistributor.h:91
ChimeraTK::async::MuxedInterruptDistributorFactory::getInterruptControllerNameAndDescriptionFromCatalogue
static std::pair< std::string, std::string > getInterruptControllerNameAndDescriptionFromCatalogue(std::vector< size_t > const &subdomainID, DeviceBackend &backend)
Definition: MuxedInterruptDistributor.cc:35
ChimeraTK::async::GenericMuxedInterruptDistributor::create
static std::unique_ptr< GenericMuxedInterruptDistributor > create(std::string const &description, const boost::shared_ptr< SubDomain< std::nullptr_t >> &parent)
Create parses the json configuration snippet 'description', and calls the constructor.
Definition: GenericMuxedInterruptDistributor.cc:664
SubDomain.h
ChimeraTK::DeviceBackend::getMetadataCatalogue
virtual MetadataCatalogue getMetadataCatalogue() const =0
Return the device metadata catalogue.
DummyMuxedInterruptDistributor.h
ChimeraTK::VersionNumber
Class for generating and holding version numbers without exposing a numeric representation.
Definition: VersionNumber.h:23
ChimeraTK::async::MuxedInterruptDistributor::activateSubDomain
virtual void activateSubDomain(SubDomain< std::nullptr_t > &subDomain, VersionNumber const &version)
Function to activate a (new) single SubDomain if the MuxedInterruptDistributor is already active.
Definition: MuxedInterruptDistributor.cc:144
ChimeraTK::async::MuxedInterruptDistributor::_backend
boost::shared_ptr< DeviceBackend > _backend
Definition: MuxedInterruptDistributor.h:84
ChimeraTK::async::VariableDistributor
Definition: VariableDistributor.h:13
ChimeraTK::to_string
std::string to_string(Boolean &value)
Definition: SupportedUserTypes.h:59
ChimeraTK::async::MuxedInterruptDistributor::activate
virtual void activate(VersionNumber version)
Definition: MuxedInterruptDistributor.cc:124
ChimeraTK::async::SubDomain::activate
void activate(BackendSpecificDataType, VersionNumber v)
Definition: SubDomain.h:208
ChimeraTK::async::MuxedInterruptDistributor::_subDomains
std::map< size_t, boost::weak_ptr< SubDomain< std::nullptr_t > > > _subDomains
Definition: MuxedInterruptDistributor.h:82
ChimeraTK::logic_error
Exception thrown when a logic error has occured.
Definition: Exception.h:51