From 87bc5266ef14acf41f0751873cca469ef7e2e01b Mon Sep 17 00:00:00 2001
From: James Rowe <jroweboy@gmail.com>
Date: Fri, 23 Feb 2018 00:33:44 -0700
Subject: [PATCH] Logging: Various logging improvements

* Uses PopWait to reduce the amount of busy waiting if there aren't many
new logs
* Opens the log file as shared on windows, letting other programs read
the logs, but not write to them while citra is running
* Flushes the logs to disk if a log >= error arrives
---
 src/common/file_util.cpp       | 15 ++++++++++-----
 src/common/file_util.h         |  5 +++--
 src/common/logging/backend.cpp | 15 +++++++++++++--
 src/common/logging/backend.h   |  5 +++--
 4 files changed, 29 insertions(+), 11 deletions(-)

diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index 446bd4398..7b256fede 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -803,8 +803,8 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
 
 IOFile::IOFile() {}
 
-IOFile::IOFile(const std::string& filename, const char openmode[]) {
-    Open(filename, openmode);
+IOFile::IOFile(const std::string& filename, const char openmode[], int flags) {
+    Open(filename, openmode, flags);
 }
 
 IOFile::~IOFile() {
@@ -825,11 +825,16 @@ void IOFile::Swap(IOFile& other) {
     std::swap(m_good, other.m_good);
 }
 
-bool IOFile::Open(const std::string& filename, const char openmode[]) {
+bool IOFile::Open(const std::string& filename, const char openmode[], int flags) {
     Close();
 #ifdef _WIN32
-    _wfopen_s(&m_file, Common::UTF8ToUTF16W(filename).c_str(),
-              Common::UTF8ToUTF16W(openmode).c_str());
+    if (flags != 0) {
+        m_file = _wfsopen(Common::UTF8ToUTF16W(filename).c_str(),
+                          Common::UTF8ToUTF16W(openmode).c_str(), flags);
+    } else {
+        _wfopen_s(&m_file, Common::UTF8ToUTF16W(filename).c_str(),
+                  Common::UTF8ToUTF16W(openmode).c_str());
+    }
 #else
     m_file = fopen(filename.c_str(), openmode);
 #endif
diff --git a/src/common/file_util.h b/src/common/file_util.h
index 091234977..8674ac224 100644
--- a/src/common/file_util.h
+++ b/src/common/file_util.h
@@ -156,7 +156,8 @@ void SplitFilename83(const std::string& filename, std::array<char, 9>& short_nam
 class IOFile : public NonCopyable {
 public:
     IOFile();
-    IOFile(const std::string& filename, const char openmode[]);
+    /// Opens the file. flags is for windows shared file settings and are ignored on other oses
+    IOFile(const std::string& filename, const char openmode[], int flags = 0);
 
     ~IOFile();
 
@@ -165,7 +166,7 @@ public:
 
     void Swap(IOFile& other);
 
-    bool Open(const std::string& filename, const char openmode[]);
+    bool Open(const std::string& filename, const char openmode[], int flags = 0);
     bool Close();
 
     template <typename T>
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 4d80fd8e2..cae48d9f3 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -9,6 +9,11 @@
 #include <future>
 #include <memory>
 #include <thread>
+#ifdef _WIN32
+#include <share.h> // For _SH_DENYWR
+#else
+#define _SH_DENYWR 0
+#endif
 #include "common/assert.h"
 #include "common/common_funcs.h" // snprintf compatibility define
 #include "common/logging/backend.h"
@@ -68,8 +73,7 @@ private:
             using namespace std::chrono_literals;
             Entry entry;
             while (running) {
-                if (!message_queue.Pop(entry)) {
-                    std::this_thread::sleep_for(1ms);
+                if (!message_queue.PopWait(entry)) {
                     continue;
                 }
                 for (const auto& backend : backends) {
@@ -97,11 +101,18 @@ void ColorConsoleBackend::Write(const Entry& entry) {
     PrintColoredMessage(entry);
 }
 
+// _SH_DENYWR allows read only access to the file for other programs.
+// It is #defined to 0 on other platforms
+FileBackend::FileBackend(const std::string& filename) : file(filename, "w", _SH_DENYWR) {}
+
 void FileBackend::Write(const Entry& entry) {
     if (!file.IsOpen()) {
         return;
     }
     file.WriteString(FormatLogMessage(entry) + '\n');
+    if (entry.log_level >= Level::Error) {
+        file.Flush();
+    }
 }
 
 /// Macro listing all log classes. Code should define CLS and SUB as desired before invoking this.
diff --git a/src/common/logging/backend.h b/src/common/logging/backend.h
index dfa4944f4..5feef5dd4 100644
--- a/src/common/logging/backend.h
+++ b/src/common/logging/backend.h
@@ -78,11 +78,12 @@ public:
 };
 
 /**
- * Backend that writes to a file passed into the constructor
+ * Backend that writes to a file passed into the constructor. If a log level is error or higher, it
+ * will flush immediately after writing
  */
 class FileBackend : public Backend {
 public:
-    explicit FileBackend(const std::string& filename) : file(filename, "w") {}
+    explicit FileBackend(const std::string& filename);
 
     const char* GetName() const override {
         return "file";