artdaq_core  v3_06_00
SharedMemoryFragmentManager.cc
1 
2 #define TRACE_NAME "SharedMemoryFragmentManager"
3 #include "artdaq-core/Core/SharedMemoryFragmentManager.hh"
4 #include "tracemf.h"
5 
6 artdaq::SharedMemoryFragmentManager::SharedMemoryFragmentManager(uint32_t shm_key, size_t buffer_count, size_t max_buffer_size, size_t buffer_timeout_us)
7  : SharedMemoryManager(shm_key, buffer_count, max_buffer_size, buffer_timeout_us)
8  , active_buffer_(-1)
9 {
10 }
11 
13 {
14  TLOG(12) << "ReadyForWrite: active_buffer is " << active_buffer_;
15  if (active_buffer_ != -1)
16  {
17  return true;
18  }
19  active_buffer_ = GetBufferForWriting(overwrite);
20 
21  return active_buffer_ != -1;
22 }
23 
24 int artdaq::SharedMemoryFragmentManager::WriteFragment(Fragment&& fragment, bool overwrite, size_t timeout_us)
25 {
26  if (!IsValid() || IsEndOfData())
27  {
28  TLOG(TLVL_WARNING) << "WriteFragment: Shared memory is not connected! Attempting reconnect...";
29  auto sts = Attach(timeout_us);
30  if (!sts)
31  {
32  return -1;
33  }
34  TLOG(TLVL_INFO) << "WriteFragment: Shared memory was successfully reconnected";
35  }
36 
37  auto waitStart = std::chrono::steady_clock::now();
38  while (!ReadyForWrite(overwrite) && TimeUtils::GetElapsedTimeMicroseconds(waitStart) < 1000)
39  {
40  // BURN THAT CPU!
41  }
42  if (!ReadyForWrite(overwrite))
43  {
44  int64_t loopCount = 0;
45  size_t sleepTime = 1000; // microseconds
46  int64_t nloops = (timeout_us - 1000) / sleepTime;
47 
48  while (!ReadyForWrite(overwrite) && (!overwrite || timeout_us == 0 || loopCount < nloops))
49  {
50  if (!IsValid() || IsEndOfData())
51  {
52  TLOG(TLVL_WARNING) << "WriteFragment: Shared memory is not connected! Attempting reconnect...";
53  auto sts = Attach(timeout_us);
54  if (!sts)
55  {
56  return -1;
57  }
58  TLOG(TLVL_INFO) << "WriteFragment: Shared memory was successfully reconnected";
59  }
60  usleep(sleepTime);
61  ++loopCount;
62  }
63  }
64  if (!ReadyForWrite(overwrite))
65  {
66  TLOG(TLVL_WARNING) << "No available buffers after waiting for " << TimeUtils::GetElapsedTimeMicroseconds(waitStart) << " us.";
67  return -3;
68  }
69 
70  TLOG(13) << "Sending fragment with seqID=" << fragment.sequenceID() << " using buffer " << active_buffer_;
71  artdaq::RawDataType* fragAddr = fragment.headerAddress();
72  size_t fragSize = fragment.size() * sizeof(artdaq::RawDataType);
73 
74  auto sts = Write(active_buffer_, fragAddr, fragSize);
75  if (sts == fragSize)
76  {
77  TLOG(13) << "Done sending Fragment with seqID=" << fragment.sequenceID() << " using buffer " << active_buffer_;
78  MarkBufferFull(active_buffer_);
79  active_buffer_ = -1;
80  return 0;
81  }
82  active_buffer_ = -1;
83  TLOG(TLVL_ERROR) << "Unexpected status from SharedMemory Write call!";
84  return -2;
85 }
86 
87 // NOT currently (2018-07-22) used! ReadFragmentHeader and ReadFragmentData
88 // (below) are called directly
90 {
91  TLOG(14) << "ReadFragment BEGIN";
93 
94  TLOG(14) << "Reading Fragment Header";
95  auto sts = ReadFragmentHeader(tmpHdr);
96  if (sts != 0)
97  {
98  return sts;
99  }
100  fragment.resize(tmpHdr.word_count - tmpHdr.num_words());
101  memcpy(fragment.headerAddress(), &tmpHdr, tmpHdr.num_words() * sizeof(artdaq::RawDataType));
102  TLOG(14) << "Reading Fragment Body - of frag w/ seqID=" << tmpHdr.sequence_id;
103  return ReadFragmentData(fragment.headerAddress() + tmpHdr.num_words(), tmpHdr.word_count - tmpHdr.num_words()); // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic)
104 }
105 
107 {
108  if (!IsValid())
109  {
110  TLOG(22) << "ReadFragmentHeader: !IsValid(), returning -3";
111  return -3;
112  }
113 
115  active_buffer_ = GetBufferForReading();
116 
117  if (active_buffer_ == -1)
118  {
119  TLOG(22) << "ReadFragmentHeader: active_buffer==-1, returning -1";
120  return -1;
121  }
122 
123  auto sts = Read(active_buffer_, &header, hdrSize);
124  if (!sts)
125  {
126  TLOG(TLVL_ERROR) << "ReadFragmentHeader: Buffer " << active_buffer_ << " returned bad status code from Read";
127  MarkBufferEmpty(active_buffer_);
128  active_buffer_ = -1;
129  return -2;
130  }
131 
132  TLOG(22) << "ReadFragmentHeader: read active_buffer_=" << active_buffer_ << " sequence_id=" << header.sequence_id;
133  return 0;
134 }
135 
137 {
138  if (!IsValid() || active_buffer_ == -1 || !CheckBuffer(active_buffer_, BufferSemaphoreFlags::Reading))
139  {
140  TLOG(TLVL_ERROR) << "ReadFragmentData: Buffer " << active_buffer_ << " failed status checks: IsValid()=" << std::boolalpha << IsValid() << ", CheckBuffer=" << CheckBuffer(active_buffer_, BufferSemaphoreFlags::Reading);
141  return -3;
142  }
143 
144  auto sts = Read(active_buffer_, destination, words * sizeof(RawDataType));
145  if (!sts)
146  {
147  TLOG(TLVL_ERROR) << "ReadFragmentData: Buffer " << active_buffer_ << " returned bad status code from Read";
148  MarkBufferEmpty(active_buffer_);
149  active_buffer_ = -1;
150  return -2;
151  }
152 
153  MarkBufferEmpty(active_buffer_);
154  active_buffer_ = -1;
155  return 0;
156 }
RawDataType word_count
number of RawDataType words in this Fragment
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...
RawDataType sequence_id
The 48-bit sequence_id uniquely identifies events within the artdaq system.
constexpr size_t GetElapsedTimeMicroseconds(std::chrono::steady_clock::time_point then, std::chrono::steady_clock::time_point now=std::chrono::steady_clock::now())
Gets the number of microseconds in the given time interval
Definition: TimeUtils.hh:41
void resize(std::size_t sz)
Resize the data payload to hold sz RawDataType words.
Definition: Fragment.hh:1012
SharedMemoryFragmentManager(uint32_t shm_key, size_t buffer_count=0, size_t max_buffer_size=0, size_t buffer_timeout_us=100 *1000000)
SharedMemoryFragmentManager Constructor.
The SharedMemoryManager creates a Shared Memory area which is divided into a number of fixed-size buf...
int WriteFragment(Fragment &&fragment, bool overwrite, size_t timeout_us)
Write a Fragment to the Shared Memory.
detail::RawFragmentHeader::RawDataType RawDataType
The RawDataType (currently a 64-bit integer) is the basic unit of data representation within artdaq ...
Definition: Fragment.hh:40
int ReadFragmentHeader(detail::RawFragmentHeader &header)
Read a Fragment Header from the Shared Memory.
int ReadFragment(Fragment &fragment)
Read a Fragment from the Shared Memory.
bool ReadyForWrite(bool overwrite) override
Check if a buffer is ready for writing, and if so, reserves it for use.
A Fragment contains the data from one piece of the DAQ system for one event The artdaq::Fragment is t...
Definition: Fragment.hh:85
int ReadFragmentData(RawDataType *destination, size_t words)
Read Fragment Data from the Shared Memory.
RawDataType * headerAddress()
Gets the address of the header.
Definition: Fragment.hh:1153