This commit is contained in:
2021-10-14 13:47:35 +02:00
commit 6625a8dfaa
4026 changed files with 844291 additions and 0 deletions
@@ -0,0 +1,109 @@
PROJECT(openvibe-module-system)
SET(PROJECT_VERSION_MAJOR ${OV_GLOBAL_VERSION_MAJOR})
SET(PROJECT_VERSION_MINOR ${OV_GLOBAL_VERSION_MINOR})
SET(PROJECT_VERSION_PATCH ${OV_GLOBAL_VERSION_PATCH})
SET(PROJECT_VERSION ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}.${PROJECT_VERSION_PATCH})
SET(SRC_FILES
include/system/defines.h
include/system/ovCChrono.h
include/system/ovCMath.h
include/system/ovCMemory.h
include/system/ovCTime.h
include/system/ovCDynamicModule.h
src/ovCChrono.cpp
src/ovCMath.cpp
src/ovCMemory.cpp
src/ovCTime.cpp
src/ovCDynamicModule.cpp
)
IF(WIN32)
LIST(APPEND SRC_FILES
"include/system/WindowsUtilities.h"
"src/WindowsUtilities.cpp"
)
ENDIF()
INCLUDE_DIRECTORIES(include)
INCLUDE("FindSourceRCProperties")
ADD_LIBRARY(${PROJECT_NAME} SHARED ${SRC_FILES})
SET_TARGET_PROPERTIES(${PROJECT_NAME} PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
FOLDER ${MODULES_FOLDER}
COMPILE_FLAGS "-DSystem_Shared -DSystem_Exports")
ADD_LIBRARY(${PROJECT_NAME}-static STATIC ${SRC_FILES})
SET_TARGET_PROPERTIES(${PROJECT_NAME}-static PROPERTIES
VERSION ${PROJECT_VERSION}
SOVERSION ${PROJECT_VERSION_MAJOR}
FOLDER ${MODULES_FOLDER}
COMPILE_FLAGS "-DSystem_Static -DSystem_Exports")
IF(UNIX)
SET_TARGET_PROPERTIES(${PROJECT_NAME}-static PROPERTIES COMPILE_FLAGS "-fPIC")
ENDIF()
INCLUDE("FindOpenViBECommon")
IF(WIN32 AND CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.0")
INCLUDE("FindThirdPartyBoost")
OV_LINK_BOOST_LIB("system" ${OV_WIN32_BOOST_VERSION})
OV_LINK_BOOST_LIB("thread" ${OV_WIN32_BOOST_VERSION})
INCLUDE("FindThirdPartyBoost_Chrono")
ENDIF()
# ---------------------------------
# Finds standard library winmm
# Adds library to target
# Adds include path
# ---------------------------------
IF(WIN32)
INCLUDE("OvSetWindowsSDKPath")
FIND_LIBRARY(LIB_STANDARD_MODULE_WINMM winmm ${OV_MS_SDK_PATH}/lib)
IF(LIB_STANDARD_MODULE_WINMM)
MESSAGE(STATUS " Found winmm...")
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${LIB_STANDARD_MODULE_WINMM})
TARGET_LINK_LIBRARIES(${PROJECT_NAME}-static ${LIB_STANDARD_MODULE_WINMM})
ELSE(LIB_STANDARD_MODULE_WINMM)
MESSAGE(STATUS " FAILED to find winmm...")
ENDIF(LIB_STANDARD_MODULE_WINMM)
FIND_LIBRARY(LIB_STANDARD_MODULE_DBGHELP dbghelp ${OV_MS_SDK_PATH}/lib)
IF(LIB_STANDARD_MODULE_DBGHELP)
MESSAGE(STATUS " Found dbghelp...")
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${LIB_STANDARD_MODULE_DBGHELP})
TARGET_LINK_LIBRARIES(${PROJECT_NAME}-static ${LIB_STANDARD_MODULE_DBGHELP})
ELSE(LIB_STANDARD_MODULE_DBGHELP)
MESSAGE(STATUS " FAILED to find dbghelp...")
ENDIF(LIB_STANDARD_MODULE_DBGHELP)
ELSE()
TARGET_LINK_LIBRARIES(${PROJECT_NAME} ${CMAKE_DL_LIBS})
ENDIF()
# ---------------------------------
# Target macros
# Defines target operating system, architecture and compiler
# ---------------------------------
SET_BUILD_PLATFORM()
# -----------------------------
# Install files
# -----------------------------
INSTALL(TARGETS ${PROJECT_NAME}
RUNTIME DESTINATION ${DIST_BINDIR}
LIBRARY DESTINATION ${DIST_LIBDIR}
ARCHIVE DESTINATION ${DIST_LIBDIR})
INSTALL(TARGETS ${PROJECT_NAME}-static
RUNTIME DESTINATION ${DIST_BINDIR}
LIBRARY DESTINATION ${DIST_LIBDIR}
ARCHIVE DESTINATION ${DIST_LIBDIR})
INSTALL(DIRECTORY include/ DESTINATION ${DIST_INCLUDEDIR} FILES_MATCHING PATTERN "*.h")
@@ -0,0 +1,31 @@
#pragma once
#include "defines.h"
#if defined TARGET_OS_Windows
#include <windows.h>
namespace System {
class System_API WindowsUtilities
{
public:
// Load a library in a matter compliant with non-ascii path
// returns the eventual error code
static void* utf16CompliantLoadLibrary(const char* path, HANDLE file = nullptr, DWORD flags = LOAD_WITH_ALTERED_SEARCH_PATH);
static BOOL utf16CompliantSetEnvironmentVariable(const char* name, const char* value);
// Load a library in a matter compliant with non-ascii path
// returns the eventual error code
static BOOL utf16CompliantCreateProcess(char* applicationName, char* commandLine, LPSECURITY_ATTRIBUTES processAttributes,
LPSECURITY_ATTRIBUTES threadAttributes, BOOL inheritHandles, DWORD creationFlags, LPVOID environment,
char* currentDirectory, LPSTARTUPINFO startupInfo, LPPROCESS_INFORMATION processInformation);
// Load a library in a matter compliant with non-ascii path
// returns the eventual error code
static HINSTANCE utf16CompliantShellExecute(HWND hwnd, LPCTSTR operation, LPCTSTR file, LPCTSTR parameters, LPCTSTR directory, INT nShowCmd);
private:
WindowsUtilities() = delete;
};
} // namespace System
#endif // TARGET_OS_Windows
@@ -0,0 +1,25 @@
#pragma once
#include <ov_common_defines.h>
#if defined System_Shared
# if defined TARGET_OS_Windows
# define System_API_Export __declspec(dllexport)
# define System_API_Import __declspec(dllimport)
# elif defined TARGET_OS_Linux || defined TARGET_OS_MacOS
# define System_API_Export __attribute__((visibility("default")))
# define System_API_Import __attribute__((visibility("default")))
# else
# define System_API_Export
# define System_API_Import
# endif
#else
# define System_API_Export
# define System_API_Import
#endif
#if defined System_Exports
# define System_API System_API_Export
#else
# define System_API System_API_Import
#endif
@@ -0,0 +1,40 @@
#pragma once
#include "defines.h"
#include <cstdlib> // fix Unix compatibility
namespace System {
class System_API CChrono final
{
public:
CChrono() { }
~CChrono();
bool reset(size_t nStep);
bool stepIn();
bool stepOut();
uint64_t getTotalStepInDuration() const;
uint64_t getTotalStepOutDuration() const;
uint64_t getAverageStepInDuration() const;
uint64_t getAverageStepOutDuration() const;
double getStepInPercentage() const;
double getStepOutPercentage() const;
bool hasNewEstimation() const { return m_hasNewEstimation; }
private:
uint64_t* m_stepInTime = nullptr;
uint64_t* m_stepOutTime = nullptr;
size_t m_nStep = 0;
size_t m_stepIdx = 0;
bool m_isInStep = false;
bool m_hasNewEstimation = false;
uint64_t m_totalStepInTime = 0;
uint64_t m_totalStepOutTime = 0;
};
} // namespace System
@@ -0,0 +1,264 @@
#pragma once
#include "defines.h"
#if defined TARGET_OS_Windows
#include <shlobj.h>
#include <Dbghelp.h>
#elif defined TARGET_OS_Linux
#include <linux/limits.h>
#elif defined TARGET_OS_MacOS
#include <sys/syslimits.h>
#endif
#include <string>
namespace System {
class CDynamicModuleSymbolLoader; // forward declare to make function declaration possible
class System_API CDynamicModule final
{
public:
enum ELogErrorCodes : size_t
{
LogErrorCodes_NoError = 0,
LogErrorCodes_ModuleAlreadyLoaded = 1,
LogErrorCodes_NoModuleLoaded = 2,
LogErrorCodes_FilenameEmpty = 3,
LogErrorCodes_FolderPathInvalid = 4,
LogErrorCodes_RegistryQueryFailed = 5,
LogErrorCodes_UnloadModuleFailed = 6,
LogErrorCodes_FailToLoadModule = 7,
LogErrorCodes_InvalidSymbol = 8,
LogErrorCodes_EnvironmentVariableInvalid = 9,
LogErrorCodes_ModuleNotFound = 10
};
CDynamicModule();
~CDynamicModule();
/**
* \brief Load module from a path.
*
* \param modulePath
* \param symbolNameCheck Symbol to check if it is present in the module. It is optionnal and is nullptr by default.
*
* \retval true If the module loaded successfully.
* \retval false If module loading failed.
*/
bool loadFromPath(const char* modulePath, const char* symbolNameCheck = nullptr);
#if defined TARGET_OS_Windows
/**
* \brief Load existing module that was already loaded by the process.
*
* \param modulePath The path to the module.
* \param symbolNameCheck Symbol to check if it is present in the module. It is optionnal and is nullptr by default.
*
* \retval true If the module loaded successfully.
* \retval false If module loading failed.
*/
bool loadFromExisting(const char* modulePath, const char* symbolNameCheck = nullptr);
/**
* \brief Load module from known path. Windows only.
*
* \param standardPath A CSIDL value that identifies the folder whose path is to be retrieved.
* Only real folders are valid. If a virtual folder is specified, this function fails.
* You can force creation of a folder by combining the folder's CSIDL with CSIDL_FLAG_CREATE.
* \param modulePath Path of the module to load.
* \param symbolNameCheck Symbol to check if it is present in the module. It is optional and is nullptr by default.
*
* \retval true If the module loaded successfully.
* \retval false If module loading failed.
*/
bool loadFromKnownPath(int standardPath, const char* modulePath, const char* symbolNameCheck = nullptr);
/**
* \brief Load module from Windows environment. Windows only.
*
* \param environmentPath Environment path.
* \param modulePath Module file path.
* \param symbolNameCheck Symbol to check if it is present in the module. It is optionnal and is nullptr by default.
*
* \retval true If the module loaded successfully.
* \retval false If module loading failed.
*/
bool loadFromEnvironment(const char* environmentPath, const char* modulePath, const char* symbolNameCheck = nullptr);
/**
* \brief Load module from the registry. Windows only.
*
* \param key Registry key. Check https://msdn.microsoft.com/en-us/library/windows/desktop/ms724836
* \param registryPath Registry path.
* \param registryKeyName Key name.
* \param samDesired A mask that specifies the desired access rights to the key to be opened.
* The function fails if the security descriptor of the key does not permit the requested access for the calling process
* Check https://msdn.microsoft.com/fr-fr/library/windows/desktop/ms724878
* \param modulePath sModulePath Module path.
* \param symbolNameCheck Symbol to check if it is present in the module. It is optionnal and is nullptr by default.
*
* \retval true If the module loaded successfully.
* \retval false If module loading failed.
*/
bool loadFromRegistry(HKEY key, const char* registryPath, const char* registryKeyName, REGSAM samDesired, const char* modulePath,
const char* symbolNameCheck = nullptr);
/**
* \brief Check the module architecture. Windows only.
* The architecture type of the computer. An image file can only be run on the specified computer or a system that emulates the specified computer.
* This member can be one of the following values.
* - x86: 0x014c
* - x64: 0x8664
* - ia64: 0x0200
*
* \param filePath Module file path
* \param architecture Architecture code
*
* \retval true If the module architecture is equal to the architecture parameter.
* \retval false If the module is unequal to the architecture parameter.
*/
static bool isModuleCompatible(const char* filePath, int architecture);
#endif
// --------------------------------------
/**
* \brief Unload the module. If setShouldFreeModule(false) is called, the unload() has no effect.
*
* \retval true In case of success.
* \retval false In case of failure.
*
* \sa setShouldFreeModule
* \sa isLoaded
*/
bool unload();
/**
* \brief Check if the module is loaded.
*
* \retval true If the module is loaded.
* \retval false If no module are loaded.
*
* \sa unload
* \sa setShouldFreeModule
*/
bool isLoaded() const { return m_Handle != nullptr; }
/**
* \brief Get the filename of the module.
*
* \return the file name of the module.
*/
const char* getFilename() const { return m_Filename; }
/**
* \brief Should be used to avoid the warning "Missing dll" when loading acquisition server
* This can happen when the loaded library needs a second library that is not detected.
*
* \param errorMode
*/
void setDynamicModuleErrorMode(const size_t errorMode) { m_ErrorMode = errorMode; }
/**
* \brief Set if the module should, or not, be free. By default the module will be free.
*
* \param shouldFreeModule Set to true to free the module when unload is called. False otherwise.
*
* \sa unload
*/
void setShouldFreeModule(const bool shouldFreeModule) { m_ShouldFreeModule = shouldFreeModule; }
/**
* \brief Get the last error code.
*
* \return The error code.
*/
size_t getLastError() const;
/**
* \brief Get the error message corresponding to the error code.
*
* \param errorCode The error code.
*
* \return the message corresponding to the error code.
*/
static const char* getErrorString(size_t errorCode);
/**
* \brief Get the detailed error
*
* \return A string with detailed information about the last error.
*/
const char* getErrorDetails() const;
private:
void* m_Handle = nullptr;
#if defined TARGET_OS_Windows
char m_Filename[MAX_PATH];
#elif defined TARGET_OS_Linux || defined TARGET_OS_MacOS
char m_Filename[PATH_MAX];
#endif
size_t m_ErrorMode = 0;
bool m_ShouldFreeModule = true;
typedef void (*symbol_t)();
char m_ErrorDetails[1024];
mutable ELogErrorCodes m_ErrorCode;
static const size_t m_ErrorModeNull = 0xffffffff;
friend class CDynamicModuleSymbolLoader;
/**
* \brief Set the error code and details.
*
* \param errorCode Error code.
* \param details Detailed string error.
*/
void setError(ELogErrorCodes errorCode, const std::string& details = std::string());
/**
* \brief Get a symbol from the module.
*
* \param symbolName Symbol name.
*
* \return The symbol.
*/
symbol_t getSymbolGeneric(const char* symbolName) const;
#ifdef TARGET_OS_Windows
/**
* \brief Get the image file headers. Windows only.
*
* \param filename The file path.
* \param headers [out] The header.
*
* \retval true In case of success.
* \retval false In case of failure.
*/
static bool getImageFileHeaders(const char* filename, IMAGE_NT_HEADERS& headers);
#endif
};
class CDynamicModuleSymbolLoader
{
public:
/**
* \brief Get a symbol from the module.
*
* \param dynamicModule
* \param symbolName The symbol name.
* \param symbol [out] The symbol.
*
* \retval true If the symbol exists.
* \retval false If the symbol does not exist.
*/
template <typename T>
static bool getSymbol(CDynamicModule& dynamicModule, const char* symbolName, T* symbol)
{
*symbol = reinterpret_cast<T>(dynamicModule.getSymbolGeneric(symbolName));
return *symbol != nullptr;
}
};
} // namespace System
@@ -0,0 +1,24 @@
#pragma once
#include "defines.h"
#include <cmath>
#include <cstdlib> // fix Unix compatibility
namespace System {
class System_API Math
{
public:
static bool initializeRandomMachine(size_t randomSeed);
static size_t randomI();
// returns a value in [0,upperLimit( -- i.e. upperLimit not included in range
static size_t randomWithCeiling(const size_t upperLimit);
static double random0To1();
static uint64_t random();
private:
Math() = delete;
};
} // namespace System
@@ -0,0 +1,52 @@
#pragma once
#include "defines.h"
#include <cstdlib> // fix Unix compatibility
namespace System {
class System_API Memory
{
public:
static bool hostToLittleEndian(uint16_t value, uint8_t* buffer);
static bool hostToLittleEndian(uint32_t value, uint8_t* buffer);
static bool hostToLittleEndian(uint64_t value, uint8_t* buffer);
static bool hostToLittleEndian(int16_t value, uint8_t* buffer);
static bool hostToLittleEndian(int value, uint8_t* buffer);
static bool hostToLittleEndian(int64_t value, uint8_t* buffer);
static bool hostToLittleEndian(float value, uint8_t* buffer);
static bool hostToLittleEndian(double value, uint8_t* buffer);
static bool hostToLittleEndian(long double value, uint8_t* buffer);
static bool hostToBigEndian(uint16_t value, uint8_t* buffer);
static bool hostToBigEndian(uint32_t value, uint8_t* buffer);
static bool hostToBigEndian(uint64_t value, uint8_t* buffer);
static bool hostToBigEndian(int16_t value, uint8_t* buffer);
static bool hostToBigEndian(int value, uint8_t* buffer);
static bool hostToBigEndian(int64_t value, uint8_t* buffer);
static bool hostToBigEndian(float value, uint8_t* buffer);
static bool hostToBigEndian(double value, uint8_t* buffer);
static bool hostToBigEndian(long double value, uint8_t* buffer);
static bool littleEndianToHost(const uint8_t* buffer, uint16_t* value);
static bool littleEndianToHost(const uint8_t* buffer, uint32_t* value);
static bool littleEndianToHost(const uint8_t* buffer, uint64_t* value);
static bool littleEndianToHost(const uint8_t* buffer, int16_t* value);
static bool littleEndianToHost(const uint8_t* buffer, int* value);
static bool littleEndianToHost(const uint8_t* buffer, int64_t* value);
static bool littleEndianToHost(const uint8_t* buffer, float* value);
static bool littleEndianToHost(const uint8_t* buffer, double* value);
static bool littleEndianToHost(const uint8_t* buffer, long double* value);
static bool bigEndianToHost(const uint8_t* buffer, uint16_t* value);
static bool bigEndianToHost(const uint8_t* buffer, uint32_t* value);
static bool bigEndianToHost(const uint8_t* buffer, uint64_t* value);
static bool bigEndianToHost(const uint8_t* buffer, int16_t* value);
static bool bigEndianToHost(const uint8_t* buffer, int* value);
static bool bigEndianToHost(const uint8_t* buffer, int64_t* value);
static bool bigEndianToHost(const uint8_t* buffer, float* value);
static bool bigEndianToHost(const uint8_t* buffer, double* value);
static bool bigEndianToHost(const uint8_t* buffer, long double* value);
private:
Memory() = delete;
};
} // namespace System
@@ -0,0 +1,72 @@
#pragma once
#include "defines.h"
#include <cstdlib> // For Unix Compatibility
namespace System {
/**
* \class Time
* \brief Static functions to handle time within the framework
*
*/
class System_API Time
{
public:
/**
* \brief Make the calling thread sleep
* \param milliSeconds : sleep duration in ms
* \return Always true
*/
static bool sleep(const size_t milliSeconds);
/**
* \brief Make the calling thread sleep
* \param seconds : sleep duration in fixed point 32:32 seconds
* \return Always true
*/
static bool zsleep(const uint64_t seconds);
/**
* \brief Retrieve time in ms (turn the 32:32 fixed point seconds to milliseconds).
* \return Elapsed time in ms since the first call to this function or zgetTime functions
*/
static uint32_t getTime() { return uint32_t((zgetTime() * 1000) >> 32); }
/**
* \brief Retrieve time in fixed point 32:32 seconds
* \return Elapsed time since the first call to the zgetTime functions or getTime.
*/
static uint64_t zgetTime() { return zgetTimeRaw(true); }
/**
* \brief Retrieve time in fixed point 32:32 seconds
* \param sinceFirstCall: If sinceFirstCall is true, returns the time since the first call to the zgetTime function or getTime.
* Otherwise, returns time since epoch of the clock.
* \return Elapsed time
*/
static uint64_t zgetTimeRaw(bool sinceFirstCall = true);
/**
* \brief Check if the internal clock used by the framework is steady
* \return True if the clock is steady, false otherwise
* \note This is a theoretical check that queries the internal
* clock implementation for available services
*/
static bool isClockSteady();
/**
* \brief Check if the internal clock used by the framework has
* a resolution higher than the required one
* \param milliSeconds : Expected clock resolution (period between ticks) in ms (must be non-zero value)
* \return True if the clock meets the requirements, false otherwise
* \note This is a theoretical check that queries the internal
* clock implementation for available services
*/
static bool checkResolution(const size_t milliSeconds);
private:
Time() = delete;
};
} // namespace System
@@ -0,0 +1,41 @@
#include "system/WindowsUtilities.h"
#if defined TARGET_OS_Windows
#include "m_ConverterUtf8.h"
#include <ShellAPI.h>
#ifndef UNICODE
#define UNICODE
#endif
namespace System {
// Load a library in a matter compliant with non-ascii path
// returns the eventual error code
void* WindowsUtilities::utf16CompliantLoadLibrary(const char* path, const HANDLE file, const DWORD flags)
{
//const HMODULE hModule = ::LoadLibraryEx(path, file, flags); // LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR|LOAD_LIBRARY_DEFAULT_DIRS);
return ::LoadLibraryEx(path, file, flags); // LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR|LOAD_LIBRARY_DEFAULT_DIRS);
}
BOOL WindowsUtilities::utf16CompliantSetEnvironmentVariable(const char* name, const char* value) { return SetEnvironmentVariable(name, value); }
// Load a library in a matter compliant with non-ascii path
// returns the eventual error code
BOOL WindowsUtilities::utf16CompliantCreateProcess(char* applicationName, char* commandLine, LPSECURITY_ATTRIBUTES processAttributes,
LPSECURITY_ATTRIBUTES threadAttributes, const BOOL inheritHandles, const DWORD creationFlags,
LPVOID environment, char* currentDirectory, LPSTARTUPINFO startupInfo,
LPPROCESS_INFORMATION processInformation)
{
return CreateProcess(applicationName, const_cast<char*>(commandLine), processAttributes, threadAttributes,
inheritHandles, creationFlags, environment, currentDirectory, startupInfo, processInformation);
}
// Load a library in a matter compliant with non-ascii path
// returns the eventual error code
HINSTANCE WindowsUtilities::utf16CompliantShellExecute(HWND hwnd, LPCTSTR operation, LPCTSTR file, LPCTSTR parameters, LPCTSTR directory, const INT nShowCmd)
{
return ShellExecute(hwnd, operation, file, parameters, directory, nShowCmd);
}
} // namespace System
#endif // TARGET_OS_Windows
@@ -0,0 +1,101 @@
#include "system/ovCChrono.h"
#include "system/ovCTime.h"
namespace System {
CChrono::~CChrono()
{
delete [] m_stepInTime;
delete [] m_stepOutTime;
}
bool CChrono::reset(const size_t nStep)
{
if (!nStep) { return false; }
uint64_t* stepInTime = new uint64_t[nStep + 1];
uint64_t* stepOutTime = new uint64_t[nStep + 1];
if (!stepInTime || !stepOutTime)
{
delete [] stepInTime;
delete [] stepOutTime;
return false;
}
for (size_t i = 0; i <= nStep; ++i)
{
stepInTime[i] = 0;
stepOutTime[i] = 0;
}
delete [] m_stepInTime;
delete [] m_stepOutTime;
m_stepInTime = stepInTime;
m_stepOutTime = stepOutTime;
m_nStep = nStep;
m_stepIdx = 0;
m_isInStep = false;
m_hasNewEstimation = false;
m_totalStepInTime = 0;
m_totalStepOutTime = 0;
return true;
}
bool CChrono::stepIn()
{
if (m_isInStep || !m_nStep) { return false; }
m_isInStep = !m_isInStep;
m_stepInTime[m_stepIdx] = Time::zgetTime();
if (m_stepIdx == m_nStep)
{
m_totalStepInTime = 0;
m_totalStepOutTime = 0;
for (size_t i = 0; i < m_nStep; ++i)
{
m_totalStepInTime += m_stepOutTime[i] - m_stepInTime[i];
m_totalStepOutTime += m_stepInTime[i + 1] - m_stepOutTime[i];
}
m_stepInTime[0] = m_stepInTime[m_nStep];
m_stepIdx = 0;
m_hasNewEstimation = true;
}
else { m_hasNewEstimation = false; }
return true;
}
bool CChrono::stepOut()
{
if (!m_isInStep || !m_nStep) { return false; }
m_isInStep = !m_isInStep;
m_stepOutTime[m_stepIdx] = Time::zgetTime();
m_stepIdx++;
return true;
}
uint64_t CChrono::getTotalStepInDuration() const { return m_totalStepInTime; }
uint64_t CChrono::getTotalStepOutDuration() const { return m_totalStepOutTime; }
uint64_t CChrono::getAverageStepInDuration() const { return m_nStep ? this->getTotalStepInDuration() / m_nStep : 0; }
uint64_t CChrono::getAverageStepOutDuration() const { return m_nStep ? this->getTotalStepOutDuration() / m_nStep : 0; }
double CChrono::getStepInPercentage() const
{
const uint64_t totalStepDuration = (this->getTotalStepInDuration() + this->getTotalStepOutDuration());
return totalStepDuration ? (this->getTotalStepInDuration() * 100.0) / totalStepDuration : 0;
}
double CChrono::getStepOutPercentage() const
{
const uint64_t totalStepDuration = (this->getTotalStepOutDuration() + this->getTotalStepInDuration());
return totalStepDuration ? (this->getTotalStepOutDuration() * 100.0) / totalStepDuration : 0;
}
} // namespace System
@@ -0,0 +1,396 @@
#include "system/ovCDynamicModule.h"
#if defined TARGET_OS_Windows
#include <system/WindowsUtilities.h> // Allowed to use utf8_to_utf16 function for os that use utf16
#elif defined TARGET_OS_Linux || defined TARGET_OS_MacOS
#include <dlfcn.h>
#endif
#include <map>
#include <vector>
#include <cstring>
namespace System {
static const std::map<CDynamicModule::ELogErrorCodes, std::string> ERROR_MAP =
{
{ CDynamicModule::LogErrorCodes_ModuleAlreadyLoaded, "A module is already loaded." },
{ CDynamicModule::LogErrorCodes_NoModuleLoaded, "No module loaded." },
{ CDynamicModule::LogErrorCodes_FilenameEmpty, "The filename is empty." },
{ CDynamicModule::LogErrorCodes_FolderPathInvalid, "The folder path is invalid." },
{ CDynamicModule::LogErrorCodes_RegistryQueryFailed, "The registry query is invalid." },
{ CDynamicModule::LogErrorCodes_UnloadModuleFailed, "Fail to unload the module." },
{ CDynamicModule::LogErrorCodes_FailToLoadModule, "Fail to load the module." },
{ CDynamicModule::LogErrorCodes_InvalidSymbol, "The symbol is invalid." },
{ CDynamicModule::LogErrorCodes_ModuleNotFound, "Module not found." }
};
#if defined TARGET_OS_Windows
static std::vector<std::string> split(char* str, const char* delim)
{
char* token = strtok(str, delim);
std::vector<std::string> result;
while (token != nullptr)
{
result.push_back(token);
token = strtok(nullptr, delim);
}
return result;
}
static std::string formatWindowsError(const DWORD code)
{
LPTSTR text;
FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | // use system message tables to retrieve error text
FORMAT_MESSAGE_ALLOCATE_BUFFER | // allocate buffer on local heap for error text
FORMAT_MESSAGE_IGNORE_INSERTS, // Important! will fail otherwise, since we're not (and CANNOT) pass insertion parameters
nullptr, // unused with FORMAT_MESSAGE_FROM_SYSTEM
code, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
LPTSTR(&text), // output
0, // minimum size for output buffer
nullptr
); // arguments - see note
return std::string(text);
}
#endif
const char* CDynamicModule::getErrorString(size_t errorCode)
{
if (ERROR_MAP.count(ELogErrorCodes(errorCode)) == 0) { return "Invalid error code"; }
return ERROR_MAP.at(ELogErrorCodes(errorCode)).c_str();
}
const char* CDynamicModule::getErrorDetails() const { return &m_ErrorDetails[0]; }
size_t CDynamicModule::getLastError() const { return m_ErrorCode; }
CDynamicModule::CDynamicModule()
: m_ErrorMode(m_ErrorModeNull), m_ErrorCode(LogErrorCodes_NoError)
{
strcpy(m_ErrorDetails, "");
strcpy(m_Filename, "");
}
CDynamicModule::~CDynamicModule() {}
// --------------------------------------
#if defined TARGET_OS_Windows
bool CDynamicModule::loadFromExisting(const char* modulePath, const char* symbolNameCheck)
{
if (m_Handle)
{
this->setError(LogErrorCodes_ModuleAlreadyLoaded, "Module [" + std::string(m_Filename) + "] is already loaded");
return false;
}
m_Handle = ::GetModuleHandle(modulePath);
if (m_Handle == nullptr)
{
this->setError(LogErrorCodes_FailToLoadModule, "Windows error: " + formatWindowsError(GetLastError()));
return false;
}
if (symbolNameCheck != nullptr)
{
if (GetProcAddress(HMODULE(m_Handle), symbolNameCheck) == nullptr)
{
this->unload();
this->setError(LogErrorCodes_InvalidSymbol, "Windows error: " + formatWindowsError(GetLastError()));
return false;
}
}
strcpy(m_Filename, modulePath);
return true;
}
#endif
bool CDynamicModule::loadFromPath(const char* modulePath, const char* symbolNameCheck)
{
if (m_Handle)
{
this->setError(LogErrorCodes_ModuleAlreadyLoaded, "Module [" + std::string(m_Filename) + "] is already loaded");
return false;
}
// Verify empty filename
if (modulePath == nullptr || (modulePath != nullptr && modulePath[0] == '\0'))
{
this->setError(LogErrorCodes_FilenameEmpty);
return false;
}
#if defined TARGET_OS_Windows
if (m_ErrorMode == m_ErrorModeNull)
{
const UINT mode = SetErrorMode(UINT(m_ErrorModeNull));
SetErrorMode(mode);
}
else { SetErrorMode(UINT(m_ErrorMode)); }
m_Handle = WindowsUtilities::utf16CompliantLoadLibrary(modulePath, nullptr, LOAD_WITH_ALTERED_SEARCH_PATH);
if (m_Handle == nullptr)
{
this->setError(LogErrorCodes_FailToLoadModule, "Fail to load [" + std::string(modulePath) + "]. Windows error:" + formatWindowsError(GetLastError()));
return false;
}
if (symbolNameCheck != nullptr)
{
if (GetProcAddress(HMODULE(m_Handle), symbolNameCheck) == nullptr)
{
this->unload();
this->setError(LogErrorCodes_InvalidSymbol,
"Symbol invalid: [" + std::string(symbolNameCheck) + "]. Windows error: " + formatWindowsError(GetLastError()));
return false;
}
}
#elif defined TARGET_OS_Linux || defined TARGET_OS_MacOS
m_Handle = ::dlopen(modulePath, RTLD_LAZY|RTLD_GLOBAL);
if (m_Handle == nullptr)
{
this->setError(LogErrorCodes_FailToLoadModule);
return false;
}
if(symbolNameCheck != nullptr)
{
if(::dlsym(m_Handle, symbolNameCheck) == nullptr)
{
char* error = ::dlerror();
if(error) { this->setError(LogErrorCodes_InvalidSymbol, "Error: " + std::string(error)); }
else { this->setError(LogErrorCodes_InvalidSymbol); }
::dlclose(m_Handle);
m_Handle = NULL;
return false;
}
}
#endif
strcpy(m_Filename, modulePath);
return true;
}
#if defined TARGET_OS_Windows
bool CDynamicModule::loadFromKnownPath(const int standardPath, const char* modulePath, const char* symbolNameCheck)
{
if (m_Handle)
{
this->setError(LogErrorCodes_ModuleAlreadyLoaded, "Module [" + std::string(m_Filename) + "] is already loaded");
return false;
}
char dllPath[MAX_PATH];
const HRESULT result = ::SHGetFolderPath(nullptr, standardPath, nullptr, SHGFP_TYPE_CURRENT, dllPath);
if (result != S_OK)
{
this->setError(LogErrorCodes_FolderPathInvalid, "Windows error code: " + std::to_string(result));
return false;
}
strcat(dllPath, "\\");
strcat(dllPath, modulePath);
return loadFromPath(dllPath, symbolNameCheck); // Error set in the loadFromPath function
}
bool CDynamicModule::loadFromEnvironment(const char* environmentPath, const char* modulePath, const char* symbolNameCheck)
{
if (m_Handle)
{
this->setError(LogErrorCodes_ModuleAlreadyLoaded, "Module [" + std::string(m_Filename) + "] is already loaded");
return false;
}
char* str = getenv(environmentPath);
if (str == nullptr)
{
this->setError(LogErrorCodes_EnvironmentVariableInvalid);
return false;
}
std::vector<std::string> paths = split(str, ";");
for (const std::string& path : paths) { if (loadFromPath((path + "\\" + modulePath).c_str(), symbolNameCheck)) { return true; } }
this->setError(LogErrorCodes_ModuleNotFound);
return false;
}
bool CDynamicModule::loadFromRegistry(HKEY key, const char* registryPath, const char* registryKeyName, REGSAM samDesired, const char* modulePath,
const char* symbolNameCheck)
{
char dllPath[MAX_PATH];
DWORD size = sizeof(dllPath);
dllPath[0] = '\0';
HKEY lKey = nullptr;
LONG result = RegOpenKeyEx(key, TEXT(registryPath), NULL, samDesired, &lKey);
if (result != ERROR_SUCCESS)
{
this->setError(LogErrorCodes_RegistryQueryFailed, "Fail to open registry key. Windows error code: " + std::to_string(result));
RegCloseKey(lKey);
return false;
}
result = ::RegQueryValueEx(lKey, registryKeyName, nullptr, nullptr, reinterpret_cast<unsigned char*>(dllPath), &size);
if (result == ERROR_SUCCESS)
{
strcat(dllPath, modulePath);
return loadFromPath(dllPath, symbolNameCheck); // Error set in the loadFromPath function
}
this->setError(LogErrorCodes_RegistryQueryFailed, "Fail to query registry value. Windows error code: " + std::to_string(result));
return false;
}
bool CDynamicModule::isModuleCompatible(const char* filePath, const int architecture)
{
IMAGE_NT_HEADERS headers;
if (!getImageFileHeaders(filePath, headers)) { return false; } // Error set in the getImageFileHeaders function
return headers.FileHeader.Machine == architecture;
}
#endif
// --------------------------------------
bool CDynamicModule::unload()
{
if (!m_Handle)
{
this->setError(LogErrorCodes_NoModuleLoaded);
return false;
}
// If the flag m_shouldFreeModule, set to true per default, is set to false,
// the module is not unloaded.
// This flag was first set for Enobio3G driver which dll freezes when unloaded
if (!m_ShouldFreeModule) { return true; }
#if defined TARGET_OS_Windows
if (::FreeModule(reinterpret_cast<HMODULE>(m_Handle)) == 0)
{
this->setError(LogErrorCodes_UnloadModuleFailed, "Windows error code: " + formatWindowsError(GetLastError()));
return false;
}
#elif defined TARGET_OS_Linux || defined TARGET_OS_MacOS
if(::dlclose(m_Handle) != 0)
{
char* error = ::dlerror();
if(error) { this->setError(LogErrorCodes_UnloadModuleFailed, "Error: " + std::string(error)); }
else { this->setError(LogErrorCodes_UnloadModuleFailed); }
return false;
}
#else
#endif
strcpy(m_Filename, "");
m_Handle = nullptr;
return true;
}
CDynamicModule::symbol_t CDynamicModule::getSymbolGeneric(const char* symbolName) const
{
symbol_t res = nullptr;
if (!m_Handle)
{
m_ErrorCode = LogErrorCodes_NoModuleLoaded;
return res;
}
if (m_Handle)
{
#if defined TARGET_OS_Windows
res = symbol_t(GetProcAddress(reinterpret_cast<HMODULE>(m_Handle), symbolName));
if (!res)
{
m_ErrorCode = LogErrorCodes_InvalidSymbol;
return res;
}
#elif defined TARGET_OS_Linux || defined TARGET_OS_MacOS
res = (CDynamicModule::symbol_t)::dlsym(m_Handle, symbolName);
if (!res)
{
m_ErrorCode = LogErrorCodes_InvalidSymbol;
return res;
}
#else
#endif
}
return res;
}
#ifdef TARGET_OS_Windows
bool CDynamicModule::getImageFileHeaders(const char* filename, IMAGE_NT_HEADERS& headers)
{
const HANDLE fileHandle = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr);
if (fileHandle == INVALID_HANDLE_VALUE) { return false; }
const HANDLE imageHandle = CreateFileMapping(fileHandle, nullptr, PAGE_READONLY, 0, 0, nullptr);
if (imageHandle == nullptr)
{
CloseHandle(fileHandle);
return false;
}
void* imagePtr = MapViewOfFile(imageHandle, FILE_MAP_READ, 0, 0, 0);
if (imagePtr == nullptr)
{
CloseHandle(imageHandle);
CloseHandle(fileHandle);
return false;
}
const PIMAGE_NT_HEADERS headersPtr = ImageNtHeader(imagePtr);
if (headersPtr == nullptr)
{
UnmapViewOfFile(imagePtr);
CloseHandle(imageHandle);
CloseHandle(fileHandle);
return false;
}
headers = *headersPtr;
UnmapViewOfFile(imagePtr);
CloseHandle(imageHandle);
CloseHandle(fileHandle);
return true;
}
#endif
void CDynamicModule::setError(const ELogErrorCodes errorCode, const std::string& details)
{
m_ErrorCode = errorCode;
strcpy(m_ErrorDetails, details.c_str());
}
} // namespace System
@@ -0,0 +1,69 @@
/**
*
* @fixme This class could benefit from a serious overhaul, e.g. using randomness from some established library or C11.
*
* - Here Linear Congruential Generator is re-implemented to avoid third-party dependencies messing the up the rand() state.
* This happened before when we used the global srand() / rand(). It made hard to make repeatable experiments on some
* platforms. The generated randomness from the introduced home-made class is not super but it should be sufficient for
* OpenViBE's present use-cases.
*
* Other notes
*
* - Due to generative process, values generated above L_RAND_MAX may not be dense (verify)
* - randomIWithCeiling() may not be dense either
*
*/
#include "system/ovCMath.h"
#include <cstdlib>
#include <cstring>
namespace System {
class RandomGenerator
{
size_t m_nextValue = 0;
public:
static const size_t L_RAND_MAX = 2147483647; // (2^32)/2-1 == 2147483647 (0x7FFFFFFF)
explicit RandomGenerator(const size_t seed = 1) : m_nextValue(seed) {}
int rand()
{
// Pretty much C99 convention and parameters for a Linear Congruential Generator
m_nextValue = (m_nextValue * 1103515245 + 12345) & L_RAND_MAX;
return int(m_nextValue);
}
void setSeed(const size_t seed) { m_nextValue = seed; }
size_t getSeed() const { return m_nextValue; }
};
// Should be only accessed via Math:: calls defined below
static RandomGenerator randomGenerator;
bool Math::initializeRandomMachine(const size_t randomSeed)
{
randomGenerator.setSeed(size_t(randomSeed));
// For safety, we install also the C++ basic random engine (it might be useg by dependencies, old code, etc)
srand(uint32_t(randomSeed));
return true;
}
size_t Math::randomI() { return size_t(random()); }
size_t Math::randomWithCeiling(const size_t upperLimit) { return size_t(random0To1() * double(upperLimit)); }
double Math::random0To1() { return double(randomGenerator.rand()) / double(RandomGenerator::L_RAND_MAX); }
uint64_t Math::random()
{
const uint64_t r1 = randomGenerator.rand();
const uint64_t r2 = randomGenerator.rand();
const uint64_t r3 = randomGenerator.rand();
const uint64_t r4 = randomGenerator.rand();
return (r1 << 24) ^ (r2 << 16) ^ (r3 << 8) ^ (r4);
}
} // namespace System
@@ -0,0 +1,169 @@
#include "system/ovCMemory.h"
#include <cstring>
namespace System {
// ________________________________________________________________________________________________________________
//
template <typename T>
bool BigEndianToHost(const uint8_t* buffer, T* value)
{
if (!buffer || !value) { return false; }
memset(value, 0, sizeof(T));
for (size_t i = 0; i < sizeof(T); ++i) { ((uint8_t*)value)[i] = buffer[sizeof(T) - 1 - i]; }
return true;
}
template <typename T>
bool LittleEndianToHost(const uint8_t* buffer, T* value)
{
if (!buffer || !value) { return false; }
memset(value, 0, sizeof(T));
for (size_t i = 0; i < sizeof(T); ++i) { ((uint8_t*)value)[i] = buffer[i]; }
return true;
}
template <typename T>
bool HostToBigEndian(const T& value, uint8_t* buffer)
{
if (!buffer) { return false; }
memset(buffer, 0, sizeof(T));
for (size_t i = 0; i < sizeof(T); ++i) { buffer[i] = ((uint8_t*)&value)[sizeof(T) - 1 - i]; }
return true;
}
template <typename T>
bool HostToLittleEndian(const T& value, uint8_t* buffer)
{
if (!buffer) { return false; }
for (size_t i = 0; i < sizeof(T); ++i) { buffer[i] = uint8_t((value >> (i * 8)) & 0xff); }
return true;
}
// ________________________________________________________________________________________________________________
//
bool Memory::hostToLittleEndian(const uint16_t value, uint8_t* buffer) { return HostToLittleEndian<uint16_t>(value, buffer); }
bool Memory::hostToLittleEndian(const uint32_t value, uint8_t* buffer) { return HostToLittleEndian<uint32_t>(value, buffer); }
bool Memory::hostToLittleEndian(const uint64_t value, uint8_t* buffer) { return HostToLittleEndian<uint64_t>(value, buffer); }
bool Memory::hostToLittleEndian(const int16_t value, uint8_t* buffer) { return HostToLittleEndian<int16_t>(value, buffer); }
bool Memory::hostToLittleEndian(const int value, uint8_t* buffer) { return HostToLittleEndian<int>(value, buffer); }
bool Memory::hostToLittleEndian(const int64_t value, uint8_t* buffer) { return HostToLittleEndian<int64_t>(value, buffer); }
bool Memory::hostToLittleEndian(const float value, uint8_t* buffer)
{
uint32_t tmp;
memcpy(&tmp, &value, sizeof(tmp));
return hostToLittleEndian(tmp, buffer);
}
bool Memory::hostToLittleEndian(const double value, uint8_t* buffer)
{
uint64_t tmp;
memcpy(&tmp, &value, sizeof(tmp));
return hostToLittleEndian(tmp, buffer);
}
bool Memory::hostToLittleEndian(const long double /*value*/, uint8_t* /*buffer*/)
{
// $$$ TODO
return false;
}
// ________________________________________________________________________________________________________________
//
bool Memory::hostToBigEndian(const uint16_t value, uint8_t* buffer) { return HostToBigEndian<uint16_t>(value, buffer); }
bool Memory::hostToBigEndian(const uint32_t value, uint8_t* buffer) { return HostToBigEndian<uint32_t>(value, buffer); }
bool Memory::hostToBigEndian(const uint64_t value, uint8_t* buffer) { return HostToBigEndian<uint64_t>(value, buffer); }
bool Memory::hostToBigEndian(const int16_t value, uint8_t* buffer) { return HostToBigEndian<int16_t>(value, buffer); }
bool Memory::hostToBigEndian(const int value, uint8_t* buffer) { return HostToBigEndian<int>(value, buffer); }
bool Memory::hostToBigEndian(const int64_t value, uint8_t* buffer) { return HostToBigEndian<int64_t>(value, buffer); }
bool Memory::hostToBigEndian(const float value, uint8_t* buffer)
{
uint32_t tmp;
memcpy(&tmp, &value, sizeof(tmp));
return hostToBigEndian(tmp, buffer);
}
bool Memory::hostToBigEndian(const double value, uint8_t* buffer)
{
uint64_t tmp;
memcpy(&tmp, &value, sizeof(tmp));
return hostToBigEndian(tmp, buffer);
}
bool Memory::hostToBigEndian(const long double /*value*/, uint8_t* /*buffer*/)
{
// $$$ TODO
return false;
}
// ________________________________________________________________________________________________________________
//
bool Memory::littleEndianToHost(const uint8_t* buffer, uint16_t* value) { return LittleEndianToHost<uint16_t>(buffer, value); }
bool Memory::littleEndianToHost(const uint8_t* buffer, uint32_t* value) { return LittleEndianToHost<uint32_t>(buffer, value); }
bool Memory::littleEndianToHost(const uint8_t* buffer, uint64_t* value) { return LittleEndianToHost<uint64_t>(buffer, value); }
bool Memory::littleEndianToHost(const uint8_t* buffer, int16_t* value) { return LittleEndianToHost<int16_t>(buffer, value); }
bool Memory::littleEndianToHost(const uint8_t* buffer, int* value) { return LittleEndianToHost<int>(buffer, value); }
bool Memory::littleEndianToHost(const uint8_t* buffer, int64_t* value) { return LittleEndianToHost<int64_t>(buffer, value); }
bool Memory::littleEndianToHost(const uint8_t* buffer, float* value)
{
uint32_t tmp;
const bool b = LittleEndianToHost<uint32_t>(buffer, &tmp);
memcpy(value, &tmp, sizeof(float));
return b;
}
bool Memory::littleEndianToHost(const uint8_t* buffer, double* value)
{
uint64_t tmp;
const bool b = LittleEndianToHost<uint64_t>(buffer, &tmp);
memcpy(value, &tmp, sizeof(double));
return b;
}
bool Memory::littleEndianToHost(const uint8_t* /*buffer*/, long double* /*value*/)
{
// $$$ TODO
return false;
}
// ________________________________________________________________________________________________________________
//
bool Memory::bigEndianToHost(const uint8_t* buffer, uint16_t* value) { return BigEndianToHost<uint16_t>(buffer, value); }
bool Memory::bigEndianToHost(const uint8_t* buffer, uint32_t* value) { return BigEndianToHost<uint32_t>(buffer, value); }
bool Memory::bigEndianToHost(const uint8_t* buffer, uint64_t* value) { return BigEndianToHost<uint64_t>(buffer, value); }
bool Memory::bigEndianToHost(const uint8_t* buffer, int16_t* value) { return BigEndianToHost<int16_t>(buffer, value); }
bool Memory::bigEndianToHost(const uint8_t* buffer, int* value) { return BigEndianToHost<int>(buffer, value); }
bool Memory::bigEndianToHost(const uint8_t* buffer, int64_t* value) { return BigEndianToHost<int64_t>(buffer, value); }
bool Memory::bigEndianToHost(const uint8_t* buffer, float* value)
{
uint32_t tmp;
const bool b = BigEndianToHost<uint32_t>(buffer, &tmp);
memcpy(value, &tmp, sizeof(float));
return b;
}
bool Memory::bigEndianToHost(const uint8_t* buffer, double* value)
{
uint64_t tmp;
const bool b = BigEndianToHost<uint64_t>(buffer, &tmp);
memcpy(value, &tmp, sizeof(double));
return b;
}
bool Memory::bigEndianToHost(const uint8_t* /*buffer*/, long double* /*value*/)
{
// $$$ TODO
return false;
}
} // namespace System
@@ -0,0 +1,92 @@
#include "system/ovCTime.h"
#include <cmath>
#include <cassert>
// \warning On Windows, avoid "using namespace System;" here as it may cause confusion with stuff coming from windows/boost
// \note Support of C++11 steady clock:
// - From GCC 4.8.1
// - From Visual Studio 2015 (therefore a strategy is needed to handle Visual Studio 2013 version)
// time handling strategy selection
// \note With officialy supported compilers and required boost version
// it should never fallback in a OV_USE_SYSTEM case
#if (defined(_MSC_VER) && _MSC_VER <= 1800 && defined(TARGET_HAS_Boost_Chrono))
#include <boost/chrono/config.hpp>
#ifdef BOOST_CHRONO_HAS_CLOCK_STEADY
#include <boost/chrono.hpp>
#include <boost/thread.hpp>
namespace Timelib = boost;
#else
#error "Please use OpenViBE recommended version of Boost"
#endif // BOOST_CHRONO_HAS_CLOCK_STEADY
#else // defined(_MSC_VER) && _MSC_VER <= 1800 && defined(TARGET_HAS_Boost_Chrono)
#include <chrono>
#include <thread>
namespace Timelib = std;
#endif // defined(_MSC_VER) && _MSC_VER <= 1800 && defined(TARGET_HAS_Boost_Chrono)
using internal_clock = Timelib::chrono::steady_clock;
// using internal_clock = chrono::high_resolution_clock;
namespace System {
bool Time::sleep(const size_t milliSeconds)
{
Timelib::this_thread::sleep_for(Timelib::chrono::milliseconds(milliSeconds));
return true;
}
bool Time::zsleep(const uint64_t seconds)
{
const uint32_t s = uint32_t(seconds >> 32);
// zero the seconds with 0xFFFFFFFF, multiply to get the rest as fixed point microsec, then grab them (now in the 32 msbs)
const uint64_t ms = ((seconds & 0xFFFFFFFFLL) * 1000000LL) >> 32;
const Timelib::chrono::microseconds duration = Timelib::chrono::seconds(s) + Timelib::chrono::microseconds(ms);
Timelib::this_thread::sleep_for(duration);
return true;
}
uint64_t Time::zgetTimeRaw(const bool sinceFirstCall)
{
static bool initialized = false;
static internal_clock::time_point start;
if (!initialized)
{
start = internal_clock::now();
initialized = true;
}
const internal_clock::time_point now = internal_clock::now();
const internal_clock::duration elapsed = (sinceFirstCall ? now - start : now.time_since_epoch());
const Timelib::chrono::microseconds elapsedMs = Timelib::chrono::duration_cast<Timelib::chrono::microseconds>(elapsed);
const uint64_t microsPerSecond = 1000ULL * 1000ULL;
const uint64_t seconds = uint64_t(elapsedMs.count() / microsPerSecond);
const uint64_t fraction = uint64_t(elapsedMs.count() % microsPerSecond);
// below in fraction part, scale [0,microsPerSecond-1] to 32bit integer range
const uint64_t res = (seconds << 32) + fraction * (0xFFFFFFFFLL / (microsPerSecond - 1));
return res;
}
bool Time::isClockSteady() { return internal_clock::is_steady; }
bool Time::checkResolution(const size_t milliSeconds)
{
assert(milliSeconds != 0);
const auto resolution = double(internal_clock::period::num) / internal_clock::period::den;
return (size_t(std::ceil(resolution * 1000)) <= milliSeconds);
}
} // namespace System