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