Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CCPMemoryTracker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// See http://core/wiki/Memory_Tracking

#include "include/CCPMemoryTracker.h"
#include "include/CCPMemory.h"
#include "include/CcpMutex.h"

#include <map>
Expand Down
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ set(SRC_FILES
CCPMemory.cpp
CCPMemoryTracker.cpp
CCPMemoryTrackerMutex.h
CcpMutex.cpp
CcpProcess.cpp
CcpSecureCrt.cpp
CcpSemaphore.cpp
Expand Down
234 changes: 234 additions & 0 deletions CcpMutex.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
// Copyright © 2026 CCP ehf.

#include <string>

#include "include/CcpMutex.h"
#include "include/CcpTelemetry.h"
#include "include/CcpThread.h"


namespace
{
// Platform independent alias for the underlying lock object used by CcpMutex
#ifdef _WIN32
#include <windows.h>
using NativeMutex = CRITICAL_SECTION;
#else
#include <pthread.h>
using NativeMutex = pthread_mutex_t;
#endif

// Small platform-specific helpers. The cross-platform CcpMutex methods below
// call these so that no public method body needs to be duplicated per OS.
NativeMutex* CreateNativeMutex( unsigned spinCount )
{
auto* mux = new NativeMutex;
#ifdef _WIN32
InitializeCriticalSectionAndSpinCount( mux, spinCount );
#else
(void)spinCount; // pthreads has no equivalent
pthread_mutexattr_t mutexAttr;
pthread_mutexattr_init( &mutexAttr );
pthread_mutexattr_settype( &mutexAttr, PTHREAD_MUTEX_RECURSIVE );

pthread_mutex_init( mux, &mutexAttr );
pthread_mutexattr_destroy( &mutexAttr );
#endif
return mux;
}

void DestroyNativeMutex( NativeMutex* mux )
{
if ( !mux )
{
return;
}
#ifdef _WIN32
::DeleteCriticalSection( mux );
#else
pthread_mutex_destroy( mux );
#endif
delete mux;
}

void LockNativeMutex( NativeMutex* mux )
{
#ifdef _WIN32
EnterCriticalSection( mux );
#else
pthread_mutex_lock( mux );
#endif
}

void UnlockNativeMutex( NativeMutex* mux )
{
#ifdef _WIN32
LeaveCriticalSection( mux );
#else
pthread_mutex_unlock( mux );
#endif
}
}

// ---------------------------------------------------------------------------
// CcpMutex
// ---------------------------------------------------------------------------

CcpMutex::CcpMutex( const char* owner, const char* name, unsigned spinCount )
: m_mutexHandle( CreateNativeMutex( spinCount ) ),
m_owner( owner ),
m_name( name )
{
#if CCP_TELEMETRY_ENABLED
EnsureTelemetryLockAnnounced();
#endif
CcpRegisterMutex( *this, owner, name );
}

CcpMutex::~CcpMutex()
{
DestroyNativeMutex( static_cast<NativeMutex*>( m_mutexHandle ) );
m_mutexHandle = nullptr;
#if CCP_TELEMETRY_ENABLED
if ( CcpTelemetryLockTrackingIsEnabled() && m_tracyLockContext && CcpTelemetryIsConnected() )
{
TracyCLockTerminate( static_cast<TracyCLockCtx>( m_tracyLockContext ) );
}
m_tracyLockContext = nullptr;
#endif
}

void CcpMutex::Acquire()
{
#if CCP_TELEMETRY_ENABLED
EnsureTelemetryLockAnnounced();
const bool emit = m_tracyLockContext && CcpTelemetryLockTrackingIsEnabled() && CcpTelemetryIsConnected();
bool notifyTracy{ false };
if ( emit )
{
notifyTracy = TracyCLockBeforeLock( static_cast<TracyCLockCtx>( m_tracyLockContext ) );
}
#endif
LockNativeMutex( static_cast<NativeMutex*>( m_mutexHandle ) );
#if CCP_TELEMETRY_ENABLED
if ( notifyTracy )
{
TracyCLockAfterLock( static_cast<TracyCLockCtx>( m_tracyLockContext ) );
}
#endif
}

void CcpMutex::Release()
{
UnlockNativeMutex( static_cast<NativeMutex*>( m_mutexHandle ) );
#if CCP_TELEMETRY_ENABLED
if ( m_tracyLockContext && CcpTelemetryLockTrackingIsEnabled() && CcpTelemetryIsConnected() )
{
TracyCLockAfterUnlock( static_cast<TracyCLockCtx>( m_tracyLockContext ) );
}
#endif
}

void CcpMutex::SetOwner( const char* owner )
{
m_owner = owner;
}

void CcpMutex::SetName( const char* name )
{
m_name = name;
}

#if CCP_TELEMETRY_ENABLED
void CcpMutex::EnsureTelemetryLockAnnounced()
{
if ( m_tracyLockContext )
{
return; // already announced
}
if ( CcpTelemetryLockTrackingIsEnabled() && CcpTelemetryIsConnected() )
{
TracyCLockCtx ctx = static_cast<TracyCLockCtx>( m_tracyLockContext );
const std::string lockName = std::string( m_owner ? m_owner : "<owner>" ) + "-" + ( m_name ? m_name : "<name>" );
TracyCLockAnnounce( ctx );
TracyCLockCustomName( ctx, lockName.c_str(), lockName.size() );
m_tracyLockContext = ctx;
}
}
#endif

// ---------------------------------------------------------------------------
// CcpAutoMutex
// ---------------------------------------------------------------------------

CcpAutoMutex::CcpAutoMutex( CcpMutex& m )
: m_mutex( m ), m_released( false )
{
m_mutex.Acquire();
}

CcpAutoMutex::~CcpAutoMutex()
{
if ( !m_released )
{
m_mutex.Release();
}
}

void CcpAutoMutex::Release()
{
m_mutex.Release();
m_released = true;
}

// ---------------------------------------------------------------------------
// CcpSpinLock
// ---------------------------------------------------------------------------

CcpSpinLock::CcpSpinLock()
: m_lock( 0 )
{
}

void CcpSpinLock::Acquire()
{
while ( true )
{
uint32_t expected = 0;
if ( m_lock.compare_exchange_strong( expected, 1 ) )
{
break;
}
CcpThreadYield();
}
}

void CcpSpinLock::Release()
{
m_lock = 0;
}

// ---------------------------------------------------------------------------
// CcpAutoSpinLock
// ---------------------------------------------------------------------------

CcpAutoSpinLock::CcpAutoSpinLock( CcpSpinLock& m )
: m_mutex( m ), m_released( false )
{
m_mutex.Acquire();
}

CcpAutoSpinLock::~CcpAutoSpinLock()
{
if ( !m_released )
{
m_mutex.Release();
}
}

void CcpAutoSpinLock::Release()
{
m_mutex.Release();
m_released = true;
}

14 changes: 10 additions & 4 deletions CcpTelemetry.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,18 +95,19 @@ bool CcpTelemetryMemoryTrackingIsEnabled()
return s_config.trackMemoryAllocations;
}

bool CcpTelemetryLockTrackingIsEnabled()
{
return s_config.trackLocks;
}

void CcpRegisterMutex( class CcpMutex& m, const char* owner, const char* name )
{
// Store the name for future Telemetry sessions, even if we're already connected.
// This is to support multiple Telemetry sessions in one ExeFile session.
MutexNameMap_t& mutexNames = GetMutexNameMap();
mutexNames[&m] = std::make_pair( owner, name );
}

void CcpRegisterThread( CcpThreadId_t threadId, const char* name )
{
// Store the name for future Telemetry sessions, even if we're already connected.
// This is to support multiple Telemetry sessions in one ExeFile session.
ThreadNameMap_t& threadNames = GetThreadNameMap();
threadNames[threadId] = name;
}
Expand Down Expand Up @@ -450,6 +451,11 @@ bool CcpTelemetryMemoryTrackingIsEnabled()
return false;
}

bool CcpTelemetryLockTrackingIsEnabled()
{
return false;
}

void CcpRegisterThread( CcpThreadId_t threadId, const char* name )
{
}
Expand Down
Loading