Author: aconway
Date: Mon Aug 20 10:18:52 2007
New Revision: 567755

URL: http://svn.apache.org/viewvc?rev=567755&view=rev
Log:

Fixed Blob bug causing test crashes/hangs.

Added:
    incubator/qpid/trunk/qpid/cpp/src/tests/Blob   (with props)
    incubator/qpid/trunk/qpid/cpp/src/tests/Blob.cpp   (with props)
Modified:
    incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Blob.cpp
    incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Blob.h
    incubator/qpid/trunk/qpid/cpp/src/qpid/framing/MethodHolder.cpp
    incubator/qpid/trunk/qpid/cpp/src/qpid/framing/MethodHolder.h
    incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Blob.cpp
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Blob.cpp?rev=567755&r1=567754&r2=567755&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Blob.cpp (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Blob.cpp Mon Aug 20 10:18:52 
2007
@@ -25,6 +25,7 @@
 namespace framing {
 
 void BlobHelper<void>::destroy(void*) {}
+
 void BlobHelper<void>::copy(void*, const void*) {}
 
 }} // namespace qpid::framing

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Blob.h
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Blob.h?rev=567755&r1=567754&r2=567755&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Blob.h (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/framing/Blob.h Mon Aug 20 10:18:52 
2007
@@ -21,6 +21,7 @@
  *
  */
 
+#include <boost/static_assert.hpp>
 #include <boost/aligned_storage.hpp>
 #include <boost/checked_delete.hpp>
 #include <boost/utility/typed_in_place_factory.hpp>
@@ -80,47 +81,62 @@
  * Objects can be allocated directly in place using
  * construct(in_place<T>(...))  or copied using operator=.
  * Constructing a new object in the blob destroys the old one.
+ *
+ * If BaseType is specified then only object that can be
+ * safely static_cast to BaseType may be stored in the Blob.
  */
-template <size_t Size>
+template <size_t Size, class BaseType=void>
 class Blob
 {
     boost::aligned_storage<Size> store;
+    BaseType* basePtr;
+    
     void (*destroy)(void*);
     void (*copy)(void*, const void*);
 
-    template <class T> void setType() {
+    template <class T>void setType() {
+        BOOST_STATIC_ASSERT(sizeof(T) <= Size);
         destroy=&BlobHelper<T>::destroy;
         copy=&BlobHelper<T>::copy;
+        // Base pointer may be offeset from store.address()
+        basePtr = reinterpret_cast<T*>(store.address());
     }
-    
+        
+    void initialize() {
+        destroy=&BlobHelper<void>::destroy;
+        copy=&BlobHelper<void>::copy;
+        basePtr=0;
+    }
+
     template<class TypedInPlaceFactory>
     void construct (const TypedInPlaceFactory& factory,
                     const boost::typed_in_place_factory_base* )
     {
-        assert(empty());
         typedef typename TypedInPlaceFactory::value_type T;
-        assert(sizeof(T) <= Size);
+        assert(empty());
         factory.apply(store.address());
         setType<T>();
     }
 
     void assign(const Blob& b) {
         assert(empty());
-        b.copy(this->get(), b.get());
+        b.copy(this->store.address(), b.store.address());
         copy = b.copy;
         destroy = b.destroy;
+        basePtr = reinterpret_cast<BaseType*>(
+            ((char*)this)+ ((char*)(b.basePtr) - (char*)(&b)));
     }
-    
+
   public:
     /** Construct an empty blob. */
-    Blob() { setType<void>(); }
+    Blob() { initialize(); }
 
     /** Copy a blob. */
-    Blob(const Blob& b) { setType<void>(); assign(b); }
+    Blob(const Blob& b) { initialize(); assign(b); }
 
     /** @see construct() */
     template<class Expr>
-    Blob( const Expr & expr ) { setType<void>(); construct(expr,&expr); }
+    Blob( const Expr & expr ) { initialize(); construct(expr,&expr); }
 
     ~Blob() { clear(); }
 
@@ -139,30 +155,28 @@
     construct(const Expr& expr) { clear(); construct(expr,&expr); }
 
     /** Copy construct an instance of T into the Blob. */
-    template<class T>
+    template <class T>
     Blob& operator=(const T& x) { clear(); construct(in_place<T>(x)); return 
*this; }
-    
-    /** Get pointer to blob contents. Caller must know how to cast it. */
-    void* get() { return store.address(); }
 
-    /** Get const pointer to blob contents */
-    const void* get() const { return empty() ? 0 : store.address(); }
-    
+    /** Get pointer to blob contents, returns 0 if empty. */
+    BaseType* get() { return  basePtr; }
+
+    /** Get pointer to blob contents, returns 0 if empty. */
+    const BaseType* get() const { return basePtr; }
+
     /** Destroy the object in the blob making it empty. */
     void clear() {
         void (*oldDestroy)(void*) = destroy; 
-        setType<void>();
+        initialize();
         oldDestroy(store.address());
     }
 
-    bool empty() const { return destroy == BlobHelper<void>::destroy; }
+    bool empty() const { return destroy==BlobHelper<void>::destroy; }
     
     static size_t size() { return Size; }
 };
 
-
 }} // namespace qpid::framing
