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