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:
parent
b429d0ce03
commit
62dd922bc0
@ -284,12 +284,6 @@ CTextureConverter::CTextureConverter(PIVFS vfs, bool highQuality) :
|
|||||||
ENSURE(nvtt::version() >= NVTT_VERSION);
|
ENSURE(nvtt::version() >= NVTT_VERSION);
|
||||||
#endif
|
#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);
|
m_WorkerThread = std::thread(RunThread, this);
|
||||||
|
|
||||||
// Maybe we should share some centralised pool of worker threads?
|
// Maybe we should share some centralised pool of worker threads?
|
||||||
@ -304,14 +298,19 @@ CTextureConverter::~CTextureConverter()
|
|||||||
m_Shutdown = true;
|
m_Shutdown = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wake it up so it sees the notification
|
while (true)
|
||||||
SDL_SemPost(m_WorkerSem);
|
{
|
||||||
|
// 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
|
// Wait for it to shut down cleanly
|
||||||
m_WorkerThread.join();
|
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)
|
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
|
// Wake up the worker thread
|
||||||
SDL_SemPost(m_WorkerSem);
|
m_WorkerCV.notify_all();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
@ -527,9 +526,7 @@ bool CTextureConverter::Poll(CTexturePtr& texture, VfsPath& dest, bool& ok)
|
|||||||
bool CTextureConverter::IsBusy()
|
bool CTextureConverter::IsBusy()
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> lock(m_WorkerMutex);
|
std::lock_guard<std::mutex> lock(m_WorkerMutex);
|
||||||
bool busy = !m_RequestQueue.empty();
|
return !m_RequestQueue.empty();
|
||||||
|
|
||||||
return busy;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CTextureConverter::RunThread(CTextureConverter* textureConverter)
|
void CTextureConverter::RunThread(CTextureConverter* textureConverter)
|
||||||
@ -540,15 +537,22 @@ void CTextureConverter::RunThread(CTextureConverter* textureConverter)
|
|||||||
#if CONFIG2_NVTT
|
#if CONFIG2_NVTT
|
||||||
|
|
||||||
// Wait until the main thread wakes us up
|
// 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();
|
g_Profiler2.RecordSyncMarker();
|
||||||
PROFILE2_EVENT("wakeup");
|
PROFILE2_EVENT("wakeup");
|
||||||
|
|
||||||
shared_ptr<ConversionRequest> request;
|
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)
|
if (textureConverter->m_Shutdown)
|
||||||
break;
|
break;
|
||||||
// If we weren't woken up for shutdown, we must have been woken up for
|
// 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
|
result->output.buffer[80] &= ~0x40; // DDPF_RGB in DDS_PIXELFORMAT.dwFlags
|
||||||
|
|
||||||
// Push the result onto the queue
|
// 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);
|
textureConverter->m_ResultQueue.push_back(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::lock_guard<std::mutex> wait_lock(textureConverter->m_WorkerMutex);
|
||||||
|
textureConverter->m_Shutdown = false;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -19,10 +19,10 @@
|
|||||||
#define INCLUDED_TEXTURECONVERTER
|
#define INCLUDED_TEXTURECONVERTER
|
||||||
|
|
||||||
#include "lib/file/vfs/vfs.h"
|
#include "lib/file/vfs/vfs.h"
|
||||||
#include "lib/external_libraries/libsdl.h"
|
|
||||||
|
|
||||||
#include "TextureManager.h"
|
#include "TextureManager.h"
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
@ -208,7 +208,7 @@ private:
|
|||||||
|
|
||||||
std::thread m_WorkerThread;
|
std::thread m_WorkerThread;
|
||||||
std::mutex m_WorkerMutex;
|
std::mutex m_WorkerMutex;
|
||||||
SDL_sem* m_WorkerSem;
|
std::condition_variable m_WorkerCV;
|
||||||
|
|
||||||
struct ConversionRequest;
|
struct ConversionRequest;
|
||||||
struct ConversionResult;
|
struct ConversionResult;
|
||||||
|
@ -341,8 +341,7 @@ public:
|
|||||||
if (m_TextureConverter.Poll(textureOut, dest, ok))
|
if (m_TextureConverter.Poll(textureOut, dest, ok))
|
||||||
return ok;
|
return ok;
|
||||||
|
|
||||||
// Spin-loop is dumb but it works okay for now
|
std::this_thread::sleep_for(std::chrono::microseconds(1));
|
||||||
SDL_Delay(0);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,7 +24,6 @@
|
|||||||
#if HAVE_PCH
|
#if HAVE_PCH
|
||||||
|
|
||||||
#include "SDL.h"
|
#include "SDL.h"
|
||||||
#include "SDL_thread.h"
|
|
||||||
#include "SDL_endian.h"
|
#include "SDL_endian.h"
|
||||||
|
|
||||||
#endif // HAVE_PCH
|
#endif // HAVE_PCH
|
||||||
|
@ -22,7 +22,6 @@
|
|||||||
#include "lib/timer.h"
|
#include "lib/timer.h"
|
||||||
#include "lib/utf8.h"
|
#include "lib/utf8.h"
|
||||||
#include "lib/external_libraries/curl.h"
|
#include "lib/external_libraries/curl.h"
|
||||||
#include "lib/external_libraries/libsdl.h"
|
|
||||||
#include "lib/external_libraries/zlib.h"
|
#include "lib/external_libraries/zlib.h"
|
||||||
#include "lib/file/archive/stream.h"
|
#include "lib/file/archive/stream.h"
|
||||||
#include "lib/os_path.h"
|
#include "lib/os_path.h"
|
||||||
@ -31,6 +30,7 @@
|
|||||||
#include "ps/Filesystem.h"
|
#include "ps/Filesystem.h"
|
||||||
#include "ps/Profiler2.h"
|
#include "ps/Profiler2.h"
|
||||||
|
|
||||||
|
#include <condition_variable>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -136,22 +136,11 @@ public:
|
|||||||
m_Headers = curl_slist_append(m_Headers, "Accept: ");
|
m_Headers = curl_slist_append(m_Headers, "Accept: ");
|
||||||
curl_easy_setopt(m_Curl, CURLOPT_HTTPHEADER, m_Headers);
|
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);
|
m_WorkerThread = std::thread(RunThread, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
~CUserReporterWorker()
|
~CUserReporterWorker()
|
||||||
{
|
{
|
||||||
// Clean up resources
|
|
||||||
|
|
||||||
SDL_DestroySemaphore(m_WorkerSem);
|
|
||||||
|
|
||||||
curl_slist_free_all(m_Headers);
|
curl_slist_free_all(m_Headers);
|
||||||
curl_easy_cleanup(m_Curl);
|
curl_easy_cleanup(m_Curl);
|
||||||
}
|
}
|
||||||
@ -167,7 +156,7 @@ public:
|
|||||||
m_Enabled = enabled;
|
m_Enabled = enabled;
|
||||||
|
|
||||||
// Wake up the worker thread
|
// Wake up the worker thread
|
||||||
SDL_SemPost(m_WorkerSem);
|
m_WorkerCV.notify_all();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,7 +175,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wake up the worker thread
|
// Wake up the worker thread
|
||||||
SDL_SemPost(m_WorkerSem);
|
m_WorkerCV.notify_all();
|
||||||
|
|
||||||
// Wait for it to shut down cleanly
|
// Wait for it to shut down cleanly
|
||||||
// TODO: should have a timeout in case of network hangs
|
// TODO: should have a timeout in case of network hangs
|
||||||
@ -215,7 +204,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wake up the worker thread
|
// 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)
|
if (now > m_LastUpdateTime + TIMER_CHECK_INTERVAL)
|
||||||
{
|
{
|
||||||
// Wake up the worker thread
|
// Wake up the worker thread
|
||||||
SDL_SemPost(m_WorkerSem);
|
m_WorkerCV.notify_all();
|
||||||
|
|
||||||
m_LastUpdateTime = now;
|
m_LastUpdateTime = now;
|
||||||
}
|
}
|
||||||
@ -259,7 +248,7 @@ private:
|
|||||||
SetStatus("waiting");
|
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:
|
* work to do. Various actions from the main thread can wake it:
|
||||||
* * SetEnabled()
|
* * SetEnabled()
|
||||||
* * Shutdown()
|
* * Shutdown()
|
||||||
@ -271,19 +260,17 @@ private:
|
|||||||
* nothing during the subsequent wakeups). We should never hang due to
|
* nothing during the subsequent wakeups). We should never hang due to
|
||||||
* processing fewer actions than wakeups.
|
* processing fewer actions than wakeups.
|
||||||
*
|
*
|
||||||
* Retransmission timeouts are triggered via the main thread - we can't simply
|
* Retransmission timeouts are triggered via the main thread.
|
||||||
* 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.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
// Wait until the main thread wakes us up
|
// Wait until the main thread wakes us up
|
||||||
while (true)
|
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();
|
g_Profiler2.RecordRegionLeave();
|
||||||
|
|
||||||
@ -488,7 +475,7 @@ private:
|
|||||||
// Thread-related members:
|
// Thread-related members:
|
||||||
std::thread m_WorkerThread;
|
std::thread m_WorkerThread;
|
||||||
std::mutex m_WorkerMutex;
|
std::mutex m_WorkerMutex;
|
||||||
SDL_sem* m_WorkerSem;
|
std::condition_variable m_WorkerCV;
|
||||||
|
|
||||||
// Shared by main thread and worker thread:
|
// Shared by main thread and worker thread:
|
||||||
// These variables are all protected by m_WorkerMutex
|
// These variables are all protected by m_WorkerMutex
|
||||||
|
Loading…
Reference in New Issue
Block a user