From: Thomas Jarosch Date: Fri, 15 Jul 2011 14:55:35 +0000 (+0200) Subject: Make ScopeTracker thread safe via TLS (thread local storage) X-Git-Tag: v2.6~50 X-Git-Url: http://developer.intra2net.com/git/?a=commitdiff_plain;h=f4fcef65e0107f1b2285cafb954bac055fabc2d7;p=libi2ncommon Make ScopeTracker thread safe via TLS (thread local storage) Thanks to Gerd for the idea --- diff --git a/src/logfunc.cpp b/src/logfunc.cpp index ba9f02f..8b1ce4f 100644 --- a/src/logfunc.cpp +++ b/src/logfunc.cpp @@ -49,10 +49,6 @@ namespace I2n namespace Logger { -/// Global lock for the logger. Used during all syslog operations -/// and modification of our shared local variables. -boost::recursive_mutex LoggerLock; - /** * @brief the global logger instance. * @@ -65,6 +61,10 @@ PartLogger GlobalLogger(""); namespace { +/// Global lock for the logger. Used during all syslog operations +/// and modification of our shared local variables. +static boost::recursive_mutex LoggerLock; + /* ** local globals: */ diff --git a/src/tracefunc.cpp b/src/tracefunc.cpp index ab1ec5e..368559c 100644 --- a/src/tracefunc.cpp +++ b/src/tracefunc.cpp @@ -21,9 +21,9 @@ on this file might be covered by the GNU General Public License. * @brief implementation of tracing functionality. * * @copyright © Copyright 2008 by Intra2net AG + * + * Every thread gets its' own ScopeTracker stack via TLS (thread local storage) * - * @note This module is not thread safe! - * @todo make this module thread safe (only useful when we can use threads...) */ #include "tracefunc.hpp" @@ -31,7 +31,7 @@ on this file might be covered by the GNU General Public License. #include #include #include - +#include namespace I2n { @@ -40,51 +40,62 @@ namespace Tracer using Logger::GlobalLogger; +class PerThreadContainer +{ +public: + typedef std::list< ScopeTracker* > ScopeTrackerList; + + /// List of currently active scope trackers + ScopeTrackerList scope_tracker_list; + + /// Precomputed indent levels + std::vector< std::string > indents; +}; namespace { -typedef std::list< ScopeTracker* > ScopeTrackerList; - -ScopeTrackerList scope_tracker_list; +/// Internal TLS (thread local storage) data container +boost::thread_specific_ptr thread_container; +/** + * Helper function to retrieve TLS pointer. + * Initializes the pointer if called for the first time. + * @return Pointer to the per thread container + */ +static PerThreadContainer *TLS_get_container() +{ + // First call? Construct options container + if (thread_container.get() == NULL) + thread_container.reset(new PerThreadContainer()); -std::vector< std::string > indents; + PerThreadContainer *per_thread = thread_container.get(); + return per_thread; +} /** * @brief ensures indent level string to exist up to the desired level. * @param level the desired indent level. */ -void ensure_indent_level(int level) +static void ensure_indent_level(PerThreadContainer *per_thread, int level) { - while (indents.size() <= level) + // First initialization? + if (per_thread->indents.empty()) + { + per_thread->indents.reserve(10); + if (level < 10) + level = 10; + + per_thread->indents.push_back(""); + } + + while (per_thread->indents.size() <= level) { - indents.push_back( indents.back() + " " ); + per_thread->indents.push_back( per_thread->indents.back() + " " ); } } // eo ensure_indent_level(int) - -/** - * @brief module initializer. - */ -class __Initializer -{ - public: - __Initializer() - { - // pre initialize indent strings: - indents.clear(); - indents.reserve(10); - indents.push_back(""); - for(int i=10; i-->0;) - { - indents.push_back( indents.back() + " " ); - } - } -} __initializer; - - } // eo namespace @@ -100,13 +111,14 @@ class __Initializer */ ScopeTracker::ScopeTracker( const SourceLocation& loc) -: Location(loc) -, Depth(0) -, FuncDepth(0) + : Location(loc) + , Depth(0) + , FuncDepth(0) + , PerThread(TLS_get_container()) { - if (!scope_tracker_list.empty()) + if (!PerThread->scope_tracker_list.empty()) { - ScopeTracker* last_tracker= scope_tracker_list.back(); + ScopeTracker* last_tracker= PerThread->scope_tracker_list.back(); if (Location) { if (last_tracker->Location @@ -118,8 +130,8 @@ ScopeTracker::ScopeTracker( } Depth= last_tracker->Depth + 1; } - ensure_indent_level(Depth); - scope_tracker_list.push_back(this); + ensure_indent_level(PerThread, Depth); + PerThread->scope_tracker_list.push_back(this); { std::ostringstream ostr; if (Location.FunctionName.empty()) @@ -139,7 +151,7 @@ ScopeTracker::ScopeTracker( // spit a message if (Logger::has_log_level(Logger::LogLevel::Debug)) { - GlobalLogger.debug() << indents[Depth] << "ENTER " << Tag; + GlobalLogger.debug() << PerThread->indents[Depth] << "ENTER " << Tag; } } // eo ScopeTrcaker::ScopeTracker(const SourceLocation&) @@ -154,15 +166,15 @@ ScopeTracker::~ScopeTracker() // spit a message if (Logger::has_log_level(Logger::LogLevel::Debug)) { - GlobalLogger.debug() << indents[Depth] << "LEAVE " << Tag; + GlobalLogger.debug() << PerThread->indents[Depth] << "LEAVE " << Tag; } - if (scope_tracker_list.empty()) + if (PerThread->scope_tracker_list.empty()) { return; } - if (scope_tracker_list.back() == this) + if (PerThread->scope_tracker_list.back() == this) { - scope_tracker_list.pop_back(); + PerThread->scope_tracker_list.pop_back(); } else { diff --git a/src/tracefunc.hpp b/src/tracefunc.hpp index 0d41f0d..7f5d0df 100644 --- a/src/tracefunc.hpp +++ b/src/tracefunc.hpp @@ -37,6 +37,7 @@ namespace I2n namespace Tracer { +class PerThreadContainer; /** * @brief scope tracker class. @@ -59,6 +60,8 @@ class ScopeTracker int FuncDepth; std::string Tag; + + PerThreadContainer *PerThread; }; // eo ScopeTracker diff --git a/test/test_logging.cpp b/test/test_logging.cpp index 8708fb6..cf2dc3d 100644 --- a/test/test_logging.cpp +++ b/test/test_logging.cpp @@ -124,4 +124,24 @@ BOOST_AUTO_TEST_CASE(TestScopeTrace1) } } // eo TestScopeTrace1() +void recursive_function(int level=0) +{ + SCOPETRACKER(); + + if (level < 10) + recursive_function(++level); +} + +BOOST_AUTO_TEST_CASE(TestRecursiveScopeTracker) +{ + Logger::enable_syslog( Logger::Facility::User ); + Logger::PartLogger log(__func__); + + Logger::set_log_level( 7 ); + Logger::enable_stderr_log(); + Logger::enable_log_file("zzUnitTest.log"); + + recursive_function(); +} + BOOST_AUTO_TEST_SUITE_END()