Project
Loading...
Searching...
No Matches
ServiceRegistry.h
Go to the documentation of this file.
1// Copyright 2019-2020 CERN and copyright holders of ALICE O2.
2// See https://alice-o2.web.cern.ch/copyright for details of the copyright holders.
3// All rights not expressly granted are reserved.
4//
5// This software is distributed under the terms of the GNU General Public
6// License v3 (GPL Version 3), copied verbatim in the file "COPYING".
7//
8// In applying this license CERN does not waive the privileges and immunities
9// granted to it by virtue of its status as an Intergovernmental Organization
10// or submit itself to any jurisdiction.
11#ifndef O2_FRAMEWORK_SERVICEREGISTRY_H_
12#define O2_FRAMEWORK_SERVICEREGISTRY_H_
13
19
20#include <array>
21#include <string>
22#include <type_traits>
23#include <typeinfo>
24#include <atomic>
25#include <mutex>
26
27namespace o2::framework
28{
29
30struct DeviceState;
31
36
37struct NoLocking {
38 void lock() {}
39 void unlock() {}
40};
41
42struct O2_DPL_CAPABILITY("mutex") MutexLock {
43 void lock() O2_DPL_ACQUIRE() { mutex.lock(); }
44 void unlock() O2_DPL_RELEASE() { mutex.unlock(); }
45 std::mutex& mutex;
46};
47
48// A pointer to a service. Includes the locking policy
49// for that service.
50template <typename T, typename LOCKING = NoLocking>
51class service_ptr : LOCKING
52{
53 public:
54 service_ptr(T* ptr, LOCKING policy) : LOCKING(policy), mPtr{ptr} { this->lock(); }
55 ~service_ptr() { this->unlock(); }
58 T& operator*() { return *mPtr; }
59 T* operator->() { return mPtr; }
60
61 private:
62 T* mPtr;
63};
64
65template <typename, typename = void>
69
70template <typename T>
71struct ServiceKindExtractor<T, std::void_t<decltype(T::service_kind)>> : std::is_same<decltype(T::service_kind), enum ServiceKind> {
72 constexpr static ServiceKind kind = T::service_kind;
73};
74
75template <typename T>
77
79 struct Salt {
80 short streamId = 0;
81 short dataProcessorId = 0;
82 };
83
84 enum struct SpecialStreamId : short {
85 Global = 0,
86 Callback = -1,
87 Invalid = -2
88 };
89
90 enum struct SpecialDataProcessorId : short {
91 Device = -1,
92 Invalid = -2
93 };
94
95 static constexpr Salt GLOBAL_CONTEXT_SALT{0, 0};
96
97 struct InstanceId {
98 uint32_t id = 0;
99 };
100
101 struct Index {
102 int32_t index = -1;
103 };
104
105 struct SpecIndex {
106 int index = -1;
107 };
108
109 // Metadata about the service. This
110 // might be interesting for debugging purposes.
111 // however it's not used to uniquely identify
112 // the service.
113 struct Meta {
115 char const* name = nullptr;
116 // The index in the
118 };
119
120 // Unique identifier for a service.
121 // While we use the salted hash to find the bucket
122 // in the hashmap, the service can be uniquely identified
123 // only by this 64 bit value.
128
129 static constexpr int32_t valueFromSalt(Salt salt) { return ((int32_t)salt.streamId) << 16 | salt.dataProcessorId; }
130 static constexpr uint64_t valueFromKey(Key key) { return ((uint64_t)key.typeHash.hash) << 32 | ((uint64_t)valueFromSalt(key.salt)); }
131
133 constexpr static int32_t MAX_DISTANCE = 8;
135 constexpr static uint32_t MAX_SERVICES = 256;
137 constexpr static uint32_t MAX_SERVICES_MASK = MAX_SERVICES - 1;
138
145 {
146 return GLOBAL_CONTEXT_SALT;
147 }
148
151 static Salt globalStreamSalt(short streamId)
152 {
153 return {streamId, 0};
154 }
155
161 static Salt dataProcessorSalt(short dataProcessorId)
162 {
163 // FIXME: old behaviour for now
164 // return {0, dataProcessorId};
165 return GLOBAL_CONTEXT_SALT;
166 }
167
171 static Salt streamSalt(short streamId, short dataProcessorId)
172 {
173 // FIXME: old behaviour for now
174 // return {streamId, dataProcessorId};
175 return {streamId, dataProcessorId};
176 }
177
179 {
180 return InstanceId{type.hash ^ valueFromSalt(salt)};
181 }
182
184 {
185 static_assert(MAX_SERVICES_MASK < 0x7FFFFFFF, "MAX_SERVICES_MASK must be smaller than 0x7FFFFFFF");
186 return Index{static_cast<int32_t>(id.id & MAX_SERVICES_MASK)};
187 }
188
190 mutable std::vector<ServicePostRenderGUIHandle> mPostRenderGUIHandles;
191
193 void throwError(const char* name, int64_t hash, int64_t streamId, int64_t dataprocessorId) const;
194
195 public:
196 using hash_type = decltype(TypeIdHelpers::uniqueId<void>());
198
201
204
208
217 void declareService(ServiceSpec const& spec, DeviceState& state, fair::mq::ProgOptions& options, ServiceRegistry::Salt salt = ServiceRegistry::globalDeviceSalt());
218
219 void bindService(ServiceRegistry::Salt salt, ServiceSpec const& spec, void* service) const;
220
221 void lateBindStreamServices(DeviceState& state, fair::mq::ProgOptions& options, ServiceRegistry::Salt salt);
222
227 void registerService(ServiceTypeHash typeHash, void* service, ServiceKind kind, Salt salt, char const* name = nullptr, ServiceRegistry::SpecIndex specIndex = SpecIndex{-1}) const;
228
229 // Lookup a given @a typeHash for a given @a threadId at
230 // a unique (per typeHash) location. There might
231 // be other typeHash which sit in the same place, but
232 // the if statement will rule them out. As long as
233 // only one thread writes in a given i + id location
234 // as guaranteed by the atomic, mServicesKey[i + id] will
235 // either be 0 or the final value.
236 // This method should NEVER register a new service, event when requested.
237 int getPos(ServiceTypeHash typeHash, Salt salt) const;
238
239 // Basic, untemplated API. This will require explicitly
240 // providing the @a typeHash for the Service type,
241 // there @a threadId of the thread asking the service
242 // and the @a kind of service. This
243 // method might trigger the registering of a new service
244 // if the service is not a stream service and the global
245 // zero service is available.
246 // Use this API only if you know what you are doing.
247 void* get(ServiceTypeHash typeHash, Salt salt, ServiceKind kind, char const* name = nullptr) const;
248
251 {
252 ServiceRegistry::registerService({handle.hash}, handle.instance, handle.kind, salt, handle.name.c_str());
253 }
254
255 mutable std::vector<ServiceSpec> mSpecs;
256 mutable std::array<std::atomic<Key>, MAX_SERVICES + MAX_DISTANCE> mServicesKey;
257 mutable std::array<void*, MAX_SERVICES + MAX_DISTANCE> mServicesValue;
258 mutable std::array<Meta, MAX_SERVICES + MAX_DISTANCE> mServicesMeta;
259 mutable std::array<std::atomic<bool>, MAX_SERVICES + MAX_DISTANCE> mServicesBooked;
260 mutable std::recursive_mutex mMutex;
261 mutable int64_t mLastLock = -1;
262 mutable std::atomic<int> lockCounter = {0};
263
265 template <class I, class C, enum ServiceKind K = ServiceKind::Serial>
266 requires std::is_base_of_v<I, C>
268 {
269 // This only works for concrete implementations of the type T.
270 // We need type elision as we do not want to know all the services in
271 // advance
272 constexpr ServiceTypeHash typeHash{TypeIdHelpers::uniqueId<I>()};
273 ServiceRegistry::registerService(typeHash, reinterpret_cast<void*>(service), K, salt, typeid(C).name());
274 }
275
277 template <class I, class C, enum ServiceKind K = ServiceKind::Serial>
278 requires std::is_base_of_v<I, C>
280 {
281 // This only works for concrete implementations of the type T.
282 // We need type elision as we do not want to know all the services in
283 // advance
284 constexpr ServiceTypeHash typeHash{TypeIdHelpers::uniqueId<I const>()};
285 this->registerService(typeHash, reinterpret_cast<void*>(const_cast<C*>(service)), K, salt, typeid(C).name());
286 }
287
289 template <typename T>
290 requires(std::is_const_v<T> == false)
291 bool active(Salt salt) const
292 {
293 constexpr ServiceTypeHash typeHash{TypeIdHelpers::uniqueId<T>()};
294 if (this->getPos(typeHash, GLOBAL_CONTEXT_SALT) != -1) {
295 return true;
296 }
297 auto result = this->getPos(typeHash, salt) != -1;
298 return result;
299 }
300
304 template <typename T>
305 T& get(Salt salt) const
306 {
307 constexpr ServiceTypeHash typeHash{TypeIdHelpers::uniqueId<T>()};
308 auto ptr = this->get(typeHash, salt, ServiceKindExtractor<T>::kind, typeid(T).name());
309 if (O2_BUILTIN_LIKELY(ptr != nullptr)) {
310 if constexpr (std::is_const_v<T>) {
311 return *reinterpret_cast<T const*>(ptr);
312 } else {
313 return *reinterpret_cast<T*>(ptr);
314 }
315 }
316 throwError(typeid(T).name(), typeHash.hash, salt.streamId, salt.dataProcessorId);
318 }
319
326 void lock(Salt salt) const O2_DPL_ACQUIRE(mMutex);
327
330 void unlock(Salt salt) const O2_DPL_RELEASE(mMutex);
331};
332
333} // namespace o2::framework
334
335#endif // O2_FRAMEWORK_SERVICEREGISTRY_H_
benchmark::State & state
#define O2_BUILTIN_UNREACHABLE
#define O2_BUILTIN_LIKELY(x)
TBranch * ptr
#define O2_DPL_ACQUIRE(...)
#define O2_DPL_RELEASE(...)
#define O2_DPL_CAPABILITY(x)
StringRef key
service_ptr(service_ptr< T, LOCKING > const &)=delete
service_ptr(T *ptr, LOCKING policy)
service_ptr & operator=(service_ptr< T, LOCKING > const &)=delete
GLuint64EXT * result
Definition glcorearb.h:5662
GLuint index
Definition glcorearb.h:781
GLuint const GLchar * name
Definition glcorearb.h:781
GLint GLint GLsizei GLint GLenum GLenum type
Definition glcorearb.h:275
Defining PrimaryVertex explicitly as messageable.
Definition TFIDInfo.h:20
ServiceKind
The kind of service we are asking for.
constexpr ServiceKind service_kind_v
Defining DataPointCompositeObject explicitly as copiable.
Running state information of a given device.
Definition DeviceState.h:34
ServiceKind kind
Kind of service.
void * instance
Type erased pointer to a service.
unsigned int hash
Unique hash associated to the type of service.
std::string name
Mnemonic name to use for the service.
static constexpr ServiceKind kind
std::array< std::atomic< Key >, MAX_SERVICES+MAX_DISTANCE > mServicesKey
void unlock(Salt salt) const O2_DPL_RELEASE(mMutex)
static constexpr Salt GLOBAL_CONTEXT_SALT
std::vector< ServiceSpec > mSpecs
static Salt streamSalt(short streamId, short dataProcessorId)
std::array< void *, MAX_SERVICES+MAX_DISTANCE > mServicesValue
void registerService(C const *service, Salt salt=ServiceRegistry::globalDeviceSalt())
decltype(TypeIdHelpers::uniqueId< void >()) hash_type
static constexpr int32_t MAX_DISTANCE
The maximum distance a entry can be from the optimal slot.
static constexpr int32_t valueFromSalt(Salt salt)
void lateBindStreamServices(DeviceState &state, fair::mq::ProgOptions &options, ServiceRegistry::Salt salt)
void declareService(ServiceSpec const &spec, DeviceState &state, fair::mq::ProgOptions &options, ServiceRegistry::Salt salt=ServiceRegistry::globalDeviceSalt())
void registerService(ServiceHandle handle, Salt salt=ServiceRegistry::globalDeviceSalt())
Register a service given an handle.
static Salt globalStreamSalt(short streamId)
void registerService(ServiceTypeHash typeHash, void *service, ServiceKind kind, Salt salt, char const *name=nullptr, ServiceRegistry::SpecIndex specIndex=SpecIndex{-1}) const
int getPos(ServiceTypeHash typeHash, Salt salt) const
ServiceRegistry & operator=(ServiceRegistry const &other)
void preExitCallbacks()
Invoke callbacks on exit.
bool active(Salt salt) const
Check if service of type T is currently active.
constexpr Index indexFromInstance(InstanceId id) const
static constexpr uint32_t MAX_SERVICES
The number of slots in the hashmap.
void bindService(ServiceRegistry::Salt salt, ServiceSpec const &spec, void *service) const
static constexpr uint64_t valueFromKey(Key key)
void throwError(const char *name, int64_t hash, int64_t streamId, int64_t dataprocessorId) const
To hide exception throwing from QC.
std::array< Meta, MAX_SERVICES+MAX_DISTANCE > mServicesMeta
void * get(ServiceTypeHash typeHash, Salt salt, ServiceKind kind, char const *name=nullptr) const
std::vector< ServicePostRenderGUIHandle > mPostRenderGUIHandles
Callbacks to be executed after the main GUI has been drawn.
void lock(Salt salt) const O2_DPL_ACQUIRE(mMutex)
std::array< std::atomic< bool >, MAX_SERVICES+MAX_DISTANCE > mServicesBooked
static Salt dataProcessorSalt(short dataProcessorId)
static constexpr uint32_t MAX_SERVICES_MASK
The mask to use to calculate the initial slot id.
constexpr InstanceId instanceFromTypeSalt(ServiceTypeHash type, Salt salt) const
void registerService(C *service, Salt salt=ServiceRegistry::globalDeviceSalt())
VectorOfTObjectPtrs other