mirror of
https://github.com/wolfpld/tracy.git
synced 2026-10-24 09:40:53 +00:00
Add a per-directory lock file to the capture daemon.
Only one daemon can write to a given output directory at a time. The lock holds the daemon PID and is removed on a clean exit; a lock whose owner is verifiably gone is taken over on the next start, and a lock whose owner cannot be read or that reads as alive must be removed by hand.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
#ifdef _WIN32
|
||||
# include <process.h>
|
||||
# include <windows.h>
|
||||
#else
|
||||
# include <unistd.h>
|
||||
@@ -7,7 +8,10 @@
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <cerrno>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <fcntl.h>
|
||||
#include <filesystem>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
@@ -37,12 +41,29 @@ static uint16_t g_listenPort = 8086;
|
||||
static std::string g_filterName;
|
||||
static int g_filterPort = 0;
|
||||
static int64_t g_memoryLimit = -1;
|
||||
static std::string g_lockFile;
|
||||
|
||||
void SigInt( int )
|
||||
{
|
||||
g_shutdown.store( true, std::memory_order_relaxed );
|
||||
}
|
||||
|
||||
static void RemoveLockFile()
|
||||
{
|
||||
std::error_code ec;
|
||||
std::filesystem::remove( g_lockFile, ec );
|
||||
}
|
||||
|
||||
static long ReadLockPid( const std::string& path )
|
||||
{
|
||||
FILE* in = fopen( path.c_str(), "r" );
|
||||
if( !in ) return -1;
|
||||
long pid = -1;
|
||||
const int result = fscanf( in, "%li", &pid );
|
||||
fclose( in );
|
||||
return ( result == 1 && pid > 0 ) ? pid : -1;
|
||||
}
|
||||
|
||||
struct ClientStats
|
||||
{
|
||||
std::atomic<float> mbps{0};
|
||||
@@ -337,7 +358,47 @@ int main( int argc, char** argv )
|
||||
std::filesystem::create_directories( outputDir );
|
||||
|
||||
InitTerminalDetection();
|
||||
|
||||
g_lockFile = outputDir + "/.tracy-capture-daemon.lock";
|
||||
{
|
||||
int lockFd = -1;
|
||||
for( int attempt = 0; attempt < 5; attempt++ )
|
||||
{
|
||||
lockFd = open( g_lockFile.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0644 );
|
||||
if( lockFd >= 0 ) break;
|
||||
if( errno != EEXIST )
|
||||
{
|
||||
fprintf( stderr, "Error: Cannot create the lock file %s: %s\n", g_lockFile.c_str(), strerror( errno ) );
|
||||
return 1;
|
||||
}
|
||||
const long owner = ReadLockPid( g_lockFile );
|
||||
if( owner <= 0 )
|
||||
{
|
||||
fprintf( stderr, "Error: The lock file %s has no readable owner PID; remove it by hand if no daemon is running\n", g_lockFile.c_str() );
|
||||
return 1;
|
||||
}
|
||||
// EPERM: the process exists under another user; treat it as alive.
|
||||
if( kill( owner, 0 ) == 0 || errno == EPERM )
|
||||
{
|
||||
fprintf( stderr, "Error: Another capture daemon (pid %ld) is already using the output directory %s\n", owner, outputDir.c_str() );
|
||||
return 1;
|
||||
}
|
||||
std::error_code ec;
|
||||
std::filesystem::remove( g_lockFile, ec );
|
||||
}
|
||||
if( lockFd < 0 )
|
||||
{
|
||||
fprintf( stderr, "Error: Another capture daemon is already using the output directory %s\n", outputDir.c_str() );
|
||||
return 1;
|
||||
}
|
||||
#ifdef _WIN32
|
||||
const std::string pid = std::to_string( _getpid() );
|
||||
#else
|
||||
const std::string pid = std::to_string( getpid() );
|
||||
#endif
|
||||
write( lockFd, pid.c_str(), pid.size() );
|
||||
close( lockFd );
|
||||
}
|
||||
atexit( RemoveLockFile );
|
||||
#ifdef _WIN32
|
||||
signal( SIGINT, SigInt );
|
||||
#else
|
||||
|
||||
Reference in New Issue
Block a user