Discussion area about developing or extending OGRE, adding plugins for it or building applications on it. No newbie questions please, use the Help forum for that.
I think that a lot of these classes that extend SharedPtr and add only the ability to do implicit downcasts between ResourcePtr and derived resource classes should be removed in favour of something like this.
moreover, for processing reference counter it is possible to use a AtomicScalar class http://www.ogre3d.org/docs/api/html/cla ... calar.html
But I don't like its current implementation. In our project interlocked functions implemented by us under Win (Win32 API) and Linux (gcc extension). In Intel TBB there is an example of quite good implementation.
I actually wrote that class I intended it to be used in the Ogre::SharedPtr but I punted that because the code was such a mess and it was much less of a hit on performance than the resource loading stuff (which was hit many more times every pass).
#if !defined(__INTERLOCKED_11_05_2012_H__)
#define __INTERLOCKED_11_05_2012_H__
#if defined(__GNUC__)
#if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2))
#include <ext/atomicity.h>
#elif defined __LCC__
#include "asm/e2k_api.h"
#else
#include <bits/atomicity.h>
#endif
#endif
////////////////////////////////////////////////////////////
////Experimental////////////////////////////////////////////
/// New atomic increment, decrement, addvalue, setvalue, getvalue functions.
/// The functions prevents more than one thread from using the same variable simultaneously.
///
namespace bm
{
#ifdef WIN32
/// The atomicIncrement function increments (increases by one) the value of the specified 32-bit variable
/// and checks the resulting value.
/// The function returns the resulting incremented value.
inline int atomicIncrement(int volatile* addend) { return InterlockedIncrement(reinterpret_cast<long volatile*>(addend)); }
/// The atomicDecrement function decrements (decreases by one) the value of the specified 32-bit variable
/// and checks the resulting value.
/// The function returns the resulting decremented value.
inline int atomicDecrement(int volatile* addend) { return InterlockedDecrement(reinterpret_cast<long volatile*>(addend)); }
/// The atomicAddValue function performs an atomic addition of a 32-bit increment value to a 32-bit addend variable.
/// The function returns the initial value of the addend parameter.
inline int atomicAddValue(int volatile* addend, int value) { return InterlockedExchangeAdd(reinterpret_cast<long volatile*>(addend), value);}
/// The atomicSetValue function atomically exchanges a pair of 32-bit values.
/// The function returns the initial value of the target.
inline int atomicSetValue(int volatile* target, int value) { return InterlockedExchange(reinterpret_cast<long volatile*>(target), value);}
#elif defined __LCC__
inline int atomicIncrement(int volatile* addend) { return __api_atomic32_add(1, addend); }
inline int atomicDecrement(int volatile* addend) { return __api_atomic32_sub(1, addend); }
inline int atomicAddValue(int volatile* addend, int value) { return __api_atomic32_add(value, addend) - value; }
inline int atomicSetValue(int volatile* target, int value) { return __api_xchg32_return(value, target);}
#else
/// The atomicIncrement function increments (increases by one) the value of the specified 32-bit variable
/// and checks the resulting value.
/// The function returns the resulting incremented value.
inline int atomicIncrement(int volatile* addend) { return __gnu_cxx::__exchange_and_add(addend, 1) + 1; }
/// The atomicDecrement function decrements (decreases by one) the value of the specified 32-bit variable
/// and checks the resulting value.
/// The function returns the resulting decremented value.
inline int atomicDecrement(int volatile* addend) { return __gnu_cxx::__exchange_and_add(addend, -1) - 1; }
/// The atomicAddValue function performs an atomic addition of a 32-bit increment value to a 32-bit addend variable.
/// The function returns the initial value of the addend parameter.
inline int atomicAddValue(int volatile* addend, int value) {return __gnu_cxx::__exchange_and_add(addend, value);}
/// The atomicSetValue function atomically exchanges a pair of 32-bit values.
/// The function returns the initial value of the target.
int atomic_exchange( int volatile* pw, int dv );
inline int atomicSetValue(int volatile* addend, int value) {return atomic_exchange(addend, -value);}
/// аналоги на assebler-e
///
inline int atomic_exchange( int volatile* pw, int dv )
{
// int r = *pw;
// *pw = dv;
// return r;
int r;
__asm__ __volatile__
(
"lock\n\t"
"xchg %1, %0":
"=m"( *pw ), "=r"( r ): // outputs (%0, %1)
"m"( *pw ), "1"( dv ): // inputs (%2, %3 == %1)
"memory", "cc" // clobbers
);
return r;
}
///
inline int atomic_exchange_and_add( int * pw, int dv )
{
// int r = *pw;
// *pw += dv;
// return r;
int r;
__asm__ __volatile__
(
"lock\n\t"
"xadd %1, %0":
"=m"( *pw ), "=r"( r ): // outputs (%0, %1)
"m"( *pw ), "1"( dv ): // inputs (%2, %3 == %1)
"memory", "cc" // clobbers
);
return r;
}
///
inline void atomic_increment( int * pw )
{
//atomic_exchange_and_add( pw, 1 );
__asm__ __volatile__
(
"lock\n\t"
"incl %0":
"=m"( *pw ): // output (%0)
"m"( *pw ): // input (%1)
"cc" // clobbers
);
}
///
inline void atomic_decrement( int * pw )
{
//atomic_exchange_and_add( pw, -1 );
__asm__ __volatile__
(
"lock\n\t"
"decl %0":
"=m"( *pw ): // output (%0)
"m"( *pw ): // input (%1)
"cc" // clobbers
);
}
#endif
/// The atomicGetValue function atomically returns the current 32-bit value of the target.
inline int atomicGetValue(int const volatile* target) { return static_cast<int const volatile &>(*target); }
}
///
////////////////////////////////////////////////////////////
#endif // #if !defined(__INTERLOCKED_11_05_2012_H__)
Well ogre has to handle the case where the compiler or system isn't recognised and uses locks in this case. That makes it a lot more complicated. Also Ogre handles more types than just int.