diff --git a/Examples/ThreadSafety/.gitignore b/Examples/ThreadSafety/.gitignore new file mode 100644 index 00000000..e74f470b --- /dev/null +++ b/Examples/ThreadSafety/.gitignore @@ -0,0 +1 @@ +LibThreadSafe_component diff --git a/Examples/ThreadSafety/LibThreadSafe_component/Bindings/CppDynamic/libthreadsafe_dynamic.h b/Examples/ThreadSafety/LibThreadSafe_component/Bindings/CppDynamic/libthreadsafe_dynamic.h new file mode 100644 index 00000000..bd577fd8 --- /dev/null +++ b/Examples/ThreadSafety/LibThreadSafe_component/Bindings/CppDynamic/libthreadsafe_dynamic.h @@ -0,0 +1,212 @@ +/*++ + +Copyright (C) 2025 Thread-safe library developers + +All rights reserved. + +This file has been generated by the Automatic Component Toolkit (ACT) version 1.8.1-develop. + +Abstract: This is an autogenerated C++-Header file in order to allow an easy + use of Thread-safe library + +Interface version: 1.0.0 + +*/ + +#ifndef __LIBTHREADSAFE_DYNAMICHEADER_CPPTYPES +#define __LIBTHREADSAFE_DYNAMICHEADER_CPPTYPES + +#include "libthreadsafe_types.hpp" + + + +/************************************************************************************************************************* + Class definition for Base +**************************************************************************************************************************/ + +/** +* Get Class Type Id +* +* @param[in] pBase - Base instance. +* @param[out] pClassTypeId - Class type as a 64 bits integer +* @return error code or 0 (success) +*/ +typedef LibThreadSafeResult (*PLibThreadSafeBase_ClassTypeIdPtr) (LibThreadSafe_Base pBase, LibThreadSafe_uint64 * pClassTypeId); + +/** +* If thread safety for class in library is enabled it should lock object for calling thread +* +* @param[in] pBase - Base instance. +* @return error code or 0 (success) +*/ +typedef LibThreadSafeResult (*PLibThreadSafeBase__lockInstancePtr) (LibThreadSafe_Base pBase); + +/** +* If thread safety for class in library is enabled it should unlock object for other threads +* +* @param[in] pBase - Base instance. +* @return error code or 0 (success) +*/ +typedef LibThreadSafeResult (*PLibThreadSafeBase__unlockInstancePtr) (LibThreadSafe_Base pBase); + +/************************************************************************************************************************* + Class definition for StringReturner +**************************************************************************************************************************/ + +/** +* Returns a string +* +* @param[in] pStringReturner - StringReturner instance. +* @param[in] nValueBufferSize - size of the buffer (including trailing 0) +* @param[out] pValueNeededChars - will be filled with the count of the written bytes, or needed buffer size. +* @param[out] pValueBuffer - buffer of , may be NULL +* @return error code or 0 (success) +*/ +typedef LibThreadSafeResult (*PLibThreadSafeStringReturner_GetStringPtr) (LibThreadSafe_StringReturner pStringReturner, const LibThreadSafe_uint32 nValueBufferSize, LibThreadSafe_uint32* pValueNeededChars, char * pValueBuffer); + +/** +* Function that may crash when called from different threads at the same time +* +* @param[in] pStringReturner - StringReturner instance. +* @return error code or 0 (success) +*/ +typedef LibThreadSafeResult (*PLibThreadSafeStringReturner_ThreadSafetyCheckPtr) (LibThreadSafe_StringReturner pStringReturner); + +/************************************************************************************************************************* + Class definition for SoftStringReturner +**************************************************************************************************************************/ + +/** +* Returns a string +* +* @param[in] pSoftStringReturner - SoftStringReturner instance. +* @param[in] nValueBufferSize - size of the buffer (including trailing 0) +* @param[out] pValueNeededChars - will be filled with the count of the written bytes, or needed buffer size. +* @param[out] pValueBuffer - buffer of , may be NULL +* @return error code or 0 (success) +*/ +typedef LibThreadSafeResult (*PLibThreadSafeSoftStringReturner_GetStringPtr) (LibThreadSafe_SoftStringReturner pSoftStringReturner, const LibThreadSafe_uint32 nValueBufferSize, LibThreadSafe_uint32* pValueNeededChars, char * pValueBuffer); + +/** +* Function that may crash when called from different threads at the same time +* +* @param[in] pSoftStringReturner - SoftStringReturner instance. +* @return error code or 0 (success) +*/ +typedef LibThreadSafeResult (*PLibThreadSafeSoftStringReturner_ThreadSafetyCheckPtr) (LibThreadSafe_SoftStringReturner pSoftStringReturner); + +/************************************************************************************************************************* + Class definition for StrictStringReturner +**************************************************************************************************************************/ + +/** +* Returns a string +* +* @param[in] pStrictStringReturner - StrictStringReturner instance. +* @param[in] nValueBufferSize - size of the buffer (including trailing 0) +* @param[out] pValueNeededChars - will be filled with the count of the written bytes, or needed buffer size. +* @param[out] pValueBuffer - buffer of , may be NULL +* @return error code or 0 (success) +*/ +typedef LibThreadSafeResult (*PLibThreadSafeStrictStringReturner_GetStringPtr) (LibThreadSafe_StrictStringReturner pStrictStringReturner, const LibThreadSafe_uint32 nValueBufferSize, LibThreadSafe_uint32* pValueNeededChars, char * pValueBuffer); + +/** +* Function that shouldn't crash when called from different threads at the same time +* +* @param[in] pStrictStringReturner - StrictStringReturner instance. +* @return error code or 0 (success) +*/ +typedef LibThreadSafeResult (*PLibThreadSafeStrictStringReturner_ThreadSafetyCheckPtr) (LibThreadSafe_StrictStringReturner pStrictStringReturner); + +/************************************************************************************************************************* + Global functions +**************************************************************************************************************************/ + +/** +* retrieves the binary version of this library. +* +* @param[out] pMajor - returns the major version of this library +* @param[out] pMinor - returns the minor version of this library +* @param[out] pMicro - returns the micro version of this library +* @return error code or 0 (success) +*/ +typedef LibThreadSafeResult (*PLibThreadSafeGetVersionPtr) (LibThreadSafe_uint32 * pMajor, LibThreadSafe_uint32 * pMinor, LibThreadSafe_uint32 * pMicro); + +/** +* Returns the last error recorded on this object +* +* @param[in] pInstance - Instance Handle +* @param[in] nErrorMessageBufferSize - size of the buffer (including trailing 0) +* @param[out] pErrorMessageNeededChars - will be filled with the count of the written bytes, or needed buffer size. +* @param[out] pErrorMessageBuffer - buffer of Message of the last error, may be NULL +* @param[out] pHasError - Is there a last error to query +* @return error code or 0 (success) +*/ +typedef LibThreadSafeResult (*PLibThreadSafeGetLastErrorPtr) (LibThreadSafe_Base pInstance, const LibThreadSafe_uint32 nErrorMessageBufferSize, LibThreadSafe_uint32* pErrorMessageNeededChars, char * pErrorMessageBuffer, bool * pHasError); + +/** +* Acquire shared ownership of an Instance +* +* @param[in] pInstance - Instance Handle +* @return error code or 0 (success) +*/ +typedef LibThreadSafeResult (*PLibThreadSafeAcquireInstancePtr) (LibThreadSafe_Base pInstance); + +/** +* Releases shared ownership of an Instance +* +* @param[in] pInstance - Instance Handle +* @return error code or 0 (success) +*/ +typedef LibThreadSafeResult (*PLibThreadSafeReleaseInstancePtr) (LibThreadSafe_Base pInstance); + +/** +* Creates a new StringReturner instance +* +* @param[out] pInstance - New StringReturner instance +* @return error code or 0 (success) +*/ +typedef LibThreadSafeResult (*PLibThreadSafeCreateStringReturnerPtr) (LibThreadSafe_StringReturner * pInstance); + +/** +* Creates a new SoftStringReturner instance +* +* @param[out] pInstance - New SoftStringReturner instance +* @return error code or 0 (success) +*/ +typedef LibThreadSafeResult (*PLibThreadSafeCreateSoftStringReturnerPtr) (LibThreadSafe_SoftStringReturner * pInstance); + +/** +* Creates a new StrictStringReturner instance +* +* @param[out] pInstance - New StrictStringReturner instance +* @return error code or 0 (success) +*/ +typedef LibThreadSafeResult (*PLibThreadSafeCreateStrictStringReturnerPtr) (LibThreadSafe_StrictStringReturner * pInstance); + +/************************************************************************************************************************* + Function Table Structure +**************************************************************************************************************************/ + +typedef struct { + void * m_LibraryHandle; + PLibThreadSafeBase_ClassTypeIdPtr m_Base_ClassTypeId; + PLibThreadSafeBase__lockInstancePtr m_Base__lockInstance; + PLibThreadSafeBase__unlockInstancePtr m_Base__unlockInstance; + PLibThreadSafeStringReturner_GetStringPtr m_StringReturner_GetString; + PLibThreadSafeStringReturner_ThreadSafetyCheckPtr m_StringReturner_ThreadSafetyCheck; + PLibThreadSafeSoftStringReturner_GetStringPtr m_SoftStringReturner_GetString; + PLibThreadSafeSoftStringReturner_ThreadSafetyCheckPtr m_SoftStringReturner_ThreadSafetyCheck; + PLibThreadSafeStrictStringReturner_GetStringPtr m_StrictStringReturner_GetString; + PLibThreadSafeStrictStringReturner_ThreadSafetyCheckPtr m_StrictStringReturner_ThreadSafetyCheck; + PLibThreadSafeGetVersionPtr m_GetVersion; + PLibThreadSafeGetLastErrorPtr m_GetLastError; + PLibThreadSafeAcquireInstancePtr m_AcquireInstance; + PLibThreadSafeReleaseInstancePtr m_ReleaseInstance; + PLibThreadSafeCreateStringReturnerPtr m_CreateStringReturner; + PLibThreadSafeCreateSoftStringReturnerPtr m_CreateSoftStringReturner; + PLibThreadSafeCreateStrictStringReturnerPtr m_CreateStrictStringReturner; +} sLibThreadSafeDynamicWrapperTable; + +#endif // __LIBTHREADSAFE_DYNAMICHEADER_CPPTYPES + diff --git a/Examples/ThreadSafety/LibThreadSafe_component/Bindings/CppDynamic/libthreadsafe_dynamic.hpp b/Examples/ThreadSafety/LibThreadSafe_component/Bindings/CppDynamic/libthreadsafe_dynamic.hpp new file mode 100644 index 00000000..4981ebd2 --- /dev/null +++ b/Examples/ThreadSafety/LibThreadSafe_component/Bindings/CppDynamic/libthreadsafe_dynamic.hpp @@ -0,0 +1,980 @@ +/*++ + +Copyright (C) 2025 Thread-safe library developers + +All rights reserved. + +This file has been generated by the Automatic Component Toolkit (ACT) version 1.8.1-develop. + +Abstract: This is an autogenerated C++-Header file in order to allow an easy + use of Thread-safe library + +Interface version: 1.0.0 + +*/ + +#ifndef __LIBTHREADSAFE_CPPHEADER_DYNAMIC_CPP +#define __LIBTHREADSAFE_CPPHEADER_DYNAMIC_CPP + +#include "libthreadsafe_types.hpp" +#include "libthreadsafe_dynamic.h" + + +#ifdef _WIN32 +#include +#else // _WIN32 +#include +#endif // _WIN32 +#include +#include +#include +#include +#include + +namespace LibThreadSafe { + +/************************************************************************************************************************* + Forward Declaration of all classes +**************************************************************************************************************************/ +class CWrapper; +class CBase; +class CStringReturner; +class CSoftStringReturner; +class CStrictStringReturner; + +/************************************************************************************************************************* + Declaration of deprecated class types +**************************************************************************************************************************/ +typedef CWrapper CLibThreadSafeWrapper; +typedef CBase CLibThreadSafeBase; +typedef CStringReturner CLibThreadSafeStringReturner; +typedef CSoftStringReturner CLibThreadSafeSoftStringReturner; +typedef CStrictStringReturner CLibThreadSafeStrictStringReturner; + +/************************************************************************************************************************* + Declaration of shared pointer types +**************************************************************************************************************************/ +typedef std::shared_ptr PWrapper; +typedef std::shared_ptr PBase; +typedef std::shared_ptr PStringReturner; +typedef std::shared_ptr PSoftStringReturner; +typedef std::shared_ptr PStrictStringReturner; + +/************************************************************************************************************************* + Declaration of deprecated shared pointer types +**************************************************************************************************************************/ +typedef PWrapper PLibThreadSafeWrapper; +typedef PBase PLibThreadSafeBase; +typedef PStringReturner PLibThreadSafeStringReturner; +typedef PSoftStringReturner PLibThreadSafeSoftStringReturner; +typedef PStrictStringReturner PLibThreadSafeStrictStringReturner; + + +/************************************************************************************************************************* + classParam Definition +**************************************************************************************************************************/ + +template class classParam { +private: + std::shared_ptr m_sharedPtr; + const T* m_ptr; + +public: + classParam(const T* ptr) + : m_ptr(ptr) + { + } + + classParam(std::shared_ptr sharedPtr) + : m_sharedPtr(sharedPtr), m_ptr(sharedPtr.get()) + { + } + + LibThreadSafeHandle GetHandle() + { + if (m_ptr != nullptr) + return m_ptr->handle(); + return (LibThreadSafeHandle)nullptr; + } +}; + + +/************************************************************************************************************************* + Class ELibThreadSafeException +**************************************************************************************************************************/ +class ELibThreadSafeException : public std::exception { +protected: + /** + * Error code for the Exception. + */ + LibThreadSafeResult m_errorCode; + /** + * Error message for the Exception. + */ + std::string m_errorMessage; + std::string m_originalErrorMessage; + +public: + /** + * Exception Constructor. + */ + ELibThreadSafeException(LibThreadSafeResult errorCode, const std::string & sErrorMessage) + : m_errorCode(errorCode), m_originalErrorMessage(sErrorMessage) + { + m_errorMessage = buildErrorMessage(); + } + + /** + * Returns error code + */ + LibThreadSafeResult getErrorCode() const noexcept + { + return m_errorCode; + } + + /** + * Returns error message + */ + const char* what() const noexcept + { + return m_errorMessage.c_str(); + } + + const char* getErrorMessage() const noexcept + { + return m_originalErrorMessage.c_str(); + } + + const char* getErrorName() const noexcept + { + switch(getErrorCode()) { + case LIBTHREADSAFE_SUCCESS: return "SUCCESS"; + case LIBTHREADSAFE_ERROR_NOTIMPLEMENTED: return "NOTIMPLEMENTED"; + case LIBTHREADSAFE_ERROR_INVALIDPARAM: return "INVALIDPARAM"; + case LIBTHREADSAFE_ERROR_INVALIDCAST: return "INVALIDCAST"; + case LIBTHREADSAFE_ERROR_BUFFERTOOSMALL: return "BUFFERTOOSMALL"; + case LIBTHREADSAFE_ERROR_GENERICEXCEPTION: return "GENERICEXCEPTION"; + case LIBTHREADSAFE_ERROR_COULDNOTLOADLIBRARY: return "COULDNOTLOADLIBRARY"; + case LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT: return "COULDNOTFINDLIBRARYEXPORT"; + case LIBTHREADSAFE_ERROR_INCOMPATIBLEBINARYVERSION: return "INCOMPATIBLEBINARYVERSION"; + case LIBTHREADSAFE_ERROR_NORESULTAVAILABLE: return "NORESULTAVAILABLE"; + case LIBTHREADSAFE_ERROR_CALCULATIONABORTED: return "CALCULATIONABORTED"; + } + return "UNKNOWN"; + } + + const char* getErrorDescription() const noexcept + { + switch(getErrorCode()) { + case LIBTHREADSAFE_SUCCESS: return "success"; + case LIBTHREADSAFE_ERROR_NOTIMPLEMENTED: return "functionality not implemented"; + case LIBTHREADSAFE_ERROR_INVALIDPARAM: return "an invalid parameter was passed"; + case LIBTHREADSAFE_ERROR_INVALIDCAST: return "a type cast failed"; + case LIBTHREADSAFE_ERROR_BUFFERTOOSMALL: return "a provided buffer is too small"; + case LIBTHREADSAFE_ERROR_GENERICEXCEPTION: return "a generic exception occurred"; + case LIBTHREADSAFE_ERROR_COULDNOTLOADLIBRARY: return "the library could not be loaded"; + case LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT: return "a required exported symbol could not be found in the library"; + case LIBTHREADSAFE_ERROR_INCOMPATIBLEBINARYVERSION: return "the version of the binary interface does not match the bindings interface"; + case LIBTHREADSAFE_ERROR_NORESULTAVAILABLE: return "no result is available"; + case LIBTHREADSAFE_ERROR_CALCULATIONABORTED: return "a calculation has been aborted"; + } + return "unknown error"; + } + +private: + + std::string buildErrorMessage() const noexcept + { + std::string msg = m_originalErrorMessage; + if (msg.empty()) { + msg = getErrorDescription(); + } + return std::string("Error: ") + getErrorName() + ": " + msg; + } +}; + +/************************************************************************************************************************* + Class CInputVector +**************************************************************************************************************************/ +template +class CInputVector { +private: + + const T* m_data; + size_t m_size; + +public: + + CInputVector(const std::vector& vec) + : m_data( vec.data() ), m_size( vec.size() ) + { + } + + CInputVector(const T* in_data, size_t in_size) + : m_data( in_data ), m_size(in_size ) + { + } + + const T* data() const + { + return m_data; + } + + size_t size() const + { + return m_size; + } + +}; + +// declare deprecated class name +template +using CLibThreadSafeInputVector = CInputVector; + +/************************************************************************************************************************* + Class CWrapper +**************************************************************************************************************************/ +class CWrapper { +public: + + explicit CWrapper(void* pSymbolLookupMethod) + { + CheckError(nullptr, initWrapperTable(&m_WrapperTable)); + CheckError(nullptr, loadWrapperTableFromSymbolLookupMethod(&m_WrapperTable, pSymbolLookupMethod)); + + CheckError(nullptr, checkBinaryVersion()); + } + + explicit CWrapper(const std::string &sFileName) + { + CheckError(nullptr, initWrapperTable(&m_WrapperTable)); + CheckError(nullptr, loadWrapperTable(&m_WrapperTable, sFileName.c_str())); + + CheckError(nullptr, checkBinaryVersion()); + } + + static PWrapper loadLibrary(const std::string &sFileName) + { + return std::make_shared(sFileName); + } + + static PWrapper loadLibraryFromSymbolLookupMethod(void* pSymbolLookupMethod) + { + return std::make_shared(pSymbolLookupMethod); + } + + ~CWrapper() + { + releaseWrapperTable(&m_WrapperTable); + } + + inline void CheckError(CBase * pBaseClass, LibThreadSafeResult nResult, bool unlockIfError = false); + + inline void GetVersion(LibThreadSafe_uint32 & nMajor, LibThreadSafe_uint32 & nMinor, LibThreadSafe_uint32 & nMicro); + inline bool GetLastError(classParam pInstance, std::string & sErrorMessage); + inline void AcquireInstance(classParam pInstance); + inline void ReleaseInstance(classParam pInstance); + inline PStringReturner CreateStringReturner(); + inline PSoftStringReturner CreateSoftStringReturner(); + inline PStrictStringReturner CreateStrictStringReturner(); + + inline CBase* polymorphicFactory(LibThreadSafeHandle); + +private: + sLibThreadSafeDynamicWrapperTable m_WrapperTable; + + LibThreadSafeResult checkBinaryVersion() + { + LibThreadSafe_uint32 nMajor, nMinor, nMicro; + GetVersion(nMajor, nMinor, nMicro); + if (nMajor != LIBTHREADSAFE_VERSION_MAJOR) { + return LIBTHREADSAFE_ERROR_INCOMPATIBLEBINARYVERSION; + } + return LIBTHREADSAFE_SUCCESS; + } + LibThreadSafeResult initWrapperTable(sLibThreadSafeDynamicWrapperTable * pWrapperTable); + LibThreadSafeResult releaseWrapperTable(sLibThreadSafeDynamicWrapperTable * pWrapperTable); + LibThreadSafeResult loadWrapperTable(sLibThreadSafeDynamicWrapperTable * pWrapperTable, const char * pLibraryFileName); + LibThreadSafeResult loadWrapperTableFromSymbolLookupMethod(sLibThreadSafeDynamicWrapperTable * pWrapperTable, void* pSymbolLookupMethod); + + friend class CBase; + friend class CStringReturner; + friend class CSoftStringReturner; + friend class CStrictStringReturner; + +}; + + +/************************************************************************************************************************* + Class CBase +**************************************************************************************************************************/ +class CBase { +public: + +protected: + /* Wrapper Object that created the class. */ + CWrapper * m_pWrapper; + /* Handle to Instance in library*/ + LibThreadSafeHandle m_pHandle; + + /* Checks for an Error code, raises Exceptions and unlocks library object*/ + void CheckError(LibThreadSafeResult nResult, bool unlockIfError) + { + if (m_pWrapper != nullptr) + m_pWrapper->CheckError(this, nResult, unlockIfError); + } +public: + /** + * CBase::CBase - Constructor for Base class. + */ + CBase(CWrapper * pWrapper, LibThreadSafeHandle pHandle) + : m_pWrapper(pWrapper), m_pHandle(pHandle) + { + } + + /** + * CBase::~CBase - Destructor for Base class. + */ + virtual ~CBase() + { + if (m_pWrapper != nullptr) + m_pWrapper->ReleaseInstance(this); + m_pWrapper = nullptr; + } + + /** + * CBase::handle - Returns handle to instance. + */ + LibThreadSafeHandle handle() const + { + return m_pHandle; + } + + /** + * CBase::wrapper - Returns wrapper instance. + */ + CWrapper * wrapper() const + { + return m_pWrapper; + } + + friend class CWrapper; + inline LibThreadSafe_uint64 ClassTypeId(); + +protected: + inline void _lockInstance(); + inline void _unlockInstance(); +}; + +/************************************************************************************************************************* + Class CStringReturner +**************************************************************************************************************************/ +class CStringReturner : public CBase { +public: + + /** + * CStringReturner::CStringReturner - Constructor for StringReturner class. + */ + CStringReturner(CWrapper* pWrapper, LibThreadSafeHandle pHandle) + : CBase(pWrapper, pHandle) + { + } + + inline std::string GetString(); + inline void ThreadSafetyCheck(); +}; + +/************************************************************************************************************************* + Class CSoftStringReturner +**************************************************************************************************************************/ +class CSoftStringReturner : public CBase { +public: + + /** + * CSoftStringReturner::CSoftStringReturner - Constructor for SoftStringReturner class. + */ + CSoftStringReturner(CWrapper* pWrapper, LibThreadSafeHandle pHandle) + : CBase(pWrapper, pHandle) + { + } + + inline std::string GetString(); + inline void ThreadSafetyCheck(); +}; + +/************************************************************************************************************************* + Class CStrictStringReturner +**************************************************************************************************************************/ +class CStrictStringReturner : public CBase { +public: + + /** + * CStrictStringReturner::CStrictStringReturner - Constructor for StrictStringReturner class. + */ + CStrictStringReturner(CWrapper* pWrapper, LibThreadSafeHandle pHandle) + : CBase(pWrapper, pHandle) + { + } + + inline std::string GetString(); + inline void ThreadSafetyCheck(); +}; + +/************************************************************************************************************************* + RTTI: Polymorphic Factory implementation +**************************************************************************************************************************/ + +/** +* IMPORTANT: PolymorphicFactory method should not be used by application directly. +* It's designed to be used on LibThreadSafeHandle object only once. +* If it's used on any existing object as a form of dynamic cast then +* CWrapper::AcquireInstance(CBase object) must be called after instantiating new object. +* This is important to keep reference count matching between application and library sides. +*/ +inline CBase* CWrapper::polymorphicFactory(LibThreadSafeHandle pHandle) +{ + LibThreadSafe_uint64 resultClassTypeId = 0; + CheckError(nullptr, m_WrapperTable.m_Base_ClassTypeId(pHandle, &resultClassTypeId)); + switch(resultClassTypeId) { + case 0x82FEB223BA4B6B0EUL: return new CBase(this, pHandle); break; // First 64 bits of SHA1 of a string: "LibThreadSafe::Base" + case 0x01755067BCC5ED81UL: return new CStringReturner(this, pHandle); break; // First 64 bits of SHA1 of a string: "LibThreadSafe::StringReturner" + case 0x6C0744711291F198UL: return new CSoftStringReturner(this, pHandle); break; // First 64 bits of SHA1 of a string: "LibThreadSafe::SoftStringReturner" + case 0xC8D8EB62D68DF429UL: return new CStrictStringReturner(this, pHandle); break; // First 64 bits of SHA1 of a string: "LibThreadSafe::StrictStringReturner" + } + return new CBase(this, pHandle); +} + + /** + * CWrapper::GetVersion - retrieves the binary version of this library. + * @param[out] nMajor - returns the major version of this library + * @param[out] nMinor - returns the minor version of this library + * @param[out] nMicro - returns the micro version of this library + */ + inline void CWrapper::GetVersion(LibThreadSafe_uint32 & nMajor, LibThreadSafe_uint32 & nMinor, LibThreadSafe_uint32 & nMicro) + { + CheckError(nullptr,m_WrapperTable.m_GetVersion(&nMajor, &nMinor, &nMicro)); + } + + /** + * CWrapper::GetLastError - Returns the last error recorded on this object + * @param[in] pInstance - Instance Handle + * @param[out] sErrorMessage - Message of the last error + * @return Is there a last error to query + */ + inline bool CWrapper::GetLastError(classParam pInstance, std::string & sErrorMessage) + { + LibThreadSafeHandle hInstance = pInstance.GetHandle(); + LibThreadSafe_uint32 bytesNeededErrorMessage = 0; + LibThreadSafe_uint32 bytesWrittenErrorMessage = 0; + bool resultHasError = 0; + CheckError(nullptr,m_WrapperTable.m_GetLastError(hInstance, 0, &bytesNeededErrorMessage, nullptr, &resultHasError)); + std::vector bufferErrorMessage(bytesNeededErrorMessage); + CheckError(nullptr,m_WrapperTable.m_GetLastError(hInstance, bytesNeededErrorMessage, &bytesWrittenErrorMessage, &bufferErrorMessage[0], &resultHasError)); + sErrorMessage = std::string(&bufferErrorMessage[0]); + + return resultHasError; + } + + /** + * CWrapper::AcquireInstance - Acquire shared ownership of an Instance + * @param[in] pInstance - Instance Handle + */ + inline void CWrapper::AcquireInstance(classParam pInstance) + { + LibThreadSafeHandle hInstance = pInstance.GetHandle(); + CheckError(nullptr,m_WrapperTable.m_AcquireInstance(hInstance)); + } + + /** + * CWrapper::ReleaseInstance - Releases shared ownership of an Instance + * @param[in] pInstance - Instance Handle + */ + inline void CWrapper::ReleaseInstance(classParam pInstance) + { + LibThreadSafeHandle hInstance = pInstance.GetHandle(); + CheckError(nullptr,m_WrapperTable.m_ReleaseInstance(hInstance)); + } + + /** + * CWrapper::CreateStringReturner - Creates a new StringReturner instance + * @return New StringReturner instance + */ + inline PStringReturner CWrapper::CreateStringReturner() + { + LibThreadSafeHandle hInstance = (LibThreadSafeHandle)nullptr; + CheckError(nullptr,m_WrapperTable.m_CreateStringReturner(&hInstance)); + + if (!hInstance) { + CheckError(nullptr,LIBTHREADSAFE_ERROR_INVALIDPARAM); + } + return std::shared_ptr(dynamic_cast(this->polymorphicFactory(hInstance))); + } + + /** + * CWrapper::CreateSoftStringReturner - Creates a new SoftStringReturner instance + * @return New SoftStringReturner instance + */ + inline PSoftStringReturner CWrapper::CreateSoftStringReturner() + { + LibThreadSafeHandle hInstance = (LibThreadSafeHandle)nullptr; + CheckError(nullptr,m_WrapperTable.m_CreateSoftStringReturner(&hInstance)); + + if (!hInstance) { + CheckError(nullptr,LIBTHREADSAFE_ERROR_INVALIDPARAM); + } + return std::shared_ptr(dynamic_cast(this->polymorphicFactory(hInstance))); + } + + /** + * CWrapper::CreateStrictStringReturner - Creates a new StrictStringReturner instance + * @return New StrictStringReturner instance + */ + inline PStrictStringReturner CWrapper::CreateStrictStringReturner() + { + LibThreadSafeHandle hInstance = (LibThreadSafeHandle)nullptr; + CheckError(nullptr,m_WrapperTable.m_CreateStrictStringReturner(&hInstance)); + + if (!hInstance) { + CheckError(nullptr,LIBTHREADSAFE_ERROR_INVALIDPARAM); + } + return std::shared_ptr(dynamic_cast(this->polymorphicFactory(hInstance))); + } + + inline void CWrapper::CheckError(CBase * pBaseClass, LibThreadSafeResult nResult, bool unlockIfError) + { + if (nResult != 0) { + std::string sErrorMessage; + if (pBaseClass != nullptr) { + GetLastError(pBaseClass, sErrorMessage); + if (unlockIfError) { + pBaseClass->_unlockInstance(); + } + } + throw ELibThreadSafeException(nResult, sErrorMessage); + } + } + + + inline LibThreadSafeResult CWrapper::initWrapperTable(sLibThreadSafeDynamicWrapperTable * pWrapperTable) + { + if (pWrapperTable == nullptr) + return LIBTHREADSAFE_ERROR_INVALIDPARAM; + + pWrapperTable->m_LibraryHandle = nullptr; + pWrapperTable->m_Base_ClassTypeId = nullptr; + pWrapperTable->m_Base__lockInstance = nullptr; + pWrapperTable->m_Base__unlockInstance = nullptr; + pWrapperTable->m_StringReturner_GetString = nullptr; + pWrapperTable->m_StringReturner_ThreadSafetyCheck = nullptr; + pWrapperTable->m_SoftStringReturner_GetString = nullptr; + pWrapperTable->m_SoftStringReturner_ThreadSafetyCheck = nullptr; + pWrapperTable->m_StrictStringReturner_GetString = nullptr; + pWrapperTable->m_StrictStringReturner_ThreadSafetyCheck = nullptr; + pWrapperTable->m_GetVersion = nullptr; + pWrapperTable->m_GetLastError = nullptr; + pWrapperTable->m_AcquireInstance = nullptr; + pWrapperTable->m_ReleaseInstance = nullptr; + pWrapperTable->m_CreateStringReturner = nullptr; + pWrapperTable->m_CreateSoftStringReturner = nullptr; + pWrapperTable->m_CreateStrictStringReturner = nullptr; + + return LIBTHREADSAFE_SUCCESS; + } + + inline LibThreadSafeResult CWrapper::releaseWrapperTable(sLibThreadSafeDynamicWrapperTable * pWrapperTable) + { + if (pWrapperTable == nullptr) + return LIBTHREADSAFE_ERROR_INVALIDPARAM; + + if (pWrapperTable->m_LibraryHandle != nullptr) { + #ifdef _WIN32 + HMODULE hModule = (HMODULE) pWrapperTable->m_LibraryHandle; + FreeLibrary(hModule); + #else // _WIN32 + dlclose(pWrapperTable->m_LibraryHandle); + #endif // _WIN32 + return initWrapperTable(pWrapperTable); + } + + return LIBTHREADSAFE_SUCCESS; + } + + inline LibThreadSafeResult CWrapper::loadWrapperTable(sLibThreadSafeDynamicWrapperTable * pWrapperTable, const char * pLibraryFileName) + { + if (pWrapperTable == nullptr) + return LIBTHREADSAFE_ERROR_INVALIDPARAM; + if (pLibraryFileName == nullptr) + return LIBTHREADSAFE_ERROR_INVALIDPARAM; + + #ifdef _WIN32 + // Convert filename to UTF16-string + int nLength = 0; + while ((pLibraryFileName[nLength] != 0) && (nLength < MAX_PATH)) + nLength++; + int nBufferSize = nLength * 2 + 2; + std::vector wsLibraryFileName(nBufferSize); + int nResult = MultiByteToWideChar(CP_UTF8, 0, pLibraryFileName, nLength, &wsLibraryFileName[0], nBufferSize); + if (nResult == 0) + return LIBTHREADSAFE_ERROR_COULDNOTLOADLIBRARY; + + HMODULE hLibrary = LoadLibraryW(wsLibraryFileName.data()); + if (hLibrary == 0) + return LIBTHREADSAFE_ERROR_COULDNOTLOADLIBRARY; + #else // _WIN32 + void* hLibrary = dlopen(pLibraryFileName, RTLD_LAZY); + if (hLibrary == 0) + return LIBTHREADSAFE_ERROR_COULDNOTLOADLIBRARY; + dlerror(); + #endif // _WIN32 + + #ifdef _WIN32 + pWrapperTable->m_Base_ClassTypeId = (PLibThreadSafeBase_ClassTypeIdPtr) GetProcAddress(hLibrary, "libthreadsafe_base_classtypeid"); + #else // _WIN32 + pWrapperTable->m_Base_ClassTypeId = (PLibThreadSafeBase_ClassTypeIdPtr) dlsym(hLibrary, "libthreadsafe_base_classtypeid"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_Base_ClassTypeId == nullptr) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + #ifdef _WIN32 + pWrapperTable->m_Base__lockInstance = (PLibThreadSafeBase__lockInstancePtr) GetProcAddress(hLibrary, "libthreadsafe_base__lockinstance"); + #else // _WIN32 + pWrapperTable->m_Base__lockInstance = (PLibThreadSafeBase__lockInstancePtr) dlsym(hLibrary, "libthreadsafe_base__lockinstance"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_Base__lockInstance == nullptr) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + #ifdef _WIN32 + pWrapperTable->m_Base__unlockInstance = (PLibThreadSafeBase__unlockInstancePtr) GetProcAddress(hLibrary, "libthreadsafe_base__unlockinstance"); + #else // _WIN32 + pWrapperTable->m_Base__unlockInstance = (PLibThreadSafeBase__unlockInstancePtr) dlsym(hLibrary, "libthreadsafe_base__unlockinstance"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_Base__unlockInstance == nullptr) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + #ifdef _WIN32 + pWrapperTable->m_StringReturner_GetString = (PLibThreadSafeStringReturner_GetStringPtr) GetProcAddress(hLibrary, "libthreadsafe_stringreturner_getstring"); + #else // _WIN32 + pWrapperTable->m_StringReturner_GetString = (PLibThreadSafeStringReturner_GetStringPtr) dlsym(hLibrary, "libthreadsafe_stringreturner_getstring"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_StringReturner_GetString == nullptr) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + #ifdef _WIN32 + pWrapperTable->m_StringReturner_ThreadSafetyCheck = (PLibThreadSafeStringReturner_ThreadSafetyCheckPtr) GetProcAddress(hLibrary, "libthreadsafe_stringreturner_threadsafetycheck"); + #else // _WIN32 + pWrapperTable->m_StringReturner_ThreadSafetyCheck = (PLibThreadSafeStringReturner_ThreadSafetyCheckPtr) dlsym(hLibrary, "libthreadsafe_stringreturner_threadsafetycheck"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_StringReturner_ThreadSafetyCheck == nullptr) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + #ifdef _WIN32 + pWrapperTable->m_SoftStringReturner_GetString = (PLibThreadSafeSoftStringReturner_GetStringPtr) GetProcAddress(hLibrary, "libthreadsafe_softstringreturner_getstring"); + #else // _WIN32 + pWrapperTable->m_SoftStringReturner_GetString = (PLibThreadSafeSoftStringReturner_GetStringPtr) dlsym(hLibrary, "libthreadsafe_softstringreturner_getstring"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_SoftStringReturner_GetString == nullptr) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + #ifdef _WIN32 + pWrapperTable->m_SoftStringReturner_ThreadSafetyCheck = (PLibThreadSafeSoftStringReturner_ThreadSafetyCheckPtr) GetProcAddress(hLibrary, "libthreadsafe_softstringreturner_threadsafetycheck"); + #else // _WIN32 + pWrapperTable->m_SoftStringReturner_ThreadSafetyCheck = (PLibThreadSafeSoftStringReturner_ThreadSafetyCheckPtr) dlsym(hLibrary, "libthreadsafe_softstringreturner_threadsafetycheck"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_SoftStringReturner_ThreadSafetyCheck == nullptr) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + #ifdef _WIN32 + pWrapperTable->m_StrictStringReturner_GetString = (PLibThreadSafeStrictStringReturner_GetStringPtr) GetProcAddress(hLibrary, "libthreadsafe_strictstringreturner_getstring"); + #else // _WIN32 + pWrapperTable->m_StrictStringReturner_GetString = (PLibThreadSafeStrictStringReturner_GetStringPtr) dlsym(hLibrary, "libthreadsafe_strictstringreturner_getstring"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_StrictStringReturner_GetString == nullptr) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + #ifdef _WIN32 + pWrapperTable->m_StrictStringReturner_ThreadSafetyCheck = (PLibThreadSafeStrictStringReturner_ThreadSafetyCheckPtr) GetProcAddress(hLibrary, "libthreadsafe_strictstringreturner_threadsafetycheck"); + #else // _WIN32 + pWrapperTable->m_StrictStringReturner_ThreadSafetyCheck = (PLibThreadSafeStrictStringReturner_ThreadSafetyCheckPtr) dlsym(hLibrary, "libthreadsafe_strictstringreturner_threadsafetycheck"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_StrictStringReturner_ThreadSafetyCheck == nullptr) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + #ifdef _WIN32 + pWrapperTable->m_GetVersion = (PLibThreadSafeGetVersionPtr) GetProcAddress(hLibrary, "libthreadsafe_getversion"); + #else // _WIN32 + pWrapperTable->m_GetVersion = (PLibThreadSafeGetVersionPtr) dlsym(hLibrary, "libthreadsafe_getversion"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_GetVersion == nullptr) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + #ifdef _WIN32 + pWrapperTable->m_GetLastError = (PLibThreadSafeGetLastErrorPtr) GetProcAddress(hLibrary, "libthreadsafe_getlasterror"); + #else // _WIN32 + pWrapperTable->m_GetLastError = (PLibThreadSafeGetLastErrorPtr) dlsym(hLibrary, "libthreadsafe_getlasterror"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_GetLastError == nullptr) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + #ifdef _WIN32 + pWrapperTable->m_AcquireInstance = (PLibThreadSafeAcquireInstancePtr) GetProcAddress(hLibrary, "libthreadsafe_acquireinstance"); + #else // _WIN32 + pWrapperTable->m_AcquireInstance = (PLibThreadSafeAcquireInstancePtr) dlsym(hLibrary, "libthreadsafe_acquireinstance"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_AcquireInstance == nullptr) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + #ifdef _WIN32 + pWrapperTable->m_ReleaseInstance = (PLibThreadSafeReleaseInstancePtr) GetProcAddress(hLibrary, "libthreadsafe_releaseinstance"); + #else // _WIN32 + pWrapperTable->m_ReleaseInstance = (PLibThreadSafeReleaseInstancePtr) dlsym(hLibrary, "libthreadsafe_releaseinstance"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_ReleaseInstance == nullptr) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + #ifdef _WIN32 + pWrapperTable->m_CreateStringReturner = (PLibThreadSafeCreateStringReturnerPtr) GetProcAddress(hLibrary, "libthreadsafe_createstringreturner"); + #else // _WIN32 + pWrapperTable->m_CreateStringReturner = (PLibThreadSafeCreateStringReturnerPtr) dlsym(hLibrary, "libthreadsafe_createstringreturner"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_CreateStringReturner == nullptr) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + #ifdef _WIN32 + pWrapperTable->m_CreateSoftStringReturner = (PLibThreadSafeCreateSoftStringReturnerPtr) GetProcAddress(hLibrary, "libthreadsafe_createsoftstringreturner"); + #else // _WIN32 + pWrapperTable->m_CreateSoftStringReturner = (PLibThreadSafeCreateSoftStringReturnerPtr) dlsym(hLibrary, "libthreadsafe_createsoftstringreturner"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_CreateSoftStringReturner == nullptr) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + #ifdef _WIN32 + pWrapperTable->m_CreateStrictStringReturner = (PLibThreadSafeCreateStrictStringReturnerPtr) GetProcAddress(hLibrary, "libthreadsafe_createstrictstringreturner"); + #else // _WIN32 + pWrapperTable->m_CreateStrictStringReturner = (PLibThreadSafeCreateStrictStringReturnerPtr) dlsym(hLibrary, "libthreadsafe_createstrictstringreturner"); + dlerror(); + #endif // _WIN32 + if (pWrapperTable->m_CreateStrictStringReturner == nullptr) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + pWrapperTable->m_LibraryHandle = hLibrary; + return LIBTHREADSAFE_SUCCESS; + } + + inline LibThreadSafeResult CWrapper::loadWrapperTableFromSymbolLookupMethod(sLibThreadSafeDynamicWrapperTable * pWrapperTable, void* pSymbolLookupMethod) + { + if (pWrapperTable == nullptr) + return LIBTHREADSAFE_ERROR_INVALIDPARAM; + if (pSymbolLookupMethod == nullptr) + return LIBTHREADSAFE_ERROR_INVALIDPARAM; + + typedef LibThreadSafeResult(*SymbolLookupType)(const char*, void**); + + SymbolLookupType pLookup = (SymbolLookupType)pSymbolLookupMethod; + + LibThreadSafeResult eLookupError = LIBTHREADSAFE_SUCCESS; + eLookupError = (*pLookup)("libthreadsafe_base_classtypeid", (void**)&(pWrapperTable->m_Base_ClassTypeId)); + if ( (eLookupError != 0) || (pWrapperTable->m_Base_ClassTypeId == nullptr) ) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + eLookupError = (*pLookup)("libthreadsafe_base__lockinstance", (void**)&(pWrapperTable->m_Base__lockInstance)); + if ( (eLookupError != 0) || (pWrapperTable->m_Base__lockInstance == nullptr) ) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + eLookupError = (*pLookup)("libthreadsafe_base__unlockinstance", (void**)&(pWrapperTable->m_Base__unlockInstance)); + if ( (eLookupError != 0) || (pWrapperTable->m_Base__unlockInstance == nullptr) ) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + eLookupError = (*pLookup)("libthreadsafe_stringreturner_getstring", (void**)&(pWrapperTable->m_StringReturner_GetString)); + if ( (eLookupError != 0) || (pWrapperTable->m_StringReturner_GetString == nullptr) ) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + eLookupError = (*pLookup)("libthreadsafe_stringreturner_threadsafetycheck", (void**)&(pWrapperTable->m_StringReturner_ThreadSafetyCheck)); + if ( (eLookupError != 0) || (pWrapperTable->m_StringReturner_ThreadSafetyCheck == nullptr) ) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + eLookupError = (*pLookup)("libthreadsafe_softstringreturner_getstring", (void**)&(pWrapperTable->m_SoftStringReturner_GetString)); + if ( (eLookupError != 0) || (pWrapperTable->m_SoftStringReturner_GetString == nullptr) ) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + eLookupError = (*pLookup)("libthreadsafe_softstringreturner_threadsafetycheck", (void**)&(pWrapperTable->m_SoftStringReturner_ThreadSafetyCheck)); + if ( (eLookupError != 0) || (pWrapperTable->m_SoftStringReturner_ThreadSafetyCheck == nullptr) ) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + eLookupError = (*pLookup)("libthreadsafe_strictstringreturner_getstring", (void**)&(pWrapperTable->m_StrictStringReturner_GetString)); + if ( (eLookupError != 0) || (pWrapperTable->m_StrictStringReturner_GetString == nullptr) ) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + eLookupError = (*pLookup)("libthreadsafe_strictstringreturner_threadsafetycheck", (void**)&(pWrapperTable->m_StrictStringReturner_ThreadSafetyCheck)); + if ( (eLookupError != 0) || (pWrapperTable->m_StrictStringReturner_ThreadSafetyCheck == nullptr) ) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + eLookupError = (*pLookup)("libthreadsafe_getversion", (void**)&(pWrapperTable->m_GetVersion)); + if ( (eLookupError != 0) || (pWrapperTable->m_GetVersion == nullptr) ) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + eLookupError = (*pLookup)("libthreadsafe_getlasterror", (void**)&(pWrapperTable->m_GetLastError)); + if ( (eLookupError != 0) || (pWrapperTable->m_GetLastError == nullptr) ) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + eLookupError = (*pLookup)("libthreadsafe_acquireinstance", (void**)&(pWrapperTable->m_AcquireInstance)); + if ( (eLookupError != 0) || (pWrapperTable->m_AcquireInstance == nullptr) ) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + eLookupError = (*pLookup)("libthreadsafe_releaseinstance", (void**)&(pWrapperTable->m_ReleaseInstance)); + if ( (eLookupError != 0) || (pWrapperTable->m_ReleaseInstance == nullptr) ) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + eLookupError = (*pLookup)("libthreadsafe_createstringreturner", (void**)&(pWrapperTable->m_CreateStringReturner)); + if ( (eLookupError != 0) || (pWrapperTable->m_CreateStringReturner == nullptr) ) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + eLookupError = (*pLookup)("libthreadsafe_createsoftstringreturner", (void**)&(pWrapperTable->m_CreateSoftStringReturner)); + if ( (eLookupError != 0) || (pWrapperTable->m_CreateSoftStringReturner == nullptr) ) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + eLookupError = (*pLookup)("libthreadsafe_createstrictstringreturner", (void**)&(pWrapperTable->m_CreateStrictStringReturner)); + if ( (eLookupError != 0) || (pWrapperTable->m_CreateStrictStringReturner == nullptr) ) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + + return LIBTHREADSAFE_SUCCESS; + } + + + /** + * Method definitions for class CBase + */ + + /** + * CBase::ClassTypeId - Get Class Type Id + * @return Class type as a 64 bits integer + */ + LibThreadSafe_uint64 CBase::ClassTypeId() + { + LibThreadSafe_uint64 resultClassTypeId = 0; + CheckError(m_pWrapper->m_WrapperTable.m_Base_ClassTypeId(m_pHandle, &resultClassTypeId), false); + + return resultClassTypeId; + } + + /** + * CBase::_lockInstance - If thread safety for class in library is enabled it should lock object for calling thread + */ + void CBase::_lockInstance() + { + CheckError(m_pWrapper->m_WrapperTable.m_Base__lockInstance(m_pHandle), false); + } + + /** + * CBase::_unlockInstance - If thread safety for class in library is enabled it should unlock object for other threads + */ + void CBase::_unlockInstance() + { + CheckError(m_pWrapper->m_WrapperTable.m_Base__unlockInstance(m_pHandle), false); + } + + /** + * Method definitions for class CStringReturner + */ + + /** + * CStringReturner::GetString - Returns a string + * @return + */ + std::string CStringReturner::GetString() + { + LibThreadSafe_uint32 bytesNeededValue = 0; + LibThreadSafe_uint32 bytesWrittenValue = 0; + CheckError(m_pWrapper->m_WrapperTable.m_StringReturner_GetString(m_pHandle, 0, &bytesNeededValue, nullptr), false); + std::vector bufferValue(bytesNeededValue); + CheckError(m_pWrapper->m_WrapperTable.m_StringReturner_GetString(m_pHandle, bytesNeededValue, &bytesWrittenValue, &bufferValue[0]), false); + + return std::string(&bufferValue[0]); + } + + /** + * CStringReturner::ThreadSafetyCheck - Function that may crash when called from different threads at the same time + */ + void CStringReturner::ThreadSafetyCheck() + { + CheckError(m_pWrapper->m_WrapperTable.m_StringReturner_ThreadSafetyCheck(m_pHandle), false); + } + + /** + * Method definitions for class CSoftStringReturner + */ + + /** + * CSoftStringReturner::GetString - Returns a string + * @return + */ + std::string CSoftStringReturner::GetString() + { + LibThreadSafe_uint32 bytesNeededValue = 0; + LibThreadSafe_uint32 bytesWrittenValue = 0; + _lockInstance(); + CheckError(m_pWrapper->m_WrapperTable.m_SoftStringReturner_GetString(m_pHandle, 0, &bytesNeededValue, nullptr), true); + std::vector bufferValue(bytesNeededValue); + CheckError(m_pWrapper->m_WrapperTable.m_SoftStringReturner_GetString(m_pHandle, bytesNeededValue, &bytesWrittenValue, &bufferValue[0]), true); + _unlockInstance(); + + return std::string(&bufferValue[0]); + } + + /** + * CSoftStringReturner::ThreadSafetyCheck - Function that may crash when called from different threads at the same time + */ + void CSoftStringReturner::ThreadSafetyCheck() + { + CheckError(m_pWrapper->m_WrapperTable.m_SoftStringReturner_ThreadSafetyCheck(m_pHandle), false); + } + + /** + * Method definitions for class CStrictStringReturner + */ + + /** + * CStrictStringReturner::GetString - Returns a string + * @return + */ + std::string CStrictStringReturner::GetString() + { + LibThreadSafe_uint32 bytesNeededValue = 0; + LibThreadSafe_uint32 bytesWrittenValue = 0; + _lockInstance(); + CheckError(m_pWrapper->m_WrapperTable.m_StrictStringReturner_GetString(m_pHandle, 0, &bytesNeededValue, nullptr), true); + std::vector bufferValue(bytesNeededValue); + CheckError(m_pWrapper->m_WrapperTable.m_StrictStringReturner_GetString(m_pHandle, bytesNeededValue, &bytesWrittenValue, &bufferValue[0]), true); + _unlockInstance(); + + return std::string(&bufferValue[0]); + } + + /** + * CStrictStringReturner::ThreadSafetyCheck - Function that shouldn't crash when called from different threads at the same time + */ + void CStrictStringReturner::ThreadSafetyCheck() + { + _lockInstance(); + CheckError(m_pWrapper->m_WrapperTable.m_StrictStringReturner_ThreadSafetyCheck(m_pHandle), true); + _unlockInstance(); + } + +} // namespace LibThreadSafe + +#endif // __LIBTHREADSAFE_CPPHEADER_DYNAMIC_CPP + diff --git a/Examples/ThreadSafety/LibThreadSafe_component/Bindings/CppDynamic/libthreadsafe_types.hpp b/Examples/ThreadSafety/LibThreadSafe_component/Bindings/CppDynamic/libthreadsafe_types.hpp new file mode 100644 index 00000000..cbc3acd4 --- /dev/null +++ b/Examples/ThreadSafety/LibThreadSafe_component/Bindings/CppDynamic/libthreadsafe_types.hpp @@ -0,0 +1,123 @@ +/*++ + +Copyright (C) 2025 Thread-safe library developers + +All rights reserved. + +This file has been generated by the Automatic Component Toolkit (ACT) version 1.8.1-develop. + +Abstract: This is an autogenerated C++-Header file with basic types in +order to allow an easy use of Thread-safe library + +Interface version: 1.0.0 + +*/ + +#ifndef __LIBTHREADSAFE_TYPES_HEADER_CPP +#define __LIBTHREADSAFE_TYPES_HEADER_CPP + + +/************************************************************************************************************************* + Scalar types definition +**************************************************************************************************************************/ + +#ifdef LIBTHREADSAFE_USELEGACYINTEGERTYPES + +typedef unsigned char LibThreadSafe_uint8; +typedef unsigned short LibThreadSafe_uint16 ; +typedef unsigned int LibThreadSafe_uint32; +typedef unsigned long long LibThreadSafe_uint64; +typedef char LibThreadSafe_int8; +typedef short LibThreadSafe_int16; +typedef int LibThreadSafe_int32; +typedef long long LibThreadSafe_int64; + +#else // LIBTHREADSAFE_USELEGACYINTEGERTYPES + +#include + +typedef uint8_t LibThreadSafe_uint8; +typedef uint16_t LibThreadSafe_uint16; +typedef uint32_t LibThreadSafe_uint32; +typedef uint64_t LibThreadSafe_uint64; +typedef int8_t LibThreadSafe_int8; +typedef int16_t LibThreadSafe_int16; +typedef int32_t LibThreadSafe_int32; +typedef int64_t LibThreadSafe_int64 ; + +#endif // LIBTHREADSAFE_USELEGACYINTEGERTYPES + +typedef float LibThreadSafe_single; +typedef double LibThreadSafe_double; + +/************************************************************************************************************************* + General type definitions +**************************************************************************************************************************/ + +typedef LibThreadSafe_int32 LibThreadSafeResult; +typedef void * LibThreadSafeHandle; +typedef void * LibThreadSafe_pvoid; + +/************************************************************************************************************************* + Version for LibThreadSafe +**************************************************************************************************************************/ + +#define LIBTHREADSAFE_VERSION_MAJOR 1 +#define LIBTHREADSAFE_VERSION_MINOR 0 +#define LIBTHREADSAFE_VERSION_MICRO 0 +#define LIBTHREADSAFE_VERSION_PRERELEASEINFO "" +#define LIBTHREADSAFE_VERSION_BUILDINFO "" + +/************************************************************************************************************************* + Error constants for LibThreadSafe +**************************************************************************************************************************/ + +#define LIBTHREADSAFE_SUCCESS 0 +#define LIBTHREADSAFE_ERROR_NOTIMPLEMENTED 1 /** functionality not implemented */ +#define LIBTHREADSAFE_ERROR_INVALIDPARAM 2 /** an invalid parameter was passed */ +#define LIBTHREADSAFE_ERROR_INVALIDCAST 3 /** a type cast failed */ +#define LIBTHREADSAFE_ERROR_BUFFERTOOSMALL 4 /** a provided buffer is too small */ +#define LIBTHREADSAFE_ERROR_GENERICEXCEPTION 5 /** a generic exception occurred */ +#define LIBTHREADSAFE_ERROR_COULDNOTLOADLIBRARY 6 /** the library could not be loaded */ +#define LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT 7 /** a required exported symbol could not be found in the library */ +#define LIBTHREADSAFE_ERROR_INCOMPATIBLEBINARYVERSION 8 /** the version of the binary interface does not match the bindings interface */ +#define LIBTHREADSAFE_ERROR_NORESULTAVAILABLE 9 /** no result is available */ +#define LIBTHREADSAFE_ERROR_CALCULATIONABORTED 10 /** a calculation has been aborted */ + +/************************************************************************************************************************* + Error strings for LibThreadSafe +**************************************************************************************************************************/ + +inline const char * LIBTHREADSAFE_GETERRORSTRING (LibThreadSafeResult nErrorCode) { + switch (nErrorCode) { + case LIBTHREADSAFE_SUCCESS: return "no error"; + case LIBTHREADSAFE_ERROR_NOTIMPLEMENTED: return "functionality not implemented"; + case LIBTHREADSAFE_ERROR_INVALIDPARAM: return "an invalid parameter was passed"; + case LIBTHREADSAFE_ERROR_INVALIDCAST: return "a type cast failed"; + case LIBTHREADSAFE_ERROR_BUFFERTOOSMALL: return "a provided buffer is too small"; + case LIBTHREADSAFE_ERROR_GENERICEXCEPTION: return "a generic exception occurred"; + case LIBTHREADSAFE_ERROR_COULDNOTLOADLIBRARY: return "the library could not be loaded"; + case LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT: return "a required exported symbol could not be found in the library"; + case LIBTHREADSAFE_ERROR_INCOMPATIBLEBINARYVERSION: return "the version of the binary interface does not match the bindings interface"; + case LIBTHREADSAFE_ERROR_NORESULTAVAILABLE: return "no result is available"; + case LIBTHREADSAFE_ERROR_CALCULATIONABORTED: return "a calculation has been aborted"; + default: return "unknown error"; + } +} + +/************************************************************************************************************************* + Declaration of handle classes +**************************************************************************************************************************/ + +typedef LibThreadSafeHandle LibThreadSafe_Base; +typedef LibThreadSafeHandle LibThreadSafe_StringReturner; +typedef LibThreadSafeHandle LibThreadSafe_SoftStringReturner; +typedef LibThreadSafeHandle LibThreadSafe_StrictStringReturner; + +namespace LibThreadSafe { + +} // namespace LibThreadSafe; + +// define legacy C-names for enums, structs and function types + +#endif // __LIBTHREADSAFE_TYPES_HEADER_CPP diff --git a/Examples/ThreadSafety/LibThreadSafe_component/Examples/CppDynamic/CMakeLists.txt b/Examples/ThreadSafety/LibThreadSafe_component/Examples/CppDynamic/CMakeLists.txt new file mode 100644 index 00000000..71931859 --- /dev/null +++ b/Examples/ThreadSafety/LibThreadSafe_component/Examples/CppDynamic/CMakeLists.txt @@ -0,0 +1,26 @@ +#[[++ + +Copyright (C) 2025 Thread-safe library developers + +All rights reserved. + +This file has been generated by the Automatic Component Toolkit (ACT) version 1.8.1-develop. + +Abstract: This is an autogenerated CMake Project that demonstrates the + usage of the Dynamic C++ bindings of Thread-safe library + +Interface version: 1.0.0 + + +]] + +cmake_minimum_required(VERSION 3.5) + +set(CMAKE_CURRENT_BINDING_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../Bindings/CppDynamic) +project(LibThreadSafeExample_CPPDynamic) +set(CMAKE_CXX_STANDARD 20) +add_executable(LibThreadSafeExample_CPPDynamic "${CMAKE_CURRENT_SOURCE_DIR}/LibThreadSafe_example.cpp") +if (UNIX) + target_link_libraries(LibThreadSafeExample_CPPDynamic ${CMAKE_DL_LIBS}) +endif (UNIX) +target_include_directories(LibThreadSafeExample_CPPDynamic PRIVATE "${CMAKE_CURRENT_BINDING_DIR}") diff --git a/Examples/ThreadSafety/LibThreadSafe_component/Examples/CppDynamic/LibThreadSafe_example.cpp b/Examples/ThreadSafety/LibThreadSafe_component/Examples/CppDynamic/LibThreadSafe_example.cpp new file mode 100644 index 00000000..00d7b90e --- /dev/null +++ b/Examples/ThreadSafety/LibThreadSafe_component/Examples/CppDynamic/LibThreadSafe_example.cpp @@ -0,0 +1,55 @@ +/*++ + +Copyright (C) 2025 Thread-safe library developers + +All rights reserved. + +This file has been generated by the Automatic Component Toolkit (ACT) version 1.8.1-develop. + +Abstract: This is an autogenerated C++ application that demonstrates the + usage of the Dynamic C++ bindings of Thread-safe library + +Interface version: 1.0.0 + +*/ + +#include +#include +#include +#include "libthreadsafe_dynamic.hpp" + +template +void testStringReturn(ArrayReturner& returner) +{ + std::vector threads; + for (int i = 0; i < 5; ++i) { + threads.emplace_back([&returner]() { + for (int j = 0; j < 10000; ++j) { + returner->GetString(); + } + }); + } +} + +template +void testThreadSafetyCheck(ArrayReturner& returner) +{ + std::vector threads; + for (int i = 0; i < 5; ++i) { + threads.emplace_back([&returner]() { + for (int j = 0; j < 10000; ++j) { + returner->ThreadSafetyCheck(); + } + }); + } +} + +int main() +{ + std::string libpath = (""); // TODO: put the location of the LibThreadSafe-library file here. + auto wrapper = LibThreadSafe::CWrapper::loadLibrary(libpath + "libthreadsafe."); // TODO: add correct suffix of the library + + LibThreadSafe::PStringReturner stringReturner = wrapper->CreateStringReturner(); + LibThreadSafe::PSoftStringReturner softStringReturner = wrapper->CreateSoftStringReturner(); + LibThreadSafe::PStrictStringReturner strictStringReturner = wrapper->CreateStrictStringReturner(); +} diff --git a/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/CMakeLists.txt b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/CMakeLists.txt new file mode 100644 index 00000000..8170408d --- /dev/null +++ b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/CMakeLists.txt @@ -0,0 +1,46 @@ +#[[++ + +Copyright (C) 2025 Thread-safe library developers + +All rights reserved. + +This file has been generated by the Automatic Component Toolkit (ACT) version 1.8.1-develop. + +Abstract: This is an autogenerated CMakeLists file for the development of Thread-safe library. + +Interface version: 1.0.0 + + +]] + +cmake_minimum_required(VERSION 3.5) + +### The implementation of the Thread-safe library component +project(LibThreadSafe) + +set (CMAKE_CXX_STANDARD 11) + +# The location of autogenerated interfaces +set(CMAKE_CURRENT_AUTOGENERATED_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Interfaces) + +file(GLOB LIBTHREADSAFE_SRC + ${CMAKE_CURRENT_SOURCE_DIR}/Stub/*.cpp +) +file(GLOB LIBTHREADSAFE_HDR + ${CMAKE_CURRENT_SOURCE_DIR}/Stub/*.hpp +) +set(LIBTHREADSAFE_SRC ${LIBTHREADSAFE_SRC} ${LIBTHREADSAFE_SRC} + ${CMAKE_CURRENT_AUTOGENERATED_DIR}/libthreadsafe_interfaceexception.cpp + ${CMAKE_CURRENT_AUTOGENERATED_DIR}/libthreadsafe_interfacewrapper.cpp +) + +add_library(libthreadsafe SHARED ${LIBTHREADSAFE_SRC}) +# Do not prefix the binary's name with "lib" on Unix systems: +set_target_properties(libthreadsafe PROPERTIES PREFIX "" IMPORT_PREFIX "" ) +# The following two properties are crucial to reduce the number of undesirably exported symbols +set_target_properties(libthreadsafe PROPERTIES CXX_VISIBILITY_PRESET hidden) +set_target_properties(libthreadsafe PROPERTIES VISIBILITY_INLINES_HIDDEN ON) +# This makes sure symbols are exported +target_compile_options(libthreadsafe PRIVATE "-D__LIBTHREADSAFE_EXPORTS") +target_include_directories(libthreadsafe PRIVATE ${CMAKE_CURRENT_AUTOGENERATED_DIR}) +target_include_directories(libthreadsafe PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Stub) diff --git a/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Interfaces/libthreadsafe_abi.hpp b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Interfaces/libthreadsafe_abi.hpp new file mode 100644 index 00000000..28c57473 --- /dev/null +++ b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Interfaces/libthreadsafe_abi.hpp @@ -0,0 +1,205 @@ +/*++ + +Copyright (C) 2025 Thread-safe library developers + +All rights reserved. + +This file has been generated by the Automatic Component Toolkit (ACT) version 1.8.1-develop. + +Abstract: This is an autogenerated C++-Header file in order to allow an easy + use of Thread-safe library + +Interface version: 1.0.0 + +*/ + +#ifndef __LIBTHREADSAFE_HEADER_CPP +#define __LIBTHREADSAFE_HEADER_CPP + +#ifdef __LIBTHREADSAFE_EXPORTS +#ifdef _WIN32 +#define LIBTHREADSAFE_DECLSPEC __declspec (dllexport) +#else // _WIN32 +#define LIBTHREADSAFE_DECLSPEC __attribute__((visibility("default"))) +#endif // _WIN32 +#else // __LIBTHREADSAFE_EXPORTS +#define LIBTHREADSAFE_DECLSPEC +#endif // __LIBTHREADSAFE_EXPORTS + +#include "libthreadsafe_types.hpp" + + +#ifdef __cplusplus +extern "C" { +#endif + +/************************************************************************************************************************* + Class definition for Base +**************************************************************************************************************************/ + +/** +* Get Class Type Id +* +* @param[in] pBase - Base instance. +* @param[out] pClassTypeId - Class type as a 64 bits integer +* @return error code or 0 (success) +*/ +LIBTHREADSAFE_DECLSPEC LibThreadSafeResult libthreadsafe_base_classtypeid(LibThreadSafe_Base pBase, LibThreadSafe_uint64 * pClassTypeId); + +/** +* If thread safety for class in library is enabled it should lock object for calling thread +* +* @param[in] pBase - Base instance. +* @return error code or 0 (success) +*/ +LIBTHREADSAFE_DECLSPEC LibThreadSafeResult libthreadsafe_base__lockinstance(LibThreadSafe_Base pBase); + +/** +* If thread safety for class in library is enabled it should unlock object for other threads +* +* @param[in] pBase - Base instance. +* @return error code or 0 (success) +*/ +LIBTHREADSAFE_DECLSPEC LibThreadSafeResult libthreadsafe_base__unlockinstance(LibThreadSafe_Base pBase); + +/************************************************************************************************************************* + Class definition for StringReturner +**************************************************************************************************************************/ + +/** +* Returns a string +* +* @param[in] pStringReturner - StringReturner instance. +* @param[in] nValueBufferSize - size of the buffer (including trailing 0) +* @param[out] pValueNeededChars - will be filled with the count of the written bytes, or needed buffer size. +* @param[out] pValueBuffer - buffer of , may be NULL +* @return error code or 0 (success) +*/ +LIBTHREADSAFE_DECLSPEC LibThreadSafeResult libthreadsafe_stringreturner_getstring(LibThreadSafe_StringReturner pStringReturner, const LibThreadSafe_uint32 nValueBufferSize, LibThreadSafe_uint32* pValueNeededChars, char * pValueBuffer); + +/** +* Function that may crash when called from different threads at the same time +* +* @param[in] pStringReturner - StringReturner instance. +* @return error code or 0 (success) +*/ +LIBTHREADSAFE_DECLSPEC LibThreadSafeResult libthreadsafe_stringreturner_threadsafetycheck(LibThreadSafe_StringReturner pStringReturner); + +/************************************************************************************************************************* + Class definition for SoftStringReturner +**************************************************************************************************************************/ + +/** +* Returns a string +* +* @param[in] pSoftStringReturner - SoftStringReturner instance. +* @param[in] nValueBufferSize - size of the buffer (including trailing 0) +* @param[out] pValueNeededChars - will be filled with the count of the written bytes, or needed buffer size. +* @param[out] pValueBuffer - buffer of , may be NULL +* @return error code or 0 (success) +*/ +LIBTHREADSAFE_DECLSPEC LibThreadSafeResult libthreadsafe_softstringreturner_getstring(LibThreadSafe_SoftStringReturner pSoftStringReturner, const LibThreadSafe_uint32 nValueBufferSize, LibThreadSafe_uint32* pValueNeededChars, char * pValueBuffer); + +/** +* Function that may crash when called from different threads at the same time +* +* @param[in] pSoftStringReturner - SoftStringReturner instance. +* @return error code or 0 (success) +*/ +LIBTHREADSAFE_DECLSPEC LibThreadSafeResult libthreadsafe_softstringreturner_threadsafetycheck(LibThreadSafe_SoftStringReturner pSoftStringReturner); + +/************************************************************************************************************************* + Class definition for StrictStringReturner +**************************************************************************************************************************/ + +/** +* Returns a string +* +* @param[in] pStrictStringReturner - StrictStringReturner instance. +* @param[in] nValueBufferSize - size of the buffer (including trailing 0) +* @param[out] pValueNeededChars - will be filled with the count of the written bytes, or needed buffer size. +* @param[out] pValueBuffer - buffer of , may be NULL +* @return error code or 0 (success) +*/ +LIBTHREADSAFE_DECLSPEC LibThreadSafeResult libthreadsafe_strictstringreturner_getstring(LibThreadSafe_StrictStringReturner pStrictStringReturner, const LibThreadSafe_uint32 nValueBufferSize, LibThreadSafe_uint32* pValueNeededChars, char * pValueBuffer); + +/** +* Function that shouldn't crash when called from different threads at the same time +* +* @param[in] pStrictStringReturner - StrictStringReturner instance. +* @return error code or 0 (success) +*/ +LIBTHREADSAFE_DECLSPEC LibThreadSafeResult libthreadsafe_strictstringreturner_threadsafetycheck(LibThreadSafe_StrictStringReturner pStrictStringReturner); + +/************************************************************************************************************************* + Global functions +**************************************************************************************************************************/ + +/** +* retrieves the binary version of this library. +* +* @param[out] pMajor - returns the major version of this library +* @param[out] pMinor - returns the minor version of this library +* @param[out] pMicro - returns the micro version of this library +* @return error code or 0 (success) +*/ +LIBTHREADSAFE_DECLSPEC LibThreadSafeResult libthreadsafe_getversion(LibThreadSafe_uint32 * pMajor, LibThreadSafe_uint32 * pMinor, LibThreadSafe_uint32 * pMicro); + +/** +* Returns the last error recorded on this object +* +* @param[in] pInstance - Instance Handle +* @param[in] nErrorMessageBufferSize - size of the buffer (including trailing 0) +* @param[out] pErrorMessageNeededChars - will be filled with the count of the written bytes, or needed buffer size. +* @param[out] pErrorMessageBuffer - buffer of Message of the last error, may be NULL +* @param[out] pHasError - Is there a last error to query +* @return error code or 0 (success) +*/ +LIBTHREADSAFE_DECLSPEC LibThreadSafeResult libthreadsafe_getlasterror(LibThreadSafe_Base pInstance, const LibThreadSafe_uint32 nErrorMessageBufferSize, LibThreadSafe_uint32* pErrorMessageNeededChars, char * pErrorMessageBuffer, bool * pHasError); + +/** +* Acquire shared ownership of an Instance +* +* @param[in] pInstance - Instance Handle +* @return error code or 0 (success) +*/ +LIBTHREADSAFE_DECLSPEC LibThreadSafeResult libthreadsafe_acquireinstance(LibThreadSafe_Base pInstance); + +/** +* Releases shared ownership of an Instance +* +* @param[in] pInstance - Instance Handle +* @return error code or 0 (success) +*/ +LIBTHREADSAFE_DECLSPEC LibThreadSafeResult libthreadsafe_releaseinstance(LibThreadSafe_Base pInstance); + +/** +* Creates a new StringReturner instance +* +* @param[out] pInstance - New StringReturner instance +* @return error code or 0 (success) +*/ +LIBTHREADSAFE_DECLSPEC LibThreadSafeResult libthreadsafe_createstringreturner(LibThreadSafe_StringReturner * pInstance); + +/** +* Creates a new SoftStringReturner instance +* +* @param[out] pInstance - New SoftStringReturner instance +* @return error code or 0 (success) +*/ +LIBTHREADSAFE_DECLSPEC LibThreadSafeResult libthreadsafe_createsoftstringreturner(LibThreadSafe_SoftStringReturner * pInstance); + +/** +* Creates a new StrictStringReturner instance +* +* @param[out] pInstance - New StrictStringReturner instance +* @return error code or 0 (success) +*/ +LIBTHREADSAFE_DECLSPEC LibThreadSafeResult libthreadsafe_createstrictstringreturner(LibThreadSafe_StrictStringReturner * pInstance); + +#ifdef __cplusplus +} +#endif + +#endif // __LIBTHREADSAFE_HEADER_CPP + diff --git a/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Interfaces/libthreadsafe_interfaceexception.cpp b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Interfaces/libthreadsafe_interfaceexception.cpp new file mode 100644 index 00000000..2bc5aa60 --- /dev/null +++ b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Interfaces/libthreadsafe_interfaceexception.cpp @@ -0,0 +1,45 @@ +/*++ + +Copyright (C) 2025 Thread-safe library developers + +All rights reserved. + +This file has been generated by the Automatic Component Toolkit (ACT) version 1.8.1-develop. + +Abstract: This is an autogenerated C++ Implementation file with the basic internal + exception type in order to allow an easy use of Thread-safe library + +Interface version: 1.0.0 + +*/ + + +#include + +#include "libthreadsafe_interfaceexception.hpp" + +/************************************************************************************************************************* + Class ELibThreadSafeInterfaceException +**************************************************************************************************************************/ +ELibThreadSafeInterfaceException::ELibThreadSafeInterfaceException(LibThreadSafeResult errorCode) + : m_errorMessage(LIBTHREADSAFE_GETERRORSTRING (errorCode)) +{ + m_errorCode = errorCode; +} + +ELibThreadSafeInterfaceException::ELibThreadSafeInterfaceException(LibThreadSafeResult errorCode, std::string errorMessage) + : m_errorMessage(errorMessage + " (" + std::to_string (errorCode) + ")") +{ + m_errorCode = errorCode; +} + +LibThreadSafeResult ELibThreadSafeInterfaceException::getErrorCode () +{ + return m_errorCode; +} + +const char * ELibThreadSafeInterfaceException::what () const noexcept +{ + return m_errorMessage.c_str(); +} + diff --git a/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Interfaces/libthreadsafe_interfaceexception.hpp b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Interfaces/libthreadsafe_interfaceexception.hpp new file mode 100644 index 00000000..1c9ac9bf --- /dev/null +++ b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Interfaces/libthreadsafe_interfaceexception.hpp @@ -0,0 +1,60 @@ +/*++ + +Copyright (C) 2025 Thread-safe library developers + +All rights reserved. + +This file has been generated by the Automatic Component Toolkit (ACT) version 1.8.1-develop. + +Abstract: This is an autogenerated C++ Header file with the basic internal + exception type in order to allow an easy use of Thread-safe library + +Interface version: 1.0.0 + +*/ + +#ifndef __LIBTHREADSAFE_INTERFACEEXCEPTION_HEADER +#define __LIBTHREADSAFE_INTERFACEEXCEPTION_HEADER + +#include +#include +#include "libthreadsafe_types.hpp" + +/************************************************************************************************************************* + Class ELibThreadSafeInterfaceException +**************************************************************************************************************************/ + + +class ELibThreadSafeInterfaceException : public std::exception { +protected: + /** + * Error code for the Exception. + */ + LibThreadSafeResult m_errorCode; + /** + * Error message for the Exception. + */ + std::string m_errorMessage; + +public: + /** + * Exception Constructor. + */ + ELibThreadSafeInterfaceException(LibThreadSafeResult errorCode); + + /** + * Custom Exception Constructor. + */ + ELibThreadSafeInterfaceException(LibThreadSafeResult errorCode, std::string errorMessage); + + /** + * Returns error code + */ + LibThreadSafeResult getErrorCode(); + /** + * Returns error message + */ + const char* what() const noexcept override; +}; + +#endif // __LIBTHREADSAFE_INTERFACEEXCEPTION_HEADER diff --git a/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Interfaces/libthreadsafe_interfaces.hpp b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Interfaces/libthreadsafe_interfaces.hpp new file mode 100644 index 00000000..4f6ff875 --- /dev/null +++ b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Interfaces/libthreadsafe_interfaces.hpp @@ -0,0 +1,406 @@ +/*++ + +Copyright (C) 2025 Thread-safe library developers + +All rights reserved. + +This file has been generated by the Automatic Component Toolkit (ACT) version 1.8.1-develop. + +Abstract: This is an autogenerated C++ header file in order to allow easy +development of Thread-safe library. The implementer of Thread-safe library needs to +derive concrete classes from the abstract classes in this header. + +Interface version: 1.0.0 + +*/ + + +#ifndef __LIBTHREADSAFE_CPPINTERFACES +#define __LIBTHREADSAFE_CPPINTERFACES + +#include +#include +#include + +#include "libthreadsafe_types.hpp" + + + +namespace LibThreadSafe { +namespace Impl { + +/** + Forward declarations of class interfaces +*/ +class IBase; +class IStringReturner; +class ISoftStringReturner; +class IStrictStringReturner; + + + +/************************************************************************************************************************* + Parameter Cache definitions +**************************************************************************************************************************/ + +class ParameterCache { + public: + virtual ~ParameterCache() {} +}; + +template class ParameterCache_1 : public ParameterCache { + private: + T1 m_param1; + public: + ParameterCache_1 (const T1 & param1) + : m_param1 (param1) + { + } + + void retrieveData (T1 & param1) + { + param1 = m_param1; + } +}; + +template class ParameterCache_2 : public ParameterCache { + private: + T1 m_param1; + T2 m_param2; + public: + ParameterCache_2 (const T1 & param1, const T2 & param2) + : m_param1 (param1), m_param2 (param2) + { + } + + void retrieveData (T1 & param1, T2 & param2) + { + param1 = m_param1; + param2 = m_param2; + } +}; + +template class ParameterCache_3 : public ParameterCache { + private: + T1 m_param1; + T2 m_param2; + T3 m_param3; + public: + ParameterCache_3 (const T1 & param1, const T2 & param2, const T3 & param3) + : m_param1 (param1), m_param2 (param2), m_param3 (param3) + { + } + + void retrieveData (T1 & param1, T2 & param2, T3 & param3) + { + param1 = m_param1; + param2 = m_param2; + param3 = m_param3; + } +}; + + +/************************************************************************************************************************* + Class interface for Base +**************************************************************************************************************************/ + +class IBase { +protected: + std::unique_ptr m_ParameterCache; +public: + /** + * IBase::~IBase - virtual destructor of IBase + */ + virtual ~IBase() {}; + + /** + * IBase::ReleaseBaseClassInterface - Releases ownership of a base class interface. Deletes the reference, if necessary. + * @param[in] pIBase - The base class instance to release + */ + static void ReleaseBaseClassInterface(IBase* pIBase) + { + if (pIBase) { + pIBase->DecRefCount(); + } + }; + + /** + * IBase::AcquireBaseClassInterface - Acquires shared ownership of a base class interface. + * @param[in] pIBase - The base class instance to acquire + */ + static void AcquireBaseClassInterface(IBase* pIBase) + { + if (pIBase) { + pIBase->IncRefCount(); + } + }; + + + /** + * IBase::GetLastErrorMessage - Returns the last error registered of this class instance + * @param[out] sErrorMessage - Message of the last error registered + * @return Has an error been registered already + */ + virtual bool GetLastErrorMessage(std::string & sErrorMessage) = 0; + + /** + * IBase::ClearErrorMessages - Clears all registered messages of this class instance + */ + virtual void ClearErrorMessages() = 0; + + /** + * IBase::RegisterErrorMessage - Registers an error message with this class instance + * @param[in] sErrorMessage - Error message to register + */ + virtual void RegisterErrorMessage(const std::string & sErrorMessage) = 0; + + /** + * IBase::IncRefCount - Increases the reference count of a class instance + */ + virtual void IncRefCount() = 0; + + /** + * IBase::DecRefCount - Decreases the reference count of a class instance and free releases it, if the last reference has been removed + * @return Has the object been released + */ + virtual bool DecRefCount() = 0; + + /** + * IBase::_setCache - set parameter cache of object + */ + void _setCache(ParameterCache * pCache) + { + m_ParameterCache.reset(pCache); + } + + /** + * IBase::_getCache - returns parameter cache of object + */ + ParameterCache* _getCache() + { + return m_ParameterCache.get(); + } + + /** + * IBase::_lockInstance - If thread safety for class in library is enabled it should lock object for calling thread + */ + virtual void _lockInstance() {} + + /** + * IBase::_unlockInstance - If thread safety for class in library is enabled it should unlock object for other threads + */ + virtual void _unlockInstance() {} + + /** + * IBase::ClassTypeId - Get Class Type Id + * @return Class type as a 64 bits integer + */ + virtual LibThreadSafe_uint64 ClassTypeId() = 0; +}; + + +/** + Definition of a shared pointer class for IBase +*/ +template +class IBaseSharedPtr : public std::shared_ptr +{ +public: + explicit IBaseSharedPtr(T* t = nullptr) + : std::shared_ptr(t, IBase::ReleaseBaseClassInterface) + { + t->IncRefCount(); + } + + // Reset function, as it also needs to properly set the deleter. + void reset(T* t = nullptr) + { + std::shared_ptr::reset(t, IBase::ReleaseBaseClassInterface); + } + + // Get-function that increases the Base class's reference count + T* getCoOwningPtr() + { + T* t = this->get(); + t->IncRefCount(); + return t; + } +}; + + +/** + Definition of a class with mutex for IBase +*/ +class IBaseWithMutex : public virtual IBase +{ +private: + std::mutex m_mutex; +public: + + /** + * IBaseWithMutex::_lockInstance - If thread safety for class in library is enabled it should lock object for calling thread + */ + virtual void _lockInstance() { m_mutex.lock(); } + + /** + * IBaseWithMutex::_unlockInstance - If thread safety for class in library is enabled it should unlock object for other threads + */ + virtual void _unlockInstance() { m_mutex.unlock();} +}; + + +typedef IBaseSharedPtr PIBase; + + +/************************************************************************************************************************* + Class interface for StringReturner +**************************************************************************************************************************/ + +class IStringReturner : public virtual IBase { +public: + /** + * IStringReturner::ClassTypeId - Get Class Type Id + * @return Class type as a 64 bits integer + */ + LibThreadSafe_uint64 ClassTypeId() override + { + return 0x1755067BCC5ED81UL; // First 64 bits of SHA1 of a string: "LibThreadSafe::StringReturner" + } + + /** + * IStringReturner::GetString - Returns a string + * @return + */ + virtual std::string GetString() = 0; + + /** + * IStringReturner::ThreadSafetyCheck - Function that may crash when called from different threads at the same time + */ + virtual void ThreadSafetyCheck() = 0; + +}; + +typedef IBaseSharedPtr PIStringReturner; + + +/************************************************************************************************************************* + Class interface for SoftStringReturner +**************************************************************************************************************************/ + +class ISoftStringReturner : public virtual IBaseWithMutex { +public: + /** + * ISoftStringReturner::ClassTypeId - Get Class Type Id + * @return Class type as a 64 bits integer + */ + LibThreadSafe_uint64 ClassTypeId() override + { + return 0x6C0744711291F198UL; // First 64 bits of SHA1 of a string: "LibThreadSafe::SoftStringReturner" + } + + /** + * ISoftStringReturner::GetString - Returns a string + * @return + */ + virtual std::string GetString() = 0; + + /** + * ISoftStringReturner::ThreadSafetyCheck - Function that may crash when called from different threads at the same time + */ + virtual void ThreadSafetyCheck() = 0; + +}; + +typedef IBaseSharedPtr PISoftStringReturner; + + +/************************************************************************************************************************* + Class interface for StrictStringReturner +**************************************************************************************************************************/ + +class IStrictStringReturner : public virtual IBaseWithMutex { +public: + /** + * IStrictStringReturner::ClassTypeId - Get Class Type Id + * @return Class type as a 64 bits integer + */ + LibThreadSafe_uint64 ClassTypeId() override + { + return 0xC8D8EB62D68DF429UL; // First 64 bits of SHA1 of a string: "LibThreadSafe::StrictStringReturner" + } + + /** + * IStrictStringReturner::GetString - Returns a string + * @return + */ + virtual std::string GetString() = 0; + + /** + * IStrictStringReturner::ThreadSafetyCheck - Function that shouldn't crash when called from different threads at the same time + */ + virtual void ThreadSafetyCheck() = 0; + +}; + +typedef IBaseSharedPtr PIStrictStringReturner; + + +/************************************************************************************************************************* + Global functions declarations +**************************************************************************************************************************/ +class CWrapper { +public: + /** + * Ilibthreadsafe::GetVersion - retrieves the binary version of this library. + * @param[out] nMajor - returns the major version of this library + * @param[out] nMinor - returns the minor version of this library + * @param[out] nMicro - returns the micro version of this library + */ + static void GetVersion(LibThreadSafe_uint32 & nMajor, LibThreadSafe_uint32 & nMinor, LibThreadSafe_uint32 & nMicro); + + /** + * Ilibthreadsafe::GetLastError - Returns the last error recorded on this object + * @param[in] pInstance - Instance Handle + * @param[out] sErrorMessage - Message of the last error + * @return Is there a last error to query + */ + static bool GetLastError(IBase* pInstance, std::string & sErrorMessage); + + /** + * Ilibthreadsafe::AcquireInstance - Acquire shared ownership of an Instance + * @param[in] pInstance - Instance Handle + */ + static void AcquireInstance(IBase* pInstance); + + /** + * Ilibthreadsafe::ReleaseInstance - Releases shared ownership of an Instance + * @param[in] pInstance - Instance Handle + */ + static void ReleaseInstance(IBase* pInstance); + + /** + * Ilibthreadsafe::CreateStringReturner - Creates a new StringReturner instance + * @return New StringReturner instance + */ + static IStringReturner * CreateStringReturner(); + + /** + * Ilibthreadsafe::CreateSoftStringReturner - Creates a new SoftStringReturner instance + * @return New SoftStringReturner instance + */ + static ISoftStringReturner * CreateSoftStringReturner(); + + /** + * Ilibthreadsafe::CreateStrictStringReturner - Creates a new StrictStringReturner instance + * @return New StrictStringReturner instance + */ + static IStrictStringReturner * CreateStrictStringReturner(); + +}; + +LibThreadSafeResult LibThreadSafe_GetProcAddress (const char * pProcName, void ** ppProcAddress); + +} // namespace Impl +} // namespace LibThreadSafe + +#endif // __LIBTHREADSAFE_CPPINTERFACES diff --git a/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Interfaces/libthreadsafe_interfacewrapper.cpp b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Interfaces/libthreadsafe_interfacewrapper.cpp new file mode 100644 index 00000000..57a8c8e1 --- /dev/null +++ b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Interfaces/libthreadsafe_interfacewrapper.cpp @@ -0,0 +1,604 @@ +/*++ + +Copyright (C) 2025 Thread-safe library developers + +All rights reserved. + +This file has been generated by the Automatic Component Toolkit (ACT) version 1.8.1-develop. + +Abstract: This is an autogenerated C++ implementation file in order to allow easy +development of Thread-safe library. The functions in this file need to be implemented. It needs to be generated only once. + +Interface version: 1.0.0 + +*/ + +#include "libthreadsafe_abi.hpp" +#include "libthreadsafe_interfaces.hpp" +#include "libthreadsafe_interfaceexception.hpp" + +#include + +using namespace LibThreadSafe::Impl; + +LibThreadSafeResult handleLibThreadSafeException(IBase * pIBaseClass, ELibThreadSafeInterfaceException & Exception) +{ + LibThreadSafeResult errorCode = Exception.getErrorCode(); + + if (pIBaseClass != nullptr) + pIBaseClass->RegisterErrorMessage(Exception.what()); + + return errorCode; +} + +LibThreadSafeResult handleStdException(IBase * pIBaseClass, std::exception & Exception) +{ + LibThreadSafeResult errorCode = LIBTHREADSAFE_ERROR_GENERICEXCEPTION; + + if (pIBaseClass != nullptr) + pIBaseClass->RegisterErrorMessage(Exception.what()); + + return errorCode; +} + +LibThreadSafeResult handleUnhandledException(IBase * pIBaseClass) +{ + LibThreadSafeResult errorCode = LIBTHREADSAFE_ERROR_GENERICEXCEPTION; + + if (pIBaseClass != nullptr) + pIBaseClass->RegisterErrorMessage("Unhandled Exception"); + + return errorCode; +} + + + +/************************************************************************************************************************* + Class implementation for Base +**************************************************************************************************************************/ +LibThreadSafeResult libthreadsafe_base_classtypeid(LibThreadSafe_Base pBase, LibThreadSafe_uint64 * pClassTypeId) +{ + IBase* pIBaseClass = (IBase *)pBase; + + try { + if (pClassTypeId == nullptr) + throw ELibThreadSafeInterfaceException (LIBTHREADSAFE_ERROR_INVALIDPARAM); + IBase* pIBase = dynamic_cast(pIBaseClass); + if (!pIBase) + throw ELibThreadSafeInterfaceException(LIBTHREADSAFE_ERROR_INVALIDCAST); + + *pClassTypeId = pIBase->ClassTypeId(); + + return LIBTHREADSAFE_SUCCESS; + } + catch (ELibThreadSafeInterfaceException & Exception) { + return handleLibThreadSafeException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + +LibThreadSafeResult libthreadsafe_base__lockinstance(LibThreadSafe_Base pBase) +{ + IBase* pIBaseClass = (IBase *)pBase; + + try { + IBase* pIBase = dynamic_cast(pIBaseClass); + if (!pIBase) + throw ELibThreadSafeInterfaceException(LIBTHREADSAFE_ERROR_INVALIDCAST); + + pIBase->_lockInstance(); + + return LIBTHREADSAFE_SUCCESS; + } + catch (ELibThreadSafeInterfaceException & Exception) { + return handleLibThreadSafeException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + +LibThreadSafeResult libthreadsafe_base__unlockinstance(LibThreadSafe_Base pBase) +{ + IBase* pIBaseClass = (IBase *)pBase; + + try { + IBase* pIBase = dynamic_cast(pIBaseClass); + if (!pIBase) + throw ELibThreadSafeInterfaceException(LIBTHREADSAFE_ERROR_INVALIDCAST); + + pIBase->_unlockInstance(); + + return LIBTHREADSAFE_SUCCESS; + } + catch (ELibThreadSafeInterfaceException & Exception) { + return handleLibThreadSafeException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + + +/************************************************************************************************************************* + Class implementation for StringReturner +**************************************************************************************************************************/ +LibThreadSafeResult libthreadsafe_stringreturner_getstring(LibThreadSafe_StringReturner pStringReturner, const LibThreadSafe_uint32 nValueBufferSize, LibThreadSafe_uint32* pValueNeededChars, char * pValueBuffer) +{ + IBase* pIBaseClass = (IBase *)pStringReturner; + + try { + if ( (!pValueBuffer) && !(pValueNeededChars) ) + throw ELibThreadSafeInterfaceException (LIBTHREADSAFE_ERROR_INVALIDPARAM); + std::string sValue(""); + IStringReturner* pIStringReturner = dynamic_cast(pIBaseClass); + if (!pIStringReturner) + throw ELibThreadSafeInterfaceException(LIBTHREADSAFE_ERROR_INVALIDCAST); + + bool isCacheCall = (pValueBuffer == nullptr); + if (isCacheCall) { + sValue = pIStringReturner->GetString(); + + pIStringReturner->_setCache (new ParameterCache_1 (sValue)); + } + else { + auto cache = dynamic_cast*> (pIStringReturner->_getCache ()); + if (cache == nullptr) + throw ELibThreadSafeInterfaceException(LIBTHREADSAFE_ERROR_INVALIDCAST); + cache->retrieveData (sValue); + pIStringReturner->_setCache (nullptr); + } + + if (pValueNeededChars) + *pValueNeededChars = (LibThreadSafe_uint32) (sValue.size()+1); + if (pValueBuffer) { + if (sValue.size() >= nValueBufferSize) + throw ELibThreadSafeInterfaceException (LIBTHREADSAFE_ERROR_BUFFERTOOSMALL); + for (size_t iValue = 0; iValue < sValue.size(); iValue++) + pValueBuffer[iValue] = sValue[iValue]; + pValueBuffer[sValue.size()] = 0; + } + return LIBTHREADSAFE_SUCCESS; + } + catch (ELibThreadSafeInterfaceException & Exception) { + return handleLibThreadSafeException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + +LibThreadSafeResult libthreadsafe_stringreturner_threadsafetycheck(LibThreadSafe_StringReturner pStringReturner) +{ + IBase* pIBaseClass = (IBase *)pStringReturner; + + try { + IStringReturner* pIStringReturner = dynamic_cast(pIBaseClass); + if (!pIStringReturner) + throw ELibThreadSafeInterfaceException(LIBTHREADSAFE_ERROR_INVALIDCAST); + + pIStringReturner->ThreadSafetyCheck(); + + return LIBTHREADSAFE_SUCCESS; + } + catch (ELibThreadSafeInterfaceException & Exception) { + return handleLibThreadSafeException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + + +/************************************************************************************************************************* + Class implementation for SoftStringReturner +**************************************************************************************************************************/ +LibThreadSafeResult libthreadsafe_softstringreturner_getstring(LibThreadSafe_SoftStringReturner pSoftStringReturner, const LibThreadSafe_uint32 nValueBufferSize, LibThreadSafe_uint32* pValueNeededChars, char * pValueBuffer) +{ + IBase* pIBaseClass = (IBase *)pSoftStringReturner; + + try { + if ( (!pValueBuffer) && !(pValueNeededChars) ) + throw ELibThreadSafeInterfaceException (LIBTHREADSAFE_ERROR_INVALIDPARAM); + std::string sValue(""); + ISoftStringReturner* pISoftStringReturner = dynamic_cast(pIBaseClass); + if (!pISoftStringReturner) + throw ELibThreadSafeInterfaceException(LIBTHREADSAFE_ERROR_INVALIDCAST); + + bool isCacheCall = (pValueBuffer == nullptr); + if (isCacheCall) { + sValue = pISoftStringReturner->GetString(); + + pISoftStringReturner->_setCache (new ParameterCache_1 (sValue)); + } + else { + auto cache = dynamic_cast*> (pISoftStringReturner->_getCache ()); + if (cache == nullptr) + throw ELibThreadSafeInterfaceException(LIBTHREADSAFE_ERROR_INVALIDCAST); + cache->retrieveData (sValue); + pISoftStringReturner->_setCache (nullptr); + } + + if (pValueNeededChars) + *pValueNeededChars = (LibThreadSafe_uint32) (sValue.size()+1); + if (pValueBuffer) { + if (sValue.size() >= nValueBufferSize) + throw ELibThreadSafeInterfaceException (LIBTHREADSAFE_ERROR_BUFFERTOOSMALL); + for (size_t iValue = 0; iValue < sValue.size(); iValue++) + pValueBuffer[iValue] = sValue[iValue]; + pValueBuffer[sValue.size()] = 0; + } + return LIBTHREADSAFE_SUCCESS; + } + catch (ELibThreadSafeInterfaceException & Exception) { + return handleLibThreadSafeException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + +LibThreadSafeResult libthreadsafe_softstringreturner_threadsafetycheck(LibThreadSafe_SoftStringReturner pSoftStringReturner) +{ + IBase* pIBaseClass = (IBase *)pSoftStringReturner; + + try { + ISoftStringReturner* pISoftStringReturner = dynamic_cast(pIBaseClass); + if (!pISoftStringReturner) + throw ELibThreadSafeInterfaceException(LIBTHREADSAFE_ERROR_INVALIDCAST); + + pISoftStringReturner->ThreadSafetyCheck(); + + return LIBTHREADSAFE_SUCCESS; + } + catch (ELibThreadSafeInterfaceException & Exception) { + return handleLibThreadSafeException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + + +/************************************************************************************************************************* + Class implementation for StrictStringReturner +**************************************************************************************************************************/ +LibThreadSafeResult libthreadsafe_strictstringreturner_getstring(LibThreadSafe_StrictStringReturner pStrictStringReturner, const LibThreadSafe_uint32 nValueBufferSize, LibThreadSafe_uint32* pValueNeededChars, char * pValueBuffer) +{ + IBase* pIBaseClass = (IBase *)pStrictStringReturner; + + try { + if ( (!pValueBuffer) && !(pValueNeededChars) ) + throw ELibThreadSafeInterfaceException (LIBTHREADSAFE_ERROR_INVALIDPARAM); + std::string sValue(""); + IStrictStringReturner* pIStrictStringReturner = dynamic_cast(pIBaseClass); + if (!pIStrictStringReturner) + throw ELibThreadSafeInterfaceException(LIBTHREADSAFE_ERROR_INVALIDCAST); + + bool isCacheCall = (pValueBuffer == nullptr); + if (isCacheCall) { + sValue = pIStrictStringReturner->GetString(); + + pIStrictStringReturner->_setCache (new ParameterCache_1 (sValue)); + } + else { + auto cache = dynamic_cast*> (pIStrictStringReturner->_getCache ()); + if (cache == nullptr) + throw ELibThreadSafeInterfaceException(LIBTHREADSAFE_ERROR_INVALIDCAST); + cache->retrieveData (sValue); + pIStrictStringReturner->_setCache (nullptr); + } + + if (pValueNeededChars) + *pValueNeededChars = (LibThreadSafe_uint32) (sValue.size()+1); + if (pValueBuffer) { + if (sValue.size() >= nValueBufferSize) + throw ELibThreadSafeInterfaceException (LIBTHREADSAFE_ERROR_BUFFERTOOSMALL); + for (size_t iValue = 0; iValue < sValue.size(); iValue++) + pValueBuffer[iValue] = sValue[iValue]; + pValueBuffer[sValue.size()] = 0; + } + return LIBTHREADSAFE_SUCCESS; + } + catch (ELibThreadSafeInterfaceException & Exception) { + return handleLibThreadSafeException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + +LibThreadSafeResult libthreadsafe_strictstringreturner_threadsafetycheck(LibThreadSafe_StrictStringReturner pStrictStringReturner) +{ + IBase* pIBaseClass = (IBase *)pStrictStringReturner; + + try { + IStrictStringReturner* pIStrictStringReturner = dynamic_cast(pIBaseClass); + if (!pIStrictStringReturner) + throw ELibThreadSafeInterfaceException(LIBTHREADSAFE_ERROR_INVALIDCAST); + + pIStrictStringReturner->ThreadSafetyCheck(); + + return LIBTHREADSAFE_SUCCESS; + } + catch (ELibThreadSafeInterfaceException & Exception) { + return handleLibThreadSafeException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + + + +/************************************************************************************************************************* + Function table lookup implementation +**************************************************************************************************************************/ + +LibThreadSafeResult LibThreadSafe::Impl::LibThreadSafe_GetProcAddress (const char * pProcName, void ** ppProcAddress) +{ + if (pProcName == nullptr) + return LIBTHREADSAFE_ERROR_INVALIDPARAM; + if (ppProcAddress == nullptr) + return LIBTHREADSAFE_ERROR_INVALIDPARAM; + *ppProcAddress = nullptr; + std::string sProcName (pProcName); + + if (sProcName == "libthreadsafe_base_classtypeid") + *ppProcAddress = (void*) &libthreadsafe_base_classtypeid; + if (sProcName == "libthreadsafe_base__lockinstance") + *ppProcAddress = (void*) &libthreadsafe_base__lockinstance; + if (sProcName == "libthreadsafe_base__unlockinstance") + *ppProcAddress = (void*) &libthreadsafe_base__unlockinstance; + if (sProcName == "libthreadsafe_stringreturner_getstring") + *ppProcAddress = (void*) &libthreadsafe_stringreturner_getstring; + if (sProcName == "libthreadsafe_stringreturner_threadsafetycheck") + *ppProcAddress = (void*) &libthreadsafe_stringreturner_threadsafetycheck; + if (sProcName == "libthreadsafe_softstringreturner_getstring") + *ppProcAddress = (void*) &libthreadsafe_softstringreturner_getstring; + if (sProcName == "libthreadsafe_softstringreturner_threadsafetycheck") + *ppProcAddress = (void*) &libthreadsafe_softstringreturner_threadsafetycheck; + if (sProcName == "libthreadsafe_strictstringreturner_getstring") + *ppProcAddress = (void*) &libthreadsafe_strictstringreturner_getstring; + if (sProcName == "libthreadsafe_strictstringreturner_threadsafetycheck") + *ppProcAddress = (void*) &libthreadsafe_strictstringreturner_threadsafetycheck; + if (sProcName == "libthreadsafe_getversion") + *ppProcAddress = (void*) &libthreadsafe_getversion; + if (sProcName == "libthreadsafe_getlasterror") + *ppProcAddress = (void*) &libthreadsafe_getlasterror; + if (sProcName == "libthreadsafe_acquireinstance") + *ppProcAddress = (void*) &libthreadsafe_acquireinstance; + if (sProcName == "libthreadsafe_releaseinstance") + *ppProcAddress = (void*) &libthreadsafe_releaseinstance; + if (sProcName == "libthreadsafe_createstringreturner") + *ppProcAddress = (void*) &libthreadsafe_createstringreturner; + if (sProcName == "libthreadsafe_createsoftstringreturner") + *ppProcAddress = (void*) &libthreadsafe_createsoftstringreturner; + if (sProcName == "libthreadsafe_createstrictstringreturner") + *ppProcAddress = (void*) &libthreadsafe_createstrictstringreturner; + + if (*ppProcAddress == nullptr) + return LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT; + return LIBTHREADSAFE_SUCCESS; +} + +/************************************************************************************************************************* + Global functions implementation +**************************************************************************************************************************/ +LibThreadSafeResult libthreadsafe_getversion(LibThreadSafe_uint32 * pMajor, LibThreadSafe_uint32 * pMinor, LibThreadSafe_uint32 * pMicro) +{ + IBase* pIBaseClass = nullptr; + + try { + if (!pMajor) + throw ELibThreadSafeInterfaceException (LIBTHREADSAFE_ERROR_INVALIDPARAM); + if (!pMinor) + throw ELibThreadSafeInterfaceException (LIBTHREADSAFE_ERROR_INVALIDPARAM); + if (!pMicro) + throw ELibThreadSafeInterfaceException (LIBTHREADSAFE_ERROR_INVALIDPARAM); + CWrapper::GetVersion(*pMajor, *pMinor, *pMicro); + + return LIBTHREADSAFE_SUCCESS; + } + catch (ELibThreadSafeInterfaceException & Exception) { + return handleLibThreadSafeException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + +LibThreadSafeResult libthreadsafe_getlasterror(LibThreadSafe_Base pInstance, const LibThreadSafe_uint32 nErrorMessageBufferSize, LibThreadSafe_uint32* pErrorMessageNeededChars, char * pErrorMessageBuffer, bool * pHasError) +{ + IBase* pIBaseClass = nullptr; + + try { + if ( (!pErrorMessageBuffer) && !(pErrorMessageNeededChars) ) + throw ELibThreadSafeInterfaceException (LIBTHREADSAFE_ERROR_INVALIDPARAM); + if (pHasError == nullptr) + throw ELibThreadSafeInterfaceException (LIBTHREADSAFE_ERROR_INVALIDPARAM); + IBase* pIBaseClassInstance = (IBase *)pInstance; + IBase* pIInstance = dynamic_cast(pIBaseClassInstance); + if (!pIInstance) + throw ELibThreadSafeInterfaceException (LIBTHREADSAFE_ERROR_INVALIDCAST); + + std::string sErrorMessage(""); + *pHasError = CWrapper::GetLastError(pIInstance, sErrorMessage); + + if (pErrorMessageNeededChars) + *pErrorMessageNeededChars = (LibThreadSafe_uint32) (sErrorMessage.size()+1); + if (pErrorMessageBuffer) { + if (sErrorMessage.size() >= nErrorMessageBufferSize) + throw ELibThreadSafeInterfaceException (LIBTHREADSAFE_ERROR_BUFFERTOOSMALL); + for (size_t iErrorMessage = 0; iErrorMessage < sErrorMessage.size(); iErrorMessage++) + pErrorMessageBuffer[iErrorMessage] = sErrorMessage[iErrorMessage]; + pErrorMessageBuffer[sErrorMessage.size()] = 0; + } + return LIBTHREADSAFE_SUCCESS; + } + catch (ELibThreadSafeInterfaceException & Exception) { + return handleLibThreadSafeException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + +LibThreadSafeResult libthreadsafe_acquireinstance(LibThreadSafe_Base pInstance) +{ + IBase* pIBaseClass = nullptr; + + try { + IBase* pIBaseClassInstance = (IBase *)pInstance; + IBase* pIInstance = dynamic_cast(pIBaseClassInstance); + if (!pIInstance) + throw ELibThreadSafeInterfaceException (LIBTHREADSAFE_ERROR_INVALIDCAST); + + CWrapper::AcquireInstance(pIInstance); + + return LIBTHREADSAFE_SUCCESS; + } + catch (ELibThreadSafeInterfaceException & Exception) { + return handleLibThreadSafeException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + +LibThreadSafeResult libthreadsafe_releaseinstance(LibThreadSafe_Base pInstance) +{ + IBase* pIBaseClass = nullptr; + + try { + IBase* pIBaseClassInstance = (IBase *)pInstance; + IBase* pIInstance = dynamic_cast(pIBaseClassInstance); + if (!pIInstance) + throw ELibThreadSafeInterfaceException (LIBTHREADSAFE_ERROR_INVALIDCAST); + + CWrapper::ReleaseInstance(pIInstance); + + return LIBTHREADSAFE_SUCCESS; + } + catch (ELibThreadSafeInterfaceException & Exception) { + return handleLibThreadSafeException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + +LibThreadSafeResult libthreadsafe_createstringreturner(LibThreadSafe_StringReturner * pInstance) +{ + IBase* pIBaseClass = nullptr; + + try { + if (pInstance == nullptr) + throw ELibThreadSafeInterfaceException (LIBTHREADSAFE_ERROR_INVALIDPARAM); + IBase* pBaseInstance(nullptr); + pBaseInstance = CWrapper::CreateStringReturner(); + + *pInstance = (IBase*)(pBaseInstance); + return LIBTHREADSAFE_SUCCESS; + } + catch (ELibThreadSafeInterfaceException & Exception) { + return handleLibThreadSafeException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + +LibThreadSafeResult libthreadsafe_createsoftstringreturner(LibThreadSafe_SoftStringReturner * pInstance) +{ + IBase* pIBaseClass = nullptr; + + try { + if (pInstance == nullptr) + throw ELibThreadSafeInterfaceException (LIBTHREADSAFE_ERROR_INVALIDPARAM); + IBase* pBaseInstance(nullptr); + pBaseInstance = CWrapper::CreateSoftStringReturner(); + + *pInstance = (IBase*)(pBaseInstance); + return LIBTHREADSAFE_SUCCESS; + } + catch (ELibThreadSafeInterfaceException & Exception) { + return handleLibThreadSafeException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + +LibThreadSafeResult libthreadsafe_createstrictstringreturner(LibThreadSafe_StrictStringReturner * pInstance) +{ + IBase* pIBaseClass = nullptr; + + try { + if (pInstance == nullptr) + throw ELibThreadSafeInterfaceException (LIBTHREADSAFE_ERROR_INVALIDPARAM); + IBase* pBaseInstance(nullptr); + pBaseInstance = CWrapper::CreateStrictStringReturner(); + + *pInstance = (IBase*)(pBaseInstance); + return LIBTHREADSAFE_SUCCESS; + } + catch (ELibThreadSafeInterfaceException & Exception) { + return handleLibThreadSafeException(pIBaseClass, Exception); + } + catch (std::exception & StdException) { + return handleStdException(pIBaseClass, StdException); + } + catch (...) { + return handleUnhandledException(pIBaseClass); + } +} + + diff --git a/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Interfaces/libthreadsafe_types.hpp b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Interfaces/libthreadsafe_types.hpp new file mode 100644 index 00000000..cbc3acd4 --- /dev/null +++ b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Interfaces/libthreadsafe_types.hpp @@ -0,0 +1,123 @@ +/*++ + +Copyright (C) 2025 Thread-safe library developers + +All rights reserved. + +This file has been generated by the Automatic Component Toolkit (ACT) version 1.8.1-develop. + +Abstract: This is an autogenerated C++-Header file with basic types in +order to allow an easy use of Thread-safe library + +Interface version: 1.0.0 + +*/ + +#ifndef __LIBTHREADSAFE_TYPES_HEADER_CPP +#define __LIBTHREADSAFE_TYPES_HEADER_CPP + + +/************************************************************************************************************************* + Scalar types definition +**************************************************************************************************************************/ + +#ifdef LIBTHREADSAFE_USELEGACYINTEGERTYPES + +typedef unsigned char LibThreadSafe_uint8; +typedef unsigned short LibThreadSafe_uint16 ; +typedef unsigned int LibThreadSafe_uint32; +typedef unsigned long long LibThreadSafe_uint64; +typedef char LibThreadSafe_int8; +typedef short LibThreadSafe_int16; +typedef int LibThreadSafe_int32; +typedef long long LibThreadSafe_int64; + +#else // LIBTHREADSAFE_USELEGACYINTEGERTYPES + +#include + +typedef uint8_t LibThreadSafe_uint8; +typedef uint16_t LibThreadSafe_uint16; +typedef uint32_t LibThreadSafe_uint32; +typedef uint64_t LibThreadSafe_uint64; +typedef int8_t LibThreadSafe_int8; +typedef int16_t LibThreadSafe_int16; +typedef int32_t LibThreadSafe_int32; +typedef int64_t LibThreadSafe_int64 ; + +#endif // LIBTHREADSAFE_USELEGACYINTEGERTYPES + +typedef float LibThreadSafe_single; +typedef double LibThreadSafe_double; + +/************************************************************************************************************************* + General type definitions +**************************************************************************************************************************/ + +typedef LibThreadSafe_int32 LibThreadSafeResult; +typedef void * LibThreadSafeHandle; +typedef void * LibThreadSafe_pvoid; + +/************************************************************************************************************************* + Version for LibThreadSafe +**************************************************************************************************************************/ + +#define LIBTHREADSAFE_VERSION_MAJOR 1 +#define LIBTHREADSAFE_VERSION_MINOR 0 +#define LIBTHREADSAFE_VERSION_MICRO 0 +#define LIBTHREADSAFE_VERSION_PRERELEASEINFO "" +#define LIBTHREADSAFE_VERSION_BUILDINFO "" + +/************************************************************************************************************************* + Error constants for LibThreadSafe +**************************************************************************************************************************/ + +#define LIBTHREADSAFE_SUCCESS 0 +#define LIBTHREADSAFE_ERROR_NOTIMPLEMENTED 1 /** functionality not implemented */ +#define LIBTHREADSAFE_ERROR_INVALIDPARAM 2 /** an invalid parameter was passed */ +#define LIBTHREADSAFE_ERROR_INVALIDCAST 3 /** a type cast failed */ +#define LIBTHREADSAFE_ERROR_BUFFERTOOSMALL 4 /** a provided buffer is too small */ +#define LIBTHREADSAFE_ERROR_GENERICEXCEPTION 5 /** a generic exception occurred */ +#define LIBTHREADSAFE_ERROR_COULDNOTLOADLIBRARY 6 /** the library could not be loaded */ +#define LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT 7 /** a required exported symbol could not be found in the library */ +#define LIBTHREADSAFE_ERROR_INCOMPATIBLEBINARYVERSION 8 /** the version of the binary interface does not match the bindings interface */ +#define LIBTHREADSAFE_ERROR_NORESULTAVAILABLE 9 /** no result is available */ +#define LIBTHREADSAFE_ERROR_CALCULATIONABORTED 10 /** a calculation has been aborted */ + +/************************************************************************************************************************* + Error strings for LibThreadSafe +**************************************************************************************************************************/ + +inline const char * LIBTHREADSAFE_GETERRORSTRING (LibThreadSafeResult nErrorCode) { + switch (nErrorCode) { + case LIBTHREADSAFE_SUCCESS: return "no error"; + case LIBTHREADSAFE_ERROR_NOTIMPLEMENTED: return "functionality not implemented"; + case LIBTHREADSAFE_ERROR_INVALIDPARAM: return "an invalid parameter was passed"; + case LIBTHREADSAFE_ERROR_INVALIDCAST: return "a type cast failed"; + case LIBTHREADSAFE_ERROR_BUFFERTOOSMALL: return "a provided buffer is too small"; + case LIBTHREADSAFE_ERROR_GENERICEXCEPTION: return "a generic exception occurred"; + case LIBTHREADSAFE_ERROR_COULDNOTLOADLIBRARY: return "the library could not be loaded"; + case LIBTHREADSAFE_ERROR_COULDNOTFINDLIBRARYEXPORT: return "a required exported symbol could not be found in the library"; + case LIBTHREADSAFE_ERROR_INCOMPATIBLEBINARYVERSION: return "the version of the binary interface does not match the bindings interface"; + case LIBTHREADSAFE_ERROR_NORESULTAVAILABLE: return "no result is available"; + case LIBTHREADSAFE_ERROR_CALCULATIONABORTED: return "a calculation has been aborted"; + default: return "unknown error"; + } +} + +/************************************************************************************************************************* + Declaration of handle classes +**************************************************************************************************************************/ + +typedef LibThreadSafeHandle LibThreadSafe_Base; +typedef LibThreadSafeHandle LibThreadSafe_StringReturner; +typedef LibThreadSafeHandle LibThreadSafe_SoftStringReturner; +typedef LibThreadSafeHandle LibThreadSafe_StrictStringReturner; + +namespace LibThreadSafe { + +} // namespace LibThreadSafe; + +// define legacy C-names for enums, structs and function types + +#endif // __LIBTHREADSAFE_TYPES_HEADER_CPP diff --git a/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe.cpp b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe.cpp new file mode 100644 index 00000000..ebbaf60f --- /dev/null +++ b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe.cpp @@ -0,0 +1,68 @@ +/*++ + +Copyright (C) 2025 Thread-safe library developers + +All rights reserved. + +This file has been generated by the Automatic Component Toolkit (ACT) version 1.8.1-develop. + +Abstract: This is an autogenerated C++ implementation file in order to allow easy +development of Thread-safe library. It needs to be generated only once. + +Interface version: 1.0.0 + +*/ + +#include "libthreadsafe_abi.hpp" +#include "libthreadsafe_interfaces.hpp" +#include "libthreadsafe_interfaceexception.hpp" + +#include "libthreadsafe_stringreturner.hpp" +#include "libthreadsafe_softstringreturner.hpp" +#include "libthreadsafe_strictstringreturner.hpp" + +using namespace LibThreadSafe; +using namespace LibThreadSafe::Impl; + +void CWrapper::GetVersion(LibThreadSafe_uint32 & nMajor, LibThreadSafe_uint32 & nMinor, LibThreadSafe_uint32 & nMicro) +{ + nMajor = LIBTHREADSAFE_VERSION_MAJOR; + nMinor = LIBTHREADSAFE_VERSION_MINOR; + nMicro = LIBTHREADSAFE_VERSION_MICRO; +} + +bool CWrapper::GetLastError(IBase* pInstance, std::string & sErrorMessage) +{ + if (pInstance) { + return pInstance->GetLastErrorMessage (sErrorMessage); + } else { + return false; + } +} + +void CWrapper::AcquireInstance(IBase* pInstance) +{ + IBase::AcquireBaseClassInterface(pInstance); +} + +void CWrapper::ReleaseInstance(IBase* pInstance) +{ + IBase::ReleaseBaseClassInterface(pInstance); +} + +IStringReturner * CWrapper::CreateStringReturner() +{ + return new CStringReturner(); +} + +ISoftStringReturner * CWrapper::CreateSoftStringReturner() +{ + return new CSoftStringReturner(); +} + +IStrictStringReturner * CWrapper::CreateStrictStringReturner() +{ + return new CStrictStringReturner(); +} + + diff --git a/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_base.cpp b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_base.cpp new file mode 100644 index 00000000..9dbb77c9 --- /dev/null +++ b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_base.cpp @@ -0,0 +1,60 @@ +/*++ + +Copyright (C) 2025 Thread-safe library developers + +All rights reserved. + +Abstract: This is a stub class definition of CBase + +*/ + +#include "libthreadsafe_base.hpp" +#include "libthreadsafe_interfaceexception.hpp" + +// Include custom headers here. + + +using namespace LibThreadSafe::Impl; + +/************************************************************************************************************************* + Class definition of CBase +**************************************************************************************************************************/ + +bool CBase::GetLastErrorMessage(std::string & sErrorMessage) +{ + if (m_pLastError.get() != nullptr) { + sErrorMessage = *m_pLastError; + return true; + } else { + sErrorMessage = ""; + return false; + } +} + +void CBase::ClearErrorMessages() +{ + m_pLastError.reset(); +} + +void CBase::RegisterErrorMessage(const std::string & sErrorMessage) +{ + if (m_pLastError.get() == nullptr) { + m_pLastError.reset(new std::string()); + } + *m_pLastError = sErrorMessage; +} + +void CBase::IncRefCount() +{ + ++m_nReferenceCount; +} + +bool CBase::DecRefCount() +{ + m_nReferenceCount--; + if (!m_nReferenceCount) { + delete this; + return true; + } + return false; +} diff --git a/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_base.hpp b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_base.hpp new file mode 100644 index 00000000..beae5e19 --- /dev/null +++ b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_base.hpp @@ -0,0 +1,73 @@ +/*++ + +Copyright (C) 2025 Thread-safe library developers + +All rights reserved. + +Abstract: This is the class declaration of CBase + +*/ + + +#ifndef __LIBTHREADSAFE_BASE +#define __LIBTHREADSAFE_BASE + +#include "libthreadsafe_interfaces.hpp" +#include +#include +#include + + +// Include custom headers here. + + +namespace LibThreadSafe { +namespace Impl { + + +/************************************************************************************************************************* + Class declaration of CBase +**************************************************************************************************************************/ + +class CBase : public virtual IBase { +private: + + std::unique_ptr m_pLastError; + uint32_t m_nReferenceCount = 1; + + /** + * Put private members here. + */ + +protected: + + /** + * Put protected members here. + */ + +public: + + /** + * Put additional public members here. They will not be visible in the external API. + */ + + bool GetLastErrorMessage(std::string & sErrorMessage) override; + + void ClearErrorMessages() override; + + void RegisterErrorMessage(const std::string & sErrorMessage) override; + + void IncRefCount() override; + + bool DecRefCount() override; + + + /** + * Public member functions to implement. + */ +}; + +} // namespace Impl +} // namespace LibThreadSafe + +#endif // __LIBTHREADSAFE_BASE diff --git a/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_softstringreturner.cpp b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_softstringreturner.cpp new file mode 100644 index 00000000..e8ca9d41 --- /dev/null +++ b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_softstringreturner.cpp @@ -0,0 +1,33 @@ +/*++ + +Copyright (C) 2025 Thread-safe library developers + +All rights reserved. + +Abstract: This is a stub class definition of CSoftStringReturner + +*/ + +#include "libthreadsafe_softstringreturner.hpp" +#include "libthreadsafe_interfaceexception.hpp" + +// Include custom headers here. + + +using namespace LibThreadSafe::Impl; + +/************************************************************************************************************************* + Class definition of CSoftStringReturner +**************************************************************************************************************************/ + +std::string CSoftStringReturner::GetString() +{ + return std::string("Get random string"); +} + +void CSoftStringReturner::ThreadSafetyCheck() +{ + values.emplace_back(values.size()); + std::reverse(values.begin(), values.end()); +} + diff --git a/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_softstringreturner.hpp b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_softstringreturner.hpp new file mode 100644 index 00000000..19a59451 --- /dev/null +++ b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_softstringreturner.hpp @@ -0,0 +1,72 @@ +/*++ + +Copyright (C) 2025 Thread-safe library developers + +All rights reserved. + +Abstract: This is the class declaration of CSoftStringReturner + +*/ + + +#ifndef __LIBTHREADSAFE_SOFTSTRINGRETURNER +#define __LIBTHREADSAFE_SOFTSTRINGRETURNER + +#include "libthreadsafe_interfaces.hpp" + +// Parent classes +#include "libthreadsafe_base.hpp" +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4250) +#endif + +// Include custom headers here. +#include + +namespace LibThreadSafe { +namespace Impl { + + +/************************************************************************************************************************* + Class declaration of CSoftStringReturner +**************************************************************************************************************************/ + +class CSoftStringReturner : public virtual ISoftStringReturner, public virtual CBase { +private: + + /** + * Put private members here. + */ + std::vector values; + +protected: + + /** + * Put protected members here. + */ + +public: + + /** + * Put additional public members here. They will not be visible in the external API. + */ + + + /** + * Public member functions to implement. + */ + + std::string GetString() override; + + void ThreadSafetyCheck() override; + +}; + +} // namespace Impl +} // namespace LibThreadSafe + +#ifdef _MSC_VER +#pragma warning(pop) +#endif +#endif // __LIBTHREADSAFE_SOFTSTRINGRETURNER diff --git a/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_strictstringreturner.cpp b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_strictstringreturner.cpp new file mode 100644 index 00000000..06a61359 --- /dev/null +++ b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_strictstringreturner.cpp @@ -0,0 +1,33 @@ +/*++ + +Copyright (C) 2025 Thread-safe library developers + +All rights reserved. + +Abstract: This is a stub class definition of CStrictStringReturner + +*/ + +#include "libthreadsafe_strictstringreturner.hpp" +#include "libthreadsafe_interfaceexception.hpp" + +// Include custom headers here. + + +using namespace LibThreadSafe::Impl; + +/************************************************************************************************************************* + Class definition of CStrictStringReturner +**************************************************************************************************************************/ + +std::string CStrictStringReturner::GetString() +{ + return std::string("Get random string"); +} + +void CStrictStringReturner::ThreadSafetyCheck() +{ + values.emplace_back(values.size()); + std::reverse(values.begin(), values.end()); +} + diff --git a/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_strictstringreturner.hpp b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_strictstringreturner.hpp new file mode 100644 index 00000000..1348994e --- /dev/null +++ b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_strictstringreturner.hpp @@ -0,0 +1,72 @@ +/*++ + +Copyright (C) 2025 Thread-safe library developers + +All rights reserved. + +Abstract: This is the class declaration of CStrictStringReturner + +*/ + + +#ifndef __LIBTHREADSAFE_STRICTSTRINGRETURNER +#define __LIBTHREADSAFE_STRICTSTRINGRETURNER + +#include "libthreadsafe_interfaces.hpp" + +// Parent classes +#include "libthreadsafe_base.hpp" +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4250) +#endif + +// Include custom headers here. +#include + +namespace LibThreadSafe { +namespace Impl { + + +/************************************************************************************************************************* + Class declaration of CStrictStringReturner +**************************************************************************************************************************/ + +class CStrictStringReturner : public virtual IStrictStringReturner, public virtual CBase { +private: + + /** + * Put private members here. + */ + std::vector values; + +protected: + + /** + * Put protected members here. + */ + +public: + + /** + * Put additional public members here. They will not be visible in the external API. + */ + + + /** + * Public member functions to implement. + */ + + std::string GetString() override; + + void ThreadSafetyCheck() override; + +}; + +} // namespace Impl +} // namespace LibThreadSafe + +#ifdef _MSC_VER +#pragma warning(pop) +#endif +#endif // __LIBTHREADSAFE_STRICTSTRINGRETURNER diff --git a/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_stringreturner.cpp b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_stringreturner.cpp new file mode 100644 index 00000000..285de91e --- /dev/null +++ b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_stringreturner.cpp @@ -0,0 +1,33 @@ +/*++ + +Copyright (C) 2025 Thread-safe library developers + +All rights reserved. + +Abstract: This is a stub class definition of CStringReturner + +*/ + +#include "libthreadsafe_stringreturner.hpp" +#include "libthreadsafe_interfaceexception.hpp" + +// Include custom headers here. + + +using namespace LibThreadSafe::Impl; + +/************************************************************************************************************************* + Class definition of CStringReturner +**************************************************************************************************************************/ + +std::string CStringReturner::GetString() +{ + return std::string("Get random string"); +} + +void CStringReturner::ThreadSafetyCheck() +{ + values.emplace_back(values.size()); + std::reverse(values.begin(), values.end()); +} + diff --git a/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_stringreturner.hpp b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_stringreturner.hpp new file mode 100644 index 00000000..9907141a --- /dev/null +++ b/Examples/ThreadSafety/LibThreadSafe_component/Implementations/Cpp/Stub/libthreadsafe_stringreturner.hpp @@ -0,0 +1,72 @@ +/*++ + +Copyright (C) 2025 Thread-safe library developers + +All rights reserved. + +Abstract: This is the class declaration of CStringReturner + +*/ + + +#ifndef __LIBTHREADSAFE_STRINGRETURNER +#define __LIBTHREADSAFE_STRINGRETURNER + +#include "libthreadsafe_interfaces.hpp" + +// Parent classes +#include "libthreadsafe_base.hpp" +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning(disable : 4250) +#endif + +// Include custom headers here. +#include + +namespace LibThreadSafe { +namespace Impl { + + +/************************************************************************************************************************* + Class declaration of CStringReturner +**************************************************************************************************************************/ + +class CStringReturner : public virtual IStringReturner, public virtual CBase { +private: + + /** + * Put private members here. + */ + std::vector values; + +protected: + + /** + * Put protected members here. + */ + +public: + + /** + * Put additional public members here. They will not be visible in the external API. + */ + + + /** + * Public member functions to implement. + */ + + std::string GetString() override; + + void ThreadSafetyCheck() override; + +}; + +} // namespace Impl +} // namespace LibThreadSafe + +#ifdef _MSC_VER +#pragma warning(pop) +#endif +#endif // __LIBTHREADSAFE_STRINGRETURNER diff --git a/Examples/ThreadSafety/LibThreadSafe_component/license.txt b/Examples/ThreadSafety/LibThreadSafe_component/license.txt new file mode 100644 index 00000000..143fe992 --- /dev/null +++ b/Examples/ThreadSafety/LibThreadSafe_component/license.txt @@ -0,0 +1,5 @@ +Copyright (C) 2025 Thread-safe library developers + +All rights reserved. + + diff --git a/Examples/ThreadSafety/Readme.md b/Examples/ThreadSafety/Readme.md new file mode 100644 index 00000000..a2fbb85d --- /dev/null +++ b/Examples/ThreadSafety/Readme.md @@ -0,0 +1,129 @@ +# ![ACT logo](../../Documentation/images/ACT_logo_50px.png) Automatic Component Toolkit + +## Tutorial: Usage of the `threadsafetyoption`class parameter + + +## Table of Contents + +- [1. Problem](#1-problem) +- [2. Solution](#2-solution) +- [3. Example](#3-example) +- [4. Support](#4-support) + +# 1. Problem +The Automatic Component Toolkit (ACT) has an issue with thread safety when returning strings (arrays) from +functions or methods, especially in the C++ Binding/Implementation. The problem arises from the caching mechanism +used in ACT. When API functions or methods that return strings are executed concurrently from multiple +threads in the library consumer code, it can result in crashes. + +# 2. Solution +### 2.1. Overview +To address the thread safety issue described above, a new parameter called `threadsafetyoption` has been introduced. +This parameter ensures thread safety by adding mutex locking mechanisms on the library implementation side. + +### 2.2. Details +The `threadsafetyoption` parameter can be set to `none`, `soft` or `strict` value: +- `none`: Does nothing. When used in child class ACT will copy `ThreadSafetyOption` from parent. +- `soft`: The binding side will call the lock mechanism only when a string is returned from an API function. +- `strict`: The binding side will call the lock mechanism every time, regardless of what is returned from the function. + +When the `threadsafetyoption` attribute in the component class is set to `soft` or `strict`, +the implementation will derive from a base class that includes mutex locking mechanisms. +This solution ensures thread safety both when a single pointer on the binding side is shared across threads, +and when different pointers that point to the same object on the implementation side are used in different threads. +Additionally, error handling mechanisms are in place to unlock the mutex in case of exception propagation, preventing deadlocks. + +### 2.3 Rules +* The base class can have the `threadsafetyoption` parameter set to `soft` or `strict`. +* If a child class has the `threadsafetyoption` parameter set to `soft` or `strict`, +its parent class must also have the `threadsafetyoption` parameter set to `soft` or `strict`, or the parent must be the base class. +* The `threadsafetyoption` parameter in a child class cannot be less strict than the parent's `threadsafetyoption` parameter. + +# 3. Example +### 3.1. Component definition +In the `threadSafeLibrary.xml` file, there are three classes defined with the same methods but different `threadsafetyoption` values: +- `StringReturner` with `threadsafetyoption` set to `none`. +- `SoftStringReturner` with `threadsafetyoption` set to `soft`. +- `StrictStringReturner`: with `threadsafetyoption` set to `strict`. + +```xml + + + + + + + + + + + + + + + + + + +``` + +Each class has the following methods: +- `GetString` which simply returns a random string. +- `ThreadSafetyCheck` which returns nothing but may crash when executed from different threads simultaneously, as no thread safety mechanism is provided in the library implementation. + +### 3.2. Usage +Let's consider below cpp example from `LibThreadSafe_example.cpp`. + +```cpp +#include +#include +#include +#include "libthreadsafe_dynamic.hpp" + +template +void testStringReturn(ArrayReturner& returner) +{ + std::vector threads; + for (int i = 0; i < 5; ++i) { + threads.emplace_back([&returner]() { + for (int j = 0; j < 10000; ++j) { + returner->GetString(); + } + }); + } +} + +template +void testThreadSafetyCheck(ArrayReturner& returner) +{ + std::vector threads; + for (int i = 0; i < 5; ++i) { + threads.emplace_back([&returner]() { + for (int j = 0; j < 10000; ++j) { + returner->ThreadSafetyCheck(); + } + }); + } +} + +int main() +{ + std::string libpath = ("Path to library"); + auto wrapper = LibThreadSafe::CWrapper::loadLibrary(libpath + ".dll"); + + LibThreadSafe::PStringReturner stringReturner = wrapper->CreateStringReturner(); + LibThreadSafe::PSoftStringReturner softStringReturner = wrapper->CreateSoftStringReturner(); + LibThreadSafe::PStrictStringReturner strictStringReturner = wrapper->CreateStrictStringReturner(); +} +``` + +Executing `testStringReturn` and `testThreadSafetyCheck` with `stringReturner` will crash because there is no thread safety mechanism enabled for this instance. + +Executing `testStringReturn` with `softStringReturner` will work as expected. However, it will crash on `testThreadSafetyCheck` because with the `soft` +value of the `threadsafetyoption` parameter, the thread safety mechanism will lock the instance on the library side only when executing functions that return strings. + +Executing `testStringReturn` or `testThreadSafetyCheck` on `strictStringReturner` will work as expected in both cases because with the `strict` value of +the `threadsafetyoption`, the instance on the implementation side will be locked during each function execution. + +# 4. Support +Currently, the `threadsafetyoption` parameter is supported only for Cpp/CppDynamic bindings and Cpp implementation. diff --git a/Examples/ThreadSafety/threadSafeLibrary.xml b/Examples/ThreadSafety/threadSafeLibrary.xml new file mode 100644 index 00000000..083994cd --- /dev/null +++ b/Examples/ThreadSafety/threadSafeLibrary.xml @@ -0,0 +1,87 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Source/automaticcomponenttoolkit.go b/Source/automaticcomponenttoolkit.go index b84f469d..4c720689 100644 --- a/Source/automaticcomponenttoolkit.go +++ b/Source/automaticcomponenttoolkit.go @@ -585,7 +585,7 @@ func printUsageInfo() { } func main() { - ACTVersion := "1.8.0-develop" + ACTVersion := "1.8.1-develop" fmt.Fprintln(os.Stdout, "Automatic Component Toolkit v"+ACTVersion) if len(os.Args) < 2 { printUsageInfo() @@ -690,6 +690,11 @@ func main() { log.Fatal(err) } + addExtraBaseClassMethods := component.addExtraBaseClassMethods() + if addExtraBaseClassMethods != nil { + log.Printf("%s", *addExtraBaseClassMethods) + } + if mode == eACTModeDiff { log.Printf("Loading Component Description File to compare to") componentB, err := ReadComponentDefinition(diffFile, ACTVersion) diff --git a/Source/buildbindingccpp.go b/Source/buildbindingccpp.go index c54855f8..be0f4ff6 100644 --- a/Source/buildbindingccpp.go +++ b/Source/buildbindingccpp.go @@ -591,7 +591,7 @@ func writeDynamicCPPMethodDeclaration(method ComponentDefinitionMethod, w Langua } func writeDynamicCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, NameSpace string, ClassIdentifier string, ClassName string, - implementationLines []string, isGlobal bool, includeComments bool, doNotThrow bool, useCPPTypes bool, ExplicitLinking bool, forWASM bool) error { + implementationLines []string, isGlobal bool, includeComments bool, doNotThrow bool, useCPPTypes bool, ExplicitLinking bool, forWASM bool, multiThreadedEnv bool, classThreadSafetyOption ThreadSafetyOption) error { WASMPrefix := "" WASMCast := "" @@ -616,6 +616,14 @@ func writeDynamicCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, N checkErrorCodeEnd := ")" makeSharedParameter := "" + if multiThreadedEnv && !isGlobal { + if classThreadSafetyOption == eThreadSafetyStrict { + checkErrorCodeEnd = ", true)" + } else { + checkErrorCodeEnd = ", false)" + } + } + if isGlobal { if ExplicitLinking { CMethodName = fmt.Sprintf("m_WrapperTable.m_%s", method.MethodName) @@ -858,6 +866,12 @@ func writeDynamicCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, N initCallParameters = initCallParameters + initCallParameter } + addThreadSafeCalls := multiThreadedEnv && !isGlobal && ((classThreadSafetyOption == eThreadSafetySoft && requiresInitCall) || classThreadSafetyOption == eThreadSafetyStrict) + + if addThreadSafeCalls { + checkErrorCodeEnd = ", true)" + } + w.Writeln(" ") if includeComments { w.Writeln(" /**") @@ -876,6 +890,11 @@ func writeDynamicCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, N w.Writeln(" {") w.Writelns(" ", definitionCodeLines) + + if addThreadSafeCalls { + w.Writeln(" %s();", getLockInstanceMethodName()) + } + if requiresInitCall { w.Writeln(" %s%s(%s)%s;", checkErrorCodeBegin, CMethodName, initCallParameters, checkErrorCodeEnd) } @@ -888,6 +907,10 @@ func writeDynamicCPPMethod(method ComponentDefinitionMethod, w LanguageWriter, N w.Writelns(" ", implementationLines) } + if addThreadSafeCalls { + w.Writeln(" %s();", getUnlockInstanceMethodName()) + } + if len(returnCodeLines) > 0 { w.Writeln(" ") w.Writelns(" ", returnCodeLines) @@ -905,11 +928,20 @@ func writeDynamicCppBaseClassMethods(component ComponentDefinition, baseClass Co w.Writeln(" /* Handle to Instance in library*/") w.Writeln(" %sHandle m_pHandle;", NameSpace) w.Writeln("") - w.Writeln(" /* Checks for an Error code and raises Exceptions */") - w.Writeln(" void CheckError(%sResult nResult)", NameSpace) + if component.isMultiThreadedEnv() { + w.Writeln(" /* Checks for an Error code, raises Exceptions and unlocks library object*/") + w.Writeln(" void CheckError(%sResult nResult, bool unlockIfError)", NameSpace) + } else { + w.Writeln(" /* Checks for an Error code and raises Exceptions */") + w.Writeln(" void CheckError(%sResult nResult)", NameSpace) + } w.Writeln(" {") w.Writeln(" if (m_pWrapper != nullptr)") - w.Writeln(" m_pWrapper->CheckError(this, nResult);") + if component.isMultiThreadedEnv() { + w.Writeln(" m_pWrapper->CheckError(this, nResult, unlockIfError);") + } else { + w.Writeln(" m_pWrapper->CheckError(this, nResult);") + } w.Writeln(" }") w.Writeln("public:") w.Writeln(" /**") @@ -1390,19 +1422,42 @@ func writeClassDeclarations(w LanguageWriter, component ComponentDefinition, cpp w.Writeln(" {") w.Writeln(" }") w.Writeln(" ") + + for _, method := range class.Methods { + err := writeDynamicCPPMethodDeclaration(method, w, NameSpace, ClassIdentifier, cppClassName) + if err != nil { + return err + } + } + } else { err := writeDynamicCppBaseClassMethods(component, baseClass, w, NameSpace, BaseName, cppClassPrefix, ClassIdentifier) if err != nil { return err } - } - for _, method := range class.Methods { - err := writeDynamicCPPMethodDeclaration(method, w, NameSpace, ClassIdentifier, cppClassName) - if err != nil { - return err + extraBaseClassMethods := []ComponentDefinitionMethod{} + for _, method := range class.Methods { + if method.isExtraBaseClassmethod() { + extraBaseClassMethods = append(extraBaseClassMethods, method) + } else { + err := writeDynamicCPPMethodDeclaration(method, w, NameSpace, ClassIdentifier, cppClassName) + if err != nil { + return err + } + } + } + + w.Writeln(" ") + w.Writeln("protected:") + for _, method := range extraBaseClassMethods { + err := writeDynamicCPPMethodDeclaration(method, w, NameSpace, ClassIdentifier, cppClassName) + if err != nil { + return err + } } } + w.Writeln("};") } return nil @@ -1450,13 +1505,22 @@ func writePolymorphicFactoryImplementation(w LanguageWriter, component Component w.Writeln("}") } -func writeCheckErrorImplementation(w LanguageWriter, ErrorMethodName string, ClassIdentifier string, cppBaseClassName string, NameSpace string) { - w.Writeln(" inline void C%sWrapper::CheckError(%s * pBaseClass, %sResult nResult)", ClassIdentifier, cppBaseClassName, NameSpace) +func writeCheckErrorImplementation(w LanguageWriter, ErrorMethodName string, ClassIdentifier string, cppBaseClassName string, NameSpace string, multiThreadedEnv bool) { + if multiThreadedEnv { + w.Writeln(" inline void C%sWrapper::CheckError(%s * pBaseClass, %sResult nResult, bool unlockIfError)", ClassIdentifier, cppBaseClassName, NameSpace) + } else { + w.Writeln(" inline void C%sWrapper::CheckError(%s * pBaseClass, %sResult nResult)", ClassIdentifier, cppBaseClassName, NameSpace) + } w.Writeln(" {") w.Writeln(" if (nResult != 0) {") w.Writeln(" std::string sErrorMessage;") w.Writeln(" if (pBaseClass != nullptr) {") w.Writeln(" %s(pBaseClass, sErrorMessage);", ErrorMethodName) + if multiThreadedEnv { + w.Writeln(" if (unlockIfError) {") + w.Writeln(" pBaseClass->%s();", getUnlockInstanceMethodName()) + w.Writeln(" }") + } w.Writeln(" }") w.Writeln(" throw E%sException(nResult, sErrorMessage);", NameSpace) w.Writeln(" }") @@ -1539,7 +1603,11 @@ func buildCppHeader(component ComponentDefinition, w LanguageWriter, NameSpace s writeWrapperLifeTimeHandling(w, cppClassPrefix, ClassIdentifier, ExplicitLinking) w.Writeln(" ") - w.Writeln(" inline void CheckError(%s * pBaseClass, %sResult nResult);", cppBaseClassName, NameSpace) + if component.isMultiThreadedEnv() { + w.Writeln(" inline void CheckError(%s * pBaseClass, %sResult nResult, bool unlockIfError = false);", cppBaseClassName, NameSpace) + } else { + w.Writeln(" inline void CheckError(%s * pBaseClass, %sResult nResult);", cppBaseClassName, NameSpace) + } w.Writeln("") for j := 0; j < len(global.Methods); j++ { @@ -1622,7 +1690,7 @@ func buildCppHeader(component ComponentDefinition, w LanguageWriter, NameSpace s implementationLines = append(implementationLines, fmt.Sprintf(" throw E%sException(%s_ERROR_COULDNOTLOADLIBRARY, \"Unknown namespace \" + %s);", NameSpace, strings.ToUpper(NameSpace), sParamName)) } - err = writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, "Wrapper", implementationLines, true, true, false, useCPPTypes, ExplicitLinking, false) + err = writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, "Wrapper", implementationLines, true, true, false, useCPPTypes, ExplicitLinking, false, component.isMultiThreadedEnv(), eThreadSafetyNone) if err != nil { return err } @@ -1630,7 +1698,7 @@ func buildCppHeader(component ComponentDefinition, w LanguageWriter, NameSpace s } w.Writeln("") - writeCheckErrorImplementation(w, component.Global.ErrorMethod, ClassIdentifier, cppBaseClassName, NameSpace) + writeCheckErrorImplementation(w, component.Global.ErrorMethod, ClassIdentifier, cppBaseClassName, NameSpace, component.isMultiThreadedEnv()) w.Writeln("") if ExplicitLinking { @@ -1648,7 +1716,7 @@ func buildCppHeader(component ComponentDefinition, w LanguageWriter, NameSpace s w.Writeln(" */") for j := 0; j < len(class.Methods); j++ { method := class.Methods[j] - err := writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, class.ClassName, make([]string, 0), false, true, false, useCPPTypes, ExplicitLinking, false) + err := writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, class.ClassName, make([]string, 0), false, true, false, useCPPTypes, ExplicitLinking, false, component.isMultiThreadedEnv(), component.getRealThreadSafetyOption(&class)) if err != nil { return err } @@ -2217,14 +2285,14 @@ func buildCppwasmGuestHeader(component ComponentDefinition, w LanguageWriter, Na implementationLines = append(implementationLines, fmt.Sprintf(" throw E%sException(%s_ERROR_COULDNOTLOADLIBRARY, \"Unknown namespace \" + %s);", NameSpace, strings.ToUpper(NameSpace), sParamName)) } - err = writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, "Wrapper", implementationLines, true, true, false, useCPPTypes, ExplicitLinking, true) + err = writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, "Wrapper", implementationLines, true, true, false, useCPPTypes, ExplicitLinking, true, false, eThreadSafetyNone) if err != nil { return err } } w.Writeln("") - writeCheckErrorImplementation(w, component.Global.ErrorMethod, ClassIdentifier, cppBaseClassName, NameSpace) + writeCheckErrorImplementation(w, component.Global.ErrorMethod, ClassIdentifier, cppBaseClassName, NameSpace, false) w.Writeln("") for i := 0; i < len(component.Classes); i++ { @@ -2236,7 +2304,7 @@ func buildCppwasmGuestHeader(component ComponentDefinition, w LanguageWriter, Na w.Writeln(" */") for j := 0; j < len(class.Methods); j++ { method := class.Methods[j] - err := writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, class.ClassName, make([]string, 0), false, true, false, useCPPTypes, ExplicitLinking, true) + err := writeDynamicCPPMethod(method, w, NameSpace, ClassIdentifier, class.ClassName, make([]string, 0), false, true, false, useCPPTypes, ExplicitLinking, true, false, eThreadSafetyNone) if err != nil { return err } diff --git a/Source/buildimplementationcpp.go b/Source/buildimplementationcpp.go index 504b93cf..e4de8349 100644 --- a/Source/buildimplementationcpp.go +++ b/Source/buildimplementationcpp.go @@ -314,6 +314,39 @@ func writeSharedPtrTemplate(component ComponentDefinition, w LanguageWriter, Cla w.Writeln("") } +func getWithMutexClassName(ClassIdentifier string, ClassName string) (string) { + return ClassIdentifier + ClassName + "WithMutex" +} + +func writeBaseInterfaceWithMutexClass(baseClass ComponentDefinitionClass, w LanguageWriter, ClassIdentifier string) { + baseClassName:= "I" + baseClass.ClassName + className := "I" + getWithMutexClassName(ClassIdentifier, baseClass.ClassName) + lockInstanceMethod := LockInstanceMethod() + unlockInstanceMethod := UnlockInstanceMethod() + + w.Writeln("") + w.Writeln("/**") + w.Writeln(" Definition of a class with mutex for %s", baseClassName) + w.Writeln("*/") + w.Writeln("class %s : public virtual %s", className, baseClassName) + w.Writeln("{") + w.Writeln("private:") + w.Writeln(" std::mutex m_mutex;") + w.Writeln("public:") + w.Writeln("") + w.Writeln(" /**") + w.Writeln(" * %s::%s - %s", className, lockInstanceMethod.MethodName, lockInstanceMethod.MethodDescription) + w.Writeln(" */") + w.Writeln(" virtual void %s() { m_mutex.lock(); }", lockInstanceMethod.MethodName) + w.Writeln("") + w.Writeln(" /**") + w.Writeln(" * %s::%s - %s", className, unlockInstanceMethod.MethodName, unlockInstanceMethod.MethodDescription) + w.Writeln(" */") + w.Writeln(" virtual void %s() { m_mutex.unlock();}", unlockInstanceMethod.MethodName) + w.Writeln("};") + w.Writeln("") +} + func writeCPPClassInterface(component ComponentDefinition, class ComponentDefinitionClass, w LanguageWriter, NameSpace string, NameSpaceImplementation string, ClassIdentifier string, BaseName string) (error) { w.Writeln("") w.Writeln("/*************************************************************************************************************************") @@ -321,12 +354,14 @@ func writeCPPClassInterface(component ComponentDefinition, class ComponentDefini w.Writeln("**************************************************************************************************************************/") w.Writeln("") parentClassString := " " - if (!component.isBaseClass(class)) { + if !component.isBaseClass(class) { parentClassString = " : public virtual " - if (class.ParentClass == "") { - parentClassString += fmt.Sprintf("I%s%s ", ClassIdentifier, component.Global.BaseClassName) + parentName := class.ParentClass + + if parentName == component.Global.BaseClassName && component.getRealThreadSafetyOption(&class) != eThreadSafetyNone { + parentClassString += fmt.Sprintf("I%s ", getWithMutexClassName(ClassIdentifier, parentName)) } else { - parentClassString += fmt.Sprintf("I%s%s ", ClassIdentifier, class.ParentClass) + parentClassString += fmt.Sprintf("I%s%s ", ClassIdentifier, parentName) } } @@ -334,9 +369,8 @@ func writeCPPClassInterface(component ComponentDefinition, class ComponentDefini w.Writeln("class %s%s{", classInterfaceName, parentClassString) if (component.isStringOutBaseClass(class)) { - w.Writeln("private:") - w.Writeln(" std::unique_ptr m_ParameterCache;") - + w.Writeln("protected:") + w.Writeln(" std::unique_ptr m_ParameterCache;") } w.Writeln("public:") @@ -411,7 +445,23 @@ func writeCPPClassInterface(component ComponentDefinition, class ComponentDefini w.Writeln(" {") w.Writeln(" return m_ParameterCache.get();") w.Writeln(" }") - w.Writeln("") + w.Writeln("") + + if component.isMultiThreadedEnv() { + lockInstanceMethod := LockInstanceMethod() + w.Writeln(" /**") + w.Writeln(" * %s::%s - %s", classInterfaceName, lockInstanceMethod.MethodName, lockInstanceMethod.MethodDescription) + w.Writeln(" */") + w.Writeln(" virtual void %s() {}", lockInstanceMethod.MethodName) + w.Writeln("") + + unlockInstanceMethod := UnlockInstanceMethod() + w.Writeln(" /**") + w.Writeln(" * %s::%s - %s", classInterfaceName, unlockInstanceMethod.MethodName, unlockInstanceMethod.MethodDescription) + w.Writeln(" */") + w.Writeln(" virtual void %s() {}", unlockInstanceMethod.MethodName) + w.Writeln("") + } } if (component.isBaseClass(class)) { @@ -440,6 +490,11 @@ func writeCPPClassInterface(component ComponentDefinition, class ComponentDefini if method.MethodName == component.Global.ClassTypeIdMethod { continue } + + if component.isBaseClass(class) && method.isExtraBaseClassmethod() { + continue + } + methodstring, _, err := buildCPPInterfaceMethodDeclaration(method, class.ClassName, NameSpace, ClassIdentifier, BaseName, w.IndentString, false, true, true) if err != nil { return err @@ -452,6 +507,9 @@ func writeCPPClassInterface(component ComponentDefinition, class ComponentDefini if component.isBaseClass(class) { writeSharedPtrTemplate(component, w, ClassIdentifier) + if component.isMultiThreadedEnv() { + writeBaseInterfaceWithMutexClass(class, w, ClassIdentifier) + } } w.Writeln("") @@ -535,6 +593,9 @@ func buildCPPInterfaces(component ComponentDefinition, w LanguageWriter, NameSpa w.Writeln("#include ") w.Writeln("#include ") + if component.isMultiThreadedEnv() { + w.Writeln("#include ") + } w.Writeln("") w.Writeln("#include \"%s_types.hpp\"", BaseName) w.Writeln("") @@ -1288,6 +1349,11 @@ func buildCPPStubClass(component ComponentDefinition, class ComponentDefinitionC for j := 0; j < len(class.Methods); j++ { method := class.Methods[j] + + if method.isExtraBaseClassmethod() { + continue; + } + methodstring, implementationdeclaration, err := buildCPPInterfaceMethodDeclaration(method, class.ClassName, NameSpace, ClassIdentifier, BaseName, stubimplw.IndentString, false, false, false) if err != nil { return err diff --git a/Source/componentdefinition.go b/Source/componentdefinition.go index 24be9903..b679290d 100644 --- a/Source/componentdefinition.go +++ b/Source/componentdefinition.go @@ -62,6 +62,26 @@ const ( eSpecialMethodBuildinfo = 9 ) +type ThreadSafetyOption int +const ( + eThreadSafetyNone = 0 + eThreadSafetySoft = 1 + eThreadSafetyStrict = 2 +) + +func (option ThreadSafetyOption) String() string { + switch option { + case eThreadSafetyNone: + return "None" + case eThreadSafetySoft: + return "Soft" + case eThreadSafetyStrict: + return "Strict" + default: + return "Unknown" + } +} + // ComponentDefinitionParam definition of a method parameter used in the component's API type ComponentDefinitionParam struct { ComponentDiffableElement @@ -90,6 +110,7 @@ type ComponentDefinitionClass struct { ClassName string `xml:"name,attr"` ClassDescription string `xml:"description,attr"` ParentClass string `xml:"parent,attr"` + ThreadSafetyOption string `xml:"threadsafetyoption,attr"` Methods []ComponentDefinitionMethod `xml:"method"` } @@ -345,6 +366,41 @@ func ReadComponentDefinition(FileName string, ACTVersion string) (ComponentDefin return component, nil } +func (component *ComponentDefinition) addExtraBaseClassMethods() *string { + if component.isMultiThreadedEnv() { + for i := 0; i < len(component.Classes); i++ { + class := component.Classes[i] + if component.isBaseClass(class) { + msg := fmt.Sprintf("Mutli threaded implementation detected, adding %s, %s", getLockInstanceMethodName(), getUnlockInstanceMethodName()) + class.Methods = append(class.Methods, LockInstanceMethod(), UnlockInstanceMethod()) + component.Classes[i] = class + return &msg + } + } + } + + return nil +} + +func (component *ComponentDefinition) getParent(class *ComponentDefinitionClass) *ComponentDefinitionClass { + parentName := class.ParentClass + if parentName == "" { + return nil + } + + for i := range component.Classes { + if component.Classes[i].ClassName == parentName { + return &component.Classes[i] + } + } + + return nil +} + +func (method *ComponentDefinitionMethod) isExtraBaseClassmethod() bool { + return method.MethodName == getLockInstanceMethodName() || method.MethodName == getUnlockInstanceMethodName() +} + func getIndentationString(str string) string { if str == "tabs" { return "\t"; @@ -521,7 +577,20 @@ func (component *ComponentDefinition) checkClasses() (error) { classTypeIdIndex := make(map[uint64]int, 0) for i := 0; i < len(classes); i++ { class := classes[i]; + if !component.isBaseClass(class) { + if class.ParentClass == "" { + class.ParentClass = component.Global.BaseClassName + classes[i] = class + } + } + classTypeHash, _ := class.classTypeId(component.NameSpace); + if class.isThreadSafe() { + err := checkThreadSafetyHierarchy(component, &class) + if err != nil { + return err + } + } if !nameIsValidIdentifier(class.ClassName) { return fmt.Errorf ("invalid class name \"%s\"", class.ClassName); } @@ -531,6 +600,9 @@ func (component *ComponentDefinition) checkClasses() (error) { if len(class.ClassDescription) > 0 && !descriptionIsValid(class.ClassDescription) { return fmt.Errorf ("invalid class description \"%s\" in class \"%s\"", class.ClassDescription, class.ClassName); } + if len(class.ThreadSafetyOption) > 0 && !threadSafetyOptionIsValid(class.ThreadSafetyOption) { + return fmt.Errorf("invalid class thread safety option \"%s\" in class \"%s\"", class.ThreadSafetyOption, class.ClassName) + } collision, hashExists := classTypeIdIndex[classTypeHash] if hashExists { return fmt.Errorf ("Classes \"%s\" and \"%s\" have a collision in their Class Type Id. Change class name.", classes[collision].ClassName, class.ClassName); @@ -540,6 +612,7 @@ func (component *ComponentDefinition) checkClasses() (error) { (*classNameList)[class.ClassName] = true classNameIndex[class.ClassName] = i classTypeIdIndex[classTypeHash] = i + } // Check parent class definitions @@ -568,7 +641,7 @@ func (component *ComponentDefinition) checkClasses() (error) { return nil } -func (component *ComponentDefinition) checkFunctionTypes() ( error) { +func (component *ComponentDefinition) checkFunctionTypes() (error) { functions := component.Functions var functionNameList = &component.NameMapsLookup.functionTypeMap @@ -591,6 +664,26 @@ func (component *ComponentDefinition) checkFunctionTypes() ( error) { return nil } +func checkThreadSafetyHierarchy(component *ComponentDefinition, class *ComponentDefinitionClass) error { + classOption := class.eThreadSafetyOption() + parent := component.getParent(class) + for parent != nil { + parentOption := parent.eThreadSafetyOption() + + if classOption != eThreadSafetyNone && parentOption == eThreadSafetyNone && !component.isBaseClass(*parent) { + return fmt.Errorf("class \"%s\" has threadSafetyOption = \"%s\", but its parent \"%s\" is not base \"%s\" class and has threadSafetyOption = \"%s\"", + class.ClassName, classOption, parent.ClassName, component.Global.BaseClassName, parentOption) + } + + if classOption < parentOption && (!component.isBaseClass(*parent) || parentOption != eThreadSafetyNone) { + return fmt.Errorf("class \"%s\" has threadSafetyOption = \"%s\", but its parent \"%s\" has threadSafetyOption = \"%s\"", class.ClassName, classOption, parent.ClassName, parentOption) + } + parent = component.getParent(parent) + } + + return nil +} + func checkDuplicateNames(nameMaps NameMaps) (error) { enumList := nameMaps.enumMap structList := nameMaps.structMap @@ -796,6 +889,14 @@ func descriptionIsValid(description string) bool { return false; } +func threadSafetyOptionIsValid(threadSafetyOption string) bool { + switch threadSafetyOption { + case "none", "strict", "soft": + return true + } + return false +} + func isScalarType(typeStr string) bool { switch (typeStr) { case "uint8", "uint16", "uint32", "uint64", "int8", "int16", "int32", "int64", "bool", "single", "double", "pointer": @@ -1272,6 +1373,32 @@ func (component *ComponentDefinition) isBaseClass(class ComponentDefinitionClass return class.ClassName == component.Global.BaseClassName } +func getLockInstanceMethodName() string { + return "_lockInstance" +} + +// LockInstanceMethod returns the xml definition of the LockInstanceMethod +func LockInstanceMethod() ComponentDefinitionMethod { + var method ComponentDefinitionMethod + source := fmt.Sprintf(` + `, getLockInstanceMethodName()) + xml.Unmarshal([]byte(source), &method) + return method +} + +func getUnlockInstanceMethodName() string { + return "_unlockInstance" +} + +// UnlockInstanceMethod returns the xml definition of the UnlockInstanceMethod +func UnlockInstanceMethod() ComponentDefinitionMethod { + var method ComponentDefinitionMethod + source := fmt.Sprintf(` + `, getUnlockInstanceMethodName()) + xml.Unmarshal([]byte(source), &method) + return method +} + func (component *ComponentDefinition) baseClass() (ComponentDefinitionClass) { for i := 0; i < len(component.Classes); i++ { if (component.isBaseClass(component.Classes[i])) { @@ -1363,6 +1490,52 @@ func (method *ComponentDefinitionMethod) getArrayOutParameters() ([]string) { return outParameters; } +func (component *ComponentDefinition) getRealThreadSafetyOption(class *ComponentDefinitionClass) ThreadSafetyOption { + option := class.eThreadSafetyOption() + if option != eThreadSafetyNone { + return option + } + + parent := component.getParent(class) + for parent != nil { + parentOption := parent.eThreadSafetyOption() + if parentOption != eThreadSafetyNone { + return parentOption + } + + parent = component.getParent(parent) + } + + return eThreadSafetyNone +} + +func (class *ComponentDefinitionClass) eThreadSafetyOption() ThreadSafetyOption { + switch class.ThreadSafetyOption { + case "strict": + return eThreadSafetyStrict + case "soft": + return eThreadSafetySoft + case "none": + return eThreadSafetyNone + } + return eThreadSafetyNone +} + +func (class *ComponentDefinitionClass) isThreadSafe() bool { + return class.eThreadSafetyOption() != eThreadSafetyNone +} + +func (component *ComponentDefinition) isMultiThreadedEnv() bool { + classes := component.Classes + for i := 0; i < len(classes); i++ { + class := classes[i] + if class.isThreadSafe() { + return true + } + } + + return false +} func (class *ComponentDefinitionClass) countMaxOutParameters() (uint32) {