artdaq_core  v3_04_09
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 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 
125 std::unique_ptr<artdaq::Fragments> artdaq::SharedMemoryEventReceiver::GetFragmentsByType(bool& err, Fragment::type_t type)
126 {
127  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!";
128  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
129  if (err) return nullptr;
130 
131  current_data_source_->ResetReadPos(current_read_buffer_);
132  current_data_source_->IncrementReadPos(current_read_buffer_, sizeof(detail::RawEventHeader));
133 
134  std::unique_ptr<Fragments> output(new Fragments());
135 
136  while (current_data_source_->MoreDataInBuffer(current_read_buffer_))
137  {
138  err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
139  if (err) return nullptr;
140  auto fragHdr = reinterpret_cast<artdaq::detail::RawFragmentHeader*>(current_data_source_->GetReadPos(current_read_buffer_));
141  if (fragHdr->type == type || type == Fragment::InvalidFragmentType)
142  {
143  output->emplace_back(fragHdr->word_count - detail::RawFragmentHeader::num_words());
144  current_data_source_->Read(current_read_buffer_, output->back().headerAddress(), fragHdr->word_count * sizeof(RawDataType));
145  output->back().autoResize();
146  }
147  else
148  {
149  current_data_source_->IncrementReadPos(current_read_buffer_, fragHdr->word_count * sizeof(RawDataType));
150  }
151  }
152 
153  return output;
154 }
155 
156 std::string artdaq::SharedMemoryEventReceiver::printBuffers_(SharedMemoryManager* data_source)
157 {
158  std::ostringstream ostr;
159  for (size_t ii = 0; ii < data_source->size(); ++ii)
160  {
161  ostr << "Buffer " << ii << ": " << std::endl;
162 
163  data_source->ResetReadPos(ii);
164  data_source->IncrementReadPos(ii, sizeof(detail::RawEventHeader));
165 
166  while (data_source->MoreDataInBuffer(ii))
167  {
168  auto fragHdr = reinterpret_cast<artdaq::detail::RawFragmentHeader*>(data_source->GetReadPos(ii));
169  ostr << " Fragment " << fragHdr->fragment_id << ": Sequence ID: " << fragHdr->sequence_id << ", Type:" << fragHdr->type;
170  if (fragHdr->MakeVerboseSystemTypeMap().count(fragHdr->type))
171  {
172  ostr << " (" << fragHdr->MakeVerboseSystemTypeMap()[fragHdr->type] << ")";
173  }
174  ostr << ", Size: " << fragHdr->word_count << " words." << std::endl;
175  data_source->IncrementReadPos(ii, fragHdr->word_count * sizeof(RawDataType));
176  }
177 
178  }
179  return ostr.str();
180 }
181 
183 {
184  std::ostringstream ostr;
185  ostr << data_.toString() << std::endl;
186 
187  ostr << "Data Buffer Fragment Counts: " << std::endl;
188  ostr << printBuffers_(&data_);
189 
190  if (data_.GetKey() != broadcasts_.GetKey())
191  {
192  ostr << "Broadcast Buffer Fragment Counts: " << std::endl;
193  ostr << printBuffers_(&broadcasts_);
194  }
195 
196  return ostr.str();
197 }
198 
200 {
201  TLOG(TLVL_TRACE) << "ReleaseBuffer BEGIN" ;
202  try
203  {
204  if(current_data_source_) current_data_source_->MarkBufferEmpty(current_read_buffer_);
205  }
206  catch (cet::exception e)
207  {
208  TLOG(TLVL_WARNING) << "A cet::exception occured while trying to release the buffer: " << e ;
209  }
210  catch (...)
211  {
212  TLOG(TLVL_ERROR) << "An unknown exception occured while trying to release the buffer" ;
213  }
214  current_read_buffer_ = -1;
215  current_header_ = nullptr;
216  current_data_source_ = nullptr;
217  TLOG(TLVL_TRACE) << "ReleaseBuffer END" ;
218 }
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...
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: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
sequence_id_t sequence_id
RawEvent sequence_id should be the same as its component Fragment sequence_ids.
Definition: RawEvent.hh:40
std::unique_ptr< Fragments > GetFragmentsByType(bool &err, Fragment::type_t type)
Get a pointer to the Fragments of a given type in the event.