123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280 |
- /*##############################################################################
- HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
- 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.
- ############################################################################## */
- #ifndef JIFACE_HPP
- #define JIFACE_HPP
- #include "platform.h"
- #include <string.h>
- #include <atomic>
- #include "jscm.hpp"
- #include "jatomic.hpp"
- void jlib_decl raiseAssertException(const char *assertion, const char *file, unsigned line);
- void jlib_decl raiseAssertCore(const char *assertion, const char *file, unsigned line);
- #undef assert
- #undef assertex
- #if defined(_DEBUG)||defined(_TESTING)
- #define assertex(p) (likely(p) ? ((void) 0) : (( (void) raiseAssertException(#p, __FILE__, __LINE__))))
- #define verifyex(p) (likely(p) ? ((void) 0) : (( (void) raiseAssertException(#p, __FILE__, __LINE__))))
- #else
- #define assertex(p)
- #define verifyex(p) ((void) (p))
- #endif
- #ifdef _DEBUG
- #define dbgassertex(x) assertex(x) //Use for asserts that are highly unlikely to occur, and would likely to be reproduced in debug mode.
- #define assert(p) (likely(p) ? ((void) 0) : (( (void) raiseAssertCore(#p, __FILE__, __LINE__))))
- #define verify(p) (likely(p) ? ((void) 0) : (( (void) raiseAssertCore(#p, __FILE__, __LINE__))))
- #else
- #define dbgassertex(x)
- #define assert(p)
- #define verify(p) ((void) (p))
- #endif
- #define DEAD_PSEUDO_COUNT 0x3fffffff
- class CEmptyClass
- {
- };
- template <class INTERFACE>
- class CInterfaceOf;
- //The simplest implementation of IInterface. Can be used in situations where speed is critical, and
- //there will never be a need for the equivalent of beforeDispose().
- //It is generally recommended to use CInterface for general classes since derived classes may need beforeDispose().
- template <class INTERFACE>
- class CSimpleInterfaceOf : public INTERFACE
- {
- friend class CInterfaceOf<INTERFACE>; // want to keep xxcount private outside this pair of classes
- public:
- inline virtual ~CSimpleInterfaceOf() {}
- inline CSimpleInterfaceOf() : xxcount(1) { }
- inline bool IsShared(void) const { return xxcount.load(std::memory_order_relaxed) > 1; }
- inline int getLinkCount(void) const { return xxcount.load(std::memory_order_relaxed); }
- inline void Link() const { xxcount.fetch_add(1,std::memory_order_relaxed); }
- inline bool Release(void) const
- {
- if (xxcount.fetch_sub(1,std::memory_order_release) == 1)
- {
- std::atomic_thread_fence(std::memory_order_acquire); // Because Herb says so.
- delete this;
- return true;
- }
- return false;
- }
- private:
- CSimpleInterfaceOf(const CSimpleInterfaceOf &) : xxcount(1) {};
- CSimpleInterfaceOf(CSimpleInterfaceOf &&) = delete;
- CSimpleInterfaceOf & operator = (const CSimpleInterfaceOf &) = delete;
- mutable std::atomic<unsigned> xxcount;
- };
- #ifdef _WIN32
- #pragma warning(push)
- #pragma warning(disable : 4251)
- #endif
- template class CSimpleInterfaceOf<CEmptyClass>;
- class jlib_decl CSimpleInterface : public CSimpleInterfaceOf<CEmptyClass>
- {
- public:
- bool Release() const; // Prevent Release() being inlined everwhere it is called
- };
- #ifdef _WIN32
- #pragma warning(pop)
- #endif
- // A more general implementation of IInterface that includes a virtual function beforeDispose().
- // beforeDispose() allows an a fully constructed object to be cleaned up (which means that virtual
- // function calls still work (unlike a virtual destructor).
- // It makes it possible to implement a cache which doesn't link count the object, but is cleared when
- // the object is disposed without a critical section in Release(). (See pattern details below).
- template <class INTERFACE>
- class CInterfaceOf : public CSimpleInterfaceOf<INTERFACE>
- {
- public:
- virtual void beforeDispose() {}
- inline bool isAlive() const { return this->xxcount.load(std::memory_order_relaxed) < DEAD_PSEUDO_COUNT; } //only safe if Link() is called first
- inline bool Release(void) const
- {
- if (this->xxcount.fetch_sub(1,std::memory_order_release) == 1)
- {
- unsigned zero = 0;
- //Because beforeDispose could cause this object to be linked/released or call isAlive(), this->xxcount is set
- //to a a high mid-point positive number to avoid poss. of releasing again.
- if (this->xxcount.compare_exchange_strong(zero, DEAD_PSEUDO_COUNT, std::memory_order_acq_rel))
- {
- try
- {
- const_cast<CInterfaceOf<INTERFACE> *>(this)->beforeDispose();
- }
- catch (...)
- {
- #if _DEBUG
- assert(!"ERROR - Exception in beforeDispose - object will be leaked");
- #endif
- throw;
- }
- delete this;
- return true;
- }
- }
- return false;
- }
- };
- class jlib_decl CInterface : public CInterfaceOf<CEmptyClass>
- {
- public:
- bool Release() const; // Prevent Release() being inlined everwhere it is called
- };
- //---------------------------------------------------------------------------------------------------------------------
- // An implementation of IInterface for objects that are never shared. Only likely to be used in a few situations.
- // It still allows use with IArrayOf and Owned classes etc.
- template <class INTERFACE>
- class CUnsharedInterfaceOf : public INTERFACE
- {
- public:
- inline virtual ~CUnsharedInterfaceOf() {}
- inline CUnsharedInterfaceOf() { }
- inline bool IsShared(void) const { return false; }
- inline int getLinkCount(void) const { return 1; }
- inline void Link() const { assert(!"Unshared::Link"); }
- inline bool Release(void) const
- {
- delete this;
- return true;
- }
- };
- //- Template variants -------------------------------------------------------------------------------------------------
- template <class INTERFACE>
- class CSingleThreadInterfaceOf;
- //An equivalent to CSimpleInterfaceOf that is not thread safe - but avoids the cost of atomic operations.
- template <class INTERFACE>
- class CSingleThreadSimpleInterfaceOf : public INTERFACE
- {
- friend class CSingleThreadInterfaceOf<INTERFACE>; // want to keep xxcount private outside this pair of classes
- public:
- inline virtual ~CSingleThreadSimpleInterfaceOf() {}
- inline CSingleThreadSimpleInterfaceOf() { xxcount = 1; }
- inline bool IsShared(void) const { return xxcount > 1; }
- inline int getLinkCount(void) const { return xxcount; }
- inline void Link() const { ++xxcount; }
- inline bool Release(void) const
- {
- if (--xxcount == 0)
- {
- delete this;
- return true;
- }
- return false;
- }
- private:
- mutable unsigned xxcount;
- };
- //An equivalent to CInterfaceOf that is not thread safe - but avoids the cost of atomic operations.
- template <class INTERFACE>
- class CSingleThreadInterfaceOf : public CSingleThreadSimpleInterfaceOf<INTERFACE>
- {
- public:
- virtual void beforeDispose() {}
- inline bool isAlive() const { return this->xxcount < DEAD_PSEUDO_COUNT; } //only safe if Link() is called first
- inline bool Release(void) const
- {
- if (--this->xxcount == 0)
- {
- //Because beforeDispose could cause this object to be linked/released or call isAlive(), xxcount is set
- //to a a high mid-point positive number to avoid poss. of releasing again.
- this->xxcount = DEAD_PSEUDO_COUNT;
- const_cast<CSingleThreadInterfaceOf<INTERFACE> *>(this)->beforeDispose();
- delete this;
- return true;
- }
- return false;
- }
- };
- /***
- A pattern for implementing a non-linking cached to a shared object. Hash table variants are a slightly more complex variant.
- static CLASS * cache;
- static CriticalSection * cs;
- CLASS * getCached()
- {
- CriticalBlock block(*cs);
- if (cache)
- {
- cache->Link(); // Must link before call to isAlive() to avoid race condition
- if (cache->isAlive())
- return cache;
- //No need for a matching Release since the object is dead and about to be disposed
- }
- //Create an item here if semantics require it. else return NULL;
- cache = new CLASS;
- return cache;
- }
- CLASS::beforeDispose()
- {
- {
- CriticalBlock block(*cs);
- if (cache == this)
- cache = NULL;
- }
- BASECLASS::beforeDispose();
- }
- ****/
- typedef class CInterface * CInterfacePtr;
- #define IMPLEMENT_IINTERFACE_USING(x) \
- virtual void Link(void) const { x::Link(); } \
- virtual bool Release(void) const { return x::Release(); }
- #define IMPLEMENT_IINTERFACE IMPLEMENT_IINTERFACE_USING(CInterface)
- #endif
|