artdaq_core  v3_00_03
SharedMemoryEventReceiver.cc
1 
2 #include "artdaq-core/Core/SharedMemoryEventReceiver.hh"
3 
4 #include "artdaq-core/Data/Fragment.hh"
5 #include <sys/time.h>
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_TRACE("SharedMemoryEventReceiver") << "SharedMemoryEventReceiver CONSTRUCTOR" << TLOG_ENDL;
20 }
21 
22 bool artdaq::SharedMemoryEventReceiver::ReadyForRead(bool broadcast, size_t timeout_us)
23 {
24  TLOG_TRACE("SharedMemoryEventReceiver") << "ReadyForRead BEGIN" << TLOG_ENDL;
25  if (current_read_buffer_ != -1 && current_data_source_ && current_header_)
26  {
27  TLOG_TRACE("SharedMemoryEventReceiver") << "ReadyForRead Returning true because already reading buffer" << TLOG_ENDL;
28  return true;
29  }
30 
31  auto start_time = TimeUtils::gettimeofday_us();
32  int buf = -1;
33  while (TimeUtils::gettimeofday_us() - start_time < timeout_us)
34  {
35  if (broadcasts_.ReadyForRead())
36  {
37  buf = broadcasts_.GetBufferForReading();
38  current_data_source_ = &broadcasts_;
39  }
40  else if (!broadcast && data_.ReadyForRead())
41  {
42  buf = data_.GetBufferForReading();
43  current_data_source_ = &data_;
44  }
45  if (buf != -1 && current_data_source_)
46  {
47  TLOG_TRACE("SharedMemoryEventReceiver") << "ReadyForRead Found buffer, returning true" << TLOG_ENDL;
48  current_read_buffer_ = buf;
49  current_data_source_->ResetReadPos(buf);
50  current_header_ = reinterpret_cast<detail::RawEventHeader*>(current_data_source_->GetReadPos(buf));
51 
52  // Ignore any Init fragments after the first
53  if (current_data_source_ == &broadcasts_)
54  {
55  bool err;
56  auto types = GetFragmentTypes(err);
57  if (!err && types.count(Fragment::type_t(Fragment::InitFragmentType)) && initialized_)
58  {
59  ReleaseBuffer();
60  continue;
61  }
62  else if (!err && types.count(Fragment::type_t(Fragment::InitFragmentType)))
63  {
64  initialized_ = true;
65  }
66  }
67 
68  return true;
69  }
70  current_data_source_ = nullptr;
71  }
72  TLOG_TRACE("SharedMemoryEventReceiver") << "ReadyForRead returning false" << TLOG_ENDL;
73  return false;
74 }
75 
77 {
78  TLOG_TRACE("SharedMemoryEventReceiver") << "ReadHeader BEGIN" << TLOG_ENDL;
79  if (current_read_buffer_ != -1 && current_data_source_)
80  {
81  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
82  if (err)
83  {
84  TLOG_WARNING("SharedMemoryEventReceiver") << "Buffer was in incorrect state, resetting" << TLOG_ENDL;
85  current_data_source_ = nullptr;
86  current_read_buffer_ = -1;
87  current_header_ = nullptr;
88  return nullptr;
89  }
90  }
91  TLOG_TRACE("SharedMemoryEventReceiver") << "Already have buffer, returning stored header" << TLOG_ENDL;
92  return current_header_;
93 }
94 
95 std::set<artdaq::Fragment::type_t> artdaq::SharedMemoryEventReceiver::GetFragmentTypes(bool& err)
96 {
97  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!";
98 
99  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
100  if (err) return std::set<Fragment::type_t>();
101 
102  current_data_source_->ResetReadPos(current_read_buffer_);
103  current_data_source_->IncrementReadPos(current_read_buffer_, sizeof(detail::RawEventHeader));
104  auto output = std::set<Fragment::type_t>();
105 
106  while (current_data_source_->MoreDataInBuffer(current_read_buffer_))
107  {
108  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
109  if (err) return std::set<Fragment::type_t>();
110  auto fragHdr = reinterpret_cast<artdaq::detail::RawFragmentHeader*>(current_data_source_->GetReadPos(current_read_buffer_));
111  output.insert(fragHdr->type);
112  current_data_source_->IncrementReadPos(current_read_buffer_, fragHdr->word_count * sizeof(RawDataType));
113  }
114 
115  return output;
116 }
117 
118 
119 std::unique_ptr<artdaq::Fragments> artdaq::SharedMemoryEventReceiver::GetFragmentsByType(bool& err, Fragment::type_t type)
120 {
121  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!";
122  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
123  if (err) return nullptr;
124 
125  current_data_source_->ResetReadPos(current_read_buffer_);
126  current_data_source_->IncrementReadPos(current_read_buffer_, sizeof(detail::RawEventHeader));
127 
128  std::unique_ptr<Fragments> output(new Fragments());
129 
130  while (current_data_source_->MoreDataInBuffer(current_read_buffer_))
131  {
132  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
133  if (err) return nullptr;
134  auto fragHdr = reinterpret_cast<artdaq::detail::RawFragmentHeader*>(current_data_source_->GetReadPos(current_read_buffer_));
135  if (fragHdr->type == type || type == Fragment::InvalidFragmentType)
136  {
137  output->emplace_back(fragHdr->word_count - detail::RawFragmentHeader::num_words());
138  current_data_source_->Read(current_read_buffer_, output->back().headerAddress(), fragHdr->word_count * sizeof(RawDataType));
139  output->back().autoResize();
140  }
141  else
142  {
143  current_data_source_->IncrementReadPos(current_read_buffer_, fragHdr->word_count * sizeof(RawDataType));
144  }
145  }
146 
147  return std::move(output);
148 }
149 
150 std::string artdaq::SharedMemoryEventReceiver::printBuffers_(SharedMemoryManager* data_source)
151 {
152  std::ostringstream ostr;
153  for (size_t ii = 0; ii < data_source->size(); ++ii)
154  {
155  ostr << "Buffer " << std::to_string(ii) << ": " << std::endl;
156 
157  data_source->ResetReadPos(ii);
158  data_source->IncrementReadPos(ii, sizeof(detail::RawEventHeader));
159 
160  while (data_source->MoreDataInBuffer(ii))
161  {
162  auto fragHdr = reinterpret_cast<artdaq::detail::RawFragmentHeader*>(data_source->GetReadPos(ii));
163  ostr << " Fragment " << std::to_string(fragHdr->fragment_id) << ": Sequence ID: " << std::to_string(fragHdr->sequence_id) << ", Type:" << std::to_string(fragHdr->type);
164  if (fragHdr->MakeVerboseSystemTypeMap().count(fragHdr->type))
165  {
166  ostr << " (" << fragHdr->MakeVerboseSystemTypeMap()[fragHdr->type] << ")";
167  }
168  ostr << ", Size: " << std::to_string(fragHdr->word_count) << " words." << std::endl;
169  data_source->IncrementReadPos(ii, fragHdr->word_count * sizeof(RawDataType));
170  }
171 
172  }
173  return ostr.str();
174 }
175 
177 {
178  std::ostringstream ostr;
179  ostr << data_.toString() << std::endl;
180 
181  ostr << "Data Buffer Fragment Counts: " << std::endl;
182  ostr << printBuffers_(&data_);
183 
184  if (data_.GetKey() != broadcasts_.GetKey())
185  {
186  ostr << "Broadcast Buffer Fragment Counts: " << std::endl;
187  ostr << printBuffers_(&broadcasts_);
188  }
189 
190  return ostr.str();
191 }
192 
194 {
195  TLOG_TRACE("SharedMemoryEventReceiver") << "ReleaseBuffer BEGIN" << TLOG_ENDL;
196  try
197  {
198  current_data_source_->MarkBufferEmpty(current_read_buffer_);
199  }
200  catch (cet::exception e)
201  {
202  TLOG_WARNING("SharedMemoryEventReceiver") << "A cet::exception occured while trying to release the buffer: " << e << TLOG_ENDL;
203  }
204  catch (...)
205  {
206  TLOG_ERROR("SharedMemoryEventReceiver") << "An unknown exception occured while trying to release the buffer" << TLOG_ENDL;
207  }
208  current_read_buffer_ = -1;
209  current_header_ = nullptr;
210  current_data_source_ = nullptr;
211  TLOG_TRACE("SharedMemoryEventReceiver") << "ReleaseBuffer END" << TLOG_ENDL;
212 }
static constexpr type_t InvalidFragmentType
Copy InvalidFragmentType from RawFragmentHeader.
Definition: Fragment.hh:146
std::vector< Fragment > Fragments
A std::vector of Fragment objects.
Definition: Fragment.hh:41
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:136
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...
static constexpr type_t InitFragmentType
Copy InitFragmentType from RawFragmentHeader.
Definition: Fragment.hh:149
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:30
detail::RawFragmentHeader::RawDataType RawDataType
The RawDataType (currently a 64-bit integer) is the basic unit of data representation within artdaq ...
Definition: Fragment.hh:39
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
std::unique_ptr< Fragments > GetFragmentsByType(bool &err, Fragment::type_t type)
Get a pointer to the Fragments of a given type in the event.