Skip to content

Commit

Permalink
WIP: Use CLock instead of std::mutex, add thread-safety annotations
Browse files Browse the repository at this point in the history
  • Loading branch information
Robyt3 committed Nov 10, 2023
1 parent 955d7d1 commit 17b2961
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 81 deletions.
29 changes: 12 additions & 17 deletions src/base/log.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -317,7 +317,7 @@ class CWindowsConsoleLogger : public ILogger
HANDLE m_pConsole;
int m_BackgroundColor;
int m_ForegroundColor;
std::mutex m_OutputLock;
CLock m_OutputLock;
bool m_Finished = false;

public:
Expand All @@ -336,7 +336,7 @@ class CWindowsConsoleLogger : public ILogger
m_ForegroundColor = FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
}
}
void Log(const CLogMessage *pMessage) override
void Log(const CLogMessage *pMessage) override REQUIRES(!m_OutputLock)
{
if(m_Filter.Filters(pMessage))
{
Expand All @@ -356,44 +356,41 @@ class CWindowsConsoleLogger : public ILogger
else
Color |= FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;

m_OutputLock.lock();
const CLockScope LockScope(m_OutputLock);
if(!m_Finished)
{
SetConsoleTextAttribute(m_pConsole, Color);
WriteConsoleW(m_pConsole, WideMessage.c_str(), WideMessage.length(), NULL, NULL);
}
m_OutputLock.unlock();
}
void GlobalFinish() override
void GlobalFinish() override REQUIRES(!m_OutputLock)
{
// Restore original color
m_OutputLock.lock();
const CLockScope LockScope(m_OutputLock);
SetConsoleTextAttribute(m_pConsole, m_BackgroundColor | m_ForegroundColor);
m_Finished = true;
m_OutputLock.unlock();
}
};
class CWindowsFileLogger : public ILogger
{
HANDLE m_pFile;
std::mutex m_OutputLock;
CLock m_OutputLock;

public:
CWindowsFileLogger(HANDLE pFile) :
m_pFile(pFile)
{
}
void Log(const CLogMessage *pMessage) override
void Log(const CLogMessage *pMessage) override REQUIRES(!m_OutputLock)
{
if(m_Filter.Filters(pMessage))
{
return;
}
m_OutputLock.lock();
const CLockScope LockScope(m_OutputLock);
DWORD Written; // we don't care about the value, but Windows 7 crashes if we pass NULL
WriteFile(m_pFile, pMessage->m_aLine, pMessage->m_LineLength, &Written, NULL);
WriteFile(m_pFile, "\r\n", 2, &Written, NULL);
m_OutputLock.unlock();
}
};
#endif
Expand Down Expand Up @@ -447,9 +444,9 @@ std::unique_ptr<ILogger> log_logger_windows_debugger()

void CFutureLogger::Set(std::shared_ptr<ILogger> pLogger)
{
std::shared_ptr<ILogger> null;
m_PendingLock.lock();
if(!std::atomic_compare_exchange_strong_explicit(&m_pLogger, &null, pLogger, std::memory_order_acq_rel, std::memory_order_acq_rel))
const CLockScope LockScope(m_PendingLock);
std::shared_ptr<ILogger> pNullLogger;
if(!std::atomic_compare_exchange_strong_explicit(&m_pLogger, &pNullLogger, pLogger, std::memory_order_acq_rel, std::memory_order_acq_rel))
{
dbg_assert(false, "future logger has already been set and can only be set once");
}
Expand All @@ -461,7 +458,6 @@ void CFutureLogger::Set(std::shared_ptr<ILogger> pLogger)
}
m_vPending.clear();
m_vPending.shrink_to_fit();
m_PendingLock.unlock();
}

void CFutureLogger::Log(const CLogMessage *pMessage)
Expand All @@ -472,15 +468,14 @@ void CFutureLogger::Log(const CLogMessage *pMessage)
pLogger->Log(pMessage);
return;
}
m_PendingLock.lock();
const CLockScope LockScope(m_PendingLock);
pLogger = std::atomic_load_explicit(&m_pLogger, std::memory_order_relaxed);
if(pLogger)
{
pLogger->Log(pMessage);
return;
}
m_vPending.push_back(*pMessage);
m_PendingLock.unlock();
}