-
 
 
 #endif  /*!QPID_FRAMING_BLOB_H*/

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/framing/MethodHolder.cpp
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/framing/MethodHolder.cpp?rev=567755&r1=567754&r2=567755&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/framing/MethodHolder.cpp (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/framing/MethodHolder.cpp Mon Aug 20 
10:18:52 2007
@@ -32,11 +32,11 @@
 namespace framing {
 
 AMQMethodBody* MethodHolder::get() {
-    return static_cast<AMQMethodBody*>(blob.get());
+    return blob.get();
 }
 
 const AMQMethodBody* MethodHolder::get() const {
-    return const_cast<MethodHolder*>(this)->get();
+    return blob.get();
 }
 
 void MethodHolder::encode(Buffer& b) const {

Modified: incubator/qpid/trunk/qpid/cpp/src/qpid/framing/MethodHolder.h
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/qpid/framing/MethodHolder.h?rev=567755&r1=567754&r2=567755&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/qpid/framing/MethodHolder.h (original)
+++ incubator/qpid/trunk/qpid/cpp/src/qpid/framing/MethodHolder.h Mon Aug 20 
10:18:52 2007
@@ -84,7 +84,7 @@
     bool empty() const { return blob.empty(); }
 
   private:
-    Blob<MAX_METHODBODY_SIZE> blob;
+    Blob<MAX_METHODBODY_SIZE, AMQMethodBody> blob;
     class CopyVisitor;
   friend struct CopyVisitor;
 };

Added: incubator/qpid/trunk/qpid/cpp/src/tests/Blob
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/tests/Blob?rev=567755&view=auto
==============================================================================
Binary file - no diff available.

Propchange: incubator/qpid/trunk/qpid/cpp/src/tests/Blob
------------------------------------------------------------------------------
    svn:executable = *

Propchange: incubator/qpid/trunk/qpid/cpp/src/tests/Blob
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/qpid/trunk/qpid/cpp/src/tests/Blob.cpp
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/tests/Blob.cpp?rev=567755&view=auto
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/tests/Blob.cpp (added)
+++ incubator/qpid/trunk/qpid/cpp/src/tests/Blob.cpp Mon Aug 20 10:18:52 2007
@@ -0,0 +1,125 @@
+/*
+ *
+ * Copyright (c) 2006 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+#include "qpid/framing/Blob.h"
+
+#define BOOST_AUTO_TEST_MAIN
+#include <boost/test/auto_unit_test.hpp>
+
+using namespace std;
+using namespace qpid::framing;
+
+struct Base {
+    int id;
+    int magic;
+
+    Base(int n) : id(n), magic(42) {}
+    Base(const Base& c) : id(c.id), magic(42) {}
+    ~Base() { BOOST_CHECK_EQUAL(42, magic); } // Detect random data. 
+};
+
+template <class T> struct Count : public Base {
+    static int instances;
+    bool destroyed;
+    
+    Count(int n) : Base(n), destroyed(false) { ++instances; }
+    Count(const Count& c) : Base(c), destroyed(false) { ++instances; }
+    ~Count() {
+        BOOST_CHECK(!destroyed); // Detect double-destructor
+        destroyed=true;
+        BOOST_CHECK(--instances >= 0);
+    }
+};
+
+template <class T> int Count<T>::instances = 0;
+
+struct Foo : public Count<Foo> { Foo(int n) : Count<Foo>(n) {}; };
+struct Bar : public Count<Bar> { Bar(int n) : Count<Bar>(n) {}; };
+
+typedef Blob<sizeof(Foo), Base> TestBlob ;
+
+BOOST_AUTO_TEST_CASE(testCtor) {
+    {
+        TestBlob empty;
+        BOOST_CHECK(empty.empty());
+        BOOST_CHECK(empty.get() == 0);
+
+        TestBlob empty2(empty);
+        BOOST_CHECK(empty2.empty());
+
+        TestBlob foo(in_place<Foo>(1));
+        BOOST_CHECK(!foo.empty());
+        BOOST_CHECK_EQUAL(1, foo.get()->id);
+        BOOST_CHECK_EQUAL(1, Foo::instances);
+
+        TestBlob foo2(foo);
+        BOOST_CHECK(!foo2.empty());
+        BOOST_CHECK_EQUAL(1, foo2.get()->id);
+        BOOST_CHECK_EQUAL(2, Foo::instances);
+    }
+    
+    BOOST_CHECK_EQUAL(0, Foo::instances);
+    BOOST_CHECK_EQUAL(0, Bar::instances);
+}
+
+
+BOOST_AUTO_TEST_CASE(testAssign) {
+    {
+        TestBlob b;
+        b = Foo(2);
+        BOOST_CHECK_EQUAL(2, b.get()->id);
+        BOOST_CHECK_EQUAL(1, Foo::instances);
+
+        TestBlob b2(b);
+        BOOST_CHECK_EQUAL(2, b.get()->id);
+        BOOST_CHECK_EQUAL(2, Foo::instances);
+    
+        b2 = Bar(3);
+        BOOST_CHECK_EQUAL(3, b2.get()->id);
+        BOOST_CHECK_EQUAL(1, Foo::instances);
+        BOOST_CHECK_EQUAL(1, Bar::instances);
+
+        b2.construct(in_place<Foo>(4)); 
+        BOOST_CHECK_EQUAL(4, b2.get()->id);
+        BOOST_CHECK_EQUAL(2, Foo::instances);
+        BOOST_CHECK_EQUAL(0, Bar::instances);
+
+        b2.clear();
+        BOOST_CHECK(b2.empty());
+        BOOST_CHECK_EQUAL(1, Foo::instances);
+    }
+    BOOST_CHECK_EQUAL(0, Foo::instances);
+    BOOST_CHECK_EQUAL(0, Bar::instances);
+}
+
+
+BOOST_AUTO_TEST_CASE(testClear) {
+    TestBlob b(in_place<Foo>(5));
+    TestBlob c(b);
+    BOOST_CHECK(!c.empty());
+    BOOST_CHECK(!b.empty());
+    BOOST_CHECK_EQUAL(2, Foo::instances);
+
+    c.clear();
+    BOOST_CHECK(c.empty());
+    BOOST_CHECK_EQUAL(1, Foo::instances);
+
+    b.clear(); 
+    BOOST_CHECK(b.empty());
+    BOOST_CHECK_EQUAL(0, Foo::instances);
+}

Propchange: incubator/qpid/trunk/qpid/cpp/src/tests/Blob.cpp
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: incubator/qpid/trunk/qpid/cpp/src/tests/Blob.cpp
------------------------------------------------------------------------------
    svn:keywords = Rev Date

Modified: incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am
URL: 
http://svn.apache.org/viewvc/incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am?rev=567755&r1=567754&r2=567755&view=diff
==============================================================================
--- incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am (original)
+++ incubator/qpid/trunk/qpid/cpp/src/tests/Makefile.am Mon Aug 20 10:18:52 2007
@@ -19,6 +19,11 @@
 #
 # Unit test programs.
 # 
+TESTS+=Blob
+check_PROGRAMS+=Blob
+Blob_SOURCES=Blob.cpp ../qpid/framing/Blob.cpp
+Blob_LDADD=-lboost_unit_test_framework
+
 TESTS+=logging
 check_PROGRAMS+=logging
 logging_SOURCES=logging.cpp test_tools.h
@@ -120,13 +125,14 @@
 
 TESTS_ENVIRONMENT = VALGRIND=$(VALGRIND) srcdir=$(srcdir) $(srcdir)/run_test
 
-system_tests = client_test exception_test quick_topictest
+system_tests = client_test exception_test quick_perftest quick_topictest
 TESTS += run-unit-tests start_broker $(system_tests) python_tests stop_broker 
 
 EXTRA_DIST +=                                                          \
   test_env run_test vg_check                                           \
   run-unit-tests start_broker python_tests stop_broker                         
\
   quick_topictest                                                      \
+  quick_perftest                                                       \
   topictest                                                            \
   .valgrind.supp-default                                               \
   .valgrindrc-default                                                  \
@@ -171,11 +177,6 @@
        cp $^ $@
 .valgrind.supp: .valgrind.supp-default
        cp $^ $@
-
-# Tell GNU make not to build targets in this directory in parallel.
-# This is necessary because with two or more identical and simultaneous
-# ltmain invocations, one may corrupt the temporaries of the other.
-.NOTPARALLEL:
 
 CLEANFILES+=valgrind.out *.log *.vglog .valgrindrc .valgrind.supp dummy_test 
$(unit_wrappers)
 MAINTAINERCLEANFILES=gen.mk


Reply via email to