Sirikata
libcore/include/sirikata/core/util/SerializationCheck.hpp
Go to the documentation of this file.
00001 /*  Sirikata
00002  *  SerializationCheck.hpp
00003  *
00004  *  Copyright (c) 2009, Ewen Cheslack-Postava
00005  *  All rights reserved.
00006  *
00007  *  Redistribution and use in source and binary forms, with or without
00008  *  modification, are permitted provided that the following conditions are
00009  *  met:
00010  *  * Redistributions of source code must retain the above copyright
00011  *    notice, this list of conditions and the following disclaimer.
00012  *  * Redistributions in binary form must reproduce the above copyright
00013  *    notice, this list of conditions and the following disclaimer in
00014  *    the documentation and/or other materials provided with the
00015  *    distribution.
00016  *  * Neither the name of Sirikata nor the names of its contributors may
00017  *    be used to endorse or promote products derived from this software
00018  *    without specific prior written permission.
00019  *
00020  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
00021  * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
00022  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
00023  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
00024  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
00025  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
00026  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00027  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00028  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00029  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00030  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031  */
00032 
00033 #ifndef _SIRIKATA_SERIALIZATION_CHECK_HPP_
00034 #define _SIRIKATA_SERIALIZATION_CHECK_HPP_
00035 
00036 #include <sirikata/core/util/Platform.hpp>
00037 #include <sirikata/core/util/AtomicTypes.hpp>
00038 
00039 #include <boost/thread/thread.hpp>
00040 
00041 namespace Sirikata {
00042 
00052 class SerializationCheck {
00053 public:
00054     // Used to mark an entire scope as
00055     class Scoped {
00056     public:
00057         Scoped(SerializationCheck* p)
00058          : parent(p)
00059         {
00060             parent->serializedEnter();
00061         }
00062         Scoped(SerializationCheck& p)
00063          : parent(&p)
00064         {
00065             parent->serializedEnter();
00066         }
00067 
00068         ~Scoped() {
00069             parent->serializedExit();
00070         }
00071     private:
00072         Scoped();
00073         Scoped(Scoped& rhs);
00074         Scoped& operator=(Scoped& rhs);
00075 
00076         SerializationCheck* parent;
00077     };
00078 
00079 
00080 
00081     SerializationCheck()
00082 #if SIRIKATA_DEBUG
00083      : mAccessors(0),
00084        mThreadID()
00085 #endif //SIRIKATA_DEBUG
00086     {
00087     }
00088 
00089     inline void serializedEnter() const {
00090 #if SIRIKATA_DEBUG
00091         int32 val = ++mAccessors;
00092 
00093         assert(val >= 1);
00094 
00095         if (val == 1) {
00096             // We're the first ones in here, we need to setup the thread id
00097             mThreadID = boost::this_thread::get_id();
00098         }
00099         else {
00100             // We got in here later on.  This is only valid if we were in the
00101             // same thread, so the thread had better already be marked and
00102             // match ours
00103             assert(mThreadID == boost::this_thread::get_id());
00104         }
00105 #endif //SIRIKATA_DEBUG
00106     }
00107 
00108     inline void serializedExit() const {
00109 #if SIRIKATA_DEBUG
00110         int32 val = --mAccessors;
00111         assert(val >= 0);
00112         if (val == (int32)0) {
00113             // We should be the only one left accessing this and a
00114             // serializedEnter should *not* be getting called, so we
00115             // can erase the thread ID now.
00116             mThreadID = boost::thread::id();
00117         }
00118 #endif //SIRIKATA_DEBUG
00119     }
00120 private:
00121 #if SIRIKATA_DEBUG
00122     // Implementation Note: Technically this isn't all thread safe.  However,
00123     // the core component which tracks the number of accessors and their order
00124     // off access is thread safe. Any thread-unsafe accesses should only result
00125     // in a bad comparison, which should result in an assertion anyway since the
00126     // whole point of this class is to verify that multiple threads are not trying
00127     // to access shared data (including this object) at the same time.
00128     mutable AtomicValue<int32> mAccessors;
00129     mutable boost::thread::id mThreadID;
00130 #endif //SIRIKATA_DEBUG
00131 };
00132 
00133 } // namespace Sirikata
00134 
00135 #endif //_SIRIKATA_SERIALIZATION_CHECK_HPP_