/* DIAGNOSTIC-CONTEXT.hpp - thread local stack for explicitly collecting diagnostic context info Copyright (C) Lumiera.org 2010, Hermann Vosseler This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /** @file diagnostic-context.hpp ** Facility for collecting diagnostic informations explicitly. ** Unlike a trace logging run, this facility is intended to be fed explicitly with ** diagnostic information describing the currently ongoing operation in a semantic ** high-level manner. The rationale is to pinpoint \em those informations which aren't ** obvious when just looking at a callstack with the debugger. Instances of the class ** DiagnosticContext should be placed explicitly as automatic (stack) variable ** into selected relevant scopes; these "information frames" can be accessed ** from an enclosed scope as a per-thread stack. DiagnosticContext provides ** an controlled environment for adding diagnostic code on demand; typically ** to be configured such as to resolve into an empty class for release builds. ** ** As of 2/10, this is an experimental feature in evaluation. To start with, ** I'll use it to solve the problem of providing a NoBug resource tracker handle ** without tangling the object monitor code (sync.hpp) with low level, NoBug related ** implementation details. ** ** @todo add the actual diagnostic content **/ #ifndef LIB_DIAGNOSTIC_CONTEXT_H #define LIB_DIAGNOSTIC_CONTEXT_H #include "lib/error.hpp" #include "lib/thread-local.hpp" #include #include namespace lib { #ifdef NOBUG_MODE_ALPHA ////////////////////////TODO don't we need the handle in BETA builds for resource logging? /** * Diagnostic data frame to collect specific informations concerning a scope. * To be placed explicitly as an automatic (stack) variable. Provides a controlled * environment for hooking up diagnostic code. Within each thread, a stack of * such information frames concerning nested scopes is maintained automatically. * It can be accessed via static API. * @warning never store this into global data structures. * @note as of 2/10 used for housing the NoBug resource tracker handle * in conjunction with object monitor based locking * @see sync.hpp */ class DiagnosticContext : boost::noncopyable { typedef nobug_resource_user* Handle; typedef ThreadLocalPtr ThreadLocalAccess; Handle handle_; DiagnosticContext * const prev_; /** embedded thread local pointer * to the innermost context encountered */ static ThreadLocalAccess& current() { static ThreadLocalAccess accessPoint; return accessPoint; } public: DiagnosticContext() : handle_(0) , prev_(current().get()) { current().set (this); } ~DiagnosticContext() { ASSERT (this == current().get()); current().set (prev_); } operator Handle* () ///< payload: NoBug resource tracker user handle { return &handle_; } /** accessing the innermost diagnostic context created */ static DiagnosticContext& access () { DiagnosticContext* innermost = current().get(); if (!innermost) throw lumiera::error::Logic ("Accessing Diagnostic context out of order; " "an instance should have been created in " "an enclosing scope"); return *innermost; } }; #else /* not NOBUG_ALPHA */ /** * Disabled placeholder for the Diagnostic context, not used in release builds. */ class DiagnosticContext : boost::noncopyable { public: operator Handle* () ///< payload: NoBug resource tracker user handle { return 0; } /** accessing the innermost diagnostic context created */ static DiagnosticContext& access () { UNIMPLEMENTED ("how to disable DiagnosticContext with minimum overhead"); } }; #endif /* NOBUG_ALPHA? */ } // namespace lib #endif