void CFutureLogger::GlobalFinish()
Expand Down
9 changes: 5 additions & 4 deletions src/base/logger.h
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
#ifndef BASE_LOGGER_H
#define BASE_LOGGER_H

#include "lock.h"
#include "log.h"

#include <atomic>
#include <memory>
#include <mutex>
#include <vector>

typedef void *IOHANDLE;
Expand Down Expand Up @@ -226,15 +227,15 @@ class CFutureLogger : public ILogger
private:
std::shared_ptr<ILogger> m_pLogger;
std::vector<CLogMessage> m_vPending;
std::mutex m_PendingLock;
CLock m_PendingLock;

public:
/**
* Replace the `CFutureLogger` instance with the given logger. It'll
* receive all log messages sent to the `CFutureLogger` so far.
*/
void Set(std::shared_ptr<ILogger> pLogger);
void Log(const CLogMessage *pMessage) override;
void Set(std::shared_ptr<ILogger> pLogger) REQUIRES(!m_PendingLock);
void Log(const CLogMessage *pMessage) override REQUIRES(!m_PendingLock);
void GlobalFinish() override;
void OnFilterChange() override;
};
Expand Down
25 changes: 12 additions & 13 deletions src/engine/client/sound.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -687,7 +687,7 @@ void CSound::SetVoiceVolume(CVoiceHandle Voice, float Volume)

int VoiceID = Voice.Id();

std::unique_lock<std::mutex> Lock(m_SoundLock);
const CLockScope LockScope(m_SoundLock);
if(m_aVoices[VoiceID].m_Age != Voice.Age())
return;

Expand All @@ -702,7 +702,7 @@ void CSound::SetVoiceFalloff(CVoiceHandle Voice, float Falloff)

int VoiceID = Voice.Id();

std::unique_lock<std::mutex> Lock(m_SoundLock);
const CLockScope LockScope(m_SoundLock);
if(m_aVoices[VoiceID].m_Age != Voice.Age())
return;

Expand All @@ -717,7 +717,7 @@ void CSound::SetVoiceLocation(CVoiceHandle Voice, float x, float y)

int VoiceID = Voice.Id();

std::unique_lock<std::mutex> Lock(m_SoundLock);
const CLockScope LockScope(m_SoundLock);
if(m_aVoices[VoiceID].m_Age != Voice.Age())
return;

Expand All @@ -732,7 +732,7 @@ void CSound::SetVoiceTimeOffset(CVoiceHandle Voice, float TimeOffset)

int VoiceID = Voice.Id();

std::unique_lock<std::mutex> Lock(m_SoundLock);
const CLockScope LockScope(m_SoundLock);
if(m_aVoices[VoiceID].m_Age != Voice.Age())
return;

Expand Down Expand Up @@ -766,7 +766,7 @@ void CSound::SetVoiceCircle(CVoiceHandle Voice, float Radius)

int VoiceID = Voice.Id();

std::unique_lock<std::mutex> Lock(m_SoundLock);
const CLockScope LockScope(m_SoundLock);
if(m_aVoices[VoiceID].m_Age != Voice.Age())
return;

Expand All @@ -781,7 +781,7 @@ void CSound::SetVoiceRectangle(CVoiceHandle Voice, float Width, float Height)

int VoiceID = Voice.Id();

std::unique_lock<std::mutex> Lock(m_SoundLock);
const CLockScope LockScope(m_SoundLock);
if(m_aVoices[VoiceID].m_Age != Voice.Age())
return;

Expand All @@ -792,7 +792,7 @@ void CSound::SetVoiceRectangle(CVoiceHandle Voice, float Width, float Height)

ISound::CVoiceHandle CSound::Play(int ChannelID, int SampleID, int Flags, float x, float y)
{
m_SoundLock.lock();
const CLockScope LockScope(m_SoundLock);

// search for voice
int VoiceID = -1;
Expand Down Expand Up @@ -836,7 +836,6 @@ ISound::CVoiceHandle CSound::Play(int ChannelID, int SampleID, int Flags, float
Age = m_aVoices[VoiceID].m_Age;
}

m_SoundLock.unlock();
return CreateVoiceHandle(VoiceID, Age);
}

