repackage as a more general facility (DiagnosticContext)
implementation unaltered (just managing the NoBug handle)
This commit is contained in:
parent
4dfd7266b9
commit
3466793976
3 changed files with 172 additions and 82 deletions
156
src/lib/diagnostic-context.hpp
Normal file
156
src/lib/diagnostic-context.hpp
Normal 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
|
||||
|
|
@ -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_;
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
Loading…
Reference in a new issue