set (GLOG_MAJOR_VERSION 0)
set (GLOG_MINOR_VERSION 3)
-set (GLOG_PATCH_VERSION 4)
+set (GLOG_PATCH_VERSION 5)
set (GLOG_VERSION
${GLOG_MAJOR_VERSION}.${GLOG_MINOR_VERSION}.${GLOG_PATCH_VERSION})
option (WITH_GFLAGS "Use gflags" ON)
option (WITH_THREADS "Enable multithreading support" ON)
+ option (WITH_TLS "Enable Thread Local Storage (TLS) support" ON)
list (APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
-include (CMakePackageConfigHelpers)
-include (CPack)
include (CheckCSourceCompiles)
include (CheckCXXCompilerFlag)
include (CheckCXXSourceCompiles)
include (CheckStructHasMember)
include (CheckSymbolExists)
include (CheckTypeSize)
+include (CMakePackageConfigHelpers)
+include (CPack)
+include (CTest)
include (DetermineGflagsNamespace)
set (CMAKE_THREAD_PREFER_PTHREAD 1)
if (WITH_GFLAGS)
- find_package (gflags)
+ find_package (gflags 2.2.0)
if (gflags_FOUND)
set (HAVE_LIB_GFLAGS 1)
check_function_exists (sigaction HAVE_SIGACTION)
check_function_exists (sigaltstack HAVE_SIGALSTACK)
-check_cxx_compiler_flag (-Wno-deprecated HAVE_NO_DEPRECATED)
-check_cxx_compiler_flag (-Wno-unnamed-type-template-args
+# NOTE gcc does not fail if you pass a non-existent -Wno-* option as an
+# argument. However, it will happily fail if you pass the corresponding -W*
+# option. So, we check whether options that disable warnings exist by testing
+# the availability of the corresponding option that enables the warning. This
+# eliminates the need to check for compiler for several (mainly Clang) options.
+
+check_cxx_compiler_flag (-Wdeprecated HAVE_NO_DEPRECATED)
+check_cxx_compiler_flag (-Wunnamed-type-template-args
HAVE_NO_UNNAMED_TYPE_TEMPLATE_ARGS)
# NOTE: Cannot use check_function_exists here since >=vc-14.0 can define
int main() { return i; }
" HAVE_NAMESPACES)
+ check_cxx_source_compiles ("
+ __declspec(thread) int tls;
+ int main() { }
+ " HAVE_MSVC_TLS)
+
+ check_cxx_source_compiles ("
+ thread_local int tls;
+ int main() { }
+ " HAVE_CXX11_TLS)
+
+ check_cxx_source_compiles ("
+ __attribute__((thread)) int tls;
+ int main() { }
+ " HAVE_CYGWIN_TLS)
+
+ if (WITH_TLS)
+ if (HAVE_CYGWIN_TLS)
+ set (GLOG_THREAD_LOCAL_STORAGE "__attribute__((thread))")
+ elseif (HAVE_MSVC_TLS)
+ set (GLOG_THREAD_LOCAL_STORAGE "__declspec(thread)")
+ elseif (HAVE_CXX11_TLS)
+ set (GLOG_THREAD_LOCAL_STORAGE thread_local)
+ endif (HAVE_CYGWIN_TLS)
+ endif (WITH_TLS)
+
set (_PC_FIELDS
"gregs[REG_PC]"
"gregs[REG_EIP]"
src/vlog_is_on.cc
)
-if (HAVE_PTHREAD)
+if (HAVE_PTHREAD OR WIN32)
list (APPEND GLOG_SRCS src/signalhandler.cc)
-endif (HAVE_PTHREAD)
+endif (HAVE_PTHREAD OR WIN32)
if (WIN32)
list (APPEND GLOG_SRCS
)
endif (WIN32)
+add_compile_options ($<$<BOOL:${HAVE_NO_UNNAMED_TYPE_TEMPLATE_ARGS}>:-Wno-unnamed-type-template-args>)
+
add_library (glog
${GLOG_SRCS}
)
+set_target_properties (glog PROPERTIES POSITION_INDEPENDENT_CODE ON)
+
if (UNWIND_LIBRARY)
target_link_libraries (glog PUBLIC ${UNWIND_LIBRARY})
endif (UNWIND_LIBRARY)
HAVE_SNPRINTF)
endif (WIN32 AND HAVE_SNPRINTF)
-if (HAVE_NO_UNNAMED_TYPE_TEMPLATE_ARGS)
- target_compile_options (glog PUBLIC -Wno-unnamed-type-template-args)
-endif (HAVE_NO_UNNAMED_TYPE_TEMPLATE_ARGS)
-
if (gflags_FOUND)
- target_include_directories (glog PUBLIC ${gflags_INCLUDE_DIR})
- target_link_libraries (glog PUBLIC ${gflags_LIBRARIES})
+ target_link_libraries (glog PUBLIC gflags)
if (NOT BUILD_SHARED_LIBS)
# Don't use __declspec(dllexport|dllimport) if this is a static build
set (HAVE_STACKTRACE 1)
endif (HAVE_EXECINFO_H)
+if (WIN32)
+ set (HAVE_STACKTRACE 1)
+ set (HAVE_SYMBOLIZE 1)
+endif (WIN32)
+
if (UNIX OR (APPLE AND HAVE_DLADDR))
set (HAVE_SYMBOLIZE 1)
endif (UNIX OR (APPLE AND HAVE_DLADDR))
# Unit testing
-add_executable (logging_unittest
- src/logging_unittest.cc
-)
-
-target_link_libraries (logging_unittest PRIVATE glog)
-
-add_executable (stl_logging_unittest
- src/stl_logging_unittest.cc
-)
+if (BUILD_TESTING)
+ add_executable (logging_unittest
+ src/logging_unittest.cc
+ )
-target_link_libraries (stl_logging_unittest PRIVATE glog)
+ target_link_libraries (logging_unittest PRIVATE glog)
-if (HAVE_NO_DEPRECATED)
- set_property (TARGET stl_logging_unittest APPEND PROPERTY COMPILE_OPTIONS
- -Wno-deprecated)
-endif (HAVE_NO_DEPRECATED)
+ add_executable (stl_logging_unittest
+ src/stl_logging_unittest.cc
+ )
-if (HAVE_UNORDERED_MAP AND HAVE_UNORDERED_SET)
- target_compile_definitions (stl_logging_unittest PRIVATE
- GLOG_STL_LOGGING_FOR_UNORDERED)
-endif (HAVE_UNORDERED_MAP AND HAVE_UNORDERED_SET)
+ target_link_libraries (stl_logging_unittest PRIVATE glog)
-if (HAVE_TR1_UNORDERED_MAP AND HAVE_TR1_UNORDERED_SET)
- target_compile_definitions (stl_logging_unittest PRIVATE
- GLOG_STL_LOGGING_FOR_TR1_UNORDERED)
-endif (HAVE_TR1_UNORDERED_MAP AND HAVE_TR1_UNORDERED_SET)
+ if (HAVE_NO_DEPRECATED)
+ set_property (TARGET stl_logging_unittest APPEND PROPERTY COMPILE_OPTIONS
+ -Wno-deprecated)
+ endif (HAVE_NO_DEPRECATED)
-if (HAVE_EXT_HASH_MAP AND HAVE_EXT_HASH_SET)
- target_compile_definitions (stl_logging_unittest PRIVATE
- GLOG_STL_LOGGING_FOR_EXT_HASH)
-endif (HAVE_EXT_HASH_MAP AND HAVE_EXT_HASH_SET)
+ if (HAVE_UNORDERED_MAP AND HAVE_UNORDERED_SET)
+ target_compile_definitions (stl_logging_unittest PRIVATE
+ GLOG_STL_LOGGING_FOR_UNORDERED)
+ endif (HAVE_UNORDERED_MAP AND HAVE_UNORDERED_SET)
-if (HAVE_EXT_SLIST)
- target_compile_definitions (stl_logging_unittest PRIVATE
- GLOG_STL_LOGGING_FOR_EXT_SLIST)
-endif (HAVE_EXT_SLIST)
+ if (HAVE_TR1_UNORDERED_MAP AND HAVE_TR1_UNORDERED_SET)
+ target_compile_definitions (stl_logging_unittest PRIVATE
+ GLOG_STL_LOGGING_FOR_TR1_UNORDERED)
+ endif (HAVE_TR1_UNORDERED_MAP AND HAVE_TR1_UNORDERED_SET)
-if (HAVE_SYMBOLIZE)
- add_executable (symbolize_unittest
- src/symbolize_unittest.cc
- )
+ if (HAVE_EXT_HASH_MAP AND HAVE_EXT_HASH_SET)
+ target_compile_definitions (stl_logging_unittest PRIVATE
+ GLOG_STL_LOGGING_FOR_EXT_HASH)
+ endif (HAVE_EXT_HASH_MAP AND HAVE_EXT_HASH_SET)
- target_link_libraries (symbolize_unittest PRIVATE glog)
-endif (HAVE_SYMBOLIZE)
+ if (HAVE_EXT_SLIST)
+ target_compile_definitions (stl_logging_unittest PRIVATE
+ GLOG_STL_LOGGING_FOR_EXT_SLIST)
+ endif (HAVE_EXT_SLIST)
-add_executable (demangle_unittest
- src/demangle_unittest.cc
-)
+ if (HAVE_SYMBOLIZE)
+ add_executable (symbolize_unittest
+ src/symbolize_unittest.cc
+ )
-target_link_libraries (demangle_unittest PRIVATE glog)
+ target_link_libraries (symbolize_unittest PRIVATE glog)
+ endif (HAVE_SYMBOLIZE)
-if (HAVE_STACKTRACE)
- add_executable (stacktrace_unittest
- src/stacktrace_unittest.cc
+ add_executable (demangle_unittest
+ src/demangle_unittest.cc
)
- target_link_libraries (stacktrace_unittest PRIVATE glog)
-endif (HAVE_STACKTRACE)
+ target_link_libraries (demangle_unittest PRIVATE glog)
-add_executable (utilities_unittest
- src/utilities_unittest.cc
-)
+ if (HAVE_STACKTRACE)
+ add_executable (stacktrace_unittest
+ src/stacktrace_unittest.cc
+ )
-target_link_libraries (utilities_unittest PRIVATE glog)
+ target_link_libraries (stacktrace_unittest PRIVATE glog)
+ endif (HAVE_STACKTRACE)
-if (HAVE_STACKTRACE AND HAVE_SYMBOLIZE)
- add_executable (signalhandler_unittest
- src/signalhandler_unittest.cc
+ add_executable (utilities_unittest
+ src/utilities_unittest.cc
)
- target_link_libraries (signalhandler_unittest PRIVATE glog)
-endif (HAVE_STACKTRACE AND HAVE_SYMBOLIZE)
+ target_link_libraries (utilities_unittest PRIVATE glog)
+
+ if (HAVE_STACKTRACE AND HAVE_SYMBOLIZE)
+ add_executable (signalhandler_unittest
+ src/signalhandler_unittest.cc
+ )
-add_test (NAME demangle COMMAND demangle_unittest)
-add_test (NAME logging COMMAND logging_unittest)
+ target_link_libraries (signalhandler_unittest PRIVATE glog)
+ endif (HAVE_STACKTRACE AND HAVE_SYMBOLIZE)
-if (TARGET signalhandler_unittest)
- add_test (NAME signalhandler COMMAND signalhandler_unittest)
-endif (TARGET signalhandler_unittest)
+ add_test (NAME demangle COMMAND demangle_unittest)
+ add_test (NAME logging COMMAND logging_unittest)
-if (TARGET stacktrace_unittest)
- add_test (NAME stacktrace COMMAND stacktrace_unittest)
-endif (TARGET stacktrace_unittest)
+ if (TARGET signalhandler_unittest)
+ add_test (NAME signalhandler COMMAND signalhandler_unittest)
+ endif (TARGET signalhandler_unittest)
-add_test (NAME stl_logging COMMAND stl_logging_unittest)
+ if (TARGET stacktrace_unittest)
+ add_test (NAME stacktrace COMMAND stacktrace_unittest)
+ endif (TARGET stacktrace_unittest)
-if (TARGET symbolize_unittest)
- add_test (NAME symbolize COMMAND symbolize_unittest)
-endif (TARGET symbolize_unittest)
+ add_test (NAME stl_logging COMMAND stl_logging_unittest)
+
+ if (TARGET symbolize_unittest)
+ add_test (NAME symbolize COMMAND symbolize_unittest)
+ endif (TARGET symbolize_unittest)
+endif (BUILD_TESTING)
install (TARGETS glog
EXPORT glog-targets
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib)
-# Build tree config
-
-set (glog_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
-set (glog_PACKAGE_DEPS)
-
if (gflags_FOUND)
- set (glog_PACKAGE_DEPS
-"
-include (CMakeFindDependencyMacro)
-
-find_dependency (gflags ${gflags_VERSION})
-")
+ set (gflags_DEPENDENCY "find_dependency (gflags ${gflags_VERSION})")
endif (gflags_FOUND)
configure_package_config_file (glog-config.cmake.in
- ${CMAKE_CURRENT_BINARY_DIR}/glog-config.cmake INSTALL_DESTINATION
- lib/cmake/glog PATH_VARS glog_INCLUDE_DIR
+ ${CMAKE_CURRENT_BINARY_DIR}/glog-config.cmake
+ INSTALL_DESTINATION lib/cmake/glog
NO_CHECK_REQUIRED_COMPONENTS_MACRO)
-# The version file is the same both for build tree and install mode config
write_basic_package_version_file (glog-config-version.cmake VERSION
${GLOG_VERSION} COMPATIBILITY SameMajorVersion)
-# Install config
-
-set (glog_INCLUDE_DIR include)
-
-configure_package_config_file (glog-config.cmake.in
- ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/glog-config.cmake
- INSTALL_DESTINATION lib/cmake/glog PATH_VARS glog_INCLUDE_DIR
- NO_CHECK_REQUIRED_COMPONENTS_MACRO)
-
-export (TARGETS glog FILE glog-targets.cmake)
+export (TARGETS glog NAMESPACE glog:: FILE glog-targets.cmake)
export (PACKAGE glog)
install (FILES
- ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/glog-config.cmake
+ ${CMAKE_CURRENT_BINARY_DIR}/glog-config.cmake
${CMAKE_CURRENT_BINARY_DIR}/glog-config-version.cmake
DESTINATION lib/cmake/glog)
-install (EXPORT glog-targets DESTINATION lib/cmake/glog)
+install (EXPORT glog-targets NAMESPACE glog:: DESTINATION lib/cmake/glog)
#define LOG_TO_STRING_FATAL(message) @ac_google_namespace@::NullStreamFatal()
#endif
+#if defined(NDEBUG) && !defined(DCHECK_ALWAYS_ON)
+#define DCHECK_IS_ON() 0
+#else
+#define DCHECK_IS_ON() 1
+#endif
+
// For DFATAL, we want to use LogMessage (as opposed to
// LogMessageFatal), to be consistent with the original behavior.
-#ifdef NDEBUG
+#if !DCHECK_IS_ON()
#define COMPACT_GOOGLE_LOG_DFATAL COMPACT_GOOGLE_LOG_ERROR
#elif GOOGLE_STRIP_LOG <= 3
#define COMPACT_GOOGLE_LOG_DFATAL @ac_google_namespace@::LogMessage( \
SYSLOG_IF(FATAL, !(condition)) << "Assert failed: " #condition
// CHECK dies with a fatal error if condition is not true. It is *not*
-// controlled by NDEBUG, so the check will be executed regardless of
+// controlled by DCHECK_IS_ON(), so the check will be executed regardless of
// compilation mode. Therefore, it is safe to do things like:
// CHECK(fp->Write(x) == 4)
#define CHECK(condition) \
#if defined(STATIC_ANALYSIS)
// Only for static analysis tool to know that it is equivalent to assert
#define CHECK_OP_LOG(name, op, val1, val2, log) CHECK((val1) op (val2))
-#elif !defined(NDEBUG)
+#elif DCHECK_IS_ON()
// In debug mode, avoid constructing CheckOpStrings if possible,
// to reduce the overhead of CHECK statments by 2x.
// Real DCHECK-heavy tests have seen 1.5x speedups.
@ac_google_namespace@::GetReferenceableValue(val2), \
#val1 " " #op " " #val2)) \
log(__FILE__, __LINE__, _result).stream()
-#endif // STATIC_ANALYSIS, !NDEBUG
+#endif // STATIC_ANALYSIS, DCHECK_IS_ON()
#if GOOGLE_STRIP_LOG <= 3
#define CHECK_OP(name, op, val1, val2) \
// Plus some debug-logging macros that get compiled to nothing for production
-#ifndef NDEBUG
+#if DCHECK_IS_ON()
#define DLOG(severity) LOG(severity)
#define DVLOG(verboselevel) VLOG(verboselevel)
LOG_IF_EVERY_N(severity, condition, n)
#define DLOG_ASSERT(condition) LOG_ASSERT(condition)
-// debug-only checking. not executed in NDEBUG mode.
+// debug-only checking. executed if DCHECK_IS_ON().
#define DCHECK(condition) CHECK(condition)
#define DCHECK_EQ(val1, val2) CHECK_EQ(val1, val2)
#define DCHECK_NE(val1, val2) CHECK_NE(val1, val2)
#define DCHECK_STRNE(str1, str2) CHECK_STRNE(str1, str2)
#define DCHECK_STRCASENE(str1, str2) CHECK_STRCASENE(str1, str2)
-#else // NDEBUG
+#else // !DCHECK_IS_ON()
#define DLOG(severity) \
true ? (void) 0 : @ac_google_namespace@::LogMessageVoidify() & LOG(severity)
while (false) \
GLOG_MSVC_POP_WARNING() CHECK_STRCASENE(str1, str2)
-#endif // NDEBUG
+#endif // DCHECK_IS_ON()
// Log only in verbose mode.
LogStreamBuf(char *buf, int len) {
setp(buf, buf + len - 2);
}
+
+ // Resets the buffer. Useful if we reuse it by means of TLS.
+ void reset() {
+ setp(pbase(), epptr());
+ }
+
// This effectively ignores overflow.
virtual int_type overflow(int_type ch) {
return ch;
size_t pcount() const { return streambuf_.pcount(); }
char* pbase() const { return streambuf_.pbase(); }
char* str() const { return pbase(); }
+ void reset() { streambuf_.reset(); }
private:
LogStream(const LogStream&);
// LOG macros, 2. this macro can be used as C++ stream.
#define LOG_AT_LEVEL(severity) @ac_google_namespace@::LogMessage(__FILE__, __LINE__, severity).stream()
+// Check if it's compiled in C++11 mode.
+//
+// GXX_EXPERIMENTAL_CXX0X is defined by gcc and clang up to at least
+// gcc-4.7 and clang-3.1 (2011-12-13). __cplusplus was defined to 1
+// in gcc before 4.7 (Crosstool 16) and clang before 3.1, but is
+// defined according to the language version in effect thereafter.
+// Microsoft Visual Studio 14 (2015) sets __cplusplus==199711 despite
+// reasonably good C++11 support, so we set LANG_CXX for it and
+// newer versions (_MSC_VER >= 1900).
+#if (defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L || \
+ (defined(_MSC_VER) && _MSC_VER >= 1900))
+// Helper for CHECK_NOTNULL().
+//
+// In C++11, all cases can be handled by a single function. Since the value
+// category of the argument is preserved (also for rvalue references),
+// member initializer lists like the one below will compile correctly:
+//
+// Foo()
+// : x_(CHECK_NOTNULL(MethodReturningUniquePtr())) {}
+template <typename T>
+T CheckNotNull(const char* file, int line, const char* names, T&& t) {
+ if (t == nullptr) {
+ LogMessageFatal(file, line, new std::string(names));
+ }
+ return std::forward<T>(t);
+}
+
+#else
+
// A small helper for CHECK_NOTNULL().
template <typename T>
T* CheckNotNull(const char *file, int line, const char *names, T* t) {
}
return t;
}
+#endif
// Allow folks to put a counter in the LOG_EVERY_X()'ed messages. This
// only works if ostream is a LogStream. If the ostream is not a
"Logs can grow very quickly and they are rarely read before they "
"need to be evicted from memory. Instead, drop them from memory "
"as soon as they are flushed to disk.");
-_START_GOOGLE_NAMESPACE_
-namespace logging {
-static const int64 kPageSize = getpagesize();
-}
-_END_GOOGLE_NAMESPACE_
#endif
// By default, errors (including fatal errors) get logged to stderr as
struct LogMessage::LogMessageData {
LogMessageData();
+ void reset();
int preserved_errno_; // preserved errno
// Buffer space; contains complete message text.
FILE* file_;
LogSeverity severity_;
uint32 bytes_since_flush_;
+ uint32 dropped_mem_length_;
uint32 file_length_;
unsigned int rollover_attempt_;
int64 next_flush_time_; // cycle count at which to flush log
}
MutexLock l(&sink_mutex_);
delete sinks_;
+ sinks_ = NULL;
}
namespace {
file_(NULL),
severity_(severity),
bytes_since_flush_(0),
+ dropped_mem_length_(0),
file_length_(0),
rollover_attempt_(kRolloverAttemptFrequency-1),
next_flush_time_(0) {
PidHasChanged()) {
if (file_ != NULL) fclose(file_);
file_ = NULL;
- file_length_ = bytes_since_flush_ = 0;
+ file_length_ = bytes_since_flush_ = dropped_mem_length_ = 0;
rollover_attempt_ = kRolloverAttemptFrequency-1;
}
(CycleClock_Now() >= next_flush_time_) ) {
FlushUnlocked();
#ifdef OS_LINUX
- if (FLAGS_drop_log_memory) {
- if (file_length_ >= logging::kPageSize) {
- // don't evict the most recent page
- uint32 len = file_length_ & ~(logging::kPageSize - 1);
- posix_fadvise(fileno(file_), 0, len, POSIX_FADV_DONTNEED);
+ // Only consider files >= 3MiB
+ if (FLAGS_drop_log_memory && file_length_ >= (3 << 20)) {
+ // Don't evict the most recent 1-2MiB so as not to impact a tailer
+ // of the log file and to avoid page rounding issue on linux < 4.7
+ uint32 total_drop_length = (file_length_ & ~((1 << 20) - 1)) - (1 << 20);
+ uint32 this_drop_length = total_drop_length - dropped_mem_length_;
+ if (this_drop_length >= (2 << 20)) {
+ // Only advise when >= 2MiB to drop
+ posix_fadvise(fileno(file_), dropped_mem_length_, this_drop_length,
+ POSIX_FADV_DONTNEED);
+ dropped_mem_length_ = total_drop_length;
}
}
#endif
static LogMessage::LogMessageData fatal_msg_data_exclusive;
static LogMessage::LogMessageData fatal_msg_data_shared;
+ #ifdef GLOG_THREAD_LOCAL_STORAGE
+ // Static thread-local log data space to use, because typically at most one
+ // LogMessageData object exists (in this case glog makes zero heap memory
+ // allocations).
+ static GLOG_THREAD_LOCAL_STORAGE bool thread_data_available = true;
+ static GLOG_THREAD_LOCAL_STORAGE LogMessage::LogMessageData thread_msg_data;
+ #endif // defined(GLOG_THREAD_LOCAL_STORAGE)
+
LogMessage::LogMessageData::LogMessageData()
: stream_(message_text_, LogMessage::kMaxLogMessageLen, 0) {
}
+ void LogMessage::LogMessageData::reset() {
+ stream_.reset();
+ }
+
LogMessage::LogMessage(const char* file, int line, LogSeverity severity,
int ctr, void (LogMessage::*send_method)())
: allocated_(NULL) {
void (LogMessage::*send_method)()) {
allocated_ = NULL;
if (severity != GLOG_FATAL || !exit_on_dfatal) {
+ #ifdef GLOG_THREAD_LOCAL_STORAGE
+ // No need for locking, because this is thread local.
+ if (thread_data_available) {
+ thread_data_available = false;
+ data_ = &thread_msg_data;
+ // Make sure to clear log data since it may have been used and filled with
+ // data. We do not want to append the new message to the previous one.
+ data_->reset();
+ } else {
+ allocated_ = new LogMessageData();
+ data_ = allocated_;
+ }
+ #else // !defined(GLOG_THREAD_LOCAL_STORAGE)
allocated_ = new LogMessageData();
data_ = allocated_;
+ #endif // defined(GLOG_THREAD_LOCAL_STORAGE)
data_->first_fatal_ = false;
} else {
MutexLock l(&fatal_msg_lock);
LogMessage::~LogMessage() {
Flush();
+ #ifdef GLOG_THREAD_LOCAL_STORAGE
+ if (data_ == &thread_msg_data)
+ thread_data_available = true;
+ #endif // defined(GLOG_THREAD_LOCAL_STORAGE)
delete allocated_;
}
# define ATTRIBUTE_NORETURN
#endif
+#if defined(OS_WINDOWS)
+__declspec(noreturn)
+#endif
static void logging_fail() ATTRIBUTE_NORETURN;
static void logging_fail() {
-#if defined(_DEBUG) && defined(_MSC_VER)
- // When debugging on windows, avoid the obnoxious dialog and make
- // it possible to continue past a LOG(FATAL) in the debugger
- __debugbreak();
-#else
abort();
-#endif
}
typedef void (*logging_fail_func_t)() ATTRIBUTE_NORETURN;
LOG(ERROR) << string("foo") << ' '<< j << ' ' << setw(10) << j << " "
<< setw(1) << hex << j;
+ LOG(ERROR) << (&LOG(ERROR) && 0) << " nested LOG";
+
LogMessage("foo", LogMessage::kNoLogPrefix, GLOG_INFO).stream() << "no prefix";
if (check_counts) {
CHECK_EQ(base_num_infos + 14, LogMessage::num_messages(GLOG_INFO));
CHECK_EQ(base_num_warning + 3, LogMessage::num_messages(GLOG_WARNING));
- CHECK_EQ(base_num_errors + 15, LogMessage::num_messages(GLOG_ERROR));
+ CHECK_EQ(base_num_errors + 17, LogMessage::num_messages(GLOG_ERROR));
}
}
static void NoAllocNewHook() {
- CHECK(false) << "unexpected new";
+ LOG(FATAL) << "unexpected new";
}
struct NewHook {