Make the workqueue slightly safer. Put g_gameInfoCache on the heap.

Cherry-picked from #8592
This commit is contained in:
Henrik Rydgard
2016-02-14 22:07:10 +01:00
parent 5f761c346b
commit da1a04be8d
18 changed files with 73 additions and 64 deletions
+1 -1
View File
@@ -206,7 +206,7 @@ int PlayBackgroundAudio() {
// last changed... (to prevent crazy amount of reads when skipping through a list)
if (!at3Reader && bgGamePath.size() && (time_now_d() - gameLastChanged > 0.5)) {
// Grab some audio from the current game and play it.
GameInfo *gameInfo = g_gameInfoCache.GetInfo(NULL, bgGamePath, GAMEINFO_WANTSND);
GameInfo *gameInfo = g_gameInfoCache->GetInfo(NULL, bgGamePath, GAMEINFO_WANTSND);
if (!gameInfo)
return 0;
+2 -2
View File
@@ -89,7 +89,7 @@ void EmuScreen::bootGame(const std::string &filename) {
}
//pre-emptive loading of game specific config if possible, to get all the settings
GameInfo *info = g_gameInfoCache.GetInfo(NULL, filename, 0);
GameInfo *info = g_gameInfoCache->GetInfo(NULL, filename, 0);
if (info && !info->id.empty()) {
g_Config.loadGameConfig(info->id);
}
@@ -139,7 +139,7 @@ void EmuScreen::bootComplete() {
host->BootDone();
host->UpdateDisassembly();
g_gameInfoCache.FlushBGs();
g_gameInfoCache->FlushBGs();
NOTICE_LOG(BOOT, "Loading %s...", PSP_CoreParameter().fileToStart.c_str());
autoLoad();
+9 -2
View File
@@ -45,7 +45,7 @@
#define unique_ptr auto_ptr
#endif
GameInfoCache g_gameInfoCache;
GameInfoCache *g_gameInfoCache;
GameInfo::~GameInfo() {
delete iconTexture;
@@ -583,6 +583,7 @@ handleELF:
}
info_->pending = false;
info_->DisposeFileLoader();
// ILOG("Completed writing info for %s", info_->GetTitle().c_str());
}
virtual float priority() {
@@ -595,9 +596,13 @@ private:
DISALLOW_COPY_AND_ASSIGN(GameInfoWorkItem);
};
GameInfoCache::GameInfoCache() : gameInfoWQ_(nullptr) {
Init();
}
GameInfoCache::~GameInfoCache() {
Clear();
Shutdown();
}
void GameInfoCache::Init() {
@@ -614,8 +619,10 @@ void GameInfoCache::Shutdown() {
}
void GameInfoCache::Clear() {
if (gameInfoWQ_)
if (gameInfoWQ_) {
gameInfoWQ_->Flush();
gameInfoWQ_->WaitUntilDone();
}
for (auto iter = info_.begin(); iter != info_.end(); iter++) {
{
lock_guard lock(iter->second->lock);
+5 -4
View File
@@ -175,13 +175,12 @@ protected:
class GameInfoCache {
public:
GameInfoCache() : gameInfoWQ_(0) {}
GameInfoCache();
~GameInfoCache();
// This creates a background worker thread!
void Init();
void Shutdown();
void Clear();
void ClearTextures();
void PurgeType(IdentifiedFileType fileType);
// All data in GameInfo including iconTexture may be zero the first time you call this
@@ -199,6 +198,8 @@ public:
}
private:
void Init();
void Shutdown();
void SetupTexture(GameInfo *info, std::string &textureData, Thin3DContext *thin3d, Thin3DTexture *&tex, double &loadTime);
// Maps ISO path to info.
@@ -209,4 +210,4 @@ private:
};
// This one can be global, no good reason not to.
extern GameInfoCache g_gameInfoCache;
extern GameInfoCache *g_gameInfoCache;
+12 -12
View File
@@ -44,8 +44,8 @@ GameScreen::~GameScreen() {
}
void GameScreen::CreateViews() {
GameInfo *info = g_gameInfoCache.GetInfo(NULL, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE);
g_gameInfoCache.WaitUntilDone(info);
GameInfo *info = g_gameInfoCache->GetInfo(NULL, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE);
g_gameInfoCache->WaitUntilDone(info);
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *ga = GetI18NCategory("Game");
@@ -117,7 +117,7 @@ void GameScreen::CreateViews() {
UI::EventReturn GameScreen::OnCreateConfig(UI::EventParams &e)
{
GameInfo *info = g_gameInfoCache.GetInfo(NULL, gamePath_,0);
GameInfo *info = g_gameInfoCache->GetInfo(NULL, gamePath_,0);
g_Config.createGameConfig(info->id);
g_Config.saveGameConfig(info->id);
info->hasConfig = true;
@@ -130,7 +130,7 @@ void GameScreen::CallbackDeleteConfig(bool yes)
{
if (yes)
{
GameInfo *info = g_gameInfoCache.GetInfo(NULL, gamePath_, 0);
GameInfo *info = g_gameInfoCache->GetInfo(NULL, gamePath_, 0);
g_Config.deleteGameConfig(info->id);
info->hasConfig = false;
screenManager()->RecreateAllViews();
@@ -155,7 +155,7 @@ void GameScreen::update(InputState &input) {
Thin3DContext *thin3d = screenManager()->getThin3DContext();
GameInfo *info = g_gameInfoCache.GetInfo(thin3d, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE);
GameInfo *info = g_gameInfoCache->GetInfo(thin3d, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE);
if (tvTitle_)
tvTitle_->SetText(info->GetTitle() + " (" + info->id + ")");
@@ -216,7 +216,7 @@ UI::EventReturn GameScreen::OnPlay(UI::EventParams &e) {
}
UI::EventReturn GameScreen::OnGameSettings(UI::EventParams &e) {
GameInfo *info = g_gameInfoCache.GetInfo(NULL, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE);
GameInfo *info = g_gameInfoCache->GetInfo(NULL, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE);
if (info && info->paramSFOLoaded) {
std::string discID = info->paramSFO.GetValueString("DISC_ID");
screenManager()->push(new GameSettingsScreen(gamePath_, discID, true));
@@ -227,7 +227,7 @@ UI::EventReturn GameScreen::OnGameSettings(UI::EventParams &e) {
UI::EventReturn GameScreen::OnDeleteSaveData(UI::EventParams &e) {
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *ga = GetI18NCategory("Game");
GameInfo *info = g_gameInfoCache.GetInfo(NULL, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE);
GameInfo *info = g_gameInfoCache->GetInfo(NULL, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE);
if (info) {
// Check that there's any savedata to delete
std::vector<std::string> saveDirs = info->GetSaveDataDirectories();
@@ -243,7 +243,7 @@ UI::EventReturn GameScreen::OnDeleteSaveData(UI::EventParams &e) {
}
void GameScreen::CallbackDeleteSaveData(bool yes) {
GameInfo *info = g_gameInfoCache.GetInfo(NULL, gamePath_, 0);
GameInfo *info = g_gameInfoCache->GetInfo(NULL, gamePath_, 0);
if (yes) {
info->DeleteAllSaveData();
info->saveDataSize = 0;
@@ -254,7 +254,7 @@ void GameScreen::CallbackDeleteSaveData(bool yes) {
UI::EventReturn GameScreen::OnDeleteGame(UI::EventParams &e) {
I18NCategory *di = GetI18NCategory("Dialog");
I18NCategory *ga = GetI18NCategory("Game");
GameInfo *info = g_gameInfoCache.GetInfo(NULL, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE);
GameInfo *info = g_gameInfoCache->GetInfo(NULL, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE);
if (info) {
screenManager()->push(
new PromptScreen(di->T("DeleteConfirmGame", "Do you really want to delete this game\nfrom your device? You can't undo this."), ga->T("ConfirmDelete"), di->T("Cancel"),
@@ -265,16 +265,16 @@ UI::EventReturn GameScreen::OnDeleteGame(UI::EventParams &e) {
}
void GameScreen::CallbackDeleteGame(bool yes) {
GameInfo *info = g_gameInfoCache.GetInfo(NULL, gamePath_, 0);
GameInfo *info = g_gameInfoCache->GetInfo(NULL, gamePath_, 0);
if (yes) {
info->Delete();
g_gameInfoCache.Clear();
g_gameInfoCache->Clear();
screenManager()->switchScreen(new MainScreen());
}
}
UI::EventReturn GameScreen::OnCreateShortcut(UI::EventParams &e) {
GameInfo *info = g_gameInfoCache.GetInfo(NULL, gamePath_, 0);
GameInfo *info = g_gameInfoCache->GetInfo(NULL, gamePath_, 0);
if (info) {
host->CreateDesktopShortcut(gamePath_, info->GetTitle());
}
+1 -1
View File
@@ -77,7 +77,7 @@ bool GameSettingsScreen::UseVerticalLayout() const {
}
void GameSettingsScreen::CreateViews() {
GameInfo *info = g_gameInfoCache.GetInfo(NULL, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE);
GameInfo *info = g_gameInfoCache->GetInfo(NULL, gamePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE);
if (bEditThenRestore)
{
+3 -3
View File
@@ -173,7 +173,7 @@ private:
};
void GameButton::Draw(UIContext &dc) {
GameInfo *ginfo = g_gameInfoCache.GetInfo(dc.GetThin3DContext(), gamePath_, 0);
GameInfo *ginfo = g_gameInfoCache->GetInfo(dc.GetThin3DContext(), gamePath_, 0);
Thin3DTexture *texture = 0;
u32 color = 0, shadowColor = 0;
using namespace UI;
@@ -976,7 +976,7 @@ bool MainScreen::DrawBackgroundFor(UIContext &dc, const std::string &gamePath, f
GameInfo *ginfo = 0;
if (!gamePath.empty()) {
ginfo = g_gameInfoCache.GetInfo(dc.GetThin3DContext(), gamePath, GAMEINFO_WANTBG);
ginfo = g_gameInfoCache->GetInfo(dc.GetThin3DContext(), gamePath, GAMEINFO_WANTBG);
// Loading texture data may bind a texture.
dc.RebindTexture();
@@ -1009,7 +1009,7 @@ UI::EventReturn MainScreen::OnGameSelected(UI::EventParams &e) {
std::string path = e.s;
#endif
GameInfo *ginfo = 0;
ginfo = g_gameInfoCache.GetInfo(nullptr, path, GAMEINFO_WANTBG);
ginfo = g_gameInfoCache->GetInfo(nullptr, path, GAMEINFO_WANTBG);
if (ginfo && ginfo->fileType == FILETYPE_PSP_SAVEDATA_DIRECTORY) {
return UI::EVENT_DONE;
}
+1 -1
View File
@@ -105,7 +105,7 @@ void DrawBackground(UIContext &dc, float alpha = 1.0f) {
}
void DrawGameBackground(UIContext &dc, const std::string &gamePath) {
GameInfo *ginfo = g_gameInfoCache.GetInfo(dc.GetThin3DContext(), gamePath, GAMEINFO_WANTBG);
GameInfo *ginfo = g_gameInfoCache->GetInfo(dc.GetThin3DContext(), gamePath, GAMEINFO_WANTBG);
dc.Flush();
if (ginfo) {
+5 -7
View File
@@ -486,8 +486,6 @@ void NativeInit(int argc, const char *argv[], const char *savegame_dir, const ch
if (!boot_filename.empty() && stateToLoad != NULL)
SaveState::Load(stateToLoad);
g_gameInfoCache.Init();
screenManager = new ScreenManager();
if (skipLogo) {
screenManager->switchScreen(new EmuScreen(boot_filename));
@@ -596,6 +594,8 @@ void NativeInitGraphics(GraphicsContext *graphicsContext) {
winAudioBackend = CreateAudioBackend((AudioBackendType)g_Config.iAudioBackend);
winAudioBackend->Init(MainWindow::GetHWND(), &Win32Mix, 44100);
#endif
g_gameInfoCache = new GameInfoCache();
}
void NativeShutdownGraphics() {
@@ -606,7 +606,8 @@ void NativeShutdownGraphics() {
screenManager->deviceLost();
g_gameInfoCache.Clear();
delete g_gameInfoCache;
g_gameInfoCache = nullptr;
uiTexture->Release();
@@ -764,13 +765,12 @@ void NativeUpdate(InputState &input) {
}
void NativeDeviceLost() {
g_gameInfoCache.Clear();
// g_gameInfoCache.Clear();
screenManager->deviceLost();
if (GetGPUBackend() == GPUBackend::OPENGL) {
gl_lost();
}
// Should dirty EVERYTHING
}
bool NativeIsAtTopLevel() {
@@ -933,8 +933,6 @@ void NativeShutdown() {
delete screenManager;
screenManager = 0;
g_gameInfoCache.Shutdown();
delete host;
host = 0;
g_Config.Save();
+3 -3
View File
@@ -181,7 +181,7 @@ SaveSlotView::SaveSlotView(const std::string &gameFilename, int slot, UI::Layout
using namespace UI;
screenshotFilename_ = SaveState::GenerateSaveSlotFilename(gamePath_, slot, "jpg");
PrioritizedWorkQueue *wq = g_gameInfoCache.WorkQueue();
PrioritizedWorkQueue *wq = g_gameInfoCache->WorkQueue();
Add(new Spacer(5));
AsyncImageFileView *fv = Add(new AsyncImageFileView(screenshotFilename_, IS_DEFAULT, wq, new UI::LayoutParams(82 * 2, 47 * 2)));
@@ -409,7 +409,7 @@ UI::EventReturn GamePauseScreen::OnSwitchUMD(UI::EventParams &e) {
void GamePauseScreen::CallbackDeleteConfig(bool yes)
{
if (yes) {
GameInfo *info = g_gameInfoCache.GetInfo(NULL, gamePath_, 0);
GameInfo *info = g_gameInfoCache->GetInfo(NULL, gamePath_, 0);
g_Config.unloadGameConfig();
g_Config.deleteGameConfig(info->id);
info->hasConfig = false;
@@ -423,7 +423,7 @@ UI::EventReturn GamePauseScreen::OnCreateConfig(UI::EventParams &e)
g_Config.createGameConfig(gameId);
g_Config.changeGameSpecific(gameId);
g_Config.saveGameConfig(gameId);
GameInfo *info = g_gameInfoCache.GetInfo(NULL, gamePath_, 0);
GameInfo *info = g_gameInfoCache->GetInfo(NULL, gamePath_, 0);
if (info) {
info->hasConfig = true;
}
+7 -7
View File
@@ -58,7 +58,7 @@ public:
void CreatePopupContents(UI::ViewGroup *parent) override {
using namespace UI;
GameInfo *ginfo = g_gameInfoCache.GetInfo(screenManager()->getThin3DContext(), savePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE);
GameInfo *ginfo = g_gameInfoCache->GetInfo(screenManager()->getThin3DContext(), savePath_, GAMEINFO_WANTBG | GAMEINFO_WANTSIZE);
LinearLayout *root = new LinearLayout(ORIENT_VERTICAL);
parent->Add(root);
if (!ginfo)
@@ -86,7 +86,7 @@ public:
} else {
std::string image_path = ReplaceAll(savePath_, ".ppst", ".jpg");
if (File::Exists(image_path)) {
PrioritizedWorkQueue *wq = g_gameInfoCache.WorkQueue();
PrioritizedWorkQueue *wq = g_gameInfoCache->WorkQueue();
toprow->Add(new AsyncImageFileView(image_path, IS_DEFAULT, wq, new UI::LayoutParams(500, 500/16*9)));
} else {
toprow->Add(new TextView(sa->T("No screenshot"), new LinearLayoutParams(Margins(10, 5))));
@@ -128,7 +128,7 @@ private:
};
UI::EventReturn SavedataPopupScreen::OnDeleteButtonClick(UI::EventParams &e) {
GameInfo *ginfo = g_gameInfoCache.GetInfo(nullptr, savePath_, GAMEINFO_WANTSIZE);
GameInfo *ginfo = g_gameInfoCache->GetInfo(nullptr, savePath_, GAMEINFO_WANTSIZE);
ginfo->Delete();
screenManager()->finishDialog(this, DR_NO);
return UI::EVENT_DONE;
@@ -142,7 +142,7 @@ static std::string CleanSaveString(std::string str) {
}
void SavedataButton::Draw(UIContext &dc) {
GameInfo *ginfo = g_gameInfoCache.GetInfo(dc.GetThin3DContext(), savePath_, GAMEINFO_WANTSIZE);
GameInfo *ginfo = g_gameInfoCache->GetInfo(dc.GetThin3DContext(), savePath_, GAMEINFO_WANTSIZE);
Thin3DTexture *texture = 0;
u32 color = 0, shadowColor = 0;
using namespace UI;
@@ -274,8 +274,8 @@ SavedataBrowser::SavedataBrowser(std::string path, UI::LayoutParams *layoutParam
}
SavedataBrowser::~SavedataBrowser() {
g_gameInfoCache.PurgeType(FILETYPE_PPSSPP_SAVESTATE);
g_gameInfoCache.PurgeType(FILETYPE_PSP_SAVEDATA_DIRECTORY);
g_gameInfoCache->PurgeType(FILETYPE_PPSSPP_SAVESTATE);
g_gameInfoCache->PurgeType(FILETYPE_PSP_SAVEDATA_DIRECTORY);
}
void SavedataBrowser::Refresh() {
@@ -368,7 +368,7 @@ void SavedataScreen::CreateViews() {
}
UI::EventReturn SavedataScreen::OnSavedataButtonClick(UI::EventParams &e) {
GameInfo *ginfo = g_gameInfoCache.GetInfo(screenManager()->getThin3DContext(), e.s, 0);
GameInfo *ginfo = g_gameInfoCache->GetInfo(screenManager()->getThin3DContext(), e.s, 0);
screenManager()->push(new SavedataPopupScreen(e.s, ginfo->GetTitle()));
// the game path: e.s;
return UI::EVENT_DONE;
+1 -3
View File
@@ -552,7 +552,7 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
{
//hack to enable/disable menu command accelerate keys
MainWindow::UpdateCommands();
//hack to make it possible to get to main window from floating windows with Esc
if (msg.hwnd != hwndMain && msg.wParam == VK_ESCAPE)
BringWindowToTop(hwndMain);
@@ -600,8 +600,6 @@ int WINAPI WinMain(HINSTANCE _hInstance, HINSTANCE hPrevInstance, LPSTR szCmdLin
delete host;
g_Config.Save();
g_gameInfoCache.Clear();
g_gameInfoCache.Shutdown();
LogManager::Shutdown();
if (g_Config.bRestartRequired) {
+4 -1
View File
@@ -31,6 +31,7 @@
#include "Common/GraphicsContext.h"
#include "Common/GL/GLInterfaceBase.h"
#include "UI/GameInfoCache.h"
#include "app-android.h"
@@ -736,7 +737,9 @@ extern "C" bool JNICALL Java_org_ppsspp_ppsspp_NativeActivity_runEGLRenderLoop(J
ProcessFrameCommands(env);
}
// Restore lost device objects. TODO: This feels like the wrong place for this.
ILOG("After render loop.");
g_gameInfoCache->WorkQueue()->Flush();
NativeDeviceLost();
ILOG("NativeDeviceLost completed.");
+2 -2
View File
@@ -49,10 +49,10 @@ void gl_lost() {
// TODO: We should really do this when we get the context back, not during gl_lost...
ILOG("gl_lost() restoring %i items:", (int)holders->size());
for (size_t i = 0; i < holders->size(); i++) {
ILOG("GLLost(%i / %i, %p)", (int)(i + 1), (int) holders->size(), (*holders)[i]);
ILOG("GLLost(%i / %i, %p, %08x)", (int)(i + 1), (int) holders->size(), (*holders)[i], *((uint32_t *)((*holders)[i])));
(*holders)[i]->GLLost();
}
ILOG("gl_lost() completed restoring %i items:", (int)holders->size());
ILOG("gl_lost() completed on %i items:", (int)holders->size());
inLost = false;
}
+4 -10
View File
@@ -473,17 +473,11 @@ public:
}
void GLLost() override {
// We lost our GL context - zero out the tex_.
tex_ = 0;
generatedMips_ = false;
if (!filename_.empty()) {
if (LoadFromFile(filename_.c_str())) {
ILOG("Reloaded lost texture %s", filename_.c_str());
} else {
ELOG("Failed to reload lost texture %s", filename_.c_str());
}
} else {
WLOG("Texture %p cannot be restored - has no filename", this);
tex_ = 0;
}
// Don't try to restore stuff, that's not what this is for. Lost just means
// that all our textures and buffers are invalid.
}
void Finalize(int zim_flags) override;
+6 -3
View File
@@ -23,13 +23,14 @@ void PrioritizedWorkQueue::Stop() {
}
void PrioritizedWorkQueue::Flush() {
if (queue_.empty())
return;
lock_guard guard(mutex_);
int flush_count = 0;
for (auto iter = queue_.begin(); iter != queue_.end(); ++iter) {
delete *iter;
flush_count++;
}
queue_.clear();
ILOG("Flushed %d un-executed tasks", flush_count);
}
void PrioritizedWorkQueue::WaitUntilDone() {
@@ -40,7 +41,7 @@ void PrioritizedWorkQueue::WaitUntilDone() {
bool empty;
{
lock_guard guard(mutex_);
empty = queue_.empty();
empty = queue_.empty() && !working_;
}
if (empty) {
break;
@@ -53,6 +54,7 @@ void PrioritizedWorkQueue::WaitUntilDone() {
// 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.
if (done_) {
return 0;
}
@@ -77,6 +79,7 @@ PrioritizedWorkQueueItem *PrioritizedWorkQueue::Pop() {
if (best != queue_.end()) {
PrioritizedWorkQueueItem *poppedItem = *best;
queue_.erase(best);
working_ = true; // This will be worked on.
return poppedItem;
} else {
// Not really sure how this can happen, but let's be safe.
+6 -1
View File
@@ -23,7 +23,7 @@ private:
class PrioritizedWorkQueue {
public:
PrioritizedWorkQueue() : done_(false) {}
PrioritizedWorkQueue() : done_(false), working_(false) {}
~PrioritizedWorkQueue();
// Takes ownership.
void Add(PrioritizedWorkQueueItem *item);
@@ -36,8 +36,13 @@ public:
void Stop();
void WaitUntilDone();
bool IsWorking() {
return working_;
}
private:
bool done_;
bool working_;
recursive_mutex mutex_;
condition_variable notEmpty_;