9 #ifndef shmimMonitor_hpp
10 #define shmimMonitor_hpp
13 #include <ImageStreamIO/ImageStruct.h>
14 #include <ImageStreamIO/ImageStreamIO.h>
16 #include "../../libMagAOX/common/paths.hpp"
30 return "shmimMonitor";
77 template<
class derivedT,
class specificT=shmimT>
248 return *
static_cast<derivedT *
>(
this);
253 template<
class derivedT,
class specificT>
257 template<
class derivedT,
class specificT>
260 config.add(specificT::configSection()+
".threadPrio",
"", specificT::configSection()+
".threadPrio", argType::Required, specificT::configSection(),
"threadPrio",
false,
"int",
"The real-time priority of the shmimMonitor thread.");
262 config.add(specificT::configSection()+
".cpuset",
"", specificT::configSection()+
".cpuset", argType::Required, specificT::configSection(),
"cpuset",
false,
"string",
"The cpuset for the shmimMonitor thread.");
264 config.add(specificT::configSection()+
".shmimName",
"", specificT::configSection()+
".shmimName", argType::Required, specificT::configSection(),
"shmimName",
false,
"string",
"The name of the ImageStreamIO shared memory image. Will be used as /tmp/<shmimName>.im.shm.");
266 config.add(specificT::configSection()+
".getExistingFirst",
"", specificT::configSection()+
".getExistingFirst", argType::Required, specificT::configSection(),
"getExistingFirst",
false,
"bool",
"If true an existing image is loaded. If false we wait for a new image.");
269 m_shmimName = derived().configName();
273 template<
class derivedT,
class specificT>
276 config(m_smThreadPrio, specificT::configSection() +
".threadPrio");
277 config(m_smCpuset, specificT::configSection() +
".cpuset");
278 config(m_shmimName, specificT::configSection() +
".shmimName");
279 config(m_getExistingFirst, specificT::configSection() +
".getExistingFirst");
282 template<
class derivedT,
class specificT>
286 m_indiP_shmimName = pcf::IndiProperty(pcf::IndiProperty::Text);
287 m_indiP_shmimName.setDevice(derived().configName());
288 m_indiP_shmimName.setName( specificT::indiPrefix() +
"_shmimName");
289 m_indiP_shmimName.setPerm(pcf::IndiProperty::ReadOnly);
290 m_indiP_shmimName.setState(pcf::IndiProperty::Idle);
291 m_indiP_shmimName.add(pcf::IndiElement(
"name"));
292 m_indiP_shmimName[
"name"] = m_shmimName;
294 if( derived().registerIndiPropertyNew( m_indiP_shmimName,
nullptr) < 0)
296 #ifndef SHMIMMONITOR_TEST_NOLOG
297 derivedT::template log<software_error>({__FILE__,__LINE__});
303 m_indiP_frameSize = pcf::IndiProperty(pcf::IndiProperty::Number);
304 m_indiP_frameSize.setDevice(derived().configName());
305 m_indiP_frameSize.setName(specificT::indiPrefix() +
"_frameSize");
306 m_indiP_frameSize.setPerm(pcf::IndiProperty::ReadOnly);
307 m_indiP_frameSize.setState(pcf::IndiProperty::Idle);
308 m_indiP_frameSize.add(pcf::IndiElement(
"width"));
309 m_indiP_frameSize[
"width"] = 0;
310 m_indiP_frameSize.add(pcf::IndiElement(
"height"));
311 m_indiP_frameSize[
"height"] = 0;
313 if(setSigSegvHandler() < 0)
315 #ifndef SHMIMMONITOR_TEST_NOLOG
316 derivedT::template log<software_error>({__FILE__,__LINE__});
321 if( derived().registerIndiPropertyNew( m_indiP_frameSize,
nullptr) < 0)
323 #ifndef SHMIMMONITOR_TEST_NOLOG
324 derivedT::template log<software_error>({__FILE__,__LINE__});
330 struct sigaction act;
334 act.sa_flags = SA_SIGINFO;
339 if( sigaction(SIGUSR1, &act, 0) < 0 )
341 std::string logss =
"Setting handler for SIGUSR1 failed. Errno says: ";
342 logss += strerror(errno);
344 derivedT::template log<software_error>({__FILE__, __LINE__, errno, 0, logss});
349 if(derived().threadStart( m_smThread, m_smThreadInit, m_smThreadID, m_smThreadProp, m_smThreadPrio, m_smCpuset, specificT::configSection(),
this, smThreadStart) < 0)
351 derivedT::template log<software_error>({__FILE__, __LINE__});
359 template<
class derivedT,
class specificT>
363 if(pthread_tryjoin_np(m_smThread.native_handle(),0) == 0)
365 derivedT::template log<software_error>({__FILE__, __LINE__,
"shmimMonitor thread " + std::to_string(m_smThreadID) +
" has exited"});
374 template<
class derivedT,
class specificT>
377 if(m_smThread.joinable())
379 pthread_kill(m_smThread.native_handle(), SIGUSR1);
392 template<
class derivedT,
class specificT>
395 struct sigaction act;
399 act.sa_flags = SA_SIGINFO;
404 if( sigaction(SIGSEGV, &act, 0) < 0 )
406 std::string logss =
"Setting handler for SIGSEGV failed. Errno says: ";
407 logss += strerror(errno);
409 derivedT::template log<software_error>({__FILE__, __LINE__, errno, 0, logss});
415 if( sigaction(SIGBUS, &act, 0) < 0 )
417 std::string logss =
"Setting handler for SIGBUS failed. Errno says: ";
418 logss += strerror(errno);
420 derivedT::template log<software_error>({__FILE__, __LINE__, errno, 0,logss});
425 derivedT::template log<text_log>(
"Installed SIGSEGV/SIGBUS signal handler.",
logPrio::LOG_DEBUG);
430 template<
class derivedT,
class specificT>
436 m_selfMonitor->handlerSigSegv(signum, siginf, ucont);
439 template<
class derivedT,
class specificT>
445 static_cast<void>(signum);
446 static_cast<void>(siginf);
447 static_cast<void>(ucont);
454 template<
class derivedT,
class specificT>
461 template<
class derivedT,
class specificT>
464 m_smThreadID = syscall(SYS_gettid);
467 while( m_smThreadInit ==
true && derived().shutdown() == 0)
476 while(derived().shutdown() == 0)
478 while((derived().state() !=
stateCodes::OPERATING || m_shmimName ==
"" ) && !derived().shutdown() && !m_restart )
483 if(derived().shutdown())
return;
497 ImageStreamIO_filename(SM_fname,
sizeof(SM_fname), m_shmimName.c_str());
498 SM_fd = open(SM_fname, O_RDWR);
501 if(!logged) derivedT::template log<text_log>(
"ImageStream " + m_shmimName +
" not found (yet). Retrying . . .",
logPrio::LOG_NOTICE);
511 if( ImageStreamIO_openIm(&m_imageStream, m_shmimName.c_str()) == 0)
513 if(m_imageStream.md[0].sem <= m_semaphoreNumber)
515 ImageStreamIO_closeIm(&m_imageStream);
522 ImageStreamIO_filename(SM_fname,
sizeof(SM_fname), m_shmimName.c_str());
525 int rv = stat(SM_fname, &buffer);
529 derivedT::template log<software_critical>({__FILE__,__LINE__, errno,
"Could not get inode for " + m_shmimName +
". Source process will need to be restarted."});
530 ImageStreamIO_closeIm(&m_imageStream);
533 m_inode = buffer.st_ino;
544 if(m_restart)
continue;
548 if(derived().m_shutdown)
552 ImageStreamIO_closeIm(&m_imageStream);
556 m_semaphoreNumber = ImageStreamIO_getsemwaitindex(&m_imageStream, m_semaphoreNumber);
558 if(m_semaphoreNumber < 0)
560 derivedT::template log<software_critical>({__FILE__,__LINE__,
"No valid semaphore found for " + m_shmimName +
". Source process will need to be restarted."});
564 derivedT::template log<software_info>({__FILE__,__LINE__,
"got semaphore index " + std::to_string(m_semaphoreNumber) +
" for " + m_shmimName });
566 ImageStreamIO_semflush(&m_imageStream, m_semaphoreNumber);
568 sem_t * sem = m_imageStream.semptr[m_semaphoreNumber];
570 m_dataType = m_imageStream.md[0].datatype;
571 m_typeSize = ImageStreamIO_typesize(m_dataType);
572 m_width = m_imageStream.md[0].size[0];
574 if(m_imageStream.md[0].naxis > 1)
576 m_height = m_imageStream.md[0].size[1];
578 if(m_imageStream.md[0].naxis > 2)
581 m_depth = m_imageStream.md[0].size[2];
595 if( derived().allocate( specificT()) < 0)
597 derivedT::template log<software_error>({__FILE__,__LINE__,
"allocation failed"});
602 size_t snx, sny, snz;
605 if(m_getExistingFirst && !m_restart && derived().shutdown() == 0)
607 if(m_imageStream.md[0].size[2] > 0)
609 curr_image = m_imageStream.md[0].cnt1;
613 atype = m_imageStream.md[0].datatype;
614 snx = m_imageStream.md[0].size[0];
618 sny = m_imageStream.md[0].size[1];
623 sny = m_imageStream.md[0].size[1];
624 snz = m_imageStream.md[0].size[2];
632 if( atype!= m_dataType || snx != m_width || sny != m_height || snz != m_depth )
637 char * curr_src = (
char *) m_imageStream.array.raw + curr_image*m_width*m_height*m_typeSize;
639 if( derived().processImage(curr_src, specificT()) < 0)
641 derivedT::template log<software_error>({__FILE__,__LINE__});
651 if(clock_gettime(CLOCK_REALTIME, &ts) < 0)
653 derivedT::template log<software_critical>({__FILE__,__LINE__,errno,0,
"clock_gettime"});
659 if(sem_timedwait(sem, &ts) == 0)
661 if(m_imageStream.md[0].size[2] > 0)
663 curr_image = m_imageStream.md[0].cnt1;
667 atype = m_imageStream.md[0].datatype;
668 snx = m_imageStream.md[0].size[0];
672 sny = m_imageStream.md[0].size[1];
677 sny = m_imageStream.md[0].size[1];
678 snz = m_imageStream.md[0].size[2];
686 if( atype!= m_dataType || snx != m_width || sny != m_height || snz != m_depth )
693 char * curr_src = (
char *) m_imageStream.array.raw + curr_image*m_width*m_height*m_typeSize;
695 if( derived().processImage(curr_src, specificT()) < 0)
697 derivedT::template log<software_error>({__FILE__,__LINE__});
702 if(m_imageStream.md[0].sem <= 0)
break;
705 if(errno == EINTR)
break;
709 if(errno != ETIMEDOUT)
711 derivedT::template log<software_error>({__FILE__, __LINE__,errno,
"sem_timedwait"});
718 ImageStreamIO_filename(SM_fname,
sizeof(SM_fname), m_shmimName.c_str());
719 SM_fd = open(SM_fname, O_RDWR);
728 int rv = stat(SM_fname, &buffer);
734 if(buffer.st_ino != m_inode)
748 if(m_semaphoreNumber >= 0) m_imageStream.semReadPID[m_semaphoreNumber] = 0;
749 ImageStreamIO_closeIm(&m_imageStream);
762 ImageStreamIO_closeIm(&m_imageStream);
768 template<
class derivedT,
class specificT>
771 if( !derived().m_indiDriver )
return 0;
bool m_smThreadInit
Synchronizer for thread startup, to allow priority setting to finish.
uint32_t m_depth
The depth of the circular buffer in the stream.
int appStartup()
Startup function.
pid_t m_smThreadID
The s.m. thread PID.
void handlerSigSegv(int signum, siginfo_t *siginf, void *ucont)
Handles SIGSEGV and SIGBUS. Sets m_restart to true.
void smThreadExec()
Execute the monitoring thread.
static shmimMonitor * m_selfMonitor
Static pointer to this (set in constructor). Used for getting out of the static SIGSEGV handler.
uint32_t m_width
The width of the images in the stream.
int updateINDI()
Update the INDI properties for this device controller.
int appLogic()
Checks the shmimMonitor thread.
uint32_t m_height
The height of the images in the stream.
std::thread m_smThread
A separate thread for the actual monitoring.
int m_smThreadPrio
Priority of the shmimMonitor thread, should normally be > 00.
IMAGE m_imageStream
The ImageStreamIO shared memory buffer.
pcf::IndiProperty m_indiP_shmimName
Property used to report the shmim buffer name.
pcf::IndiProperty m_indiP_frameSize
Property used to report the current frame size.
static void smThreadStart(shmimMonitor *s)
Thread starter, called by MagAOXApp::threadStart on thread construction. Calls smThreadExec.
int m_semaphoreNumber
The image structure semaphore index.
std::string m_shmimName
The name of the shared memory image, is used in /tmp/<shmimName>.im.shm. Derived classes should set a...
int appShutdown()
Shuts down the shmimMonitor thread.
uint8_t m_dataType
The ImageStreamIO type code.
bool m_restart
Flag indicating tha the shared memory should be reinitialized.
pcf::IndiProperty m_smThreadProp
The property to hold the s.m. thread details.
static void _handlerSigSegv(int signum, siginfo_t *siginf, void *ucont)
The handler called when SIGSEGV or SIGBUS is received, which will be due to ImageStreamIO server rese...
size_t m_typeSize
The size of the type, in bytes. Result of sizeof.
ino_t m_inode
The inode of the image stream file.
void setupConfig(mx::app::appConfigurator &config)
Setup the configuration system.
std::string m_smCpuset
The cpuset to assign the shmimMonitor thread to. Ignored if empty (the default).
int setSigSegvHandler()
Sets the handler for SIGSEGV and SIGBUS.
bool m_getExistingFirst
If set to true by derivedT, any existing image will be grabbed and sent to processImage before waitin...
void loadConfig(mx::app::appConfigurator &config)
load the configuration system results
@ OPERATING
The device is operating, other than homing.
void updateIfChanged(pcf::IndiProperty &p, const std::string &el, const T &newVal, indiDriverT *indiDriver, pcf::IndiProperty::PropertyStateType newState=pcf::IndiProperty::Ok)
Update the value of the INDI element, but only if it has changed.
void sigUsr1Handler(int signum, siginfo_t *siginf, void *ucont)
Empty signal handler. SIGUSR1 is used to interrupt sleep in various threads.
constexpr static logPrioT LOG_DEBUG
Used for debugging.
constexpr static logPrioT LOG_NOTICE
A normal but significant condition.
static std::string configSection()
static std::string indiPrefix()