00001
00002 #define TRACE_NAME "SharedMemoryFragmentManager"
00003 #include "artdaq-core/Core/SharedMemoryFragmentManager.hh"
00004 #include "tracemf.h"
00005
00006
00007 artdaq::SharedMemoryFragmentManager::SharedMemoryFragmentManager(uint32_t shm_key, size_t buffer_count, size_t max_buffer_size, size_t buffer_timeout_us)
00008 : SharedMemoryManager(shm_key, buffer_count, max_buffer_size, buffer_timeout_us)
00009 , active_buffer_(-1)
00010 {
00011
00012 }
00013
00014 bool artdaq::SharedMemoryFragmentManager::ReadyForWrite(bool overwrite)
00015 {
00016 TLOG(12) << "ReadyForWrite: active_buffer is " << active_buffer_;
00017 if (active_buffer_ != -1) return true;
00018 active_buffer_ = GetBufferForWriting(overwrite);
00019
00020 return active_buffer_ != -1;
00021 }
00022
00023 int artdaq::SharedMemoryFragmentManager::WriteFragment(Fragment&& fragment, bool overwrite, size_t timeout_us)
00024 {
00025 if (!IsValid()) { return -1; }
00026
00027 auto waitStart = std::chrono::steady_clock::now();
00028 while (!ReadyForWrite(overwrite) && TimeUtils::GetElapsedTimeMicroseconds(waitStart) < 1000)
00029 {
00030
00031 }
00032 if (!ReadyForWrite(overwrite))
00033 {
00034 int64_t loopCount = 0;
00035 size_t sleepTime = 1000;
00036 int64_t nloops = (timeout_us - 1000) / sleepTime;
00037
00038 while (!ReadyForWrite(overwrite) && (!overwrite || timeout_us == 0 || loopCount < nloops))
00039 {
00040 usleep(sleepTime);
00041 ++loopCount;
00042 }
00043 }
00044 if (!ReadyForWrite(overwrite))
00045 {
00046 TLOG(TLVL_WARNING) << "No available buffers after waiting for " << TimeUtils::GetElapsedTimeMicroseconds(waitStart) << " us.";
00047 return -3;
00048 }
00049
00050 TLOG(13) << "Sending fragment with seqID=" << fragment.sequenceID() << " using buffer " << active_buffer_;
00051 artdaq::RawDataType* fragAddr = fragment.headerAddress();
00052 size_t fragSize = fragment.size() * sizeof(artdaq::RawDataType);
00053
00054 auto sts = Write(active_buffer_, fragAddr, fragSize);
00055 if (sts == fragSize)
00056 {
00057 TLOG(13) << "Done sending Fragment with seqID=" << fragment.sequenceID() << " using buffer " << active_buffer_;
00058 MarkBufferFull(active_buffer_);
00059 active_buffer_ = -1;
00060 return 0;
00061 }
00062 active_buffer_ = -1;
00063 TLOG(TLVL_ERROR) << "Unexpected status from SharedMemory Write call!";
00064 return -2;
00065 }
00066
00067
00068
00069
00070 int artdaq::SharedMemoryFragmentManager::ReadFragment(Fragment& fragment)
00071 {
00072 TLOG(14) << "ReadFragment BEGIN";
00073 detail::RawFragmentHeader tmpHdr;
00074
00075 TLOG(14) << "Reading Fragment Header";
00076 auto sts = ReadFragmentHeader(tmpHdr);
00077 if (sts != 0) return sts;
00078 fragment.resize(tmpHdr.word_count - tmpHdr.num_words());
00079 memcpy(fragment.headerAddress(), &tmpHdr, tmpHdr.num_words() * sizeof(artdaq::RawDataType));
00080 TLOG(14) << "Reading Fragment Body - of frag w/ seqID="<<tmpHdr.sequence_id;
00081 return ReadFragmentData(fragment.headerAddress() + tmpHdr.num_words(), tmpHdr.word_count - tmpHdr.num_words());
00082 }
00083
00084 int artdaq::SharedMemoryFragmentManager::ReadFragmentHeader(detail::RawFragmentHeader& header)
00085 {
00086 if (!IsValid()) {
00087 TLOG(22) << "ReadFragmentHeader: !IsValid(), returning -3";
00088 return -3;
00089 }
00090
00091 size_t hdrSize = artdaq::detail::RawFragmentHeader::num_words() * sizeof(artdaq::RawDataType);
00092 active_buffer_ = GetBufferForReading();
00093
00094 if (active_buffer_ == -1) {
00095 TLOG(22) << "ReadFragmentHeader: active_buffer==-1, returning -1";
00096 return -1;
00097 }
00098
00099 auto sts = Read(active_buffer_, &header, hdrSize);
00100 if (!sts) {
00101 TLOG(TLVL_ERROR) << "ReadFragmentHeader: Buffer " << active_buffer_ << " returned bad status code from Read";
00102 MarkBufferEmpty(active_buffer_);
00103 active_buffer_ = -1;
00104 return -2;
00105 }
00106
00107 TLOG(22) << "ReadFragmentHeader: read active_buffer_="<<active_buffer_<<" sequence_id="<<header.sequence_id;
00108 return 0;
00109 }
00110
00111 int artdaq::SharedMemoryFragmentManager::ReadFragmentData(RawDataType* destination, size_t words)
00112 {
00113 if (!IsValid() || active_buffer_ == -1 || !CheckBuffer(active_buffer_, BufferSemaphoreFlags::Reading)) {
00114 TLOG(TLVL_ERROR) << "ReadFragmentData: Buffer " << active_buffer_ << " failed status checks: IsValid()=" << std::boolalpha << IsValid() << ", CheckBuffer=" << CheckBuffer(active_buffer_, BufferSemaphoreFlags::Reading);
00115 return -3;
00116 }
00117
00118 auto sts = Read(active_buffer_, destination, words * sizeof(RawDataType));
00119 if (!sts) {
00120 TLOG(TLVL_ERROR) << "ReadFragmentData: Buffer " << active_buffer_ << " returned bad status code from Read";
00121 MarkBufferEmpty(active_buffer_);
00122 active_buffer_ = -1;
00123 return -2;
00124 }
00125
00126 MarkBufferEmpty(active_buffer_);
00127 active_buffer_ = -1;
00128 return 0;
00129 }