Expand All @@ -853,7 +852,7 @@ ISound::CVoiceHandle CSound::Play(int ChannelID, int SampleID, int Flags)
void CSound::Pause(int SampleID)
{
// TODO: a nice fade out
std::unique_lock<std::mutex> Lock(m_SoundLock);
const CLockScope LockScope(m_SoundLock);
CSample *pSample = &m_aSamples[SampleID];
for(auto &Voice : m_aVoices)
{
Expand All @@ -868,7 +867,7 @@ void CSound::Pause(int SampleID)
void CSound::Stop(int SampleID)
{
// TODO: a nice fade out
std::unique_lock<std::mutex> Lock(m_SoundLock);
const CLockScope LockScope(m_SoundLock);
CSample *pSample = &m_aSamples[SampleID];
for(auto &Voice : m_aVoices)
{
Expand All @@ -886,7 +885,7 @@ void CSound::Stop(int SampleID)
void CSound::StopAll()
{
// TODO: a nice fade out
std::unique_lock<std::mutex> Lock(m_SoundLock);
const CLockScope LockScope(m_SoundLock);
for(auto &Voice : m_aVoices)
{
if(Voice.m_pSample)
Expand All @@ -907,7 +906,7 @@ void CSound::StopVoice(CVoiceHandle Voice)

int VoiceID = Voice.Id();

std::unique_lock<std::mutex> Lock(m_SoundLock);
const CLockScope LockScope(m_SoundLock);
if(m_aVoices[VoiceID].m_Age != Voice.Age())
return;

Expand All @@ -917,7 +916,7 @@ void CSound::StopVoice(CVoiceHandle Voice)

bool CSound::IsPlaying(int SampleID)
{
std::unique_lock<std::mutex> Lock(m_SoundLock);
const CLockScope LockScope(m_SoundLock);
const CSample *pSample = &m_aSamples[SampleID];
return std::any_of(std::begin(m_aVoices), std::end(m_aVoices), [pSample](const auto &Voice) { return Voice.m_pSample == pSample; });
}
Expand Down
35 changes: 18 additions & 17 deletions src/engine/client/sound.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,13 @@
#ifndef ENGINE_CLIENT_SOUND_H
#define ENGINE_CLIENT_SOUND_H

#include <base/lock.h>

#include <engine/sound.h>

#include <SDL_audio.h>

#include <atomic>
#include <mutex>

struct CSample
{
Expand Down Expand Up @@ -57,7 +58,7 @@ class CSound : public IEngineSound

bool m_SoundEnabled = false;
SDL_AudioDeviceID m_Device = 0;
std::mutex m_SoundLock;
CLock m_SoundLock;

CSample m_aSamples[NUM_SAMPLES] = {{0}};
CVoice m_aVoices[NUM_VOICES] = {{0}};
Expand Down Expand Up @@ -103,24 +104,24 @@ class CSound : public IEngineSound
void SetChannel(int ChannelID, float Vol, float Pan) override;
void SetListenerPos(float x, float y) override;

void SetVoiceVolume(CVoiceHandle Voice, float Volume) override;
void SetVoiceFalloff(CVoiceHandle Voice, float Falloff) override;
void SetVoiceLocation(CVoiceHandle Voice, float x, float y) override;
void SetVoiceTimeOffset(CVoiceHandle Voice, float TimeOffset) override; // in s
void SetVoiceVolume(CVoiceHandle Voice, float Volume) override REQUIRES(!m_SoundLock);
void SetVoiceFalloff(CVoiceHandle Voice, float Falloff) override REQUIRES(!m_SoundLock);
void SetVoiceLocation(CVoiceHandle Voice, float x, float y) override REQUIRES(!m_SoundLock);
void SetVoiceTimeOffset(CVoiceHandle Voice, float TimeOffset) override REQUIRES(!m_SoundLock); // in s

void SetVoiceCircle(CVoiceHandle Voice, float Radius) override;
void SetVoiceRectangle(CVoiceHandle Voice, float Width, float Height) override;
void SetVoiceCircle(CVoiceHandle Voice, float Radius) override REQUIRES(!m_SoundLock);
void SetVoiceRectangle(CVoiceHandle Voice, float Width, float Height) override REQUIRES(!m_SoundLock);

CVoiceHandle Play(int ChannelID, int SampleID, int Flags, float x, float y);
CVoiceHandle PlayAt(int ChannelID, int SampleID, int Flags, float x, float y) override;
CVoiceHandle Play(int ChannelID, int SampleID, int Flags) override;
void Pause(int SampleID) override;
void Stop(int SampleID) override;
void StopAll() override;
void StopVoice(CVoiceHandle Voice) override;
bool IsPlaying(int SampleID) override;
CVoiceHandle Play(int ChannelID, int SampleID, int Flags, float x, float y) REQUIRES(!m_SoundLock);
CVoiceHandle PlayAt(int ChannelID, int SampleID, int Flags, float x, float y) override REQUIRES(!m_SoundLock);
CVoiceHandle Play(int ChannelID, int SampleID, int Flags) override REQUIRES(!m_SoundLock);
void Pause(int SampleID) override REQUIRES(!m_SoundLock);
void Stop(int SampleID) override REQUIRES(!m_SoundLock);
void StopAll() override REQUIRES(!m_SoundLock);
void StopVoice(CVoiceHandle Voice) override REQUIRES(!m_SoundLock);
bool IsPlaying(int SampleID) override REQUIRES(!m_SoundLock);

void Mix(short *pFinalOut, unsigned Frames) override;
void Mix(short *pFinalOut, unsigned Frames) override REQUIRES(!m_SoundLock);
void PauseAudioDevice() override;
void UnpauseAudioDevice() override;
};
Expand Down
4 changes: 2 additions & 2 deletions src/engine/server/server_logger.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ class CServer;
class CServerLogger : public ILogger
{
CServer *m_pServer = nullptr;
std::mutex m_PendingLock;
CLock m_PendingLock;
std::vector<CLogMessage> m_vPending;
std::thread::id m_MainThread;

public:
CServerLogger(CServer *pServer);
void Log(const CLogMessage *pMessage) override;
void Log(const CLogMessage *pMessage) override REQUIRES(!m_PendingLock);
// Must be called from the main thread!
void OnServerDeletion();
};
Expand Down
14 changes: 7 additions & 7 deletions src/engine/shared/assertion_logger.cpp
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
#include "assertion_logger.h"

#include <base/lock.h>
#include <base/logger.h>
#include <base/system.h>

#include <engine/shared/ringbuffer.h>
#include <engine/storage.h>

#include <mutex>

class CAssertionLogger : public ILogger
{
void Dump();
Expand All @@ -16,16 +16,16 @@ class CAssertionLogger : public ILogger
char m_aMessage[1024];
};

std::mutex m_DbgMessageMutex;
CLock m_DbgMessageMutex;
CStaticRingBuffer<SDebugMessageItem, sizeof(SDebugMessageItem) * 64, CRingBufferBase::FLAG_RECYCLE> m_DbgMessages;

char m_aAssertLogPath[IO_MAX_PATH_LENGTH];
char m_aGameName[256];

public:
CAssertionLogger(const char *pAssertLogPath, const char *pGameName);
void Log(const CLogMessage *pMessage) override;
void GlobalFinish() override;
void Log(const CLogMessage *pMessage) override REQUIRES(!m_DbgMessageMutex);
void GlobalFinish() override REQUIRES(!m_DbgMessageMutex);
};

void CAssertionLogger::Log(const CLogMessage *pMessage)
Expand All @@ -34,7 +34,7 @@ void CAssertionLogger::Log(const CLogMessage *pMessage)
{
return;
}
std::unique_lock<std::mutex> Lock(m_DbgMessageMutex);
const CLockScope LockScope(m_DbgMessageMutex);
SDebugMessageItem *pMsgItem = (SDebugMessageItem *)m_DbgMessages.Allocate(sizeof(SDebugMessageItem));
str_copy(pMsgItem->m_aMessage, pMessage->m_aLine);
}
Expand All @@ -53,7 +53,7 @@ void CAssertionLogger::Dump()
char aDate[64];
str_timestamp(aDate, sizeof(aDate));
str_format(aAssertLogFile, std::size(aAssertLogFile), "%s%s_assert_log_%s_%d.txt", m_aAssertLogPath, m_aGameName, aDate, pid());
std::unique_lock<std::mutex> Lock(m_DbgMessageMutex);
const CLockScope LockScope(m_DbgMessageMutex);
IOHANDLE FileHandle = io_open(aAssertLogFile, IOFLAG_WRITE);
if(FileHandle)
{
Expand Down
Loading

0 comments on commit 17b2961

Please sign in to comment.