aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRSDuck <RSDuck@users.noreply.github.com>2021-03-11 16:54:27 +0100
committerRSDuck <RSDuck@users.noreply.github.com>2021-03-11 16:54:43 +0100
commitbc63531e0062324166ccee0e2bada40075118923 (patch)
treee96146d5567853e3b55b15a8d11efcee6eec1117 /src
parentae7761c33e0e73a0f21e8651a4c7525aadb709eb (diff)
avoid leaking threads in NDSCart_SRAMManager
also atomics
Diffstat (limited to 'src')
-rw-r--r--src/GPU3D_Soft.cpp10
-rw-r--r--src/GPU3D_Soft.h5
-rw-r--r--src/NDSCart_SRAMManager.cpp229
3 files changed, 127 insertions, 117 deletions
diff --git a/src/GPU3D_Soft.cpp b/src/GPU3D_Soft.cpp
index 22f7f01..dd4a304 100644
--- a/src/GPU3D_Soft.cpp
+++ b/src/GPU3D_Soft.cpp
@@ -33,7 +33,7 @@ void RenderThreadFunc();
void SoftRenderer::StopRenderThread()
{
- if (RenderThreadRunning)
+ if (RenderThreadRunning.load(std::memory_order_relaxed))
{
RenderThreadRunning = false;
Platform::Semaphore_Post(Sema_RenderStart);
@@ -46,7 +46,7 @@ void SoftRenderer::SetupRenderThread()
{
if (Threaded)
{
- if (!RenderThreadRunning)
+ if (!RenderThreadRunning.load(std::memory_order_relaxed))
{
RenderThreadRunning = true;
RenderThread = Platform::Thread_Create(std::bind(&SoftRenderer::RenderThreadFunc, this));
@@ -1646,7 +1646,7 @@ void SoftRenderer::RenderPolygons(bool threaded, Polygon** polygons, int npolys)
void SoftRenderer::VCount144()
{
- if (RenderThreadRunning)
+ if (RenderThreadRunning.load(std::memory_order_relaxed))
Platform::Semaphore_Wait(Sema_RenderDone);
}
@@ -1660,7 +1660,7 @@ void SoftRenderer::RenderFrame()
FrameIdentical = !(textureChanged || texPalChanged) && RenderFrameIdentical;
- if (RenderThreadRunning)
+ if (RenderThreadRunning.load(std::memory_order_relaxed))
{
Platform::Semaphore_Post(Sema_RenderStart);
}
@@ -1701,7 +1701,7 @@ void SoftRenderer::RenderThreadFunc()
u32* SoftRenderer::GetLine(int line)
{
- if (RenderThreadRunning)
+ if (RenderThreadRunning.load(std::memory_order_relaxed))
{
if (line < 192)
Platform::Semaphore_Wait(Sema_ScanlineCount);
diff --git a/src/GPU3D_Soft.h b/src/GPU3D_Soft.h
index ee1977d..9f6f993 100644
--- a/src/GPU3D_Soft.h
+++ b/src/GPU3D_Soft.h
@@ -21,6 +21,7 @@
#include "GPU3D.h"
#include "Platform.h"
#include <thread>
+#include <atomic>
namespace GPU3D
{
@@ -506,8 +507,8 @@ private:
bool Threaded;
Platform::Thread* RenderThread;
- bool RenderThreadRunning;
- bool RenderThreadRendering;
+ std::atomic_bool RenderThreadRunning;
+ std::atomic_bool RenderThreadRendering;
Platform::Semaphore* Sema_RenderStart;
Platform::Semaphore* Sema_RenderDone;
Platform::Semaphore* Sema_ScanlineCount;
diff --git a/src/NDSCart_SRAMManager.cpp b/src/NDSCart_SRAMManager.cpp
index c93db2a..49c5357 100644
--- a/src/NDSCart_SRAMManager.cpp
+++ b/src/NDSCart_SRAMManager.cpp
@@ -20,156 +20,165 @@
#include <string.h>
#include <unistd.h>
#include <time.h>
+#include <atomic>
#include "NDSCart_SRAMManager.h"
#include "Platform.h"
namespace NDSCart_SRAMManager
{
- Platform::Thread* FlushThread;
- bool FlushThreadRunning;
- Platform::Mutex* SecondaryBufferLock;
- char Path[1024];
+Platform::Thread* FlushThread;
+std::atomic_bool FlushThreadRunning;
+Platform::Mutex* SecondaryBufferLock;
- u8* Buffer;
- u32 Length;
+char Path[1024];
- u8* SecondaryBuffer;
- u32 SecondaryBufferLength;
-
- time_t TimeAtLastFlushRequest;
+u8* Buffer;
+u32 Length;
- // We keep versions in case the user closes the application before
- // a flush cycle is finished.
- u32 PreviousFlushVersion;
- u32 FlushVersion;
+u8* SecondaryBuffer;
+u32 SecondaryBufferLength;
- void FlushThreadFunc();
+time_t TimeAtLastFlushRequest;
- bool Init()
- {
- SecondaryBufferLock = Platform::Mutex_Create();
+// We keep versions in case the user closes the application before
+// a flush cycle is finished.
+u32 PreviousFlushVersion;
+u32 FlushVersion;
- return true;
- }
+void FlushThreadFunc();
- void DeInit()
- {
- if (FlushThreadRunning)
- {
- FlushThreadRunning = false;
- Platform::Thread_Wait(FlushThread);
- Platform::Thread_Free(FlushThread);
- FlushSecondaryBuffer();
- }
+bool Init()
+{
+ SecondaryBufferLock = Platform::Mutex_Create();
- if (SecondaryBuffer) delete SecondaryBuffer;
- SecondaryBuffer = NULL;
+ return true;
+}
- Platform::Mutex_Free(SecondaryBufferLock);
- }
-
- void Setup(const char* path, u8* buffer, u32 length)
+void DeInit()
+{
+ if (FlushThreadRunning)
{
- // Flush SRAM in case there is unflushed data from previous state.
+ FlushThreadRunning = false;
+ Platform::Thread_Wait(FlushThread);
+ Platform::Thread_Free(FlushThread);
FlushSecondaryBuffer();
+ }
- Platform::Mutex_Lock(SecondaryBufferLock);
+ if (SecondaryBuffer) delete[] SecondaryBuffer;
+ SecondaryBuffer = NULL;
- strncpy(Path, path, 1023);
- Path[1023] = '\0';
+ Platform::Mutex_Free(SecondaryBufferLock);
+}
- Buffer = buffer;
- Length = length;
+void Setup(const char* path, u8* buffer, u32 length)
+{
+ // Flush SRAM in case there is unflushed data from previous state.
+ FlushSecondaryBuffer();
- if(SecondaryBuffer) delete SecondaryBuffer; // Delete secondary buffer, there might be previous state.
+ Platform::Mutex_Lock(SecondaryBufferLock);
- SecondaryBuffer = new u8[length];
- SecondaryBufferLength = length;
+ strncpy(Path, path, 1023);
+ Path[1023] = '\0';
- FlushVersion = 0;
- PreviousFlushVersion = 0;
- TimeAtLastFlushRequest = 0;
+ Buffer = buffer;
+ Length = length;
- Platform::Mutex_Unlock(SecondaryBufferLock);
+ if(SecondaryBuffer) delete[] SecondaryBuffer; // Delete secondary buffer, there might be previous state.
- if (path[0] != '\0')
- {
- FlushThread = Platform::Thread_Create(FlushThreadFunc);
- FlushThreadRunning = true;
- }
- }
+ SecondaryBuffer = new u8[length];
+ SecondaryBufferLength = length;
- void RequestFlush()
+ FlushVersion = 0;
+ PreviousFlushVersion = 0;
+ TimeAtLastFlushRequest = 0;
+
+ Platform::Mutex_Unlock(SecondaryBufferLock);
+
+ if (path[0] != '\0' && !FlushThreadRunning)
{
- Platform::Mutex_Lock(SecondaryBufferLock);
- printf("NDS SRAM: Flush requested\n");
- memcpy(SecondaryBuffer, Buffer, Length);
- FlushVersion++;
- TimeAtLastFlushRequest = time(NULL);
- Platform::Mutex_Unlock(SecondaryBufferLock);
+ FlushThread = Platform::Thread_Create(FlushThreadFunc);
+ FlushThreadRunning = true;
}
-
- void FlushThreadFunc()
+ else if (path[0] == '\0' && FlushThreadRunning)
{
- for (;;)
- {
- Platform::Sleep(100 * 1000); // 100ms
+ FlushThreadRunning = false;
+ Platform::Thread_Wait(FlushThread);
+ Platform::Thread_Free(FlushThread);
+ }
+}
- if (!FlushThreadRunning) return;
-
- // We debounce for two seconds after last flush request to ensure that writing has finished.
- if (TimeAtLastFlushRequest == 0 || difftime(time(NULL), TimeAtLastFlushRequest) < 2)
- {
- continue;
- }
+void RequestFlush()
+{
+ Platform::Mutex_Lock(SecondaryBufferLock);
+ printf("NDS SRAM: Flush requested\n");
+ memcpy(SecondaryBuffer, Buffer, Length);
+ FlushVersion++;
+ TimeAtLastFlushRequest = time(NULL);
+ Platform::Mutex_Unlock(SecondaryBufferLock);
+}
- FlushSecondaryBuffer();
- }
- }
-
- void FlushSecondaryBuffer(u8* dst, s32 dstLength)
+void FlushThreadFunc()
+{
+ for (;;)
{
- // When flushing to a file, there's no point in re-writing the exact same data.
- if (!dst && !NeedsFlush()) return;
- // When flushing to memory, we don't know if dst already has any data so we only check that we CAN flush.
- if (dst && dstLength < SecondaryBufferLength) return;
+ Platform::Sleep(100 * 1000); // 100ms
- Platform::Mutex_Lock(SecondaryBufferLock);
- if (dst)
- {
- memcpy(dst, SecondaryBuffer, SecondaryBufferLength);
- }
- else
+ if (!FlushThreadRunning) return;
+
+ // We debounce for two seconds after last flush request to ensure that writing has finished.
+ if (TimeAtLastFlushRequest == 0 || difftime(time(NULL), TimeAtLastFlushRequest) < 2)
{
- FILE* f = Platform::OpenFile(Path, "wb");
- if (f)
- {
- printf("NDS SRAM: Written\n");
- fwrite(SecondaryBuffer, SecondaryBufferLength, 1, f);
- fclose(f);
- }
+ continue;
}
- PreviousFlushVersion = FlushVersion;
- TimeAtLastFlushRequest = 0;
- Platform::Mutex_Unlock(SecondaryBufferLock);
+
+ FlushSecondaryBuffer();
}
+}
+
+void FlushSecondaryBuffer(u8* dst, s32 dstLength)
+{
+ // When flushing to a file, there's no point in re-writing the exact same data.
+ if (!dst && !NeedsFlush()) return;
+ // When flushing to memory, we don't know if dst already has any data so we only check that we CAN flush.
+ if (dst && dstLength < SecondaryBufferLength) return;
- bool NeedsFlush()
+ Platform::Mutex_Lock(SecondaryBufferLock);
+ if (dst)
{
- return FlushVersion != PreviousFlushVersion;
+ memcpy(dst, SecondaryBuffer, SecondaryBufferLength);
}
-
- void UpdateBuffer(u8* src, s32 srcLength)
+ else
{
- if (!src || srcLength != Length) return;
+ FILE* f = Platform::OpenFile(Path, "wb");
+ if (f)
+ {
+ printf("NDS SRAM: Written\n");
+ fwrite(SecondaryBuffer, SecondaryBufferLength, 1, f);
+ fclose(f);
+ }
+ }
+ PreviousFlushVersion = FlushVersion;
+ TimeAtLastFlushRequest = 0;
+ Platform::Mutex_Unlock(SecondaryBufferLock);
+}
- // should we create a lock for the primary buffer? this method is not intended to be called from a secondary thread in the way Flush is
- memcpy(Buffer, src, srcLength);
- Platform::Mutex_Lock(SecondaryBufferLock);
- memcpy(SecondaryBuffer, src, srcLength);
- Platform::Mutex_Unlock(SecondaryBufferLock);
+bool NeedsFlush()
+{
+ return FlushVersion != PreviousFlushVersion;
+}
+
+void UpdateBuffer(u8* src, s32 srcLength)
+{
+ if (!src || srcLength != Length) return;
+
+ // should we create a lock for the primary buffer? this method is not intended to be called from a secondary thread in the way Flush is
+ memcpy(Buffer, src, srcLength);
+ Platform::Mutex_Lock(SecondaryBufferLock);
+ memcpy(SecondaryBuffer, src, srcLength);
+ Platform::Mutex_Unlock(SecondaryBufferLock);
+
+ PreviousFlushVersion = FlushVersion;
+}
- PreviousFlushVersion = FlushVersion;
- }
}