mudgangster

Tiny, scriptable MUD client
Log | Files | Refs | README

TracyLock.hpp (16607B)


      1 #ifndef __TRACYLOCK_HPP__
      2 #define __TRACYLOCK_HPP__
      3 
      4 #include <atomic>
      5 #include <limits>
      6 
      7 #include "../common/TracySystem.hpp"
      8 #include "../common/TracyAlign.hpp"
      9 #include "TracyProfiler.hpp"
     10 
     11 namespace tracy
     12 {
     13 
     14 class LockableCtx
     15 {
     16 public:
     17     tracy_force_inline LockableCtx( const SourceLocationData* srcloc )
     18         : m_id( GetLockCounter().fetch_add( 1, std::memory_order_relaxed ) )
     19 #ifdef TRACY_ON_DEMAND
     20         , m_lockCount( 0 )
     21         , m_active( false )
     22 #endif
     23     {
     24         assert( m_id != std::numeric_limits<uint32_t>::max() );
     25 
     26         Magic magic;
     27         auto token = GetToken();
     28         auto& tail = token->get_tail_index();
     29         auto item = token->enqueue_begin( magic );
     30         MemWrite( &item->hdr.type, QueueType::LockAnnounce );
     31         MemWrite( &item->lockAnnounce.id, m_id );
     32         MemWrite( &item->lockAnnounce.time, Profiler::GetTime() );
     33         MemWrite( &item->lockAnnounce.lckloc, (uint64_t)srcloc );
     34         MemWrite( &item->lockAnnounce.type, LockType::Lockable );
     35 #ifdef TRACY_ON_DEMAND
     36         GetProfiler().DeferItem( *item );
     37 #endif
     38         tail.store( magic + 1, std::memory_order_release );
     39     }
     40 
     41     LockableCtx( const LockableCtx& ) = delete;
     42     LockableCtx& operator=( const LockableCtx& ) = delete;
     43 
     44     tracy_force_inline ~LockableCtx()
     45     {
     46         Magic magic;
     47         auto token = GetToken();
     48         auto& tail = token->get_tail_index();
     49         auto item = token->enqueue_begin( magic );
     50         MemWrite( &item->hdr.type, QueueType::LockTerminate );
     51         MemWrite( &item->lockTerminate.id, m_id );
     52         MemWrite( &item->lockTerminate.time, Profiler::GetTime() );
     53         MemWrite( &item->lockTerminate.type, LockType::Lockable );
     54 #ifdef TRACY_ON_DEMAND
     55         GetProfiler().DeferItem( *item );
     56 #endif
     57         tail.store( magic + 1, std::memory_order_release );
     58     }
     59 
     60     tracy_force_inline bool BeforeLock()
     61     {
     62 #ifdef TRACY_ON_DEMAND
     63         bool queue = false;
     64         const auto locks = m_lockCount.fetch_add( 1, std::memory_order_relaxed );
     65         const auto active = m_active.load( std::memory_order_relaxed );
     66         if( locks == 0 || active )
     67         {
     68             const bool connected = GetProfiler().IsConnected();
     69             if( active != connected ) m_active.store( connected, std::memory_order_relaxed );
     70             if( connected ) queue = true;
     71         }
     72         if( !queue ) return false;
     73 #endif
     74 
     75         auto item = Profiler::QueueSerial();
     76         MemWrite( &item->hdr.type, QueueType::LockWait );
     77         MemWrite( &item->lockWait.thread, GetThreadHandle() );
     78         MemWrite( &item->lockWait.id, m_id );
     79         MemWrite( &item->lockWait.time, Profiler::GetTime() );
     80         MemWrite( &item->lockWait.type, LockType::Lockable );
     81         Profiler::QueueSerialFinish();
     82         return true;
     83     }
     84 
     85     tracy_force_inline void AfterLock()
     86     {
     87         auto item = Profiler::QueueSerial();
     88         MemWrite( &item->hdr.type, QueueType::LockObtain );
     89         MemWrite( &item->lockObtain.thread, GetThreadHandle() );
     90         MemWrite( &item->lockObtain.id, m_id );
     91         MemWrite( &item->lockObtain.time, Profiler::GetTime() );
     92         Profiler::QueueSerialFinish();
     93     }
     94 
     95     tracy_force_inline void AfterUnlock()
     96     {
     97 #ifdef TRACY_ON_DEMAND
     98         m_lockCount.fetch_sub( 1, std::memory_order_relaxed );
     99         if( !m_active.load( std::memory_order_relaxed ) ) return;
    100         if( !GetProfiler().IsConnected() )
    101         {
    102             m_active.store( false, std::memory_order_relaxed );
    103             return;
    104         }
    105 #endif
    106 
    107         auto item = Profiler::QueueSerial();
    108         MemWrite( &item->hdr.type, QueueType::LockRelease );
    109         MemWrite( &item->lockRelease.thread, GetThreadHandle() );
    110         MemWrite( &item->lockRelease.id, m_id );
    111         MemWrite( &item->lockRelease.time, Profiler::GetTime() );
    112         Profiler::QueueSerialFinish();
    113     }
    114 
    115     tracy_force_inline void AfterTryLock( bool acquired )
    116     {
    117 #ifdef TRACY_ON_DEMAND
    118         if( !acquired ) return;
    119 
    120         bool queue = false;
    121         const auto locks = m_lockCount.fetch_add( 1, std::memory_order_relaxed );
    122         const auto active = m_active.load( std::memory_order_relaxed );
    123         if( locks == 0 || active )
    124         {
    125             const bool connected = GetProfiler().IsConnected();
    126             if( active != connected ) m_active.store( connected, std::memory_order_relaxed );
    127             if( connected ) queue = true;
    128         }
    129         if( !queue ) return;
    130 #endif
    131 
    132         if( acquired )
    133         {
    134             auto item = Profiler::QueueSerial();
    135             MemWrite( &item->hdr.type, QueueType::LockObtain );
    136             MemWrite( &item->lockObtain.thread, GetThreadHandle() );
    137             MemWrite( &item->lockObtain.id, m_id );
    138             MemWrite( &item->lockObtain.time, Profiler::GetTime() );
    139             Profiler::QueueSerialFinish();
    140         }
    141     }
    142 
    143     tracy_force_inline void Mark( const SourceLocationData* srcloc )
    144     {
    145 #ifdef TRACY_ON_DEMAND
    146         const auto active = m_active.load( std::memory_order_relaxed );
    147         if( !active ) return;
    148         const auto connected = GetProfiler().IsConnected();
    149         if( !connected )
    150         {
    151             if( active ) m_active.store( false, std::memory_order_relaxed );
    152             return;
    153         }
    154 #endif
    155 
    156         auto item = Profiler::QueueSerial();
    157         MemWrite( &item->hdr.type, QueueType::LockMark );
    158         MemWrite( &item->lockMark.thread, GetThreadHandle() );
    159         MemWrite( &item->lockMark.id, m_id );
    160         MemWrite( &item->lockMark.srcloc, (uint64_t)srcloc );
    161         Profiler::QueueSerialFinish();
    162     }
    163 
    164 private:
    165     uint32_t m_id;
    166 
    167 #ifdef TRACY_ON_DEMAND
    168     std::atomic<uint32_t> m_lockCount;
    169     std::atomic<bool> m_active;
    170 #endif
    171 };
    172 
    173 template<class T>
    174 class Lockable
    175 {
    176 public:
    177     tracy_force_inline Lockable( const SourceLocationData* srcloc )
    178         : m_ctx( srcloc )
    179     {
    180     }
    181 
    182     Lockable( const Lockable& ) = delete;
    183     Lockable& operator=( const Lockable& ) = delete;
    184 
    185     tracy_force_inline void lock()
    186     {
    187         const auto runAfter = m_ctx.BeforeLock();
    188         m_lockable.lock();
    189         if( runAfter ) m_ctx.AfterLock();
    190     }
    191 
    192     tracy_force_inline void unlock()
    193     {
    194         m_lockable.unlock();
    195         m_ctx.AfterUnlock();
    196     }
    197 
    198     tracy_force_inline bool try_lock()
    199     {
    200         const auto acquired = m_lockable.try_lock();
    201         m_ctx.AfterTryLock( acquired );
    202         return acquired;
    203     }
    204 
    205     tracy_force_inline void Mark( const SourceLocationData* srcloc )
    206     {
    207         m_ctx.Mark( srcloc );
    208     }
    209 
    210 private:
    211     T m_lockable;
    212     LockableCtx m_ctx;
    213 };
    214 
    215 
    216 class SharedLockableCtx
    217 {
    218 public:
    219     tracy_force_inline SharedLockableCtx( const SourceLocationData* srcloc )
    220         : m_id( GetLockCounter().fetch_add( 1, std::memory_order_relaxed ) )
    221 #ifdef TRACY_ON_DEMAND
    222         , m_lockCount( 0 )
    223         , m_active( false )
    224 #endif
    225     {
    226         assert( m_id != std::numeric_limits<uint32_t>::max() );
    227 
    228         Magic magic;
    229         auto token = GetToken();
    230         auto& tail = token->get_tail_index();
    231         auto item = token->enqueue_begin( magic );
    232         MemWrite( &item->hdr.type, QueueType::LockAnnounce );
    233         MemWrite( &item->lockAnnounce.id, m_id );
    234         MemWrite( &item->lockAnnounce.time, Profiler::GetTime() );
    235         MemWrite( &item->lockAnnounce.lckloc, (uint64_t)srcloc );
    236         MemWrite( &item->lockAnnounce.type, LockType::SharedLockable );
    237 
    238 #ifdef TRACY_ON_DEMAND
    239         GetProfiler().DeferItem( *item );
    240 #endif
    241 
    242         tail.store( magic + 1, std::memory_order_release );
    243     }
    244 
    245     SharedLockableCtx( const SharedLockableCtx& ) = delete;
    246     SharedLockableCtx& operator=( const SharedLockableCtx& ) = delete;
    247 
    248     tracy_force_inline ~SharedLockableCtx()
    249     {
    250         Magic magic;
    251         auto token = GetToken();
    252         auto& tail = token->get_tail_index();
    253         auto item = token->enqueue_begin( magic );
    254         MemWrite( &item->hdr.type, QueueType::LockTerminate );
    255         MemWrite( &item->lockTerminate.id, m_id );
    256         MemWrite( &item->lockTerminate.time, Profiler::GetTime() );
    257         MemWrite( &item->lockTerminate.type, LockType::SharedLockable );
    258 
    259 #ifdef TRACY_ON_DEMAND
    260         GetProfiler().DeferItem( *item );
    261 #endif
    262 
    263         tail.store( magic + 1, std::memory_order_release );
    264     }
    265 
    266     tracy_force_inline bool BeforeLock()
    267     {
    268 #ifdef TRACY_ON_DEMAND
    269         bool queue = false;
    270         const auto locks = m_lockCount.fetch_add( 1, std::memory_order_relaxed );
    271         const auto active = m_active.load( std::memory_order_relaxed );
    272         if( locks == 0 || active )
    273         {
    274             const bool connected = GetProfiler().IsConnected();
    275             if( active != connected ) m_active.store( connected, std::memory_order_relaxed );
    276             if( connected ) queue = true;
    277         }
    278         if( !queue ) return false;
    279 #endif
    280 
    281         auto item = Profiler::QueueSerial();
    282         MemWrite( &item->hdr.type, QueueType::LockWait );
    283         MemWrite( &item->lockWait.thread, GetThreadHandle() );
    284         MemWrite( &item->lockWait.id, m_id );
    285         MemWrite( &item->lockWait.time, Profiler::GetTime() );
    286         MemWrite( &item->lockWait.type, LockType::SharedLockable );
    287         Profiler::QueueSerialFinish();
    288         return true;
    289     }
    290 
    291     tracy_force_inline void AfterLock()
    292     {
    293         auto item = Profiler::QueueSerial();
    294         MemWrite( &item->hdr.type, QueueType::LockObtain );
    295         MemWrite( &item->lockObtain.thread, GetThreadHandle() );
    296         MemWrite( &item->lockObtain.id, m_id );
    297         MemWrite( &item->lockObtain.time, Profiler::GetTime() );
    298         Profiler::QueueSerialFinish();
    299     }
    300 
    301     tracy_force_inline void AfterUnlock()
    302     {
    303 #ifdef TRACY_ON_DEMAND
    304         m_lockCount.fetch_sub( 1, std::memory_order_relaxed );
    305         if( !m_active.load( std::memory_order_relaxed ) ) return;
    306         if( !GetProfiler().IsConnected() )
    307         {
    308             m_active.store( false, std::memory_order_relaxed );
    309             return;
    310         }
    311 #endif
    312 
    313         auto item = Profiler::QueueSerial();
    314         MemWrite( &item->hdr.type, QueueType::LockRelease );
    315         MemWrite( &item->lockRelease.thread, GetThreadHandle() );
    316         MemWrite( &item->lockRelease.id, m_id );
    317         MemWrite( &item->lockRelease.time, Profiler::GetTime() );
    318         Profiler::QueueSerialFinish();
    319     }
    320 
    321     tracy_force_inline void AfterTryLock( bool acquired )
    322     {
    323 #ifdef TRACY_ON_DEMAND
    324         if( !acquired ) return;
    325 
    326         bool queue = false;
    327         const auto locks = m_lockCount.fetch_add( 1, std::memory_order_relaxed );
    328         const auto active = m_active.load( std::memory_order_relaxed );
    329         if( locks == 0 || active )
    330         {
    331             const bool connected = GetProfiler().IsConnected();
    332             if( active != connected ) m_active.store( connected, std::memory_order_relaxed );
    333             if( connected ) queue = true;
    334         }
    335         if( !queue ) return;
    336 #endif
    337 
    338         if( acquired )
    339         {
    340             auto item = Profiler::QueueSerial();
    341             MemWrite( &item->hdr.type, QueueType::LockObtain );
    342             MemWrite( &item->lockObtain.thread, GetThreadHandle() );
    343             MemWrite( &item->lockObtain.id, m_id );
    344             MemWrite( &item->lockObtain.time, Profiler::GetTime() );
    345             Profiler::QueueSerialFinish();
    346         }
    347     }
    348 
    349     tracy_force_inline bool BeforeLockShared()
    350     {
    351 #ifdef TRACY_ON_DEMAND
    352         bool queue = false;
    353         const auto locks = m_lockCount.fetch_add( 1, std::memory_order_relaxed );
    354         const auto active = m_active.load( std::memory_order_relaxed );
    355         if( locks == 0 || active )
    356         {
    357             const bool connected = GetProfiler().IsConnected();
    358             if( active != connected ) m_active.store( connected, std::memory_order_relaxed );
    359             if( connected ) queue = true;
    360         }
    361         if( !queue ) return false;
    362 #endif
    363 
    364         auto item = Profiler::QueueSerial();
    365         MemWrite( &item->hdr.type, QueueType::LockSharedWait );
    366         MemWrite( &item->lockWait.thread, GetThreadHandle() );
    367         MemWrite( &item->lockWait.id, m_id );
    368         MemWrite( &item->lockWait.time, Profiler::GetTime() );
    369         MemWrite( &item->lockWait.type, LockType::SharedLockable );
    370         Profiler::QueueSerialFinish();
    371         return true;
    372     }
    373 
    374     tracy_force_inline void AfterLockShared()
    375     {
    376         auto item = Profiler::QueueSerial();
    377         MemWrite( &item->hdr.type, QueueType::LockSharedObtain );
    378         MemWrite( &item->lockObtain.thread, GetThreadHandle() );
    379         MemWrite( &item->lockObtain.id, m_id );
    380         MemWrite( &item->lockObtain.time, Profiler::GetTime() );
    381         Profiler::QueueSerialFinish();
    382     }
    383 
    384     tracy_force_inline void AfterUnlockShared()
    385     {
    386 #ifdef TRACY_ON_DEMAND
    387         m_lockCount.fetch_sub( 1, std::memory_order_relaxed );
    388         if( !m_active.load( std::memory_order_relaxed ) ) return;
    389         if( !GetProfiler().IsConnected() )
    390         {
    391             m_active.store( false, std::memory_order_relaxed );
    392             return;
    393         }
    394 #endif
    395 
    396         auto item = Profiler::QueueSerial();
    397         MemWrite( &item->hdr.type, QueueType::LockSharedRelease );
    398         MemWrite( &item->lockRelease.thread, GetThreadHandle() );
    399         MemWrite( &item->lockRelease.id, m_id );
    400         MemWrite( &item->lockRelease.time, Profiler::GetTime() );
    401         Profiler::QueueSerialFinish();
    402     }
    403 
    404     tracy_force_inline void AfterTryLockShared( bool acquired )
    405     {
    406 #ifdef TRACY_ON_DEMAND
    407         if( !acquired ) return;
    408 
    409         bool queue = false;
    410         const auto locks = m_lockCount.fetch_add( 1, std::memory_order_relaxed );
    411         const auto active = m_active.load( std::memory_order_relaxed );
    412         if( locks == 0 || active )
    413         {
    414             const bool connected = GetProfiler().IsConnected();
    415             if( active != connected ) m_active.store( connected, std::memory_order_relaxed );
    416             if( connected ) queue = true;
    417         }
    418         if( !queue ) return;
    419 #endif
    420 
    421         if( acquired )
    422         {
    423             auto item = Profiler::QueueSerial();
    424             MemWrite( &item->hdr.type, QueueType::LockSharedObtain );
    425             MemWrite( &item->lockObtain.thread, GetThreadHandle() );
    426             MemWrite( &item->lockObtain.id, m_id );
    427             MemWrite( &item->lockObtain.time, Profiler::GetTime() );
    428             Profiler::QueueSerialFinish();
    429         }
    430     }
    431 
    432     tracy_force_inline void Mark( const SourceLocationData* srcloc )
    433     {
    434 #ifdef TRACY_ON_DEMAND
    435         const auto active = m_active.load( std::memory_order_relaxed );
    436         if( !active ) return;
    437         const auto connected = GetProfiler().IsConnected();
    438         if( !connected )
    439         {
    440             if( active ) m_active.store( false, std::memory_order_relaxed );
    441             return;
    442         }
    443 #endif
    444 
    445         auto item = Profiler::QueueSerial();
    446         MemWrite( &item->hdr.type, QueueType::LockMark );
    447         MemWrite( &item->lockMark.thread, GetThreadHandle() );
    448         MemWrite( &item->lockMark.id, m_id );
    449         MemWrite( &item->lockMark.srcloc, (uint64_t)srcloc );
    450         Profiler::QueueSerialFinish();
    451     }
    452 
    453 private:
    454     uint32_t m_id;
    455 
    456 #ifdef TRACY_ON_DEMAND
    457     std::atomic<uint32_t> m_lockCount;
    458     std::atomic<bool> m_active;
    459 #endif
    460 };
    461 
    462 template<class T>
    463 class SharedLockable
    464 {
    465 public:
    466     tracy_force_inline SharedLockable( const SourceLocationData* srcloc )
    467         : m_ctx( srcloc )
    468     {
    469     }
    470 
    471     SharedLockable( const SharedLockable& ) = delete;
    472     SharedLockable& operator=( const SharedLockable& ) = delete;
    473 
    474     tracy_force_inline void lock()
    475     {
    476         const auto runAfter = m_ctx.BeforeLock();
    477         m_lockable.lock();
    478         if( runAfter ) m_ctx.AfterLock();
    479     }
    480 
    481     tracy_force_inline void unlock()
    482     {
    483         m_lockable.unlock();
    484         m_ctx.AfterUnlock();
    485     }
    486 
    487     tracy_force_inline bool try_lock()
    488     {
    489         const auto acquired = m_lockable.try_lock();
    490         m_ctx.AfterTryLock( acquired );
    491         return acquired;
    492     }
    493 
    494     tracy_force_inline void lock_shared()
    495     {
    496         const auto runAfter = m_ctx.BeforeLockShared();
    497         m_lockable.lock_shared();
    498         if( runAfter ) m_ctx.AfterLockShared();
    499     }
    500 
    501     tracy_force_inline void unlock_shared()
    502     {
    503         m_lockable.unlock_shared();
    504         m_ctx.AfterUnlockShared();
    505     }
    506 
    507     tracy_force_inline bool try_lock_shared()
    508     {
    509         const auto acquired = m_lockable.try_lock_shared();
    510         m_ctx.AfterTryLockShared( acquired );
    511         return acquired;
    512     }
    513 
    514     tracy_force_inline void Mark( const SourceLocationData* srcloc )
    515     {
    516         m_ctx.Mark( srcloc );
    517     }
    518 
    519 private:
    520     T m_lockable;
    521     SharedLockableCtx m_ctx;
    522 };
    523 
    524 
    525 };
    526 
    527 #endif