artdaq_core  v3_05_07
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) return true;
16  active_buffer_ = GetBufferForWriting(overwrite);
17 
18  return active_buffer_ != -1;
19 }
20 
21 int artdaq::SharedMemoryFragmentManager::WriteFragment(Fragment&& fragment, bool overwrite, size_t timeout_us)
22 {
23  if (!IsValid() || IsEndOfData())
24  {
25  TLOG(TLVL_WARNING) << "WriteFragment: Shared memory is not connected! Attempting reconnect...";
26  auto sts = Attach(timeout_us);
27  if (!sts)
28  {
29  return -1;
30  }
31  TLOG(TLVL_INFO) << "WriteFragment: Shared memory was successfully reconnected";
32  }
33 
34  auto waitStart = std::chrono::steady_clock::now();
35  while (!ReadyForWrite(overwrite) && TimeUtils::GetElapsedTimeMicroseconds(waitStart) < 1000)
36  {
37  // BURN THAT CPU!
38  }
39  if (!ReadyForWrite(overwrite))
40  {
41  int64_t loopCount = 0;
42  size_t sleepTime = 1000; // microseconds
43  int64_t nloops = (timeout_us - 1000) / sleepTime;
44 
45  while (!ReadyForWrite(overwrite) && (!overwrite || timeout_us == 0 || loopCount < nloops))
46  {
47  usleep(sleepTime);
48  ++loopCount;
49  }
50  }
51  if (!ReadyForWrite(overwrite))
52  {
53  TLOG(TLVL_WARNING) << "No available buffers after waiting for " << TimeUtils::GetElapsedTimeMicroseconds(waitStart) << " us.";
54  return -3;
55  }
56 
57  TLOG(13) << "Sending fragment with seqID=" << fragment.sequenceID() << " using buffer " << active_buffer_;
58  artdaq::RawDataType* fragAddr = fragment.headerAddress();
59  size_t fragSize = fragment.size() * sizeof(artdaq::RawDataType);
60 
61  auto sts = Write(active_buffer_, fragAddr, fragSize);
62  if (sts == fragSize)
63  {
64  TLOG(13) << "Done sending Fragment with seqID=" << fragment.sequenceID() << " using buffer " << active_buffer_;
65  MarkBufferFull(active_buffer_);
66  active_buffer_ = -1;
67  return 0;
68  }
69  active_buffer_ = -1;
70  TLOG(TLVL_ERROR) << "Unexpected status from SharedMemory Write call!";
71  return -2;
72 }
73 
74 // NOT currently (2018-07-22) used! ReadFragmentHeader and ReadFragmentData
75 // (below) are called directly
77 {
78  TLOG(14) << "ReadFragment BEGIN";
80 
81  TLOG(14) << "Reading Fragment Header";
82  auto sts = ReadFragmentHeader(tmpHdr);
83  if (sts != 0) return sts;
84  fragment.resize(tmpHdr.word_count - tmpHdr.num_words());
85  memcpy(fragment.headerAddress(), &tmpHdr, tmpHdr.num_words() * sizeof(artdaq::RawDataType));
86  TLOG(14) << "Reading Fragment Body - of frag w/ seqID=" << tmpHdr.sequence_id;
87  return ReadFragmentData(fragment.headerAddress() + tmpHdr.num_words(), tmpHdr.word_count - tmpHdr.num_words());
88 }
89 
91 {
92  if (!IsValid())
93  {
94  TLOG(22) << "ReadFragmentHeader: !IsValid(), returning -3";
95  return -3;
96  }
97 
99  active_buffer_ = GetBufferForReading();
100 
101  if (active_buffer_ == -1)
102  {
103  TLOG(22) << "ReadFragmentHeader: active_buffer==-1, returning -1";
104  return -1;
105  }
106 
107  auto sts = Read(active_buffer_, &header, hdrSize);
108  if (!sts)
109  {
110  TLOG(TLVL_ERROR) << "ReadFragmentHeader: Buffer " << active_buffer_ << " returned bad status code from Read";
111  MarkBufferEmpty(active_buffer_);
112  active_buffer_ = -1;
113  return -2;
114  }
115 
116  TLOG(22) << "ReadFragmentHeader: read active_buffer_=" << active_buffer_ << " sequence_id=" << header.sequence_id;
117  return 0;
118 }
119 
121 {
122  if (!IsValid() || active_buffer_ == -1 || !CheckBuffer(active_buffer_, BufferSemaphoreFlags::Reading))
123  {
124  TLOG(TLVL_ERROR) << "ReadFragmentData: Buffer " << active_buffer_ << " failed status checks: IsValid()=" << std::boolalpha << IsValid() << ", CheckBuffer=" << CheckBuffer(active_buffer_, BufferSemaphoreFlags::Reading);
125  return -3;
126  }
127 
128  auto sts = Read(active_buffer_, destination, words * sizeof(RawDataType));
129  if (!sts)
130  {
131  TLOG(TLVL_ERROR) << "ReadFragmentData: Buffer " << active_buffer_ << " returned bad status code from Read";
132  MarkBufferEmpty(active_buffer_);
133  active_buffer_ = -1;
134  return -2;
135  }
136 
137  MarkBufferEmpty(active_buffer_);
138  active_buffer_ = -1;
139  return 0;
140 }
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:998
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:1139