artdaq_core  v3_05_07
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_ && current_header_)
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  int buf = -1;
35  while (first || time_diff < timeout_us)
36  {
37  if (broadcasts_.ReadyForRead())
38  {
39  buf = broadcasts_.GetBufferForReading();
40  current_data_source_ = &broadcasts_;
41  }
42  else if (!broadcast && data_.ReadyForRead())
43  {
44  buf = data_.GetBufferForReading();
45  current_data_source_ = &data_;
46  }
47  if (buf != -1 && current_data_source_)
48  {
49  current_read_buffer_ = buf;
50  current_data_source_->ResetReadPos(buf);
51  current_header_ = reinterpret_cast<detail::RawEventHeader*>(current_data_source_->GetReadPos(buf));
52  TLOG(TLVL_TRACE) << "ReadyForRead Found buffer, returning true. event hdr sequence_id=" << current_header_->sequence_id;
53 
54  // Ignore any Init fragments after the first
55  if (current_data_source_ == &broadcasts_)
56  {
57  bool err;
58  auto types = GetFragmentTypes(err);
59  if (!err && types.count(Fragment::type_t(Fragment::InitFragmentType)) && initialized_)
60  {
61  ReleaseBuffer();
62  continue;
63  }
64  else if (!err && types.count(Fragment::type_t(Fragment::InitFragmentType)))
65  {
66  initialized_ = true;
67  }
68  }
69 
70  return true;
71  }
72  current_data_source_ = nullptr;
73  first = false;
74 
75  time_diff = TimeUtils::gettimeofday_us() - start_time;
76  usleep(time_diff < 10000 ? time_diff : 10000);
77  }
78  TLOG(TLVL_TRACE) << "ReadyForRead returning false";
79  return false;
80 }
81 
83 {
84  TLOG(TLVL_TRACE) << "ReadHeader BEGIN";
85  if (current_read_buffer_ != -1 && current_data_source_)
86  {
87  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
88  if (err)
89  {
90  TLOG(TLVL_WARNING) << "Buffer was in incorrect state, resetting";
91  current_data_source_ = nullptr;
92  current_read_buffer_ = -1;
93  current_header_ = nullptr;
94  return nullptr;
95  }
96  }
97  TLOG(TLVL_TRACE) << "Already have buffer, returning stored header";
98  return current_header_;
99 }
100 
101 std::set<artdaq::Fragment::type_t> artdaq::SharedMemoryEventReceiver::GetFragmentTypes(bool& err)
102 {
103  if (current_read_buffer_ == -1 || !current_header_ || !current_data_source_) throw cet::exception("AccessViolation") << "Cannot call GetFragmentTypes when not currently reading a buffer! Call ReadHeader() first!";
104 
105  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
106  if (err) return std::set<Fragment::type_t>();
107 
108  current_data_source_->ResetReadPos(current_read_buffer_);
109  current_data_source_->IncrementReadPos(current_read_buffer_, sizeof(detail::RawEventHeader));
110  auto output = std::set<Fragment::type_t>();
111 
112  while (current_data_source_->MoreDataInBuffer(current_read_buffer_))
113  {
114  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
115  if (err) return std::set<Fragment::type_t>();
116  auto fragHdr = reinterpret_cast<artdaq::detail::RawFragmentHeader*>(current_data_source_->GetReadPos(current_read_buffer_));
117  output.insert(fragHdr->type);
118  current_data_source_->IncrementReadPos(current_read_buffer_, fragHdr->word_count * sizeof(RawDataType));
119  }
120 
121  return output;
122 }
123 
124 std::unique_ptr<artdaq::Fragments> artdaq::SharedMemoryEventReceiver::GetFragmentsByType(bool& err, Fragment::type_t type)
125 {
126  if (!current_data_source_ || !current_header_ || current_read_buffer_ == -1) throw cet::exception("AccessViolation") << "Cannot call GetFragmentsByType when not currently reading a buffer! Call ReadHeader() first!";
127  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
128  if (err) return nullptr;
129 
130  current_data_source_->ResetReadPos(current_read_buffer_);
131  current_data_source_->IncrementReadPos(current_read_buffer_, sizeof(detail::RawEventHeader));
132 
133  std::unique_ptr<Fragments> output(new Fragments());
134 
135  while (current_data_source_->MoreDataInBuffer(current_read_buffer_))
136  {
137  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
138  if (err) return nullptr;
139  auto fragHdr = reinterpret_cast<artdaq::detail::RawFragmentHeader*>(current_data_source_->GetReadPos(current_read_buffer_));
140  if (fragHdr->type == type || type == Fragment::InvalidFragmentType)
141  {
142  output->emplace_back(fragHdr->word_count - detail::RawFragmentHeader::num_words());
143  current_data_source_->Read(current_read_buffer_, output->back().headerAddress(), fragHdr->word_count * sizeof(RawDataType));
144  output->back().autoResize();
145  }
146  else
147  {
148  current_data_source_->IncrementReadPos(current_read_buffer_, fragHdr->word_count * sizeof(RawDataType));
149  }
150  }
151 
152  return output;
153 }
154 
155 std::string artdaq::SharedMemoryEventReceiver::printBuffers_(SharedMemoryManager* data_source)
156 {
157  std::ostringstream ostr;
158  for (size_t ii = 0; ii < data_source->size(); ++ii)
159  {
160  ostr << "Buffer " << ii << ": " << std::endl;
161 
162  data_source->ResetReadPos(ii);
163  data_source->IncrementReadPos(ii, sizeof(detail::RawEventHeader));
164 
165  while (data_source->MoreDataInBuffer(ii))
166  {
167  auto fragHdr = reinterpret_cast<artdaq::detail::RawFragmentHeader*>(data_source->GetReadPos(ii));
168  ostr << " Fragment " << fragHdr->fragment_id << ": Sequence ID: " << fragHdr->sequence_id << ", Type:" << fragHdr->type;
169  if (fragHdr->MakeVerboseSystemTypeMap().count(fragHdr->type))
170  {
171  ostr << " (" << fragHdr->MakeVerboseSystemTypeMap()[fragHdr->type] << ")";
172  }
173  ostr << ", Size: " << fragHdr->word_count << " words." << std::endl;
174  data_source->IncrementReadPos(ii, fragHdr->word_count * sizeof(RawDataType));
175  }
176  }
177  return ostr.str();
178 }
179 
181 {
182  std::ostringstream ostr;
183  ostr << data_.toString() << std::endl;
184 
185  ostr << "Data Buffer Fragment Counts: " << std::endl;
186  ostr << printBuffers_(&data_);
187 
188  if (data_.GetKey() != broadcasts_.GetKey())
189  {
190  ostr << "Broadcast Buffer Fragment Counts: " << std::endl;
191  ostr << printBuffers_(&broadcasts_);
192  }
193 
194  return ostr.str();
195 }
196 
198 {
199  TLOG(TLVL_TRACE) << "ReleaseBuffer BEGIN";
200  try
201  {
202  if (current_data_source_) current_data_source_->MarkBufferEmpty(current_read_buffer_);
203  }
204  catch (cet::exception const& e)
205  {
206  TLOG(TLVL_WARNING) << "A cet::exception occured while trying to release the buffer: " << e;
207  }
208  catch (...)
209  {
210  TLOG(TLVL_ERROR) << "An unknown exception occured while trying to release the buffer";
211  }
212  current_read_buffer_ = -1;
213  current_header_ = nullptr;
214  current_data_source_ = nullptr;
215  TLOG(TLVL_TRACE) << "ReleaseBuffer END";
216 }
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.
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: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.