diff --git a/Source/Core/Common/Common.vcxproj b/Source/Core/Common/Common.vcxproj
index 2f3f340c14..73f6c8815b 100644
--- a/Source/Core/Common/Common.vcxproj
+++ b/Source/Core/Common/Common.vcxproj
@@ -110,6 +110,7 @@
+
diff --git a/Source/Core/Common/Common.vcxproj.filters b/Source/Core/Common/Common.vcxproj.filters
index a55b5d26d6..f9f84f8426 100644
--- a/Source/Core/Common/Common.vcxproj.filters
+++ b/Source/Core/Common/Common.vcxproj.filters
@@ -53,6 +53,7 @@
+
diff --git a/Source/Core/Common/ScopeGuard.h b/Source/Core/Common/ScopeGuard.h
new file mode 100644
index 0000000000..ab021a178c
--- /dev/null
+++ b/Source/Core/Common/ScopeGuard.h
@@ -0,0 +1,50 @@
+// Copyright 2015 Dolphin Emulator Project
+// Licensed under GPLv2+
+// Refer to the license.txt file included.
+
+#pragma once
+
+#include
+
+namespace Common
+{
+
+class ScopeGuard final
+{
+public:
+ template
+ ScopeGuard(Callable&& finalizer) : m_finalizer(std::forward(finalizer)) {}
+
+ ScopeGuard(ScopeGuard&& other) : m_finalizer(std::move(other.m_finalizer))
+ {
+ other.m_finalizer = nullptr;
+ }
+
+ ~ScopeGuard()
+ {
+ Exit();
+ }
+
+ void Dismiss()
+ {
+ m_finalizer = nullptr;
+ }
+
+ void Exit()
+ {
+ if (m_finalizer)
+ {
+ m_finalizer(); // must not throw
+ m_finalizer = nullptr;
+ }
+ }
+
+ ScopeGuard(const ScopeGuard&) = delete;
+
+ void operator=(const ScopeGuard&) = delete;
+
+private:
+ std::function m_finalizer;
+};
+
+} // Namespace Common
diff --git a/Source/Core/Core/State.cpp b/Source/Core/Core/State.cpp
index e74a88b500..129aaa15ea 100644
--- a/Source/Core/Core/State.cpp
+++ b/Source/Core/Core/State.cpp
@@ -9,6 +9,7 @@
#include "Common/CommonTypes.h"
#include "Common/Event.h"
+#include "Common/ScopeGuard.h"
#include "Common/StringUtil.h"
#include "Common/Thread.h"
#include "Common/Timer.h"
@@ -280,8 +281,20 @@ struct CompressAndDumpState_args
static void CompressAndDumpState(CompressAndDumpState_args save_args)
{
std::lock_guard lk(*save_args.buffer_mutex);
- if (!save_args.wait)
+
+ // ScopeGuard is used here to ensure that g_compressAndDumpStateSyncEvent.Set()
+ // will be called and that it will happen after the IOFile is closed.
+ // Both ScopeGuard's and IOFile's finalization occur at respective object destruction time.
+ // As Local (stack) objects are destructed in the reverse order of construction and "ScopeGuard on_exit"
+ // is created before the "IOFile f", it is guaranteed that the file will be finalized before
+ // the ScopeGuard's finalization (i.e. "g_compressAndDumpStateSyncEvent.Set()" call).
+ Common::ScopeGuard on_exit([]()
+ {
g_compressAndDumpStateSyncEvent.Set();
+ });
+ // If it is not required to wait, we call finalizer early (and it won't be called again at destruction).
+ if (!save_args.wait)
+ on_exit.Exit();
const u8* const buffer_data = &(*(save_args.buffer_vector))[0];
const size_t buffer_size = (save_args.buffer_vector)->size();
@@ -313,7 +326,6 @@ static void CompressAndDumpState(CompressAndDumpState_args save_args)
if (!f)
{
Core::DisplayMessage("Could not save state", 2000);
- g_compressAndDumpStateSyncEvent.Set();
return;
}
@@ -361,7 +373,6 @@ static void CompressAndDumpState(CompressAndDumpState_args save_args)
}
Core::DisplayMessage(StringFromFormat("Saved State to %s", filename.c_str()), 2000);
- g_compressAndDumpStateSyncEvent.Set();
}
void SaveAs(const std::string& filename, bool wait)