Reapply "Refactor log channel registration mechanism"

Changes wrt. previous version:
- add #include <atomic>: fix build on windows
- add extra {} around the string literals used to initialize
  llvm::StringLiteral: fix gcc build

llvm-svn: 295442
diff --git a/lldb/source/Core/Log.cpp b/lldb/source/Core/Log.cpp
index 0a98379..181dcc2 100644
--- a/lldb/source/Core/Log.cpp
+++ b/lldb/source/Core/Log.cpp
@@ -18,8 +18,10 @@
 #include "lldb/Utility/StreamString.h"
 
 // Other libraries and framework includes
+#include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallString.h"
 #include "llvm/Support/Chrono.h"
+#include "llvm/Support/ManagedStatic.h"
 #include "llvm/Support/Path.h"
 #include "llvm/Support/Signals.h"
 #include "llvm/Support/raw_ostream.h"
@@ -36,6 +38,76 @@
 using namespace lldb;
 using namespace lldb_private;
 
+namespace {
+  struct ChannelAndLog {
+    Log log;
+    Log::Channel &channel;
+
+    ChannelAndLog(Log::Channel &channel) : channel(channel) {}
+  };
+  typedef llvm::StringMap<ChannelAndLog> ChannelMap;
+}
+
+static llvm::ManagedStatic<ChannelMap> g_channel_map;
+
+static void ListCategories(Stream &stream, const ChannelMap::value_type &entry) {
+  stream.Format("Logging categories for '{0}':\n", entry.first());
+  stream.Format("  all - all available logging categories\n");
+  stream.Format("  default - default set of logging categories\n");
+  for (const auto &category : entry.second.channel.categories)
+    stream.Format("  {0} - {1}\n", category.name, category.description);
+}
+
+static uint32_t GetFlags(Stream &stream, const ChannelMap::value_type &entry,
+                  const char **categories) {
+  bool list_categories = false;
+  uint32_t flags = 0;
+  for (size_t i = 0; categories[i]; ++i) {
+    if (llvm::StringRef("all").equals_lower(categories[i])) {
+      flags |= UINT32_MAX;
+      continue;
+    }
+    if (llvm::StringRef("default").equals_lower(categories[i])) {
+      flags |= entry.second.channel.default_flags;
+      continue;
+    }
+    auto cat = llvm::find_if(entry.second.channel.categories,
+                             [&](const Log::Category &c) {
+                               return c.name.equals_lower(categories[i]);
+                             });
+    if (cat != entry.second.channel.categories.end()) {
+      flags |= cat->flag;
+      continue;
+    }
+    stream.Format("error: unrecognized log category '{0}'\n", categories[i]);
+    list_categories = true;
+  }
+  if (list_categories)
+    ListCategories(stream, entry);
+  return flags;
+}
+
+void Log::Channel::Enable(Log &log,
+                          const std::shared_ptr<llvm::raw_ostream> &stream_sp,
+                          uint32_t flags) {
+  log.GetMask().Set(flags);
+  if (log.GetMask().Get()) {
+    log.SetStream(stream_sp);
+    log_ptr.store(&log, std::memory_order_release);
+  }
+}
+
+void Log::Channel::Disable(uint32_t flags) {
+  Log *log = log_ptr.load(std::memory_order_acquire);
+  if (!log)
+    return;
+  log->GetMask().Clear(flags);
+  if (!log->GetMask().Get()) {
+    log->SetStream(nullptr);
+    log_ptr.store(nullptr, std::memory_order_release);
+  }
+}
+
 Log::Log() : m_stream_sp(), m_options(0), m_mask_bits(0) {}
 
 Log::Log(const std::shared_ptr<llvm::raw_ostream> &stream_sp)
@@ -152,9 +224,6 @@
 typedef std::map<ConstString, Log::Callbacks> CallbackMap;
 typedef CallbackMap::iterator CallbackMapIter;
 
-typedef std::map<ConstString, LogChannelSP> LogChannelMap;
-typedef LogChannelMap::iterator LogChannelMapIter;
-
 // Surround our callback map with a singleton function so we don't have any
 // global initializers.
 static CallbackMap &GetCallbackMap() {
@@ -162,9 +231,17 @@
   return g_callback_map;
 }
 
