00001
00002 #include "artdaq-core/Core/SharedMemoryEventReceiver.hh"
00003
00004 #include "artdaq-core/Data/Fragment.hh"
00005 #include <sys/time.h>
00006 #define TRACE_NAME "SharedMemoryEventReceiver"
00007 #include "tracemf.h"
00008
00009 using std::string;
00010
00011 artdaq::SharedMemoryEventReceiver::SharedMemoryEventReceiver(uint32_t shm_key, uint32_t broadcast_shm_key)
00012 : current_read_buffer_(-1)
00013 , initialized_(false)
00014 , current_header_(nullptr)
00015 , current_data_source_(nullptr)
00016 , data_(shm_key)
00017 , broadcasts_(broadcast_shm_key)
00018 {
00019 TLOG(TLVL_TRACE) << "SharedMemoryEventReceiver CONSTRUCTOR" ;
00020 }
00021
00022 bool artdaq::SharedMemoryEventReceiver::ReadyForRead(bool broadcast, size_t timeout_us)
00023 {
00024 TLOG(TLVL_TRACE) << "ReadyForRead BEGIN timeout_us=" << timeout_us ;
00025 if (current_read_buffer_ != -1 && current_data_source_ && current_header_)
00026 {
00027 TLOG(TLVL_TRACE) << "ReadyForRead Returning true because already reading buffer" ;
00028 return true;
00029 }
00030
00031 bool first = true;
00032 auto start_time = TimeUtils::gettimeofday_us();
00033 uint64_t time_diff = 0;
00034 int buf = -1;
00035 while (first || time_diff < timeout_us)
00036 {
00037 if (broadcasts_.ReadyForRead())
00038 {
00039 buf = broadcasts_.GetBufferForReading();
00040 current_data_source_ = &broadcasts_;
00041 }
00042 else if (!broadcast && data_.ReadyForRead())
00043 {
00044 buf = data_.GetBufferForReading();
00045 current_data_source_ = &data_;
00046 }
00047 if (buf != -1 && current_data_source_)
00048 {
00049 current_read_buffer_ = buf;
00050 current_data_source_->ResetReadPos(buf);
00051 current_header_ = reinterpret_cast<detail::RawEventHeader*>(current_data_source_->GetReadPos(buf));
00052 TLOG(TLVL_TRACE) << "ReadyForRead Found buffer, returning true. event hdr sequence_id=" << current_header_->sequence_id;
00053
00054
00055 if (current_data_source_ == &broadcasts_)
00056 {
00057 bool err;
00058 auto types = GetFragmentTypes(err);
00059 if (!err && types.count(Fragment::type_t(Fragment::InitFragmentType)) && initialized_)
00060 {
00061 ReleaseBuffer();
00062 continue;
00063 }
00064 else if (!err && types.count(Fragment::type_t(Fragment::InitFragmentType)))
00065 {
00066 initialized_ = true;
00067 }
00068 }
00069
00070 return true;
00071 }
00072 current_data_source_ = nullptr;
00073 first = false;
00074
00075 time_diff = TimeUtils::gettimeofday_us() - start_time;
00076 usleep(time_diff < 10000 ? time_diff : 10000 );
00077 }
00078 TLOG(TLVL_TRACE) << "ReadyForRead returning false" ;
00079 return false;
00080 }
00081
00082 artdaq::detail::RawEventHeader* artdaq::SharedMemoryEventReceiver::ReadHeader(bool& err)
00083 {
00084 TLOG(TLVL_TRACE) << "ReadHeader BEGIN" ;
00085 if (current_read_buffer_ != -1 && current_data_source_)
00086 {
00087 err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
00088 if (err)
00089 {
00090 TLOG(TLVL_WARNING) << "Buffer was in incorrect state, resetting" ;
00091 current_data_source_ = nullptr;
00092 current_read_buffer_ = -1;
00093 current_header_ = nullptr;
00094 return nullptr;
00095 }
00096 }
00097 TLOG(TLVL_TRACE) << "Already have buffer, returning stored header" ;
00098 return current_header_;
00099 }
00100
00101 std::set<artdaq::Fragment::type_t> artdaq::SharedMemoryEventReceiver::GetFragmentTypes(bool& err)
00102 {
00103 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!";
00104
00105 err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
00106 if (err) return std::set<Fragment::type_t>();
00107
00108 current_data_source_->ResetReadPos(current_read_buffer_);
00109 current_data_source_->IncrementReadPos(current_read_buffer_, sizeof(detail::RawEventHeader));
00110 auto output = std::set<Fragment::type_t>();
00111
00112 while (current_data_source_->MoreDataInBuffer(current_read_buffer_))
00113 {
00114 err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
00115 if (err) return std::set<Fragment::type_t>();
00116 auto fragHdr = reinterpret_cast<artdaq::detail::RawFragmentHeader*>(current_data_source_->GetReadPos(current_read_buffer_));
00117 output.insert(fragHdr->type);
00118 current_data_source_->IncrementReadPos(current_read_buffer_, fragHdr->word_count * sizeof(RawDataType));
00119 }
00120
00121 return output;
00122 }
00123
00124
00125 std::unique_ptr<artdaq::Fragments> artdaq::SharedMemoryEventReceiver::GetFragmentsByType(bool& err, Fragment::type_t type)
00126 {
00127 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!";
00128 err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
00129 if (err) return nullptr;
00130
00131 current_data_source_->ResetReadPos(current_read_buffer_);
00132 current_data_source_->IncrementReadPos(current_read_buffer_, sizeof(detail::RawEventHeader));
00133
00134 std::unique_ptr<Fragments> output(new Fragments());
00135
00136 while (current_data_source_->MoreDataInBuffer(current_read_buffer_))
00137 {
00138 err = !current_data_source_->CheckBuffer(current_read_buffer_, SharedMemoryManager::BufferSemaphoreFlags::Reading);
00139 if (err) return nullptr;
00140 auto fragHdr = reinterpret_cast<artdaq::detail::RawFragmentHeader*>(current_data_source_->GetReadPos(current_read_buffer_));
00141 if (fragHdr->type == type || type == Fragment::InvalidFragmentType)
00142 {
00143 output->emplace_back(fragHdr->word_count - detail::RawFragmentHeader::num_words());
00144 current_data_source_->Read(current_read_buffer_, output->back().headerAddress(), fragHdr->word_count * sizeof(RawDataType));
00145 output->back().autoResize();
00146 }
00147 else
00148 {
00149 current_data_source_->IncrementReadPos(current_read_buffer_, fragHdr->word_count * sizeof(RawDataType));
00150 }
00151 }
00152
00153 return output;
00154 }
00155
00156 std::string artdaq::SharedMemoryEventReceiver::printBuffers_(SharedMemoryManager* data_source)
00157 {
00158 std::ostringstream ostr;
00159 for (size_t ii = 0; ii < data_source->size(); ++ii)
00160 {
00161 ostr << "Buffer " << ii << ": " << std::endl;
00162
00163 data_source->ResetReadPos(ii);
00164 data_source->IncrementReadPos(ii, sizeof(detail::RawEventHeader));
00165
00166 while (data_source->MoreDataInBuffer(ii))
00167 {
00168 auto fragHdr = reinterpret_cast<artdaq::detail::RawFragmentHeader*>(data_source->GetReadPos(ii));
00169 ostr << " Fragment " << fragHdr->fragment_id << ": Sequence ID: " << fragHdr->sequence_id << ", Type:" << fragHdr->type;
00170 if (fragHdr->MakeVerboseSystemTypeMap().count(fragHdr->type))
00171 {
00172 ostr << " (" << fragHdr->MakeVerboseSystemTypeMap()[fragHdr->type] << ")";
00173 }
00174 ostr << ", Size: " << fragHdr->word_count << " words." << std::endl;
00175 data_source->IncrementReadPos(ii, fragHdr->word_count * sizeof(RawDataType));
00176 }
00177
00178 }
00179 return ostr.str();
00180 }
00181
00182 std::string artdaq::SharedMemoryEventReceiver::toString()
00183 {
00184 std::ostringstream ostr;
00185 ostr << data_.toString() << std::endl;
00186
00187 ostr << "Data Buffer Fragment Counts: " << std::endl;
00188 ostr << printBuffers_(&data_);
00189
00190 if (data_.GetKey() != broadcasts_.GetKey())
00191 {
00192 ostr << "Broadcast Buffer Fragment Counts: " << std::endl;
00193 ostr << printBuffers_(&broadcasts_);
00194 }
00195
00196 return ostr.str();
00197 }
00198
00199 void artdaq::SharedMemoryEventReceiver::ReleaseBuffer()
00200 {
00201 TLOG(TLVL_TRACE) << "ReleaseBuffer BEGIN" ;
00202 try
00203 {
00204 if(current_data_source_) current_data_source_->MarkBufferEmpty(current_read_buffer_);
00205 }
00206 catch (cet::exception e)
00207 {
00208 TLOG(TLVL_WARNING) << "A cet::exception occured while trying to release the buffer: " << e ;
00209 }
00210 catch (...)
00211 {
00212 TLOG(TLVL_ERROR) << "An unknown exception occured while trying to release the buffer" ;
00213 }
00214 current_read_buffer_ = -1;
00215 current_header_ = nullptr;
00216 current_data_source_ = nullptr;
00217 TLOG(TLVL_TRACE) << "ReleaseBuffer END" ;
00218 }