Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-01-18 10:01:39

0001 
0002 // Copyright 2020, Jefferson Science Associates, LLC.
0003 // Subject to the terms in the LICENSE file found in the top-level directory.
0004 
0005 
0006 #ifndef JANA2_JEVENTGROUPTRACKER_H
0007 #define JANA2_JEVENTGROUPTRACKER_H
0008 
0009 #include <JANA/Services/JServiceLocator.h>
0010 #include <JANA/JObject.h>
0011 
0012 #include <atomic>
0013 #include <thread>
0014 
0015 /// A persistent JObject
0016 class JEventGroup : public JObject {
0017 
0018     const int m_group_id;
0019     mutable std::atomic_int m_events_in_flight;
0020     mutable std::atomic_bool m_group_closed;
0021 
0022     friend class JEventGroupManager;
0023 
0024     /// Construction of JEventGroup is restricted to JEventGroupManager. This enforces the
0025     /// invariant that pointer equality <=> group_id, assuming a singleton JEventGroupManager.
0026     explicit JEventGroup(int group_id) : m_group_id(group_id),
0027                                          m_events_in_flight(0),
0028                                          m_group_closed(true) {}
0029 
0030 public:
0031 
0032     /// Report back what group this actual is. This is mostly for debugging purposes.
0033     int GetGroupId() const {
0034         return m_group_id;
0035     }
0036 
0037     /// Record that another event belonging to this group has been emitted.
0038     /// This is meant to be called from JEventSource::GetEvent.
0039     void StartEvent() const {
0040         m_events_in_flight += 1;
0041         m_group_closed = false;
0042     }
0043 
0044     /// Report an event as finished. If this was the last event in the group, IsGroupFinished will now return true.
0045     /// Please only call once per event, so that we don't have to maintain a set of outstanding event ids.
0046     /// This takes advantage of C++ atomics to detect if _we_ were the one who finished the whole group without
0047     /// needing a lock.
0048     /// This is meant to be called from JEventProcessor::Process.
0049     bool FinishEvent() const {
0050         auto prev_events_in_flight = m_events_in_flight.fetch_sub(1);
0051         assert(prev_events_in_flight > 0); // detect if someone is miscounting
0052         return (prev_events_in_flight == 1) && m_group_closed;
0053     }
0054 
0055     /// Indicate that no more events in the group are on their way. Note that groups can be re-opened
0056     /// by simply emitting another event tagged according to that group.
0057     /// This is meant to be called from JEventSource::GetEvent.
0058     void CloseGroup() const {
0059         m_group_closed = true;
0060     }
0061 
0062     /// Test whether all events in the group have finished. Two conditions have to hold:
0063     /// 1. The number of in-flight events must be zero
0064     /// 2. The group must be closed. Otherwise, if the JEventSource is slow but the JEventProcessor is fast,
0065     ///    the number of in-flight events could drop to zero before the group is conceptually finished.
0066     /// This is meant to be callable from any JANA component.
0067     /// Note that this doesn't indicate anything about _who_
0068     bool IsGroupFinished() const {
0069         return m_group_closed && (m_events_in_flight == 0);
0070     }
0071 
0072     /// Block until every event in this group has finished, and the eventsource has declared the group closed.
0073     /// This is meant to be callable from any JANA component.
0074     void WaitUntilGroupFinished() {
0075         while (!(m_group_closed && (m_events_in_flight == 0))) {
0076             std::this_thread::sleep_for(std::chrono::milliseconds(10));
0077         }
0078     }
0079 };
0080 
0081 /// JEventGroupManager is a JService which
0082 /// The purpose of JEventGroupManager is to
0083 /// 1. Maintain ownership over all JEventGroup objects, ensuring that the pointers live the entire
0084 ///    duration of JApplication::Run() and are always deleted afterwards.
0085 /// 2. Enforce the invariant where any two objects with the same identity (i.e. pointer equality) have
0086 ///    equal group ids. This makes debugging much easier.
0087 /// 3. Encourage the practice of keeping state which is shared between different JEvents _explicit_ by using JServices.
0088 
0089 class JEventGroupManager final : public JService {
0090 
0091     std::mutex m_mutex;
0092     std::map<int, JEventGroup*> m_eventgroups;
0093 
0094 public:
0095     ~JEventGroupManager() final {
0096         for (auto item : m_eventgroups) {
0097             delete item.second;
0098         }
0099     }
0100 
0101     JEventGroup* GetEventGroup(int group_id) {
0102         std::lock_guard<std::mutex> lock(m_mutex);
0103         auto result = m_eventgroups.find(group_id);
0104         if (result == m_eventgroups.end()) {
0105             auto* eg = new JEventGroup(group_id);
0106             m_eventgroups.insert(std::make_pair(group_id, eg));
0107             return eg;
0108         }
0109         else {
0110             return result->second;
0111         }
0112     }
0113 
0114 };
0115 
0116 
0117 #endif //JANA2_JEVENTGROUPTRACKER_H