PageRenderTime 52ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/hphp/runtime/base/apc-handle.h

https://gitlab.com/Blueprint-Marketing/hhvm
C Header | 238 lines | 90 code | 24 blank | 124 comment | 9 complexity | c5b488e146e56df9ad638887f784643f MD5 | raw file
  1. /*
  2. +----------------------------------------------------------------------+
  3. | HipHop for PHP |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2010-2014 Facebook, Inc. (http://www.facebook.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 3.01 of the PHP license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.php.net/license/3_01.txt |
  11. | If you did not receive a copy of the PHP license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@php.net so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. */
  16. #ifndef incl_HPHP_APC_HANDLE_H_
  17. #define incl_HPHP_APC_HANDLE_H_
  18. #include <atomic>
  19. #include "hphp/util/atomic.h"
  20. #include "hphp/util/hash.h"
  21. #include "hphp/util/lock.h"
  22. #include "hphp/runtime/base/type-variant.h"
  23. #if (defined(__APPLE__) || defined(__APPLE_CC__)) && (defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__))
  24. # if defined(__LITTLE_ENDIAN__)
  25. # undef WORDS_BIGENDIAN
  26. # else
  27. # if defined(__BIG_ENDIAN__)
  28. # define WORDS_BIGENDIAN
  29. # endif
  30. # endif
  31. #endif
  32. namespace HPHP {
  33. ///////////////////////////////////////////////////////////////////////////////
  34. /*
  35. * An APCHandle is the externally visible handle for in-memory APC values. The
  36. * main role of the APCHandle is to hold the type information of the value,
  37. * manage the lifetime. When new values are added to APC, they are created
  38. * using APCHandle::Create.
  39. *
  40. * Internally the family of APC entities (all APCXXXX classes, e.g. APCString,
  41. * APCArray, ...) embed the handle and provide an API to return the instance
  42. * from the handle pointer. Examples:
  43. *
  44. * APCString APCTypedValue
  45. * ---------------- --------------
  46. * | APCHandle | | SharedData |
  47. * | StringData | | APCHandle |
  48. * ---------------- --------------
  49. *
  50. * So, for an APCString the caller gets back an APCHandle* pointing to the
  51. * location of the field in the class. APCString::fromHandle(APCHandle*
  52. * handle) will simply return the pointer itself as the handle sits at offset 0
  53. * (reinterpret_cast<APCString*>(handle)). For an APCTypedValue,
  54. * APCTypedValue::fromHandle(APCHandle* handle) would return the handle pointer
  55. * minus the offset (in words) of the handle. Normally the handle sits at
  56. * position 0 so the call ends up being a no-op.
  57. *
  58. * APCTypedValue is, at the moment, the only entity with the handle at a
  59. * non-zero offset and that is because the layout of APCTypedValue and
  60. * TypedValue have to be the same, and we let the DataType field in APCHandle
  61. * be used through a TypedValue*. This layout allows for an important
  62. * optimization when an APCTypedValue is contained inside an APCArray---in such
  63. * cases the APCTypedValue is returned directly instead of creating another
  64. * TypedValue.
  65. *
  66. * It's important to point out that APCHandle::type() is not enough to
  67. * determine the APCXXX class behind the APCHandle. That is because both
  68. * APCObject and APCArray can have a serialized form that it is just a string
  69. * (see isSerializedArray and isSerializedObj).
  70. *
  71. * Thread safety:
  72. *
  73. * const-qualified member functions on this class are safe for concurrent
  74. * use by multiple threads, as long as no other thread may be calling any
  75. * non-const member functions that are not documented as exceptions to this
  76. * rule.
  77. *
  78. */
  79. struct APCHandle {
  80. struct Pair {
  81. APCHandle* handle;
  82. size_t size;
  83. };
  84. /*
  85. * Create an instance of an APC object according to the type of source and
  86. * the various flags. This is the only entry point to create APC entities.
  87. */
  88. static Pair Create(const Variant& source, bool serialized,
  89. bool inner = false, bool unserializeObj = false);
  90. /*
  91. * Memory management API.
  92. *
  93. * APC handles can be managed both by eager reference counting and via the
  94. * Treadmill. Memory management operations on APC handles go through this
  95. * API to hide which scheme is being used from users of APCHandle. The
  96. * active scheme can be different for different handles in the same process.
  97. *
  98. * function | Uncounted | Counted
  99. * -----------------+-----------+-----------
  100. * reference | no-op | incref
  101. * unreference | no-op | decref
  102. * unreferenceRoot | treadmill | decref
  103. *
  104. * The `size' argument to unreferenceRoot is only use for stats collection,
  105. * so zero may be passed in some situations.
  106. *
  107. * unreferenceRoot may be called while this APCHandle is still being read by
  108. * other threads---it is an exception to the thread-safety rule documented
  109. * above the class.
  110. */
  111. void reference() const {
  112. if (!isUncounted()) {
  113. realIncRef();
  114. }
  115. }
  116. void unreference() const {
  117. if (!isUncounted()) {
  118. realDecRef();
  119. }
  120. }
  121. void unreferenceRoot(size_t size);
  122. /*
  123. * Get an instance of the PHP object represented by this APCHandle. The
  124. * instance returned will be local to the request/thread that performed
  125. * the call.
  126. */
  127. Variant toLocal() const;
  128. /*
  129. * Return the PHP DataType represented by this APCHandle.
  130. *
  131. * Note that this does not entirely determine the type of APC storage being
  132. * used---for example, objects and arrays can be represented as serialized
  133. * APCStrings, in which case type() will still KindOfObject or KindOfArray.
  134. * See isSerializedArray and isSerializedObj below.
  135. */
  136. DataType type() const { return m_type; }
  137. /*
  138. * When we load KindOfObjects that are !isObj() (i.e. they are back by an
  139. * APCString containing a serialized object), we may attempt to convert it to
  140. * an APCObject representation. If the conversion is not possible (for
  141. * example, if there are internal references), we set this flag so that we
  142. * don't try over and over.
  143. *
  144. * The non-const setObjAttempted function is safe for concurrent use with
  145. * multiple readers and writers on a live APCHandle---it is an exception to
  146. * the thread-safety rule documented above the class.
  147. */
  148. bool objAttempted() const {
  149. return m_obj_attempted.load(std::memory_order_relaxed);
  150. }
  151. void setObjAttempted() {
  152. m_obj_attempted.store(true, std::memory_order_relaxed);
  153. }
  154. /*
  155. * For KindOfObject and KindOfArray, reprectively, these flags distinguish
  156. * between the APCObject and APCArray representations and serialized
  157. * APCString representations. And an APCCollection wraps an array that
  158. * represents a php KindOfObject for a particular collection type.
  159. */
  160. bool isSerializedObj() const { return m_flags & FSerializedObj; }
  161. bool isSerializedArray() const { return m_flags & FSerializedArray; }
  162. bool isAPCCollection() const { return m_flags & FAPCCollection; }
  163. void setSerializedObj() { m_flags |= FSerializedObj; }
  164. void setSerializedArray() { m_flags |= FSerializedArray; }
  165. void setAPCCollection() { m_flags |= FAPCCollection; }
  166. /*
  167. * If true, this APCHandle is not using reference counting.
  168. */
  169. bool isUncounted() const { return m_flags & FUncounted; }
  170. void setUncounted() { m_flags |= FUncounted; }
  171. /*
  172. * If this APCHandle is using an APCArray representation, this flag
  173. * discriminates between two different storage schemes inside APCArray.
  174. */
  175. bool isPacked() const { return m_flags & FPacked; }
  176. void setPacked() { m_flags |= FPacked; }
  177. private:
  178. constexpr static uint8_t FSerializedArray = 1 << 0;
  179. constexpr static uint8_t FSerializedObj = 1 << 1;
  180. constexpr static uint8_t FPacked = 1 << 2;
  181. constexpr static uint8_t FUncounted = 1 << 3;
  182. constexpr static uint8_t FAPCCollection = 1 << 4;
  183. private:
  184. friend struct APCTypedValue;
  185. friend struct APCString;
  186. friend struct APCArray;
  187. friend struct APCObject;
  188. friend struct APCCollection;
  189. explicit APCHandle(DataType type) : m_type(type) {}
  190. APCHandle(const APCHandle&) = delete;
  191. APCHandle& operator=(APCHandle const&) = delete;
  192. private:
  193. void realIncRef() const {
  194. assert(IS_REFCOUNTED_TYPE(m_type));
  195. ++m_count;
  196. }
  197. void realDecRef() const {
  198. assert(m_count.load() > 0);
  199. if (m_count > 1) {
  200. assert(IS_REFCOUNTED_TYPE(m_type));
  201. if (--m_count) return;
  202. }
  203. const_cast<APCHandle*>(this)->deleteShared();
  204. }
  205. void deleteShared();
  206. private:
  207. DataType m_type;
  208. std::atomic<uint8_t> m_obj_attempted{false};
  209. uint8_t m_flags{0};
  210. mutable std::atomic<uint32_t> m_count{1};
  211. };
  212. ///////////////////////////////////////////////////////////////////////////////
  213. }
  214. #endif