Index: lldb/include/lldb/Core/Debugger.h =================================================================== --- lldb/include/lldb/Core/Debugger.h +++ lldb/include/lldb/Core/Debugger.h @@ -53,6 +53,8 @@ } namespace lldb_private { +class LogHandler; +class CallbackLogHandler; class Address; class CommandInterpreter; class Process; @@ -553,8 +555,8 @@ llvm::Optional m_current_event_id; - llvm::StringMap> m_log_streams; - std::shared_ptr m_log_callback_stream_sp; + llvm::StringMap> m_stream_handlers; + std::shared_ptr m_callback_handler_sp; ConstString m_instance_name; static LoadPluginCallbackType g_load_plugin_callback; typedef std::vector LoadedPluginsList; Index: lldb/include/lldb/Utility/Log.h =================================================================== --- lldb/include/lldb/Utility/Log.h +++ lldb/include/lldb/Utility/Log.h @@ -45,6 +45,41 @@ // Logging Functions namespace lldb_private { +class LogHandler { +public: + virtual ~LogHandler() = default; + virtual void Emit(std::string message) = 0; + virtual void Flush() = 0; +}; + +class StreamLogHandler : public LogHandler { +public: + StreamLogHandler(int fd, bool should_close, bool unbuffered); + + void Emit(std::string message) override; + void Flush() override; + + static std::shared_ptr Create(int fd, bool unbuffered); + +private: + llvm::raw_fd_ostream m_stream; +}; + +class CallbackLogHandler : public LogHandler { +public: + CallbackLogHandler(lldb::LogOutputCallback callback, void *baton); + + void Emit(std::string message) override; + void Flush() override; + + static std::shared_ptr + Create(lldb::LogOutputCallback callback, void *baton); + +private: + lldb::LogOutputCallback m_callback; + void *m_baton; +}; + class Log final { public: /// The underlying type of all log channel enums. Declare them as: @@ -111,7 +146,7 @@ static void Unregister(llvm::StringRef name); static bool - EnableLogChannel(const std::shared_ptr &log_stream_sp, + EnableLogChannel(const std::shared_ptr &log_handler_sp, uint32_t log_options, llvm::StringRef channel, llvm::ArrayRef categories, llvm::raw_ostream &error_stream); @@ -188,7 +223,7 @@ // Their modification however, is still protected by this mutex. llvm::sys::RWMutex m_mutex; - std::shared_ptr m_stream_sp; + std::shared_ptr m_handler; std::atomic m_options{0}; std::atomic m_mask{0}; @@ -199,13 +234,13 @@ void Format(llvm::StringRef file, llvm::StringRef function, const llvm::formatv_object_base &payload); - std::shared_ptr GetStream() { + std::shared_ptr GetHandler() { llvm::sys::ScopedReader lock(m_mutex); - return m_stream_sp; + return m_handler; } - void Enable(const std::shared_ptr &stream_sp, - uint32_t options, uint32_t flags); + void Enable(const std::shared_ptr &handler_sp, uint32_t options, + uint32_t flags); void Disable(uint32_t flags); Index: lldb/include/lldb/Utility/StreamCallback.h =================================================================== --- lldb/include/lldb/Utility/StreamCallback.h +++ /dev/null @@ -1,35 +0,0 @@ -//===-- StreamCallback.h -----------------------------------*- C++ -*-===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#ifndef LLDB_UTILITY_STREAMCALLBACK_H -#define LLDB_UTILITY_STREAMCALLBACK_H - -#include "lldb/lldb-types.h" -#include "llvm/Support/raw_ostream.h" - -#include -#include - -namespace lldb_private { - -class StreamCallback : public llvm::raw_ostream { -public: - StreamCallback(lldb::LogOutputCallback callback, void *baton); - ~StreamCallback() override = default; - -private: - lldb::LogOutputCallback m_callback; - void *m_baton; - - void write_impl(const char *Ptr, size_t Size) override; - uint64_t current_pos() const override; -}; - -} // namespace lldb_private - -#endif // LLDB_UTILITY_STREAMCALLBACK_H Index: lldb/source/Core/Debugger.cpp =================================================================== --- lldb/source/Core/Debugger.cpp +++ lldb/source/Core/Debugger.cpp @@ -51,7 +51,6 @@ #include "lldb/Utility/ReproducerProvider.h" #include "lldb/Utility/State.h" #include "lldb/Utility/Stream.h" -#include "lldb/Utility/StreamCallback.h" #include "lldb/Utility/StreamString.h" #if defined(_WIN32) @@ -758,8 +757,7 @@ m_forward_listener_sp(), m_clear_once() { m_instance_name.SetString(llvm::formatv("debugger_{0}", GetID()).str()); if (log_callback) - m_log_callback_stream_sp = - std::make_shared(log_callback, baton); + m_callback_handler_sp = CallbackLogHandler::Create(log_callback, baton); m_command_interpreter_up->Initialize(); // Always add our default platform to the platform list PlatformSP default_platform_sp(Platform::GetHostPlatform()); @@ -1292,8 +1290,7 @@ // For simplicity's sake, I am not going to deal with how to close down any // open logging streams, I just redirect everything from here on out to the // callback. - m_log_callback_stream_sp = - std::make_shared(log_callback, baton); + m_callback_handler_sp = CallbackLogHandler::Create(log_callback, baton); } static void PrivateReportProgress(Debugger &debugger, uint64_t progress_id, @@ -1412,22 +1409,21 @@ llvm::StringRef log_file, uint32_t log_options, llvm::raw_ostream &error_stream) { const bool should_close = true; - const bool unbuffered = true; - std::shared_ptr log_stream_sp; - if (m_log_callback_stream_sp) { - log_stream_sp = m_log_callback_stream_sp; + std::shared_ptr log_handler_sp; + if (m_callback_handler_sp) { + log_handler_sp = m_callback_handler_sp; // For now when using the callback mode you always get thread & timestamp. log_options |= LLDB_LOG_OPTION_PREPEND_TIMESTAMP | LLDB_LOG_OPTION_PREPEND_THREAD_NAME; } else if (log_file.empty()) { - log_stream_sp = std::make_shared( - GetOutputFile().GetDescriptor(), !should_close, unbuffered); + log_handler_sp = StreamLogHandler::Create(GetOutputFile().GetDescriptor(), + !should_close); } else { - auto pos = m_log_streams.find(log_file); - if (pos != m_log_streams.end()) - log_stream_sp = pos->second.lock(); - if (!log_stream_sp) { + auto pos = m_stream_handlers.find(log_file); + if (pos != m_stream_handlers.end()) + log_handler_sp = pos->second.lock(); + if (!log_handler_sp) { File::OpenOptions flags = File::eOpenOptionWriteOnly | File::eOpenOptionCanCreate; if (log_options & LLDB_LOG_OPTION_APPEND) @@ -1442,18 +1438,18 @@ return false; } - log_stream_sp = std::make_shared( - (*file)->GetDescriptor(), should_close, unbuffered); - m_log_streams[log_file] = log_stream_sp; + log_handler_sp = + StreamLogHandler::Create((*file)->GetDescriptor(), should_close); + m_stream_handlers[log_file] = log_handler_sp; } } - assert(log_stream_sp); + assert(log_handler_sp); if (log_options == 0) log_options = LLDB_LOG_OPTION_PREPEND_THREAD_NAME | LLDB_LOG_OPTION_THREADSAFE; - return Log::EnableLogChannel(log_stream_sp, log_options, channel, categories, + return Log::EnableLogChannel(log_handler_sp, log_options, channel, categories, error_stream); } Index: lldb/source/Utility/CMakeLists.txt =================================================================== --- lldb/source/Utility/CMakeLists.txt +++ lldb/source/Utility/CMakeLists.txt @@ -56,7 +56,6 @@ State.cpp Status.cpp Stream.cpp - StreamCallback.cpp StreamString.cpp StringExtractor.cpp StringExtractorGDBRemote.cpp Index: lldb/source/Utility/Log.cpp =================================================================== --- lldb/source/Utility/Log.cpp +++ lldb/source/Utility/Log.cpp @@ -84,14 +84,14 @@ return flags; } -void Log::Enable(const std::shared_ptr &stream_sp, +void Log::Enable(const std::shared_ptr &handler_sp, uint32_t options, uint32_t flags) { llvm::sys::ScopedWriter lock(m_mutex); MaskType mask = m_mask.fetch_or(flags, std::memory_order_relaxed); if (mask | flags) { m_options.store(options, std::memory_order_relaxed); - m_stream_sp = stream_sp; + m_handler = handler_sp; m_channel.log_ptr.store(this, std::memory_order_relaxed); } } @@ -101,7 +101,7 @@ MaskType mask = m_mask.fetch_and(~flags, std::memory_order_relaxed); if (!(mask & ~flags)) { - m_stream_sp.reset(); + m_handler.reset(); m_channel.log_ptr.store(nullptr, std::memory_order_relaxed); } } @@ -191,10 +191,10 @@ g_channel_map->erase(iter); } -bool Log::EnableLogChannel( - const std::shared_ptr &log_stream_sp, - uint32_t log_options, llvm::StringRef channel, - llvm::ArrayRef categories, llvm::raw_ostream &error_stream) { +bool Log::EnableLogChannel(const std::shared_ptr &log_handler_sp, + uint32_t log_options, llvm::StringRef channel, + llvm::ArrayRef categories, + llvm::raw_ostream &error_stream) { auto iter = g_channel_map->find(channel); if (iter == g_channel_map->end()) { error_stream << llvm::formatv("Invalid log channel '{0}'.\n", channel); @@ -203,7 +203,7 @@ uint32_t flags = categories.empty() ? iter->second.m_channel.default_flags : GetFlags(error_stream, *iter, categories); - iter->second.Enable(log_stream_sp, log_options, flags); + iter->second.Enable(log_handler_sp, log_options, flags); return true; } @@ -314,19 +314,19 @@ void Log::WriteMessage(const std::string &message) { // Make a copy of our stream shared pointer in case someone disables our log // while we are logging and releases the stream - auto stream_sp = GetStream(); - if (!stream_sp) + auto handler_sp = GetHandler(); + if (!handler_sp) return; Flags options = GetOptions(); if (options.Test(LLDB_LOG_OPTION_THREADSAFE)) { static std::recursive_mutex g_LogThreadedMutex; std::lock_guard guard(g_LogThreadedMutex); - *stream_sp << message; - stream_sp->flush(); + handler_sp->Emit(message); + handler_sp->Flush(); } else { - *stream_sp << message; - stream_sp->flush(); + handler_sp->Emit(message); + handler_sp->Flush(); } } @@ -338,3 +338,31 @@ message << payload << "\n"; WriteMessage(message.str()); } + +StreamLogHandler::StreamLogHandler(int fd, bool should_close, bool unbuffered) + : m_stream(fd, should_close, unbuffered) {} + +void StreamLogHandler::Emit(std::string message) { m_stream << message; } + +void StreamLogHandler::Flush() { m_stream.flush(); } + +std::shared_ptr StreamLogHandler::Create(int fd, + bool should_close) { + constexpr const bool unbuffered = true; + return std::make_shared(fd, should_close, unbuffered); +} + +CallbackLogHandler::CallbackLogHandler(lldb::LogOutputCallback callback, + void *baton) + : m_callback(callback), m_baton(baton) {} + +void CallbackLogHandler::Emit(std::string message) { + m_callback(message.c_str(), m_baton); +} + +void CallbackLogHandler::Flush() {} + +std::shared_ptr +CallbackLogHandler::Create(lldb::LogOutputCallback callback, void *baton) { + return std::make_shared(callback, baton); +} Index: lldb/source/Utility/StreamCallback.cpp =================================================================== --- lldb/source/Utility/StreamCallback.cpp +++ /dev/null @@ -1,22 +0,0 @@ -//===-- StreamCallback.cpp ------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lldb/Utility/StreamCallback.h" - -#include - -using namespace lldb_private; - -StreamCallback::StreamCallback(lldb::LogOutputCallback callback, void *baton) - : llvm::raw_ostream(true), m_callback(callback), m_baton(baton) {} - -void StreamCallback::write_impl(const char *Ptr, size_t Size) { - m_callback(std::string(Ptr, Size).c_str(), m_baton); -} - -uint64_t StreamCallback::current_pos() const { return 0; } Index: lldb/unittests/Core/CMakeLists.txt =================================================================== --- lldb/unittests/Core/CMakeLists.txt +++ lldb/unittests/Core/CMakeLists.txt @@ -8,7 +8,6 @@ RichManglingContextTest.cpp SourceLocationSpecTest.cpp SourceManagerTest.cpp - StreamCallbackTest.cpp UniqueCStringMapTest.cpp LINK_LIBS Index: lldb/unittests/Core/StreamCallbackTest.cpp =================================================================== --- lldb/unittests/Core/StreamCallbackTest.cpp +++ /dev/null @@ -1,27 +0,0 @@ -//===-- StreamCallbackTest.cpp --------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -#include "lldb/Utility/StreamCallback.h" -#include "gtest/gtest.h" - -using namespace lldb; -using namespace lldb_private; - -static char test_baton; -static size_t callback_count = 0; -static void TestCallback(const char *data, void *baton) { - EXPECT_STREQ("Foobar", data); - EXPECT_EQ(&test_baton, baton); - ++callback_count; -} - -TEST(StreamCallbackTest, Callback) { - StreamCallback stream(TestCallback, &test_baton); - stream << "Foobar"; - EXPECT_EQ(1u, callback_count); -}