src/hotspot/share/logging/logOutputList.hpp
changeset 47216 71c04702a3d5
parent 40656 d4964c292b78
child 49364 601146c66cad
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/hotspot/share/logging/logOutputList.hpp	Tue Sep 12 19:03:39 2017 +0200
@@ -0,0 +1,131 @@
+/*
+ * Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+#ifndef SHARE_VM_LOGGING_LOGOUTPUTLIST_HPP
+#define SHARE_VM_LOGGING_LOGOUTPUTLIST_HPP
+
+#include "logging/logLevel.hpp"
+#include "memory/allocation.hpp"
+#include "utilities/globalDefinitions.hpp"
+
+class LogOutput;
+
+// Data structure to keep track of log outputs for a given tagset.
+// Essentially a sorted linked list going from error level outputs
+// to outputs of finer levels. Keeps an index from each level to
+// the first node in the list for the corresponding level.
+// This allows a log message on, for example, info level to jump
+// straight into the list where the first info level output can
+// be found. The log message will then be printed on that output,
+// as well as all outputs in nodes that follow in the list (which
+// can be additional info level outputs and/or debug and trace outputs).
+//
+// Each instance keeps track of the number of current readers of the list.
+// To remove a node from the list the node must first be unlinked,
+// and the memory for that node can be freed whenever the removing
+// thread observes an active reader count of 0 (after unlinking it).
+class LogOutputList VALUE_OBJ_CLASS_SPEC {
+ private:
+  struct LogOutputNode : public CHeapObj<mtLogging> {
+    LogOutput*      _value;
+    LogOutputNode*  _next;
+    LogLevelType    _level;
+  };
+
+  LogOutputNode*  _level_start[LogLevel::Count];
+  volatile jint   _active_readers;
+
+  LogOutputNode* find(const LogOutput* output) const;
+  void remove_output(LogOutputNode* node);
+  void add_output(LogOutput* output, LogLevelType level);
+  void update_output_level(LogOutputNode* node, LogLevelType level);
+
+  // Bookkeeping functions to keep track of number of active readers/iterators for the list.
+  jint increase_readers();
+  jint decrease_readers();
+  void wait_until_no_readers() const;
+
+ public:
+  LogOutputList() : _active_readers(0) {
+    for (size_t i = 0; i < LogLevel::Count; i++) {
+      _level_start[i] = NULL;
+    }
+  }
+
+  // Test if the outputlist has an output for the given level.
+  bool is_level(LogLevelType level) const {
+    return _level_start[level] != NULL;
+  }
+
+  LogLevelType level_for(const LogOutput* output) const {
+    LogOutputNode* node = this->find(output);
+    if (node == NULL) {
+      return LogLevel::Off;
+    }
+    return node->_level;
+  }
+
+  // Set (add/update/remove) the output to the specified level.
+  void set_output_level(LogOutput* output, LogLevelType level);
+
+  class Iterator VALUE_OBJ_CLASS_SPEC {
+    friend class LogOutputList;
+   private:
+    LogOutputNode*  _current;
+    LogOutputList*  _list;
+    Iterator(LogOutputList* list, LogOutputNode* start) : _current(start), _list(list) {
+    }
+
+   public:
+    ~Iterator() {
+      _list->decrease_readers();
+    }
+
+    LogOutput* operator*() {
+      return _current->_value;
+    }
+
+    void operator++(int) {
+      _current = _current->_next;
+    }
+
+    bool operator!=(const LogOutputNode *ref) const {
+      return _current != ref;
+    }
+
+    LogLevelType level() const {
+      return _current->_level;
+    }
+  };
+
+  Iterator iterator(LogLevelType level = LogLevel::Last) {
+    increase_readers();
+    return Iterator(this, _level_start[level]);
+  }
+
+  LogOutputNode* end() const {
+    return NULL;
+  }
+};
+
+#endif // SHARE_VM_LOGGING_LOGOUTPUTLIST_HPP