xref: /trunk/main/sal/inc/osl/diagnose.hxx (revision 22076bf1)
1565d668cSAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3565d668cSAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4565d668cSAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5565d668cSAndrew Rist  * distributed with this work for additional information
6565d668cSAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7565d668cSAndrew Rist  * to you under the Apache License, Version 2.0 (the
8565d668cSAndrew Rist  * "License"); you may not use this file except in compliance
9565d668cSAndrew Rist  * with the License.  You may obtain a copy of the License at
10565d668cSAndrew Rist  *
11565d668cSAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12565d668cSAndrew Rist  *
13565d668cSAndrew Rist  * Unless required by applicable law or agreed to in writing,
14565d668cSAndrew Rist  * software distributed under the License is distributed on an
15565d668cSAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16565d668cSAndrew Rist  * KIND, either express or implied.  See the License for the
17565d668cSAndrew Rist  * specific language governing permissions and limitations
18565d668cSAndrew Rist  * under the License.
19565d668cSAndrew Rist  *
20565d668cSAndrew Rist  *************************************************************/
21565d668cSAndrew Rist 
22565d668cSAndrew Rist 
23cdf0e10cSrcweir #if ! defined(OSL_DIAGNOSE_HXX_INCLUDED)
24cdf0e10cSrcweir #define OSL_DIAGNOSE_HXX_INCLUDED
25cdf0e10cSrcweir 
26cdf0e10cSrcweir #include "osl/diagnose.h"
27cdf0e10cSrcweir #include "osl/interlck.h"
28cdf0e10cSrcweir #include "osl/mutex.hxx"
29cdf0e10cSrcweir #include "rtl/instance.hxx"
30cdf0e10cSrcweir #include <hash_set>
31cdf0e10cSrcweir #include <functional>
32cdf0e10cSrcweir #include <typeinfo>
33cdf0e10cSrcweir 
34cdf0e10cSrcweir namespace osl {
35cdf0e10cSrcweir /// @internal
36cdf0e10cSrcweir namespace detail {
37cdf0e10cSrcweir 
38cdf0e10cSrcweir struct ObjectRegistryData;
39cdf0e10cSrcweir 
40cdf0e10cSrcweir } // namespace detail
41cdf0e10cSrcweir } // namespace osl
42cdf0e10cSrcweir 
43cdf0e10cSrcweir extern "C" {
44cdf0e10cSrcweir 
45cdf0e10cSrcweir /** @internal */
46cdf0e10cSrcweir bool SAL_CALL osl_detail_ObjectRegistry_storeAddresses( char const* pName )
47cdf0e10cSrcweir     SAL_THROW_EXTERN_C();
48cdf0e10cSrcweir 
49cdf0e10cSrcweir /** @internal */
50cdf0e10cSrcweir bool SAL_CALL osl_detail_ObjectRegistry_checkObjectCount(
51cdf0e10cSrcweir     ::osl::detail::ObjectRegistryData const& rData, ::std::size_t nExpected )
52cdf0e10cSrcweir     SAL_THROW_EXTERN_C();
53cdf0e10cSrcweir 
54cdf0e10cSrcweir /** @internal */
55cdf0e10cSrcweir void SAL_CALL osl_detail_ObjectRegistry_registerObject(
56cdf0e10cSrcweir     ::osl::detail::ObjectRegistryData & rData, void const* pObj )
57cdf0e10cSrcweir     SAL_THROW_EXTERN_C();
58cdf0e10cSrcweir 
59cdf0e10cSrcweir /** @internal */
60cdf0e10cSrcweir void SAL_CALL osl_detail_ObjectRegistry_revokeObject(
61cdf0e10cSrcweir     ::osl::detail::ObjectRegistryData & rData, void const* pObj )
62cdf0e10cSrcweir     SAL_THROW_EXTERN_C();
63cdf0e10cSrcweir 
64cdf0e10cSrcweir /** @internal */
65cdf0e10cSrcweir ::osl::Mutex & SAL_CALL osl_detail_ObjectRegistry_getMutex()
66cdf0e10cSrcweir     SAL_THROW_EXTERN_C();
67cdf0e10cSrcweir 
68cdf0e10cSrcweir } // extern "C"
69cdf0e10cSrcweir 
70cdf0e10cSrcweir namespace osl {
71cdf0e10cSrcweir 
72cdf0e10cSrcweir /// @internal
73cdf0e10cSrcweir namespace detail {
74cdf0e10cSrcweir 
75cdf0e10cSrcweir struct VoidPtrHash : ::std::unary_function<void const*, ::std::size_t> {
operator ()osl::detail::VoidPtrHash76cdf0e10cSrcweir     ::std::size_t operator()( void const* p ) const {
77cdf0e10cSrcweir         ::std::size_t const d = static_cast< ::std::size_t >(
78cdf0e10cSrcweir             reinterpret_cast< ::std::ptrdiff_t >(p) );
79cdf0e10cSrcweir         return d + (d >> 3);
80cdf0e10cSrcweir     }
81cdf0e10cSrcweir };
82cdf0e10cSrcweir 
83*22076bf1SHerbert Dürr typedef ::std::hash_set<void const*, VoidPtrHash, ::std::equal_to<void const*> > VoidPointerSet;
84cdf0e10cSrcweir 
85cdf0e10cSrcweir struct ObjectRegistryData {
ObjectRegistryDataosl::detail::ObjectRegistryData86cdf0e10cSrcweir     ObjectRegistryData( ::std::type_info const& rTypeInfo )
87cdf0e10cSrcweir         : m_pName(rTypeInfo.name()), m_nCount(0), m_addresses(),
88cdf0e10cSrcweir           m_bStoreAddresses(osl_detail_ObjectRegistry_storeAddresses(m_pName)){}
89cdf0e10cSrcweir 
90cdf0e10cSrcweir     char const* const m_pName;
91cdf0e10cSrcweir     oslInterlockedCount m_nCount;
92cdf0e10cSrcweir     VoidPointerSet m_addresses;
93cdf0e10cSrcweir     bool const m_bStoreAddresses;
94cdf0e10cSrcweir };
95cdf0e10cSrcweir 
96cdf0e10cSrcweir template <typename T>
97cdf0e10cSrcweir class ObjectRegistry
98cdf0e10cSrcweir {
99cdf0e10cSrcweir public:
ObjectRegistry()100cdf0e10cSrcweir     ObjectRegistry() : m_data( typeid(T) ) {}
~ObjectRegistry()101cdf0e10cSrcweir     ~ObjectRegistry() { checkObjectCount(0); }
102cdf0e10cSrcweir 
checkObjectCount(::std::size_t nExpected) const103cdf0e10cSrcweir     bool checkObjectCount( ::std::size_t nExpected ) const {
104cdf0e10cSrcweir         bool const bRet = osl_detail_ObjectRegistry_checkObjectCount(
105cdf0e10cSrcweir             m_data, nExpected );
106cdf0e10cSrcweir         if (!bRet && m_data.m_bStoreAddresses) {
107cdf0e10cSrcweir             MutexGuard const guard( osl_detail_ObjectRegistry_getMutex() );
108cdf0e10cSrcweir             // following loop is for debugging purposes, iterating over map:
109cdf0e10cSrcweir             VoidPointerSet::const_iterator iPos(m_data.m_addresses.begin());
110cdf0e10cSrcweir             VoidPointerSet::const_iterator const iEnd(m_data.m_addresses.end());
111cdf0e10cSrcweir             for ( ; iPos != iEnd; ++iPos ) {
112cdf0e10cSrcweir                 OSL_ASSERT( *iPos != 0 );
113cdf0e10cSrcweir             }
114cdf0e10cSrcweir         }
115cdf0e10cSrcweir         return bRet;
116cdf0e10cSrcweir     }
117cdf0e10cSrcweir 
registerObject(void const * pObj)118cdf0e10cSrcweir     void registerObject( void const* pObj ) {
119cdf0e10cSrcweir         osl_detail_ObjectRegistry_registerObject(m_data, pObj);
120cdf0e10cSrcweir     }
121cdf0e10cSrcweir 
revokeObject(void const * pObj)122cdf0e10cSrcweir     void revokeObject( void const* pObj ) {
123cdf0e10cSrcweir         osl_detail_ObjectRegistry_revokeObject(m_data, pObj);
124cdf0e10cSrcweir     }
125cdf0e10cSrcweir 
126cdf0e10cSrcweir private:
127cdf0e10cSrcweir     // not impl:
128cdf0e10cSrcweir     ObjectRegistry( ObjectRegistry const& );
129cdf0e10cSrcweir     ObjectRegistry const& operator=( ObjectRegistry const& );
130cdf0e10cSrcweir 
131cdf0e10cSrcweir     ObjectRegistryData m_data;
132cdf0e10cSrcweir };
133cdf0e10cSrcweir 
134cdf0e10cSrcweir } // namespace detail
135cdf0e10cSrcweir 
136cdf0e10cSrcweir /** Helper class which indicates leaking object(s) of a particular class in
137cdf0e10cSrcweir     non-pro builds; use e.g.
138cdf0e10cSrcweir 
139cdf0e10cSrcweir     <pre>
140cdf0e10cSrcweir     class MyClass : private osl::DebugBase<MyClass> {...};
141cdf0e10cSrcweir     </pre>
142cdf0e10cSrcweir 
143cdf0e10cSrcweir     Using the environment variable
144cdf0e10cSrcweir 
145cdf0e10cSrcweir     OSL_DEBUGBASE_STORE_ADDRESSES=MyClass;YourClass;...
146cdf0e10cSrcweir 
147cdf0e10cSrcweir     you can specify a ';'-separated list of strings matching to class names
148cdf0e10cSrcweir     (or "all" for all classes), for which DebugBase stores addresses to created
149cdf0e10cSrcweir     objects instead of just counting them.  This enables you to iterate over
150cdf0e10cSrcweir     leaking objects in your debugger.
151cdf0e10cSrcweir 
152cdf0e10cSrcweir     @tpl InheritingClassT binds the template instance to that class
153cdf0e10cSrcweir     @internal Use at own risk.
154cdf0e10cSrcweir               For now this is just public (yet unpublished) API and may change
155cdf0e10cSrcweir               in the future!
156cdf0e10cSrcweir */
157cdf0e10cSrcweir template <typename InheritingClassT>
158cdf0e10cSrcweir class DebugBase
159cdf0e10cSrcweir {
160cdf0e10cSrcweir public:
161cdf0e10cSrcweir #if OSL_DEBUG_LEVEL <= 0
checkObjectCount(::std::size_t=0)162cdf0e10cSrcweir     static bool checkObjectCount( ::std::size_t = 0 ) { return true; }
163cdf0e10cSrcweir #else // OSL_DEBUG_LEVEL > 0
164cdf0e10cSrcweir     /** @return whether the expected number of objects is alive,
165cdf0e10cSrcweir                 else this function OSL_ASSERTs
166cdf0e10cSrcweir     */
167cdf0e10cSrcweir     static bool checkObjectCount( ::std::size_t nExpected = 0 ) {
168cdf0e10cSrcweir         return StaticObjectRegistry::get().checkObjectCount(nExpected);
169cdf0e10cSrcweir     }
170cdf0e10cSrcweir 
171cdf0e10cSrcweir protected:
172cdf0e10cSrcweir     DebugBase() {
173cdf0e10cSrcweir         StaticObjectRegistry::get().registerObject( this );
174cdf0e10cSrcweir     }
175cdf0e10cSrcweir     ~DebugBase() {
176cdf0e10cSrcweir         StaticObjectRegistry::get().revokeObject( this );
177cdf0e10cSrcweir     }
178cdf0e10cSrcweir 
179cdf0e10cSrcweir private:
180cdf0e10cSrcweir     struct StaticObjectRegistry
181cdf0e10cSrcweir         : ::rtl::Static<detail::ObjectRegistry<InheritingClassT>,
182cdf0e10cSrcweir                         StaticObjectRegistry> {};
183cdf0e10cSrcweir #endif
184cdf0e10cSrcweir };
185cdf0e10cSrcweir 
186cdf0e10cSrcweir } // namespace osl
187cdf0e10cSrcweir 
188cdf0e10cSrcweir #endif // ! defined(OSL_DIAGNOSE_HXX_INCLUDED)
189cdf0e10cSrcweir 
190