diff --git a/src/lib/diagnostic-context.hpp b/src/lib/diagnostic-context.hpp new file mode 100644 index 000000000..0003c0677 --- /dev/null +++ b/src/lib/diagnostic-context.hpp @@ -0,0 +1,156 @@ +/* + 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 diff --git a/src/lib/sync.hpp b/src/lib/sync.hpp index e258f35ee..d6197ab0f 100644 --- a/src/lib/sync.hpp +++ b/src/lib/sync.hpp @@ -68,7 +68,7 @@ #include "lib/error.hpp" #include "lib/util.hpp" -#include "lib/sync-nobug-resource-handle.hpp" +#include "lib/diagnostic-context.hpp" extern "C" { #include "lib/mutex.h" @@ -238,10 +238,10 @@ namespace lib { : protected MTX { protected: - NobugResourceHandle& + DiagnosticContext& _usage() { - return NobugResourceHandle::access(); + return DiagnosticContext::access(); } ~Mutex () { } @@ -459,7 +459,7 @@ namespace lib { public: class Lock - : sync::NobugResourceHandle + : DiagnosticContext { Monitor& mon_; diff --git a/src/lib/sync-nobug-resource-handle.hpp b/src/lib/thread-local.hpp similarity index 51% rename from src/lib/sync-nobug-resource-handle.hpp rename to src/lib/thread-local.hpp index 4415fa1a5..d0cdb06a4 100644 --- a/src/lib/sync-nobug-resource-handle.hpp +++ b/src/lib/thread-local.hpp @@ -1,5 +1,5 @@ /* - SYNC-NOBUG-RESOURCE-HANDLE.hpp - supplement: manage storage for NoBug resource handles + THREAD-LOCAL.hpp - support using thread local data Copyright (C) Lumiera.org 2010, Hermann Vosseler @@ -20,19 +20,19 @@ */ -/** @file sync-nobug-resource-handle.hpp - ** Supplement to sync.hpp: manage the storage for NoBug resource handles. - ** For resource tracking we need storage for each \em usage of a resource, in order - ** to provide a user handle for this usage situation. I consider this an internal - ** detail and want to keep it away from the code concerned with the resource itself - ** (here the object monitor). +/** @file thread-local.hpp + ** Helpers for working with thread local data. + ** As we don't want to depend on boost.threads, we'll provide some simple + ** support facilities for dealing with thread local data in RAII fashion. + ** Draft as of 2/10, to be extended on demand. ** - ** @todo experimental solution + ** @todo care for unit test coverage + ** @todo WIP-WIP. Maybe add facilities similar to boost::specific_ptr **/ -#ifndef LIB_SYNC_NOBUG_RESOURCE_HANDLE_H -#define LIB_SYNC_NOBUG_RESOURCE_HANDLE_H +#ifndef LIB_THREAD_LOCAL_H +#define LIB_THREAD_LOCAL_H #include "lib/error.hpp" @@ -44,7 +44,6 @@ namespace lib { -namespace sync{ /** @@ -104,75 +103,10 @@ namespace sync{ ,lumiera::error::LUMIERA_ERROR_BOTTOM_VALUE); return p; } - + }; - - -//#ifdef NOBUG_MODE_ALPHA /////////TODO don't we need the handle in BETA builds for resource logging? - /** - * Diagnostic context, housing the NoBug resource tracker handle. - * Instances of this class should be created on the stack at appropriate scopes. - * When used in nested scopes, a chain (stack) of contexts is maintained automatically. - * Client code can access the innermost handle via static API. - * @warning never store this into global data structures. - */ - class NobugResourceHandle - : boost::noncopyable - { - typedef nobug_resource_user* Handle; - typedef ThreadLocalPtr ThreadLocalAccess; - - Handle handle_; - NobugResourceHandle * const prev_; - - /** embedded thread local pointer - * to the innermost context encountered */ - static ThreadLocalAccess& - current() - { - static ThreadLocalAccess accessPoint; - return accessPoint; - } - - - public: - NobugResourceHandle() - : handle_(0) - , prev_(current().get()) - { - current().set (this); - } - - ~NobugResourceHandle() - { - ASSERT (this == current().get()); - current().set (prev_); - } - - - operator Handle* () ///< payload: NoBug resource tracker user handle - { - return &handle_; - } - - /** accessing the innermost diagnostic context created */ - static NobugResourceHandle& - access () - { - NobugResourceHandle* 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; - } - }; -//#endif - - - -}} // namespace lib::sync +} // namespace lib #endif