ChimeraTK-DeviceAccess  03.18.00
DomainImpl.h
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
3 #pragma once
4 
5 #include "../VersionNumber.h"
7 #include "Domain.h"
8 #include "SubDomain.h"
9 
10 #include <functional>
11 
12 namespace ChimeraTK::async {
13 
14  template<typename BackendDataType>
15  class DomainImpl : public Domain {
16  public:
17  DomainImpl(boost::shared_ptr<DeviceBackend> backend, size_t domainId) : _backend(backend), _id(domainId) {}
18 
37  VersionNumber distribute(BackendDataType data, VersionNumber version = VersionNumber{nullptr});
38 
50  VersionNumber activate(BackendDataType data, VersionNumber version = VersionNumber{nullptr});
51 
52  void deactivate() override;
53  void sendException(const std::exception_ptr& e) noexcept override;
54 
55  template<typename UserDataType>
56  boost::shared_ptr<AsyncNDRegisterAccessor<UserDataType>> subscribe(
57  RegisterPath name, size_t numberOfWords, size_t wordOffsetInRegister, AccessModeFlags flags);
58 
59  protected:
60  // Everything in this class is protected by the mutex from the Domain base class.
61  boost::weak_ptr<SubDomain<BackendDataType>> _subDomain;
62 
63  boost::shared_ptr<DeviceBackend> _backend;
64  size_t _id;
65 
66  // Data to resolve a race condition (see distribute and activate)
67  BackendDataType _notDistributedData;
70  };
71 
72  /********************************************************************************************************************/
73 
74  template<typename BackendDataType>
76  std::lock_guard l(_mutex);
77  // everything incl. potential creation of a new version number must happen under the lock
78  if(version == VersionNumber(nullptr)) {
79  version = {};
80  }
81 
82  if(!_isActive) {
83  // Store the data. We might need it later if the data in activate is older due to a race condition.
84  _notDistributedData = data;
85  _notDistributedVersion = version;
86  return VersionNumber{nullptr};
87  }
88 
89  if(version < _activationVersion) {
90  return VersionNumber{nullptr};
91  }
92 
93  auto subDomain = _subDomain.lock();
94  if(!subDomain) {
95  return VersionNumber{nullptr};
96  }
97 
98  subDomain->distribute(data, version);
99  return version;
100  }
101 
102  /********************************************************************************************************************/
103 
104  template<typename BackendDataType>
106  std::lock_guard l(_mutex);
107  // everything incl. potential creation of a new version number must happen under the lock
108  if(version == VersionNumber(nullptr)) {
109  version = {};
110  }
111 
112  _isActive = true;
113 
114  auto subDomain = _subDomain.lock();
115  if(!subDomain) {
116  return VersionNumber{nullptr};
117  }
118 
119  if(version >= _notDistributedVersion) {
120  subDomain->activate(data, version);
121  _activationVersion = version;
122  }
123  else {
124  // Due to a race condition, it has been tried to distribute newer data before activate was called.
125  subDomain->activate(_notDistributedData, _notDistributedVersion);
126  _activationVersion = _notDistributedVersion;
127  }
128  return _activationVersion;
129  }
130 
131  /********************************************************************************************************************/
132 
133  template<typename BackendDataType>
135  std::lock_guard l(_mutex);
136 
137  _isActive = false;
138  }
139 
140  /********************************************************************************************************************/
141 
142  template<typename BackendDataType>
143  void DomainImpl<BackendDataType>::sendException(const std::exception_ptr& e) noexcept {
144  std::lock_guard l(_mutex);
145 
146  if(!_isActive) {
147  // don't send exceptions if async read is off
148  return;
149  }
150 
151  _isActive = false;
152  auto subDomain = _subDomain.lock();
153  if(!subDomain) {
154  return;
155  }
156 
157  subDomain->sendException(e);
158  }
159 
160  /********************************************************************************************************************/
161 
162  template<typename BackendDataType>
163  template<typename UserDataType>
164  boost::shared_ptr<AsyncNDRegisterAccessor<UserDataType>> DomainImpl<BackendDataType>::subscribe(
165  RegisterPath name, size_t numberOfWords, size_t wordOffsetInRegister, AccessModeFlags flags) {
166  std::lock_guard l(_mutex);
167 
168  auto subDomain = _subDomain.lock();
169  if(!subDomain) {
170  subDomain = boost::make_shared<SubDomain<BackendDataType>>(
171  _backend, std::vector<size_t>({_id}), nullptr, shared_from_this());
172  _subDomain = subDomain;
173  }
174 
175  return subDomain->template subscribe<UserDataType>(name, numberOfWords, wordOffsetInRegister, flags);
176  }
177 
178 } // namespace ChimeraTK::async
ChimeraTK::async::DomainImpl::_id
size_t _id
Definition: DomainImpl.h:64
ChimeraTK::async::DomainImpl::_notDistributedVersion
VersionNumber _notDistributedVersion
Definition: DomainImpl.h:68
Domain.h
ChimeraTK::async::DomainImpl::subscribe
boost::shared_ptr< AsyncNDRegisterAccessor< UserDataType > > subscribe(RegisterPath name, size_t numberOfWords, size_t wordOffsetInRegister, AccessModeFlags flags)
Definition: DomainImpl.h:164
ChimeraTK::async
Definition: design_AsyncNDRegisterAcessor_and_NumericAddressedBackend.dox:1
ChimeraTK::async::DomainImpl::distribute
VersionNumber distribute(BackendDataType data, VersionNumber version=VersionNumber{nullptr})
Distribute the data via the associated distribution tree.
Definition: DomainImpl.h:75
SubDomain.h
ChimeraTK::async::DomainImpl::DomainImpl
DomainImpl(boost::shared_ptr< DeviceBackend > backend, size_t domainId)
Definition: DomainImpl.h:17
ChimeraTK::async::DomainImpl
Definition: DomainImpl.h:15
ChimeraTK::async::DomainImpl::activate
VersionNumber activate(BackendDataType data, VersionNumber version=VersionNumber{nullptr})
Activate and distribute the initial value.
Definition: DomainImpl.h:105
ChimeraTK::async::DomainImpl::_subDomain
boost::weak_ptr< SubDomain< BackendDataType > > _subDomain
Definition: DomainImpl.h:61
ChimeraTK::RegisterPath
Class to store a register path name.
Definition: RegisterPath.h:16
AsyncNDRegisterAccessor.h
ChimeraTK::VersionNumber
Class for generating and holding version numbers without exposing a numeric representation.
Definition: VersionNumber.h:23
ChimeraTK::async::DomainImpl::_activationVersion
VersionNumber _activationVersion
Definition: DomainImpl.h:69
ChimeraTK::AccessModeFlags
Set of AccessMode flags with additional functionality for an easier handling.
Definition: AccessMode.h:48
ChimeraTK::async::DomainImpl::sendException
void sendException(const std::exception_ptr &e) noexcept override
Definition: DomainImpl.h:143
ChimeraTK::async::DomainImpl::deactivate
void deactivate() override
Definition: DomainImpl.h:134
ChimeraTK::async::DomainImpl::_notDistributedData
BackendDataType _notDistributedData
Definition: DomainImpl.h:67
ChimeraTK::async::DomainImpl::_backend
boost::shared_ptr< DeviceBackend > _backend
Definition: DomainImpl.h:63
ChimeraTK::async::Domain
The Domain is the thread-safe entry point for each distribution tree.
Definition: Domain.h:25