diff options
Diffstat (limited to 'src/common')
-rw-r--r-- | src/common/CMakeLists.txt | 5 | ||||
-rw-r--r-- | src/common/detached_tasks.cpp | 41 | ||||
-rw-r--r-- | src/common/detached_tasks.h | 40 | ||||
-rw-r--r-- | src/common/hex_util.cpp | 19 | ||||
-rw-r--r-- | src/common/hex_util.h | 5 | ||||
-rw-r--r-- | src/common/logging/text_formatter.cpp | 2 | ||||
-rw-r--r-- | src/common/param_package.cpp | 18 | ||||
-rw-r--r-- | src/common/param_package.h | 2 | ||||
-rw-r--r-- | src/common/web_result.h | 24 |
9 files changed, 153 insertions, 3 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 6a3f1fe08..d0e506689 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -29,7 +29,7 @@ if ($ENV{CI}) if (BUILD_VERSION) # This leaves a trailing space on the last word, but we actually want that # because of how it's styled in the title bar. - set(BUILD_FULLNAME "${REPO_NAME} #${BUILD_VERSION} ") + set(BUILD_FULLNAME "${REPO_NAME} ${BUILD_VERSION} ") else() set(BUILD_FULLNAME "") endif() @@ -41,6 +41,8 @@ configure_file("${CMAKE_CURRENT_SOURCE_DIR}/scm_rev.cpp.in" "${CMAKE_CURRENT_SOU add_library(common STATIC alignment.h assert.h + detached_tasks.cpp + detached_tasks.h bit_field.h bit_set.h cityhash.cpp @@ -87,6 +89,7 @@ add_library(common STATIC timer.cpp timer.h vector_math.h + web_result.h ) if(ARCHITECTURE_x86_64) diff --git a/src/common/detached_tasks.cpp b/src/common/detached_tasks.cpp new file mode 100644 index 000000000..a347d9e02 --- /dev/null +++ b/src/common/detached_tasks.cpp @@ -0,0 +1,41 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <thread> +#include "common/assert.h" +#include "common/detached_tasks.h" + +namespace Common { + +DetachedTasks* DetachedTasks::instance = nullptr; + +DetachedTasks::DetachedTasks() { + ASSERT(instance == nullptr); + instance = this; +} + +void DetachedTasks::WaitForAllTasks() { + std::unique_lock<std::mutex> lock(mutex); + cv.wait(lock, [this]() { return count == 0; }); +} + +DetachedTasks::~DetachedTasks() { + std::unique_lock<std::mutex> lock(mutex); + ASSERT(count == 0); + instance = nullptr; +} + +void DetachedTasks::AddTask(std::function<void()> task) { + std::unique_lock<std::mutex> lock(instance->mutex); + ++instance->count; + std::thread([task{std::move(task)}]() { + task(); + std::unique_lock<std::mutex> lock(instance->mutex); + --instance->count; + std::notify_all_at_thread_exit(instance->cv, std::move(lock)); + }) + .detach(); +} + +} // namespace Common diff --git a/src/common/detached_tasks.h b/src/common/detached_tasks.h new file mode 100644 index 000000000..5dd8fc27b --- /dev/null +++ b/src/common/detached_tasks.h @@ -0,0 +1,40 @@ +// Copyright 2018 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <condition_variable> +#include <functional> + +namespace Common { + +/** + * A background manager which ensures that all detached task is finished before program exits. + * + * Some tasks, telemetry submission for example, prefer executing asynchronously and don't care + * about the result. These tasks are suitable for std::thread::detach(). However, this is unsafe if + * the task is launched just before the program exits (which is a common case for telemetry), so we + * need to block on these tasks on program exit. + * + * To make detached task safe, a single DetachedTasks object should be placed in the main(), and + * call WaitForAllTasks() after all program execution but before global/static variable destruction. + * Any potentially unsafe detached task should be executed via DetachedTasks::AddTask. + */ +class DetachedTasks { +public: + DetachedTasks(); + ~DetachedTasks(); + void WaitForAllTasks(); + + static void AddTask(std::function<void()> task); + +private: + static DetachedTasks* instance; + + std::condition_variable cv; + std::mutex mutex; + int count = 0; +}; + +} // namespace Common diff --git a/src/common/hex_util.cpp b/src/common/hex_util.cpp index 589ae5cbf..5b63f9e81 100644 --- a/src/common/hex_util.cpp +++ b/src/common/hex_util.cpp @@ -18,6 +18,25 @@ u8 ToHexNibble(char c1) { return 0; } +std::vector<u8> HexStringToVector(std::string_view str, bool little_endian) { + std::vector<u8> out(str.size() / 2); + if (little_endian) { + for (std::size_t i = str.size() - 2; i <= str.size(); i -= 2) + out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]); + } else { + for (std::size_t i = 0; i < str.size(); i += 2) + out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]); + } + return out; +} + +std::string HexVectorToString(const std::vector<u8>& vector, bool upper) { + std::string out; + for (u8 c : vector) + out += fmt::format(upper ? "{:02X}" : "{:02x}", c); + return out; +} + std::array<u8, 16> operator""_array16(const char* str, std::size_t len) { if (len != 32) { LOG_ERROR(Common, diff --git a/src/common/hex_util.h b/src/common/hex_util.h index 863a5ccd9..68f003cb6 100644 --- a/src/common/hex_util.h +++ b/src/common/hex_util.h @@ -7,6 +7,7 @@ #include <array> #include <cstddef> #include <string> +#include <vector> #include <fmt/format.h> #include "common/common_types.h" @@ -14,6 +15,8 @@ namespace Common { u8 ToHexNibble(char c1); +std::vector<u8> HexStringToVector(std::string_view str, bool little_endian); + template <std::size_t Size, bool le = false> std::array<u8, Size> HexStringToArray(std::string_view str) { std::array<u8, Size> out{}; @@ -27,6 +30,8 @@ std::array<u8, Size> HexStringToArray(std::string_view str) { return out; } +std::string HexVectorToString(const std::vector<u8>& vector, bool upper = true); + template <std::size_t Size> std::string HexArrayToString(std::array<u8, Size> array, bool upper = true) { std::string out; diff --git a/src/common/logging/text_formatter.cpp b/src/common/logging/text_formatter.cpp index 05437c137..6a0605c63 100644 --- a/src/common/logging/text_formatter.cpp +++ b/src/common/logging/text_formatter.cpp @@ -31,7 +31,7 @@ std::string FormatLogMessage(const Entry& entry) { } void PrintMessage(const Entry& entry) { - auto str = FormatLogMessage(entry) + '\n'; + const auto str = FormatLogMessage(entry).append(1, '\n'); fputs(str.c_str(), stderr); } diff --git a/src/common/param_package.cpp b/src/common/param_package.cpp index 9526ca0c6..b916b4866 100644 --- a/src/common/param_package.cpp +++ b/src/common/param_package.cpp @@ -20,7 +20,15 @@ constexpr char KEY_VALUE_SEPARATOR_ESCAPE[] = "$0"; constexpr char PARAM_SEPARATOR_ESCAPE[] = "$1"; constexpr char ESCAPE_CHARACTER_ESCAPE[] = "$2"; +/// A placeholder for empty param packages to avoid empty strings +/// (they may be recognized as "not set" by some frontend libraries like qt) +constexpr char EMPTY_PLACEHOLDER[] = "[empty]"; + ParamPackage::ParamPackage(const std::string& serialized) { + if (serialized == EMPTY_PLACEHOLDER) { + return; + } + std::vector<std::string> pairs; Common::SplitString(serialized, PARAM_SEPARATOR, pairs); @@ -46,7 +54,7 @@ ParamPackage::ParamPackage(std::initializer_list<DataType::value_type> list) : d std::string ParamPackage::Serialize() const { if (data.empty()) - return ""; + return EMPTY_PLACEHOLDER; std::string result; @@ -120,4 +128,12 @@ bool ParamPackage::Has(const std::string& key) const { return data.find(key) != data.end(); } +void ParamPackage::Erase(const std::string& key) { + data.erase(key); +} + +void ParamPackage::Clear() { + data.clear(); +} + } // namespace Common diff --git a/src/common/param_package.h b/src/common/param_package.h index 7842cd4ef..6a0a9b656 100644 --- a/src/common/param_package.h +++ b/src/common/param_package.h @@ -32,6 +32,8 @@ public: void Set(const std::string& key, int value); void Set(const std::string& key, float value); bool Has(const std::string& key) const; + void Erase(const std::string& key); + void Clear(); private: DataType data; diff --git a/src/common/web_result.h b/src/common/web_result.h new file mode 100644 index 000000000..969926674 --- /dev/null +++ b/src/common/web_result.h @@ -0,0 +1,24 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <string> + +namespace Common { +struct WebResult { + enum class Code : u32 { + Success, + InvalidURL, + CredentialsMissing, + LibError, + HttpError, + WrongContent, + NoWebservice, + }; + Code result_code; + std::string result_string; + std::string returned_data; +}; +} // namespace Common |