diff --git a/CMakeLists.txt b/CMakeLists.txt index 90d75dde6..07baa2e65 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.16) cmake_policy(SET CMP0074 NEW) # find_package() uses _ROOT implicit hints -project(jana2 VERSION 2.1.2) +project(jana2 VERSION 2.2.0) set(CMAKE_POSITION_INDEPENDENT_CODE ON) # Enable -fPIC for all targets diff --git a/src/examples/TimesliceExample/MyClusterFactory.h b/src/examples/TimesliceExample/MyClusterFactory.h index 57f849c0e..e871ff486 100644 --- a/src/examples/TimesliceExample/MyClusterFactory.h +++ b/src/examples/TimesliceExample/MyClusterFactory.h @@ -9,8 +9,8 @@ struct MyClusterFactory : public JOmniFactory { - PodioInput m_protoclusters_in {this, "evt_protoclusters"}; - PodioOutput m_clusters_out {this, "clusters"}; + PodioInput m_protoclusters_in {this}; + PodioOutput m_clusters_out {this}; void Configure() { diff --git a/src/examples/TimesliceExample/MyFileReaderGenerator.h b/src/examples/TimesliceExample/MyFileReaderGenerator.h index 85c3bd7a8..14181c4f0 100644 --- a/src/examples/TimesliceExample/MyFileReaderGenerator.h +++ b/src/examples/TimesliceExample/MyFileReaderGenerator.h @@ -8,6 +8,7 @@ class MyFileReaderGenerator : public JEventSourceGenerator { JEventSource* MakeJEventSource(std::string resource_name) override { auto source = new MyFileReader; + source->SetResourceName(resource_name); // Check if the string "timeslices" appears anywhere in our filename. // If so, we assume the file contains timeslices, otherwise it contains physics events. diff --git a/src/examples/TimesliceExample/MyFileWriter.h b/src/examples/TimesliceExample/MyFileWriter.h index c2cca798d..c7f1301e8 100644 --- a/src/examples/TimesliceExample/MyFileWriter.h +++ b/src/examples/TimesliceExample/MyFileWriter.h @@ -16,13 +16,15 @@ struct MyFileWriter : public JEventProcessor { // Trigger the creation of clusters - PodioInput m_evt_clusters_in {this, "clusters"}; + PodioInput m_evt_clusters_in {this, {.name="clusters"}}; // Retrieve the PODIO frame so we can write it directly - Input m_evt_frame_in {this, "", JEventLevel::PhysicsEvent}; + Input m_evt_frame_in {this, {.name = "", + .level = JEventLevel::PhysicsEvent}}; - // TODO: Support optional inputs - // Input m_ts_frame_in {this, "", JEventLevel::Timeslice}; + Input m_ts_frame_in {this, {.name = "", + .level = JEventLevel::Timeslice, + .is_optional = true }}; std::unique_ptr m_writer = nullptr; std::mutex m_mutex; @@ -44,9 +46,7 @@ struct MyFileWriter : public JEventProcessor { auto ts_nr = ts.GetEventNumber(); if (event->GetEventIndex() == 0) { - // m_writer->writeFrame(*(m_ts_frame_in().at(0)), "timeslices"); - auto ts_frame_in = ts.Get(); - m_writer->writeFrame(*(ts_frame_in.at(0)), "timeslices"); + m_writer->writeFrame(*(m_ts_frame_in().at(0)), "timeslices"); } LOG_DEBUG(GetLogger()) diff --git a/src/examples/TimesliceExample/MyProtoclusterFactory.h b/src/examples/TimesliceExample/MyProtoclusterFactory.h index c1039957c..85a62ff89 100644 --- a/src/examples/TimesliceExample/MyProtoclusterFactory.h +++ b/src/examples/TimesliceExample/MyProtoclusterFactory.h @@ -9,8 +9,8 @@ struct MyProtoclusterFactory : public JOmniFactory { - PodioInput hits_in {this, "hits"}; - PodioOutput clusters_out {this, "protoclusters"}; + PodioInput hits_in {this}; + PodioOutput clusters_out {this}; void Configure() { } diff --git a/src/examples/TimesliceExample/MyTimesliceSplitter.h b/src/examples/TimesliceExample/MyTimesliceSplitter.h index 34094d6d2..ac4249334 100644 --- a/src/examples/TimesliceExample/MyTimesliceSplitter.h +++ b/src/examples/TimesliceExample/MyTimesliceSplitter.h @@ -10,7 +10,8 @@ struct MyTimesliceSplitter : public JEventUnfolder { - PodioInput m_timeslice_clusters_in {this, "ts_protoclusters", JEventLevel::Timeslice}; + PodioInput m_timeslice_clusters_in {this, {.name = "ts_protoclusters", + .level = JEventLevel::Timeslice}}; PodioOutput m_event_clusters_out {this, "evt_protoclusters"}; PodioOutput m_event_info_out {this, "evt_info"}; diff --git a/src/examples/TimesliceExample/TimesliceExample.cc b/src/examples/TimesliceExample/TimesliceExample.cc index 45ec694f8..4ce44fecd 100644 --- a/src/examples/TimesliceExample/TimesliceExample.cc +++ b/src/examples/TimesliceExample/TimesliceExample.cc @@ -33,22 +33,22 @@ void InitPlugin(JApplication *app) { app->Add(new JOmniFactoryGeneratorT( { .tag = "timeslice_protoclusterizer", .level = JEventLevel::Timeslice, - .input_tags = {"hits"}, - .output_tags = {"ts_protoclusters"} + .input_names = {"hits"}, + .output_names = {"ts_protoclusters"} })); // Factory that produces event-level protoclusters from event-level hits app->Add(new JOmniFactoryGeneratorT( { .tag = "event_protoclusterizer", - .input_tags = {"hits"}, - .output_tags = {"evt_protoclusters"}} + .input_names = {"hits"}, + .output_names = {"evt_protoclusters"}} )); // Factory that produces event-level clusters from event-level protoclusters app->Add(new JOmniFactoryGeneratorT( { .tag = "clusterizer", - .input_tags = {"evt_protoclusters"}, - .output_tags = {"clusters"}} + .input_names = {"evt_protoclusters"}, + .output_names = {"clusters"}} )); diff --git a/src/libraries/JANA/JEvent.h b/src/libraries/JANA/JEvent.h index 29e601047..2fa573c4f 100644 --- a/src/libraries/JANA/JEvent.h +++ b/src/libraries/JANA/JEvent.h @@ -80,13 +80,13 @@ class JEvent : public std::enable_shared_from_this //OBJECTS // C style getters template JFactoryT* Get(const T** item, const std::string& tag="") const; - template JFactoryT* Get(std::vector &vec, const std::string& tag = "") const; + template JFactoryT* Get(std::vector &vec, const std::string& tag = "", bool strict=true) const; template void GetAll(std::vector &vec) const; // C++ style getters template const T* GetSingle(const std::string& tag = "") const; template const T* GetSingleStrict(const std::string& tag = "") const; - template std::vector Get(const std::string& tag = "") const; + template std::vector Get(const std::string& tag = "", bool strict=true) const; template typename JFactoryT::PairType GetIterators(const std::string& aTag = "") const; template std::vector GetAll() const; template std::map,std::vector> GetAllChildren() const; @@ -336,9 +336,10 @@ JFactoryT* JEvent::Get(const T** destination, const std::string& tag) const template -JFactoryT* JEvent::Get(std::vector& destination, const std::string& tag) const +JFactoryT* JEvent::Get(std::vector& destination, const std::string& tag, bool strict) const { - auto factory = GetFactory(tag, true); + auto factory = GetFactory(tag, strict); + if (factory == nullptr) return nullptr; // Will have thrown already if strict==true JCallGraphEntryMaker cg_entry(mCallGraph, factory); // times execution until this goes out of scope auto iterators = factory->CreateAndGetData(this->shared_from_this()); for (auto it=iterators.first; it!=iterators.second; it++) { @@ -392,12 +393,13 @@ template const T* JEvent::GetSingleStrict(const std::string& tag) const template -std::vector JEvent::Get(const std::string& tag) const { +std::vector JEvent::Get(const std::string& tag, bool strict) const { - auto factory = GetFactory(tag, true); + auto factory = GetFactory(tag, strict); + std::vector vec; + if (factory == nullptr) return vec; // Will have thrown already if strict==true JCallGraphEntryMaker cg_entry(mCallGraph, factory); // times execution until this goes out of scope auto iters = factory->CreateAndGetData(this->shared_from_this()); - std::vector vec; for (auto it=iters.first; it!=iters.second; ++it) { vec.push_back(*it); } diff --git a/src/libraries/JANA/JEventSource.h b/src/libraries/JANA/JEventSource.h index 60b8418bf..731f6aedb 100644 --- a/src/libraries/JANA/JEventSource.h +++ b/src/libraries/JANA/JEventSource.h @@ -111,12 +111,24 @@ class JEventSource : public jana::omni::JComponent, public jana::omni::JHasOutpu std::lock_guard lock(m_mutex); if (m_status == Status::Uninitialized) { Open(); + if (GetResourceName().empty()) { + LOG_INFO(GetLogger()) << "Opened event source" << LOG_END; + } + else { + LOG_INFO(GetLogger()) << "Opened event source '" << GetResourceName() << "'" << LOG_END; + } m_status = Status::Initialized; } } else { if (m_status == Status::Uninitialized) { Open(); + if (GetResourceName().empty()) { + LOG_INFO(GetLogger()) << "Opened event source" << LOG_END; + } + else { + LOG_INFO(GetLogger()) << "Opened event source '" << GetResourceName() << "'" << LOG_END; + } m_status = Status::Initialized; } } @@ -147,10 +159,22 @@ class JEventSource : public jana::omni::JComponent, public jana::omni::JHasOutpu if (with_lock) { std::lock_guard lock(m_mutex); Close(); + if (GetResourceName().empty()) { + LOG_INFO(GetLogger()) << "Closed event source" << LOG_END; + } + else { + LOG_INFO(GetLogger()) << "Closed event source '" << GetResourceName() << "'" << LOG_END; + } m_status = Status::Finalized; } else { Close(); + if (GetResourceName().empty()) { + LOG_INFO(GetLogger()) << "Closed event source" << LOG_END; + } + else { + LOG_INFO(GetLogger()) << "Closed event source '" << GetResourceName() << "'" << LOG_END; + } m_status = Status::Finalized; } } diff --git a/src/libraries/JANA/JService.cc b/src/libraries/JANA/JService.cc index 6ac7f2241..5438d1ba7 100644 --- a/src/libraries/JANA/JService.cc +++ b/src/libraries/JANA/JService.cc @@ -7,6 +7,7 @@ void JService::DoInit(JServiceLocator* sl) { std::lock_guard lock(m_mutex); + if (this->m_status != Status::Uninitialized) return; try { for (auto* parameter : m_parameters) { parameter->Configure(*(m_app->GetJParameterManager()), m_prefix); diff --git a/src/libraries/JANA/Omni/JHasInputs.h b/src/libraries/JANA/Omni/JHasInputs.h index 89c7d3d50..7c6161ba4 100644 --- a/src/libraries/JANA/Omni/JHasInputs.h +++ b/src/libraries/JANA/Omni/JHasInputs.h @@ -20,12 +20,61 @@ struct JHasInputs { void RegisterInput(InputBase* input) { m_inputs.push_back(input); } + + struct InputOptions { + std::string name {""}; + JEventLevel level {JEventLevel::None}; + bool is_optional {false}; + // bool is_shortcircuiting {false}; + // bool contains_single_item {false}; + }; + + struct VariadicInputOptions { + std::vector names {""}; + std::vector levels {JEventLevel::None}; + bool is_optional {false}; + // bool is_shortcircuiting {false}; + // bool contains_single_item {false}; + }; struct InputBase { std::string type_name; - std::vector collection_names; - std::vector collection_levels; + std::vector names; + std::vector levels; bool is_variadic = false; + bool is_optional = false; + //bool is_shortcircuiting = false; + //bool contains_single_item = false; + + + void Configure(const InputOptions& options) { + this->names.clear(); + this->names.push_back(options.name); + this->levels.clear(); + this->levels.push_back(options.level); + this->is_optional = options.is_optional; + // this->is_shortcircuiting = options.is_shortcircuiting; + // this->contains_single_item = options.contains_single_item; + } + + void ConfigureVariadic(const VariadicInputOptions& options) { + if (!is_variadic) { throw JException("Setting variadic options on non-variadic input"); } + this->names = options.names; + if (options.levels.size() == options.names.size()) { + this->levels = options.levels; + } + else if (options.levels.size() == 0) { + for (size_t i=0; ilevels.push_back(JEventLevel::None); + } + } + else { + throw JException("Wrong number of levels provided!"); + } + this->is_optional = options.is_optional; + // this->is_shortcircuiting = options.is_shortcircuiting; + // this->contains_single_item = options.contains_single_item; + } virtual void GetCollection(const JEvent& event) = 0; virtual void PrefetchCollection(const JEvent& event) = 0; @@ -37,35 +86,43 @@ struct JHasInputs { std::vector m_data; public: - Input(JHasInputs* owner, std::string default_tag="", JEventLevel level=JEventLevel::None) { + + Input(JHasInputs* owner) { owner->RegisterInput(this); - this->collection_names.push_back(default_tag); this->type_name = JTypeInfo::demangle(); - this->collection_levels.push_back(level); + } + + Input(JHasInputs* owner, const InputOptions& options) { + owner->RegisterInput(this); + this->type_name = JTypeInfo::demangle(); + Configure(options); } const std::vector& operator()() { return m_data; } + private: friend class JComponentT; void GetCollection(const JEvent& event) { - auto& level = this->collection_levels[0]; + auto& level = this->levels[0]; if (level == event.GetLevel() || level == JEventLevel::None) { - m_data = event.Get(this->collection_names[0]); + m_data = event.Get(this->names[0], !this->is_optional); } else { - m_data = event.GetParent(level).template Get(this->collection_names[0]); + if (this->is_optional && !event.HasParent(level)) return; + m_data = event.GetParent(level).template Get(this->names[0], !this->is_optional); } } void PrefetchCollection(const JEvent& event) { - auto& level = this->collection_levels[0]; - auto& name = this->collection_names[0]; + auto& level = this->levels[0]; + auto& name = this->names[0]; if (level == event.GetLevel() || level == JEventLevel::None) { - event.Get(name); + event.Get(name, !this->is_optional); } else { - event.GetParent(level).template Get(name); + if (this->is_optional && !event.HasParent(level)) return; + event.GetParent(level).template Get(name, !this->is_optional); } } }; @@ -78,11 +135,15 @@ struct JHasInputs { public: - PodioInput(JHasInputs* owner, std::string default_collection_name="", JEventLevel level=JEventLevel::None) { + PodioInput(JHasInputs* owner) { + owner->RegisterInput(this); + this->type_name = JTypeInfo::demangle(); + } + + PodioInput(JHasInputs* owner, const InputOptions& options) { owner->RegisterInput(this); - this->collection_names.push_back(default_collection_name); - this->collection_levels.push_back(level); this->type_name = JTypeInfo::demangle(); + Configure(options); } const typename PodioTypeMap::collection_t* operator()() { @@ -90,24 +151,26 @@ struct JHasInputs { } void GetCollection(const JEvent& event) { - auto& level = this->collection_levels[0]; - auto& name = this->collection_names[0]; + auto& level = this->levels[0]; + auto& name = this->names[0]; if (level == event.GetLevel() || level == JEventLevel::None) { - m_data = event.GetCollection(name); + m_data = event.GetCollection(name, !this->is_optional); } else { - m_data = event.GetParent(level).template GetCollection(name); + if (this->is_optional && !event.HasParent(level)) return; + m_data = event.GetParent(level).template GetCollection(name, !this->is_optional); } } void PrefetchCollection(const JEvent& event) { - auto& level = this->collection_levels[0]; - auto& name = this->collection_names[0]; + auto& level = this->levels[0]; + auto& name = this->names[0]; if (level == event.GetLevel() || level == JEventLevel::None) { - event.GetCollection(name); + event.GetCollection(name, !this->is_optional); } else { - event.GetParent(level).template GetCollection(name); + if (this->is_optional && !event.HasParent(level)) return; + event.GetParent(level).template GetCollection(name, !this->is_optional); } } }; @@ -120,14 +183,17 @@ struct JHasInputs { public: - VariadicPodioInput(JHasInputs* owner, std::vector default_names={}, JEventLevel level=JEventLevel::None) { + VariadicPodioInput(JHasInputs* owner) { owner->RegisterInput(this); - this->collection_names = default_names; this->type_name = JTypeInfo::demangle(); this->is_variadic = true; - for (int i=0; icollection_levels.push_back(level); - } + } + + VariadicPodioInput(JHasInputs* owner, const VariadicInputOptions& options) { + owner->RegisterInput(this); + this->type_name = JTypeInfo::demangle(); + this->is_variadic = true; + ConfigureVariadic(options); } const std::vector::collection_t*> operator()() { @@ -136,33 +202,35 @@ struct JHasInputs { void GetCollection(const JEvent& event) { m_data.clear(); - if (collection_names.size() != collection_levels.size()) { - throw JException("Misconfigured VariadicPodioInput: collection_names.size()=%d, collection_levels.size()=%d", collection_names.size(), collection_levels.size()); + if (names.size() != levels.size()) { + throw JException("Misconfigured VariadicPodioInput: names.size()=%d, levels.size()=%d", names.size(), levels.size()); } - for (size_t i=0; i(coll_name)); + m_data.push_back(event.GetCollection(coll_name, !this->is_optional)); } else { - m_data.push_back(event.GetParent(level).GetCollection(coll_name)); + if (this->is_optional && !event.HasParent(level)) return; + m_data.push_back(event.GetParent(level).GetCollection(coll_name, !this->is_optional)); } } } void PrefetchCollection(const JEvent& event) { - if (collection_names.size() != collection_levels.size()) { - throw JException("Misconfigured VariadicPodioInput: collection_names.size()=%d, collection_levels.size()=%d", collection_names.size(), collection_levels.size()); + if (names.size() != levels.size()) { + throw JException("Misconfigured VariadicPodioInput: names.size()=%d, levels.size()=%d", names.size(), levels.size()); } - for (size_t i=0; i(coll_name); + event.GetCollection(coll_name, !this->is_optional); } else { - event.GetParent(level).GetCollection(coll_name); + if (this->is_optional && !event.HasParent(level)) return; + event.GetParent(level).GetCollection(coll_name, !this->is_optional); } } } diff --git a/src/libraries/JANA/Omni/JOmniFactory.h b/src/libraries/JANA/Omni/JOmniFactory.h index 02b463257..e955dde64 100644 --- a/src/libraries/JANA/Omni/JOmniFactory.h +++ b/src/libraries/JANA/Omni/JOmniFactory.h @@ -222,25 +222,25 @@ class JOmniFactory : public JMultifactory, public jana::omni::JHasInputs { // Set input collection names size_t i = 0; for (auto* input : m_inputs) { - input->collection_names.clear(); + input->names.clear(); if (input->is_variadic) { for (size_t j = 0; j<(variadic_input_collection_count/variadic_input_count); ++j) { - input->collection_names.push_back(input_collection_names[i++]); + input->names.push_back(input_collection_names[i++]); if (!input_collection_levels.empty()) { - input->collection_levels.push_back(input_collection_levels[i++]); + input->levels.push_back(input_collection_levels[i++]); } else { - input->collection_levels.push_back(level); + input->levels.push_back(level); } } } else { - input->collection_names.push_back(input_collection_names[i++]); + input->names.push_back(input_collection_names[i++]); if (!input_collection_levels.empty()) { - input->collection_levels.push_back(input_collection_levels[i++]); + input->levels.push_back(input_collection_levels[i++]); } else { - input->collection_levels.push_back(level); + input->levels.push_back(level); } } } diff --git a/src/libraries/JANA/Omni/JOmniFactoryGeneratorT.h b/src/libraries/JANA/Omni/JOmniFactoryGeneratorT.h index a1051e610..44e3e5bba 100644 --- a/src/libraries/JANA/Omni/JOmniFactoryGeneratorT.h +++ b/src/libraries/JANA/Omni/JOmniFactoryGeneratorT.h @@ -16,18 +16,18 @@ class JOmniFactoryGeneratorT : public JFactoryGenerator { struct TypedWiring { std::string tag = ""; JEventLevel level = JEventLevel::PhysicsEvent; - std::vector input_tags = {}; + std::vector input_names = {}; std::vector input_levels = {}; - std::vector output_tags = {}; + std::vector output_names = {}; FactoryConfigType configs = {}; /// Must be copyable! }; struct UntypedWiring { std::string tag = ""; JEventLevel level = JEventLevel::PhysicsEvent; - std::vector input_tags = {}; + std::vector input_names = {}; std::vector input_levels = {}; - std::vector output_tags = {}; + std::vector output_names = {}; std::map configs = {}; }; @@ -36,24 +36,23 @@ class JOmniFactoryGeneratorT : public JFactoryGenerator { explicit JOmniFactoryGeneratorT() = default; explicit JOmniFactoryGeneratorT(std::string tag, - std::vector default_input_tags, - std::vector default_output_tags, + std::vector input_names, + std::vector output_names, FactoryConfigType configs) { m_typed_wirings.push_back({.tag=tag, - .input_tags=default_input_tags, - .output_tags=default_output_tags, - .configs=configs - }); + .input_names=input_names, + .output_names=output_names, + .configs=configs + }); }; explicit JOmniFactoryGeneratorT(std::string tag, - std::vector default_input_tags, - std::vector default_output_tags) { + std::vector input_names, + std::vector output_names) { m_typed_wirings.push_back({.tag=tag, - .input_tags=default_input_tags, - .output_tags=default_output_tags, - .configs={} - }); + .input_names=input_names, + .output_names=output_names + }); } @@ -63,20 +62,20 @@ class JOmniFactoryGeneratorT : public JFactoryGenerator { void AddWiring(std::string tag, - std::vector default_input_tags, - std::vector default_output_tags, + std::vector input_names, + std::vector output_names, FactoryConfigType configs) { - m_typed_wirings.push_back({.m_tag=tag, - .m_default_input_tags=default_input_tags, - .m_default_output_tags=default_output_tags, - .configs=configs - }); + m_typed_wirings.push_back({.tag=tag, + .input_names=input_names, + .output_names=output_names, + .configs=configs + }); } void AddWiring(std::string tag, - std::vector input_tags, - std::vector output_tags, + std::vector input_names, + std::vector output_names, std::map configs={}) { // Create throwaway factory so we can populate its config using our map. @@ -85,10 +84,10 @@ class JOmniFactoryGeneratorT : public JFactoryGenerator { auto configs_typed = factory.config(); m_typed_wirings.push_back({.tag=tag, - .input_tags=input_tags, - .output_tags=output_tags, - .configs=configs_typed - }); + .input_names=input_names, + .output_names=output_names, + .configs=configs_typed + }); } @@ -113,7 +112,7 @@ class JOmniFactoryGeneratorT : public JFactoryGenerator { // Set up all of the wiring prereqs so that Init() can do its thing // Specifically, it needs valid input/output tags, a valid logger, and // valid default values in its Config object - factory->PreInit(wiring.tag, wiring.level, wiring.input_tags, wiring.input_levels, wiring.output_tags); + factory->PreInit(wiring.tag, wiring.level, wiring.input_names, wiring.input_levels, wiring.output_names); // Factory is ready factory_set->Add(factory); diff --git a/src/libraries/JANA/Services/JServiceLocator.h b/src/libraries/JANA/Services/JServiceLocator.h index 7d5414783..21cfd0218 100644 --- a/src/libraries/JANA/Services/JServiceLocator.h +++ b/src/libraries/JANA/Services/JServiceLocator.h @@ -30,16 +30,11 @@ /// but also don't get freed prematurely if a JApplication or JServiceLocator go out of scope. class JServiceLocator { - std::map, std::once_flag*>> underlying; + std::map> underlying; std::mutex mutex; public: - ~JServiceLocator() { - for (auto pair : underlying) { - delete pair.second.second; // Delete each pointer to once_flag - } - } template void provide(std::shared_ptr t) { @@ -51,7 +46,7 @@ class JServiceLocator { std::lock_guard lock(mutex); auto svc = std::dynamic_pointer_cast(t); assert(svc != nullptr); - underlying[std::type_index(typeid(T))] = std::make_pair(svc, new std::once_flag()); + underlying[std::type_index(typeid(T))] = svc; } template @@ -68,12 +63,13 @@ class JServiceLocator { oss << "Service not found: '" << JTypeInfo::demangle() << "'. Did you forget to include a plugin?" << std::endl; throw JException(oss.str()); } - auto& pair = iter->second; - auto& wired = pair.second; - auto ptr = pair.first; - std::call_once(*wired, [&](){ptr->DoInit(this);}); - auto svc = std::static_pointer_cast(ptr); - return svc; + auto svc = iter->second; + svc->DoInit(this); + // Will short-circuit if already initialized + // Note: Requires JApplication to already be set. + + auto svc_typed = std::static_pointer_cast(svc); + return svc_typed; } void wire_everything() { @@ -81,10 +77,8 @@ class JServiceLocator { /// but it makes user errors easier to understand, and it prevents Services from being /// unpredictably finalized later on, particularly during computation. - for (auto& item : underlying) { - auto sharedptr = item.second.first; - auto& wired = item.second.second; - std::call_once(*wired, [&](){sharedptr->DoInit(this);}); + for (auto& entry : underlying) { + entry.second->DoInit(this); } } }; diff --git a/src/libraries/JANA/Utils/JEventLevel.h b/src/libraries/JANA/Utils/JEventLevel.h index 22a10b6c8..4b19b308f 100644 --- a/src/libraries/JANA/Utils/JEventLevel.h +++ b/src/libraries/JANA/Utils/JEventLevel.h @@ -5,7 +5,7 @@ #include #include -enum class JEventLevel { Run, Subrun, Timeslice, Block, PhysicsEvent, Subevent, Task, None }; +enum class JEventLevel { Run, Subrun, SlowControls, Timeslice, Block, PhysicsEvent, Subevent, Task, None }; inline std::ostream& operator<<(std::ostream& os, JEventLevel level) { switch (level) { @@ -13,6 +13,7 @@ inline std::ostream& operator<<(std::ostream& os, JEventLevel level) { case JEventLevel::Subrun: os << "Subrun"; break; case JEventLevel::Timeslice: os << "Timeslice"; break; case JEventLevel::Block: os << "Block"; break; + case JEventLevel::SlowControls: os << "SlowControls"; break; case JEventLevel::PhysicsEvent: os << "PhysicsEvent"; break; case JEventLevel::Subevent: os << "Subevent"; break; case JEventLevel::Task: os << "Task"; break; @@ -33,7 +34,8 @@ inline JEventLevel next_level(JEventLevel current_level) { case JEventLevel::Run: return JEventLevel::Subrun; case JEventLevel::Subrun: return JEventLevel::Timeslice; case JEventLevel::Timeslice: return JEventLevel::Block; - case JEventLevel::Block: return JEventLevel::PhysicsEvent; + case JEventLevel::Block: return JEventLevel::SlowControls; + case JEventLevel::SlowControls: return JEventLevel::PhysicsEvent; case JEventLevel::PhysicsEvent: return JEventLevel::Subevent; case JEventLevel::Subevent: return JEventLevel::Task; case JEventLevel::Task: return JEventLevel::None; diff --git a/src/programs/unit_tests/JServiceLocatorTests.cc b/src/programs/unit_tests/JServiceLocatorTests.cc index 41f00b369..df9b31052 100644 --- a/src/programs/unit_tests/JServiceLocatorTests.cc +++ b/src/programs/unit_tests/JServiceLocatorTests.cc @@ -78,11 +78,14 @@ struct OmniService : public JService { Service parman {this}; Parameter bucket_count {this, "bucket_count", 5, "Some integer representing a bucket count"}; + std::atomic_int init_call_count {0}; void Init() override { LOG_INFO(GetLogger()) << "Calling OmniService::Init" << LOG_END; REQUIRE(parman->GetParameterValue("bucket_count") == 22); REQUIRE(bucket_count() == 22); + REQUIRE(init_call_count == 0); + init_call_count++; } }; @@ -94,5 +97,9 @@ TEST_CASE("JService Omni interface") { auto sut = app.GetService(); REQUIRE(sut->GetStatus() == JService::Status::Initialized); REQUIRE(sut->bucket_count() == 22); + + // Fetch again to make sure Init() is only called once + sut = app.GetService(); + LOG << "Retrieved service " << sut << LOG_END; // Just in case the optimizer tries to get rid of this }