LCOV - code coverage report
Current view: top level - artdaq/ArtModules - ArtdaqSharedMemoryService_service.cc (source / functions) Coverage Total Hit
Test: artdaq.info.cleaned Lines: 0.0 % 203 0
Test Date: 2026-10-29 00:35:58 Functions: 0.0 % 55 0

            Line data    Source code
       1              : #include "TRACE/tracemf.h"
       2              : 
       3              : #include "artdaq/ArtModules/ArtdaqSharedMemoryServiceInterface.h"
       4              : #include "artdaq/DAQdata/Globals.hh"
       5              : 
       6              : #include "artdaq-core/Core/SharedMemoryEventReceiver.hh"
       7              : #include "artdaq-core/Utilities/ExceptionHandler.hh"
       8              : 
       9              : #include "art/Framework/Services/Registry/ServiceDefinitionMacros.h"
      10              : #include "art/Framework/Services/Registry/ServiceHandle.h"
      11              : #include "fhiclcpp/types/Atom.h"
      12              : #include "fhiclcpp/types/Comment.h"
      13              : #include "fhiclcpp/types/ConfigurationTable.h"
      14              : #include "fhiclcpp/types/Name.h"
      15              : 
      16              : #include <cstdint>
      17              : #include <memory>
      18              : 
      19              : #define TRACE_NAME "ArtdaqSharedMemoryService"
      20              : // ----------------------------------------------------------------------
      21              : 
      22              : /**
      23              :  * \brief ArtdaqSharedMemoryService extends ArtdaqSharedMemoryServiceInterface.
      24              :  * It receives events from shared memory using SharedMemoryEventReceiver. It also manages the artdaq Global varaibles my_rank and app_name.
      25              :  * Users should retrieve a ServiceHandle to this class before using artdaq Globals to ensure the correct values are used.
      26              :  */
      27              : class ArtdaqSharedMemoryService : public ArtdaqSharedMemoryServiceInterface
      28              : {
      29              : public:
      30              :         /// <summary>
      31              :         /// Allowed Configuration parameters of NetMonTransportService. May be used for configuration validation
      32              :         /// </summary>
      33              :         struct Config
      34              :         {
      35              :                 /// "shared_memory_key" (Default: 0xBEE70000 + pid): Key to use when connecting to shared memory. Will default to 0xBEE70000 + getppid().
      36              :                 fhicl::Atom<uint32_t> shared_memory_key{fhicl::Name{"shared_memory_key"}, fhicl::Comment{"Key to use when connecting to shared memory. Will default to 0xBEE70000 + getppid()."}, 0xBEE70000};
      37              :                 /// "shared_memory_key" (Default: 0xCEE70000 + pid): Key to use when connecting to broadcast shared memory. Will default to 0xCEE70000 + getppid().
      38              :                 fhicl::Atom<uint32_t> broadcast_shared_memory_key{fhicl::Name{"broadcast_shared_memory_key"}, fhicl::Comment{"Key to use when connecting to broadcast shared memory. Will default to 0xCEE70000 + getppid()."}, 0xCEE70000};
      39              :                 /// "rank" (OPTIONAL) : The rank of this applicaiton, for use by non - artdaq applications running NetMonTransportService
      40              :                 fhicl::Atom<int> rank{fhicl::Name{"rank"}, fhicl::Comment{"Rank of this artdaq application. Used for data transfers"}};
      41              :                 /// "subrun_closure_threshold" (Default: 5) Minimum number of events in event ordering list before releasing a subrun/run change event. -1 to always require safety valve timeout to release subrun/run change events. 0 to always release subrun/run change events immediately.
      42              :                 fhicl::Atom<int> subrun_closure_threshold{fhicl::Name{"subrun_closure_threshold"}, fhicl::Comment{"Minimum number of events in event ordering list before releasing a subrun/run change event"}, 1};
      43              :                 /// "safety_valve_timeout_s" (Default: 10.0): Maximum time (in s) to wait before releasing the front of the event ordering list
      44              :                 fhicl::Atom<double> safety_valve_timeout_s{fhicl::Name{"safety_valve_timeout_s"}, fhicl::Comment{"Maximum time (in s) to wait before releasing the front of the event ordering list"}, 10.0};
      45              :         };
      46              :         /// Used for ParameterSet validation (if desired)
      47              :         using Parameters = fhicl::WrappedTable<Config>;
      48              : 
      49              :         /**
      50              :          * \brief NetMonTransportService Destructor. Calls disconnect().
      51              :          */
      52              :         virtual ~ArtdaqSharedMemoryService();
      53              : 
      54              :         /**
      55              :          * \brief NetMonTransportService Constructor
      56              :          * \param pset ParameterSet used to configure NetMonTransportService and DataSenderManager. See NetMonTransportService::Config
      57              :          */
      58              :         ArtdaqSharedMemoryService(fhicl::ParameterSet const& pset, art::ActivityRegistry&);
      59              : 
      60              :         /**
      61              :          * \brief Receive event(s) from the shared memory
      62              :          * \param broadcast Whether to only attempt to receive a broadcast (broadcasts are always preferentially received over data)
      63              :          * \return Map of Fragment types retrieved from shared memory
      64              :          */
      65              :         std::shared_ptr<ArtdaqEvent> ReceiveEvent(bool broadcast) override;
      66              : 
      67              :         /**
      68              :          * \brief Get the number of events which are ready to be read
      69              :          * \return The number of events which can be read
      70              :          */
      71            0 :         size_t GetQueueSize() override { return incoming_events_->ReadReadyCount(); }
      72              : 
      73              :         /**
      74              :          * \brief Get the maximum number of events which can be stored in the shared memory
      75              :          * \return The maximum number of events which can be stored in the shared memory
      76              :          */
      77            0 :         size_t GetQueueCapacity() override { return incoming_events_->size(); }
      78              : 
      79              :         /**
      80              :          * \brief Get the ID of this art process
      81              :          * \return The ID of this art process from the shared memory segment
      82              :          */
      83            0 :         size_t GetMyId() override { return incoming_events_->GetMyId(); }
      84              : 
      85              : private:
      86              :         ArtdaqSharedMemoryService(ArtdaqSharedMemoryService const&) = delete;
      87              :         ArtdaqSharedMemoryService(ArtdaqSharedMemoryService&&) = delete;
      88              :         ArtdaqSharedMemoryService& operator=(ArtdaqSharedMemoryService const&) = delete;
      89              :         ArtdaqSharedMemoryService& operator=(ArtdaqSharedMemoryService&&) = delete;
      90              : 
      91              :         std::shared_ptr<ArtdaqEvent> ReadEventFromSharedMemory(bool broadcast);
      92              : 
      93              : private:
      94              :         std::unique_ptr<artdaq::SharedMemoryEventReceiver> incoming_events_;
      95              :         std::list<std::shared_ptr<ArtdaqEvent>> event_ordering_;
      96              :         std::set<artdaq::Fragment::sequence_id_t> released_broadcast_sequence_ids_;
      97              :         size_t read_timeout_;
      98              :         int subrun_closure_threshold_{1};
      99              :         double safety_valve_timeout_s_{10.0};
     100              :         bool last_read_timeout_{false};
     101              :         bool resume_after_timeout_;
     102              :         bool printed_exit_message_{false};
     103              :         bool end_of_data_received_{false};
     104              :         bool subrun_has_events_{false};
     105              :         uint32_t current_subrun_{0};
     106              : };
     107              : 
     108            0 : DECLARE_ART_SERVICE_INTERFACE_IMPL(ArtdaqSharedMemoryService, ArtdaqSharedMemoryServiceInterface, LEGACY)
     109              : 
     110              : static fhicl::ParameterSet empty_pset;
     111              : 
     112              : // clang-format off
     113              : #define TLVL_CONSTRUCTOR    TLVL_DEBUG + 32
     114              : #define TLVL_READEVENT      TLVL_DEBUG + 33
     115              : #define TLVL_READEVENT_2    TLVL_DEBUG + 34
     116              : #define TLVL_READEVENT_3    TLVL_DEBUG + 35
     117              : #define TLVL_RECEIVEEVENT   TLVL_DEBUG + 36
     118              : #define TLVL_RECEIVEEVENT_2 TLVL_DEBUG + 37
     119              : #define TLVL_RECEIVEEVENT_3 TLVL_DEBUG + 38
     120              : #define TLVL_RECEIVEEVENT_4 TLVL_DEBUG + 39
     121              : // clang-format on
     122              : 
     123            0 : ArtdaqSharedMemoryService::ArtdaqSharedMemoryService(fhicl::ParameterSet const& pset, art::ActivityRegistry& /*unused*/)
     124            0 :     : incoming_events_(nullptr)
     125            0 :     , event_ordering_()
     126            0 :     , read_timeout_(pset.get<size_t>("read_timeout_us", static_cast<size_t>(pset.get<double>("waiting_time", 600.0) * 1000000)))
     127            0 :     , subrun_closure_threshold_(pset.get<int>("subrun_closure_threshold", artdaq::SharedMemoryManager::GetCatchUpFactor() + 2))  // +2, one for ESRF itself, one for extra padding to ensure that no catch-up is being performed
     128            0 :     , safety_valve_timeout_s_(pset.get<double>("safety_valve_timeout_s", 10.0))
     129            0 :     , resume_after_timeout_(pset.get<bool>("resume_after_timeout", true))
     130              : {
     131            0 :         TLOG(TLVL_CONSTRUCTOR) << "ArtdaqSharedMemoryService CONSTRUCTOR";
     132              : 
     133            0 :         incoming_events_ = std::make_unique<artdaq::SharedMemoryEventReceiver>(
     134            0 :             pset.get<int>("shared_memory_key", artdaq::Globals::SharedMemoryKey(0xEE000000, true)),
     135            0 :             pset.get<int>("broadcast_shared_memory_key", artdaq::Globals::SharedMemoryKey(0xBB000000, true)));
     136              : 
     137            0 :         char const* artapp_env = getenv("ARTDAQ_APPLICATION_NAME");
     138            0 :         std::string artapp_str;
     139            0 :         if (artapp_env != nullptr)
     140              :         {
     141            0 :                 artapp_str = std::string(artapp_env) + "_";
     142              :         }
     143              : 
     144            0 :         TLOG(TLVL_CONSTRUCTOR) << "Setting app_name";
     145            0 :         artdaq::Globals::my_art_id_ = incoming_events_->GetMyId();
     146            0 :         app_name = artapp_str + "art" + std::to_string(artdaq::Globals::my_art_id_);
     147              :         // artdaq::configureMessageFacility(app_name.c_str()); // ELF 11/20/2020: MessageFacility already configured by initialization pset
     148              : 
     149            0 :         artapp_env = getenv("ARTDAQ_RANK");
     150            0 :         if (artapp_env != nullptr && my_rank < 0)
     151              :         {
     152            0 :                 TLOG(TLVL_CONSTRUCTOR) << "Setting rank from envrionment";
     153            0 :                 my_rank = strtol(artapp_env, nullptr, 10);
     154            0 :         }
     155              :         else
     156              :         {
     157            0 :                 TLOG(TLVL_CONSTRUCTOR) << "Setting my_rank from shared memory";
     158            0 :                 my_rank = incoming_events_->GetRank();
     159              :         }
     160              : 
     161              :         try
     162              :         {
     163            0 :                 if (metricMan)
     164              :                 {
     165            0 :                         metricMan->initialize(pset.get<fhicl::ParameterSet>("metrics", fhicl::ParameterSet()), app_name);
     166            0 :                         metricMan->do_start();
     167              :                 }
     168              :         }
     169            0 :         catch (...)
     170              :         {
     171            0 :                 artdaq::ExceptionHandler(artdaq::ExceptionHandlerRethrow::no, "Error loading metrics in ArtdaqSharedMemoryService()");
     172            0 :         }
     173              : 
     174            0 :         TLOG(TLVL_INFO) << "app_name is " << app_name << ", rank " << my_rank;
     175            0 : }
     176              : 
     177            0 : ArtdaqSharedMemoryService::~ArtdaqSharedMemoryService()
     178              : {
     179            0 :         artdaq::Globals::CleanUpGlobals();
     180            0 : }
     181              : 
     182            0 : std::shared_ptr<ArtdaqEvent> ArtdaqSharedMemoryService::ReadEventFromSharedMemory(bool broadcast)
     183              : {
     184            0 :         TLOG(TLVL_READEVENT) << "ReadEventFromSharedMemory BEGIN";
     185            0 :         std::shared_ptr<ArtdaqEvent> output_event;
     186              : 
     187            0 :         while (output_event == nullptr)
     188              :         {
     189            0 :                 TLOG(TLVL_READEVENT_2) << "ReadEventFromSharedMemory: Waiting for available buffer";
     190            0 :                 bool got_event = false;
     191            0 :                 auto start_time = std::chrono::steady_clock::now();
     192            0 :                 auto read_timeout_to_use = read_timeout_ > 100000 ? 100000 : read_timeout_;
     193            0 :                 if (!resume_after_timeout_ || broadcast) read_timeout_to_use = read_timeout_;
     194            0 :                 while (!incoming_events_->IsEndOfData() && !got_event)
     195              :                 {
     196            0 :                         got_event = incoming_events_->ReadyForRead(broadcast, read_timeout_to_use);
     197            0 :                         if (!got_event && (!resume_after_timeout_ || broadcast))  // Only try broadcasts once!
     198              :                         {
     199            0 :                                 TLOG(TLVL_ERROR) << "Timeout occurred! No data received after " << read_timeout_to_use << " us. Returning empty Fragment list!";
     200            0 :                                 last_read_timeout_ = true;
     201            0 :                                 return nullptr;
     202              :                         }
     203            0 :                         if (!got_event && artdaq::TimeUtils::GetElapsedTimeMicroseconds(start_time) > read_timeout_)
     204              :                         {
     205            0 :                                 TLOG(TLVL_READEVENT_2) << "Timeout occurred! No data received after " << artdaq::TimeUtils::GetElapsedTimeMicroseconds(start_time) << " us. Retrying.";
     206            0 :                                 last_read_timeout_ = true;
     207              :                         }
     208              :                 }
     209              : 
     210            0 :                 if (incoming_events_->IsEndOfData())
     211              :                 {
     212            0 :                         if (!printed_exit_message_)
     213              :                         {
     214            0 :                                 TLOG(TLVL_INFO) << "End of Data signal received, exiting";
     215            0 :                                 printed_exit_message_ = true;
     216              :                         }
     217            0 :                         return nullptr;
     218              :                 }
     219              : 
     220            0 :                 TLOG(TLVL_READEVENT) << "ReadEventFromSharedMemory: Reading buffer header";
     221            0 :                 last_read_timeout_ = false;
     222            0 :                 output_event = std::make_shared<ArtdaqEvent>();
     223            0 :                 auto errflag = false;
     224            0 :                 auto hdrPtr = incoming_events_->ReadHeader(errflag);
     225            0 :                 if (errflag || hdrPtr == nullptr)
     226              :                 {  // Buffer was changed out from under reader!
     227            0 :                         incoming_events_->ReleaseBuffer();
     228            0 :                         continue;  // retry
     229              :                 }
     230            0 :                 output_event->header = std::make_shared<artdaq::detail::RawEventHeader>(*hdrPtr);
     231            0 :                 TLOG(TLVL_READEVENT) << "ReadEventFromSharedMemory: Getting Fragment types";
     232            0 :                 auto fragmentTypes = incoming_events_->GetFragmentTypes(errflag);
     233            0 :                 if (errflag)
     234              :                 {  // Buffer was changed out from under reader!
     235            0 :                         incoming_events_->ReleaseBuffer();
     236            0 :                         continue;  // retry
     237              :                 }
     238            0 :                 if (fragmentTypes.empty())
     239              :                 {
     240            0 :                         TLOG(TLVL_ERROR) << "Event has no Fragments! Aborting!";
     241            0 :                         incoming_events_->ReleaseBuffer();
     242            0 :                         return nullptr;
     243              :                 }
     244              : 
     245            0 :                 for (auto const& type : fragmentTypes)
     246              :                 {
     247            0 :                         TLOG(TLVL_READEVENT_3) << "ReadEventFromSharedMemory: Getting all Fragments of type " << static_cast<int>(type);
     248            0 :                         output_event->fragments[type] = incoming_events_->GetFragmentsByType(errflag, type);
     249            0 :                         if (!output_event->fragments[type])
     250              :                         {
     251            0 :                                 TLOG(TLVL_WARNING) << "Error retrieving Fragments from shared memory! (Most likely due to a buffer overwrite) Retrying...";
     252            0 :                                 incoming_events_->ReleaseBuffer();
     253            0 :                                 output_event->fragments.clear();
     254            0 :                                 continue;
     255            0 :                         }
     256              :                         // Events coming out of the EventStore are not sorted but need to be sorted by sequence ID before they can be passed to art.
     257            0 :                         std::sort(output_event->fragments[type]->begin(), output_event->fragments[type]->end(), artdaq::fragmentSequenceIDCompare);
     258              :                 }
     259            0 :                 TLOG(TLVL_READEVENT) << "ReadEventFromSharedMemory: Releasing buffer";
     260            0 :                 incoming_events_->ReleaseBuffer();
     261            0 :         }
     262              : 
     263            0 :         TLOG(TLVL_READEVENT) << "ReadEventFromSharedMemory END";
     264            0 :         return output_event;
     265            0 : }
     266              : 
     267            0 : std::shared_ptr<ArtdaqEvent> ArtdaqSharedMemoryService::ReceiveEvent(bool broadcast)
     268              : {
     269            0 :         TLOG(TLVL_RECEIVEEVENT) << "ReceiveEvent BEGIN";
     270            0 :         std::shared_ptr<ArtdaqEvent> output_event;
     271            0 :         auto start_time = std::chrono::steady_clock::now();
     272              : 
     273            0 :         while (output_event == nullptr)
     274              :         {
     275              :                 // If we experienced a timeout, or have an EndOfData event, drain any held Start/End Run/SubRun events
     276            0 :                 if (last_read_timeout_ || end_of_data_received_)
     277              :                 {
     278            0 :                         if (event_ordering_.size() > 0)
     279              :                         {
     280            0 :                                 output_event = event_ordering_.front();
     281            0 :                                 event_ordering_.pop_front();
     282            0 :                                 break;  // while(output_event == nullptr)
     283              :                         }
     284              :                         // Don't try to get more data if we have an EndOfData event
     285            0 :                         if (end_of_data_received_) { break; }
     286              :                 }
     287              : 
     288            0 :                 if (event_ordering_.size() > 0)
     289              :                 {
     290            0 :                         auto first_type = event_ordering_.front()->FirstFragmentType();
     291            0 :                         auto first_sr = event_ordering_.front()->header->subrun_id;
     292              :                         // If there is an Init Fragment, return it
     293            0 :                         if (first_type == artdaq::Fragment::InitFragmentType)
     294              :                         {
     295            0 :                                 TLOG(TLVL_RECEIVEEVENT) << "Returning Init Fragment";
     296            0 :                                 output_event = event_ordering_.front();
     297            0 :                                 event_ordering_.pop_front();
     298            0 :                                 break;  // while(output_event == nullptr)
     299              :                         }
     300            0 :                         if (current_subrun_ != 0 && first_sr <= current_subrun_)
     301              :                         {
     302            0 :                                 if (artdaq::Fragment::isUserFragmentType(first_type) || first_type == artdaq::Fragment::ContainerFragmentType || first_type == artdaq::Fragment::EmptyFragmentType || first_type == artdaq::Fragment::DataFragmentType)
     303              :                                 {
     304            0 :                                         TLOG(TLVL_RECEIVEEVENT) << "Returning Fragment due to subrun match";
     305            0 :                                         output_event = event_ordering_.front();
     306            0 :                                         event_ordering_.pop_front();
     307            0 :                                         break;  // while(output_event == nullptr)
     308              :                                 }
     309            0 :                                 else if (subrun_closure_threshold_ >= 0 && event_ordering_.size() > static_cast<size_t>(subrun_closure_threshold_))
     310              :                                 {
     311              :                                         // First Fragment is broadcast (begin/end run/subrun), but there's more in event ordering!
     312            0 :                                         TLOG(TLVL_RECEIVEEVENT) << "Returning Broadcast Fragment due to subrun closure";
     313              : 
     314            0 :                                         if (released_broadcast_sequence_ids_.count(event_ordering_.front()->header->sequence_id) == 0)
     315              :                                         {
     316            0 :                                                 output_event = event_ordering_.front();
     317            0 :                                                 released_broadcast_sequence_ids_.insert(event_ordering_.front()->header->sequence_id);
     318            0 :                                                 while (released_broadcast_sequence_ids_.size() > 1000) { released_broadcast_sequence_ids_.erase(released_broadcast_sequence_ids_.begin()); }
     319              :                                         }
     320              :                                         else
     321              :                                         {
     322            0 :                                                 TLOG(TLVL_WARNING) << "Discarding duplicate Broadcast with sequence ID " << event_ordering_.front()->header->sequence_id << " and count " << event_ordering_.front()->fragments.size();
     323              :                                         }
     324            0 :                                         event_ordering_.pop_front();
     325            0 :                                         continue;  // while(output_event == nullptr)
     326            0 :                                 }
     327            0 :                         }
     328            0 :                         else if (current_subrun_ != 0 && first_sr > current_subrun_ + 1)
     329              :                         {
     330            0 :                                 TLOG(TLVL_RECEIVEEVENT) << "Returning Fragment due to stale current_subrun_ (first_sr=" << first_sr << ", current_subrun_=" << current_subrun_ << ")";
     331            0 :                                 output_event = event_ordering_.front();
     332            0 :                                 event_ordering_.pop_front();
     333            0 :                                 break;  // while(output_event == nullptr)
     334              :                         }
     335              : 
     336            0 :                         if (event_ordering_.size() == 1 && (first_type == artdaq::Fragment::EndOfRunFragmentType || first_type == artdaq::Fragment::RunDataFragmentType))
     337              :                         {
     338            0 :                                 TLOG(TLVL_RECEIVEEVENT) << "Returning Broadcast Fragment due to end-of-run";
     339            0 :                                 output_event = event_ordering_.front();
     340            0 :                                 event_ordering_.pop_front();
     341            0 :                                 break;  // while(output_event == nullptr)
     342              :                         }
     343              : 
     344            0 :                         if (current_subrun_ == 0)
     345              :                         {
     346            0 :                                 if (artdaq::Fragment::isUserFragmentType(first_type) || first_type == artdaq::Fragment::ContainerFragmentType || first_type == artdaq::Fragment::EmptyFragmentType || first_type == artdaq::Fragment::DataFragmentType)
     347              :                                 {
     348            0 :                                         TLOG(TLVL_RECEIVEEVENT) << "Returning Fragment due to unset subrun";
     349            0 :                                         output_event = event_ordering_.front();
     350            0 :                                         event_ordering_.pop_front();
     351            0 :                                         break;  // while(output_event == nullptr)
     352              :                                 }
     353              :                                 // We cannot close a subrun that has not yet been opened
     354            0 :                                 if (first_type == artdaq::Fragment::EndOfSubrunFragmentType || first_type == artdaq::Fragment::SubrunDataFragmentType)
     355              :                                 {
     356            0 :                                         TLOG(TLVL_WARNING) << "Subrun is unset, discarding EndOfSubrun Fragment(s) for subrun " << first_sr;
     357            0 :                                         event_ordering_.pop_front();
     358              :                                 }
     359              :                                 // Likewise, we cannot close a run that is not open
     360            0 :                                 if (first_type == artdaq::Fragment::EndOfRunFragmentType || first_type == artdaq::Fragment::RunDataFragmentType)
     361              :                                 {
     362            0 :                                         TLOG(TLVL_WARNING) << "Subrun is unset, discarding EndOfRun Fragment(s) for run " << event_ordering_.front()->header->run_id;
     363            0 :                                         event_ordering_.pop_front();
     364              :                                 }
     365              :                         }
     366              : 
     367            0 :                         if (artdaq::TimeUtils::GetElapsedTime(start_time) > safety_valve_timeout_s_)
     368              :                         {
     369            0 :                                 TLOG(subrun_closure_threshold_ < 0 ? TLVL_INFO : TLVL_WARNING) << "Returning Fragment due to safety valve timeout (" << safety_valve_timeout_s_ << " s). event_ordering_ size=" << event_ordering_.size()
     370            0 :                                                                                                << " (th=" << subrun_closure_threshold_ << "), first event type=" << static_cast<int>(first_type) << " sr="
     371            0 :                                                                                                << first_sr << " (c=" << current_subrun_ << ")";
     372            0 :                                 output_event = event_ordering_.front();
     373            0 :                                 event_ordering_.pop_front();
     374            0 :                                 break;  // while(output_event == nullptr)
     375              :                         }
     376              :                 }
     377              : 
     378            0 :                 auto next_event = ReadEventFromSharedMemory(broadcast);
     379            0 :                 if (next_event == nullptr)
     380              :                 {
     381            0 :                         if (event_ordering_.size() > 0)
     382              :                         {
     383            0 :                                 output_event = event_ordering_.front();
     384            0 :                                 event_ordering_.pop_front();
     385              :                         }
     386              :                         else
     387              :                         {
     388              :                                 // Will return nullptr
     389            0 :                                 break;  // while(output_event == nullptr)
     390              :                         }
     391              :                 }
     392              :                 else
     393              :                 {
     394              :                         // Reset start time when new event arrives
     395            0 :                         start_time = std::chrono::steady_clock::now();
     396            0 :                         TLOG(TLVL_RECEIVEEVENT_2) << "Adding ArtdaqEvent with run=" << next_event->header->run_id << ", subrun=" << next_event->header->subrun_id << ", seq=" << next_event->header->sequence_id << ", and type " << static_cast<int>(next_event->FirstFragmentType()) << " to event ordering list";
     397            0 :                         if (next_event->FirstFragmentType() == artdaq::Fragment::EndOfDataFragmentType) { end_of_data_received_ = true; }
     398            0 :                         else if (next_event->header->subrun_id < current_subrun_ && next_event->FirstFragmentType() != artdaq::Fragment::RunDataFragmentType && next_event->FirstFragmentType() == artdaq::Fragment::EndOfRunFragmentType)
     399              :                         {
     400            0 :                                 auto seq_mask = 0xFFFFFFFF & next_event->header->sequence_id;
     401            0 :                                 TLOG(TLVL_WARNING) << "ArtdaqEvent with run = " << next_event->header->run_id << ", subrun = " << next_event->header->subrun_id << ", seq = " << next_event->header->sequence_id << " (32b mask " << seq_mask << "), and type " << static_cast<int>(next_event->FirstFragmentType()) << " is from a previous subrun! (current=" << current_subrun_ << ")";
     402              :                         }
     403            0 :                         event_ordering_.push_back(next_event);
     404            0 :                         if (event_ordering_.size() > 1)
     405              :                         {
     406            0 :                                 TLOG(TLVL_RECEIVEEVENT_2) << "event_ordering_ size is now " << event_ordering_.size();
     407              :                         }
     408            0 :                         event_ordering_.sort();
     409              :                 }
     410            0 :         }
     411              : 
     412            0 :         if (output_event != nullptr)
     413              :         {
     414            0 :                 auto type = output_event->FirstFragmentType();
     415            0 :                 TLOG(TLVL_RECEIVEEVENT_3) << "Returning ArtdaqEvent with run=" << output_event->header->run_id << ", subrun=" << output_event->header->subrun_id
     416            0 :                                           << ", seq=" << output_event->header->sequence_id << ", and type " << static_cast<int>(type);
     417            0 :                 if (output_event->header->subrun_id > current_subrun_ && output_event->header->subrun_id != 65535)  // EndOfRun Fragments have subrun -1
     418              :                 {
     419            0 :                         if (current_subrun_ != 0)
     420              :                         {
     421            0 :                                 TLOG(TLVL_WARNING) << "Event subrun " << output_event->header->subrun_id << " is greater than current_subrun_ (" << current_subrun_ << "), incrementing";
     422              :                         }
     423              :                         else
     424              :                         {
     425            0 :                                 TLOG(TLVL_DEBUG) << "Incrementing current_subrun_ from 0 to " << output_event->header->subrun_id << " due to unset subrun";
     426              :                         }
     427            0 :                         current_subrun_ = output_event->header->subrun_id;
     428              :                 }
     429            0 :                 if (type == artdaq::Fragment::EndOfSubrunFragmentType || type == artdaq::Fragment::SubrunDataFragmentType || type == artdaq::Fragment::EndOfRunFragmentType || type == artdaq::Fragment::RunDataFragmentType || type == artdaq::Fragment::InitFragmentType)
     430              :                 {
     431            0 :                         if (type == artdaq::Fragment::EndOfSubrunFragmentType || type == artdaq::Fragment::SubrunDataFragmentType)
     432              :                         {
     433            0 :                                 TLOG(TLVL_RECEIVEEVENT_4) << "EndOfSubrun or SubrunData Fragment recieved, incrementing current_subrun from " << current_subrun_ << " to " << (current_subrun_ + 1);
     434            0 :                                 current_subrun_++;
     435            0 :                                 subrun_has_events_ = false;
     436            0 :                         }
     437              :                         else
     438              :                         {
     439            0 :                                 TLOG(TLVL_DEBUG) << "Due to run/subrun/control conditions, setting current_subrun to 0";
     440            0 :                                 current_subrun_ = 0;
     441            0 :                                 subrun_has_events_ = false;
     442              :                         }
     443            0 :                 }
     444              :                 else
     445              :                 {
     446            0 :                         subrun_has_events_ = true;
     447              :                 }
     448              :         }
     449              : 
     450            0 :         TLOG(TLVL_RECEIVEEVENT) << "ReceiveEvent END";
     451              : 
     452            0 :         return output_event;
     453            0 : }
     454              : 
     455            0 : DEFINE_ART_SERVICE_INTERFACE_IMPL(ArtdaqSharedMemoryService, ArtdaqSharedMemoryServiceInterface)
        

Generated by: LCOV version 2.0-1