memory_segment.h 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. // Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
  2. //
  3. // Permission to use, copy, modify, and/or distribute this software for any
  4. // purpose with or without fee is hereby granted, provided that the above
  5. // copyright notice and this permission notice appear in all copies.
  6. //
  7. // THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
  8. // REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
  9. // AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
  10. // INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
  11. // LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
  12. // OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  13. // PERFORMANCE OF THIS SOFTWARE.
  14. #ifndef MEMORY_SEGMENT_H
  15. #define MEMORY_SEGMENT_H
  16. #include <exceptions/exceptions.h>
  17. #include <utility>
  18. #include <stdlib.h>
  19. namespace isc {
  20. namespace util {
  21. /// \brief Exception that can be thrown when constructing a MemorySegment
  22. /// object.
  23. class MemorySegmentOpenError : public Exception {
  24. public:
  25. MemorySegmentOpenError(const char* file, size_t line, const char* what) :
  26. isc::Exception(file, line, what) {}
  27. };
  28. /// \brief Exception that is thrown, when allocating space in a MemorySegment
  29. /// results in growing the underlying segment.
  30. ///
  31. /// See MemorySegment::allocate() for details.
  32. class MemorySegmentGrown : public Exception {
  33. public:
  34. MemorySegmentGrown(const char* file, size_t line, const char* what) :
  35. isc::Exception(file, line, what) {}
  36. };
  37. /// \brief General error that can be thrown by a MemorySegment
  38. /// implementation.
  39. class MemorySegmentError : public Exception {
  40. public:
  41. MemorySegmentError(const char* file, size_t line, const char* what) :
  42. isc::Exception(file, line, what) {}
  43. };
  44. /// \brief Memory Segment Class
  45. ///
  46. /// This class specifies an interface for allocating memory segments.
  47. /// It's intended to provide a unified interface, whether the underlying
  48. /// memory is local to a specific process or is sharable by multiple
  49. /// processes.
  50. ///
  51. /// This is an abstract class and a real implementation such as
  52. /// MemorySegmentLocal should be used in code.
  53. class MemorySegment {
  54. public:
  55. /// \brief Destructor
  56. virtual ~MemorySegment() {}
  57. /// \brief Allocate/acquire a fragment of memory.
  58. ///
  59. /// The source of the memory is dependent on the implementation used.
  60. ///
  61. /// Depending on the implementation details, it may have to grow the
  62. /// internal memory segment (again, in an implementation dependent way)
  63. /// to allocate the required size of memory. In that case the
  64. /// implementation must grow the internal segment sufficiently so the
  65. /// next call to allocate() for the same size will succeed, and throw
  66. /// a \c MemorySegmentGrown exception (not really allocating the memory
  67. /// yet).
  68. ///
  69. /// An application that uses this memory segment abstraction to allocate
  70. /// memory should expect this exception, and should normally catch it
  71. /// at an appropriate layer (which may be immediately after a call to
  72. /// \c allocate() or a bit higher layer). It should interpret the
  73. /// exception as any raw address that belongs to the segment may have
  74. /// been remapped and must be re-fetched via an already established
  75. /// named address using the \c getNamedAddress() method.
  76. ///
  77. /// The intended use case of \c allocate() with the \c MemorySegmentGrown
  78. /// exception is to build a complex object that would internally require
  79. /// multiple calls to \c allocate():
  80. ///
  81. /// \code
  82. /// ComplicatedStuff* stuff = NULL;
  83. /// while (!stuff) { // this must eventually succeed or result in bad_alloc
  84. /// try {
  85. /// // create() is a factory method that takes a memory segment
  86. /// // and calls allocate() on it multiple times. create()
  87. /// // provides an exception guarantee that any intermediately
  88. /// // allocated memory will be properly deallocate()-ed on
  89. /// // exception.
  90. /// stuff = ComplicatedStuff::create(mem_segment);
  91. /// } catch (const MemorySegmentGrown&) { /* just try again */ }
  92. /// }
  93. /// \endcode
  94. ///
  95. /// This way, \c create() can be written as if each call to \c allocate()
  96. /// always succeeds.
  97. ///
  98. /// Alternatively, or in addition to this, we could introduce a "no throw"
  99. /// version of this method with a way to tell the caller the reason of
  100. /// any failure (whether it's really out of memory or just due to growing
  101. /// the segment). That would be more convenient if the caller wants to
  102. /// deal with the failures on a per-call basis rather than as a set
  103. /// of calls like in the above example. At the moment, we don't expect
  104. /// to have such use-cases, so we only provide the exception
  105. /// version.
  106. ///
  107. /// \throw std::bad_alloc The implementation cannot allocate the
  108. /// requested storage.
  109. /// \throw MemorySegmentGrown The memory segment doesn't have sufficient
  110. /// space for the requested size and has grown internally.
  111. /// \throw MemorySegmentError An attempt was made to allocate
  112. /// storage on a read-only memory segment.
  113. ///
  114. /// \param size The size of the memory requested in bytes.
  115. /// \return Returns pointer to the memory allocated.
  116. virtual void* allocate(size_t size) = 0;
  117. /// \brief Free/release a segment of memory.
  118. ///
  119. /// This method may throw <code>isc::OutOfRange</code> if \c size is
  120. /// not equal to the originally allocated size. \c size could be
  121. /// used by some implementations such as a slice allocator, where
  122. /// freeing memory also requires the size to be specified. We also
  123. /// use this argument in some implementations to test if all allocated
  124. /// memory was deallocated properly.
  125. ///
  126. /// Specific implementation may also throw \c MemorySegmentError if it
  127. /// encounters violation of implementation specific restrictions.
  128. ///
  129. /// In general, however, this method must succeed and exception free
  130. /// as long as the caller passes valid parameters (\c ptr specifies
  131. /// memory previously allocated and \c size is correct).
  132. ///
  133. /// \throw OutOfRange The passed size doesn't match the allocated memory
  134. /// size (when identifiable for the implementation).
  135. /// \throw MemorySegmentError Failure of implementation specific
  136. /// validation.
  137. ///
  138. /// \param ptr Pointer to the block of memory to free/release. This
  139. /// should be equal to a value returned by <code>allocate()</code>.
  140. /// \param size The size of the memory to be freed in bytes. This
  141. /// should be equal to the number of bytes originally allocated.
  142. virtual void deallocate(void* ptr, size_t size) = 0;
  143. /// \brief Check if all allocated memory was deallocated.
  144. ///
  145. /// \return Returns <code>true</code> if all allocated memory (including
  146. /// names associated by memory addresses by \c setNamedAddress()) was
  147. /// deallocated, <code>false</code> otherwise.
  148. virtual bool allMemoryDeallocated() = 0;
  149. /// \brief Associate specified address in the segment with a given name.
  150. ///
  151. /// This method establishes an association between the given name and
  152. /// the address in an implementation specific way. The stored address
  153. /// is retrieved by the name later by calling \c getNamedAddress().
  154. /// If the underlying memory segment is sharable by multiple processes,
  155. /// the implementation must ensure the portability of the association;
  156. /// if a process gives an address in the shared segment a name, another
  157. /// process that shares the same segment should be able to retrieve the
  158. /// corresponding address by that name (in such cases the real address
  159. /// may be different between these two processes).
  160. ///
  161. /// \c addr must be 0 (NULL) or an address that belongs to this segment.
  162. /// The latter case means it must be the return value of a previous call
  163. /// to \c allocate(). The actual implementation is encouraged to detect
  164. /// violation of this restriction and signal it with an exception, but
  165. /// it's not an API requirement. It's generally the caller's
  166. /// responsibility to meet the restriction. Note that NULL is allowed
  167. /// as \c addr even if it wouldn't be considered to "belong to" the
  168. /// segment in its normal sense; it can be used to indicate that memory
  169. /// has not been allocated for the specified name. A subsequent call
  170. /// to \c getNamedAddress() will return NamedAddressResult(true, NULL)
  171. /// for that name.
  172. ///
  173. /// \note Naming an address is intentionally separated from allocation
  174. /// so that, for example, one module of a program can name a memory
  175. /// region allocated by another module of the program.
  176. ///
  177. /// There can be an existing association for the name; in that case the
  178. /// association will be overridden with the newly given address.
  179. ///
  180. /// While normally unexpected, it's possible that available space in the
  181. /// segment is not sufficient to allocate a space (if not already exist)
  182. /// for the specified name in the segment. In that case, if possible, the
  183. /// implementation should try to grow the internal segment and retry
  184. /// establishing the association. The implementation should throw
  185. /// std::bad_alloc if even reasonable attempts of retry still fail.
  186. ///
  187. /// This method should normally return false, but if the internal segment
  188. /// had to grow to store the given name, it must return true. The
  189. /// application should interpret it just like the case of
  190. /// \c MemorySegmentGrown exception thrown from the \c allocate() method.
  191. ///
  192. /// \note The behavior in case the internal segment grows is different
  193. /// from that of \c allocate(). This is intentional. In intended use
  194. /// cases (for the moment) this method will be called independently,
  195. /// rather than as part of a set of allocations. It's also expected
  196. /// that other raw memory addresses (which would have been invalidated
  197. /// due to the change to the segment) won't be referenced directly
  198. /// immediately after this call. So, the caller should normally be able
  199. /// to call this method as mostly never-fail one (except in case of real
  200. /// memory exhaustion) and ignore the return value.
  201. ///
  202. /// \throw std::bad_alloc Allocation of a segment space for the given name
  203. /// failed.
  204. /// \throw InvalidParameter name is NULL.
  205. /// \throw MemorySegmentError Failure of implementation specific
  206. /// validation.
  207. ///
  208. /// \param name A C string to be associated with \c addr. Must not be NULL.
  209. /// \param addr A memory address returned by a prior call to \c allocate.
  210. /// \return true if the internal segment has grown to allocate space for
  211. /// the name; false otherwise (see above).
  212. bool setNamedAddress(const char* name, void* addr) {
  213. // This public method implements common validation. The actual
  214. // work specific to the derived segment is delegated to the
  215. // corresponding protected method.
  216. if (!name) {
  217. isc_throw(InvalidParameter,
  218. "NULL name is given to setNamedAddress");
  219. }
  220. return (setNamedAddressImpl(name, addr));
  221. }
  222. /// \brief Type definition for result returned by getNamedAddress()
  223. typedef std::pair<bool, void*> NamedAddressResult;
  224. /// \brief Return the address in the segment that has the given name.
  225. ///
  226. /// This method returns the memory address in the segment corresponding
  227. /// to the specified \c name. The name and address must have been
  228. /// associated by a prior call to \c setNameAddress(). If no address
  229. /// associated with the given name is found, it returns NULL.
  230. ///
  231. /// This method should generally be considered exception free, but there
  232. /// can be a small chance it throws, depending on the internal
  233. /// implementation (e.g., if it converts the name to std::string), so the
  234. /// API doesn't guarantee that property. In general, if this method
  235. /// throws it should be considered a fatal condition.
  236. ///
  237. /// \throw InvalidParameter name is NULL.
  238. ///
  239. /// \param name A C string of which the segment memory address is to be
  240. /// returned. Must not be NULL.
  241. /// \return An std::pair containing a bool (set to true if the name
  242. /// was found, or false otherwise) and the address associated with
  243. /// the name (which is undefined if the name was not found).
  244. NamedAddressResult getNamedAddress(const char* name) const {
  245. // This public method implements common validation. The actual
  246. // work specific to the derived segment is delegated to the
  247. // corresponding protected method.
  248. if (!name) {
  249. isc_throw(InvalidParameter,
  250. "NULL name is given to getNamedAddress");
  251. }
  252. return (getNamedAddressImpl(name));
  253. }
  254. /// \brief Delete a name previously associated with a segment address.
  255. ///
  256. /// This method deletes the association of the given \c name to
  257. /// a corresponding segment address previously established by
  258. /// \c setNamedAddress(). If there is no association for the given name
  259. /// this method returns false; otherwise it returns true.
  260. ///
  261. /// See \c getNamedAddress() about exception consideration.
  262. ///
  263. /// \throw InvalidParameter name is NULL.
  264. /// \throw MemorySegmentError Failure of implementation specific
  265. /// validation.
  266. ///
  267. /// \param name A C string of which the segment memory address is to be
  268. /// deleted. Must not be NULL.
  269. bool clearNamedAddress(const char* name) {
  270. // This public method implements common validation. The actual
  271. // work specific to the derived segment is delegated to the
  272. // corresponding protected method.
  273. if (!name) {
  274. isc_throw(InvalidParameter,
  275. "NULL name is given to clearNamedAddress");
  276. }
  277. return (clearNamedAddressImpl(name));
  278. }
  279. protected:
  280. /// \brief Implementation of setNamedAddress beyond common validation.
  281. virtual bool setNamedAddressImpl(const char* name, void* addr) = 0;
  282. /// \brief Implementation of getNamedAddress beyond common validation.
  283. virtual NamedAddressResult getNamedAddressImpl(const char* name) const = 0;
  284. /// \brief Implementation of clearNamedAddress beyond common validation.
  285. virtual bool clearNamedAddressImpl(const char* name) = 0;
  286. };
  287. } // namespace util
  288. } // namespace isc
  289. #endif // MEMORY_SEGMENT_H
  290. // Local Variables:
  291. // mode: c++
  292. // End: