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