artdaq_core  v3_02_01
SharedMemoryFragmentManager.cc
1 
2 #define TRACE_NAME "SharedMemoryFragmentManager"
3 #include "artdaq-core/Core/SharedMemoryFragmentManager.hh"
4 #include "tracemf.h"
5 
6 
7 artdaq::SharedMemoryFragmentManager::SharedMemoryFragmentManager(uint32_t shm_key, size_t buffer_count, size_t max_buffer_size, size_t buffer_timeout_us)
8  : SharedMemoryManager(shm_key, buffer_count, max_buffer_size, buffer_timeout_us)
9  , active_buffer_(-1)
10 {
11 
12 }
13 
15 {
16  TLOG(12) << "ReadyForWrite: active_buffer is " << active_buffer_;
17  if (active_buffer_ != -1) return true;
18  active_buffer_ = GetBufferForWriting(overwrite);
19 
20  return active_buffer_ != -1;
21 }
22 
23 int artdaq::SharedMemoryFragmentManager::WriteFragment(Fragment&& fragment, bool overwrite, size_t timeout_us)
24 {
25  if (!IsValid()) { return -1; }
26 
27  auto waitStart = std::chrono::steady_clock::now();
28  while (!ReadyForWrite(overwrite) && TimeUtils::GetElapsedTimeMicroseconds(waitStart) < 1000)
29  {
30  // BURN THAT CPU!
31  }
32  if (!ReadyForWrite(overwrite))
33  {
34  int64_t loopCount = 0;
35  size_t sleepTime = 1000; // microseconds
36  int64_t nloops = (timeout_us - 1000) / sleepTime;
37 
38  while (!ReadyForWrite(overwrite) && (!overwrite || timeout_us == 0 || loopCount < nloops))
39  {
40  usleep(sleepTime);
41  ++loopCount;
42  }
43  }
44  if (!ReadyForWrite(overwrite))
45  {
46  TLOG(TLVL_WARNING) << "No available buffers after waiting for " << TimeUtils::GetElapsedTimeMicroseconds(waitStart) << " us.";
47  return -3;
48  }
49 
50  TLOG(13) << "Sending fragment with seqID=" << fragment.sequenceID() << " using buffer " << active_buffer_;
51  artdaq::RawDataType* fragAddr = fragment.headerAddress();
52  size_t fragSize = fragment.size() * sizeof(artdaq::RawDataType);
53 
54  auto sts = Write(active_buffer_, fragAddr, fragSize);
55  if (sts == fragSize)
56  {
57  TLOG(13) << "Done sending Fragment with seqID=" << fragment.sequenceID() << " using buffer " << active_buffer_;
58  MarkBufferFull(active_buffer_);
59  active_buffer_ = -1;
60  return 0;
61  }
62  active_buffer_ = -1;
63  TLOG(TLVL_ERROR) << "Unexpected status from SharedMemory Write call!";
64  return -2;
65 }
66 
68 {
69  TLOG(14) << "ReadFragment BEGIN";
71 
72  TLOG(14) << "Reading Fragment Header";
73  auto sts = ReadFragmentHeader(tmpHdr);
74  if (sts != 0) return sts;
75  fragment.resize(tmpHdr.word_count - tmpHdr.num_words());
76  memcpy(fragment.headerAddress(), &tmpHdr, tmpHdr.num_words() * sizeof(artdaq::RawDataType));
77  TLOG(14) << "Reading Fragment Body";
78  return ReadFragmentData(fragment.headerAddress() + tmpHdr.num_words(), tmpHdr.word_count - tmpHdr.num_words());
79 }
80 
82 {
83  if (!IsValid()) return -3;
84 
86  active_buffer_ = GetBufferForReading();
87 
88  if (active_buffer_ == -1) return -1;
89 
90  auto sts = Read(active_buffer_, &header, hdrSize);
91  if (!sts) {
92  TLOG(TLVL_ERROR) << "ReadFragmentData: Buffer " << active_buffer_ << " returned bad status code from Read";
93  MarkBufferEmpty(active_buffer_);
94  active_buffer_ = -1;
95  return -2;
96  }
97 
98  return 0;
99 }
100 
102 {
103  if (!IsValid() || active_buffer_ == -1 || !CheckBuffer(active_buffer_, BufferSemaphoreFlags::Reading)) {
104  TLOG(TLVL_ERROR) << "ReadFragmentData: Buffer " << active_buffer_ << " failed status checks: IsValid()=" << std::boolalpha << IsValid() << ", CheckBuffer=" << CheckBuffer(active_buffer_, BufferSemaphoreFlags::Reading);
105  return -3;
106  }
107 
108  auto sts = Read(active_buffer_, destination, words * sizeof(RawDataType));
109  if (!sts) {
110  TLOG(TLVL_ERROR) << "ReadFragmentData: Buffer " << active_buffer_ << " returned bad status code from Read";
111  MarkBufferEmpty(active_buffer_);
112  active_buffer_ = -1;
113  return -2;
114  }
115 
116  MarkBufferEmpty(active_buffer_);
117  active_buffer_ = -1;
118  return 0;
119 }
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...
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:43
void resize(std::size_t sz)
Resize the data payload to hold sz RawDataType words.
Definition: Fragment.hh:973
SharedMemoryFragmentManager(uint32_t shm_key, size_t buffer_count, size_t max_buffer_size, 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:39
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:84
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:1121