From 9f187b46ae761e8275362d6c1533e9fe79028c7b Mon Sep 17 00:00:00 2001 From: jsdelfino Date: Sun, 1 Nov 2009 05:24:54 +0000 Subject: Improved memory management using APR memory pools, changed frame allocation in eval library to support forward references and fixed memory leak in XML parsing code. Also simplified a bit the printing of lists to make them easier to read. git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@831639 13f79535-47bb-0310-9956-ffa450edef68 --- cpp/sca/kernel/Makefile.am | 6 +- cpp/sca/kernel/element.hpp | 6 +- cpp/sca/kernel/function.hpp | 22 ++++--- cpp/sca/kernel/gc.hpp | 135 +++++++++++++++++++++++++++++++++++++++++ cpp/sca/kernel/kernel-test.cpp | 12 +++- cpp/sca/kernel/list.hpp | 29 ++++++++- cpp/sca/kernel/value.hpp | 108 ++++++++++++++++++++++++++------- cpp/sca/kernel/xml.hpp | 38 ++++++++---- 8 files changed, 303 insertions(+), 53 deletions(-) (limited to 'cpp/sca/kernel') diff --git a/cpp/sca/kernel/Makefile.am b/cpp/sca/kernel/Makefile.am index d3caa16b3b..0bbfa195c7 100644 --- a/cpp/sca/kernel/Makefile.am +++ b/cpp/sca/kernel/Makefile.am @@ -19,13 +19,13 @@ noinst_PROGRAMS = kernel-test xsd-test nobase_include_HEADERS = *.hpp -INCLUDES = -I. -I$(top_builddir)/kernel -I${LIBXML2_INCLUDE} +INCLUDES = -I. -I$(top_builddir)/kernel -I${LIBXML2_INCLUDE} -I${APR_INCLUDE} kernel_test_SOURCES = kernel-test.cpp -kernel_test_LDADD = -lpthread -L${LIBXML2_LIB} -lxml2 +kernel_test_LDADD = -lpthread -L${LIBXML2_LIB} -lxml2 -L${APR_LIB} -lapr-1 -laprutil-1 xsd_test_SOURCES = xsd-test.cpp -xsd_test_LDADD = -lpthread -L${LIBXML2_LIB} -lxml2 +xsd_test_LDADD = -lpthread -L${LIBXML2_LIB} -lxml2 -L${APR_LIB} -lapr-1 -laprutil-1 TESTS = kernel-test diff --git a/cpp/sca/kernel/element.hpp b/cpp/sca/kernel/element.hpp index af221f849b..d93e90742b 100644 --- a/cpp/sca/kernel/element.hpp +++ b/cpp/sca/kernel/element.hpp @@ -219,19 +219,19 @@ struct selectorLambda { const list select; selectorLambda(const list& s) : select(s) { } - const bool evalApply(const list& s, const list v) const { + const bool evalExpr(const list& s, const list v) const { if (isNil(s)) return true; if (isNil(v)) return false; if (car(s) != car(v)) return false; - return evalApply(cdr(s), cdr(v)); + return evalExpr(cdr(s), cdr(v)); } const bool operator()(const value& v) const { if (!isList(v)) return false; - return evalApply(select, v); + return evalExpr(select, v); } }; diff --git a/cpp/sca/kernel/function.hpp b/cpp/sca/kernel/function.hpp index 9492879e5e..c99ee5dbad 100644 --- a/cpp/sca/kernel/function.hpp +++ b/cpp/sca/kernel/function.hpp @@ -64,8 +64,6 @@ bool printLambdaCounters() { template class Callable { public: - unsigned int refCount; - Callable() : refCount(0) { } @@ -76,14 +74,6 @@ public: virtual ~Callable() { } - unsigned int acquire() { - return __sync_add_and_fetch(&refCount, 1); - } - - unsigned int release() { - return __sync_sub_and_fetch(&refCount, 1); - } - template class Proxy: public Callable { public: Proxy(const F& f) : function(f) { @@ -112,6 +102,18 @@ public: const F function; }; +private: + friend class gc_counting_ptr; + + unsigned int refCount; + + unsigned int acquire() { + return __sync_add_and_fetch(&refCount, 1); + } + + unsigned int release() { + return __sync_sub_and_fetch(&refCount, 1); + } }; template class lambda; diff --git a/cpp/sca/kernel/gc.hpp b/cpp/sca/kernel/gc.hpp index 0d292f6194..7739e714c2 100644 --- a/cpp/sca/kernel/gc.hpp +++ b/cpp/sca/kernel/gc.hpp @@ -26,6 +26,8 @@ * Garbage collected pointer. */ +#include +#include #include namespace tuscany @@ -265,5 +267,138 @@ template std::ostream& operator<<(std::ostream& out, const gc_counti return out << p.ptr; } +/** + * Apache Portable Runtime library context + */ +class APRContext { +public: + APRContext() { + apr_initialize(); + } + ~APRContext() { + apr_terminate(); + } +}; + +APRContext aprContext; + +/** + * Garbage collected memory pool, using an APR pool. + */ +class gc_pool { +public: + gc_pool() : aprPool(new APRPool) { + } + + operator apr_pool_t*() const { + return aprPool->p; + } + +private: + class APRPool { + friend class gc_pool; + friend class gc_counting_ptr; + + unsigned int refCount; + apr_pool_t* p; + + APRPool() : refCount(0) { + apr_pool_create(&p, NULL); + } + + ~APRPool() { + apr_pool_destroy(p); + } + + unsigned int acquire() { + return __sync_add_and_fetch(&refCount, 1); + } + + unsigned int release() { + return __sync_sub_and_fetch(&refCount, 1); + } + }; + + const gc_counting_ptr aprPool; +}; + +/** + * Garbage collected pointer to pooled memory. + */ +template class gc_pool_ptr { +public: + gc_pool_ptr(T* ptr = 0) throw() : ptr(ptr) { + } + + ~gc_pool_ptr() throw() { + } + + gc_pool_ptr(const gc_pool_ptr& r) throw() : ptr(r.ptr) { + } + + gc_pool_ptr& operator=(const gc_pool_ptr& r) throw() { + if(this == &r) + return *this; + ptr = r.ptr; + return *this; + } + + const bool operator==(const gc_pool_ptr& r) const throw() { + if (this == &r) + return true; + return ptr == r.ptr; + } + + const bool operator!=(const gc_pool_ptr& r) const throw() { + return !this->operator ==(r); + } + + T& operator*() const throw() { + return *ptr; + } + + T* operator->() const throw() { + return ptr; + } + + operator T*() const throw() { + return ptr; + } + + template friend std::ostream& operator<<(std::ostream&, const gc_pool_ptr&); + +private: + T* ptr; +}; + +template std::ostream& operator<<(std::ostream& out, const gc_pool_ptr& p) { + return out << p.ptr; +} + +/** + * Cleanup function, called by the APR pool to cleanup registered resources. + * Calls the allocated object's destructor. + */ +template apr_status_t gc_pool_cleanupCallback(void* v) { + T* t = static_cast(v); + t->~T(); + return APR_SUCCESS; +} + +/** + * Returns a pointer to an object allocated from a memory pool. + */ +template gc_pool_ptr gc_pool_new(const gc_pool& mp) { + + // Allocate memory from the pool + void* m = apr_palloc(mp, sizeof(T)); + + // Register a cleanup callback + apr_pool_cleanup_register(mp, m, gc_pool_cleanupCallback, apr_pool_cleanup_null) ; + + // Run the requested type's constructor over the allocated memory + return new (m) T(); +} + } #endif /* tuscany_gc_hpp */ diff --git a/cpp/sca/kernel/kernel-test.cpp b/cpp/sca/kernel/kernel-test.cpp index 9f977a64f9..0234f6eb3e 100644 --- a/cpp/sca/kernel/kernel-test.cpp +++ b/cpp/sca/kernel/kernel-test.cpp @@ -152,7 +152,7 @@ bool testOut() { std::ostringstream os2; os2 << mklist(1, 2, 3); - assert(os2.str() == "(1, 2, 3)"); + assert(os2.str() == "(1 2 3)"); return true; } @@ -334,6 +334,14 @@ bool testValue() { const list v = mklist(mklist("x", "X"), mklist("a", "A"), mklist("y", "Y")); assert(cadr((list >)value(v)) == mklist("a", "A")); + + const value pv(gc_ptr(new value(1))); + assert(*(gc_ptr)pv == value(1)); + + const list lpv = mklist(gc_ptr(new value(1)), gc_ptr(new value(2))); + assert(*(gc_ptr)car(lpv) == value(1)); + *(gc_ptr)cadr(lpv) = value(3); + assert(*(gc_ptr)cadr(lpv) == value(3)); return true; } @@ -521,7 +529,7 @@ bool testReadXML() { return true; } -std::ostringstream* xmlWriter(std::ostringstream* os, const std::string& s) { +std::ostringstream* xmlWriter(const std::string& s, std::ostringstream* os) { (*os) << s; return os; } diff --git a/cpp/sca/kernel/list.hpp b/cpp/sca/kernel/list.hpp index 62c5d91150..deb4414d98 100644 --- a/cpp/sca/kernel/list.hpp +++ b/cpp/sca/kernel/list.hpp @@ -144,7 +144,7 @@ template std::ostream& operator<<(std::ostream& out, const list& ml = cdr(ml); if (isNil(ml)) break; - out << ", "; + out << " "; } return out << ")"; } @@ -163,6 +163,17 @@ template const list cons(const T& car, const list& cdr) { return list (car, result(cdr)); } +/** + * Cons variations for use with the reduce and reduceRight functions. + */ +template const list lcons(const list& cdr, const T& car) { + return cons(car, cdr); +} + +template const list rcons(const T& car, const list& cdr) { + return cons(car, cdr); +} + /** * Construct a list from a single value. */ @@ -350,6 +361,22 @@ template const R reduce(const lambda& f, const return reduceAccumulate (f)(initial, p); } +template struct reduceRightAccumulate { + const lambda f; + reduceRightAccumulate(const lambda& f) : + f(f) { + } + R operator()(const list& p, const R& acc) const { + if(isNil(p)) + return acc; + return (*this)(cdr(p), f(car(p), acc)); + } +}; + +template const R reduceRight(const lambda& f, const R& initial, const list& p) { + return reduceRightAccumulate (f)(p, initial); +} + /** * Run a filter lambda function on a list. */ diff --git a/cpp/sca/kernel/value.hpp b/cpp/sca/kernel/value.hpp index d57264ff43..618bd7b622 100644 --- a/cpp/sca/kernel/value.hpp +++ b/cpp/sca/kernel/value.hpp @@ -60,7 +60,7 @@ class value { public: enum ValueType { - Undefined, Symbol, String, List, Number, Boolean, Character, Lambda + Undefined, Symbol, String, List, Number, Bool, Char, Lambda, Ptr, PoolPtr }; value() : @@ -84,10 +84,14 @@ public: str() = v.str(); case value::Number: num() = v.num(); - case value::Boolean: + case value::Bool: boo() = v.boo(); - case value::Character: + case value::Char: chr() = v.chr(); + case value::Ptr: + ptr() = v.ptr(); + case value::PoolPtr: + poolptr() = v.poolptr(); default: break; } @@ -108,10 +112,14 @@ public: str() = v.str(); case value::Number: num() = v.num(); - case value::Boolean: + case value::Bool: boo() = v.boo(); - case value::Character: + case value::Char: chr() = v.chr(); + case value::Ptr: + ptr() = v.ptr(); + case value::PoolPtr: + poolptr() = v.poolptr(); default: break; } @@ -165,13 +173,25 @@ public: } value(const bool boo) : - type(value::Boolean), data(vdata(result(boo))) { + type(value::Bool), data(vdata(result(boo))) { countValues++; countVValues++; } value(const char chr) : - type(value::Character), data(vdata(result(chr))) { + type(value::Char), data(vdata(result(chr))) { + countValues++; + countVValues++; + } + + value(const gc_ptr ptr) : + type(value::Ptr), data(vdata(result(ptr))) { + countValues++; + countVValues++; + } + + value(const gc_pool_ptr ptr) : + type(value::PoolPtr), data(vdata(result(ptr))) { countValues++; countVValues++; } @@ -198,10 +218,14 @@ public: return str()() == v.str()(); case value::Number: return num()() == v.num()(); - case value::Boolean: + case value::Bool: return boo()() == v.boo()(); - case value::Character: + case value::Char: return chr()() == v.chr()(); + case value::Ptr: + return ptr()() == v.ptr()(); + case value::PoolPtr: + return poolptr()() == v.poolptr()(); default: return false; } @@ -215,6 +239,8 @@ public: switch(type) { case value::List: case value::Lambda: + case value::Ptr: + case value::PoolPtr: return ""; case value::Symbol: case value::String: @@ -224,13 +250,13 @@ public: sos << num()(); return sos.str(); } - case value::Boolean: { + case value::Bool: { if(boo()()) return "true"; else return "false"; } - case value::Character: { + case value::Char: { std::ostringstream sos; sos << chr()(); return sos.str(); @@ -256,6 +282,14 @@ public: return chr()(); } + operator const gc_ptr() const { + return ptr()(); + } + + operator const gc_pool_ptr() const { + return poolptr()(); + } + operator const list() const { return lst()(); } @@ -294,6 +328,14 @@ private: return vdata (); } + lambda()>& ptr() const { + return vdata()> (); + } + + lambda()>& poolptr() const { + return vdata()> (); + } + lambda& str() const { return vdata (); } @@ -328,18 +370,30 @@ std::ostream& operator<<(std::ostream& out, const value& v) { case value::Lambda: return out << "lambda::" << v.func(); case value::Symbol: - return out << "symbol::" << v.str()(); + return out << v.str()(); case value::String: - return out << "string::" << '\"' << v.str()() << '\"'; + return out << '\"' << v.str()() << '\"'; case value::Number: - return out << "number::" << v.num()(); - case value::Boolean: + return out << v.num()(); + case value::Bool: if(v.boo()()) - return out << "bool::" << "true"; + return out << "true"; else - return out << "bool::" << "false"; - case value::Character: - return out << "char::" << v.chr()(); + return out << "false"; + case value::Char: + return out << v.chr()(); + case value::Ptr: { + const gc_ptr p = v.ptr()(); + if (p == gc_ptr(NULL)) + return out << "pointer::null"; + return out << "pointer::" << *p; + } + case value::PoolPtr: { + const gc_pool_ptr p = v.poolptr()(); + if (p == gc_pool_ptr(NULL)) + return out << "pointer::null"; + return out << "pointer::" << *p; + } default: return out << "undefined"; } @@ -369,12 +423,20 @@ const bool isNumber(const value& value) { return value.type == value::Number; } -const bool isBoolean(const value& value) { - return value.type == value::Boolean; +const bool isBool(const value& value) { + return value.type == value::Bool; +} + +const bool isChar(const value& value) { + return value.type == value::Char; +} + +const bool isPtr(const value& value) { + return value.type == value::Ptr; } -const bool isCharacter(const value& value) { - return value.type == value::Character; +const bool isPoolPtr(const value& value) { + return value.type == value::PoolPtr; } const bool isTaggedList(const value& exp, value tag) { diff --git a/cpp/sca/kernel/xml.hpp b/cpp/sca/kernel/xml.hpp index afc3f5cc38..b7611b8477 100644 --- a/cpp/sca/kernel/xml.hpp +++ b/cpp/sca/kernel/xml.hpp @@ -39,6 +39,22 @@ namespace tuscany { +/** + * Initializes the libxml2 library. + */ +class XMLParser { +public: + XMLParser() { + xmlInitParser(); + } + + ~XMLParser() { + xmlCleanupParser(); + } +}; + +XMLParser xmlParser; + /** * Encapsulates a libxml2 xmlTextReader and its state. */ @@ -54,6 +70,7 @@ public: } ~XMLReader() { + xmlTextReaderClose(xml); xmlFreeTextReader(xml); } @@ -298,9 +315,9 @@ const failable write(const list& l, const xmlTextWrite */ template class XMLWriteContext { public: - XMLWriteContext(const lambda& reduce, const R& accum) : reduce(reduce), accum(accum) { + XMLWriteContext(const lambda& reduce, const R& accum) : reduce(reduce), accum(accum) { } - const lambda reduce; + const lambda reduce; R accum; }; @@ -309,36 +326,35 @@ public: */ template int writeCallback(void *context, const char* buffer, int len) { XMLWriteContext& cx = *static_cast*>(context); - cx.accum = cx.reduce(cx.accum, std::string(buffer, len)); + cx.accum = cx.reduce(std::string(buffer, len), cx.accum); return len; } /** * Convert a list of values to an XML document. */ -template const failable writeXML(const lambda& reduce, const R& initial, const list& l) { +template const failable writeXML(const lambda& reduce, const R& initial, const list& l) { XMLWriteContext cx(reduce, initial); xmlOutputBufferPtr out = xmlOutputBufferCreateIO(writeCallback, NULL, &cx, NULL); + if (out == NULL) + return std::string("xmlOutputBufferCreateIO failed"); xmlTextWriterPtr xml = xmlNewTextWriter(out); if (xml == NULL) return std::string("xmlNewTextWriter failed"); const failable w = write(l, xml); - if (!hasValue(w)) + xmlFreeTextWriter(xml); + if (!hasValue(w)) { return std::string(w); - + } return cx.accum; } /** * Convert a list of values to a list of strings representing an XML document. */ -const list writeXMLList(const list& listSoFar, const std::string& s) { - return cons(s, listSoFar); -} - const failable, std::string> writeXML(const list& l) { - const failable, std::string> ls = writeXML >(writeXMLList, list(), l); + const failable, std::string> ls = writeXML >(rcons, list(), l); if (!hasValue(ls)) return ls; return reverse(list(ls)); -- cgit v1.2.3