memory_segment.h 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  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() const = 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. /// Note that names beginning with an underscore ("_") are reserved
  162. /// for internal use by this class. If such a name is passed to this
  163. /// method, an isc::InvalidParameter exception will be thrown.
  164. ///
  165. /// \c addr must be 0 (NULL) or an address that belongs to this segment.
  166. /// The latter case means it must be the return value of a previous call
  167. /// to \c allocate(). The actual implementation is encouraged to detect
  168. /// violation of this restriction and signal it with an exception, but
  169. /// it's not an API requirement. It's generally the caller's
  170. /// responsibility to meet the restriction. Note that NULL is allowed
  171. /// as \c addr even if it wouldn't be considered to "belong to" the
  172. /// segment in its normal sense; it can be used to indicate that memory
  173. /// has not been allocated for the specified name. A subsequent call
  174. /// to \c getNamedAddress() will return NamedAddressResult(true, NULL)
  175. /// for that name.
  176. ///
  177. /// \note Naming an address is intentionally separated from allocation
  178. /// so that, for example, one module of a program can name a memory
  179. /// region allocated by another module of the program.
  180. ///
  181. /// There can be an existing association for the name; in that case the
  182. /// association will be overridden with the newly given address.
  183. ///
  184. /// While normally unexpected, it's possible that available space in the
  185. /// segment is not sufficient to allocate a space (if not already exist)
  186. /// for the specified name in the segment. In that case, if possible, the
  187. /// implementation should try to grow the internal segment and retry
  188. /// establishing the association. The implementation should throw
  189. /// std::bad_alloc if even reasonable attempts of retry still fail.
  190. ///
  191. /// This method should normally return false, but if the internal segment
  192. /// had to grow to store the given name, it must return true. The
  193. /// application should interpret it just like the case of
  194. /// \c MemorySegmentGrown exception thrown from the \c allocate() method.
  195. ///
  196. /// \note The behavior in case the internal segment grows is different
  197. /// from that of \c allocate(). This is intentional. In intended use
  198. /// cases (for the moment) this method will be called independently,
  199. /// rather than as part of a set of allocations. It's also expected
  200. /// that other raw memory addresses (which would have been invalidated
  201. /// due to the change to the segment) won't be referenced directly
  202. /// immediately after this call. So, the caller should normally be able
  203. /// to call this method as mostly never-fail one (except in case of real
  204. /// memory exhaustion) and ignore the return value.
  205. ///
  206. /// \throw std::bad_alloc Allocation of a segment space for the given name
  207. /// failed.
  208. /// \throw InvalidParameter name is NULL.
  209. /// \throw MemorySegmentError Failure of implementation specific
  210. /// validation.
  211. ///
  212. /// \param name A C string to be associated with \c addr. Must not be NULL.
  213. /// \param addr A memory address returned by a prior call to \c allocate.
  214. /// \return true if the internal segment has grown to allocate space for
  215. /// the name; false otherwise (see above).
  216. bool setNamedAddress(const char* name, void* addr) {
  217. // This public method implements common validation. The actual
  218. // work specific to the derived segment is delegated to the
  219. // corresponding protected method.
  220. if (!name) {
  221. isc_throw(InvalidParameter,
  222. "NULL name is given to setNamedAddress");
  223. }
  224. if (*name == '_') {
  225. isc_throw(InvalidParameter,
  226. "Names beginning with _ are reserved for "
  227. "internal use only.");
  228. }
  229. return (setNamedAddressImpl(name, addr));
  230. }
  231. /// \brief Type definition for result returned by getNamedAddress()
  232. typedef std::pair<bool, void*> NamedAddressResult;
  233. /// \brief Return the address in the segment that has the given name.
  234. ///
  235. /// This method returns the memory address in the segment corresponding
  236. /// to the specified \c name. The name and address must have been
  237. /// associated by a prior call to \c setNameAddress(). If no address
  238. /// associated with the given name is found, it returns NULL.
  239. ///
  240. /// This method should generally be considered exception free, but there
  241. /// can be a small chance it throws, depending on the internal
  242. /// implementation (e.g., if it converts the name to std::string), so the
  243. /// API doesn't guarantee that property. In general, if this method
  244. /// throws it should be considered a fatal condition.
  245. ///
  246. /// \throw InvalidParameter name is NULL.
  247. ///
  248. /// \param name A C string of which the segment memory address is to be
  249. /// returned. Must not be NULL.
  250. /// \return An std::pair containing a bool (set to true if the name
  251. /// was found, or false otherwise) and the address associated with
  252. /// the name (which is undefined if the name was not found).
  253. NamedAddressResult getNamedAddress(const char* name) const {
  254. // This public method implements common validation. The actual
  255. // work specific to the derived segment is delegated to the
  256. // corresponding protected method.
  257. if (!name) {
  258. isc_throw(InvalidParameter,
  259. "NULL name is given to getNamedAddress");
  260. }
  261. return (getNamedAddressImpl(name));
  262. }
  263. /// \brief Delete a name previously associated with a segment address.
  264. ///
  265. /// This method deletes the association of the given \c name to
  266. /// a corresponding segment address previously established by
  267. /// \c setNamedAddress(). If there is no association for the given name
  268. /// this method returns false; otherwise it returns true.
  269. ///
  270. /// See \c getNamedAddress() about exception consideration.
  271. ///
  272. /// \throw InvalidParameter name is NULL.
  273. /// \throw MemorySegmentError Failure of implementation specific
  274. /// validation.
  275. ///
  276. /// \param name A C string of which the segment memory address is to be
  277. /// deleted. Must not be NULL.
  278. bool clearNamedAddress(const char* name) {
  279. // This public method implements common validation. The actual
  280. // work specific to the derived segment is delegated to the
  281. // corresponding protected method.
  282. if (!name) {
  283. isc_throw(InvalidParameter,
  284. "NULL name is given to clearNamedAddress");
  285. }
  286. return (clearNamedAddressImpl(name));
  287. }
  288. protected:
  289. /// \brief Implementation of setNamedAddress beyond common validation.
  290. virtual bool setNamedAddressImpl(const char* name, void* addr) = 0;
  291. /// \brief Implementation of getNamedAddress beyond common validation.
  292. virtual NamedAddressResult getNamedAddressImpl(const char* name) const = 0;
  293. /// \brief Implementation of clearNamedAddress beyond common validation.
  294. virtual bool clearNamedAddressImpl(const char* name) = 0;
  295. };
  296. } // namespace util
  297. } // namespace isc
  298. #endif // MEMORY_SEGMENT_H
  299. // Local Variables:
  300. // mode: c++
  301. // End: