From 955b0fb9db6df117773eb3972048f97226c31280 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 6 Mar 2016 13:16:50 -0800 Subject: [PATCH 1/5] UI: Minor header cleanup. --- UI/CwCheatScreen.cpp | 4 +++- UI/CwCheatScreen.h | 6 ------ UI/GameInfoCache.cpp | 5 +++++ UI/GameInfoCache.h | 8 ++------ UI/GameSettingsScreen.h | 2 -- UI/MiscScreens.cpp | 12 +++--------- UI/MiscScreens.h | 3 ++- UI/PauseScreen.cpp | 5 ++--- UI/Store.cpp | 1 + UI/Store.h | 2 -- android/jni/app-android.cpp | 1 + 11 files changed, 19 insertions(+), 30 deletions(-) diff --git a/UI/CwCheatScreen.cpp b/UI/CwCheatScreen.cpp index 82a40ef263..416d5767be 100644 --- a/UI/CwCheatScreen.cpp +++ b/UI/CwCheatScreen.cpp @@ -15,18 +15,20 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include #include "input/input_state.h" #include "ui/ui.h" #include "util/text/utf8.h" #include "i18n/i18n.h" +#include "Common/FileUtil.h" #include "Core/Core.h" #include "Core/Config.h" +#include "Core/CwCheat.h" #include "Core/MIPS/JitCommon/NativeJit.h" #include "UI/OnScreenDisplay.h" #include "UI/ui_atlas.h" -#include "UI/GamepadEmu.h" #include "UI/MainScreen.h" #include "UI/EmuScreen.h" diff --git a/UI/CwCheatScreen.h b/UI/CwCheatScreen.h index d08e6e160f..22cc35429c 100644 --- a/UI/CwCheatScreen.h +++ b/UI/CwCheatScreen.h @@ -15,16 +15,11 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. -#include -#include "Common/FileUtil.h" - #include "base/functional.h" #include "ui/view.h" #include "ui/ui_screen.h" #include "ui/ui_context.h" -#include "../Core/CwCheat.h" #include "UI/MiscScreens.h" -#include "UI/GameSettingsScreen.h" extern std::string activeCheatFile; extern std::string gameTitle; @@ -37,7 +32,6 @@ public: void processFileOff(std::string deactivatedCheat); const char * name; std::string activatedCheat, deactivatedCheat; - UI::EventReturn OnBack(UI::EventParams ¶ms); UI::EventReturn OnAddCheat(UI::EventParams ¶ms); UI::EventReturn OnImportCheat(UI::EventParams ¶ms); UI::EventReturn OnEditCheatFile(UI::EventParams ¶ms); diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index 244d8bf721..2a58c6365b 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -702,6 +702,11 @@ void GameInfoCache::PurgeType(IdentifiedFileType fileType) { } } +void GameInfoCache::WaitUntilDone(GameInfo *info) { + // Hack - should really wait specifically for that item. + gameInfoWQ_->WaitUntilDone(); +} + // Runs on the main thread. GameInfo *GameInfoCache::GetInfo(Thin3DContext *thin3d, const std::string &gamePath, int wantFlags) { diff --git a/UI/GameInfoCache.h b/UI/GameInfoCache.h index 1770702162..366c6c1825 100644 --- a/UI/GameInfoCache.h +++ b/UI/GameInfoCache.h @@ -22,12 +22,12 @@ #include "base/mutex.h" #include "file/file_util.h" -#include "thread/prioritizedworkqueue.h" #include "Core/ELF/ParamSFO.h" #include "Core/Loaders.h" class Thin3DContext; class Thin3DTexture; +class PrioritizedWorkQueue; // A GameInfo holds information about a game, and also lets you do things that the VSH // does on the PSP, namely checking for and deleting savedata, and similar things. @@ -180,7 +180,6 @@ public: // This creates a background worker thread! void Clear(); - void ClearTextures(); void PurgeType(IdentifiedFileType fileType); // All data in GameInfo including iconTexture may be zero the first time you call this @@ -192,10 +191,7 @@ public: PrioritizedWorkQueue *WorkQueue() { return gameInfoWQ_; } - void WaitUntilDone(GameInfo *info) { - // Hack - should really wait specifically for that item. - gameInfoWQ_->WaitUntilDone(); - } + void WaitUntilDone(GameInfo *info); private: void Init(); diff --git a/UI/GameSettingsScreen.h b/UI/GameSettingsScreen.h index 89224865af..3759057b9e 100644 --- a/UI/GameSettingsScreen.h +++ b/UI/GameSettingsScreen.h @@ -100,7 +100,6 @@ private: UI::EventReturn OnImmersiveModeChange(UI::EventParams &e); UI::EventReturn OnAdhocGuides(UI::EventParams &e); - UI::EventReturn OnAudioBackend(UI::EventParams &e); UI::EventReturn OnSavedataManager(UI::EventParams &e); UI::EventReturn OnSysInfo(UI::EventParams &e); @@ -145,7 +144,6 @@ protected: private: std::string tempProAdhocServer; UI::TextView *addrView_; - UI::EventReturn OnBack(UI::EventParams &e); UI::EventReturn On0Click(UI::EventParams &e); UI::EventReturn On1Click(UI::EventParams &e); UI::EventReturn On2Click(UI::EventParams &e); diff --git a/UI/MiscScreens.cpp b/UI/MiscScreens.cpp index a30c55036f..7925287eda 100644 --- a/UI/MiscScreens.cpp +++ b/UI/MiscScreens.cpp @@ -27,7 +27,9 @@ #include "ui/view.h" #include "ui/viewgroup.h" #include "ui/ui.h" +#include "util/random/rng.h" #include "file/vfs.h" +#include "UI/ui_atlas.h" #include "UI/MiscScreens.h" #include "UI/EmuScreen.h" #include "UI/MainScreen.h" @@ -35,12 +37,11 @@ #include "Core/Config.h" #include "Core/Host.h" #include "Core/System.h" -#include "Core/MIPS/JitCommon/JitCommon.h" #include "Core/MIPS/JitCommon/NativeJit.h" #include "Core/HLE/sceUtility.h" -#include "Common/CPUDetect.h" #include "Common/FileUtil.h" #include "GPU/GPUState.h" +#include "GPU/Common/PostShader.h" #include "ui_atlas.h" @@ -48,13 +49,6 @@ #pragma execution_character_set("utf-8") #endif -#include "base/timeutil.h" -#include "base/colorutil.h" -#include "gfx_es2/draw_buffer.h" -#include "util/random/rng.h" - -#include "UI/ui_atlas.h" - static const int symbols[4] = { I_CROSS, I_CIRCLE, diff --git a/UI/MiscScreens.h b/UI/MiscScreens.h index e25f476b44..1885110b13 100644 --- a/UI/MiscScreens.h +++ b/UI/MiscScreens.h @@ -24,7 +24,8 @@ #include "file/file_util.h" #include "base/functional.h" #include "ui/ui_screen.h" -#include "GPU/Common/PostShader.h" + +struct ShaderInfo; extern std::string boot_filename; diff --git a/UI/PauseScreen.cpp b/UI/PauseScreen.cpp index abce83ca07..609c5b3aef 100644 --- a/UI/PauseScreen.cpp +++ b/UI/PauseScreen.cpp @@ -16,8 +16,10 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include "i18n/i18n.h" +#include "gfx_es2/draw_buffer.h" #include "ui/view.h" #include "ui/viewgroup.h" +#include "ui/ui_context.h" #include "ui/ui_screen.h" #include "thin3d/thin3d.h" @@ -40,9 +42,6 @@ #include "UI/MainScreen.h" #include "UI/GameInfoCache.h" -#include "gfx_es2/draw_buffer.h" -#include "ui/ui_context.h" - void AsyncImageFileView::GetContentDimensions(const UIContext &dc, float &w, float &h) const { if (texture_) { float texw = (float)texture_->Width(); diff --git a/UI/Store.cpp b/UI/Store.cpp index 74bc3fef56..b9569698cb 100644 --- a/UI/Store.cpp +++ b/UI/Store.cpp @@ -29,6 +29,7 @@ #include "Common/StringUtils.h" #include "Core/Config.h" #include "Core/System.h" +#include "Core/Util/GameManager.h" #include "UI/EmuScreen.h" #include "UI/Store.h" diff --git a/UI/Store.h b/UI/Store.h index fc1c35edfb..9f00dc7524 100644 --- a/UI/Store.h +++ b/UI/Store.h @@ -22,7 +22,6 @@ #include "ui/viewgroup.h" #include "net/http_client.h" -#include "Core/Util/GameManager.h" #include "UI/MiscScreens.h" // Game screen: Allows you to start a game, delete saves, delete the game, @@ -68,7 +67,6 @@ public: protected: virtual void CreateViews(); UI::EventReturn OnGameSelected(UI::EventParams &e); - UI::EventReturn OnCategorySelected(UI::EventParams &e); UI::EventReturn OnRetry(UI::EventParams &e); UI::EventReturn OnGameLaunch(UI::EventParams &e); diff --git a/android/jni/app-android.cpp b/android/jni/app-android.cpp index aaa541281f..59e698ffb5 100644 --- a/android/jni/app-android.cpp +++ b/android/jni/app-android.cpp @@ -19,6 +19,7 @@ #include "base/NativeApp.h" #include "base/logging.h" #include "base/timeutil.h" +#include "thread/prioritizedworkqueue.h" #include "thread/threadutil.h" #include "file/zip_read.h" #include "input/input_state.h" From da03b80c97159f23c1afc4dbde48bb1744b13e2b Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 6 Mar 2016 13:30:31 -0800 Subject: [PATCH 2/5] Standardize on just one mutex implementation. --- Common/LogManager.cpp | 10 +++++----- Common/LogManager.h | 13 ++++++------- Core/CoreTiming.cpp | 18 +++++++++--------- Core/HLE/sceCtrl.cpp | 22 +++++++++++----------- Core/SaveState.cpp | 11 ++++++----- UI/OnScreenDisplay.cpp | 2 +- UI/OnScreenDisplay.h | 4 ++-- ext/native/base/mutex.h | 2 ++ 8 files changed, 42 insertions(+), 40 deletions(-) diff --git a/Common/LogManager.cpp b/Common/LogManager.cpp index 373a76040e..5d7d5da981 100644 --- a/Common/LogManager.cpp +++ b/Common/LogManager.cpp @@ -187,7 +187,7 @@ void LogManager::Log(LogTypes::LOG_LEVELS level, LogTypes::LOG_TYPE type, const if (level > log->GetLevel() || !log->IsEnabled() || !log->HasListeners()) return; - std::lock_guard lk(log_lock_); + lock_guard lk(log_lock_); static const char level_to_char[8] = "-NEWIDV"; char formattedTime[13]; Common::Timer::GetTimeFormatted(formattedTime); @@ -266,13 +266,13 @@ LogChannel::LogChannel(const char* shortName, const char* fullName, bool enable) // LogContainer void LogChannel::AddListener(LogListener *listener) { - std::lock_guard lk(m_listeners_lock); + lock_guard lk(m_listeners_lock); m_listeners.insert(listener); m_hasListeners = true; } void LogChannel::RemoveListener(LogListener *listener) { - std::lock_guard lk(m_listeners_lock); + lock_guard lk(m_listeners_lock); m_listeners.erase(listener); m_hasListeners = !m_listeners.empty(); } @@ -281,7 +281,7 @@ void LogChannel::Trigger(LogTypes::LOG_LEVELS level, const char *msg) { #ifdef __SYMBIAN32__ RDebug::Printf("%s",msg); #else - std::lock_guard lk(m_listeners_lock); + lock_guard lk(m_listeners_lock); std::set::const_iterator i; for (i = m_listeners.begin(); i != m_listeners.end(); ++i) { @@ -303,7 +303,7 @@ void FileLogListener::Log(LogTypes::LOG_LEVELS, const char *msg) { if (!IsEnabled() || !IsValid()) return; - std::lock_guard lk(m_log_lock); + lock_guard lk(m_log_lock); m_logfile << msg << std::flush; } diff --git a/Common/LogManager.h b/Common/LogManager.h index 452ffdf86b..d6a0785718 100644 --- a/Common/LogManager.h +++ b/Common/LogManager.h @@ -17,13 +17,12 @@ #pragma once +#include +#include "base/mutex.h" +#include "file/ini_file.h" #include "Log.h" #include "StringUtils.h" #include "FileUtil.h" -#include "file/ini_file.h" - -#include -#include "StdMutex.h" #define MAX_MESSAGES 8000 #define MAX_MSGLEN 1024 @@ -51,7 +50,7 @@ public: const char* GetName() const { return "file"; } private: - std::mutex m_log_lock; + recursive_mutex m_log_lock; std::ofstream m_logfile; bool m_enable; }; @@ -113,7 +112,7 @@ public: private: char m_fullName[128]; char m_shortName[32]; - std::mutex m_listeners_lock; + recursive_mutex m_listeners_lock; std::set m_listeners; bool m_hasListeners; }; @@ -128,7 +127,7 @@ private: DebuggerLogListener *debuggerLog_; RingbufferLogListener *ringLog_; static LogManager *logManager_; // Singleton. Ugh. - std::mutex log_lock_; + recursive_mutex log_lock_; LogManager(); ~LogManager(); diff --git a/Core/CoreTiming.cpp b/Core/CoreTiming.cpp index 7b25787fdc..42da031ba9 100644 --- a/Core/CoreTiming.cpp +++ b/Core/CoreTiming.cpp @@ -20,10 +20,10 @@ #include #include "base/logging.h" +#include "base/mutex.h" #include "profiler/profiler.h" #include "Common/MsgHandler.h" -#include "Common/StdMutex.h" #include "Common/Atomics.h" #include "Core/CoreTiming.h" #include "Core/Core.h" @@ -86,7 +86,7 @@ s64 idledCycles; s64 lastGlobalTimeTicks; s64 lastGlobalTimeUs; -static std::recursive_mutex externalEventSection; +static recursive_mutex externalEventSection; // Warning: not included in save state. void (*advanceCallback)(int cyclesExecuted) = NULL; @@ -228,7 +228,7 @@ void Shutdown() delete ev; } - std::lock_guard lk(externalEventSection); + lock_guard lk(externalEventSection); while(eventTsPool) { Event *ev = eventTsPool; @@ -252,7 +252,7 @@ u64 GetIdleTicks() // schedule things to be executed on the main thread. void ScheduleEvent_Threadsafe(s64 cyclesIntoFuture, int event_type, u64 userdata) { - std::lock_guard lk(externalEventSection); + lock_guard lk(externalEventSection); Event *ne = GetNewTsEvent(); ne->time = GetTicks() + cyclesIntoFuture; ne->type = event_type; @@ -273,7 +273,7 @@ void ScheduleEvent_Threadsafe_Immediate(int event_type, u64 userdata) { if(false) //Core::IsCPUThread()) { - std::lock_guard lk(externalEventSection); + lock_guard lk(externalEventSection); event_types[event_type].callback(userdata, 0); } else @@ -368,7 +368,7 @@ s64 UnscheduleEvent(int event_type, u64 userdata) s64 UnscheduleThreadsafeEvent(int event_type, u64 userdata) { s64 result = 0; - std::lock_guard lk(externalEventSection); + lock_guard lk(externalEventSection); if (!tsFirst) return result; while(tsFirst) @@ -478,7 +478,7 @@ void RemoveEvent(int event_type) void RemoveThreadsafeEvent(int event_type) { - std::lock_guard lk(externalEventSection); + lock_guard lk(externalEventSection); if (!tsFirst) { return; @@ -552,7 +552,7 @@ void MoveEvents() { Common::AtomicStoreRelease(hasTsEvents, 0); - std::lock_guard lk(externalEventSection); + lock_guard lk(externalEventSection); // Move events from async queue into main queue while (tsFirst) { @@ -692,7 +692,7 @@ void Event_DoStateOld(PointerWrap &p, BaseEvent *ev) void DoState(PointerWrap &p) { - std::lock_guard lk(externalEventSection); + lock_guard lk(externalEventSection); auto s = p.Section("CoreTiming", 1, 3); if (!s) diff --git a/Core/HLE/sceCtrl.cpp b/Core/HLE/sceCtrl.cpp index 75116abd8f..298ada31a7 100644 --- a/Core/HLE/sceCtrl.cpp +++ b/Core/HLE/sceCtrl.cpp @@ -17,6 +17,7 @@ // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. #include +#include "base/mutex.h" #include "Globals.h" #include "Core/HLE/HLE.h" #include "Core/HLE/FunctionWrappers.h" @@ -24,7 +25,6 @@ #include "Core/CoreTiming.h" #include "Core/MemMapHelpers.h" #include "Common/ChunkFile.h" -#include "Common/StdMutex.h" #include "Core/HLE/sceCtrl.h" #include "Core/HLE/sceDisplay.h" #include "Core/HLE/sceKernel.h" @@ -84,7 +84,7 @@ static int ctrlIdleBack = -1; static int ctrlCycle = 0; static std::vector waitingThreads; -static std::recursive_mutex ctrlMutex; +static recursive_mutex ctrlMutex; static int ctrlTimer = -1; @@ -101,7 +101,7 @@ const u32 CTRL_EMU_RAPIDFIRE_MASK = CTRL_UP | CTRL_DOWN | CTRL_LEFT | CTRL_RIGHT static void __CtrlUpdateLatch() { - std::lock_guard guard(ctrlMutex); + lock_guard guard(ctrlMutex); // Copy in the current data to the current buffer. ctrlBufs[ctrlBuf] = ctrlCurrent; @@ -144,14 +144,14 @@ static int __CtrlResetLatch() u32 __CtrlPeekButtons() { - std::lock_guard guard(ctrlMutex); + lock_guard guard(ctrlMutex); return ctrlCurrent.buttons; } void __CtrlPeekAnalog(int stick, float *x, float *y) { - std::lock_guard guard(ctrlMutex); + lock_guard guard(ctrlMutex); *x = (ctrlCurrent.analog[stick][CTRL_ANALOG_X] - 127.5f) / 127.5f; *y = -(ctrlCurrent.analog[stick][CTRL_ANALOG_Y] - 127.5f) / 127.5f; @@ -170,27 +170,27 @@ u32 __CtrlReadLatch() void __CtrlButtonDown(u32 buttonBit) { - std::lock_guard guard(ctrlMutex); + lock_guard guard(ctrlMutex); ctrlCurrent.buttons |= buttonBit; } void __CtrlButtonUp(u32 buttonBit) { - std::lock_guard guard(ctrlMutex); + lock_guard guard(ctrlMutex); ctrlCurrent.buttons &= ~buttonBit; } void __CtrlSetAnalogX(float x, int stick) { u8 scaled = clamp_u8((int)ceilf(x * 127.5f + 127.5f)); - std::lock_guard guard(ctrlMutex); + lock_guard guard(ctrlMutex); ctrlCurrent.analog[stick][CTRL_ANALOG_X] = scaled; } void __CtrlSetAnalogY(float y, int stick) { u8 scaled = clamp_u8((int)ceilf(-y * 127.5f + 127.5f)); - std::lock_guard guard(ctrlMutex); + lock_guard guard(ctrlMutex); ctrlCurrent.analog[stick][CTRL_ANALOG_Y] = scaled; } @@ -304,7 +304,7 @@ void __CtrlInit() ctrlIdleBack = -1; ctrlCycle = 0; - std::lock_guard guard(ctrlMutex); + lock_guard guard(ctrlMutex); ctrlBuf = 1; ctrlBufRead = 0; @@ -326,7 +326,7 @@ void __CtrlInit() void __CtrlDoState(PointerWrap &p) { - std::lock_guard guard(ctrlMutex); + lock_guard guard(ctrlMutex); auto s = p.Section("sceCtrl", 1, 3); if (!s) diff --git a/Core/SaveState.cpp b/Core/SaveState.cpp index b9a0321ba0..ee8f3d1aaa 100644 --- a/Core/SaveState.cpp +++ b/Core/SaveState.cpp @@ -15,13 +15,14 @@ // Official git repository and contact information can be found at // https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/. +#include #include +#include "base/mutex.h" #include "base/timeutil.h" #include "base/NativeApp.h" #include "i18n/i18n.h" -#include "Common/StdMutex.h" #include "Common/FileUtil.h" #include "Common/ChunkFile.h" @@ -206,7 +207,7 @@ namespace SaveState static bool needsProcess = false; static std::vector pending; - static std::recursive_mutex mutex; + static recursive_mutex mutex; static bool hasLoadedState = false; // TODO: Should this be configurable? @@ -250,7 +251,7 @@ namespace SaveState void Enqueue(SaveState::Operation op) { - std::lock_guard guard(mutex); + lock_guard guard(mutex); pending.push_back(op); // Don't actually run it until next frame. @@ -486,7 +487,7 @@ namespace SaveState std::vector Flush() { - std::lock_guard guard(mutex); + lock_guard guard(mutex); std::vector copy = pending; pending.clear(); @@ -670,7 +671,7 @@ namespace SaveState // Make sure there's a directory for save slots pspFileSystem.MkDir("ms0:/PSP/PPSSPP_STATE"); - std::lock_guard guard(mutex); + lock_guard guard(mutex); rewindStates.Clear(); hasLoadedState = false; diff --git a/UI/OnScreenDisplay.cpp b/UI/OnScreenDisplay.cpp index 58bae28060..eb4646e5a2 100644 --- a/UI/OnScreenDisplay.cpp +++ b/UI/OnScreenDisplay.cpp @@ -55,7 +55,7 @@ restart: void OnScreenMessages::Show(const std::string &text, float duration_s, uint32_t color, int icon, bool checkUnique, const char *id) { double now = time_now_d(); - std::lock_guard guard(mutex_); + lock_guard guard(mutex_); if (checkUnique) { for (auto iter = messages_.begin(); iter != messages_.end(); ++iter) { if (iter->text == text || (id && iter->id && !strcmp(iter->id, id))) { diff --git a/UI/OnScreenDisplay.h b/UI/OnScreenDisplay.h index 208f27d27a..8a0c6c17e0 100644 --- a/UI/OnScreenDisplay.h +++ b/UI/OnScreenDisplay.h @@ -3,9 +3,9 @@ #include #include +#include "base/mutex.h" #include "base/basictypes.h" #include "math/geom2d.h" -#include "Common/StdMutex.h" #include "ui/view.h" @@ -39,7 +39,7 @@ public: private: std::list messages_; - std::recursive_mutex mutex_; + recursive_mutex mutex_; }; class OnScreenMessagesView : public UI::InertView { diff --git a/ext/native/base/mutex.h b/ext/native/base/mutex.h index f1f9a3cd44..765bd84824 100644 --- a/ext/native/base/mutex.h +++ b/ext/native/base/mutex.h @@ -19,6 +19,8 @@ #undef p #undef DrawText #undef itoa +#undef min +#undef max #else #include From f1f046d88582055b52c29abc53968716737bad09 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 6 Mar 2016 13:31:14 -0800 Subject: [PATCH 3/5] Remove now-unused mutex implementation. --- Common/Common.vcxproj | 1 - Common/Common.vcxproj.filters | 1 - Common/StdMutex.h | 353 ---------------------------------- 3 files changed, 355 deletions(-) delete mode 100644 Common/StdMutex.h diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj index e5c94153c5..91be776722 100644 --- a/Common/Common.vcxproj +++ b/Common/Common.vcxproj @@ -233,7 +233,6 @@ - diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters index 7ef3033764..cc8b91d6ad 100644 --- a/Common/Common.vcxproj.filters +++ b/Common/Common.vcxproj.filters @@ -19,7 +19,6 @@ - diff --git a/Common/StdMutex.h b/Common/StdMutex.h deleted file mode 100644 index d42060e980..0000000000 --- a/Common/StdMutex.h +++ /dev/null @@ -1,353 +0,0 @@ - -#pragma once - -#define GCC_VER(x,y,z) ((x) * 10000 + (y) * 100 + (z)) -#define GCC_VERSION GCC_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) - -// Note: __MAC_10_7 is defined on 10.7+. -#if (__cplusplus >= 201103L || defined(__APPLE__) \ - || (GCC_VERSION >= GCC_VER(4,4,0) && __GXX_EXPERIMENTAL_CXX0X__)) \ -/* GCC 4.4 provides , except on these platforms: */ \ - && !defined(ANDROID) && !defined(__SYMBIAN32__) && !defined(MACGNUSTD) -#include -#else - -// partial implementation for win32/pthread -#include - -#if defined(_WIN32) // WIN32 -#include "CommonWindows.h" -#else // POSIX -#include -#endif - -#if (_MSC_VER >= 1600) || (GCC_VERSION >= GCC_VER(4,3,0) && __GXX_EXPERIMENTAL_CXX0X__) -#define USE_RVALUE_REFERENCES -#endif - -#if defined(_WIN32) && defined(_M_X64) -#define USE_SRWLOCKS -#endif - -namespace std -{ - -class recursive_mutex -{ -#ifdef _WIN32 - typedef CRITICAL_SECTION native_type; -#else - typedef pthread_mutex_t native_type; -#endif - -public: - typedef native_type* native_handle_type; - - recursive_mutex(const recursive_mutex&) /*= delete*/; - recursive_mutex& operator=(const recursive_mutex&) /*= delete*/; - - recursive_mutex() - { -#ifdef _WIN32 - InitializeCriticalSection(&m_handle); -#else - pthread_mutexattr_t attr; - pthread_mutexattr_init(&attr); - pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); - pthread_mutex_init(&m_handle, &attr); -#endif - } - - ~recursive_mutex() - { -#ifdef _WIN32 - DeleteCriticalSection(&m_handle); -#else - pthread_mutex_destroy(&m_handle); -#endif - } - - void lock() - { -#ifdef _WIN32 - EnterCriticalSection(&m_handle); -#else - pthread_mutex_lock(&m_handle); -#endif - } - - void unlock() - { -#ifdef _WIN32 - LeaveCriticalSection(&m_handle); -#else - pthread_mutex_unlock(&m_handle); -#endif - } - - bool try_lock() - { -#ifdef _WIN32 - return (0 != TryEnterCriticalSection(&m_handle)); -#else - return !pthread_mutex_trylock(&m_handle); -#endif - } - - native_handle_type native_handle() - { - return &m_handle; - } - -private: - native_type m_handle; -}; - -#if !defined(_WIN32) || defined(USE_SRWLOCKS) - -class mutex -{ -#ifdef _WIN32 - typedef SRWLOCK native_type; -#else - typedef pthread_mutex_t native_type; -#endif - -public: - typedef native_type* native_handle_type; - - mutex(const mutex&) /*= delete*/; - mutex& operator=(const mutex&) /*= delete*/; - - mutex() - { -#ifdef _WIN32 - InitializeSRWLock(&m_handle); -#else - pthread_mutex_init(&m_handle, NULL); -#endif - } - - ~mutex() - { -#ifdef _WIN32 -#else - pthread_mutex_destroy(&m_handle); -#endif - } - - void lock() - { -#ifdef _WIN32 - AcquireSRWLockExclusive(&m_handle); -#else - pthread_mutex_lock(&m_handle); -#endif - } - - void unlock() - { -#ifdef _WIN32 - ReleaseSRWLockExclusive(&m_handle); -#else - pthread_mutex_unlock(&m_handle); -#endif - } - - bool try_lock() - { -#ifdef _WIN32 - // XXX TryAcquireSRWLockExclusive requires Windows 7! - // return (0 != TryAcquireSRWLockExclusive(&m_handle)); - return false; -#else - return !pthread_mutex_trylock(&m_handle); -#endif - } - - native_handle_type native_handle() - { - return &m_handle; - } - -private: - native_type m_handle; -}; - -#else -typedef recursive_mutex mutex; // just use CriticalSections - -#endif - -enum defer_lock_t { defer_lock }; -enum try_to_lock_t { try_to_lock }; -enum adopt_lock_t { adopt_lock }; - -template -class lock_guard -{ -public: - typedef Mutex mutex_type; - - explicit lock_guard(mutex_type& m) - : pm(m) - { - m.lock(); - } - - lock_guard(mutex_type& m, adopt_lock_t) - : pm(m) - { - } - - ~lock_guard() - { - pm.unlock(); - } - - lock_guard(lock_guard const&) /*= delete*/; - lock_guard& operator=(lock_guard const&) /*= delete*/; - -private: - mutex_type& pm; -}; - -template -class unique_lock -{ -public: - typedef Mutex mutex_type; - - unique_lock() - : pm(NULL), owns(false) - {} - - /*explicit*/ unique_lock(mutex_type& m) - : pm(&m), owns(true) - { - m.lock(); - } - - unique_lock(mutex_type& m, defer_lock_t) - : pm(&m), owns(false) - {} - - unique_lock(mutex_type& m, try_to_lock_t) - : pm(&m), owns(m.try_lock()) - {} - - unique_lock(mutex_type& m, adopt_lock_t) - : pm(&m), owns(true) - {} - - //template - //unique_lock(mutex_type& m, const chrono::time_point& abs_time); - - //template - //unique_lock(mutex_type& m, const chrono::duration& rel_time); - - ~unique_lock() - { - if (owns_lock()) - mutex()->unlock(); - } - -#ifdef USE_RVALUE_REFERENCES - unique_lock& operator=(const unique_lock&) /*= delete*/; - - unique_lock& operator=(unique_lock&& other) - { -#else - unique_lock& operator=(const unique_lock& u) - { - // ugly const_cast to get around lack of rvalue references - unique_lock& other = const_cast(u); -#endif - swap(other); - return *this; - } - -#ifdef USE_RVALUE_REFERENCES - unique_lock(const unique_lock&) /*= delete*/; - - unique_lock(unique_lock&& other) - : pm(NULL), owns(false) - { -#else - unique_lock(const unique_lock& u) - : pm(NULL), owns(false) - { - // ugly const_cast to get around lack of rvalue references - unique_lock& other = const_cast(u); -#endif - swap(other); - } - - void lock() - { - mutex()->lock(); - owns = true; - } - - bool try_lock() - { - owns = mutex()->try_lock(); - return owns; - } - - //template - //bool try_lock_for(const chrono::duration& rel_time); - //template - //bool try_lock_until(const chrono::time_point& abs_time); - - void unlock() - { - mutex()->unlock(); - owns = false; - } - - void swap(unique_lock& u) - { - std::swap(pm, u.pm); - std::swap(owns, u.owns); - } - - mutex_type* release() - { - mutex_type* const ret = mutex(); - - pm = NULL; - owns = false; - - return ret; - } - - bool owns_lock() const - { - return owns; - } - - //explicit operator bool () const - //{ - // return owns_lock(); - //} - - mutex_type* mutex() const - { - return pm; - } - -private: - mutex_type* pm; - bool owns; -}; - -template -void swap(unique_lock& x, unique_lock& y) -{ - x.swap(y); -} - -} - -#endif From 8a9e30f83319cd963375f2689d6e417f9560d1e0 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 6 Mar 2016 13:52:16 -0800 Subject: [PATCH 4/5] UI: Wait for the specific game info item to finish. In case we have slow-loading ones. --- UI/GameInfoCache.cpp | 23 +++++++++-- UI/GameInfoCache.h | 2 + ext/native/thread/prioritizedworkqueue.cpp | 47 +++++++++++++++------- ext/native/thread/prioritizedworkqueue.h | 7 +++- 4 files changed, 59 insertions(+), 20 deletions(-) diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index 2a58c6365b..4380c6b37a 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -298,6 +298,11 @@ std::string GameInfo::GetTitle() { return title; } +bool GameInfo::IsPending() { + lock_guard guard(lock); + return pending; +} + void GameInfo::SetTitle(const std::string &newTitle) { lock_guard guard(lock); title = newTitle; @@ -581,8 +586,11 @@ handleELF: info_->saveDataSize = info_->GetSaveDataSizeInBytes(); info_->installDataSize = info_->GetInstallDataSizeInBytes(); } - info_->pending = false; + info_->DisposeFileLoader(); + + lock_guard lock(info_->lock); + info_->pending = false; // ILOG("Completed writing info for %s", info_->GetTitle().c_str()); } @@ -703,8 +711,15 @@ void GameInfoCache::PurgeType(IdentifiedFileType fileType) { } void GameInfoCache::WaitUntilDone(GameInfo *info) { - // Hack - should really wait specifically for that item. - gameInfoWQ_->WaitUntilDone(); + while (info->IsPending()) { + if (gameInfoWQ_->WaitUntilDone(false)) { + // A true return means everything finished, so bail out. + // This way even if something gets stuck, we won't hang. + break; + } + + // Otherwise, wait again if it's not done... + } } @@ -743,12 +758,12 @@ again: { lock_guard lock(info->lock); info->wantFlags |= wantFlags; + info->pending = true; } GameInfoWorkItem *item = new GameInfoWorkItem(gamePath, info); gameInfoWQ_->Add(item); - info->pending = true; info_[gamePath] = info; return info; } diff --git a/UI/GameInfoCache.h b/UI/GameInfoCache.h index 366c6c1825..1cea1ce090 100644 --- a/UI/GameInfoCache.h +++ b/UI/GameInfoCache.h @@ -119,6 +119,8 @@ public: std::string GetTitle(); void SetTitle(const std::string &newTitle); + bool IsPending(); + // Hold this when reading or writing from the GameInfo. // Don't need to hold it when just passing around the pointer, // and obviously also not when creating it and holding the only pointer diff --git a/ext/native/thread/prioritizedworkqueue.cpp b/ext/native/thread/prioritizedworkqueue.cpp index 421d08b92d..8d6d7561cd 100644 --- a/ext/native/thread/prioritizedworkqueue.cpp +++ b/ext/native/thread/prioritizedworkqueue.cpp @@ -33,28 +33,45 @@ void PrioritizedWorkQueue::Flush() { ILOG("Flushed %d un-executed tasks", flush_count); } -void PrioritizedWorkQueue::WaitUntilDone() { - if (queue_.empty()) - return; - // This could be made more elegant.. - while (true) { - bool empty; - { - lock_guard guard(mutex_); - empty = queue_.empty() && !working_; - } - if (empty) { - break; - } - sleep_ms(10); +bool PrioritizedWorkQueue::WaitUntilDone(bool all) { + // We'll lock drain this entire time, so make sure you follow that lock ordering. + lock_guard guard(drainMutex_); + if (AllItemsDone()) { + return true; } + + while (!AllItemsDone()) { + drain_.wait(drainMutex_); + if (!all) { + // Return whether empty or not, something just drained. + return AllItemsDone(); + } + } + + return true; } +void PrioritizedWorkQueue::NotifyDrain() { + lock_guard guard(drainMutex_); + drain_.notify_one(); +} + +bool PrioritizedWorkQueue::AllItemsDone() { + lock_guard guard(mutex_); + return queue_.empty() && !working_; +} // The worker should simply call this in a loop. Will block when appropriate. PrioritizedWorkQueueItem *PrioritizedWorkQueue::Pop() { + { + lock_guard guard(mutex_); + working_ = false; // The thread only calls Pop if it's done. + } + + // Important: make sure mutex_ is not locked while draining. + NotifyDrain(); + lock_guard guard(mutex_); - working_ = false; // The thread only calls Pop if it's done. if (done_) { return 0; } diff --git a/ext/native/thread/prioritizedworkqueue.h b/ext/native/thread/prioritizedworkqueue.h index 9ebfd21df0..5d3acea216 100644 --- a/ext/native/thread/prioritizedworkqueue.h +++ b/ext/native/thread/prioritizedworkqueue.h @@ -34,17 +34,22 @@ public: void Flush(); bool Done() { return done_; } void Stop(); - void WaitUntilDone(); + bool WaitUntilDone(bool all = true); bool IsWorking() { return working_; } private: + void NotifyDrain(); + bool AllItemsDone(); + bool done_; bool working_; recursive_mutex mutex_; + recursive_mutex drainMutex_; condition_variable notEmpty_; + condition_variable drain_; std::vector queue_; From f38869141abccbb8596c21941b29349ae2de2e70 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Sun, 6 Mar 2016 14:00:09 -0800 Subject: [PATCH 5/5] UI: Correct a race condition when loading bgs. --- UI/GameInfoCache.cpp | 13 +++++++++++++ UI/GameInfoCache.h | 4 +++- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/UI/GameInfoCache.cpp b/UI/GameInfoCache.cpp index 4380c6b37a..3901033699 100644 --- a/UI/GameInfoCache.cpp +++ b/UI/GameInfoCache.cpp @@ -303,6 +303,11 @@ bool GameInfo::IsPending() { return pending; } +bool GameInfo::IsWorking() { + lock_guard guard(lock); + return working; +} + void GameInfo::SetTitle(const std::string &newTitle) { lock_guard guard(lock); title = newTitle; @@ -360,6 +365,7 @@ public: std::string filename = gamePath_; { lock_guard lock(info_->lock); + info_->working = true; info_->fileType = Identify_File(info_->GetFileLoader()); } @@ -591,6 +597,7 @@ handleELF: lock_guard lock(info_->lock); info_->pending = false; + info_->working = false; // ILOG("Completed writing info for %s", info_->GetTitle().c_str()); } @@ -755,8 +762,14 @@ again: if (!info) { info = new GameInfo(); } + { lock_guard lock(info->lock); + if (info->IsWorking()) { + // Uh oh, it's currently in process. It could mark pending = false with the wrong wantFlags. + // Let's wait it out, then queue. + WaitUntilDone(info); + } info->wantFlags |= wantFlags; info->pending = true; } diff --git a/UI/GameInfoCache.h b/UI/GameInfoCache.h index 1cea1ce090..70eba8749a 100644 --- a/UI/GameInfoCache.h +++ b/UI/GameInfoCache.h @@ -98,7 +98,7 @@ public: : disc_total(0), disc_number(0), region(-1), fileType(FILETYPE_UNKNOWN), paramSFOLoaded(false), hasConfig(false), iconTexture(nullptr), pic0Texture(nullptr), pic1Texture(nullptr), wantFlags(0), lastAccessedTime(0.0), timeIconWasLoaded(0.0), timePic0WasLoaded(0.0), timePic1WasLoaded(0.0), - gameSize(0), saveDataSize(0), installDataSize(0), pending(true), fileLoader(nullptr) {} + gameSize(0), saveDataSize(0), installDataSize(0), pending(true), working(false), fileLoader(nullptr) {} ~GameInfo(); bool Delete(); // Better be sure what you're doing when calling this. @@ -120,6 +120,7 @@ public: void SetTitle(const std::string &newTitle); bool IsPending(); + bool IsWorking(); // Hold this when reading or writing from the GameInfo. // Don't need to hold it when just passing around the pointer, @@ -166,6 +167,7 @@ public: u64 saveDataSize; u64 installDataSize; bool pending; + bool working; protected: // Note: this can change while loading, use GetTitle().