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