diff --git a/include/profiler/profiler.h b/include/profiler/profiler.h index 55e9b74..42c2887 100644 --- a/include/profiler/profiler.h +++ b/include/profiler/profiler.h @@ -20,7 +20,23 @@ along with this program.If not, see . #define EASY_PROFILER____H_______ #ifdef _WIN32 -#define __func__ __FUNCTION__ +# define __func__ __FUNCTION__ +# if defined(_MSC_VER) && _MSC_VER <= 1800 +// There is no support for C++11 thread_local keyword prior to Visual Studio 2015. Use __declspec(thread) instead. +# define EASY_THREAD_LOCAL __declspec(thread) +# endif +#elif defined(__GNUC__) +# if (__GNUC__ == 4 && __GNUC_MINOR__ < 8) || (__GNUC__ < 4) +// There is no support for C++11 thread_local keyword prior to gcc 4.8. Use __thread instead. +# define EASY_THREAD_LOCAL __thread +# endif +#endif + +// TODO: Check thread_local support for Clang! + +#ifndef EASY_THREAD_LOCAL +# define EASY_THREAD_LOCAL thread_local +# define EASY_THREAD_LOCAL_CPP11 #endif #if defined ( __clang__ ) @@ -80,9 +96,9 @@ Block will be automatically completed by destructor. \ingroup profiler */ #define EASY_BLOCK(name, ...)\ - static const ::profiler::StaticBlockDescriptor EASY_UNIQUE_DESC(__LINE__)(EASY_COMPILETIME_NAME(name), __FILE__, __LINE__,\ + static const ::profiler::block_id_t EASY_UNIQUE_DESC(__LINE__) = ::profiler::registerDescription(EASY_COMPILETIME_NAME(name), __FILE__, __LINE__,\ ::profiler::BLOCK_TYPE_BLOCK , ## __VA_ARGS__);\ - ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_BLOCK, EASY_UNIQUE_DESC(__LINE__).id(), EASY_RUNTIME_NAME(name));\ + ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_BLOCK, EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name));\ ::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable /** Macro of beginning of block with function name and custom color. @@ -105,9 +121,9 @@ Name of the block automatically created with function name. \ingroup profiler */ #define EASY_FUNCTION(...)\ - static const ::profiler::StaticBlockDescriptor EASY_UNIQUE_DESC(__LINE__)(__func__, __FILE__, __LINE__,\ + static const ::profiler::block_id_t EASY_UNIQUE_DESC(__LINE__) = ::profiler::registerDescription(__func__, __FILE__, __LINE__,\ ::profiler::BLOCK_TYPE_BLOCK , ## __VA_ARGS__);\ - ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_BLOCK, EASY_UNIQUE_DESC(__LINE__).id(), "");\ + ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_BLOCK, EASY_UNIQUE_DESC(__LINE__), "");\ ::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable /** Macro of completion of last nearest open block. @@ -145,9 +161,9 @@ will end previously opened EASY_BLOCK or EASY_FUNCTION. \ingroup profiler */ #define EASY_EVENT(name, ...)\ - static const ::profiler::StaticBlockDescriptor EASY_UNIQUE_DESC(__LINE__)(EASY_COMPILETIME_NAME(name), __FILE__, __LINE__,\ + static const ::profiler::block_id_t EASY_UNIQUE_DESC(__LINE__) = ::profiler::registerDescription(EASY_COMPILETIME_NAME(name), __FILE__, __LINE__,\ ::profiler::BLOCK_TYPE_EVENT , ## __VA_ARGS__);\ - ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_EVENT, EASY_UNIQUE_DESC(__LINE__).id(), EASY_RUNTIME_NAME(name));\ + ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(::profiler::BLOCK_TYPE_EVENT, EASY_UNIQUE_DESC(__LINE__), EASY_RUNTIME_NAME(name));\ ::profiler::beginBlock(EASY_UNIQUE_BLOCK(__LINE__)); // this is to avoid compiler warning about unused variable /** Macro enabling profiler @@ -166,10 +182,15 @@ If this thread has been already named then nothing changes. \ingroup profiler */ -#ifdef _WIN32 -#define EASY_THREAD(name) ::profiler::setThreadName(name, __FILE__, __func__, __LINE__); +#ifdef EASY_THREAD_LOCAL_CPP11 +#define EASY_THREAD(name)\ + EASY_THREAD_LOCAL static const char* EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = \ + ::profiler::setThreadName(name, __FILE__, __func__, __LINE__); #else -#define EASY_THREAD(name) thread_local static const ::profiler::ThreadNameSetter EASY_TOKEN_CONCATENATE(unique_profiler_thread_name_setter_, __LINE__)(name, __FILE__, __func__, __LINE__); +#define EASY_THREAD(name)\ + EASY_THREAD_LOCAL static const char* EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = nullptr;\ + if (EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) == nullptr)\ + EASY_TOKEN_CONCATENATE(unique_profiler_thread_name, __LINE__) = ::profiler::setThreadName(name, __FILE__, __func__, __LINE__); #endif /** Macro of naming main thread. @@ -211,20 +232,9 @@ class ThreadStorage; namespace profiler { class Block; - class StaticBlockDescriptor; - - extern "C"{ - void PROFILER_API beginBlock(Block& _block); - void PROFILER_API endBlock(); - void PROFILER_API setEnabled(bool isEnable); - uint32_t PROFILER_API dumpBlocksToFile(const char* filename); - void PROFILER_API setThreadName(const char* name, const char* filename, const char* _funcname, int line); - void PROFILER_API setContextSwitchLogFilename(const char* name); - PROFILER_API const char* getContextSwitchLogFilename(); - } - typedef uint64_t timestamp_t; - typedef uint32_t thread_id_t; + typedef uint64_t timestamp_t; + typedef uint32_t thread_id_t; typedef uint32_t block_id_t; enum BlockType : uint8_t @@ -237,6 +247,17 @@ namespace profiler { BLOCK_TYPES_NUMBER }; typedef BlockType block_type_t; + + extern "C" { + PROFILER_API block_id_t registerDescription(const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color = DefaultBlockColor); + PROFILER_API void beginBlock(Block& _block); + PROFILER_API void endBlock(); + PROFILER_API void setEnabled(bool isEnable); + PROFILER_API uint32_t dumpBlocksToFile(const char* filename); + PROFILER_API const char* setThreadName(const char* name, const char* filename, const char* _funcname, int line); + PROFILER_API void setContextSwitchLogFilename(const char* name); + PROFILER_API const char* getContextSwitchLogFilename(); + } #pragma pack(push,1) class PROFILER_API BaseBlockDescriptor @@ -322,28 +343,6 @@ namespace profiler { ////////////////////////////////////////////////////////////////////// - class PROFILER_API StaticBlockDescriptor final - { - block_id_t m_id; - - public: - - StaticBlockDescriptor(const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color = DefaultBlockColor); - inline block_id_t id() const { return m_id; } - }; - -#ifndef _WIN32 - struct PROFILER_API ThreadNameSetter final - { - ThreadNameSetter(const char* _name, const char* _filename, const char* _funcname, int _line) - { - setThreadName(_name, _filename, _funcname, _line); - } - }; -#endif - - ////////////////////////////////////////////////////////////////////// - } // END of namespace profiler. #if defined ( __clang__ ) diff --git a/src/event_trace_win.cpp b/src/event_trace_win.cpp index 2480434..804d4f3 100644 --- a/src/event_trace_win.cpp +++ b/src/event_trace_win.cpp @@ -48,9 +48,9 @@ namespace profiler { auto _contextSwitchEvent = reinterpret_cast(_traceEvent->UserData); const auto time = static_cast<::profiler::timestamp_t>(_traceEvent->EventHeader.TimeStamp.QuadPart); - static const ::profiler::StaticBlockDescriptor desc("OS.ContextSwitch", __FILE__, __LINE__, ::profiler::BLOCK_TYPE_CONTEXT_SWITCH, ::profiler::colors::White); - MANAGER._cswitchBeginBlock(time, desc.id(), _contextSwitchEvent->OldThreadId); - MANAGER._cswitchEndBlock(_contextSwitchEvent->NewThreadId, time); + static const auto desc = MANAGER.addBlockDescriptor("OS.ContextSwitch", __FILE__, __LINE__, ::profiler::BLOCK_TYPE_CONTEXT_SWITCH, ::profiler::colors::White); + MANAGER.beginContextSwitch(_contextSwitchEvent->OldThreadId, time, desc); + MANAGER.endContextSwitch(_contextSwitchEvent->NewThreadId, time); } ////////////////////////////////////////////////////////////////////////// diff --git a/src/profile_manager.cpp b/src/profile_manager.cpp index 4dc6bb5..9b482c0 100644 --- a/src/profile_manager.cpp +++ b/src/profile_manager.cpp @@ -10,16 +10,6 @@ ////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////// -#define EASY_INTERNAL_BLOCK(name, easyType, CODE) CODE -//#define EASY_INTERNAL_BLOCK(name, easyType, CODE)\ -// static const profiler::StaticBlockDescriptor EASY_UNIQUE_DESC(__LINE__)(name, __FILE__, __LINE__, easyType, profiler::colors::White);\ -// ::profiler::Block EASY_UNIQUE_BLOCK(__LINE__)(easyType, EASY_UNIQUE_DESC(__LINE__).id(), "");\ -// CODE\ -// EASY_UNIQUE_BLOCK(__LINE__).finish();\ -// thread_storage.storeBlock(EASY_UNIQUE_BLOCK(__LINE__)) - -////////////////////////////////////////////////////////////////////////// - using namespace profiler; #ifdef _WIN32 @@ -29,14 +19,19 @@ extern decltype(LARGE_INTEGER::QuadPart) CPU_FREQUENCY; //auto& MANAGER = ProfileManager::instance(); #define MANAGER ProfileManager::instance() -extern "C"{ +extern "C" { - void PROFILER_API endBlock() + PROFILER_API block_id_t registerDescription(const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color) + { + return MANAGER.addBlockDescriptor(_name, _filename, _line, _block_type, _color); + } + + PROFILER_API void endBlock() { MANAGER.endBlock(); } - void PROFILER_API setEnabled(bool isEnable) + PROFILER_API void setEnabled(bool isEnable) { MANAGER.setEnabled(isEnable); #ifdef _WIN32 @@ -47,22 +42,22 @@ extern "C"{ #endif } - void PROFILER_API beginBlock(Block& _block) + PROFILER_API void beginBlock(Block& _block) { MANAGER.beginBlock(_block); } - uint32_t PROFILER_API dumpBlocksToFile(const char* filename) + PROFILER_API uint32_t dumpBlocksToFile(const char* filename) { return MANAGER.dumpBlocksToFile(filename); } - void PROFILER_API setThreadName(const char* name, const char* filename, const char* _funcname, int line) + PROFILER_API const char* setThreadName(const char* name, const char* filename, const char* _funcname, int line) { return MANAGER.setThreadName(name, filename, _funcname, line); } - void PROFILER_API setContextSwitchLogFilename(const char* name) + PROFILER_API void setContextSwitchLogFilename(const char* name) { return MANAGER.setContextSwitchLogFilename(name); } @@ -84,12 +79,6 @@ SerializedBlock::SerializedBlock(const Block& block, uint16_t name_length) ////////////////////////////////////////////////////////////////////////// -StaticBlockDescriptor::StaticBlockDescriptor(const char* _name, const char* _filename, int _line, block_type_t _block_type, color_t _color) - : m_id(MANAGER.addBlockDescriptor(_name, _filename, _line, _block_type, _color)) -{ - -} - BaseBlockDescriptor::BaseBlockDescriptor(int _line, block_type_t _block_type, color_t _color) : m_line(_line) , m_type(_block_type) @@ -136,6 +125,8 @@ void ThreadStorage::clearClosed() ////////////////////////////////////////////////////////////////////////// +EASY_THREAD_LOCAL static ::ThreadStorage* THREAD_STORAGE = nullptr; + // #ifdef _WIN32 // LPTOP_LEVEL_EXCEPTION_FILTER PREVIOUS_FILTER = NULL; // LONG WINAPI easyTopLevelExceptionFilter(struct _EXCEPTION_POINTERS* ExceptionInfo) @@ -175,32 +166,30 @@ void ProfileManager::beginBlock(Block& _block) if (!m_isEnabled) return; - EASY_INTERNAL_BLOCK("Easy.Spin", profiler::BLOCK_TYPE_BLOCK,\ - auto& thread_storage = threadStorage(getCurrentThreadId());\ - ); + if (THREAD_STORAGE == nullptr) + THREAD_STORAGE = &threadStorage(getCurrentThreadId()); - EASY_INTERNAL_BLOCK("Easy.Insert", profiler::BLOCK_TYPE_BLOCK,\ - if (!_block.isFinished()) - thread_storage.blocks.openedList.emplace(_block); - else - thread_storage.storeBlock(_block);\ - ); + if (!_block.isFinished()) + THREAD_STORAGE->blocks.openedList.emplace(_block); + else + THREAD_STORAGE->storeBlock(_block); } -void ProfileManager::_cswitchBeginBlock(profiler::timestamp_t _time, profiler::block_id_t _id, profiler::thread_id_t _thread_id) +void ProfileManager::beginContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::block_id_t _id) { - auto thread_storage = _threadStorage(_thread_id); - if (thread_storage != nullptr) - thread_storage->sync.openedList.emplace(_time, profiler::BLOCK_TYPE_CONTEXT_SWITCH, _id, ""); + auto ts = findThreadStorage(_thread_id); + if (ts != nullptr) + ts->sync.openedList.emplace(_time, profiler::BLOCK_TYPE_CONTEXT_SWITCH, _id, ""); } -void ProfileManager::_cswitchStoreBlock(profiler::timestamp_t _time, profiler::block_id_t _id, profiler::thread_id_t _thread_id) +void ProfileManager::storeContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::block_id_t _id) { - auto thread_storage = _threadStorage(_thread_id); - if (thread_storage != nullptr){ + auto ts = findThreadStorage(_thread_id); + if (ts != nullptr) + { profiler::Block lastBlock(_time, profiler::BLOCK_TYPE_CONTEXT_SWITCH, _id, ""); lastBlock.finish(_time); - thread_storage->storeCSwitch(lastBlock); + ts->storeCSwitch(lastBlock); } } @@ -209,29 +198,28 @@ void ProfileManager::endBlock() if (!m_isEnabled) return; - auto& thread_storage = threadStorage(getCurrentThreadId()); - if (thread_storage.blocks.openedList.empty()) + if (THREAD_STORAGE->blocks.openedList.empty()) return; - Block& lastBlock = thread_storage.blocks.openedList.top(); + Block& lastBlock = THREAD_STORAGE->blocks.openedList.top(); if (!lastBlock.isFinished()) lastBlock.finish(); - thread_storage.storeBlock(lastBlock); - thread_storage.blocks.openedList.pop(); + THREAD_STORAGE->storeBlock(lastBlock); + THREAD_STORAGE->blocks.openedList.pop(); } -void ProfileManager::_cswitchEndBlock(profiler::thread_id_t _thread_id, profiler::timestamp_t _endtime) +void ProfileManager::endContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _endtime) { - auto thread_storage = _threadStorage(_thread_id); - if (thread_storage == nullptr || thread_storage->sync.openedList.empty()) + auto ts = findThreadStorage(_thread_id); + if (ts == nullptr || ts->sync.openedList.empty()) return; - Block& lastBlock = thread_storage->sync.openedList.top(); + Block& lastBlock = ts->sync.openedList.top(); lastBlock.finish(_endtime); - thread_storage->storeCSwitch(lastBlock); - thread_storage->sync.openedList.pop(); + ts->storeCSwitch(lastBlock); + ts->sync.openedList.pop(); } void ProfileManager::setEnabled(bool isEnable) @@ -283,11 +271,11 @@ uint32_t ProfileManager::dumpBlocksToFile(const char* filename) if(infile.is_open()) { - while (infile >> timestamp >> thread_from >> thread_to ) + static const auto desc = addBlockDescriptor("OS.ContextSwitch", __FILE__, __LINE__, ::profiler::BLOCK_TYPE_CONTEXT_SWITCH, ::profiler::colors::White); + while (infile >> timestamp >> thread_from >> thread_to) { - static const ::profiler::StaticBlockDescriptor desc("OS.ContextSwitch", __FILE__, __LINE__, ::profiler::BLOCK_TYPE_CONTEXT_SWITCH, ::profiler::colors::White); - _cswitchBeginBlock(timestamp, desc.id(), thread_from); - _cswitchEndBlock(thread_to, timestamp); + beginContextSwitch(thread_from, timestamp, desc); + endContextSwitch(thread_to, timestamp); } } @@ -385,15 +373,22 @@ uint32_t ProfileManager::dumpBlocksToFile(const char* filename) return blocks_number; } -void ProfileManager::setThreadName(const char* name, const char* filename, const char* _funcname, int line) +const char* ProfileManager::setThreadName(const char* name, const char* filename, const char* _funcname, int line) { - auto& thread_storage = threadStorage(getCurrentThreadId()); - if (thread_storage.named) - return; + if (THREAD_STORAGE == nullptr) + { + THREAD_STORAGE = &threadStorage(getCurrentThreadId()); + } - const auto id = addBlockDescriptor(_funcname, filename, line, profiler::BLOCK_TYPE_THREAD_SIGN, profiler::colors::Random); - thread_storage.storeBlock(profiler::Block(profiler::BLOCK_TYPE_THREAD_SIGN, id, name)); - thread_storage.named = true; + if (!THREAD_STORAGE->named) + { + const auto id = addBlockDescriptor(_funcname, filename, line, profiler::BLOCK_TYPE_THREAD_SIGN, profiler::colors::Random); + THREAD_STORAGE->storeBlock(profiler::Block(profiler::BLOCK_TYPE_THREAD_SIGN, id, name)); + THREAD_STORAGE->name = name; + THREAD_STORAGE->named = true; + } + + return THREAD_STORAGE->name.c_str(); } ////////////////////////////////////////////////////////////////////////// diff --git a/src/profile_manager.h b/src/profile_manager.h index 7244e43..2408471 100644 --- a/src/profile_manager.h +++ b/src/profile_manager.h @@ -26,8 +26,8 @@ along with this program.If not, see . #include #include #include -#include #include +#include #include ////////////////////////////////////////////////////////////////////////// @@ -44,10 +44,10 @@ along with this program.If not, see . inline uint32_t getCurrentThreadId() { #ifdef _WIN32 - return (uint32_t)::GetCurrentThreadId(); + return (uint32_t)::GetCurrentThreadId(); #else - thread_local static pid_t x = syscall(__NR_gettid); - thread_local static uint32_t _id = (uint32_t)x;//std::hash()(std::this_thread::get_id()); + EASY_THREAD_LOCAL static const pid_t x = syscall(__NR_gettid); + EASY_THREAD_LOCAL static const uint32_t _id = (uint32_t)x;//std::hash()(std::this_thread::get_id()); return _id; #endif } @@ -150,6 +150,7 @@ public: BlocksList, SIZEOF_CSWITCH * (uint16_t)1024U> blocks; BlocksList sync; + std::string name; bool named = false; void storeBlock(const profiler::Block& _block); @@ -161,8 +162,6 @@ public: class ProfileManager final { - friend profiler::StaticBlockDescriptor; - ProfileManager(); ProfileManager(const ProfileManager& p) = delete; ProfileManager& operator=(const ProfileManager&) = delete; @@ -185,11 +184,20 @@ public: static ProfileManager& instance(); ~ProfileManager(); + template + uint32_t addBlockDescriptor(TArgs ... _args) + { + guard_lock_t lock(m_storedSpin); + const auto id = static_cast(m_descriptors.size()); + m_descriptors.emplace_back(m_usedMemorySize, _args...); + return id; + } + void beginBlock(profiler::Block& _block); void endBlock(); void setEnabled(bool isEnable); uint32_t dumpBlocksToFile(const char* filename); - void setThreadName(const char* name, const char* filename, const char* _funcname, int line); + const char* setThreadName(const char* name, const char* filename, const char* _funcname, int line); void setContextSwitchLogFilename(const char* name) { @@ -201,28 +209,19 @@ public: return m_csInfoFilename.c_str(); } - void _cswitchBeginBlock(profiler::timestamp_t _time, profiler::block_id_t _id, profiler::thread_id_t _thread_id); - void _cswitchStoreBlock(profiler::timestamp_t _time, profiler::block_id_t _id, profiler::thread_id_t _thread_id); - void _cswitchEndBlock(profiler::thread_id_t _thread_id, profiler::timestamp_t _endtime); + void beginContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::block_id_t _id); + void storeContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _time, profiler::block_id_t _id); + void endContextSwitch(profiler::thread_id_t _thread_id, profiler::timestamp_t _endtime); private: - template - uint32_t addBlockDescriptor(TArgs ... _args) - { - guard_lock_t lock(m_storedSpin); - const auto id = static_cast(m_descriptors.size()); - m_descriptors.emplace_back(m_usedMemorySize, _args...); - return id; - } - ThreadStorage& threadStorage(profiler::thread_id_t _thread_id) { guard_lock_t lock(m_spin); return m_threads[_thread_id]; } - ThreadStorage* _threadStorage(profiler::thread_id_t _thread_id) + ThreadStorage* findThreadStorage(profiler::thread_id_t _thread_id) { guard_lock_t lock(m_spin); auto it = m_threads.find(_thread_id); diff --git a/src/spin_lock.h b/src/spin_lock.h index 803ef51..21ab16c 100644 --- a/src/spin_lock.h +++ b/src/spin_lock.h @@ -16,53 +16,87 @@ You should have received a copy of the GNU General Public License along with this program.If not, see . **/ -#ifndef ________SPIN_LOCK__________H______ -#define ________SPIN_LOCK__________H______ +#ifndef EASY_PROFILER__SPIN_LOCK__________H______ +#define EASY_PROFILER__SPIN_LOCK__________H______ +#define EASY_USE_CRITICAL_SECTION // Use CRITICAL_SECTION instead of std::atomic_flag + +#if defined(_WIN32) && defined(EASY_USE_CRITICAL_SECTION) +#include +#else #include - -namespace profiler{ - - class spin_lock - { - std::atomic_flag m_lock; - public: - void lock() - { - while (m_lock.test_and_set(std::memory_order_acquire)){} - } - - void unlock() - { - m_lock.clear(std::memory_order_release); - } - - spin_lock(){ - m_lock.clear(); - } - }; - - template - class guard_lock - { - T& m_mutex; - bool m_isLocked = false; - public: - explicit guard_lock(T& m) :m_mutex(m){ - m_mutex.lock(); - m_isLocked = true; - } - ~guard_lock(){ - this->release(); - } - inline void release(){ - if (m_isLocked){ - m_mutex.unlock(); - m_isLocked = false; - } - - } - }; -} - #endif + +namespace profiler { + +#if defined(_WIN32) && defined(EASY_USE_CRITICAL_SECTION) + // std::atomic_flag on Windows works slower than critical section, so we will use it instead of std::atomic_flag... + // By the way, Windows critical sections are slower than std::atomic_flag on Unix. + class spin_lock final { CRITICAL_SECTION m_lock; public: + + void lock() { + EnterCriticalSection(&m_lock); + } + + void unlock() { + LeaveCriticalSection(&m_lock); + } + + spin_lock() { + InitializeCriticalSection(&m_lock); + } + + ~spin_lock() { + DeleteCriticalSection(&m_lock); + } + }; +#else + // std::atomic_flag on Unix works fine and very fast (almost instant!) + class spin_lock final { ::std::atomic_flag m_lock; public: + + void lock() { + while (m_lock.test_and_set(::std::memory_order_acquire)); + } + + void unlock() { + m_lock.clear(::std::memory_order_release); + } + + spin_lock() { + m_lock.clear(); + } + }; +#endif + + template + class guard_lock final + { + T& m_lock; + bool m_isLocked = false; + + public: + + explicit guard_lock(T& m) : m_lock(m) { + m_lock.lock(); + m_isLocked = true; + } + + ~guard_lock() { + unlock(); + } + + inline void unlock() { + if (m_isLocked) { + m_lock.unlock(); + m_isLocked = false; + } + } + }; + +} // END of namespace profiler. + +#ifdef EASY_USE_CRITICAL_SECTION +# undef EASY_USE_CRITICAL_SECTION +#endif + +#endif // EASY_PROFILER__SPIN_LOCK__________H______