artdaq_core  3.09.14
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 "TRACE/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_DEBUG + 33) << "SharedMemoryEventReceiver CONSTRUCTOR";
18 }
19 
20 bool artdaq::SharedMemoryEventReceiver::ReadyForRead(bool broadcast, size_t timeout_us)
21 {
22  TLOG(TLVL_DEBUG + 33) << "ReadyForRead BEGIN timeout_us=" << timeout_us;
23  if (current_read_buffer_ != -1 && (current_data_source_ != nullptr) && (current_header_ != nullptr))
24  {
25  TLOG(TLVL_DEBUG + 33) << "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_DEBUG + 33) << "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_DEBUG + 33) << "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_DEBUG + 33) << "ReadyForRead returning false";
87  return false;
88 }
89 
91 {
92  TLOG(TLVL_DEBUG + 33) << "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_DEBUG + 33) << "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  void* data_ptr = data_source->GetBufferStart(ii);
189  void* end_ptr = static_cast<uint8_t*>(data_ptr) + data_source->BufferDataSize(ii);
190  data_ptr = static_cast<uint8_t*>(data_ptr) + sizeof(detail::RawEventHeader);
191  TLOG_DEBUG(33) << "Buffer " << ii << ": data_ptr: " << data_ptr << ", end_ptr: " << end_ptr;
192 
193  while (data_ptr < end_ptr)
194  {
195  auto fragHdr = reinterpret_cast<artdaq::detail::RawFragmentHeader*>(data_ptr); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
196  ostr << " Fragment " << fragHdr->fragment_id << ": Sequence ID: " << fragHdr->sequence_id << ", Type:" << fragHdr->type;
197  if (artdaq::detail::RawFragmentHeader::MakeVerboseSystemTypeMap().count(fragHdr->type) != 0u)
198  {
199  ostr << " (" << artdaq::detail::RawFragmentHeader::MakeVerboseSystemTypeMap()[fragHdr->type] << ")";
200  }
201  ostr << ", Size: " << fragHdr->word_count << " words." << std::endl;
202  data_ptr = static_cast<uint8_t*>(data_ptr) + fragHdr->word_count * sizeof(RawDataType);
203 
204  TLOG_DEBUG(33) << "Buffer " << ii << ": After reading Fragment of size " << static_cast<int>(fragHdr->word_count * sizeof(RawDataType)) << " data_ptr: " << data_ptr << ", end_ptr: " << end_ptr;
205  }
206  }
207  return ostr.str();
208 }
209 
211 {
212  std::ostringstream ostr;
213  ostr << data_.toString() << std::endl;
214 
215  ostr << "Data Buffer Fragment Counts: " << std::endl;
216  ostr << printBuffers_(&data_);
217 
218  if (data_.GetKey() != broadcasts_.GetKey())
219  {
220  ostr << "Broadcast Buffer Fragment Counts: " << std::endl;
221  ostr << printBuffers_(&broadcasts_);
222  }
223 
224  return ostr.str();
225 }
226 
228 {
229  TLOG(TLVL_DEBUG + 33) << "ReleaseBuffer BEGIN";
230  try
231  {
232  if (current_data_source_ != nullptr)
233  {
234  current_data_source_->MarkBufferEmpty(current_read_buffer_, false, false);
235  }
236  }
237  catch (cet::exception const& e)
238  {
239  TLOG(TLVL_WARNING) << "A cet::exception occured while trying to release the buffer: " << e;
240  }
241  catch (...)
242  {
243  TLOG(TLVL_ERROR) << "An unknown exception occured while trying to release the buffer";
244  }
245  current_read_buffer_ = -1;
246  current_header_ = nullptr;
247  current_data_source_ = nullptr;
248  TLOG(TLVL_DEBUG + 33) << "ReleaseBuffer END";
249 }
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.
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
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
size_t BufferDataSize(int buffer)
Get the current size of the buffer&#39;s data.
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.
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.
void * GetBufferStart(int buffer)
Get a pointer to the start position of the buffer.
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.