From 54200cc7e8523478825dd6ccb760be17e898dc6a Mon Sep 17 00:00:00 2001 From: William S Fulton Date: Tue, 9 Oct 2007 23:56:31 +0000 Subject: [PATCH] shared_ptr memory leak testing. Make increment and decrement counts thread safe. Fix template test. git-svn-id: https://swig.svn.sourceforge.net/svnroot/swig/trunk@9977 626c5289-ae23-0410-ae9c-e8d60b6d4f22 --- .../csharp/li_boost_shared_ptr_runme.cs | 21 ++- .../java/li_boost_shared_ptr_runme.java | 22 ++- Examples/test-suite/li_boost_shared_ptr.i | 175 +++++++++++++----- Examples/test-suite/shared_ptr_wrapper.h | 100 ++++++++++ Examples/test-suite/swig_examples_lock.h | 59 ++++++ 5 files changed, 322 insertions(+), 55 deletions(-) create mode 100644 Examples/test-suite/shared_ptr_wrapper.h create mode 100644 Examples/test-suite/swig_examples_lock.h diff --git a/Examples/test-suite/csharp/li_boost_shared_ptr_runme.cs b/Examples/test-suite/csharp/li_boost_shared_ptr_runme.cs index 8a07f7e65..34c641806 100644 --- a/Examples/test-suite/csharp/li_boost_shared_ptr_runme.cs +++ b/Examples/test-suite/csharp/li_boost_shared_ptr_runme.cs @@ -13,14 +13,14 @@ public class runme li_boost_shared_ptr.debug_shared=debug; - const int loopCount = 1; + // Change loop count to run for a long time to monitor memory + const int loopCount = 1; //50000; for (int i=0; i* shared_ptr<>& and use IntPtr instead of HandleRef for C# ??? -// Put tests in a loop and monitor memory -// Remove proxy upcast method - implement %feature("shadow") ??? which replaces the shadow method -// Change GC to garbage collect until expected result with time out +// Remove proxy upcast method - implement %feature("shadow") ??? which replaces the proxy method // pgcpp - make it work if comments in jtype typemap %exception { @@ -51,22 +72,24 @@ struct Klass { Klass(const std::string &val) : value(val) { if (debug_shared) cout << "Klass(string) [" << value << "]" << endl; increment(); } virtual ~Klass() { if (debug_shared) cout << "~Klass() [" << value << "]" << endl; decrement(); } - virtual std::string getValue() { return value; } + virtual std::string getValue() const { return value; } void append(const std::string &s) { value += s; } Klass(const Klass &other) : value(other.value) { if (debug_shared) cout << "Klass(const Klass&) [" << value << "]" << endl; increment(); } Klass &operator=(const Klass &other) { value = other.value; return *this; } static int getTotal_count() { return total_count; } -private: // TODO: make operator= private too to test shared_ptr - // lock increment and decrement as a destructor could be called at the same time as a new object is being created - static void increment() { /*EnterCriticalSection(lock);*/ total_count++; } - static void decrement() { /*EnterCriticalSection(lock);*/ total_count--; } +private: + // lock increment and decrement as a destructor could be called at the same time as a + // new object is being created - C# / Java, at least, have finalizers run in a separate thread + static SwigExamples::CriticalSection critical_section; + static void increment() { SwigExamples::Lock lock(critical_section); total_count++; } + static void decrement() { SwigExamples::Lock lock(critical_section); total_count--; } static int total_count; -// static CriticalSection lock; std::string value; int array[1024]; }; +SwigExamples::CriticalSection Space::Klass::critical_section; struct IgnoredMultipleInheritBase { virtual ~IgnoredMultipleInheritBase() {} double d; double e;}; @@ -76,7 +99,7 @@ struct KlassDerived : IgnoredMultipleInheritBase, Klass { KlassDerived() : Klass() {} KlassDerived(const std::string &val) : Klass(val) {} virtual ~KlassDerived() {} - virtual std::string getValue() { return Klass::getValue() + "-Derived"; } + virtual std::string getValue() const { return Klass::getValue() + "-Derived"; } }; KlassDerived* derivedpointertest(KlassDerived* kd) { if (kd) @@ -85,38 +108,38 @@ KlassDerived* derivedpointertest(KlassDerived* kd) { } -boost::shared_ptr factorycreate() { - return boost::shared_ptr(new Klass("factorycreate")); +SwigBoost::shared_ptr factorycreate() { + return SwigBoost::shared_ptr(new Klass("factorycreate")); } // smart pointer -boost::shared_ptr smartpointertest(boost::shared_ptr k) { +SwigBoost::shared_ptr smartpointertest(SwigBoost::shared_ptr k) { if (k) k->append(" smartpointertest"); - return boost::shared_ptr(k); + return SwigBoost::shared_ptr(k); } -boost::shared_ptr* smartpointerpointertest(boost::shared_ptr* k) { +SwigBoost::shared_ptr* smartpointerpointertest(SwigBoost::shared_ptr* k) { if (k && *k) (*k)->append(" smartpointerpointertest"); return k; } -boost::shared_ptr& smartpointerreftest(boost::shared_ptr& k) { +SwigBoost::shared_ptr& smartpointerreftest(SwigBoost::shared_ptr& k) { if (k) k->append(" smartpointerreftest"); return k; } -boost::shared_ptr*& smartpointerpointerreftest(boost::shared_ptr*& k) { +SwigBoost::shared_ptr*& smartpointerpointerreftest(SwigBoost::shared_ptr*& k) { if (k && *k) (*k)->append(" smartpointerpointerreftest"); return k; } // const -boost::shared_ptr constsmartpointertest(boost::shared_ptr k) { - return boost::shared_ptr(k); +SwigBoost::shared_ptr constsmartpointertest(SwigBoost::shared_ptr k) { + return SwigBoost::shared_ptr(k); } -boost::shared_ptr* constsmartpointerpointertest(boost::shared_ptr* k) { +SwigBoost::shared_ptr* constsmartpointerpointertest(SwigBoost::shared_ptr* k) { return k; } -boost::shared_ptr& constsmartpointerreftest(boost::shared_ptr& k) { +SwigBoost::shared_ptr& constsmartpointerreftest(SwigBoost::shared_ptr& k) { return k; } // plain pointer @@ -138,7 +161,7 @@ Klass*& pointerreftest(Klass*& k) { return k; } // null -std::string nullsmartpointerpointertest(boost::shared_ptr* k) { +std::string nullsmartpointerpointertest(SwigBoost::shared_ptr* k) { if (k && *k) return "not null"; else if (!k) @@ -150,8 +173,8 @@ std::string nullsmartpointerpointertest(boost::shared_ptr* k) { Klass *pointerownertest() { return new Klass("pointerownertest"); } -boost::shared_ptr* smartpointerpointerownertest() { - return new boost::shared_ptr(new Klass("smartpointerpointerownertest")); +SwigBoost::shared_ptr* smartpointerpointerownertest() { + return new SwigBoost::shared_ptr(new Klass("smartpointerpointerownertest")); } /* Klass* arraytest(Klass k[]) { @@ -161,11 +184,11 @@ Klass* arraytest(Klass k[]) { */ -long use_count(const boost::shared_ptr& sptr) { +long use_count(const SwigBoost::shared_ptr& sptr) { return sptr.use_count(); } -const boost::shared_ptr& ref_1() { - static boost::shared_ptr sptr; +const SwigBoost::shared_ptr& ref_1() { + static SwigBoost::shared_ptr sptr; return sptr; } @@ -182,32 +205,90 @@ const boost::shared_ptr& ref_1() { %inline %{ struct MemberVariables { MemberVariables() : SmartMemberPointer(&SmartMemberValue), SmartMemberReference(SmartMemberValue), MemberPointer(0), MemberReference(MemberValue) {} - boost::shared_ptr SmartMemberValue; - boost::shared_ptr * SmartMemberPointer; - boost::shared_ptr & SmartMemberReference; + SwigBoost::shared_ptr SmartMemberValue; + SwigBoost::shared_ptr * SmartMemberPointer; + SwigBoost::shared_ptr & SmartMemberReference; Space::Klass MemberValue; Space::Klass * MemberPointer; Space::Klass & MemberReference; }; %} -// Templates -%inline %{ -template struct Base { -}; -typedef Base BaseIntDouble_t; -%} -%template(BaseIntDouble) Base; -%inline %{ -template struct Pair : Base { - T1 m_t1; - T2 m_t2; - Pair(T1 t1, T2 t2) : m_t1(t1), m_t2(t2) {} -}; -%} -%template(PairIntDouble) Pair; +// Note: %template after the shared_ptr typemaps SWIG_SHARED_PTR(BaseIntDouble, Base) // Note: cannot use Base in the macro below because of the comma in the type, // so we use a typedef instead. Alternatively use %arg(Base). %arg is defined in swigmacros.swg. SWIG_SHARED_PTR_DERIVED(PairIntDouble, BaseIntDouble_t, Pair) +// Templates +%inline %{ +template struct Base { + Space::Klass klassBase; + T1 baseVal1; + T2 baseVal2; + Base(T1 t1, T2 t2) : baseVal1(t1*2), baseVal2(t2*2) {} +}; +typedef Base BaseIntDouble_t; +%} + +%template(BaseIntDouble) Base; + +%inline %{ +template struct Pair : Base { + Space::Klass klassPair; + T1 val1; + T2 val2; + Pair(T1 t1, T2 t2) : Base(t1, t2), val1(t1), val2(t2) {} +}; +%} + +%template(PairIntDouble) Pair; + + +// For counting the instances of shared_ptr (all of which are created on the heap) +// shared_ptr_wrapper_count() gives overall count +%inline %{ +namespace SwigBoost { + const int NOT_COUNTING = -123456; + int shared_ptr_wrapper_count() { + #ifdef SHARED_PTR_WRAPPER + return SwigBoost::SharedPtrWrapper::getTotalCount(); + #else + return NOT_COUNTING; + #endif + } + #ifdef SHARED_PTR_WRAPPER + template<> std::string show_message(boost::shared_ptr*t) { + if (!t) + return "null shared_ptr!!!"; + if (boost::get_deleter(*t)) + return "Klass NULL DELETER"; // pointer may be dangling so cannot use it + if (*t) + return "Klass: " + (*t)->getValue(); + else + return "Klass: NULL"; + } + template<> std::string show_message(boost::shared_ptr*t) { + if (!t) + return "null shared_ptr!!!"; + if (boost::get_deleter(*t)) + return "Klass NULL DELETER"; // pointer may be dangling so cannot use it + if (*t) + return "Klass: " + (*t)->getValue(); + else + return "Klass: NULL"; + } + template<> std::string show_message(boost::shared_ptr*t) { + if (!t) + return "null shared_ptr!!!"; + if (boost::get_deleter(*t)) + return "KlassDerived NULL DELETER"; // pointer may be dangling so cannot use it + if (*t) + return "KlassDerived: " + (*t)->getValue(); + else + return "KlassDerived: NULL"; + } + #endif +} +%} + diff --git a/Examples/test-suite/shared_ptr_wrapper.h b/Examples/test-suite/shared_ptr_wrapper.h new file mode 100644 index 000000000..f6d039899 --- /dev/null +++ b/Examples/test-suite/shared_ptr_wrapper.h @@ -0,0 +1,100 @@ +// defines SwigBoost::shared_ptr, a wrapper around boost::shared_ptr +// Use this shared_ptr wrapper for testing memory leaks of shared_ptr. +// getTotalCount() should return zero at end of test + +#include + +struct SWIG_null_deleter; // forward reference, definition is in shared_ptr.i +namespace SwigBoost { +// This template can be specialized for better debugging information +template std::string show_message(boost::shared_ptr*t) { + if (!t) + return "null shared_ptr!!!"; + if (boost::get_deleter(*t)) + return std::string(typeid(t).name()) + " NULL DELETER"; + if (*t) + return std::string(typeid(t).name()) + " object"; + else + return std::string(typeid(t).name()) + " NULL"; +} + +namespace SharedPtrWrapper { + static SwigExamples::CriticalSection critical_section; + static int total_count = 0; + + template void increment(boost::shared_ptr* ptr) { + SwigExamples::Lock lock(critical_section); + std::cout << ptr << " " << show_message(ptr) << " " << " +" << std::endl << std::flush; + total_count++; + } + template void decrement(boost::shared_ptr* ptr) { + SwigExamples::Lock lock(critical_section); + std::cout << ptr << " " << show_message(ptr) << " " << " -" << std::endl << std::flush; + total_count--; + } + static int getTotalCount() { return total_count; } +} + +template class shared_ptr { +private: + typedef shared_ptr this_type; +public: + typedef typename boost::detail::shared_ptr_traits::reference reference; + + shared_ptr() : m_shared_ptr() { + SharedPtrWrapper::increment(&m_shared_ptr); + } + template explicit shared_ptr(Y* p) : m_shared_ptr(p) { + SharedPtrWrapper::increment(&m_shared_ptr); + } + template explicit shared_ptr(Y* p, D d) : m_shared_ptr(p, d) { + SharedPtrWrapper::increment(&m_shared_ptr); + } + + shared_ptr(shared_ptr const & other) + : m_shared_ptr(other.m_shared_ptr) + { + SharedPtrWrapper::increment(&m_shared_ptr); + } + + template shared_ptr(shared_ptr const & other) + : m_shared_ptr(other.m_shared_ptr) + { + SharedPtrWrapper::increment(&m_shared_ptr); + } + + reference operator*() const { + return m_shared_ptr.operator*(); + } + T* operator->() const { + return m_shared_ptr.operator->(); + } + T* get() const { + return m_shared_ptr.get(); + } + operator bool() const { + return m_shared_ptr.get() == 0 ? false : true; + } + bool unique() const { + return m_shared_ptr.unique(); + } + long use_count() const { + return m_shared_ptr.use_count(); + } + void swap(shared_ptr& other) { + std::swap(m_shared_ptr, other.m_shared_ptr); + } + template bool _internal_less(shared_ptr const & rhs) const { + return m_shared_ptr < rhs.m_shared_ptr; + } + ~shared_ptr() { + SharedPtrWrapper::decrement(&m_shared_ptr); + } + +private: + template friend class shared_ptr; + + boost::shared_ptr m_shared_ptr; +}; +} + diff --git a/Examples/test-suite/swig_examples_lock.h b/Examples/test-suite/swig_examples_lock.h new file mode 100644 index 000000000..b28f5bf1a --- /dev/null +++ b/Examples/test-suite/swig_examples_lock.h @@ -0,0 +1,59 @@ + +namespace SwigExamples { + +# if defined(_WIN32) || defined(__WIN32__) + +class CriticalSection { +public: + CriticalSection() { + InitializeCriticalSection(&mutex_); + } + ~CriticalSection() { + DeleteCriticalSection(&mutex_); + } + CRITICAL_SECTION mutex_; +}; + +struct Lock { + Lock(CriticalSection &cs) : critical_section(cs) { + EnterCriticalSection(&critical_section.mutex_); + } + ~Lock() { + LeaveCriticalSection(&critical_section.mutex_); + } +private: + CriticalSection &critical_section; +}; + +#else + +#include +class CriticalSection { +public: + CriticalSection() { + pthread_mutexattr_t mutexattr; + pthread_mutexattr_settype(&mutexattr, PTHREAD_MUTEX_RECURSIVE_NP); + pthread_mutex_init(&mutex_, &mutexattr); + pthread_mutexattr_destroy(&mutexattr); + } + ~CriticalSection() { + pthread_mutex_destroy (&mutex_); + } + pthread_mutex_t mutex_; +}; + +struct Lock { + Lock(CriticalSection &cs) : critical_section(cs) { + pthread_mutex_lock (&critical_section.mutex_); + } + ~Lock() { + pthread_mutex_unlock (&critical_section.mutex_); + } +private: + CriticalSection &critical_section; +}; + +#endif + +} +