artdaq_core  v3_08_00
SharedMemoryEventReceiver.cc
1 
2 #include "artdaq-core/Core/SharedMemoryEventReceiver.hh"
3 
4 #include <sys/time.h>
5 #include "artdaq-core/Data/Fragment.hh"
6 #define TRACE_NAME "SharedMemoryEventReceiver"
7 #include "tracemf.h"
8 
9 artdaq::SharedMemoryEventReceiver::SharedMemoryEventReceiver(uint32_t shm_key, uint32_t broadcast_shm_key)
10  : current_read_buffer_(-1)
11  , initialized_(false)
12  , current_header_(nullptr)
13  , current_data_source_(nullptr)
14  , data_(shm_key)
15  , broadcasts_(broadcast_shm_key)
16 {
17  TLOG(TLVL_TRACE) << "SharedMemoryEventReceiver CONSTRUCTOR";
18 }
19 
20 bool artdaq::SharedMemoryEventReceiver::ReadyForRead(bool broadcast, size_t timeout_us)
21 {
22  TLOG(TLVL_TRACE) << "ReadyForRead BEGIN timeout_us=" << timeout_us;
23  if (current_read_buffer_ != -1 && (current_data_source_ != nullptr) && (current_header_ != nullptr))
24  {
25  TLOG(TLVL_TRACE) << "ReadyForRead Returning true because already reading buffer";
26  return true;
27  }
28 
29  bool first = true;
30  auto start_time = TimeUtils::gettimeofday_us();
31  uint64_t time_diff = 0;
32  uint64_t max_sleep = 5000000; // 5 seconds
33  int buf = -1;
34  while (first || time_diff < timeout_us)
35  {
36  if (broadcasts_.ReadyForRead())
37  {
38  buf = broadcasts_.GetBufferForReading();
39  current_data_source_ = &broadcasts_;
40  }
41  else if (!broadcast && data_.ReadyForRead())
42  {
43  buf = data_.GetBufferForReading();
44  current_data_source_ = &data_;
45  }
46  if (buf != -1 && (current_data_source_ != nullptr))
47  {
48  current_read_buffer_ = buf;
49  current_data_source_->ResetReadPos(buf);
50  current_header_ = reinterpret_cast<detail::RawEventHeader*>(current_data_source_->GetReadPos(buf)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
51  TLOG(TLVL_TRACE) << "ReadyForRead Found buffer, returning true. event hdr sequence_id=" << current_header_->sequence_id;
52 
53  // Ignore any Init fragments after the first
54  if (current_data_source_ == &broadcasts_)
55  {
56  bool err;
57  auto types = GetFragmentTypes(err);
58  if (!err && (types.count(Fragment::type_t(Fragment::InitFragmentType)) != 0u) && initialized_)
59  {
60  ReleaseBuffer();
61  continue;
62  }
63  if (!err && (types.count(Fragment::type_t(Fragment::InitFragmentType)) != 0u))
64  {
65  initialized_ = true;
66  }
67  }
68 
69  return true;
70  }
71  current_data_source_ = nullptr;
72  first = false;
73 
74  if (broadcasts_.IsEndOfData() || data_.IsEndOfData())
75  {
76  TLOG(TLVL_TRACE) << "End-Of-Data condition detected, returning false";
77  return false;
78  }
79 
80  time_diff = TimeUtils::gettimeofday_us() - start_time;
81  auto sleep_time = time_diff;
82  if (sleep_time < 10000) sleep_time = 10000;
83  if (sleep_time > max_sleep) sleep_time = max_sleep;
84  usleep(sleep_time);
85  }
86  TLOG(TLVL_TRACE) << "ReadyForRead returning false";
87  return false;
88 }
89 
91 {
92  TLOG(TLVL_TRACE) << "ReadHeader BEGIN";
93  if (current_read_buffer_ != -1 && (current_data_source_ != nullptr))
94  {
95  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
96  if (err)
97  {
98  TLOG(TLVL_WARNING) << "Buffer was in incorrect state, resetting";
99  current_data_source_ = nullptr;
100  current_read_buffer_ = -1;
101  current_header_ = nullptr;
102  return nullptr;
103  }
104  }
105  TLOG(TLVL_TRACE) << "Already have buffer, returning stored header";
106  return current_header_;
107 }
108 
109 std::set<artdaq::Fragment::type_t> artdaq::SharedMemoryEventReceiver::GetFragmentTypes(bool& err)
110 {
111  if (current_read_buffer_ == -1 || (current_header_ == nullptr) || (current_data_source_ == nullptr))
112  {
113  throw cet::exception("AccessViolation") << "Cannot call GetFragmentTypes when not currently reading a buffer! Call ReadHeader() first!"; // NOLINT(cert-err60-cpp)
114  }
115 
116  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
117  if (err)
118  {
119  return std::set<Fragment::type_t>();
120  }
121 
122  current_data_source_->ResetReadPos(current_read_buffer_);
123  current_data_source_->IncrementReadPos(current_read_buffer_, sizeof(detail::RawEventHeader));
124  auto output = std::set<Fragment::type_t>();
125 
126  while (current_data_source_->MoreDataInBuffer(current_read_buffer_))
127  {
128  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
129  if (err)
130  {
131  return std::set<Fragment::type_t>();
132  }
133  auto fragHdr = reinterpret_cast<artdaq::detail::RawFragmentHeader*>(current_data_source_->GetReadPos(current_read_buffer_)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
134  output.insert(fragHdr->type);
135  current_data_source_->IncrementReadPos(current_read_buffer_, fragHdr->word_count * sizeof(RawDataType));
136  }
137 
138  return output;
139 }
140 
141 std::unique_ptr<artdaq::Fragments> artdaq::SharedMemoryEventReceiver::GetFragmentsByType(bool& err, Fragment::type_t type)
142 {
143  if ((current_data_source_ == nullptr) || (current_header_ == nullptr) || current_read_buffer_ == -1)
144  {
145  throw cet::exception("AccessViolation") << "Cannot call GetFragmentsByType when not currently reading a buffer! Call ReadHeader() first!"; // NOLINT(cert-err60-cpp)
146  }
147  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
148  if (err)
149  {
150  return nullptr;
151  }
152 
153  current_data_source_->ResetReadPos(current_read_buffer_);
154  current_data_source_->IncrementReadPos(current_read_buffer_, sizeof(detail::RawEventHeader));
155 
156  std::unique_ptr<Fragments> output(new Fragments());
157 
158  while (current_data_source_->MoreDataInBuffer(current_read_buffer_))
159  {
160  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
161  if (err)
162  {
163  return nullptr;
164  }
165  auto fragHdr = reinterpret_cast<artdaq::detail::RawFragmentHeader*>(current_data_source_->GetReadPos(current_read_buffer_)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
166  if (fragHdr->type == type || type == Fragment::InvalidFragmentType)
167  {
168  output->emplace_back(fragHdr->word_count - detail::RawFragmentHeader::num_words());
169  current_data_source_->Read(current_read_buffer_, output->back().headerAddress(), fragHdr->word_count * sizeof(RawDataType));
170  output->back().autoResize();
171  }
172  else
173  {
174  current_data_source_->IncrementReadPos(current_read_buffer_, fragHdr->word_count * sizeof(RawDataType));
175  }
176  }
177 
178  return output;
179 }
180 
181 std::string artdaq::SharedMemoryEventReceiver::printBuffers_(SharedMemoryManager* data_source)
182 {
183  std::ostringstream ostr;
184  for (size_t ii = 0; ii < data_source->size(); ++ii)
185  {
186  ostr << "Buffer " << ii << ": " << std::endl;
187 
188  data_source->ResetReadPos(ii);
189  data_source->IncrementReadPos(ii, sizeof(detail::RawEventHeader));
190 
191  while (data_source->MoreDataInBuffer(ii))
192  {
193  auto fragHdr = reinterpret_cast<artdaq::detail::RawFragmentHeader*>(data_source->GetReadPos(ii)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
194  ostr << " Fragment " << fragHdr->fragment_id << ": Sequence ID: " << fragHdr->sequence_id << ", Type:" << fragHdr->type;
195  if (artdaq::detail::RawFragmentHeader::MakeVerboseSystemTypeMap().count(fragHdr->type) != 0u)
196  {
197  ostr << " (" << artdaq::detail::RawFragmentHeader::MakeVerboseSystemTypeMap()[fragHdr->type] << ")";
198  }
199  ostr << ", Size: " << fragHdr->word_count << " words." << std::endl;
200  data_source->IncrementReadPos(ii, fragHdr->word_count * sizeof(RawDataType));
201  }
202  }
203  return ostr.str();
204 }
205 
207 {
208  std::ostringstream ostr;
209  ostr << data_.toString() << std::endl;
210 
211  ostr << "Data Buffer Fragment Counts: " << std::endl;
212  ostr << printBuffers_(&data_);
213 
214  if (data_.GetKey() != broadcasts_.GetKey())
215  {
216  ostr << "Broadcast Buffer Fragment Counts: " << std::endl;
217  ostr << printBuffers_(&broadcasts_);
218  }
219 
220  return ostr.str();
221 }
222 
224 {
225  TLOG(TLVL_TRACE) << "ReleaseBuffer BEGIN";
226  try
227  {
228  if (current_data_source_ != nullptr)
229  {
230  current_data_source_->MarkBufferEmpty(current_read_buffer_, false, false);
231  }
232  }
233  catch (cet::exception const& e)
234  {
235  TLOG(TLVL_WARNING) << "A cet::exception occured while trying to release the buffer: " << e;
236  }
237  catch (...)
238  {
239  TLOG(TLVL_ERROR) << "An unknown exception occured while trying to release the buffer";
240  }
241  current_read_buffer_ = -1;
242  current_header_ = nullptr;
243  current_data_source_ = nullptr;
244  TLOG(TLVL_TRACE) << "ReleaseBuffer END";
245 }
static constexpr type_t InvalidFragmentType
Copy InvalidFragmentType from RawFragmentHeader.
Definition: Fragment.hh:147
std::vector< Fragment > Fragments
A std::vector of Fragment objects.
Definition: Fragment.hh:42
void ReleaseBuffer()
Release the buffer currently being read to the Empty state.
void IncrementReadPos(int buffer, size_t read)
Increment the read position for a given buffer.
static constexpr std::size_t num_words()
Returns the number of RawDataType words present in the header.
The RawFragmentHeader class contains the basic fields used by artdaq for routing Fragment objects thr...
detail::RawFragmentHeader::type_t type_t
typedef for type_t from RawFragmentHeader
Definition: Fragment.hh:137
void ResetReadPos(int buffer)
Set the read position of the given buffer to the beginning of the buffer.
bool MoreDataInBuffer(int buffer)
Determine if more data is available to be read, based on the read position and data size...
RawDataType fragment_id
The fragment_id uniquely identifies a particular piece of hardware within the artdaq system...
static constexpr type_t InitFragmentType
Copy InitFragmentType from RawFragmentHeader.
Definition: Fragment.hh:150
The buffer is currently being read from.
The SharedMemoryManager creates a Shared Memory area which is divided into a number of fixed-size buf...
SharedMemoryEventReceiver(uint32_t shm_key, uint32_t broadcast_shm_key)
Connect to a Shared Memory segment using the given parameters.
size_t size() const
Get the number of buffers in the shared memory segment.
static std::map< type_t, std::string > MakeVerboseSystemTypeMap()
Returns a map of all system types.
The header information used to identify key properties of the RawEvent object.
Definition: RawEvent.hh:26
detail::RawFragmentHeader::RawDataType RawDataType
The RawDataType (currently a 64-bit integer) is the basic unit of data representation within artdaq ...
Definition: Fragment.hh:40
std::set< Fragment::type_t > GetFragmentTypes(bool &err)
Get a set of Fragment Types present in the event.
void * GetReadPos(int buffer)
Get a pointer to the current read position of the buffer.
bool ReadyForRead(bool broadcast=false, size_t timeout_us=1000000)
Determine whether an event is available for reading.
std::string toString()
Write out information about the Shared Memory to a string.
detail::RawEventHeader * ReadHeader(bool &err)
Get the Event header.
uint64_t gettimeofday_us()
Get the current time of day in microseconds (from gettimeofday system call)
Definition: TimeUtils.cc:51
sequence_id_t sequence_id
RawEvent sequence_id should be the same as its component Fragment sequence_ids.
Definition: RawEvent.hh:38
std::unique_ptr< Fragments > GetFragmentsByType(bool &err, Fragment::type_t type)
Get a pointer to the Fragments of a given type in the event.