artdaq_core  v3_07_05
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 using std::string;
10 
11 artdaq::SharedMemoryEventReceiver::SharedMemoryEventReceiver(uint32_t shm_key, uint32_t broadcast_shm_key)
12  : current_read_buffer_(-1)
13  , initialized_(false)
14  , current_header_(nullptr)
15  , current_data_source_(nullptr)
16  , data_(shm_key)
17  , broadcasts_(broadcast_shm_key)
18 {
19  TLOG(TLVL_TRACE) << "SharedMemoryEventReceiver CONSTRUCTOR";
20 }
21 
22 bool artdaq::SharedMemoryEventReceiver::ReadyForRead(bool broadcast, size_t timeout_us)
23 {
24  TLOG(TLVL_TRACE) << "ReadyForRead BEGIN timeout_us=" << timeout_us;
25  if (current_read_buffer_ != -1 && (current_data_source_ != nullptr) && (current_header_ != nullptr))
26  {
27  TLOG(TLVL_TRACE) << "ReadyForRead Returning true because already reading buffer";
28  return true;
29  }
30 
31  bool first = true;
32  auto start_time = TimeUtils::gettimeofday_us();
33  uint64_t time_diff = 0;
34  uint64_t max_sleep = 5000000; // 5 seconds
35  int buf = -1;
36  while (first || time_diff < timeout_us)
37  {
38  if (broadcasts_.ReadyForRead())
39  {
40  buf = broadcasts_.GetBufferForReading();
41  current_data_source_ = &broadcasts_;
42  }
43  else if (!broadcast && data_.ReadyForRead())
44  {
45  buf = data_.GetBufferForReading();
46  current_data_source_ = &data_;
47  }
48  if (buf != -1 && (current_data_source_ != nullptr))
49  {
50  current_read_buffer_ = buf;
51  current_data_source_->ResetReadPos(buf);
52  current_header_ = reinterpret_cast<detail::RawEventHeader*>(current_data_source_->GetReadPos(buf)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
53  TLOG(TLVL_TRACE) << "ReadyForRead Found buffer, returning true. event hdr sequence_id=" << current_header_->sequence_id;
54 
55  // Ignore any Init fragments after the first
56  if (current_data_source_ == &broadcasts_)
57  {
58  bool err;
59  auto types = GetFragmentTypes(err);
60  if (!err && (types.count(Fragment::type_t(Fragment::InitFragmentType)) != 0u) && initialized_)
61  {
62  ReleaseBuffer();
63  continue;
64  }
65  if (!err && (types.count(Fragment::type_t(Fragment::InitFragmentType)) != 0u))
66  {
67  initialized_ = true;
68  }
69  }
70 
71  return true;
72  }
73  current_data_source_ = nullptr;
74  first = false;
75 
76  if (broadcasts_.IsEndOfData() || data_.IsEndOfData())
77  {
78  TLOG(TLVL_TRACE) << "End-Of-Data condition detected, returning false";
79  return false;
80  }
81 
82  time_diff = TimeUtils::gettimeofday_us() - start_time;
83  auto sleep_time = time_diff;
84  if (sleep_time < 10000) sleep_time = 10000;
85  if (sleep_time > max_sleep) sleep_time = max_sleep;
86  usleep(sleep_time);
87  }
88  TLOG(TLVL_TRACE) << "ReadyForRead returning false";
89  return false;
90 }
91 
93 {
94  TLOG(TLVL_TRACE) << "ReadHeader BEGIN";
95  if (current_read_buffer_ != -1 && (current_data_source_ != nullptr))
96  {
97  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
98  if (err)
99  {
100  TLOG(TLVL_WARNING) << "Buffer was in incorrect state, resetting";
101  current_data_source_ = nullptr;
102  current_read_buffer_ = -1;
103  current_header_ = nullptr;
104  return nullptr;
105  }
106  }
107  TLOG(TLVL_TRACE) << "Already have buffer, returning stored header";
108  return current_header_;
109 }
110 
111 std::set<artdaq::Fragment::type_t> artdaq::SharedMemoryEventReceiver::GetFragmentTypes(bool& err)
112 {
113  if (current_read_buffer_ == -1 || (current_header_ == nullptr) || (current_data_source_ == nullptr))
114  {
115  throw cet::exception("AccessViolation") << "Cannot call GetFragmentTypes when not currently reading a buffer! Call ReadHeader() first!"; // NOLINT(cert-err60-cpp)
116  }
117 
118  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
119  if (err)
120  {
121  return std::set<Fragment::type_t>();
122  }
123 
124  current_data_source_->ResetReadPos(current_read_buffer_);
125  current_data_source_->IncrementReadPos(current_read_buffer_, sizeof(detail::RawEventHeader));
126  auto output = std::set<Fragment::type_t>();
127 
128  while (current_data_source_->MoreDataInBuffer(current_read_buffer_))
129  {
130  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
131  if (err)
132  {
133  return std::set<Fragment::type_t>();
134  }
135  auto fragHdr = reinterpret_cast<artdaq::detail::RawFragmentHeader*>(current_data_source_->GetReadPos(current_read_buffer_)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
136  output.insert(fragHdr->type);
137  current_data_source_->IncrementReadPos(current_read_buffer_, fragHdr->word_count * sizeof(RawDataType));
138  }
139 
140  return output;
141 }
142 
143 std::unique_ptr<artdaq::Fragments> artdaq::SharedMemoryEventReceiver::GetFragmentsByType(bool& err, Fragment::type_t type)
144 {
145  if ((current_data_source_ == nullptr) || (current_header_ == nullptr) || current_read_buffer_ == -1)
146  {
147  throw cet::exception("AccessViolation") << "Cannot call GetFragmentsByType when not currently reading a buffer! Call ReadHeader() first!"; // NOLINT(cert-err60-cpp)
148  }
149  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
150  if (err)
151  {
152  return nullptr;
153  }
154 
155  current_data_source_->ResetReadPos(current_read_buffer_);
156  current_data_source_->IncrementReadPos(current_read_buffer_, sizeof(detail::RawEventHeader));
157 
158  std::unique_ptr<Fragments> output(new Fragments());
159 
160  while (current_data_source_->MoreDataInBuffer(current_read_buffer_))
161  {
162  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
163  if (err)
164  {
165  return nullptr;
166  }
167  auto fragHdr = reinterpret_cast<artdaq::detail::RawFragmentHeader*>(current_data_source_->GetReadPos(current_read_buffer_)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
168  if (fragHdr->type == type || type == Fragment::InvalidFragmentType)
169  {
170  output->emplace_back(fragHdr->word_count - detail::RawFragmentHeader::num_words());
171  current_data_source_->Read(current_read_buffer_, output->back().headerAddress(), fragHdr->word_count * sizeof(RawDataType));
172  output->back().autoResize();
173  }
174  else
175  {
176  current_data_source_->IncrementReadPos(current_read_buffer_, fragHdr->word_count * sizeof(RawDataType));
177  }
178  }
179 
180  return output;
181 }
182 
183 std::string artdaq::SharedMemoryEventReceiver::printBuffers_(SharedMemoryManager* data_source)
184 {
185  std::ostringstream ostr;
186  for (size_t ii = 0; ii < data_source->size(); ++ii)
187  {
188  ostr << "Buffer " << ii << ": " << std::endl;
189 
190  data_source->ResetReadPos(ii);
191  data_source->IncrementReadPos(ii, sizeof(detail::RawEventHeader));
192 
193  while (data_source->MoreDataInBuffer(ii))
194  {
195  auto fragHdr = reinterpret_cast<artdaq::detail::RawFragmentHeader*>(data_source->GetReadPos(ii)); // 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_source->IncrementReadPos(ii, fragHdr->word_count * sizeof(RawDataType));
203  }
204  }
205  return ostr.str();
206 }
207 
209 {
210  std::ostringstream ostr;
211  ostr << data_.toString() << std::endl;
212 
213  ostr << "Data Buffer Fragment Counts: " << std::endl;
214  ostr << printBuffers_(&data_);
215 
216  if (data_.GetKey() != broadcasts_.GetKey())
217  {
218  ostr << "Broadcast Buffer Fragment Counts: " << std::endl;
219  ostr << printBuffers_(&broadcasts_);
220  }
221 
222  return ostr.str();
223 }
224 
226 {
227  TLOG(TLVL_TRACE) << "ReleaseBuffer BEGIN";
228  try
229  {
230  if (current_data_source_ != nullptr)
231  {
232  current_data_source_->MarkBufferEmpty(current_read_buffer_, false, false);
233  }
234  }
235  catch (cet::exception const& e)
236  {
237  TLOG(TLVL_WARNING) << "A cet::exception occured while trying to release the buffer: " << e;
238  }
239  catch (...)
240  {
241  TLOG(TLVL_ERROR) << "An unknown exception occured while trying to release the buffer";
242  }
243  current_read_buffer_ = -1;
244  current_header_ = nullptr;
245  current_data_source_ = nullptr;
246  TLOG(TLVL_TRACE) << "ReleaseBuffer END";
247 }
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.