/* Copyright 2011-2012 FARGOS Development, LLC */ #ifndef _SHARED_VARIABLE_HPP_ #define _SHARED_VARIABLE_HPP_ "$Id: shared_variable.hpp 43 2011-07-26 08:49:09Z geoff $" #include //needed for deferredList #include #include #include // to pick up MAP_FILE defines for createSegment modes /*! \brief Shared memory variable which allows statistics and operational * controls to be exposed to other processes with minimal runtime overhead. */ class SharedMemoryVariable { friend class SharedMemoryVariableManager; public: enum SharedMemoryVariableType { SMV_TYPE_NONE=0, SMV_TYPE_UNSIGNED=1, SMV_TYPE_LARGE=2, SMV_TYPE_INT32=4, SMV_TYPE_UINT32=SMV_TYPE_INT32|SMV_TYPE_UNSIGNED, SMV_TYPE_INT64=SMV_TYPE_INT32|SMV_TYPE_LARGE, SMV_TYPE_UINT64=SMV_TYPE_INT64|SMV_TYPE_UNSIGNED, SMV_TYPE_FLOAT=8, SMV_TYPE_DOUBLE=SMV_TYPE_FLOAT|SMV_TYPE_LARGE, SMV_TYPE_FIXED=SMV_TYPE_FLOAT|SMV_TYPE_UNSIGNED, SMV_TYPE_TINY_STRING=16, // 7 or less chars + null SMV_TYPE_TINY_BINARY_STRING=SMV_TYPE_TINY_STRING|SMV_TYPE_UNSIGNED, SMV_TYPE_STRING=SMV_TYPE_TINY_STRING|SMV_TYPE_LARGE, SMV_TYPE_BINARY_STRING=SMV_TYPE_STRING|SMV_TYPE_UNSIGNED, SMV_TYPE_NAME_NODE=32 }; enum { SMV_DISPLAY_NAME=1, SMV_DISPLAY_VALUE=2, SMV_DISPLAY_TYPE=4, SMV_DISPLAY_EQUALS=8 }; /*! \brief Storage layout for shared memory variable record within * a memory mapped segment. * * Note: all data in this record must be able to be interpreted regardless * of address space. */ struct SharedMemoryVariable_Record { /* WARNING: it is MANDATORY that numericValue be at offset 0 */ union { uint64_t u64; int64_t i64; int32_t i32; uint32_t u32; float f; double d; char tinyString[8]; } numericValue; /* 8 bytes, must be at offset 0 */ uint32_t parentNodeOffset; uint16_t recordType; //!< type of record, see \ref SharedMemoryVariableType uint16_t allocatedLength; //!< allocated length uint16_t usedLength; //!< used length, always <= allocated length uint16_t varNameLength; //!< strlen() + 1; includes null in count char varName[0]; //!< variable name //! \brief Format variable into text buffer. char *formatAsText(char *bfr, int bfrLen, int displayMode, const char *pathPrefix=0) const; //! \brief Get parent path name of variable. int getPathPrefix(char *bfr, int bfrLen, unsigned char *base) const; }; protected: static SharedMemoryVariable_Record unallocated_data; SharedMemoryVariable_Record *dataPointer; class SharedMemoryVariableNode *parentNodeRecord; const char *variableName; unsigned int minLength; unsigned char dataType; unsigned char registered; unsigned char _pad1[2]; public: //! \brief Return type as text string. static const char *typeName(unsigned int t); //! \brief Return type of variable, see \ref SharedMemoryVariableType unsigned int getType() const OME_ALWAYS_INLINE { return (dataType); } //! \brief Return minimum number of bytes required for variable record. unsigned int getMinLength() const OME_ALWAYS_INLINE { return (minLength); } //! \brief Get variable name. const char *getName(uint32_t *retNameLen=0) const OME_ALWAYS_INLINE { if (OME_EXPECT_TRUE(dataPointer != 0)) { if (retNameLen != 0) *retNameLen = dataPointer->varNameLength; return (dataPointer->varName); } else { // not yet allocated if (retNameLen != 0) *retNameLen = strlen(variableName); return (variableName); } } //! \brief Get full path name of variable uint32_t getFullName(char *bfr, uint32_t bfrLen) const; /*! \brief Construct an shared memory variable and attach to the * indicated manager for the collection of variables. */ SharedMemoryVariable(class SharedMemoryVariableManager *mgr, const char *varName, int varType, unsigned int length, class SharedMemoryVariableNode *parentNode = 0); virtual ~SharedMemoryVariable(); }; // end class SharedMemoryVariable /*! \brief Manager for collection of shared memory variables. * * \note One of the significant features of the SharedMemoryVariableManager * is that it provides support for registering SharedMemoryVariables with it * prior to the shared memory segment being created. This allows static * variables to be defined and the segment to be created at runtime after * a file name is computed. */ class SharedMemoryVariableManager { protected: typedef std::set smv_list_t; smv_list_t *deferredList; BufferRegion *bfrMgr; unsigned char *regionBase; unsigned int regionLength; /*! \brief Internal routine to allocate storage within the segment /* for a shared memory variable. */ void allocateVariable(SharedMemoryVariable *var); public: //! \brief Open a file and map it to a memory segment for variable // storage. static unsigned char *createSegment(const char *fileName, uint32_t *segmentLengthPtr, int initMode); //! \brief Use an existing memory segment for variable storage. void attachExistingSegment(unsigned char *segment, uint32_t segmentLength); //! \brief Initialize a memory segment for use variable storage. void initializeSegment(unsigned char *segment, uint32_t segmentLength, const char *componentName); /*! \brief Convenience function to create a file and map it to * segment for variable storage. The filename will include the * component name, date, and process Id. */ unsigned char *createAndAttachStandardSegment(const char *componentName, uint32_t *segmentLength); /*! \brief Constructor for a shared memory variable manager. * * @param inDataSegment should be set to false if the object is * constructed in the heap (e.g., via the new operator). */ SharedMemoryVariableManager(bool inDataSegment=true); virtual ~SharedMemoryVariableManager(); SharedMemoryVariable::SharedMemoryVariable_Record *iterateOverSegment(SharedBufferAllocRecord **iterator); uint32_t offsetInSegment(const SharedMemoryVariable::SharedMemoryVariable_Record *rec) const { uint32_t result = reinterpret_cast(rec) - bfrMgr->getBufferBase(); return (result); } inline bool initialized() const OME_ALWAYS_INLINE { return (bfrMgr != 0); } //! \brief Register a single variable with the segment manager. bool registerVariable(SharedMemoryVariable &var); //! \brief Register an array of variables with the segment manager. void registerVariables(int count, SharedMemoryVariable *vars[]); }; // end class SharedMemoryVariableManager //! \brief Default shared memory variable manager. extern SharedMemoryVariableManager DEFAULT_sharedMemoryVariableManager; /*! \brief Intermediate naming node for supporting variable naming * hierarchies. Each individual variable only stores its dedicated suffix; * an arbitrary path can be constructed using a linked list of parent naming * nodes and elements in the logical path name hierarchy are only stored once. */ class SharedMemoryVariableNode : public SharedMemoryVariable { public: SharedMemoryVariableNode(const char *varName, SharedMemoryVariableNode *parentNode=0, SharedMemoryVariableManager *mgr=&DEFAULT_sharedMemoryVariableManager) : SharedMemoryVariable(mgr, varName, SMV_TYPE_NAME_NODE, strlen(varName), parentNode) {} }; /*! \brief Convenience template for creating shared memory variables of * one of the supported numeric types. */ template class SMV_Numeric: public SharedMemoryVariable { public: SMV_Numeric(const char *varName, SharedMemoryVariableManager *mgr=&DEFAULT_sharedMemoryVariableManager, SharedMemoryVariableNode *parentNode=0) : SharedMemoryVariable(mgr, varName, typeid(NUMTYPE) == typeid(int32_t) ? SMV_TYPE_INT32 : typeid(NUMTYPE) == typeid(uint32_t) ? SMV_TYPE_UINT32 : typeid(NUMTYPE) == typeid(int64_t) ? SMV_TYPE_INT64 : typeid(NUMTYPE) == typeid(uint64_t) ? SMV_TYPE_UINT64 : typeid(NUMTYPE) == typeid(float) ? SMV_TYPE_FLOAT : typeid(NUMTYPE) == typeid(double) ? SMV_TYPE_DOUBLE : ~0, /* default if unknown */ sizeof(NUMTYPE), parentNode) {} /* WARNING: these all depend on SharedMemoryVariable_Record having * the numeric field at offset 0 */ //! \brief Cast operator for a numeric shared memory variable. inline operator NUMTYPE() const OME_ALWAYS_INLINE { return (*reinterpret_cast(dataPointer)); } //! \brief Assignment operator for a numeric shared memory variable. inline NUMTYPE operator=(const NUMTYPE arg) OME_ALWAYS_INLINE { return (*reinterpret_cast(dataPointer) = arg); } //! \brief Addition operator for a numeric shared memory variable. inline NUMTYPE operator+=(const NUMTYPE arg) OME_ALWAYS_INLINE { return (*reinterpret_cast(dataPointer) += arg); } //! \brief Subtraction operator for a numeric shared memory variable. inline NUMTYPE operator-=(const NUMTYPE arg) OME_ALWAYS_INLINE { return (*reinterpret_cast(dataPointer) -= arg); } }; // end class SMV_Numeric /*! \brief Convenience class for string variables. */ class SMV_String: public SharedMemoryVariable { public: SMV_String(const char *varName, unsigned int reservedLength, SharedMemoryVariableManager *mgr=&DEFAULT_sharedMemoryVariableManager, SharedMemoryVariableNode *parentNode=0) : SharedMemoryVariable(mgr, varName, SMV_TYPE_STRING, reservedLength, parentNode) {}; //! \brief Cast operator for a shared memory string variable. inline operator const char *() const OME_ALWAYS_INLINE { return (dataPointer->varName + dataPointer->varNameLength); }; //! \brief Assignment operator into a shared memory string variable. inline char *operator=(const char *val) OME_ALWAYS_INLINE { // TODO: either externalize the overhead of a record or make // allocatedLength not include any recording keeping overhead. // The FixedBufferManager prefixes the data block with the allocation // record, whereas the CircularBufferManager keeps allocation records // separate from data records. const int headerOverhead = sizeof(SharedMemoryVariable_Record) + sizeof(SharedBufferAllocRecord); // TODO: this depends on storage mode strncpy(dataPointer->varName + dataPointer->varNameLength, val, dataPointer->allocatedLength - (headerOverhead + dataPointer->varNameLength)); return (dataPointer->varName + dataPointer->varNameLength); } }; // end class SMV_String /*! \brief Convenience macro to declare a shared memory counter variable. * * Note: no support for alternate segment managers or parent naming nodes. * Best used for simple instrumentation. */ #define DECLARE_SMV_COUNTER(name) SMV_Numeric name(#name) #endif /* vim: set expandtab shiftwidth=4 tabstop=4: */