-static LogChannelMap &GetChannelMap() {
-  static LogChannelMap g_channel_map;
-  return g_channel_map;
+void Log::Register(llvm::StringRef name, Channel &channel) {
+  auto iter = g_channel_map->try_emplace(name, channel);
+  assert(iter.second == true);
+  (void)iter;
+}
+
+void Log::Unregister(llvm::StringRef name) {
+  auto iter = g_channel_map->find(name);
+  assert(iter != g_channel_map->end());
+  iter->second.channel.Disable(UINT32_MAX);
+  g_channel_map->erase(iter);
 }
 
 void Log::RegisterLogChannel(const ConstString &channel,
@@ -190,7 +267,7 @@
 
 bool Log::EnableLogChannel(
     const std::shared_ptr<llvm::raw_ostream> &log_stream_sp,
-    uint32_t log_options, const char *channel, const char **categories,
+    uint32_t log_options, llvm::StringRef channel, const char **categories,
     Stream &error_stream) {
   Log::Callbacks log_callbacks;
   if (Log::GetLogChannelCallbacks(ConstString(channel), log_callbacks)) {
@@ -198,52 +275,52 @@
     return true;
   }
 
-  LogChannelSP log_channel_sp(LogChannel::FindPlugin(channel));
-  if (log_channel_sp) {
-    if (log_channel_sp->Enable(log_stream_sp, log_options, &error_stream,
-                               categories)) {
-      return true;
-    } else {
-      error_stream.Printf("Invalid log channel '%s'.\n", channel);
-      return false;
-    }
-  } else {
-    error_stream.Printf("Invalid log channel '%s'.\n", channel);
+  auto iter = g_channel_map->find(channel);
+  if (iter == g_channel_map->end()) {
+    error_stream.Format("Invalid log channel '{0}'.\n", channel);
     return false;
   }
+  uint32_t flags = categories && categories[0]
+                       ? GetFlags(error_stream, *iter, categories)
+                       : iter->second.channel.default_flags;
+  iter->second.channel.Enable(iter->second.log, log_stream_sp, flags);
+  return true;
 }
 
-void Log::EnableAllLogChannels(
-    const std::shared_ptr<llvm::raw_ostream> &log_stream_sp,
-    uint32_t log_options, const char **categories, Stream *feedback_strm) {
-  CallbackMap &callback_map = GetCallbackMap();
-  CallbackMapIter pos, end = callback_map.end();
-
-  for (pos = callback_map.begin(); pos != end; ++pos)
-    pos->second.enable(log_stream_sp, log_options, categories, feedback_strm);
-
-  LogChannelMap &channel_map = GetChannelMap();
-  LogChannelMapIter channel_pos, channel_end = channel_map.end();
-  for (channel_pos = channel_map.begin(); channel_pos != channel_end;
-       ++channel_pos) {
-    channel_pos->second->Enable(log_stream_sp, log_options, feedback_strm,
-                                categories);
+bool Log::DisableLogChannel(llvm::StringRef channel, const char **categories,
+                            Stream &error_stream) {
+  Log::Callbacks log_callbacks;
+  if (Log::GetLogChannelCallbacks(ConstString(channel), log_callbacks)) {
+    log_callbacks.disable(categories, &error_stream);
+    return true;
   }
+
+  auto iter = g_channel_map->find(channel);
+  if (iter == g_channel_map->end()) {
+    error_stream.Format("Invalid log channel '{0}'.\n", channel);
+    return false;
+  }
+  uint32_t flags = categories && categories[0]
+                       ? GetFlags(error_stream, *iter, categories)
+                       : UINT32_MAX;
+  iter->second.channel.Disable(flags);
+  return true;
 }
 
-void Log::AutoCompleteChannelName(const char *channel_name,
-                                  StringList &matches) {
-  LogChannelMap &map = GetChannelMap();
-  LogChannelMapIter pos, end = map.end();
-  for (pos = map.begin(); pos != end; ++pos) {
-    const char *pos_channel_name = pos->first.GetCString();
-    if (channel_name && channel_name[0]) {
-      if (NameMatches(channel_name, eNameMatchStartsWith, pos_channel_name)) {
-        matches.AppendString(pos_channel_name);
-      }
-    } else
-      matches.AppendString(pos_channel_name);
+bool Log::ListChannelCategories(llvm::StringRef channel, Stream &stream) {
+  Log::Callbacks log_callbacks;
+  if (Log::GetLogChannelCallbacks(ConstString(channel), log_callbacks)) {
+    log_callbacks.list_categories(&stream);
+    return true;
   }
+
+  auto ch = g_channel_map->find(channel);
+  if (ch == g_channel_map->end()) {
+    stream.Format("Invalid log channel '{0}'.\n", channel);
+    return false;
+  }
+  ListCategories(stream, *ch);
+  return true;
 }
 
 void Log::DisableAllLogChannels(Stream *feedback_strm) {
@@ -254,11 +331,8 @@
   for (pos = callback_map.begin(); pos != end; ++pos)
     pos->second.disable(categories, feedback_strm);
 
-  LogChannelMap &channel_map = GetChannelMap();
-  LogChannelMapIter channel_pos, channel_end = channel_map.end();
-  for (channel_pos = channel_map.begin(); channel_pos != channel_end;
-       ++channel_pos)
-    channel_pos->second->Disable(categories, feedback_strm);
+  for (auto &entry : *g_channel_map)
+    entry.second.channel.Disable(UINT32_MAX);
 }
 
 void Log::Initialize() {
@@ -270,9 +344,8 @@
 
 void Log::ListAllLogChannels(Stream *strm) {
   CallbackMap &callback_map = GetCallbackMap();
-  LogChannelMap &channel_map = GetChannelMap();
 
-  if (callback_map.empty() && channel_map.empty()) {
+  if (callback_map.empty() && g_channel_map->empty()) {
     strm->PutCString("No logging channels are currently registered.\n");
     return;
   }
@@ -281,17 +354,9 @@
   for (pos = callback_map.begin(); pos != end; ++pos)
     pos->second.list_categories(strm);
 
-  uint32_t idx = 0;
-  const char *name;
-  for (idx = 0;
-       (name = PluginManager::GetLogChannelCreateNameAtIndex(idx)) != nullptr;
-       ++idx) {
-    LogChannelSP log_channel_sp(LogChannel::FindPlugin(name));
-    if (log_channel_sp)
-      log_channel_sp->ListCategories(strm);
-  }
+  for (const auto &channel : *g_channel_map)
+    ListCategories(*strm, channel);
 }
-
 bool Log::GetVerbose() const { return m_options.Test(LLDB_LOG_OPTION_VERBOSE); }
 
 void Log::WriteHeader(llvm::raw_ostream &OS, llvm::StringRef file,
@@ -358,33 +423,3 @@
   message << payload << "\n";
   WriteMessage(message.str());
 }
-
-LogChannelSP LogChannel::FindPlugin(const char *plugin_name) {
-  LogChannelSP log_channel_sp;
-  LogChannelMap &channel_map = GetChannelMap();
-  ConstString log_channel_name(plugin_name);
-  LogChannelMapIter pos = channel_map.find(log_channel_name);
-  if (pos == channel_map.end()) {
-    ConstString const_plugin_name(plugin_name);
-    LogChannelCreateInstance create_callback =
-        PluginManager::GetLogChannelCreateCallbackForPluginName(
-            const_plugin_name);
-    if (create_callback) {
-      log_channel_sp.reset(create_callback());
-      if (log_channel_sp) {
-        // Cache the one and only loaded instance of each log channel
-        // plug-in after it has been loaded once.
-        channel_map[log_channel_name] = log_channel_sp;
-      }
-    }
-  } else {
-    // We have already loaded an instance of this log channel class,
-    // so just return the cached instance.
-    log_channel_sp = pos->second;
-  }
-  return log_channel_sp;
-}
-
-LogChannel::LogChannel() : m_log_ap() {}
-
-LogChannel::~LogChannel() = default;