xref: /aoo41x/main/sal/inc/osl/diagnose.hxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 #if ! defined(OSL_DIAGNOSE_HXX_INCLUDED)
28 #define OSL_DIAGNOSE_HXX_INCLUDED
29 
30 #if ! defined(_OSL_DIAGNOSE_H_)
31 #include "osl/diagnose.h"
32 #endif
33 #if ! defined(_OSL_INTERLOCK_H_)
34 #include "osl/interlck.h"
35 #endif
36 #if ! defined(_OSL_MUTEX_HXX_)
37 #include "osl/mutex.hxx"
38 #endif
39 #if ! defined(INCLUDED_RTL_ALLOCATOR_HXX)
40 #include "rtl/allocator.hxx"
41 #endif
42 #if ! defined(_RTL_INSTANCE_HXX_)
43 #include "rtl/instance.hxx"
44 #endif
45 #include <hash_set>
46 #include <functional>
47 #include <typeinfo>
48 
49 namespace osl {
50 /// @internal
51 namespace detail {
52 
53 struct ObjectRegistryData;
54 
55 } // namespace detail
56 } // namespace osl
57 
58 extern "C" {
59 
60 /** @internal */
61 bool SAL_CALL osl_detail_ObjectRegistry_storeAddresses( char const* pName )
62     SAL_THROW_EXTERN_C();
63 
64 /** @internal */
65 bool SAL_CALL osl_detail_ObjectRegistry_checkObjectCount(
66     ::osl::detail::ObjectRegistryData const& rData, ::std::size_t nExpected )
67     SAL_THROW_EXTERN_C();
68 
69 /** @internal */
70 void SAL_CALL osl_detail_ObjectRegistry_registerObject(
71     ::osl::detail::ObjectRegistryData & rData, void const* pObj )
72     SAL_THROW_EXTERN_C();
73 
74 /** @internal */
75 void SAL_CALL osl_detail_ObjectRegistry_revokeObject(
76     ::osl::detail::ObjectRegistryData & rData, void const* pObj )
77     SAL_THROW_EXTERN_C();
78 
79 /** @internal */
80 ::osl::Mutex & SAL_CALL osl_detail_ObjectRegistry_getMutex()
81     SAL_THROW_EXTERN_C();
82 
83 } // extern "C"
84 
85 namespace osl {
86 
87 /// @internal
88 namespace detail {
89 
90 struct VoidPtrHash : ::std::unary_function<void const*, ::std::size_t> {
91     ::std::size_t operator()( void const* p ) const {
92         ::std::size_t const d = static_cast< ::std::size_t >(
93             reinterpret_cast< ::std::ptrdiff_t >(p) );
94         return d + (d >> 3);
95     }
96 };
97 
98 typedef ::std::hash_set<void const*, VoidPtrHash, ::std::equal_to<void const*>,
99                         ::rtl::Allocator<void const*> > VoidPointerSet;
100 
101 struct ObjectRegistryData {
102     ObjectRegistryData( ::std::type_info const& rTypeInfo )
103         : m_pName(rTypeInfo.name()), m_nCount(0), m_addresses(),
104           m_bStoreAddresses(osl_detail_ObjectRegistry_storeAddresses(m_pName)){}
105 
106     char const* const m_pName;
107     oslInterlockedCount m_nCount;
108     VoidPointerSet m_addresses;
109     bool const m_bStoreAddresses;
110 };
111 
112 template <typename T>
113 class ObjectRegistry
114 {
115 public:
116     ObjectRegistry() : m_data( typeid(T) ) {}
117     ~ObjectRegistry() { checkObjectCount(0); }
118 
119     bool checkObjectCount( ::std::size_t nExpected ) const {
120         bool const bRet = osl_detail_ObjectRegistry_checkObjectCount(
121             m_data, nExpected );
122         if (!bRet && m_data.m_bStoreAddresses) {
123             MutexGuard const guard( osl_detail_ObjectRegistry_getMutex() );
124             // following loop is for debugging purposes, iterating over map:
125             VoidPointerSet::const_iterator iPos(m_data.m_addresses.begin());
126             VoidPointerSet::const_iterator const iEnd(m_data.m_addresses.end());
127             for ( ; iPos != iEnd; ++iPos ) {
128                 OSL_ASSERT( *iPos != 0 );
129             }
130         }
131         return bRet;
132     }
133 
134     void registerObject( void const* pObj ) {
135         osl_detail_ObjectRegistry_registerObject(m_data, pObj);
136     }
137 
138     void revokeObject( void const* pObj ) {
139         osl_detail_ObjectRegistry_revokeObject(m_data, pObj);
140     }
141 
142 private:
143     // not impl:
144     ObjectRegistry( ObjectRegistry const& );
145     ObjectRegistry const& operator=( ObjectRegistry const& );
146 
147     ObjectRegistryData m_data;
148 };
149 
150 } // namespace detail
151 
152 /** Helper class which indicates leaking object(s) of a particular class in
153     non-pro builds; use e.g.
154 
155     <pre>
156     class MyClass : private osl::DebugBase<MyClass> {...};
157     </pre>
158 
159     Using the environment variable
160 
161     OSL_DEBUGBASE_STORE_ADDRESSES=MyClass;YourClass;...
162 
163     you can specify a ';'-separated list of strings matching to class names
164     (or "all" for all classes), for which DebugBase stores addresses to created
165     objects instead of just counting them.  This enables you to iterate over
166     leaking objects in your debugger.
167 
168     @tpl InheritingClassT binds the template instance to that class
169     @internal Use at own risk.
170               For now this is just public (yet unpublished) API and may change
171               in the future!
172 */
173 template <typename InheritingClassT>
174 class DebugBase
175 {
176 public:
177 #if OSL_DEBUG_LEVEL <= 0
178     static bool checkObjectCount( ::std::size_t = 0 ) { return true; }
179 #else // OSL_DEBUG_LEVEL > 0
180     /** @return whether the expected number of objects is alive,
181                 else this function OSL_ASSERTs
182     */
183     static bool checkObjectCount( ::std::size_t nExpected = 0 ) {
184         return StaticObjectRegistry::get().checkObjectCount(nExpected);
185     }
186 
187 protected:
188     DebugBase() {
189         StaticObjectRegistry::get().registerObject( this );
190     }
191     ~DebugBase() {
192         StaticObjectRegistry::get().revokeObject( this );
193     }
194 
195 private:
196     struct StaticObjectRegistry
197         : ::rtl::Static<detail::ObjectRegistry<InheritingClassT>,
198                         StaticObjectRegistry> {};
199 #endif
200 };
201 
202 } // namespace osl
203 
204 #endif // ! defined(OSL_DIAGNOSE_HXX_INCLUDED)
205 
206