/* * jlabROCSharedMemoryWrapper.cpp * * Created on: June 16, 2014 * Author: * * This class provides a wrapper around accessing the shared memory on the ROCs */ #include "jlabROCSharedMemoryWrapper.hh" #include "jlabBoard.hh" #include "jlabFADC250Board.hh" #include "jlabDiscBoard.hh" #include "jlabSSPDIRCBoard.hh" jlabROCSharedMemoryWrapper::jlabROCSharedMemoryWrapper(bool locDebugFlag) : dDebugFlag(locDebugFlag) { dROCSharedMemory = NULL; dStopSharedMemoryThreadFlag = false; Get_SharedMemoryPointer(); // Need to read shared memory to determine which slots contain which types of boards. // Cannot lock (semaphore) to read shared memory, because is a program crashes while reading or writing, it will not release the lock // Thus, we must rely on timing our reads such that they do not overlap writes. // Currently, shared memory is updated every 1 second, and the shared-memory "update" flags are set to indicate when data is updated. // If we check this memory every (e.g.) 100 microseconds, but only read it in if the "update" flag has been changed, // then we should be updating at a high enough frequency to avoid read / write overlaps. // However, at the beginning, we don't know what the previous update flag was. // We can read in the current values, but: // Another program may currently be writing to the shared memory // The update flag itself may be in the process of being overwritten. // Thus, we require that the update flag have changed at least once from the initial input to be sure that the data isn't corrupt // Initialize update flags uint32_t locMemoryUpdateFlag_Discriminators = dROCSharedMemory->discr_scalers.update; uint32_t locMemoryUpdateFlag_FADC250s = dROCSharedMemory->f250_scalers.update; uint32_t locMemoryUpdateFlag_DIRCSCALERs = dROCSharedMemory->dirc_scalers.update; // uint32_t locMemoryUpdateFlag_DIRCTEMPs = dROCSharedMemory->dirc_temps.update; if(dDebugFlag) cout << "check for scalar update" << endl; // Require that EITHER the discriminators OR the FADC250s have been updated. // Don't require both: the crate may only have one type installed. bool locUpdatedFlag = false; while(!locUpdatedFlag) { usleep(100); //sleep for 100 microseconds //Discriminators if(locMemoryUpdateFlag_Discriminators != dROCSharedMemory->discr_scalers.update) locUpdatedFlag = true; //FADC250s if(locMemoryUpdateFlag_FADC250s != dROCSharedMemory->f250_scalers.update) locUpdatedFlag = true; //SSPDIRC if(locMemoryUpdateFlag_DIRCSCALERs != dROCSharedMemory->dirc_scalers.update) locUpdatedFlag = true; // if(locMemoryUpdateFlag_DIRCTEMPs != dROCSharedMemory->dirc_temps.update) // locUpdatedFlag = true; } // The update flag has been recently set, it is safe to read in the current data (as long as we are fast relative to 1 second) if(dDebugFlag) cout << "scalers updated, read slots and create boards" << endl; // Set which slots are which, and create boards for them for(uint32_t locSlot = 1; locSlot <= dNumSlots; ++locSlot) { // Timers are at index 16 (0 -> 15 are channels) // Data is in array indices 1 -> 21 (ignore index 0!) if(dROCSharedMemory->discr_scalers.counters[locSlot][MAX_CHAN] != 0) { dBoardMap[locSlot] = new jlabDiscBoard(locSlot, this); dDiscriminatorSlots.insert(locSlot); } else if(dROCSharedMemory->f250_scalers.counters[locSlot][MAX_CHAN] != 0) { dBoardMap[locSlot] = new jlabFADC250Board(locSlot, this); dFADC250Slots.insert(locSlot); } else if(dROCSharedMemory->dirc_scalers.counters[locSlot][0] != 0 // && dROCSharedMemory->dirc_temps.counters[locSlot][16] != 0 ) ) { dBoardMap[locSlot] = new jlabSSPDIRCBoard(locSlot, this); dDIRCSlots.insert(locSlot); } } // Set initial values for data if(dDebugFlag) cout << "boards created, set initial data" << endl; Update_Discriminators(); Update_FADC250s(); Update_DIRCSCALERs(); } jlabROCSharedMemoryWrapper::~jlabROCSharedMemoryWrapper(void) { } void jlabROCSharedMemoryWrapper::Get_SharedMemoryPointer(void) { // Get the semaphore identifier associated with the key (first argument) // The associated set of N (argument-2) semaphores are created // Returns -1 on error // http://pubs.opengroup.org/onlinepubs/007908799/xsh/semget.html if((semid = semget(SEM_ID1, 1, 0)) < 0) cout << "shmem: cannot get semaphore" << endl; // Get the shared memory identifier associated with the key (first argument) // The associated data structure (and shared memory segment of (at least) N (argument-2) size) are created // Returns -1 on error // http://pubs.opengroup.org/onlinepubs/007908799/xsh/shmget.html if((shmid = shmget(SHM_ID1, sizeof(roc_shmem), 0)) < 0) { stringstream ssMessage; ssMessage << "==> shmem: shared memory 0x" << std::hex << SHM_ID1 << ", size=" << std::dec << sizeof(roc_shmem) << " get error=" << shmid; cout << ssMessage.str(); throw std::runtime_error( ssMessage.str() ); } // Attach the shared memory segment associated with argument-1 to the address space of the calling process // When 2nd-argument is NULL, memory segment is attached to the first-available address space // http://pubs.opengroup.org/onlinepubs/007908799/xsh/shmat.html if((dROCSharedMemory = (roc_shmem*)shmat(shmid, 0, 0)) < 0) { stringstream ssMessage; ssMessage << "==> shmem: shared memory attach error"; cout << ssMessage.str(); throw std::runtime_error( ssMessage.str() ); } cout << "==> shmem: shared memory attached OK ptr=" << std::hex << dROCSharedMemory << std::dec << endl; } void jlabROCSharedMemoryWrapper::Loop_ReadingSharedMemory(void) { // Cannot lock (semaphore) to read shared memory, because is a program crashes while reading or writing, it will not release the lock // Thus, we must rely on timing our reads such that they do not overlap writes. // Currently, shared memory is updated every 1 second, and the shared-memory "update" flags are set to indicate when data is updated. // If we check this memory every (e.g.) 100 microseconds, but only read it in if the "update" flag is different than the last value, // then we should be updating at a high enough frequency to avoid read / write overlaps. // However, at the beginning of the loop, we don't know what the most-recent previous update flag was. // We can read in the current values, but: // Another program may currently be writing to the shared memory // The update flag itself may be in the process of being overwritten. // Thus, we require that the update flag have changed at least once from the initial input to be sure that the data isn't corrupt // Initialize update flags uint32_t locMemoryUpdateFlag_Discriminators = dROCSharedMemory->discr_scalers.update; uint32_t locMemoryUpdateFlag_FADC250s = dROCSharedMemory->f250_scalers.update; uint32_t locMemoryUpdateFlag_DIRCSCALERs = dROCSharedMemory->dirc_scalers.update; // uint32_t locMemoryUpdateFlag_DIRCTEMPs = dROCSharedMemory->dirc_temps.update; if(dDebugFlag) cout << "Begin reading shared memory (loop)" << endl; suseconds_t lastUpdateDIRC = GetTime(); while(!dStopSharedMemoryThreadFlag) { suseconds_t currentTime = GetTime(); // cout << "Old update is " << locMemoryUpdateFlag_DIRCSCALERs << " , new update is " << dROCSharedMemory->dirc_scalers.update << endl; //Discriminators if(locMemoryUpdateFlag_Discriminators != dROCSharedMemory->discr_scalers.update) { //Discriminator data has been updated since last read. Set board data. Update_Discriminators(); locMemoryUpdateFlag_Discriminators = dROCSharedMemory->discr_scalers.update; } if(locMemoryUpdateFlag_FADC250s != dROCSharedMemory->f250_scalers.update) { //FADC250 data has been updated since last read. Set board data. Update_FADC250s(); locMemoryUpdateFlag_FADC250s = dROCSharedMemory->f250_scalers.update; } if(locMemoryUpdateFlag_DIRCSCALERs != dROCSharedMemory->dirc_scalers.update) { //SSPDIRC data has been updated since last read. Set board data. Update_DIRCSCALERs(); locMemoryUpdateFlag_DIRCSCALERs = dROCSharedMemory->dirc_scalers.update; lastUpdateDIRC = currentTime; AlarmBoardsDIRC( true ); } else if( (currentTime - lastUpdateDIRC) > dMaxUpdateWaitTime ) { AlarmBoardsDIRC( false ); } usleep(500); //sleep for 300 microseconds } if(dDebugFlag) cout << "End reading shared memory" << endl; } void jlabROCSharedMemoryWrapper::Update_Discriminators(void) { set::const_iterator locIterator = dDiscriminatorSlots.begin(); for(; locIterator != dDiscriminatorSlots.end(); ++locIterator) { uint32_t locSlot = *locIterator; jlabDiscBoard* locDiscBoard = static_cast(dBoardMap[locSlot]); locDiscBoard->Set_Data(dROCSharedMemory->discr_scalers); } } void jlabROCSharedMemoryWrapper::Update_FADC250s(void) { set::const_iterator locIterator = dFADC250Slots.begin(); for(; locIterator != dFADC250Slots.end(); ++locIterator) { uint32_t locSlot = *locIterator; jlabFADC250Board* locFADC250Board = static_cast(dBoardMap[locSlot]); locFADC250Board->Set_Data(dROCSharedMemory->f250_scalers); } } void jlabROCSharedMemoryWrapper::Update_DIRCSCALERs(void) { set::const_iterator locIterator = dDIRCSlots.begin(); for(; locIterator != dDIRCSlots.end(); ++locIterator) { uint32_t locSlot = *locIterator; jlabSSPDIRCBoard* locSSPDIRCBoard = static_cast(dBoardMap[locSlot]); locSSPDIRCBoard->Set_Data(dROCSharedMemory->dirc_scalers); } } void jlabROCSharedMemoryWrapper::AlarmBoardsDIRC( bool updateStatus ) { set::const_iterator locIterator = dDIRCSlots.begin(); for(; locIterator != dDIRCSlots.end(); ++locIterator) { uint32_t locSlot = *locIterator; jlabSSPDIRCBoard* locSSPDIRCBoard = static_cast(dBoardMap[locSlot]); locSSPDIRCBoard->SetUpdateIsRunning( updateStatus ); } }