artdaq_core  v3_06_01
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  time_diff = TimeUtils::gettimeofday_us() - start_time;
77  auto sleep_time = time_diff;
78  if (sleep_time < 10000) sleep_time = 10000;
79  if (sleep_time > max_sleep) sleep_time = max_sleep;
80  usleep(sleep_time);
81  }
82  TLOG(TLVL_TRACE) << "ReadyForRead returning false";
83  return false;
84 }
85 
87 {
88  TLOG(TLVL_TRACE) << "ReadHeader BEGIN";
89  if (current_read_buffer_ != -1 && (current_data_source_ != nullptr))
90  {
91  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
92  if (err)
93  {
94  TLOG(TLVL_WARNING) << "Buffer was in incorrect state, resetting";
95  current_data_source_ = nullptr;
96  current_read_buffer_ = -1;
97  current_header_ = nullptr;
98  return nullptr;
99  }
100  }
101  TLOG(TLVL_TRACE) << "Already have buffer, returning stored header";
102  return current_header_;
103 }
104 
105 std::set<artdaq::Fragment::type_t> artdaq::SharedMemoryEventReceiver::GetFragmentTypes(bool& err)
106 {
107  if (current_read_buffer_ == -1 || (current_header_ == nullptr) || (current_data_source_ == nullptr))
108  {
109  throw cet::exception("AccessViolation") << "Cannot call GetFragmentTypes when not currently reading a buffer! Call ReadHeader() first!"; // NOLINT(cert-err60-cpp)
110  }
111 
112  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
113  if (err)
114  {
115  return std::set<Fragment::type_t>();
116  }
117 
118  current_data_source_->ResetReadPos(current_read_buffer_);
119  current_data_source_->IncrementReadPos(current_read_buffer_, sizeof(detail::RawEventHeader));
120  auto output = std::set<Fragment::type_t>();
121 
122  while (current_data_source_->MoreDataInBuffer(current_read_buffer_))
123  {
124  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
125  if (err)
126  {
127  return std::set<Fragment::type_t>();
128  }
129  auto fragHdr = reinterpret_cast<artdaq::detail::RawFragmentHeader*>(current_data_source_->GetReadPos(current_read_buffer_)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
130  output.insert(fragHdr->type);
131  current_data_source_->IncrementReadPos(current_read_buffer_, fragHdr->word_count * sizeof(RawDataType));
132  }
133 
134  return output;
135 }
136 
137 std::unique_ptr<artdaq::Fragments> artdaq::SharedMemoryEventReceiver::GetFragmentsByType(bool& err, Fragment::type_t type)
138 {
139  if ((current_data_source_ == nullptr) || (current_header_ == nullptr) || current_read_buffer_ == -1)
140  {
141  throw cet::exception("AccessViolation") << "Cannot call GetFragmentsByType when not currently reading a buffer! Call ReadHeader() first!"; // NOLINT(cert-err60-cpp)
142  }
143  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
144  if (err)
145  {
146  return nullptr;
147  }
148 
149  current_data_source_->ResetReadPos(current_read_buffer_);
150  current_data_source_->IncrementReadPos(current_read_buffer_, sizeof(detail::RawEventHeader));
151 
152  std::unique_ptr<Fragments> output(new Fragments());
153 
154  while (current_data_source_->MoreDataInBuffer(current_read_buffer_))
155  {
156  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
157  if (err)
158  {
159  return nullptr;
160  }
161  auto fragHdr = reinterpret_cast<artdaq::detail::RawFragmentHeader*>(current_data_source_->GetReadPos(current_read_buffer_)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
162  if (fragHdr->type == type || type == Fragment::InvalidFragmentType)
163  {
164  output->emplace_back(fragHdr->word_count - detail::RawFragmentHeader::num_words());
165  current_data_source_->Read(current_read_buffer_, output->back().headerAddress(), fragHdr->word_count * sizeof(RawDataType));
166  output->back().autoResize();
167  }
168  else
169  {
170  current_data_source_->IncrementReadPos(current_read_buffer_, fragHdr->word_count * sizeof(RawDataType));
171  }
172  }
173 
174  return output;
175 }
176 
177 std::string artdaq::SharedMemoryEventReceiver::printBuffers_(SharedMemoryManager* data_source)
178 {
179  std::ostringstream ostr;
180  for (size_t ii = 0; ii < data_source->size(); ++ii)
181  {
182  ostr << "Buffer " << ii << ": " << std::endl;
183 
184  data_source->ResetReadPos(ii);
185  data_source->IncrementReadPos(ii, sizeof(detail::RawEventHeader));
186 
187  while (data_source->MoreDataInBuffer(ii))
188  {
189  auto fragHdr = reinterpret_cast<artdaq::detail::RawFragmentHeader*>(data_source->GetReadPos(ii)); // NOLINT(cppcoreguidelines-pro-type-reinterpret-cast)
190  ostr << " Fragment " << fragHdr->fragment_id << ": Sequence ID: " << fragHdr->sequence_id << ", Type:" << fragHdr->type;
191  if (artdaq::detail::RawFragmentHeader::MakeVerboseSystemTypeMap().count(fragHdr->type) != 0u)
192  {
193  ostr << " (" << artdaq::detail::RawFragmentHeader::MakeVerboseSystemTypeMap()[fragHdr->type] << ")";
194  }
195  ostr << ", Size: " << fragHdr->word_count << " words." << std::endl;
196  data_source->IncrementReadPos(ii, fragHdr->word_count * sizeof(RawDataType));
197  }
198  }
199  return ostr.str();
200 }
201 
203 {
204  std::ostringstream ostr;
205  ostr << data_.toString() << std::endl;
206 
207  ostr << "Data Buffer Fragment Counts: " << std::endl;
208  ostr << printBuffers_(&data_);
209 
210  if (data_.GetKey() != broadcasts_.GetKey())
211  {
212  ostr << "Broadcast Buffer Fragment Counts: " << std::endl;
213  ostr << printBuffers_(&broadcasts_);
214  }
215 
216  return ostr.str();
217 }
218 
220 {
221  TLOG(TLVL_TRACE) << "ReleaseBuffer BEGIN";
222  try
223  {
224  if (current_data_source_ != nullptr)
225  {
226  current_data_source_->MarkBufferEmpty(current_read_buffer_);
227  }
228  }
229  catch (cet::exception const& e)
230  {
231  TLOG(TLVL_WARNING) << "A cet::exception occured while trying to release the buffer: " << e;
232  }
233  catch (...)
234  {
235  TLOG(TLVL_ERROR) << "An unknown exception occured while trying to release the buffer";
236  }
237  current_read_buffer_ = -1;
238  current_header_ = nullptr;
239  current_data_source_ = nullptr;
240  TLOG(TLVL_TRACE) << "ReleaseBuffer END";
241 }
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:28
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:40
std::unique_ptr< Fragments > GetFragmentsByType(bool &err, Fragment::type_t type)
Get a pointer to the Fragments of a given type in the event.