repackage as a more general facility (DiagnosticContext)

implementation unaltered (just managing the NoBug handle)
This commit is contained in:
Fischlurch 2010-02-13 04:54:59 +01:00
parent 4dfd7266b9
commit 3466793976
3 changed files with 172 additions and 82 deletions

View file

@ -0,0 +1,156 @@
/*
DIAGNOSTIC-CONTEXT.hpp - thread local stack for explicitly collecting diagnostic context info
Copyright (C) Lumiera.org
2010, Hermann Vosseler <Ichthyostega@web.de>
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 <boost/noncopyable.hpp>
#include <nobug.h>
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<DiagnosticContext> 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

View file

@ -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_;

View file

@ -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 <Ichthyostega@web.de>
@ -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<NobugResourceHandle> 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