jscm.hpp 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  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 _JSCM_HPP_
  14. #define _JSCM_HPP_
  15. #undef interface
  16. #define implements public
  17. #define extends public
  18. #ifdef _MSC_VER
  19. #define interface struct __declspec(novtable)
  20. #else
  21. #define interface struct
  22. #endif
  23. #ifdef JLIB_EXPORTS
  24. #define jlib_decl DECL_EXPORT
  25. #define jlib_thrown_decl DECL_EXPORT
  26. #else
  27. #define jlib_decl DECL_IMPORT
  28. #define jlib_thrown_decl DECL_IMPORT
  29. #endif
  30. #include <atomic>
  31. interface IInterface
  32. {
  33. virtual void Link() const = 0;
  34. virtual bool Release() const = 0;
  35. };
  36. template <class X> inline void Link(X * ptr) { if (ptr) ptr->Link(); }
  37. template <class X> inline void Release(X * ptr) { if (ptr) ptr->Release(); }
  38. #define QUERYINTERFACE(ptr, TYPE) (dynamic_cast<TYPE *>(ptr))
  39. //This base class implements a shared pointer based on a link count held in the object.
  40. //The two derived classes Owned and Linked should be used as the concrete types to construct a shared object
  41. //from a pointer.
  42. template <class CLASS> class Shared
  43. {
  44. public:
  45. inline Shared() { ptr = NULL; }
  46. inline Shared(CLASS * _ptr, bool owned) { ptr = _ptr; if (!owned && _ptr) _ptr->Link(); }
  47. inline Shared(const Shared & other) { ptr = other.getLink(); }
  48. #if defined(__cplusplus) && __cplusplus >= 201100
  49. inline Shared(Shared && other) { ptr = other.getClear(); }
  50. explicit operator bool() const { return ptr != nullptr; }
  51. #endif
  52. inline ~Shared() { ::Release(ptr); }
  53. inline Shared<CLASS> & operator = (const Shared<CLASS> & other) { this->set(other.get()); return *this; }
  54. inline CLASS * operator -> () const { return ptr; }
  55. inline operator CLASS *() const { return ptr; }
  56. inline void clear() { CLASS *temp=ptr; ptr=NULL; ::Release(temp); }
  57. inline CLASS * get() const { return ptr; }
  58. inline CLASS * getClear() { CLASS * temp = ptr; ptr = NULL; return temp; }
  59. inline CLASS * getLink() const { if (ptr) ptr->Link(); return ptr; }
  60. inline void set(CLASS * _ptr)
  61. {
  62. CLASS * temp = ptr;
  63. if (temp != _ptr)
  64. {
  65. ::Link(_ptr);
  66. ptr = _ptr;
  67. ::Release(temp);
  68. }
  69. }
  70. inline void set(const Shared<CLASS> &other) { this->set(other.get()); }
  71. inline void setown(CLASS * _ptr) { CLASS * temp = ptr; ptr = _ptr; ::Release(temp); }
  72. inline bool setownIfNull(CLASS * _ptr)
  73. {
  74. if (!ptr)
  75. {
  76. ptr = _ptr;
  77. return true;
  78. }
  79. else
  80. {
  81. ::Release(_ptr);
  82. return false;
  83. }
  84. }
  85. inline void swap(Shared<CLASS> & other) { CLASS * temp = ptr; ptr = other.ptr; other.ptr = temp; }
  86. protected:
  87. inline Shared(CLASS * _ptr) { ptr = _ptr; } // deliberately protected
  88. private:
  89. inline void setown(const Shared<CLASS> &other); // illegal - going to cause a -ve leak
  90. inline Shared<CLASS> & operator = (const CLASS * other);
  91. private:
  92. CLASS * ptr;
  93. };
  94. // Similar to class Shared<X>, but thread safe versions of the functions (avoid the need for critical sections)
  95. template <class CLASS> class AtomicShared
  96. {
  97. public:
  98. inline AtomicShared() { ptr.store(nullptr, std::memory_order_relaxed); }
  99. inline AtomicShared(CLASS * _ptr, bool owned) { ptr.store(_ptr, std::memory_order_relaxed); if (!owned && _ptr) _ptr->Link(); }
  100. inline AtomicShared(const AtomicShared & other) { ptr.store(other.getLinkNonAtomic(), std::memory_order_relaxed); }
  101. #if defined(__cplusplus) && __cplusplus >= 201100
  102. inline AtomicShared(AtomicShared && other) { ptr.store(other.getClear(), std::memory_order_relaxed); }
  103. #endif
  104. inline ~AtomicShared() { ::Release(ptr.load(std::memory_order_relaxed)); }
  105. inline AtomicShared<CLASS> & operator = (const AtomicShared<CLASS> & other) { this->setown(other.getLinkNonAtomic()); return *this; }
  106. inline void clear() { ::Release(getClear()); }
  107. inline CLASS * getClear()
  108. {
  109. return ptr.exchange(nullptr);
  110. }
  111. inline CLASS * getClearNonAtomic()
  112. {
  113. CLASS * result = ptr.load();
  114. ptr.store(nullptr);
  115. return result;
  116. }
  117. //The getLink() function cannot be implemented in a thread safe way - e.g. if clear is called concurrently
  118. //then temp will point to a freed object. (Might be possible with support for transactional memory...)
  119. inline CLASS * getLinkNonAtomic() const
  120. {
  121. CLASS * temp = ptr;
  122. if (temp)
  123. temp->Link();
  124. return temp;
  125. }
  126. inline bool isSet() const { return ptr != nullptr; }
  127. inline void set(CLASS * _ptr)
  128. {
  129. if (ptr != _ptr)
  130. {
  131. LINK(_ptr);
  132. this->setown(_ptr);
  133. }
  134. }
  135. inline bool setownIfNull(CLASS * _ptr)
  136. {
  137. CLASS * expected = nullptr;
  138. if (ptr.compare_exchange_strong(expected, _ptr))
  139. return true;
  140. ::Release(_ptr);
  141. return false;
  142. }
  143. inline void setown(CLASS * _ptr)
  144. {
  145. CLASS * temp = ptr.exchange(_ptr);
  146. ::Release(temp);
  147. }
  148. inline CLASS * swap(CLASS * _ptr)
  149. {
  150. return ptr.exchange(_ptr);
  151. }
  152. //swap - this will only update this once, but other can temporarily have a null value
  153. inline void swap(AtomicShared<CLASS> & other)
  154. {
  155. CLASS * temp = other.getClear();
  156. temp = this->swap(temp);
  157. temp = other.swap(temp);
  158. ::Release(temp);
  159. }
  160. protected:
  161. inline AtomicShared(CLASS * _ptr) { ptr = _ptr; } // deliberately protected
  162. private:
  163. inline void setown(const AtomicShared<CLASS> &other); // illegal - going to cause a -ve leak
  164. inline AtomicShared<CLASS> & operator = (const CLASS * other);
  165. private:
  166. std::atomic<CLASS *> ptr;
  167. };
  168. //An Owned Shared object takes ownership of the pointer that is passed in the constructor.
  169. template <class CLASS> class Owned : public Shared<CLASS>
  170. {
  171. public:
  172. inline Owned() { }
  173. inline Owned(CLASS * _ptr) : Shared<CLASS>(_ptr) { }
  174. inline Shared<CLASS> & operator = (const Shared<CLASS> & other) { this->set(other.get()); return *this; }
  175. private:
  176. inline Owned(const Shared<CLASS> & other); // Almost certainly a bug
  177. inline Owned<CLASS> & operator = (const CLASS * other);
  178. };
  179. //A Linked Shared object takes does not take ownership of the pointer that is passed in the constructor.
  180. template <class CLASS> class Linked : public Shared<CLASS>
  181. {
  182. public:
  183. inline Linked() { }
  184. inline Linked(CLASS * _ptr) : Shared<CLASS>(LINK(_ptr)) { }
  185. inline Linked(const Shared<CLASS> & other) : Shared<CLASS>(other) { }
  186. inline Shared<CLASS> & operator = (const Shared<CLASS> & other) { this->set(other.get()); return *this; }
  187. private:
  188. inline Linked<CLASS> & operator = (const CLASS * other);
  189. };
  190. // IStringVal manages returning of arbitrary null-terminated string data between systems that may not share heap managers
  191. interface IStringVal
  192. {
  193. virtual const char * str() const = 0;
  194. virtual void set(const char * val) = 0;
  195. virtual void clear() = 0;
  196. virtual void setLen(const char * val, unsigned length) = 0;
  197. virtual unsigned length() const = 0;
  198. };
  199. // IDataVal manages returning of arbitrary unterminated binary data between systems that may not share heap managers
  200. interface IDataVal
  201. {
  202. virtual const void * data() const = 0;
  203. virtual void clear() = 0;
  204. virtual void setLen(const void * val, size_t length) = 0;
  205. virtual size_t length() const = 0;
  206. virtual void * reserve(size_t length) = 0;
  207. };
  208. // IIterator
  209. interface IIterator : extends IInterface
  210. {
  211. virtual bool first() = 0;
  212. virtual bool next() = 0;
  213. virtual bool isValid() = 0;
  214. virtual IInterface & query() = 0;
  215. virtual IInterface & get() = 0;
  216. };
  217. template <class C>
  218. interface IIteratorOf : public IInterface
  219. {
  220. public:
  221. virtual bool first() = 0;
  222. virtual bool next() = 0;
  223. virtual bool isValid() = 0;
  224. virtual C & query() = 0;
  225. C & get() { C &c = query(); c.Link(); return c; }
  226. };
  227. #define ForEach(i) for((i).first();(i).isValid();(i).next())
  228. typedef IInterface * IInterfacePtr;
  229. typedef Owned<IInterface> OwnedIInterface;
  230. typedef Linked<IInterface> LinkedIInterface;
  231. template <class X> inline X * LINK(X * ptr) { if (ptr) ptr->Link(); return ptr; }
  232. template <class X> inline X & OLINK(X & obj) { obj.Link(); return obj; }
  233. template <class X> inline X * LINK(const Shared<X> &ptr) { return ptr.getLink(); }
  234. class StringBuffer;
  235. // When changing this enum, be sure to update (a) the string functions, and (b) NUM value in jlog.hpp
  236. typedef enum
  237. {
  238. // Target audience: system admins
  239. // Purpose: Information useful for administering the platform, diagnosing errors and
  240. // resolving system issues
  241. MSGAUD_operator = 0x01,
  242. // Target audience: ECL developers
  243. // Purpose: Information useful for diagnosing and resolving issues (performance and faults)
  244. // in the execution ECL queries
  245. MSGAUD_user = 0x02,
  246. // Target audience: HPCC Platform developers
  247. // Purpose: Information related to errors relating to potential bugs or any unexpected errors that
  248. // would not be resolvable by sysadmin or ECL developers. Additional information that may
  249. // be useful for improving the platform.
  250. MSGAUD_programmer = 0x20,
  251. // MSGAUD_legacy = 0x40, REMOVED - may be reused later
  252. // Target audience: persons involved in accounting and security audits
  253. MSGAUD_audit = 0x80,
  254. // MSGAUD_all is to be used for filtering or specifying which messages are to be logged
  255. // (A message itself should not be logged as MSGAUD_all)
  256. MSGAUD_all = 0xFF
  257. } MessageAudience;
  258. interface jlib_thrown_decl IException : public IInterface
  259. {
  260. virtual int errorCode() const = 0;
  261. virtual StringBuffer & errorMessage(StringBuffer &msg) const = 0;
  262. virtual MessageAudience errorAudience() const = 0;
  263. };
  264. #endif