* @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"
#include <list>
#include <vector>
#include <sstream>
-
+#include <boost/thread/tss.hpp>
namespace I2n
{
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<PerThreadContainer> 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 <anonymous>
*/
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
}
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())
// 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&)
// 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
{