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