diff --git a/Utilities/File.cpp b/Utilities/File.cpp index 225c7d4547..421fc7e04a 100644 --- a/Utilities/File.cpp +++ b/Utilities/File.cpp @@ -764,7 +764,13 @@ fs::file::file(const std::string& path, bs_t mode) disp = test(mode & fs::trunc) ? TRUNCATE_EXISTING : OPEN_EXISTING; } - const HANDLE handle = CreateFileW(to_wchar(path).get(), access, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL, disp, FILE_ATTRIBUTE_NORMAL, NULL); + DWORD share = 0; + if (!test(mode & fs::unshare)) + { + share |= FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE; + } + + const HANDLE handle = CreateFileW(to_wchar(path).get(), access, share, NULL, disp, FILE_ATTRIBUTE_NORMAL, NULL); if (handle == INVALID_HANDLE_VALUE) { diff --git a/Utilities/File.h b/Utilities/File.h index 9293410461..24d200c8e0 100644 --- a/Utilities/File.h +++ b/Utilities/File.h @@ -25,6 +25,7 @@ namespace fs create, trunc, excl, + unshare, __bitset_enum_max }; @@ -35,6 +36,7 @@ namespace fs constexpr auto create = +open_mode::create; // Create file if it doesn't exist constexpr auto trunc = +open_mode::trunc; // Clear opened file if it's not empty constexpr auto excl = +open_mode::excl; // Failure if the file already exists (used with `create`) + constexpr auto unshare = +open_mode::unshare; // Prevent opening the file twice constexpr auto rewrite = open_mode::write + open_mode::create + open_mode::trunc; diff --git a/Utilities/Log.cpp b/Utilities/Log.cpp index 2ed352d98f..0d8e419250 100644 --- a/Utilities/Log.cpp +++ b/Utilities/Log.cpp @@ -9,9 +9,11 @@ #include #ifdef _WIN32 +#define NOMINMAX #include #else #include +#include #endif static std::string empty_string() @@ -45,15 +47,22 @@ void fmt_class_string::format(std::string& out, u64 arg) namespace logs { + constexpr std::size_t s_log_size = 64 * 1024 * 1024; + class file_writer { - // Could be memory-mapped file fs::file m_file; +#ifdef _WIN32 + ::HANDLE m_fmap; +#endif + atomic_t m_pos{0}; + uchar* m_fptr; + public: file_writer(const std::string& name); - virtual ~file_writer() = default; + virtual ~file_writer(); // Append raw data void log(const char* text, std::size_t size); @@ -63,6 +72,8 @@ namespace logs { file_listener(const std::string& name); + virtual ~file_listener() = default; + // Encode level, current thread name, channel name and write log message virtual void log(u64 stamp, const message& msg, const std::string& prefix, const std::string& text) override; }; @@ -273,10 +284,17 @@ logs::file_writer::file_writer(const std::string& name) { try { - if (!m_file.open(fs::get_config_dir() + name, fs::rewrite + fs::append)) + if (!m_file.open(fs::get_config_dir() + name, fs::read + fs::write + fs::create + fs::trunc + fs::unshare)) { fmt::throw_exception("Can't create log file %s (error %s)", name, fs::g_tls_error); } + +#ifdef _WIN32 + m_fmap = CreateFileMappingW(m_file.get_handle(), 0, PAGE_READWRITE, s_log_size >> 32, s_log_size & 0xffffffff, 0); + m_fptr = (uchar*)MapViewOfFile(m_fmap, FILE_MAP_WRITE, 0, 0, 0); +#else + m_fptr = (uchar*)::mmap(0, s_log_size, PROT_READ | PROT_WRITE, MAP_SHARED, m_file.get_handle(), 0); +#endif } catch (...) { @@ -284,9 +302,29 @@ logs::file_writer::file_writer(const std::string& name) } } +logs::file_writer::~file_writer() +{ +#ifdef _WIN32 + UnmapViewOfFile(m_fptr); + CloseHandle(m_fmap); + m_file.seek(std::min(+m_pos, s_log_size)); + SetEndOfFile(m_file.get_handle()); +#else + ::munmap(m_fptr, s_log_size); + m_file.trunc(std::min(+m_pos, s_log_size)); +#endif +} + void logs::file_writer::log(const char* text, std::size_t size) { - m_file.write(text, size); + // Acquire memory + const auto pos = m_pos.fetch_add(size); + + // Write if possible + if (pos + size <= s_log_size) + { + std::memcpy(m_fptr + pos, text, size); + } } logs::file_listener::file_listener(const std::string& name)