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.

преди 15 години
преди 15 години
преди 5 години
преди 5 години
преди 5 години
преди 5 години
преди 5 години
преди 5 години
преди 2 години
преди 10 години
преди 10 години
преди 8 години
преди 8 години
преди 15 години
преди 8 години
преди 10 години
преди 15 години
преди 6 години
преди 10 години
преди 15 години
преди 10 години
преди 15 години
преди 4 години
преди 4 години
преди 10 години
преди 15 години
преди 3 години
преди 4 години
преди 3 години
преди 2 години
преди 3 години
преди 15 години
преди 3 години
преди 4 години
преди 3 години
преди 2 години
преди 15 години
преди 4 години
преди 3 години
преди 4 години
преди 3 години
преди 4 години
преди 4 години
преди 8 години
преди 4 години
преди 3 години
преди 8 години
преди 15 години
преди 3 години
преди 4 години
преди 3 години
преди 4 години
преди 15 години
преди 10 години
преди 10 години
преди 3 години
преди 15 години
преди 10 години
преди 3 години
преди 15 години
преди 10 години
преди 10 години
преди 15 години
преди 15 години
преди 10 години
преди 15 години
преди 10 години
преди 15 години
преди 15 години
преди 15 години
преди 10 години
преди 15 години
преди 15 години
преди 10 години
преди 15 години
преди 10 години
преди 15 години
преди 10 години
преди 15 години
преди 10 години
преди 15 години
преди 10 години
преди 2 години
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