1
0
forked from 0ad/0ad

pthread -> std::thread (5/7) - Replace sdl semaphore with condition variable

This removes a dependency on the SDL_Thread header.

Differential Revision: https://code.wildfiregames.com/D1921
This was SVN commit r22772.
This commit is contained in:
wraitii 2019-08-24 11:26:58 +00:00
parent b429d0ce03
commit 62dd922bc0
5 changed files with 39 additions and 48 deletions

View File

@ -284,12 +284,6 @@ CTextureConverter::CTextureConverter(PIVFS vfs, bool highQuality) :
ENSURE(nvtt::version() >= NVTT_VERSION);
#endif
// Set up the worker thread:
// Use SDL semaphores since OS X doesn't implement sem_init
m_WorkerSem = SDL_CreateSemaphore(0);
ENSURE(m_WorkerSem);
m_WorkerThread = std::thread(RunThread, this);
// Maybe we should share some centralised pool of worker threads?
@ -304,14 +298,19 @@ CTextureConverter::~CTextureConverter()
m_Shutdown = true;
}
// Wake it up so it sees the notification
SDL_SemPost(m_WorkerSem);
while (true)
{
// Wake the thread up so that it shutdowns.
// If we send the message once, there is a chance it will be missed,
// so keep sending until shtudown becomes false again, indicating that the thread has shut down.
std::lock_guard<std::mutex> lock(m_WorkerMutex);
m_WorkerCV.notify_all();
if (!m_Shutdown)
break;
}
// Wait for it to shut down cleanly
m_WorkerThread.join();
// Clean up resources
SDL_DestroySemaphore(m_WorkerSem);
}
bool CTextureConverter::ConvertTexture(const CTexturePtr& texture, const VfsPath& src, const VfsPath& dest, const Settings& settings)
@ -463,7 +462,7 @@ bool CTextureConverter::ConvertTexture(const CTexturePtr& texture, const VfsPath
}
// Wake up the worker thread
SDL_SemPost(m_WorkerSem);
m_WorkerCV.notify_all();
return true;
@ -527,9 +526,7 @@ bool CTextureConverter::Poll(CTexturePtr& texture, VfsPath& dest, bool& ok)
bool CTextureConverter::IsBusy()
{
std::lock_guard<std::mutex> lock(m_WorkerMutex);
bool busy = !m_RequestQueue.empty();
return busy;
return !m_RequestQueue.empty();
}
void CTextureConverter::RunThread(CTextureConverter* textureConverter)
@ -540,15 +537,22 @@ void CTextureConverter::RunThread(CTextureConverter* textureConverter)
#if CONFIG2_NVTT
// Wait until the main thread wakes us up
while (SDL_SemWait(textureConverter->m_WorkerSem) == 0)
while (true)
{
// We may have several textures in the incoming queue, process them all before going back to sleep.
if (!textureConverter->IsBusy()) {
std::unique_lock<std::mutex> wait_lock(textureConverter->m_WorkerMutex);
// Use the no-condition variant because spurious wake-ups don't matter that much here.
textureConverter->m_WorkerCV.wait(wait_lock);
}
g_Profiler2.RecordSyncMarker();
PROFILE2_EVENT("wakeup");
shared_ptr<ConversionRequest> request;
{
std::lock_guard<std::mutex> lock(textureConverter->m_WorkerMutex);
std::lock_guard<std::mutex> wait_lock(textureConverter->m_WorkerMutex);
if (textureConverter->m_Shutdown)
break;
// If we weren't woken up for shutdown, we must have been woken up for
@ -588,9 +592,11 @@ void CTextureConverter::RunThread(CTextureConverter* textureConverter)
result->output.buffer[80] &= ~0x40; // DDPF_RGB in DDS_PIXELFORMAT.dwFlags
// Push the result onto the queue
std::lock_guard<std::mutex> lock(textureConverter->m_WorkerMutex);
std::lock_guard<std::mutex> wait_lock(textureConverter->m_WorkerMutex);
textureConverter->m_ResultQueue.push_back(result);
}
std::lock_guard<std::mutex> wait_lock(textureConverter->m_WorkerMutex);
textureConverter->m_Shutdown = false;
#endif
}

View File

@ -19,10 +19,10 @@
#define INCLUDED_TEXTURECONVERTER
#include "lib/file/vfs/vfs.h"
#include "lib/external_libraries/libsdl.h"
#include "TextureManager.h"
#include <condition_variable>
#include <mutex>
#include <thread>
@ -208,7 +208,7 @@ private:
std::thread m_WorkerThread;
std::mutex m_WorkerMutex;
SDL_sem* m_WorkerSem;
std::condition_variable m_WorkerCV;
struct ConversionRequest;
struct ConversionResult;

