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