jiface.hpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280
  1. /*##############################################################################
  2. HPCC SYSTEMS software Copyright (C) 2012 HPCC Systems®.
  3. Licensed under the Apache License, Version 2.0 (the "License");
  4. you may not use this file except in compliance with the License.
  5. You may obtain a copy of the License at
  6. http://www.apache.org/licenses/LICENSE-2.0
  7. Unless required by applicable law or agreed to in writing, software
  8. distributed under the License is distributed on an "AS IS" BASIS,
  9. WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  10. See the License for the specific language governing permissions and
  11. limitations under the License.
  12. ############################################################################## */
  13. #ifndef JIFACE_HPP
  14. #define JIFACE_HPP
  15. #include "platform.h"
  16. #include <string.h>
  17. #include <atomic>
  18. #include "jscm.hpp"
  19. #include "jatomic.hpp"
  20. void jlib_decl raiseAssertException(const char *assertion, const char *file, unsigned line);
  21. void jlib_decl raiseAssertCore(const char *assertion, const char *file, unsigned line);
  22. #undef assert
  23. #undef assertex
  24. #if defined(_DEBUG)||defined(_TESTING)
  25. #define assertex(p) (likely(p) ? ((void) 0) : (( (void) raiseAssertException(#p, __FILE__, __LINE__))))
  26. #define verifyex(p) (likely(p) ? ((void) 0) : (( (void) raiseAssertException(#p, __FILE__, __LINE__))))
  27. #else
  28. #define assertex(p)
  29. #define verifyex(p) ((void) (p))
  30. #endif
  31. #ifdef _DEBUG
  32. #define dbgassertex(x) assertex(x) //Use for asserts that are highly unlikely to occur, and would likely to be reproduced in debug mode.
  33. #define assert(p) (likely(p) ? ((void) 0) : (( (void) raiseAssertCore(#p, __FILE__, __LINE__))))
  34. #define verify(p) (likely(p) ? ((void) 0) : (( (void) raiseAssertCore(#p, __FILE__, __LINE__))))
  35. #else
  36. #define dbgassertex(x)
  37. #define assert(p)
  38. #define verify(p) ((void) (p))
  39. #endif
  40. #define DEAD_PSEUDO_COUNT 0x3fffffff
  41. class CEmptyClass
  42. {
  43. };
  44. template <class INTERFACE>
  45. class CInterfaceOf;
  46. //The simplest implementation of IInterface. Can be used in situations where speed is critical, and
  47. //there will never be a need for the equivalent of beforeDispose().
  48. //It is generally recommended to use CInterface for general classes since derived classes may need beforeDispose().
  49. template <class INTERFACE>
  50. class CSimpleInterfaceOf : public INTERFACE
  51. {
  52. friend class CInterfaceOf<INTERFACE>; // want to keep xxcount private outside this pair of classes
  53. public:
  54. inline virtual ~CSimpleInterfaceOf() {}
  55. inline CSimpleInterfaceOf() : xxcount(1) { }
  56. inline bool IsShared(void) const { return xxcount.load(std::memory_order_relaxed) > 1; }
  57. inline int getLinkCount(void) const { return xxcount.load(std::memory_order_relaxed); }
  58. inline void Link() const { xxcount.fetch_add(1,std::memory_order_relaxed); }
  59. inline bool Release(void) const
  60. {
  61. if (xxcount.fetch_sub(1,std::memory_order_release) == 1)
  62. {
  63. std::atomic_thread_fence(std::memory_order_acquire); // Because Herb says so.
  64. delete this;
  65. return true;
  66. }
  67. return false;
  68. }
  69. private:
  70. CSimpleInterfaceOf(const CSimpleInterfaceOf &) : xxcount(1) {};
  71. CSimpleInterfaceOf(CSimpleInterfaceOf &&) = delete;
  72. CSimpleInterfaceOf & operator = (const CSimpleInterfaceOf &) = delete;
  73. mutable std::atomic<unsigned> xxcount;
  74. };
  75. #ifdef _WIN32
  76. #pragma warning(push)
  77. #pragma warning(disable : 4251)
  78. #endif
  79. template class CSimpleInterfaceOf<CEmptyClass>;
  80. class jlib_decl CSimpleInterface : public CSimpleInterfaceOf<CEmptyClass>
  81. {
  82. public:
  83. bool Release() const; // Prevent Release() being inlined everwhere it is called
  84. };
  85. #ifdef _WIN32
  86. #pragma warning(pop)
  87. #endif
  88. // A more general implementation of IInterface that includes a virtual function beforeDispose().
  89. // beforeDispose() allows an a fully constructed object to be cleaned up (which means that virtual
  90. // function calls still work (unlike a virtual destructor).
  91. // It makes it possible to implement a cache which doesn't link count the object, but is cleared when
  92. // the object is disposed without a critical section in Release(). (See pattern details below).
  93. template <class INTERFACE>
  94. class CInterfaceOf : public CSimpleInterfaceOf<INTERFACE>
  95. {
  96. public:
  97. virtual void beforeDispose() {}
  98. inline bool isAlive() const { return this->xxcount.load(std::memory_order_relaxed) < DEAD_PSEUDO_COUNT; } //only safe if Link() is called first
  99. inline bool Release(void) const
  100. {
  101. if (this->xxcount.fetch_sub(1,std::memory_order_release) == 1)
  102. {
  103. unsigned zero = 0;
  104. //Because beforeDispose could cause this object to be linked/released or call isAlive(), this->xxcount is set
  105. //to a a high mid-point positive number to avoid poss. of releasing again.
  106. if (this->xxcount.compare_exchange_strong(zero, DEAD_PSEUDO_COUNT, std::memory_order_acq_rel))
  107. {
  108. try
  109. {
  110. const_cast<CInterfaceOf<INTERFACE> *>(this)->beforeDispose();
  111. }
  112. catch (...)
  113. {
  114. #if _DEBUG
  115. assert(!"ERROR - Exception in beforeDispose - object will be leaked");
  116. #endif
  117. throw;
  118. }
  119. delete this;
  120. return true;
  121. }
  122. }
  123. return false;
  124. }
  125. };
  126. class jlib_decl CInterface : public CInterfaceOf<CEmptyClass>
  127. {
  128. public:
  129. bool Release() const; // Prevent Release() being inlined everwhere it is called
  130. };
  131. //---------------------------------------------------------------------------------------------------------------------
  132. // An implementation of IInterface for objects that are never shared. Only likely to be used in a few situations.
  133. // It still allows use with IArrayOf and Owned classes etc.
  134. template <class INTERFACE>
  135. class CUnsharedInterfaceOf : public INTERFACE
  136. {
  137. public:
  138. inline virtual ~CUnsharedInterfaceOf() {}
  139. inline CUnsharedInterfaceOf() { }
  140. inline bool IsShared(void) const { return false; }
  141. inline int getLinkCount(void) const { return 1; }
  142. inline void Link() const { assert(!"Unshared::Link"); }
  143. inline bool Release(void) const
  144. {
  145. delete this;
  146. return true;
  147. }
  148. };
  149. //- Template variants -------------------------------------------------------------------------------------------------
  150. template <class INTERFACE>
  151. class CSingleThreadInterfaceOf;
  152. //An equivalent to CSimpleInterfaceOf that is not thread safe - but avoids the cost of atomic operations.
  153. template <class INTERFACE>
  154. class CSingleThreadSimpleInterfaceOf : public INTERFACE
  155. {
  156. friend class CSingleThreadInterfaceOf<INTERFACE>; // want to keep xxcount private outside this pair of classes
  157. public:
  158. inline virtual ~CSingleThreadSimpleInterfaceOf() {}
  159. inline CSingleThreadSimpleInterfaceOf() { xxcount = 1; }
  160. inline bool IsShared(void) const { return xxcount > 1; }
  161. inline int getLinkCount(void) const { return xxcount; }
  162. inline void Link() const { ++xxcount; }
  163. inline bool Release(void) const
  164. {
  165. if (--xxcount == 0)
  166. {
  167. delete this;
  168. return true;
  169. }
  170. return false;
  171. }
  172. private:
  173. mutable unsigned xxcount;
  174. };
  175. //An equivalent to CInterfaceOf that is not thread safe - but avoids the cost of atomic operations.
  176. template <class INTERFACE>
  177. class CSingleThreadInterfaceOf : public CSingleThreadSimpleInterfaceOf<INTERFACE>
  178. {
  179. public:
  180. virtual void beforeDispose() {}
  181. inline bool isAlive() const { return this->xxcount < DEAD_PSEUDO_COUNT; } //only safe if Link() is called first
  182. inline bool Release(void) const
  183. {
  184. if (--this->xxcount == 0)
  185. {
  186. //Because beforeDispose could cause this object to be linked/released or call isAlive(), xxcount is set
  187. //to a a high mid-point positive number to avoid poss. of releasing again.
  188. this->xxcount = DEAD_PSEUDO_COUNT;
  189. const_cast<CSingleThreadInterfaceOf<INTERFACE> *>(this)->beforeDispose();
  190. delete this;
  191. return true;
  192. }
  193. return false;
  194. }
  195. };
  196. /***
  197. A pattern for implementing a non-linking cached to a shared object. Hash table variants are a slightly more complex variant.
  198. static CLASS * cache;
  199. static CriticalSection * cs;
  200. CLASS * getCached()
  201. {
  202. CriticalBlock block(*cs);
  203. if (cache)
  204. {
  205. cache->Link(); // Must link before call to isAlive() to avoid race condition
  206. if (cache->isAlive())
  207. return cache;
  208. //No need for a matching Release since the object is dead and about to be disposed
  209. }
  210. //Create an item here if semantics require it. else return NULL;
  211. cache = new CLASS;
  212. return cache;
  213. }
  214. CLASS::beforeDispose()
  215. {
  216. {
  217. CriticalBlock block(*cs);
  218. if (cache == this)
  219. cache = NULL;
  220. }
  221. BASECLASS::beforeDispose();
  222. }
  223. ****/
  224. typedef class CInterface * CInterfacePtr;
  225. #define IMPLEMENT_IINTERFACE_USING(x) \
  226. virtual void Link(void) const { x::Link(); } \
  227. virtual bool Release(void) const { return x::Release(); }
  228. #define IMPLEMENT_IINTERFACE IMPLEMENT_IINTERFACE_USING(CInterface)
  229. #endif