View File

@ -341,8 +341,7 @@ public:
if (m_TextureConverter.Poll(textureOut, dest, ok))
return ok;
// Spin-loop is dumb but it works okay for now
SDL_Delay(0);
std::this_thread::sleep_for(std::chrono::microseconds(1));
}
}

View File

@ -24,7 +24,6 @@
#if HAVE_PCH
#include "SDL.h"
#include "SDL_thread.h"
#include "SDL_endian.h"
#endif // HAVE_PCH

View File

@ -22,7 +22,6 @@
#include "lib/timer.h"
#include "lib/utf8.h"
#include "lib/external_libraries/curl.h"
#include "lib/external_libraries/libsdl.h"
#include "lib/external_libraries/zlib.h"
#include "lib/file/archive/stream.h"
#include "lib/os_path.h"
@ -31,6 +30,7 @@
#include "ps/Filesystem.h"
#include "ps/Profiler2.h"
#include <condition_variable>
#include <fstream>
#include <mutex>
#include <string>
@ -136,22 +136,11 @@ public:
m_Headers = curl_slist_append(m_Headers, "Accept: ");
curl_easy_setopt(m_Curl, CURLOPT_HTTPHEADER, m_Headers);
// Set up the worker thread:
// Use SDL semaphores since OS X doesn't implement sem_init
m_WorkerSem = SDL_CreateSemaphore(0);
ENSURE(m_WorkerSem);
m_WorkerThread = std::thread(RunThread, this);
}
~CUserReporterWorker()
{
// Clean up resources
SDL_DestroySemaphore(m_WorkerSem);
curl_slist_free_all(m_Headers);
curl_easy_cleanup(m_Curl);
}
@ -167,7 +156,7 @@ public:
m_Enabled = enabled;
// Wake up the worker thread
SDL_SemPost(m_WorkerSem);
m_WorkerCV.notify_all();
}
}
@ -186,7 +175,7 @@ public:
}
// Wake up the worker thread
SDL_SemPost(m_WorkerSem);
m_WorkerCV.notify_all();
// Wait for it to shut down cleanly
// TODO: should have a timeout in case of network hangs
@ -215,7 +204,7 @@ public:
}
// Wake up the worker thread
SDL_SemPost(m_WorkerSem);
m_WorkerCV.notify_all();
}
/**
@ -228,7 +217,7 @@ public:
if (now > m_LastUpdateTime + TIMER_CHECK_INTERVAL)
{
// Wake up the worker thread
SDL_SemPost(m_WorkerSem);
m_WorkerCV.notify_all();
m_LastUpdateTime = now;
}
@ -259,7 +248,7 @@ private:
SetStatus("waiting");
/*
* We use a semaphore to let the thread be woken up when it has
* We use a condition_variable to let the thread be woken up when it has
* work to do. Various actions from the main thread can wake it:
* * SetEnabled()
* * Shutdown()
@ -271,19 +260,17 @@ private:
* nothing during the subsequent wakeups). We should never hang due to
* processing fewer actions than wakeups.
*
* Retransmission timeouts are triggered via the main thread - we can't simply
* use SDL_SemWaitTimeout because on Linux it's implemented as an inefficient
* busy-wait loop, and we can't use a manual busy-wait with a long delay time
* because we'd lose responsiveness. So the main thread pings the worker
* occasionally so it can check its timer.
* Retransmission timeouts are triggered via the main thread.
*/
// Wait until the main thread wakes us up
while (true)
{
g_Profiler2.RecordRegionEnter("semaphore wait");
g_Profiler2.RecordRegionEnter("condition_variable wait");
ENSURE(SDL_SemWait(m_WorkerSem) == 0);
std::unique_lock<std::mutex> lock(m_WorkerMutex);
m_WorkerCV.wait(lock, [this] { return m_Enabled || m_Shutdown; });
lock.unlock();
g_Profiler2.RecordRegionLeave();
@ -488,7 +475,7 @@ private:
// Thread-related members:
std::thread m_WorkerThread;
std::mutex m_WorkerMutex;
SDL_sem* m_WorkerSem;
std::condition_variable m_WorkerCV;
// Shared by main thread and worker thread:
// These variables are all protected by m_WorkerMutex