You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mem_pool.h 13KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436
  1. /*-
  2. * Copyright 2019 Vsevolod Stakhov
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /**
  17. * @file mem_pool.h
  18. * \brief Memory pools library.
  19. *
  20. * Memory pools library. Library is designed to implement efficient way to
  21. * store data in memory avoiding calling of many malloc/free. It has overhead
  22. * because of fact that objects live in pool for rather long time and are not freed
  23. * immediately after use, but if we know certainly when these objects can be used, we
  24. * can use pool for them
  25. */
  26. #ifndef RSPAMD_MEM_POOL_H
  27. #define RSPAMD_MEM_POOL_H
  28. #include "config.h"
  29. #if defined(HAVE_PTHREAD_PROCESS_SHARED) && !defined(DISABLE_PTHREAD_MUTEX)
  30. #include <pthread.h>
  31. #endif
  32. #ifdef __cplusplus
  33. extern "C" {
  34. #endif
  35. struct f_str_s;
  36. #ifdef __has_attribute
  37. # if __has_attribute(alloc_size)
  38. # define RSPAMD_ATTR_ALLOC_SIZE(pos) __attribute__((alloc_size(pos)))
  39. # else
  40. # define RSPAMD_ATTR_ALLOC_SIZE(pos)
  41. # endif
  42. # if __has_attribute(assume_aligned)
  43. # define RSPAMD_ATTR_ALLOC_ALIGN(al) __attribute__((assume_aligned(al)))
  44. # else
  45. # define RSPAMD_ATTR_ALLOC_ALIGN(al)
  46. # endif
  47. # if __has_attribute(returns_nonnull)
  48. # define RSPAMD_ATTR_RETURNS_NONNUL __attribute__((returns_nonnull))
  49. # else
  50. # define RSPAMD_ATTR_RETURNS_NONNUL
  51. # endif
  52. #else
  53. #define RSPAMD_ATTR_ALLOC_SIZE(pos)
  54. #define RSPAMD_ATTR_ALLOC_ALIGN(al)
  55. #define RSPAMD_ATTR_RETURNS_NONNUL
  56. #endif
  57. #define MEMPOOL_TAG_LEN 20
  58. #define MEMPOOL_UID_LEN 20
  59. /* All pointers are aligned as this variable */
  60. #define MIN_MEM_ALIGNMENT G_MEM_ALIGN
  61. /**
  62. * Destructor type definition
  63. */
  64. typedef void (*rspamd_mempool_destruct_t) (void *ptr);
  65. /**
  66. * Pool mutex structure
  67. */
  68. #if !defined(HAVE_PTHREAD_PROCESS_SHARED) || defined(DISABLE_PTHREAD_MUTEX)
  69. typedef struct memory_pool_mutex_s {
  70. gint lock;
  71. pid_t owner;
  72. guint spin;
  73. } rspamd_mempool_mutex_t;
  74. /**
  75. * Rwlock for locking shared memory regions
  76. */
  77. typedef struct memory_pool_rwlock_s {
  78. rspamd_mempool_mutex_t *__r_lock; /**< read mutex (private) */
  79. rspamd_mempool_mutex_t *__w_lock; /**< write mutex (private) */
  80. } rspamd_mempool_rwlock_t;
  81. #else
  82. typedef pthread_mutex_t rspamd_mempool_mutex_t;
  83. typedef pthread_rwlock_t rspamd_mempool_rwlock_t;
  84. #endif
  85. /**
  86. * Tag to use for logging purposes
  87. */
  88. struct rspamd_mempool_tag {
  89. gchar tagname[MEMPOOL_TAG_LEN]; /**< readable name */
  90. gchar uid[MEMPOOL_UID_LEN]; /**< unique id */
  91. };
  92. enum rspamd_mempool_flags {
  93. RSPAMD_MEMPOOL_DEBUG = (1u << 0u),
  94. };
  95. /**
  96. * Memory pool type
  97. */
  98. struct rspamd_mempool_entry_point;
  99. struct rspamd_mutex_s;
  100. struct rspamd_mempool_specific;
  101. typedef struct memory_pool_s {
  102. struct rspamd_mempool_specific *priv;
  103. struct rspamd_mempool_tag tag; /**< memory pool tag */
  104. } rspamd_mempool_t;
  105. /**
  106. * Statistics structure
  107. */
  108. typedef struct memory_pool_stat_s {
  109. guint pools_allocated; /**< total number of allocated pools */
  110. guint pools_freed; /**< number of freed pools */
  111. guint bytes_allocated; /**< bytes that are allocated with pool allocator */
  112. guint chunks_allocated; /**< number of chunks that are allocated */
  113. guint shared_chunks_allocated; /**< shared chunks allocated */
  114. guint chunks_freed; /**< chunks freed */
  115. guint oversized_chunks; /**< oversized chunks */
  116. guint fragmented_size; /**< fragmentation size */
  117. } rspamd_mempool_stat_t;
  118. /**
  119. * Allocate new memory poll
  120. * @param size size of pool's page
  121. * @return new memory pool object
  122. */
  123. rspamd_mempool_t *rspamd_mempool_new_ (gsize size, const gchar *tag, gint flags,
  124. const gchar *loc);
  125. #define rspamd_mempool_new(size, tag, flags) \
  126. rspamd_mempool_new_((size), (tag), (flags), G_STRLOC)
  127. #define rspamd_mempool_new_default(tag, flags) \
  128. rspamd_mempool_new_(rspamd_mempool_suggest_size_(G_STRLOC), (tag), (flags), G_STRLOC)
  129. /**
  130. * Get memory from pool
  131. * @param pool memory pool object
  132. * @param size bytes to allocate
  133. * @return pointer to allocated object
  134. */
  135. void *rspamd_mempool_alloc_ (rspamd_mempool_t *pool, gsize size, gsize alignment, const gchar *loc)
  136. RSPAMD_ATTR_ALLOC_SIZE(2) RSPAMD_ATTR_ALLOC_ALIGN(MIN_MEM_ALIGNMENT) RSPAMD_ATTR_RETURNS_NONNUL;
  137. #define rspamd_mempool_alloc(pool, size) \
  138. rspamd_mempool_alloc_((pool), (size), MIN_MEM_ALIGNMENT, (G_STRLOC))
  139. #define rspamd_mempool_alloc_type(pool, type) \
  140. (type *)(rspamd_mempool_alloc_((pool), sizeof(type), \
  141. MAX(MIN_MEM_ALIGNMENT, RSPAMD_ALIGNOF(type)), (G_STRLOC)))
  142. #define rspamd_mempool_alloc_buffer(pool, buflen) \
  143. (char *)(rspamd_mempool_alloc_((pool), sizeof(char) * (buflen), MIN_MEM_ALIGNMENT, (G_STRLOC)))
  144. /**
  145. * Notify external memory usage for memory pool
  146. * @param pool
  147. * @param size
  148. * @param loc
  149. */
  150. void rspamd_mempool_notify_alloc_ (rspamd_mempool_t *pool, gsize size, const gchar *loc);
  151. #define rspamd_mempool_notify_alloc(pool, size) \
  152. rspamd_mempool_notify_alloc_((pool), (size), (G_STRLOC))
  153. /**
  154. * Get memory and set it to zero
  155. * @param pool memory pool object
  156. * @param size bytes to allocate
  157. * @return pointer to allocated object
  158. */
  159. void *rspamd_mempool_alloc0_ (rspamd_mempool_t *pool, gsize size, gsize alignment, const gchar *loc)
  160. RSPAMD_ATTR_ALLOC_SIZE(2) RSPAMD_ATTR_ALLOC_ALIGN(MIN_MEM_ALIGNMENT) RSPAMD_ATTR_RETURNS_NONNUL;
  161. #define rspamd_mempool_alloc0(pool, size) \
  162. rspamd_mempool_alloc0_((pool), (size), MIN_MEM_ALIGNMENT, (G_STRLOC))
  163. #define rspamd_mempool_alloc0_type(pool, type) \
  164. (type *)(rspamd_mempool_alloc0_((pool), sizeof(type), \
  165. MAX(MIN_MEM_ALIGNMENT, RSPAMD_ALIGNOF(type)), (G_STRLOC)))
  166. /**
  167. * Make a copy of string in pool
  168. * @param pool memory pool object
  169. * @param src source string
  170. * @return pointer to newly created string that is copy of src
  171. */
  172. gchar *rspamd_mempool_strdup_ (rspamd_mempool_t *pool, const gchar *src, const gchar *loc)
  173. RSPAMD_ATTR_ALLOC_ALIGN(MIN_MEM_ALIGNMENT);
  174. #define rspamd_mempool_strdup(pool, src) \
  175. rspamd_mempool_strdup_ ((pool), (src), (G_STRLOC))
  176. /**
  177. * Make a copy of fixed string in pool as null terminated string
  178. * @param pool memory pool object
  179. * @param src source string
  180. * @return pointer to newly created string that is copy of src
  181. */
  182. gchar *rspamd_mempool_fstrdup_ (rspamd_mempool_t *pool,
  183. const struct f_str_s *src,
  184. const gchar *loc)
  185. RSPAMD_ATTR_ALLOC_ALIGN(MIN_MEM_ALIGNMENT);
  186. #define rspamd_mempool_fstrdup(pool, src) \
  187. rspamd_mempool_fstrdup_ ((pool), (src), G_STRLOC)
  188. struct f_str_tok;
  189. /**
  190. * Make a copy of fixed string token in pool as null terminated string
  191. * @param pool memory pool object
  192. * @param src source string
  193. * @return pointer to newly created string that is copy of src
  194. */
  195. gchar *rspamd_mempool_ftokdup_ (rspamd_mempool_t *pool,
  196. const struct f_str_tok *src,
  197. const gchar *loc)
  198. RSPAMD_ATTR_ALLOC_ALIGN(MIN_MEM_ALIGNMENT);
  199. #define rspamd_mempool_ftokdup(pool, src) \
  200. rspamd_mempool_ftokdup_ ((pool), (src), (G_STRLOC))
  201. /**
  202. * Allocate piece of shared memory
  203. * @param pool memory pool object
  204. * @param size bytes to allocate
  205. */
  206. void *rspamd_mempool_alloc_shared_ (rspamd_mempool_t *pool, gsize size, gsize alignment, const gchar *loc)
  207. RSPAMD_ATTR_ALLOC_SIZE(2) RSPAMD_ATTR_ALLOC_ALIGN(MIN_MEM_ALIGNMENT) RSPAMD_ATTR_RETURNS_NONNUL;
  208. #define rspamd_mempool_alloc_shared(pool, size) \
  209. rspamd_mempool_alloc_shared_((pool), (size), MIN_MEM_ALIGNMENT, (G_STRLOC))
  210. void *rspamd_mempool_alloc0_shared_ (rspamd_mempool_t *pool, gsize size, gsize alignment, const gchar *loc)
  211. RSPAMD_ATTR_ALLOC_SIZE(2) RSPAMD_ATTR_ALLOC_ALIGN(MIN_MEM_ALIGNMENT) RSPAMD_ATTR_RETURNS_NONNUL;
  212. #define rspamd_mempool_alloc0_shared(pool, size) \
  213. rspamd_mempool_alloc0_shared_((pool), (size), MIN_MEM_ALIGNMENT, (G_STRLOC))
  214. /**
  215. * Add destructor callback to pool
  216. * @param pool memory pool object
  217. * @param func pointer to function-destructor
  218. * @param data pointer to data that would be passed to destructor
  219. */
  220. void rspamd_mempool_add_destructor_full (rspamd_mempool_t *pool,
  221. rspamd_mempool_destruct_t func,
  222. void *data,
  223. const gchar *function,
  224. const gchar *line);
  225. /* Macros for common usage */
  226. #define rspamd_mempool_add_destructor(pool, func, data) \
  227. rspamd_mempool_add_destructor_full (pool, func, data, (G_STRFUNC), (G_STRLOC))
  228. /**
  229. * Replace destructor callback to pool for specified pointer
  230. * @param pool memory pool object
  231. * @param func pointer to function-destructor
  232. * @param old_data pointer to old data
  233. * @param new_data pointer to data that would be passed to destructor
  234. */
  235. void rspamd_mempool_replace_destructor (rspamd_mempool_t *pool,
  236. rspamd_mempool_destruct_t func,
  237. void *old_data, void *new_data);
  238. /**
  239. * Calls all destructors associated with the specific memory pool without removing
  240. * of the pool itself
  241. * @param pool
  242. */
  243. void rspamd_mempool_destructors_enforce (rspamd_mempool_t *pool);
  244. /**
  245. * Delete pool, free all its chunks and call destructors chain
  246. * @param pool memory pool object
  247. */
  248. void rspamd_mempool_delete (rspamd_mempool_t *pool);
  249. /**
  250. * Get new mutex from pool (allocated in shared memory)
  251. * @param pool memory pool object
  252. * @return mutex object
  253. */
  254. rspamd_mempool_mutex_t *rspamd_mempool_get_mutex (rspamd_mempool_t *pool);
  255. /**
  256. * Lock mutex
  257. * @param mutex mutex to lock
  258. */
  259. void rspamd_mempool_lock_mutex (rspamd_mempool_mutex_t *mutex);
  260. /**
  261. * Unlock mutex
  262. * @param mutex mutex to unlock
  263. */
  264. void rspamd_mempool_unlock_mutex (rspamd_mempool_mutex_t *mutex);
  265. /**
  266. * Create new rwlock and place it in shared memory
  267. * @param pool memory pool object
  268. * @return rwlock object
  269. */
  270. rspamd_mempool_rwlock_t *rspamd_mempool_get_rwlock (rspamd_mempool_t *pool);
  271. /**
  272. * Acquire read lock
  273. * @param lock rwlock object
  274. */
  275. void rspamd_mempool_rlock_rwlock (rspamd_mempool_rwlock_t *lock);
  276. /**
  277. * Acquire write lock
  278. * @param lock rwlock object
  279. */
  280. void rspamd_mempool_wlock_rwlock (rspamd_mempool_rwlock_t *lock);
  281. /**
  282. * Release read lock
  283. * @param lock rwlock object
  284. */
  285. void rspamd_mempool_runlock_rwlock (rspamd_mempool_rwlock_t *lock);
  286. /**
  287. * Release write lock
  288. * @param lock rwlock object
  289. */
  290. void rspamd_mempool_wunlock_rwlock (rspamd_mempool_rwlock_t *lock);
  291. /**
  292. * Get pool allocator statistics
  293. * @param st stat pool struct
  294. */
  295. void rspamd_mempool_stat (rspamd_mempool_stat_t *st);
  296. /**
  297. * Reset memory pool stat
  298. */
  299. void rspamd_mempool_stat_reset (void);
  300. /**
  301. * Get optimal pool size based on page size for this system
  302. * @return size of memory page in system
  303. */
  304. #define rspamd_mempool_suggest_size() rspamd_mempool_suggest_size_(G_STRLOC)
  305. gsize rspamd_mempool_suggest_size_ (const char *loc);
  306. gsize rspamd_mempool_get_used_size (rspamd_mempool_t *pool);
  307. gsize rspamd_mempool_get_wasted_size (rspamd_mempool_t *pool);
  308. /**
  309. * Set memory pool variable
  310. * @param pool memory pool object
  311. * @param name name of variable
  312. * @param gpointer value value of variable
  313. * @param destructor pointer to function-destructor
  314. */
  315. void rspamd_mempool_set_variable (rspamd_mempool_t *pool,
  316. const gchar *name,
  317. gpointer value,
  318. rspamd_mempool_destruct_t destructor);
  319. /**
  320. * Get memory pool variable
  321. * @param pool memory pool object
  322. * @param name name of variable
  323. * @return NULL or pointer to variable data
  324. */
  325. gpointer rspamd_mempool_get_variable (rspamd_mempool_t *pool,
  326. const gchar *name);
  327. /**
  328. * Removes variable from memory pool
  329. * @param pool memory pool object
  330. * @param name name of variable
  331. */
  332. void rspamd_mempool_remove_variable (rspamd_mempool_t *pool,
  333. const gchar *name);
  334. /**
  335. * Prepend element to a list creating it in the memory pool
  336. * @param l
  337. * @param p
  338. * @return
  339. */
  340. GList *rspamd_mempool_glist_prepend (rspamd_mempool_t *pool,
  341. GList *l, gpointer p) G_GNUC_WARN_UNUSED_RESULT;
  342. /**
  343. * Append element to a list creating it in the memory pool
  344. * @param l
  345. * @param p
  346. * @return
  347. */
  348. GList *rspamd_mempool_glist_append (rspamd_mempool_t *pool,
  349. GList *l, gpointer p) G_GNUC_WARN_UNUSED_RESULT;
  350. #ifdef __cplusplus
  351. }
  352. #endif
  353. #ifdef __cplusplus
  354. #include <stdexcept> /* For std::runtime_error */
  355. namespace rspamd {
  356. template<class T>
  357. class mempool_allocator {
  358. public:
  359. typedef T value_type;
  360. mempool_allocator() = delete;
  361. template<class U>
  362. mempool_allocator(const mempool_allocator<U> &other) : pool(other.pool) {}
  363. mempool_allocator(rspamd_mempool_t *_pool) : pool(_pool) {}
  364. [[nodiscard]] constexpr T* allocate(std::size_t n)
  365. {
  366. if (G_MAXSIZE / 2 / sizeof(T) > n) {
  367. throw std::runtime_error("integer overflow");
  368. }
  369. return reinterpret_cast<T*>(rspamd_mempool_alloc(pool, n * sizeof(T)));
  370. }
  371. constexpr void deallocate(T* p, std::size_t n) {
  372. /* Do nothing */
  373. }
  374. private:
  375. rspamd_mempool_t *pool;
  376. };
  377. }
  378. #endif
  379. #endif