11 #include <boost/filesystem.hpp>
12 #include <boost/lambda/lambda.hpp>
23 :
DummyBackendBase(mapFileName), _mapFile(mapFileName), _barSizesInBytes(getBarSizesInBytesFromRegisterMapping()),
24 sharedMemoryManager(*this, instanceId, mapFileName) {
30 sharedMemoryManager.intDispatcherIf.reset();
35 void SharedDummyBackend::setupBarContents() {
36 for(
auto& _barSizesInByte : _barSizesInBytes) {
37 std::string barName = SHARED_MEMORY_BAR_PREFIX +
std::to_string(_barSizesInByte.first);
39 size_t barSizeInWords = (_barSizesInByte.second +
sizeof(int32_t) - 1) /
sizeof(int32_t);
42 std::lock_guard<boost::interprocess::named_mutex> lock(sharedMemoryManager.interprocessMutex);
43 _barContents[_barSizesInByte.first] = sharedMemoryManager.findOrConstructVector(barName, barSizeInWords);
45 catch(boost::interprocess::bad_alloc&) {
47 sharedMemoryManager.~SharedMemoryManager();
49 std::string errMsg{
"Could not allocate shared memory while constructing registers. "
50 "Please file a bug report at "
51 "https://github.com/ChimeraTK/DeviceAccess."};
70 checkSizeIsMultipleOfWordSize(sizeInBytes);
71 uint64_t wordBaseIndex = address /
sizeof(int32_t);
73 std::lock_guard<boost::interprocess::named_mutex> lock(sharedMemoryManager.interprocessMutex);
74 for(uint64_t wordIndex = 0; wordIndex < sizeInBytes /
sizeof(int32_t); ++wordIndex) {
84 checkSizeIsMultipleOfWordSize(sizeInBytes);
85 uint64_t wordBaseIndex = address /
sizeof(int32_t);
87 std::lock_guard<boost::interprocess::named_mutex> lock(sharedMemoryManager.interprocessMutex);
89 for(uint64_t wordIndex = 0; wordIndex < sizeInBytes /
sizeof(int32_t); ++wordIndex) {
95 std::stringstream info;
96 info <<
"SharedDummyBackend";
100 size_t SharedDummyBackend::getTotalRegisterSizeInBytes()
const {
101 size_t totalRegSize = 0;
102 for(
const auto& pair : _barSizesInBytes) {
103 totalRegSize += pair.second;
108 void SharedDummyBackend::checkSizeIsMultipleOfWordSize(
size_t sizeInBytes) {
109 if(sizeInBytes %
sizeof(int32_t)) {
115 std::string address, std::map<std::string, std::string> parameters) {
116 std::string mapFileName = parameters[
"map"];
117 if(mapFileName.empty()) {
125 return returnInstance<SharedDummyBackend>(address, address, convertPathRelativeToDmapToAbs(mapFileName));
128 std::string SharedDummyBackend::convertPathRelativeToDmapToAbs(
const std::string& mapfileName) {
136 return boost::filesystem::canonical(absPathToMapFile).string();
140 this->sharedMemoryManager.intDispatcherIf->triggerInterrupt(interruptNumber);
147 SharedDummyBackend::InterruptDispatcherInterface::InterruptDispatcherInterface(
SharedDummyBackend& backend,
148 boost::interprocess::managed_shared_memory& shm, boost::interprocess::named_mutex& shmMutex)
149 : _shmMutex(shmMutex), _backend(backend) {
151 _semBuf = shm.find_or_construct<ShmForSems>(boost::interprocess::unique_instance)();
154 _dispatcherThread = boost::movelib::unique_ptr<InterruptDispatcherThread>(
new InterruptDispatcherThread(
this));
157 SharedDummyBackend::InterruptDispatcherInterface::~InterruptDispatcherInterface() {
159 _dispatcherThread.reset();
165 std::lock_guard<boost::interprocess::named_mutex> lock(_shmMutex);
166 _semBuf->removeSem(_semId);
168 catch(boost::interprocess::interprocess_exception&) {
175 void SharedDummyBackend::InterruptDispatcherInterface::cleanupShm(boost::interprocess::managed_shared_memory& shm) {
178 void SharedDummyBackend::InterruptDispatcherInterface::cleanupShm(
179 boost::interprocess::managed_shared_memory& shm,
PidSet* pidSet) {
180 ShmForSems* semBuf = shm.find_or_construct<ShmForSems>(boost::interprocess::unique_instance)();
181 semBuf->cleanup(pidSet);
184 void SharedDummyBackend::InterruptDispatcherInterface::triggerInterrupt(uint32_t intNumber) {
185 std::list<boost::interprocess::interprocess_semaphore*> semList;
187 std::lock_guard<boost::interprocess::named_mutex> lock(_shmMutex);
190 semList = _semBuf->findSems(intNumber,
true);
193 for(
auto* sem : semList) {
195 std::cout <<
" InterruptDispatcherInterface::triggerInterrupt: post sem for interrupt: " << intNumber
203 SharedDummyBackend::InterruptDispatcherThread::InterruptDispatcherThread(
204 InterruptDispatcherInterface* dispatcherInterf)
205 : _dispatcherInterf(dispatcherInterf), _semId(dispatcherInterf->_semId), _semShm(dispatcherInterf->_semBuf) {
206 _thr = boost::thread(&InterruptDispatcherThread::run,
this);
209 SharedDummyBackend::InterruptDispatcherThread::~InterruptDispatcherThread() {
215 catch(boost::system::system_error&) {
220 void SharedDummyBackend::InterruptDispatcherThread::run() {
225 std::map<std::pair<int, int>, std::uint32_t> lastInterruptState;
227 std::lock_guard<boost::interprocess::named_mutex> lock(_dispatcherInterf->_shmMutex);
228 for(
auto& entry : _semShm->interruptEntries) {
229 assert(entry._controllerId == 0);
230 if(!entry.used)
continue;
231 lastInterruptState[std::make_pair(entry._controllerId, entry._intNumber)] = entry._counter;
234 _sem = _semShm->addSem(_semId);
239 InterruptEntry interruptEntries[maxInterruptEntries];
244 std::lock_guard<boost::interprocess::named_mutex> lock(_dispatcherInterf->_shmMutex);
245 std::memcpy(interruptEntries, _semShm->interruptEntries,
sizeof(interruptEntries));
247 for(
auto& entry : interruptEntries) {
248 assert(entry._controllerId == 0);
249 if(!entry.used)
continue;
252 auto key = std::make_pair(entry._controllerId, entry._intNumber);
253 auto it = lastInterruptState.find(key);
254 if(it != lastInterruptState.end()) {
255 while(it->second != entry._counter) {
258 std::cout <<
"existing interrupt event for x,y = " << entry._controllerId <<
", " << entry._intNumber
261 handleInterrupt(entry._intNumber);
269 std::cout <<
"count = " << entry._counter <<
" interrupt events for x,y = " << entry._controllerId <<
", "
270 << entry._intNumber << std::endl;
272 handleInterrupt(entry._intNumber);
273 lastInterruptState[key] = entry._counter;
279 void SharedDummyBackend::InterruptDispatcherThread::stop() noexcept {
284 boost::this_thread::sleep_for(boost::chrono::milliseconds{10});
287 catch(
const boost::thread_interrupted&) {
298 catch(
const boost::system::system_error&) {
306 catch(
const boost::interprocess::interprocess_exception&) {
311 void SharedDummyBackend::InterruptDispatcherThread::handleInterrupt(uint32_t interruptNumber) {
312 SharedDummyBackend& backend = _dispatcherInterf->_backend;
313 auto asyncDomain = boost::dynamic_pointer_cast<async::DomainImpl<std::nullptr_t>>(
314 backend._asyncDomainsContainer.getDomain(interruptNumber));
319 assert(!backend._asyncDomainsContainer.getDomain(interruptNumber));
323 asyncDomain->distribute(
nullptr);
326 SharedDummyBackend::ShmForSems::Sem* SharedDummyBackend::ShmForSems::addSem(SemId semId) {
328 for(
auto& entry : semEntries) {
329 if(entry.used && entry.semId == semId) {
330 throw logic_error(
"error: semId already exists - check assumption about identifiers!");
334 for(
auto& entry : semEntries) {
345 throw runtime_error(
"error: semaphore array full - increase maxSems!");
348 bool SharedDummyBackend::ShmForSems::removeSem(SemId semId) {
350 for(
auto& entry : semEntries) {
351 if(entry.used && entry.semId == semId) {
359 void SharedDummyBackend::ShmForSems::cleanup(
PidSet* pidSet) {
360 for(
auto& entry : semEntries) {
362 if(std::find(std::begin(*pidSet), std::end(*pidSet), (int32_t)entry.semId) == std::end(*pidSet)) {
369 void SharedDummyBackend::ShmForSems::addInterrupt(uint32_t interruptNumber) {
371 for(
auto& entry : interruptEntries) {
372 if(entry.used && entry._controllerId == 0 &&
static_cast<uint32_t
>(entry._intNumber) == interruptNumber) {
380 for(
auto& entry : interruptEntries) {
383 entry._controllerId = 0;
384 entry._intNumber =
static_cast<int>(interruptNumber);
391 throw runtime_error(
"no place left in interruptEntries!");
396 std::list<SharedDummyBackend::ShmForSems::Sem*> SharedDummyBackend::ShmForSems::findSems(
397 uint32_t interruptNumber,
bool update) {
399 for(
auto& entry : semEntries) {
402 ret.push_back(&entry.s);
405 if(update) addInterrupt(interruptNumber);
409 void SharedDummyBackend::ShmForSems::print() {
410 std::cout <<
"shmem contents: " << std::endl;
411 for(
auto& entry : semEntries) {
412 if(entry.used) std::cout <<
"sem : " << entry.semId << std::endl;
414 for(
auto& entry : interruptEntries) {
416 std::cout <<
"interrupt : " << entry._controllerId <<
"," << entry._intNumber <<
" count = " << entry._counter
421 std::cout << std::endl;