udev: String substitutions can be done in ENV, too
[systemd_ALT.git] / src / basic / mempool.c
blob391f29b66785e9a9a90571130982096486d8beb4
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <stdint.h>
4 #include <stdlib.h>
6 #include "format-util.h"
7 #include "macro.h"
8 #include "memory-util.h"
9 #include "mempool.h"
11 struct pool {
12 struct pool *next;
13 size_t n_tiles;
14 size_t n_used;
17 static void* pool_ptr(struct pool *p) {
18 return ((uint8_t*) ASSERT_PTR(p)) + ALIGN(sizeof(struct pool));
21 void* mempool_alloc_tile(struct mempool *mp) {
22 size_t i;
24 /* When a tile is released we add it to the list and simply
25 * place the next pointer at its offset 0. */
27 assert(mp);
28 assert(mp->tile_size >= sizeof(void*));
29 assert(mp->at_least > 0);
31 if (mp->freelist) {
32 void *t;
34 t = mp->freelist;
35 mp->freelist = *(void**) mp->freelist;
36 return t;
39 if (_unlikely_(!mp->first_pool) ||
40 _unlikely_(mp->first_pool->n_used >= mp->first_pool->n_tiles)) {
41 size_t size, n;
42 struct pool *p;
44 n = mp->first_pool ? mp->first_pool->n_tiles : 0;
45 n = MAX(mp->at_least, n * 2);
46 size = PAGE_ALIGN(ALIGN(sizeof(struct pool)) + n*mp->tile_size);
47 n = (size - ALIGN(sizeof(struct pool))) / mp->tile_size;
49 p = malloc(size);
50 if (!p)
51 return NULL;
53 p->next = mp->first_pool;
54 p->n_tiles = n;
55 p->n_used = 0;
57 mp->first_pool = p;
60 i = mp->first_pool->n_used++;
62 return (uint8_t*) pool_ptr(mp->first_pool) + i*mp->tile_size;
65 void* mempool_alloc0_tile(struct mempool *mp) {
66 void *p;
68 p = mempool_alloc_tile(mp);
69 if (p)
70 memzero(p, mp->tile_size);
71 return p;
74 void* mempool_free_tile(struct mempool *mp, void *p) {
75 assert(mp);
77 if (!p)
78 return NULL;
80 *(void**) p = mp->freelist;
81 mp->freelist = p;
83 return NULL;
86 static bool pool_contains(struct mempool *mp, struct pool *p, void *ptr) {
87 size_t off;
88 void *a;
90 assert(mp);
91 assert(p);
93 if (!ptr)
94 return false;
96 a = pool_ptr(p);
97 if ((uint8_t*) ptr < (uint8_t*) a)
98 return false;
100 off = (uint8_t*) ptr - (uint8_t*) a;
101 if (off >= mp->tile_size * p->n_tiles)
102 return false;
104 assert(off % mp->tile_size == 0);
105 return true;
108 static bool pool_is_unused(struct mempool *mp, struct pool *p) {
109 assert(mp);
110 assert(p);
112 if (p->n_used == 0)
113 return true;
115 /* Check if all tiles in this specific pool are in the freelist. */
116 size_t n = 0;
117 void *i = mp->freelist;
118 while (i) {
119 if (pool_contains(mp, p, i))
120 n++;
122 i = *(void**) i;
125 assert(n <= p->n_used);
127 return n == p->n_used;
130 static void pool_unlink(struct mempool *mp, struct pool *p) {
131 size_t m = 0;
133 assert(mp);
134 assert(p);
136 if (p->n_used == 0)
137 return;
139 void **i = &mp->freelist;
140 while (*i) {
141 void *d = *i;
143 if (pool_contains(mp, p, d)) {
144 *i = *(void**) d;
145 m++;
147 if (m == p->n_used)
148 break;
149 } else
150 i = (void**) d;
154 void mempool_trim(struct mempool *mp) {
155 size_t trimmed = 0, left = 0;
157 assert(mp);
159 struct pool **p = &mp->first_pool;
160 while (*p) {
161 struct pool *d = *p;
163 if (pool_is_unused(mp, d)) {
164 trimmed += d->n_tiles * mp->tile_size;
165 pool_unlink(mp, d);
166 *p = d->next;
167 free(d);
168 } else {
169 left += d->n_tiles * mp->tile_size;
170 p = &d->next;
174 log_debug("Trimmed %s from memory pool %p. (%s left)", FORMAT_BYTES(trimmed), mp, FORMAT_BYTES(left));