Use C++11 threads

This commit is contained in:
Tamás Bálint Misius
2019-04-17 00:23:57 +02:00
parent 9d92b77163
commit 2e76b10619
20 changed files with 230 additions and 375 deletions

View File

@@ -21,8 +21,6 @@ namespace http
post_fields_last(NULL) post_fields_last(NULL)
#endif #endif
{ {
pthread_cond_init(&done_cv, NULL);
pthread_mutex_init(&rm_mutex, NULL);
easy = curl_easy_init(); easy = curl_easy_init();
RequestManager::Ref().AddRequest(this); RequestManager::Ref().AddRequest(this);
} }
@@ -36,8 +34,6 @@ namespace http
curl_formfree(post_fields_first); curl_formfree(post_fields_first);
#endif #endif
curl_slist_free_all(headers); curl_slist_free_all(headers);
pthread_mutex_destroy(&rm_mutex);
pthread_cond_destroy(&done_cv);
} }
void Request::AddHeader(ByteString name, ByteString value) void Request::AddHeader(ByteString name, ByteString value)
@@ -179,9 +175,10 @@ namespace http
curl_easy_setopt(easy, CURLOPT_WRITEFUNCTION, Request::WriteDataHandler); curl_easy_setopt(easy, CURLOPT_WRITEFUNCTION, Request::WriteDataHandler);
} }
pthread_mutex_lock(&rm_mutex); {
rm_started = true; std::lock_guard<std::mutex> g(rm_mutex);
pthread_mutex_unlock(&rm_mutex); rm_started = true;
}
RequestManager::Ref().StartRequest(this); RequestManager::Ref().StartRequest(this);
} }
@@ -194,19 +191,18 @@ namespace http
return ""; // shouldn't happen but just in case return ""; // shouldn't happen but just in case
} }
pthread_mutex_lock(&rm_mutex); ByteString response_out;
while (!rm_finished)
{ {
pthread_cond_wait(&done_cv, &rm_mutex); std::unique_lock<std::mutex> l(rm_mutex);
done_cv.wait(l, [this]() { return rm_finished; });
rm_started = false;
rm_canceled = true;
if (status_out)
{
*status_out = status;
}
response_out = std::move(response_body);
} }
rm_started = false;
rm_canceled = true;
if (status_out)
{
*status_out = status;
}
ByteString response_out = std::move(response_body);
pthread_mutex_unlock(&rm_mutex);
RequestManager::Ref().RemoveRequest(this); RequestManager::Ref().RemoveRequest(this);
return response_out; return response_out;
@@ -214,7 +210,7 @@ namespace http
void Request::CheckProgress(int *total, int *done) void Request::CheckProgress(int *total, int *done)
{ {
pthread_mutex_lock(&rm_mutex); std::lock_guard<std::mutex> g(rm_mutex);
if (total) if (total)
{ {
*total = rm_total; *total = rm_total;
@@ -223,43 +219,37 @@ namespace http
{ {
*done = rm_done; *done = rm_done;
} }
pthread_mutex_unlock(&rm_mutex);
} }
// returns true if the request has finished // returns true if the request has finished
bool Request::CheckDone() bool Request::CheckDone()
{ {
pthread_mutex_lock(&rm_mutex); std::lock_guard<std::mutex> g(rm_mutex);
bool ret = rm_finished; return rm_finished;
pthread_mutex_unlock(&rm_mutex);
return ret;
} }
// returns true if the request was canceled // returns true if the request was canceled
bool Request::CheckCanceled() bool Request::CheckCanceled()
{ {
pthread_mutex_lock(&rm_mutex); std::lock_guard<std::mutex> g(rm_mutex);
bool ret = rm_canceled; return rm_canceled;
pthread_mutex_unlock(&rm_mutex);
return ret;
} }
// returns true if the request is running // returns true if the request is running
bool Request::CheckStarted() bool Request::CheckStarted()
{ {
pthread_mutex_lock(&rm_mutex); std::lock_guard<std::mutex> g(rm_mutex);
bool ret = rm_started; return rm_started;
pthread_mutex_unlock(&rm_mutex);
return ret;
} }
// cancels the request, the request thread will delete the Request* when it finishes (do not use Request in any way after canceling) // cancels the request, the request thread will delete the Request* when it finishes (do not use Request in any way after canceling)
void Request::Cancel() void Request::Cancel()
{ {
pthread_mutex_lock(&rm_mutex); {
rm_canceled = true; std::lock_guard<std::mutex> g(rm_mutex);
pthread_mutex_unlock(&rm_mutex); rm_canceled = true;
}
RequestManager::Ref().RemoveRequest(this); RequestManager::Ref().RemoveRequest(this);
} }

View File

@@ -3,10 +3,10 @@
#include <map> #include <map>
#include "common/tpt-minmax.h" // for MSVC, ensures windows.h doesn't cause compile errors by defining min/max #include "common/tpt-minmax.h" // for MSVC, ensures windows.h doesn't cause compile errors by defining min/max
#include "common/tpt-thread.h" #include <mutex>
#include <condition_variable>
#include <curl/curl.h> #include <curl/curl.h>
#include "common/String.h" #include "common/String.h"
#undef GetUserName // pthreads defines this, breaks stuff
#if defined(CURL_AT_LEAST_VERSION) && CURL_AT_LEAST_VERSION(7, 55, 0) #if defined(CURL_AT_LEAST_VERSION) && CURL_AT_LEAST_VERSION(7, 55, 0)
# define REQUEST_USE_CURL_OFFSET_T # define REQUEST_USE_CURL_OFFSET_T
@@ -32,7 +32,7 @@ namespace http
volatile bool rm_finished; volatile bool rm_finished;
volatile bool rm_canceled; volatile bool rm_canceled;
volatile bool rm_started; volatile bool rm_started;
pthread_mutex_t rm_mutex; std::mutex rm_mutex;
bool added_to_multi; bool added_to_multi;
int status; int status;
@@ -46,7 +46,7 @@ namespace http
std::map<ByteString, ByteString> post_fields_map; std::map<ByteString, ByteString> post_fields_map;
#endif #endif
pthread_cond_t done_cv; std::condition_variable done_cv;
static size_t WriteDataHandler(char * ptr, size_t size, size_t count, void * userdata); static size_t WriteDataHandler(char * ptr, size_t size, size_t count, void * userdata);

View File

@@ -21,36 +21,27 @@ namespace http
rt_shutting_down(false), rt_shutting_down(false),
multi(NULL) multi(NULL)
{ {
pthread_cond_init(&rt_cv, NULL);
pthread_mutex_init(&rt_mutex, NULL);
} }
RequestManager::~RequestManager() RequestManager::~RequestManager()
{ {
pthread_mutex_destroy(&rt_mutex);
pthread_cond_destroy(&rt_cv);
} }
void RequestManager::Shutdown() void RequestManager::Shutdown()
{ {
pthread_mutex_lock(&rt_mutex); {
rt_shutting_down = true; std::lock_guard<std::mutex> g(rt_mutex);
pthread_cond_signal(&rt_cv); rt_shutting_down = true;
pthread_mutex_unlock(&rt_mutex); }
rt_cv.notify_one();
pthread_join(worker_thread, NULL); worker_thread.join();
curl_multi_cleanup(multi); curl_multi_cleanup(multi);
multi = NULL; multi = NULL;
curl_global_cleanup(); curl_global_cleanup();
} }
TH_ENTRY_POINT void *RequestManager::RequestManagerHelper(void *obj)
{
((RequestManager *)obj)->Worker();
return NULL;
}
void RequestManager::Initialise(ByteString Proxy) void RequestManager::Initialise(ByteString Proxy)
{ {
curl_global_init(CURL_GLOBAL_DEFAULT); curl_global_init(CURL_GLOBAL_DEFAULT);
@@ -64,7 +55,7 @@ namespace http
user_agent = ByteString::Build("PowderToy/", SAVE_VERSION, ".", MINOR_VERSION, " (", IDENT_PLATFORM, "; ", IDENT_BUILD, "; M", MOD_ID, ") TPTPP/", SAVE_VERSION, ".", MINOR_VERSION, ".", BUILD_NUM, IDENT_RELTYPE, ".", SNAPSHOT_ID); user_agent = ByteString::Build("PowderToy/", SAVE_VERSION, ".", MINOR_VERSION, " (", IDENT_PLATFORM, "; ", IDENT_BUILD, "; M", MOD_ID, ") TPTPP/", SAVE_VERSION, ".", MINOR_VERSION, ".", BUILD_NUM, IDENT_RELTYPE, ".", SNAPSHOT_ID);
pthread_create(&worker_thread, NULL, &RequestManager::RequestManagerHelper, this); worker_thread = std::thread([this]() { Worker(); });
} }
void RequestManager::Worker() void RequestManager::Worker()
@@ -72,24 +63,25 @@ namespace http
bool shutting_down = false; bool shutting_down = false;
while (!shutting_down) while (!shutting_down)
{ {
pthread_mutex_lock(&rt_mutex);
if (!requests_added_to_multi)
{ {
while (!rt_shutting_down && requests_to_add.empty() && !requests_to_start && !requests_to_remove) std::unique_lock<std::mutex> l(rt_mutex);
if (!requests_added_to_multi)
{ {
pthread_cond_wait(&rt_cv, &rt_mutex); while (!rt_shutting_down && requests_to_add.empty() && !requests_to_start && !requests_to_remove)
{
rt_cv.wait(l);
}
} }
shutting_down = rt_shutting_down;
requests_to_remove = false;
requests_to_start = false;
for (Request *request : requests_to_add)
{
request->status = 0;
requests.insert(request);
}
requests_to_add.clear();
} }
shutting_down = rt_shutting_down;
requests_to_remove = false;
requests_to_start = false;
for (Request *request : requests_to_add)
{
request->status = 0;
requests.insert(request);
}
requests_to_add.clear();
pthread_mutex_unlock(&rt_mutex);
if (multi && requests_added_to_multi) if (multi && requests_added_to_multi)
{ {
@@ -157,52 +149,60 @@ namespace http
std::set<Request *> requests_to_remove; std::set<Request *> requests_to_remove;
for (Request *request : requests) for (Request *request : requests)
{ {
pthread_mutex_lock(&request->rm_mutex); bool signal_done = false;
if (shutting_down)
{ {
// In the weird case that a http::Request::Simple* call is std::lock_guard<std::mutex> g(request->rm_mutex);
// waiting on this Request, we should fail the request if (shutting_down)
// instead of cancelling it ourselves.
request->status = 610;
}
if (!request->rm_canceled && request->rm_started && !request->added_to_multi && !request->status)
{
if (multi && request->easy)
{ {
MultiAdd(request); // In the weird case that a http::Request::Simple* call is
// waiting on this Request, we should fail the request
// instead of cancelling it ourselves.
request->status = 610;
} }
else if (!request->rm_canceled && request->rm_started && !request->added_to_multi && !request->status)
{ {
request->status = 604; if (multi && request->easy)
{
MultiAdd(request);
}
else
{
request->status = 604;
}
} }
} if (!request->rm_canceled && request->rm_started && !request->rm_finished)
if (!request->rm_canceled && request->rm_started && !request->rm_finished)
{
if (multi && request->easy)
{ {
if (multi && request->easy)
{
#ifdef REQUEST_USE_CURL_OFFSET_T #ifdef REQUEST_USE_CURL_OFFSET_T
curl_easy_getinfo(request->easy, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &request->rm_total); curl_easy_getinfo(request->easy, CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &request->rm_total);
curl_easy_getinfo(request->easy, CURLINFO_SIZE_DOWNLOAD_T, &request->rm_done); curl_easy_getinfo(request->easy, CURLINFO_SIZE_DOWNLOAD_T, &request->rm_done);
#else #else
double total, done; double total, done;
curl_easy_getinfo(request->easy, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &total); curl_easy_getinfo(request->easy, CURLINFO_CONTENT_LENGTH_DOWNLOAD, &total);
curl_easy_getinfo(request->easy, CURLINFO_SIZE_DOWNLOAD, &done); curl_easy_getinfo(request->easy, CURLINFO_SIZE_DOWNLOAD, &done);
request->rm_total = (curl_off_t)total; request->rm_total = (curl_off_t)total;
request->rm_done = (curl_off_t)done; request->rm_done = (curl_off_t)done;
#endif #endif
}
if (request->status)
{
request->rm_finished = true;
MultiRemove(request);
signal_done = true;
}
} }
if (request->status) if (request->rm_canceled)
{ {
request->rm_finished = true; requests_to_remove.insert(request);
MultiRemove(request);
pthread_cond_signal(&request->done_cv);
} }
} }
if (request->rm_canceled)
if (signal_done)
{ {
requests_to_remove.insert(request); request->done_cv.notify_one();
} }
pthread_mutex_unlock(&request->rm_mutex);
} }
for (Request *request : requests_to_remove) for (Request *request : requests_to_remove)
{ {
@@ -235,25 +235,28 @@ namespace http
void RequestManager::AddRequest(Request *request) void RequestManager::AddRequest(Request *request)
{ {
pthread_mutex_lock(&rt_mutex); {
requests_to_add.insert(request); std::lock_guard<std::mutex> g(rt_mutex);
pthread_cond_signal(&rt_cv); requests_to_add.insert(request);
pthread_mutex_unlock(&rt_mutex); }
rt_cv.notify_one();
} }
void RequestManager::StartRequest(Request *request) void RequestManager::StartRequest(Request *request)
{ {
pthread_mutex_lock(&rt_mutex); {
requests_to_start = true; std::lock_guard<std::mutex> g(rt_mutex);
pthread_cond_signal(&rt_cv); requests_to_start = true;
pthread_mutex_unlock(&rt_mutex); }
rt_cv.notify_one();
} }
void RequestManager::RemoveRequest(Request *request) void RequestManager::RemoveRequest(Request *request)
{ {
pthread_mutex_lock(&rt_mutex); {
requests_to_remove = true; std::lock_guard<std::mutex> g(rt_mutex);
pthread_cond_signal(&rt_cv); requests_to_remove = true;
pthread_mutex_unlock(&rt_mutex); }
rt_cv.notify_one();
} }
} }

View File

@@ -2,20 +2,21 @@
#define REQUESTMANAGER_H #define REQUESTMANAGER_H
#include "common/tpt-minmax.h" // for MSVC, ensures windows.h doesn't cause compile errors by defining min/max #include "common/tpt-minmax.h" // for MSVC, ensures windows.h doesn't cause compile errors by defining min/max
#include "common/tpt-thread.h" #include <thread>
#include <mutex>
#include <condition_variable>
#include <ctime> #include <ctime>
#include <set> #include <set>
#include <curl/curl.h> #include <curl/curl.h>
#include "common/Singleton.h" #include "common/Singleton.h"
#include "common/String.h" #include "common/String.h"
#undef GetUserName // pthreads (included by curl) defines this, breaks stuff
namespace http namespace http
{ {
class Request; class Request;
class RequestManager : public Singleton<RequestManager> class RequestManager : public Singleton<RequestManager>
{ {
pthread_t worker_thread; std::thread worker_thread;
std::set<Request *> requests; std::set<Request *> requests;
int requests_added_to_multi; int requests_added_to_multi;
@@ -23,8 +24,8 @@ namespace http
bool requests_to_start; bool requests_to_start;
bool requests_to_remove; bool requests_to_remove;
bool rt_shutting_down; bool rt_shutting_down;
pthread_mutex_t rt_mutex; std::mutex rt_mutex;
pthread_cond_t rt_cv; std::condition_variable rt_cv;
CURLM *multi; CURLM *multi;
@@ -36,8 +37,6 @@ namespace http
void StartRequest(Request *request); void StartRequest(Request *request);
void RemoveRequest(Request *request); void RemoveRequest(Request *request);
static TH_ENTRY_POINT void *RequestManagerHelper(void *obj);
public: public:
RequestManager(); RequestManager();
~RequestManager(); ~RequestManager();

View File

@@ -4,7 +4,6 @@
#include <limits> #include <limits>
#include <stdexcept> #include <stdexcept>
#include "common/tpt-thread.h"
#include "String.h" #include "String.h"
ByteString ConversionError::formatError(ByteString::value_type const *at, ByteString::value_type const *upto) ByteString ConversionError::formatError(ByteString::value_type const *at, ByteString::value_type const *upto)
@@ -374,31 +373,10 @@ struct LocaleImpl
} }
}; };
static void destroyLocaleImpl(void *ptr)
{
delete static_cast<LocaleImpl *>(ptr);
}
static pthread_once_t localeOnce = PTHREAD_ONCE_INIT;
static pthread_key_t localeKey;
static void createLocaleKey()
{
if(int error = pthread_key_create(&localeKey, destroyLocaleImpl))
throw std::system_error(error, std::system_category(), "Could not create TLS key for LocaleImpl");
}
static LocaleImpl *getLocaleImpl() static LocaleImpl *getLocaleImpl()
{ {
pthread_once(&localeOnce, createLocaleKey); thread_local LocaleImpl li;
void *ptr = pthread_getspecific(localeKey); return &li;
if(!ptr)
{
ptr = static_cast<void *>(new LocaleImpl());
if(int error = pthread_setspecific(localeKey, ptr))
throw std::system_error(error, std::system_category(), "Could not put LocaleImpl into TLS");
}
return static_cast<LocaleImpl *>(ptr);
} }
ByteString ByteStringBuilder::Build() const ByteString ByteStringBuilder::Build() const

View File

@@ -1,26 +0,0 @@
#ifndef TPT_THREAD_H
#define TPT_THREAD_H
#if defined(WIN) && defined(__GNUC__)
#define TH_ENTRY_POINT __attribute__((force_align_arg_pointer))
#define _TIMESPEC_DEFINED
#else
#define TH_ENTRY_POINT
#endif
// fix 'timespec' error in VS 2015
#if defined(_MSC_VER) && (_MSC_VER >= 1900)
#define _TIMESPEC_DEFINED 1
#endif
#include <pthread.h>
#undef GetUserName
// Fix deprecation warnings with recent pthread versions on Windows
#if defined(_PTW32_STATIC_LIB) && defined(WIN)
#if PTW32_VERSION <= 2, 8, 0, 0
#define PTW32_STATIC_LIB
#endif
#endif
#endif

View File

@@ -128,9 +128,6 @@ public:
VideoBuffer DumpFrame(); VideoBuffer DumpFrame();
void Acquire();
void Release();
void blendpixel(int x, int y, int r, int g, int b, int a); void blendpixel(int x, int y, int r, int g, int b, int a);
void addpixel(int x, int y, int r, int g, int b, int a); void addpixel(int x, int y, int r, int g, int b, int a);

View File

@@ -1,22 +1,12 @@
#include "Graphics.h" #include "Graphics.h"
#include "FontReader.h" #include "FontReader.h"
#include "common/tpt-thread.h"
#ifdef OGLI #ifdef OGLI
static pthread_mutex_t gMutex = PTHREAD_MUTEX_INITIALIZER;
//static pthread_mutex_t TMPMUT = PTHREAD_MUTEX_INITIALIZER;
Graphics::Graphics(): Graphics::Graphics():
sdl_scale(1) sdl_scale(1)
{ {
// if(gMutex == TMPMUT)
// pthread_mutex_init (&gMutex, NULL);
LoadDefaults(); LoadDefaults();
InitialiseTextures(); InitialiseTextures();
//Texture for main UI
} }
void Graphics::LoadDefaults() void Graphics::LoadDefaults()
@@ -68,16 +58,6 @@ void Graphics::DestroyTextures()
//Todo... //Todo...
} }
void Graphics::Acquire()
{
pthread_mutex_lock(&gMutex);
}
void Graphics::Release()
{
pthread_mutex_unlock(&gMutex);
}
Graphics::~Graphics() Graphics::~Graphics()
{ {
} }

View File

@@ -9,16 +9,6 @@ sdl_scale(1)
} }
void Graphics::Acquire()
{
}
void Graphics::Release()
{
}
Graphics::~Graphics() Graphics::~Graphics()
{ {
free(vid); free(vid);

View File

@@ -225,7 +225,6 @@ void Engine::Draw()
{ {
if(lastBuffer && !(state_ && state_->Position.X == 0 && state_->Position.Y == 0 && state_->Size.X == width_ && state_->Size.Y == height_)) if(lastBuffer && !(state_ && state_->Position.X == 0 && state_->Position.Y == 0 && state_->Size.X == width_ && state_->Size.Y == height_))
{ {
g->Acquire();
g->Clear(); g->Clear();
#ifndef OGLI #ifndef OGLI
memcpy(g->vid, lastBuffer, (width_ * height_) * PIXELSIZE); memcpy(g->vid, lastBuffer, (width_ * height_) * PIXELSIZE);
@@ -242,7 +241,6 @@ void Engine::Draw()
state_->DoDraw(); state_->DoDraw();
g->Finalise(); g->Finalise();
g->Release();
FrameIndex++; FrameIndex++;
FrameIndex %= 7200; FrameIndex %= 7200;
} }

View File

@@ -3,6 +3,8 @@
#include "client/Client.h" #include "client/Client.h"
#include <thread>
SearchModel::SearchModel(): SearchModel::SearchModel():
loadedSave(NULL), loadedSave(NULL),
currentSort("best"), currentSort("best"),
@@ -14,8 +16,10 @@ SearchModel::SearchModel():
saveListLoaded(false), saveListLoaded(false),
updateSaveListWorking(false), updateSaveListWorking(false),
updateSaveListFinished(false), updateSaveListFinished(false),
updateSaveListResult(nullptr),
updateTagListWorking(false), updateTagListWorking(false),
updateTagListFinished(false) updateTagListFinished(false),
updateTagListResult(nullptr)
{ {
} }
@@ -29,36 +33,26 @@ bool SearchModel::GetShowTags()
return showTags; return showTags;
} }
TH_ENTRY_POINT void * SearchModel::updateSaveListTHelper(void * obj) void SearchModel::updateSaveListT()
{
return ((SearchModel *)obj)->updateSaveListT();
}
void * SearchModel::updateSaveListT()
{ {
ByteString category = ""; ByteString category = "";
if(showFavourite) if(showFavourite)
category = "Favourites"; category = "Favourites";
if(showOwn && Client::Ref().GetAuthUser().UserID) if(showOwn && Client::Ref().GetAuthUser().UserID)
category = "by:"+Client::Ref().GetAuthUser().Username; category = "by:"+Client::Ref().GetAuthUser().Username;
vector<SaveInfo*> * saveList = Client::Ref().SearchSaves((currentPage-1)*20, 20, lastQuery, currentSort=="new"?"date":"votes", category, thResultCount); std::vector<SaveInfo*> * saveList = Client::Ref().SearchSaves((currentPage-1)*20, 20, lastQuery, currentSort=="new"?"date":"votes", category, thResultCount);
updateSaveListResult = saveList;
updateSaveListFinished = true; updateSaveListFinished = true;
return saveList;
} }
TH_ENTRY_POINT void * SearchModel::updateTagListTHelper(void * obj) void SearchModel::updateTagListT()
{
return ((SearchModel *)obj)->updateTagListT();
}
void * SearchModel::updateTagListT()
{ {
int tagResultCount; int tagResultCount;
std::vector<std::pair<ByteString, int> > * tagList = Client::Ref().GetTags(0, 24, "", tagResultCount); std::vector<std::pair<ByteString, int> > * tagList = Client::Ref().GetTags(0, 24, "", tagResultCount);
updateTagListResult = tagList;
updateTagListFinished = true; updateTagListFinished = true;
return tagList;
} }
bool SearchModel::UpdateSaveList(int pageNumber, String query) bool SearchModel::UpdateSaveList(int pageNumber, String query)
@@ -88,12 +82,12 @@ bool SearchModel::UpdateSaveList(int pageNumber, String query)
{ {
updateTagListFinished = false; updateTagListFinished = false;
updateTagListWorking = true; updateTagListWorking = true;
pthread_create(&updateTagListThread, 0, &SearchModel::updateTagListTHelper, this); std::thread([this]() { updateTagListT(); }).detach();
} }
updateSaveListFinished = false; updateSaveListFinished = false;
updateSaveListWorking = true; updateSaveListWorking = true;
pthread_create(&updateSaveListThread, 0, &SearchModel::updateSaveListTHelper, this); std::thread([this]() { updateSaveListT(); }).detach();
return true; return true;
} }
return false; return false;
@@ -117,12 +111,12 @@ SaveInfo * SearchModel::GetLoadedSave(){
return loadedSave; return loadedSave;
} }
vector<SaveInfo*> SearchModel::GetSaveList() std::vector<SaveInfo*> SearchModel::GetSaveList()
{ {
return saveList; return saveList;
} }
vector<pair<ByteString, int> > SearchModel::GetTagList() std::vector<std::pair<ByteString, int> > SearchModel::GetTagList()
{ {
return tagList; return tagList;
} }
@@ -137,8 +131,8 @@ void SearchModel::Update()
lastError = ""; lastError = "";
saveListLoaded = true; saveListLoaded = true;
vector<SaveInfo*> * tempSaveList; std::vector<SaveInfo *> *tempSaveList = updateSaveListResult;
pthread_join(updateSaveListThread, (void**)&tempSaveList); updateSaveListResult = nullptr;
if(tempSaveList) if(tempSaveList)
{ {
@@ -164,8 +158,8 @@ void SearchModel::Update()
{ {
updateTagListWorking = false; updateTagListWorking = false;
vector<pair<ByteString, int> > * tempTagList; std::vector<std::pair<ByteString, int>> *tempTagList = updateTagListResult;
pthread_join(updateTagListThread, (void**)&tempTagList); updateTagListResult = nullptr;
if(tempTagList) if(tempTagList)
{ {

View File

@@ -4,13 +4,11 @@
#include <vector> #include <vector>
#include "common/String.h" #include "common/String.h"
#include "common/tpt-minmax.h" #include "common/tpt-minmax.h"
#include "common/tpt-thread.h" #include <atomic>
#include <cmath> #include <cmath>
#include "client/SaveInfo.h" #include "client/SaveInfo.h"
#include "SearchView.h" #include "SearchView.h"
using namespace std;
class SearchView; class SearchView;
class SearchModel class SearchModel
{ {
@@ -19,10 +17,10 @@ private:
ByteString currentSort; ByteString currentSort;
String lastQuery; String lastQuery;
String lastError; String lastError;
vector<int> selected; std::vector<int> selected;
vector<SearchView*> observers; std::vector<SearchView*> observers;
vector<SaveInfo*> saveList; std::vector<SaveInfo*> saveList;
vector<pair<ByteString, int> > tagList; std::vector<std::pair<ByteString, int> > tagList;
int currentPage; int currentPage;
int resultCount; int resultCount;
int thResultCount; int thResultCount;
@@ -40,16 +38,14 @@ private:
//Variables and methods for background save request //Variables and methods for background save request
bool saveListLoaded; bool saveListLoaded;
bool updateSaveListWorking; bool updateSaveListWorking;
volatile bool updateSaveListFinished; std::atomic<bool> updateSaveListFinished;
pthread_t updateSaveListThread; void updateSaveListT();
TH_ENTRY_POINT static void * updateSaveListTHelper(void * obj); std::vector<SaveInfo *> *updateSaveListResult;
void * updateSaveListT();
bool updateTagListWorking; bool updateTagListWorking;
volatile bool updateTagListFinished; std::atomic<bool> updateTagListFinished;
pthread_t updateTagListThread; void updateTagListT();
TH_ENTRY_POINT static void * updateTagListTHelper(void * obj); std::vector<std::pair<ByteString, int>> *updateTagListResult;
void * updateTagListT();
public: public:
SearchModel(); SearchModel();
virtual ~SearchModel(); virtual ~SearchModel();
@@ -58,8 +54,8 @@ public:
bool GetShowTags(); bool GetShowTags();
void AddObserver(SearchView * observer); void AddObserver(SearchView * observer);
bool UpdateSaveList(int pageNumber, String query); bool UpdateSaveList(int pageNumber, String query);
vector<SaveInfo*> GetSaveList(); std::vector<SaveInfo*> GetSaveList();
vector<pair<ByteString, int> > GetTagList(); std::vector<std::pair<ByteString, int> > GetTagList();
String GetLastError() { return lastError; } String GetLastError() { return lastError; }
int GetPageCount() int GetPageCount()
{ {
@@ -79,7 +75,7 @@ public:
void SetLoadedSave(SaveInfo * save); void SetLoadedSave(SaveInfo * save);
SaveInfo * GetLoadedSave(); SaveInfo * GetLoadedSave();
bool GetSavesLoaded() { return saveListLoaded; } bool GetSavesLoaded() { return saveListLoaded; }
vector<int> GetSelected() { return selected; } std::vector<int> GetSelected() { return selected; }
void ClearSelected() { selected.clear(); notifySelectedChanged(); } void ClearSelected() { selected.clear(); notifySelectedChanged(); }
void SelectSave(int saveID); void SelectSave(int saveID);
void DeselectSave(int saveID); void DeselectSave(int saveID);

View File

@@ -1,6 +1,5 @@
#include <cmath> #include <cmath>
#include <sys/types.h> #include <sys/types.h>
#include "common/tpt-thread.h"
#include "Config.h" #include "Config.h"
#include "Gravity.h" #include "Gravity.h"
#include "Misc.h" #include "Misc.h"
@@ -85,13 +84,15 @@ void Gravity::gravity_update_async()
int result; int result;
if (ngrav_enable) if (ngrav_enable)
{ {
if (!pthread_mutex_trylock(&gravmutex)) bool signal_grav = false;
{ {
result = grav_ready; std::unique_lock<std::mutex> l(gravmutex, std::defer_lock);
if (result) //Did the gravity thread finish? if (l.try_lock())
{ {
//if (!sys_pause||framerender){ //Only update if not paused result = grav_ready;
//Switch the full size gravmaps, we don't really need the two above any more if (result) //Did the gravity thread finish?
{
float *tmpf; float *tmpf;
if (th_gravchanged && !ignoreNextResult) if (th_gravchanged && !ignoreNextResult)
@@ -121,10 +122,14 @@ void Gravity::gravity_update_async()
th_gravmap = tmpf; th_gravmap = tmpf;
grav_ready = 0; //Tell the other thread that we're ready for it to continue grav_ready = 0; //Tell the other thread that we're ready for it to continue
pthread_cond_signal(&gravcv); signal_grav = true;
//} }
}
if (signal_grav)
{
gravcv.notify_one();
} }
pthread_mutex_unlock(&gravmutex);
} }
//Apply the gravity mask //Apply the gravity mask
membwand(gravy, gravmask, (XRES/CELL)*(YRES/CELL)*sizeof(float), (XRES/CELL)*(YRES/CELL)*sizeof(unsigned)); membwand(gravy, gravmask, (XRES/CELL)*(YRES/CELL)*sizeof(float), (XRES/CELL)*(YRES/CELL)*sizeof(unsigned));
@@ -133,12 +138,6 @@ void Gravity::gravity_update_async()
} }
} }
TH_ENTRY_POINT void *Gravity::update_grav_async_helper(void * context)
{
((Gravity *)context)->update_grav_async();
return NULL;
}
void Gravity::update_grav_async() void Gravity::update_grav_async()
{ {
int done = 0; int done = 0;
@@ -155,7 +154,8 @@ void Gravity::update_grav_async()
if (!grav_fft_status) if (!grav_fft_status)
grav_fft_init(); grav_fft_init();
#endif #endif
pthread_mutex_lock(&gravmutex);
std::unique_lock<std::mutex> l(gravmutex);
while (!thread_done) while (!thread_done)
{ {
if (!done) if (!done)
@@ -167,13 +167,11 @@ void Gravity::update_grav_async()
thread_done = gravthread_done; thread_done = gravthread_done;
} else { } else {
// wait for main thread // wait for main thread
pthread_cond_wait(&gravcv, &gravmutex); gravcv.wait(l);
done = grav_ready; done = grav_ready;
thread_done = gravthread_done; thread_done = gravthread_done;
} }
} }
pthread_mutex_unlock(&gravmutex);
pthread_exit(NULL);
} }
void Gravity::start_grav_async() void Gravity::start_grav_async()
@@ -183,9 +181,7 @@ void Gravity::start_grav_async()
gravthread_done = 0; gravthread_done = 0;
grav_ready = 0; grav_ready = 0;
pthread_mutex_init (&gravmutex, NULL); gravthread = std::thread([this]() { update_grav_async(); }); //Start asynchronous gravity simulation
pthread_cond_init(&gravcv, NULL);
pthread_create(&gravthread, NULL, &Gravity::update_grav_async_helper, this); //Start asynchronous gravity simulation
ngrav_enable = 1; ngrav_enable = 1;
memset(gravy, 0, (XRES/CELL)*(YRES/CELL)*sizeof(float)); memset(gravy, 0, (XRES/CELL)*(YRES/CELL)*sizeof(float));
@@ -198,12 +194,12 @@ void Gravity::stop_grav_async()
{ {
if (ngrav_enable) if (ngrav_enable)
{ {
pthread_mutex_lock(&gravmutex); {
gravthread_done = 1; std::lock_guard<std::mutex> g(gravmutex);
pthread_cond_signal(&gravcv); gravthread_done = 1;
pthread_mutex_unlock(&gravmutex); }
pthread_join(gravthread, NULL); gravcv.notify_one();
pthread_mutex_destroy(&gravmutex); //Destroy the mutex gravthread.join();
ngrav_enable = 0; ngrav_enable = 0;
} }
//Clear the grav velocities //Clear the grav velocities

View File

@@ -1,7 +1,9 @@
#ifndef GRAVITY_H #ifndef GRAVITY_H
#define GRAVITY_H #define GRAVITY_H
#include "common/tpt-thread.h" #include <thread>
#include <mutex>
#include <condition_variable>
#include "Config.h" #include "Config.h"
#include "Simulation.h" #include "Simulation.h"
@@ -18,28 +20,6 @@ struct mask_el {
}; };
typedef struct mask_el mask_el; typedef struct mask_el mask_el;
/*
* float *gravmap = NULL;//Maps to be used by the main thread
float *gravp = NULL;
float *gravy = NULL;
float *gravx = NULL;
unsigned *gravmask = NULL;
float *th_ogravmap = NULL;// Maps to be processed by the gravity thread
float *th_gravmap = NULL;
float *th_gravx = NULL;
float *th_gravy = NULL;
float *th_gravp = NULL;
int th_gravchanged = 0;
pthread_t gravthread;
pthread_mutex_t gravmutex;
pthread_cond_t gravcv;
int grav_ready = 0;
int gravthread_done = 0;
*/
class Gravity class Gravity
{ {
private: private:
@@ -52,9 +32,9 @@ private:
int th_gravchanged; int th_gravchanged;
pthread_t gravthread; std::thread gravthread;
pthread_mutex_t gravmutex; std::mutex gravmutex;
pthread_cond_t gravcv; std::condition_variable gravcv;
int grav_ready; int grav_ready;
int gravthread_done; int gravthread_done;
@@ -84,7 +64,6 @@ public:
void gravity_cleanup(); void gravity_cleanup();
void gravity_update_async(); void gravity_update_async();
TH_ENTRY_POINT static void *update_grav_async_helper(void * context);
void update_grav_async(); void update_grav_async();
void start_grav_async(); void start_grav_async();

View File

@@ -29,13 +29,11 @@ SaveRenderer::SaveRenderer(){
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // Reset framebuffer binding glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); // Reset framebuffer binding
glDisable(GL_TEXTURE_2D); glDisable(GL_TEXTURE_2D);
#endif #endif
pthread_mutex_init(&renderMutex, NULL);
} }
VideoBuffer * SaveRenderer::Render(GameSave * save, bool decorations, bool fire) VideoBuffer * SaveRenderer::Render(GameSave * save, bool decorations, bool fire)
{ {
pthread_mutex_lock(&renderMutex); std::lock_guard<std::mutex> gx(renderMutex);
int width, height; int width, height;
VideoBuffer * tempThumb = NULL; VideoBuffer * tempThumb = NULL;
@@ -43,7 +41,6 @@ VideoBuffer * SaveRenderer::Render(GameSave * save, bool decorations, bool fire)
height = save->blockHeight; height = save->blockHeight;
bool doCollapse = save->Collapsed(); bool doCollapse = save->Collapsed();
g->Acquire();
g->Clear(); g->Clear();
sim->clear_sim(); sim->clear_sim();
@@ -148,15 +145,13 @@ VideoBuffer * SaveRenderer::Render(GameSave * save, bool decorations, bool fire)
} }
if(doCollapse) if(doCollapse)
save->Collapse(); save->Collapse();
g->Release();
pthread_mutex_unlock(&renderMutex);
return tempThumb; return tempThumb;
} }
VideoBuffer * SaveRenderer::Render(unsigned char * saveData, int dataSize, bool decorations, bool fire) VideoBuffer * SaveRenderer::Render(unsigned char * saveData, int dataSize, bool decorations, bool fire)
{ {
pthread_mutex_lock(&renderMutex); std::lock_guard<std::mutex> g(renderMutex);
GameSave * tempSave; GameSave * tempSave;
try { try {
@@ -167,17 +162,15 @@ VideoBuffer * SaveRenderer::Render(unsigned char * saveData, int dataSize, bool
VideoBuffer * buffer = new VideoBuffer(64, 64); VideoBuffer * buffer = new VideoBuffer(64, 64);
buffer->BlendCharacter(32, 32, 'x', 255, 255, 255, 255); buffer->BlendCharacter(32, 32, 'x', 255, 255, 255, 255);
pthread_mutex_unlock(&renderMutex);
return buffer; return buffer;
} }
VideoBuffer * thumb = Render(tempSave, decorations, fire); VideoBuffer * thumb = Render(tempSave, decorations, fire);
delete tempSave; delete tempSave;
pthread_mutex_unlock(&renderMutex);
return thumb; return thumb;
} }
SaveRenderer::~SaveRenderer() { SaveRenderer::~SaveRenderer()
pthread_mutex_destroy(&renderMutex); {
} }

View File

@@ -4,7 +4,7 @@
#include "graphics/OpenGLHeaders.h" #include "graphics/OpenGLHeaders.h"
#endif #endif
#include "common/Singleton.h" #include "common/Singleton.h"
#include "common/tpt-thread.h" #include <mutex>
class GameSave; class GameSave;
class VideoBuffer; class VideoBuffer;
@@ -16,7 +16,7 @@ class SaveRenderer: public Singleton<SaveRenderer> {
Graphics * g; Graphics * g;
Simulation * sim; Simulation * sim;
Renderer * ren; Renderer * ren;
pthread_mutex_t renderMutex; std::mutex renderMutex;
public: public:
SaveRenderer(); SaveRenderer();
VideoBuffer * Render(GameSave * save, bool decorations = true, bool fire = true); VideoBuffer * Render(GameSave * save, bool decorations = true, bool fire = true);

View File

@@ -5,11 +5,13 @@
void AbandonableTask::doWork_wrapper() void AbandonableTask::doWork_wrapper()
{ {
Task::doWork_wrapper(); Task::doWork_wrapper();
pthread_cond_signal(&done_cv); done_cv.notify_one();
pthread_mutex_lock(&taskMutex); bool abandoned;
bool abandoned = thAbandoned; {
pthread_mutex_unlock(&taskMutex); std::lock_guard<std::mutex> g(taskMutex);
abandoned = thAbandoned;
}
if (abandoned) if (abandoned)
{ {
delete this; delete this;
@@ -18,12 +20,10 @@ void AbandonableTask::doWork_wrapper()
void AbandonableTask::Finish() void AbandonableTask::Finish()
{ {
pthread_mutex_lock(&taskMutex);
while (!thDone)
{ {
pthread_cond_wait(&done_cv, &taskMutex); std::unique_lock<std::mutex> l(taskMutex);
done_cv.wait(l, [this]() { return thDone; });
} }
pthread_mutex_unlock(&taskMutex);
// Poll to make sure that the rest of the Task knows that it's // Poll to make sure that the rest of the Task knows that it's
// done, not just us. This has to be done because the thread that started // done, not just us. This has to be done because the thread that started
@@ -37,23 +37,24 @@ void AbandonableTask::Finish()
void AbandonableTask::Abandon() void AbandonableTask::Abandon()
{ {
bool delete_this = false; bool delete_this = false;
pthread_mutex_lock(&taskMutex);
if (thDone)
{ {
// If thDone is true, the thread has already finished. We're std::lock_guard<std::mutex> g(taskMutex);
// not calling Poll because it may call callbacks, which if (thDone)
// an abandoned task shouldn't do. Instead we just delete the {
// AbandonableTask after unlocking the mutex. // If thDone is true, the thread has already finished. We're
delete_this = true; // not calling Poll because it may call callbacks, which
// an abandoned task shouldn't do. Instead we just delete the
// AbandonableTask after unlocking the mutex.
delete_this = true;
}
else
{
// If at this point thDone is still false, the thread is still
// running, meaning we can safely set thAbandoned and let
// AbandonableTask::doWork_wrapper delete the AbandonableTask later.
thAbandoned = true;
}
} }
else
{
// If at this point thDone is still false, the thread is still
// running, meaning we can safely set thAbandoned and let
// AbandonableTask::doWork_wrapper delete the AbandonableTask later.
thAbandoned = true;
}
pthread_mutex_unlock(&taskMutex);
if (delete_this) if (delete_this)
{ {
@@ -64,11 +65,9 @@ void AbandonableTask::Abandon()
AbandonableTask::AbandonableTask() : AbandonableTask::AbandonableTask() :
thAbandoned(false) thAbandoned(false)
{ {
pthread_cond_init(&done_cv, NULL);
} }
AbandonableTask::~AbandonableTask() AbandonableTask::~AbandonableTask()
{ {
pthread_cond_destroy(&done_cv);
} }

View File

@@ -3,9 +3,11 @@
#include "Task.h" #include "Task.h"
#include <condition_variable>
class AbandonableTask : public Task class AbandonableTask : public Task
{ {
pthread_cond_t done_cv; std::condition_variable done_cv;
public: public:
void Finish(); void Finish();

View File

@@ -12,10 +12,7 @@ void Task::AddTaskListener(TaskListener * listener)
void Task::Start() void Task::Start()
{ {
before(); before();
// This would use a lambda if we didn't use pthreads and if I dared omit std::thread([this]() { doWork_wrapper(); }).detach();
// the TH_ENTRY_POINT from the function type.
pthread_create(&doWorkThread, 0, &Task::doWork_helper, this);
pthread_detach(doWorkThread);
} }
int Task::GetProgress() int Task::GetProgress()
@@ -52,13 +49,14 @@ void Task::Poll()
bool newSuccess = false; bool newSuccess = false;
String newStatus; String newStatus;
String newError; String newError;
pthread_mutex_lock(&taskMutex); {
newProgress = thProgress; std::lock_guard<std::mutex> g(taskMutex);
newDone = thDone; newProgress = thProgress;
newSuccess = thSuccess; newDone = thDone;
newStatus = thStatus; newSuccess = thSuccess;
newError = thError; newStatus = thStatus;
pthread_mutex_unlock(&taskMutex); newError = thError;
}
success = newSuccess; success = newSuccess;
@@ -93,12 +91,10 @@ Task::Task() :
thDone(false), thDone(false),
listener(NULL) listener(NULL)
{ {
pthread_mutex_init(&taskMutex, NULL);
} }
Task::~Task() Task::~Task()
{ {
pthread_mutex_destroy(&taskMutex);
} }
void Task::before() void Task::before()
@@ -124,37 +120,29 @@ void Task::after()
void Task::doWork_wrapper() void Task::doWork_wrapper()
{ {
bool newSuccess = doWork(); bool newSuccess = doWork();
pthread_mutex_lock(&taskMutex); {
thSuccess = newSuccess; std::lock_guard<std::mutex> g(taskMutex);
thDone = true; thSuccess = newSuccess;
pthread_mutex_unlock(&taskMutex); thDone = true;
} }
TH_ENTRY_POINT void *Task::doWork_helper(void *ref)
{
((Task *)ref)->doWork_wrapper();
return NULL;
} }
void Task::notifyProgress(int progress) void Task::notifyProgress(int progress)
{ {
pthread_mutex_lock(&taskMutex); std::lock_guard<std::mutex> g(taskMutex);
thProgress = progress; thProgress = progress;
pthread_mutex_unlock(&taskMutex);
} }
void Task::notifyStatus(String status) void Task::notifyStatus(String status)
{ {
pthread_mutex_lock(&taskMutex); std::lock_guard<std::mutex> g(taskMutex);
thStatus = status; thStatus = status;
pthread_mutex_unlock(&taskMutex);
} }
void Task::notifyError(String error) void Task::notifyError(String error)
{ {
pthread_mutex_lock(&taskMutex); std::lock_guard<std::mutex> g(taskMutex);
thError = error; thError = error;
pthread_mutex_unlock(&taskMutex);
} }
void Task::notifyProgressMain() void Task::notifyProgressMain()

View File

@@ -2,9 +2,10 @@
#define TASK_H_ #define TASK_H_
#include "common/String.h" #include "common/String.h"
#include "common/tpt-thread.h"
#include "TaskListener.h" #include "TaskListener.h"
#include "Config.h" #include "Config.h"
#include <thread>
#include <mutex>
class TaskListener; class TaskListener;
class Task { class Task {
@@ -19,6 +20,7 @@ public:
virtual void Poll(); virtual void Poll();
Task(); Task();
virtual ~Task(); virtual ~Task();
protected: protected:
int progress; int progress;
bool done; bool done;
@@ -32,16 +34,13 @@ protected:
String thStatus; String thStatus;
String thError; String thError;
TaskListener * listener; TaskListener *listener;
pthread_t doWorkThread; std::mutex taskMutex;
pthread_mutex_t taskMutex;
virtual void before(); virtual void before();
virtual void after(); virtual void after();
virtual bool doWork(); virtual bool doWork();
virtual void doWork_wrapper(); virtual void doWork_wrapper();
TH_ENTRY_POINT static void * doWork_helper(void * ref);
virtual void notifyProgress(int progress); virtual void notifyProgress(int progress);
virtual void notifyError(String error); virtual void notifyError(String error);