diff options
author | Ian Rogers <irogers@google.com> | 2014-10-21 23:31:19 -0700 |
---|---|---|
committer | Ian Rogers <irogers@google.com> | 2014-10-22 12:06:23 -0700 |
commit | c7dd295a4e0cc1d15c0c96088e55a85389bade74 (patch) | |
tree | 0c08a2236bc9ba5d9a4dc75d4dd0ed2d76f8f1c6 /runtime/base | |
parent | 94e5af8602150efa95bde35cc9be9891ddf30135 (diff) | |
download | android_art-c7dd295a4e0cc1d15c0c96088e55a85389bade74.tar.gz android_art-c7dd295a4e0cc1d15c0c96088e55a85389bade74.tar.bz2 android_art-c7dd295a4e0cc1d15c0c96088e55a85389bade74.zip |
Tidy up logging.
Move gVerboseMethods to CompilerOptions. Now "--verbose-methods=" option to
dex2oat rather than runtime argument "-verbose-methods:".
Move ToStr and Dumpable out of logging.h, move LogMessageData into logging.cc
except for a forward declaration.
Remove ConstDumpable as Dump methods are all const (and make this so if not
currently true).
Make LogSeverity an enum and improve compile time assertions and type checking.
Remove log_severity.h that's only used in logging.h.
With system headers gone from logging.h, go add to .cc files missing system
header includes.
Also, make operator new in ValueObject private for compile time instantiation
checking.
Change-Id: I3228f614500ccc9b14b49c72b9821c8b0db3d641
Diffstat (limited to 'runtime/base')
-rw-r--r-- | runtime/base/bit_vector.cc | 2 | ||||
-rw-r--r-- | runtime/base/dumpable.h | 53 | ||||
-rw-r--r-- | runtime/base/logging.cc | 134 | ||||
-rw-r--r-- | runtime/base/logging.h | 365 | ||||
-rw-r--r-- | runtime/base/logging_android.cc | 43 | ||||
-rw-r--r-- | runtime/base/mutex.cc | 6 | ||||
-rw-r--r-- | runtime/base/to_str.h (renamed from runtime/base/logging_linux.cc) | 42 | ||||
-rw-r--r-- | runtime/base/unix_file/mapped_file.cc | 14 |
8 files changed, 338 insertions, 321 deletions
diff --git a/runtime/base/bit_vector.cc b/runtime/base/bit_vector.cc index 3d2f0deac5..1e0be3a433 100644 --- a/runtime/base/bit_vector.cc +++ b/runtime/base/bit_vector.cc @@ -16,6 +16,8 @@ #include "bit_vector.h" +#include <sstream> + #include "allocator.h" #include "bit_vector-inl.h" diff --git a/runtime/base/dumpable.h b/runtime/base/dumpable.h new file mode 100644 index 0000000000..3c316cc015 --- /dev/null +++ b/runtime/base/dumpable.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_BASE_DUMPABLE_H_ +#define ART_RUNTIME_BASE_DUMPABLE_H_ + +#include "base/macros.h" + +namespace art { + +// A convenience to allow any class with a "Dump(std::ostream& os)" member function +// but without an operator<< to be used as if it had an operator<<. Use like this: +// +// os << Dumpable<MyType>(my_type_instance); +// +template<typename T> +class Dumpable FINAL { + public: + explicit Dumpable(const T& value) : value_(value) { + } + + void Dump(std::ostream& os) const { + value_.Dump(os); + } + + private: + const T& value_; + + DISALLOW_COPY_AND_ASSIGN(Dumpable); +}; + +template<typename T> +std::ostream& operator<<(std::ostream& os, const Dumpable<T>& rhs) { + rhs.Dump(os); + return os; +} + +} // namespace art + +#endif // ART_RUNTIME_BASE_DUMPABLE_H_ diff --git a/runtime/base/logging.cc b/runtime/base/logging.cc index 5af597b89b..46c3538ca3 100644 --- a/runtime/base/logging.cc +++ b/runtime/base/logging.cc @@ -16,17 +16,25 @@ #include "logging.h" +#include <sstream> + #include "base/mutex.h" #include "runtime.h" #include "thread-inl.h" #include "utils.h" +// Headers for LogMessage::LogLine. +#ifdef HAVE_ANDROID_OS +#include "cutils/log.h" +#else +#include <sys/types.h> +#include <unistd.h> +#endif + namespace art { LogVerbosity gLogVerbosity; -std::vector<std::string> gVerboseMethods; - unsigned int gAborting = 0; static LogSeverity gMinimumLogSeverity = INFO; @@ -47,14 +55,6 @@ const char* ProgramInvocationShortName() { : "art"; } -// Configure logging based on ANDROID_LOG_TAGS environment variable. -// We need to parse a string that looks like -// -// *:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i -// -// The tag (or '*' for the global level) comes first, followed by a colon -// and a letter indicating the minimum priority level we're expected to log. -// This can be used to reveal or conceal logs with specific tags. void InitLogging(char* argv[]) { if (gCmdLine.get() != nullptr) { return; @@ -65,22 +65,22 @@ void InitLogging(char* argv[]) { // Stash the command line for later use. We can use /proc/self/cmdline on Linux to recover this, // but we don't have that luxury on the Mac, and there are a couple of argv[0] variants that are // commonly used. - if (argv != NULL) { + if (argv != nullptr) { gCmdLine.reset(new std::string(argv[0])); - for (size_t i = 1; argv[i] != NULL; ++i) { + for (size_t i = 1; argv[i] != nullptr; ++i) { gCmdLine->append(" "); gCmdLine->append(argv[i]); } gProgramInvocationName.reset(new std::string(argv[0])); const char* last_slash = strrchr(argv[0], '/'); - gProgramInvocationShortName.reset(new std::string((last_slash != NULL) ? last_slash + 1 + gProgramInvocationShortName.reset(new std::string((last_slash != nullptr) ? last_slash + 1 : argv[0])); } else { - // TODO: fall back to /proc/self/cmdline when argv is NULL on Linux + // TODO: fall back to /proc/self/cmdline when argv is NULL on Linux. gCmdLine.reset(new std::string("<unset>")); } const char* tags = getenv("ANDROID_LOG_TAGS"); - if (tags == NULL) { + if (tags == nullptr) { return; } @@ -119,47 +119,121 @@ void InitLogging(char* argv[]) { } } -LogMessageData::LogMessageData(const char* file, int line, LogSeverity severity, int error) - : file(file), - line_number(line), - severity(severity), - error(error) { - const char* last_slash = strrchr(file, '/'); - file = (last_slash == NULL) ? file : last_slash + 1; -} +// This indirection greatly reduces the stack impact of having +// lots of checks/logging in a function. +class LogMessageData { + public: + LogMessageData(const char* file, unsigned int line, LogSeverity severity, int error) + : file_(file), + line_number_(line), + severity_(severity), + error_(error) { + const char* last_slash = strrchr(file, '/'); + file = (last_slash == nullptr) ? file : last_slash + 1; + } + + const char * GetFile() const { + return file_; + } + unsigned int GetLineNumber() const { + return line_number_; + } + + LogSeverity GetSeverity() const { + return severity_; + } + + int GetError() const { + return error_; + } + + std::ostream& GetBuffer() { + return buffer_; + } + + std::string ToString() const { + return buffer_.str(); + } + + private: + std::ostringstream buffer_; + const char* const file_; + const unsigned int line_number_; + const LogSeverity severity_; + const int error_; + + DISALLOW_COPY_AND_ASSIGN(LogMessageData); +}; + + +LogMessage::LogMessage(const char* file, unsigned int line, LogSeverity severity, int error) + : data_(new LogMessageData(file, line, severity, error)) { +} LogMessage::~LogMessage() { - if (data_->severity < gMinimumLogSeverity) { + if (data_->GetSeverity() < gMinimumLogSeverity) { return; // No need to format something we're not going to output. } // Finish constructing the message. - if (data_->error != -1) { - data_->buffer << ": " << strerror(data_->error); + if (data_->GetError() != -1) { + data_->GetBuffer() << ": " << strerror(data_->GetError()); } - std::string msg(data_->buffer.str()); + std::string msg(data_->ToString()); // Do the actual logging with the lock held. { MutexLock mu(Thread::Current(), *Locks::logging_lock_); if (msg.find('\n') == std::string::npos) { - LogLine(*data_, msg.c_str()); + LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), msg.c_str()); } else { msg += '\n'; size_t i = 0; while (i < msg.size()) { size_t nl = msg.find('\n', i); msg[nl] = '\0'; - LogLine(*data_, &msg[i]); + LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), &msg[i]); i = nl + 1; } } } // Abort if necessary. - if (data_->severity == FATAL) { + if (data_->GetSeverity() == FATAL) { Runtime::Abort(); } } +std::ostream& LogMessage::stream() { + return data_->GetBuffer(); +} + +#ifdef HAVE_ANDROID_OS +static const android_LogPriority kLogSeverityToAndroidLogPriority[] = { + ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN, + ANDROID_LOG_ERROR, ANDROID_LOG_FATAL, ANDROID_LOG_FATAL +}; +COMPILE_ASSERT(arraysize(kLogSeverityToAndroidLogPriority) == INTERNAL_FATAL + 1, + mismatch_in_size_of_kLogSeverityToAndroidLogPriority_and_values_in_LogSeverity); +#endif + +void LogMessage::LogLine(const char* file, unsigned int line, LogSeverity log_severity, + const char* message) { +#ifdef HAVE_ANDROID_OS + const char* tag = ProgramInvocationShortName(); + int priority = kLogSeverityToAndroidLogPriority[log_severity]; + if (priority == ANDROID_LOG_FATAL) { + LOG_PRI(priority, tag, "%s:%u] %s", file, line, message); + } else { + LOG_PRI(priority, tag, "%s", message); + } +#else + static const char* log_characters = "VDIWEFF"; + CHECK_EQ(strlen(log_characters), INTERNAL_FATAL + 1U); + char severity = log_characters[log_severity]; + fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n", + ProgramInvocationShortName(), severity, getpid(), ::art::GetTid(), file, line, message); +#endif +} + } // namespace art diff --git a/runtime/base/logging.h b/runtime/base/logging.h index cf3e763f1e..5e8e994020 100644 --- a/runtime/base/logging.h +++ b/runtime/base/logging.h @@ -17,29 +17,113 @@ #ifndef ART_RUNTIME_BASE_LOGGING_H_ #define ART_RUNTIME_BASE_LOGGING_H_ -#include <cerrno> -#include <cstring> -#include <iostream> // NOLINT +#include <iostream> #include <memory> -#include <sstream> -#include <signal.h> -#include <vector> #include "base/macros.h" -#include "log_severity.h" +namespace art { + +enum LogSeverity { + VERBOSE, + DEBUG, + INFO, + WARNING, + ERROR, + FATAL, + INTERNAL_FATAL, // For Runtime::Abort. +}; + +// The members of this struct are the valid arguments to VLOG and VLOG_IS_ON in code, +// and the "-verbose:" command line argument. +struct LogVerbosity { + bool class_linker; // Enabled with "-verbose:class". + bool compiler; + bool gc; + bool heap; + bool jdwp; + bool jni; + bool monitor; + bool profiler; + bool signals; + bool startup; + bool third_party_jni; // Enabled with "-verbose:third-party-jni". + bool threads; + bool verifier; +}; + +// Global log verbosity setting, initialized by InitLogging. +extern LogVerbosity gLogVerbosity; + +// 0 if not abort, non-zero if an abort is in progress. Used on fatal exit to prevents recursive +// aborts. Global declaration allows us to disable some error checking to ensure fatal shutdown +// makes forward progress. +extern unsigned int gAborting; + +// Configure logging based on ANDROID_LOG_TAGS environment variable. +// We need to parse a string that looks like +// +// *:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i +// +// The tag (or '*' for the global level) comes first, followed by a colon +// and a letter indicating the minimum priority level we're expected to log. +// This can be used to reveal or conceal logs with specific tags. +extern void InitLogging(char* argv[]); + +// Returns the command line used to invoke the current tool or nullptr if InitLogging hasn't been +// performed. +extern const char* GetCmdLine(); + +// The command used to start the ART runtime, such as "/system/bin/dalvikvm". If InitLogging hasn't +// been performed then just returns "art" +extern const char* ProgramInvocationName(); + +// A short version of the command used to start the ART runtime, such as "dalvikvm". If InitLogging +// hasn't been performed then just returns "art" +extern const char* ProgramInvocationShortName(); + +// Logs a message to logcat on Android otherwise to stderr. If the severity is FATAL it also causes +// an abort. For example: LOG(FATAL) << "We didn't expect to reach here"; +#define LOG(severity) ::art::LogMessage(__FILE__, __LINE__, severity, -1).stream() + +// A variant of LOG that also logs the current errno value. To be used when library calls fail. +#define PLOG(severity) ::art::LogMessage(__FILE__, __LINE__, severity, errno).stream() + +// Marker that code is yet to be implemented. +#define UNIMPLEMENTED(level) LOG(level) << __PRETTY_FUNCTION__ << " unimplemented " + +// Is verbose logging enabled for the given module? Where the module is defined in LogVerbosity. +#define VLOG_IS_ON(module) UNLIKELY(::art::gLogVerbosity.module) + +// Variant of LOG that logs when verbose logging is enabled for a module. For example, +// VLOG(jni) << "A JNI operation was performed"; +#define VLOG(module) \ + if (VLOG_IS_ON(module)) \ + ::art::LogMessage(__FILE__, __LINE__, INFO, -1).stream() + +// Return the stream associated with logging for the given module. +#define VLOG_STREAM(module) ::art::LogMessage(__FILE__, __LINE__, INFO, -1).stream() + +// Check whether condition x holds and LOG(FATAL) if not. The value of the expression x is only +// evaluated once. Extra logging can be appended using << after. For example, +// CHECK(false == true) results in a log message of "Check failed: false == true". #define CHECK(x) \ if (UNLIKELY(!(x))) \ - ::art::LogMessage(__FILE__, __LINE__, FATAL, -1).stream() \ + ::art::LogMessage(__FILE__, __LINE__, ::art::FATAL, -1).stream() \ << "Check failed: " #x << " " +// Helper for CHECK_xx(x,y) macros. #define CHECK_OP(LHS, RHS, OP) \ for (auto _values = ::art::MakeEagerEvaluator(LHS, RHS); \ UNLIKELY(!(_values.lhs OP _values.rhs)); /* empty */) \ - ::art::LogMessage(__FILE__, __LINE__, FATAL, -1).stream() \ + ::art::LogMessage(__FILE__, __LINE__, ::art::FATAL, -1).stream() \ << "Check failed: " << #LHS << " " << #OP << " " << #RHS \ << " (" #LHS "=" << _values.lhs << ", " #RHS "=" << _values.rhs << ") " + +// Check whether a condition holds between x and y, LOG(FATAL) if not. The value of the expressions +// x and y is evaluated once. Extra logging can be appended using << after. For example, +// CHECK_NE(0 == 1, false) results in "Check failed: false != false (0==1=false, false=false) ". #define CHECK_EQ(x, y) CHECK_OP(x, y, ==) #define CHECK_NE(x, y) CHECK_OP(x, y, !=) #define CHECK_LE(x, y) CHECK_OP(x, y, <=) @@ -47,22 +131,25 @@ #define CHECK_GE(x, y) CHECK_OP(x, y, >=) #define CHECK_GT(x, y) CHECK_OP(x, y, >) +// Helper for CHECK_STRxx(s1,s2) macros. #define CHECK_STROP(s1, s2, sense) \ if (UNLIKELY((strcmp(s1, s2) == 0) != sense)) \ - LOG(FATAL) << "Check failed: " \ - << "\"" << s1 << "\"" \ - << (sense ? " == " : " != ") \ - << "\"" << s2 << "\"" + LOG(::art::FATAL) << "Check failed: " \ + << "\"" << s1 << "\"" \ + << (sense ? " == " : " != ") \ + << "\"" << s2 << "\"" +// Check for string (const char*) equality between s1 and s2, LOG(FATAL) if not. #define CHECK_STREQ(s1, s2) CHECK_STROP(s1, s2, true) #define CHECK_STRNE(s1, s2) CHECK_STROP(s1, s2, false) +// Perform the pthread function call(args), LOG(FATAL) on error. #define CHECK_PTHREAD_CALL(call, args, what) \ do { \ int rc = call args; \ if (rc != 0) { \ errno = rc; \ - PLOG(FATAL) << # call << " failed for " << what; \ + PLOG(::art::FATAL) << # call << " failed for " << what; \ } \ } while (false) @@ -74,81 +161,34 @@ // n / 2; // } #define CHECK_CONSTEXPR(x, out, dummy) \ - (UNLIKELY(!(x))) ? (LOG(FATAL) << "Check failed: " << #x out, dummy) : - -#ifndef NDEBUG - -#define DCHECK(x) CHECK(x) -#define DCHECK_EQ(x, y) CHECK_EQ(x, y) -#define DCHECK_NE(x, y) CHECK_NE(x, y) -#define DCHECK_LE(x, y) CHECK_LE(x, y) -#define DCHECK_LT(x, y) CHECK_LT(x, y) -#define DCHECK_GE(x, y) CHECK_GE(x, y) -#define DCHECK_GT(x, y) CHECK_GT(x, y) -#define DCHECK_STREQ(s1, s2) CHECK_STREQ(s1, s2) -#define DCHECK_STRNE(s1, s2) CHECK_STRNE(s1, s2) -#define DCHECK_CONSTEXPR(x, out, dummy) CHECK_CONSTEXPR(x, out, dummy) - -#else // NDEBUG - -#define DCHECK(condition) \ - while (false) \ - CHECK(condition) - -#define DCHECK_EQ(val1, val2) \ - while (false) \ - CHECK_EQ(val1, val2) - -#define DCHECK_NE(val1, val2) \ - while (false) \ - CHECK_NE(val1, val2) - -#define DCHECK_LE(val1, val2) \ - while (false) \ - CHECK_LE(val1, val2) - -#define DCHECK_LT(val1, val2) \ - while (false) \ - CHECK_LT(val1, val2) - -#define DCHECK_GE(val1, val2) \ - while (false) \ - CHECK_GE(val1, val2) - -#define DCHECK_GT(val1, val2) \ - while (false) \ - CHECK_GT(val1, val2) - -#define DCHECK_STREQ(str1, str2) \ - while (false) \ - CHECK_STREQ(str1, str2) + (UNLIKELY(!(x))) ? (LOG(::art::FATAL) << "Check failed: " << #x out, dummy) : -#define DCHECK_STRNE(str1, str2) \ - while (false) \ - CHECK_STRNE(str1, str2) - -#define DCHECK_CONSTEXPR(x, out, dummy) \ - (false && (x)) ? (dummy) : +// DCHECKs are debug variants of CHECKs only enabled in debug builds. Generally CHECK should be +// used unless profiling identifies a CHECK as being in performance critical code. +#if defined(NDEBUG) +static constexpr bool kEnableDChecks = false; +#else +static constexpr bool kEnableDChecks = true; #endif -#define LOG(severity) ::art::LogMessage(__FILE__, __LINE__, severity, -1).stream() -#define PLOG(severity) ::art::LogMessage(__FILE__, __LINE__, severity, errno).stream() - -#define LG LOG(INFO) - -#define UNIMPLEMENTED(level) LOG(level) << __PRETTY_FUNCTION__ << " unimplemented " - -#define VLOG_IS_ON(module) UNLIKELY(::art::gLogVerbosity.module) -#define VLOG(module) if (VLOG_IS_ON(module)) ::art::LogMessage(__FILE__, __LINE__, INFO, -1).stream() -#define VLOG_STREAM(module) ::art::LogMessage(__FILE__, __LINE__, INFO, -1).stream() - -// -// Implementation details beyond this point. -// - -namespace art { +#define DCHECK(x) if (::art::kEnableDChecks) CHECK(x) +#define DCHECK_EQ(x, y) if (::art::kEnableDChecks) CHECK_EQ(x, y) +#define DCHECK_NE(x, y) if (::art::kEnableDChecks) CHECK_NE(x, y) +#define DCHECK_LE(x, y) if (::art::kEnableDChecks) CHECK_LE(x, y) +#define DCHECK_LT(x, y) if (::art::kEnableDChecks) CHECK_LT(x, y) +#define DCHECK_GE(x, y) if (::art::kEnableDChecks) CHECK_GE(x, y) +#define DCHECK_GT(x, y) if (::art::kEnableDChecks) CHECK_GT(x, y) +#define DCHECK_STREQ(s1, s2) if (::art::kEnableDChecks) CHECK_STREQ(s1, s2) +#define DCHECK_STRNE(s1, s2) if (::art::kEnableDChecks) CHECK_STRNE(s1, s2) +#if defined(NDEBUG) +#define DCHECK_CONSTEXPR(x, out, dummy) +#else +#define DCHECK_CONSTEXPR(x, out, dummy) CHECK_CONSTEXPR(x, out, dummy) +#endif +// Temporary class created to evaluate the LHS and RHS, used with MakeEagerEvaluator to infer the +// types of LHS and RHS. template <typename LHS, typename RHS> struct EagerEvaluator { EagerEvaluator(LHS l, RHS r) : lhs(l), rhs(r) { } @@ -156,10 +196,14 @@ struct EagerEvaluator { RHS rhs; }; -// We want char*s to be treated as pointers, not strings. If you want them treated like strings, -// you'd need to use CHECK_STREQ and CHECK_STRNE anyway to compare the characters rather than their -// addresses. We could express this more succinctly with std::remove_const, but this is quick and -// easy to understand, and works before we have C++0x. We rely on signed/unsigned warnings to +// Helper function for CHECK_xx. +template <typename LHS, typename RHS> +static inline EagerEvaluator<LHS, RHS> MakeEagerEvaluator(LHS lhs, RHS rhs) { + return EagerEvaluator<LHS, RHS>(lhs, rhs); +} + +// Explicitly instantiate EagerEvalue for pointers so that char*s aren't treated as strings. To +// compare strings use CHECK_STREQ and CHECK_STRNE. We rely on signed/unsigned warnings to // protect you against combinations not explicitly listed below. #define EAGER_PTR_EVALUATOR(T1, T2) \ template <> struct EagerEvaluator<T1, T2> { \ @@ -182,153 +226,30 @@ EAGER_PTR_EVALUATOR(const signed char*, signed char*); EAGER_PTR_EVALUATOR(signed char*, const signed char*); EAGER_PTR_EVALUATOR(signed char*, signed char*); -template <typename LHS, typename RHS> -EagerEvaluator<LHS, RHS> MakeEagerEvaluator(LHS lhs, RHS rhs) { - return EagerEvaluator<LHS, RHS>(lhs, rhs); -} - -// This indirection greatly reduces the stack impact of having -// lots of checks/logging in a function. -struct LogMessageData { - public: - LogMessageData(const char* file, int line, LogSeverity severity, int error); - std::ostringstream buffer; - const char* const file; - const int line_number; - const LogSeverity severity; - const int error; - - private: - DISALLOW_COPY_AND_ASSIGN(LogMessageData); -}; +// Data for the log message, not stored in LogMessage to avoid increasing the stack size. +class LogMessageData; +// A LogMessage is a temporarily scoped object used by LOG and the unlikely part of a CHECK. The +// destructor will abort if the severity is FATAL. class LogMessage { public: - LogMessage(const char* file, int line, LogSeverity severity, int error) - : data_(new LogMessageData(file, line, severity, error)) { - } + LogMessage(const char* file, unsigned int line, LogSeverity severity, int error); ~LogMessage(); // TODO: enable LOCKS_EXCLUDED(Locks::logging_lock_). - std::ostream& stream() { - return data_->buffer; - } + // Returns the stream associated with the message, the LogMessage performs output when it goes + // out of scope. + std::ostream& stream(); - private: - static void LogLine(const LogMessageData& data, const char*); + // The routine that performs the actual logging. + static void LogLine(const char* file, unsigned int line, LogSeverity severity, const char* msg); + private: const std::unique_ptr<LogMessageData> data_; - friend void HandleUnexpectedSignal(int signal_number, siginfo_t* info, void* raw_context); - friend class Mutex; DISALLOW_COPY_AND_ASSIGN(LogMessage); }; -// A convenience to allow any class with a "Dump(std::ostream& os)" member function -// but without an operator<< to be used as if it had an operator<<. Use like this: -// -// os << Dumpable<MyType>(my_type_instance); -// -template<typename T> -class Dumpable { - public: - explicit Dumpable(T& value) : value_(value) { - } - - void Dump(std::ostream& os) const { - value_.Dump(os); - } - - private: - T& value_; - - DISALLOW_COPY_AND_ASSIGN(Dumpable); -}; - -template<typename T> -std::ostream& operator<<(std::ostream& os, const Dumpable<T>& rhs) { - rhs.Dump(os); - return os; -} - -template<typename T> -class ConstDumpable { - public: - explicit ConstDumpable(const T& value) : value_(value) { - } - - void Dump(std::ostream& os) const { - value_.Dump(os); - } - - private: - const T& value_; - - DISALLOW_COPY_AND_ASSIGN(ConstDumpable); -}; - -template<typename T> -std::ostream& operator<<(std::ostream& os, const ConstDumpable<T>& rhs) { - rhs.Dump(os); - return os; -} - -// Helps you use operator<< in a const char*-like context such as our various 'F' methods with -// format strings. -template<typename T> -class ToStr { - public: - explicit ToStr(const T& value) { - std::ostringstream os; - os << value; - s_ = os.str(); - } - - const char* c_str() const { - return s_.c_str(); - } - - const std::string& str() const { - return s_; - } - - private: - std::string s_; - DISALLOW_COPY_AND_ASSIGN(ToStr); -}; - -// The members of this struct are the valid arguments to VLOG and VLOG_IS_ON in code, -// and the "-verbose:" command line argument. -struct LogVerbosity { - bool class_linker; // Enabled with "-verbose:class". - bool compiler; - bool gc; - bool heap; - bool jdwp; - bool jni; - bool monitor; - bool profiler; - bool signals; - bool startup; - bool third_party_jni; // Enabled with "-verbose:third-party-jni". - bool threads; - bool verifier; -}; - -extern LogVerbosity gLogVerbosity; - -extern std::vector<std::string> gVerboseMethods; - -// Used on fatal exit. Prevents recursive aborts. Allows us to disable -// some error checking to ensure fatal shutdown makes forward progress. -extern unsigned int gAborting; - -extern void InitLogging(char* argv[]); - -extern const char* GetCmdLine(); -extern const char* ProgramInvocationName(); -extern const char* ProgramInvocationShortName(); - } // namespace art #endif // ART_RUNTIME_BASE_LOGGING_H_ diff --git a/runtime/base/logging_android.cc b/runtime/base/logging_android.cc deleted file mode 100644 index 9b1ac58461..0000000000 --- a/runtime/base/logging_android.cc +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2011 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "logging.h" - -#include <unistd.h> - -#include <iostream> - -#include "base/stringprintf.h" -#include "cutils/log.h" - -namespace art { - -static const int kLogSeverityToAndroidLogPriority[] = { - ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN, - ANDROID_LOG_ERROR, ANDROID_LOG_FATAL, ANDROID_LOG_FATAL -}; - -void LogMessage::LogLine(const LogMessageData& data, const char* message) { - const char* tag = ProgramInvocationShortName(); - int priority = kLogSeverityToAndroidLogPriority[data.severity]; - if (priority == ANDROID_LOG_FATAL) { - LOG_PRI(priority, tag, "%s:%d] %s", data.file, data.line_number, message); - } else { - LOG_PRI(priority, tag, "%s", message); - } -} - -} // namespace art diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc index 70b6f7e295..1d373497eb 100644 --- a/runtime/base/mutex.cc +++ b/runtime/base/mutex.cc @@ -428,9 +428,9 @@ void Mutex::ExclusiveUnlock(Thread* self) { if (this != Locks::logging_lock_) { LOG(FATAL) << "Unexpected state_ in unlock " << cur_state << " for " << name_; } else { - LogMessageData data(__FILE__, __LINE__, INTERNAL_FATAL, -1); - LogMessage::LogLine(data, StringPrintf("Unexpected state_ %d in unlock for %s", - cur_state, name_).c_str()); + LogMessage::LogLine(__FILE__, __LINE__, INTERNAL_FATAL, + StringPrintf("Unexpected state_ %d in unlock for %s", + cur_state, name_).c_str()); _exit(1); } } diff --git a/runtime/base/logging_linux.cc b/runtime/base/to_str.h index 0399128d65..6b1c84c411 100644 --- a/runtime/base/logging_linux.cc +++ b/runtime/base/to_str.h @@ -14,25 +14,37 @@ * limitations under the License. */ -#include "logging.h" +#ifndef ART_RUNTIME_BASE_TO_STR_H_ +#define ART_RUNTIME_BASE_TO_STR_H_ -#include <sys/types.h> -#include <unistd.h> +#include <sstream> -#include <cstdio> -#include <cstring> -#include <iostream> +namespace art { -#include "base/stringprintf.h" -#include "utils.h" +// Helps you use operator<< in a const char*-like context such as our various 'F' methods with +// format strings. +template<typename T> +class ToStr { + public: + explicit ToStr(const T& value) { + std::ostringstream os; + os << value; + s_ = os.str(); + } -namespace art { + const char* c_str() const { + return s_.c_str(); + } -void LogMessage::LogLine(const LogMessageData& data, const char* message) { - char severity = "VDIWEFF"[data.severity]; - fprintf(stderr, "%s %c %5d %5d %s:%d] %s\n", - ProgramInvocationShortName(), severity, getpid(), ::art::GetTid(), - data.file, data.line_number, message); -} + const std::string& str() const { + return s_; + } + + private: + std::string s_; + DISALLOW_COPY_AND_ASSIGN(ToStr); +}; } // namespace art + +#endif // ART_RUNTIME_BASE_TO_STR_H_ diff --git a/runtime/base/unix_file/mapped_file.cc b/runtime/base/unix_file/mapped_file.cc index 63927b1216..77f4d020a9 100644 --- a/runtime/base/unix_file/mapped_file.cc +++ b/runtime/base/unix_file/mapped_file.cc @@ -42,7 +42,7 @@ bool MappedFile::MapReadOnly() { struct stat st; int result = TEMP_FAILURE_RETRY(fstat(Fd(), &st)); if (result == -1) { - PLOG(WARNING) << "Failed to stat file '" << GetPath() << "'"; + PLOG(::art::WARNING) << "Failed to stat file '" << GetPath() << "'"; return false; } file_size_ = st.st_size; @@ -50,8 +50,8 @@ bool MappedFile::MapReadOnly() { mapped_file_ = mmap(NULL, file_size_, PROT_READ, MAP_PRIVATE, Fd(), 0); } while (mapped_file_ == MAP_FAILED && errno == EINTR); if (mapped_file_ == MAP_FAILED) { - PLOG(WARNING) << "Failed to mmap file '" << GetPath() << "' of size " - << file_size_ << " bytes to memory"; + PLOG(::art::WARNING) << "Failed to mmap file '" << GetPath() << "' of size " + << file_size_ << " bytes to memory"; return false; } map_mode_ = kMapReadOnly; @@ -67,8 +67,7 @@ bool MappedFile::MapReadWrite(int64_t file_size) { int result = TEMP_FAILURE_RETRY(ftruncate(Fd(), file_size)); #endif if (result == -1) { - PLOG(ERROR) << "Failed to truncate file '" << GetPath() - << "' to size " << file_size; + PLOG(::art::ERROR) << "Failed to truncate file '" << GetPath() << "' to size " << file_size; return false; } file_size_ = file_size; @@ -77,7 +76,7 @@ bool MappedFile::MapReadWrite(int64_t file_size) { mmap(NULL, file_size_, PROT_READ | PROT_WRITE, MAP_SHARED, Fd(), 0); } while (mapped_file_ == MAP_FAILED && errno == EINTR); if (mapped_file_ == MAP_FAILED) { - PLOG(WARNING) << "Failed to mmap file '" << GetPath() << "' of size " + PLOG(::art::WARNING) << "Failed to mmap file '" << GetPath() << "' of size " << file_size_ << " bytes to memory"; return false; } @@ -89,8 +88,7 @@ bool MappedFile::Unmap() { CHECK(IsMapped()); int result = TEMP_FAILURE_RETRY(munmap(mapped_file_, file_size_)); if (result == -1) { - PLOG(WARNING) << "Failed unmap file '" << GetPath() << "' of size " - << file_size_; + PLOG(::art::WARNING) << "Failed unmap file '" << GetPath() << "' of size " << file_size_; return false; } else { mapped_file_ = NULL; |