4 * Copyright (C) 2001-2004 Sistina Software, Inc. All rights reserved.
5 * Copyright (C) 2004-2006 Red Hat, Inc. All rights reserved.
7 * This file is part of the device-mapper userspace tools.
9 * This copyrighted material is made available to anyone wishing to use,
10 * modify, copy, or redistribute it subject to the terms and conditions
11 * of the GNU Lesser General Public License v.2.1.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software Foundation,
15 * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
27 struct chunk
*chunk
, *spare_chunk
; /* spare_chunk is a one entry free
28 list to stop 'bobbling' */
31 unsigned object_alignment
;
34 void _align_chunk(struct chunk
*c
, unsigned alignment
);
35 struct chunk
*_new_chunk(struct dm_pool
*p
, size_t s
);
37 /* by default things come out aligned for doubles */
38 #define DEFAULT_ALIGNMENT __alignof__ (double)
40 struct dm_pool
*dm_pool_create(const char *name
, size_t chunk_hint
)
42 size_t new_size
= 1024;
43 struct dm_pool
*p
= dm_malloc(sizeof(*p
));
46 log_error("Couldn't create memory pool %s (size %"
47 PRIsize_t
")", name
, sizeof(*p
));
50 memset(p
, 0, sizeof(*p
));
52 /* round chunk_hint up to the next power of 2 */
53 p
->chunk_size
= chunk_hint
+ sizeof(struct chunk
);
54 while (new_size
< p
->chunk_size
)
56 p
->chunk_size
= new_size
;
57 dm_list_add(&_dm_pools
, &p
->list
);
61 void dm_pool_destroy(struct dm_pool
*p
)
64 dm_free(p
->spare_chunk
);
72 dm_list_del(&p
->list
);
76 void *dm_pool_alloc(struct dm_pool
*p
, size_t s
)
78 return dm_pool_alloc_aligned(p
, s
, DEFAULT_ALIGNMENT
);
81 void *dm_pool_alloc_aligned(struct dm_pool
*p
, size_t s
, unsigned alignment
)
83 struct chunk
*c
= p
->chunk
;
88 _align_chunk(c
, alignment
);
90 /* have we got room ? */
91 if (!c
|| (c
->begin
> c
->end
) || (c
->end
- c
->begin
< s
)) {
92 /* allocate new chunk */
93 size_t needed
= s
+ alignment
+ sizeof(struct chunk
);
94 c
= _new_chunk(p
, (needed
> p
->chunk_size
) ?
95 needed
: p
->chunk_size
);
100 _align_chunk(c
, alignment
);
108 void dm_pool_empty(struct dm_pool
*p
)
112 for (c
= p
->chunk
; c
&& c
->prev
; c
= c
->prev
)
116 dm_pool_free(p
, (char *) (c
+ 1));
119 void dm_pool_free(struct dm_pool
*p
, void *ptr
)
121 struct chunk
*c
= p
->chunk
;
124 if (((char *) c
< (char *) ptr
) &&
125 ((char *) c
->end
> (char *) ptr
)) {
131 dm_free(p
->spare_chunk
);
137 log_error("Internal error: pool_free asked to free pointer "
143 int dm_pool_begin_object(struct dm_pool
*p
, size_t hint
)
145 struct chunk
*c
= p
->chunk
;
146 const size_t align
= DEFAULT_ALIGNMENT
;
149 p
->object_alignment
= align
;
152 _align_chunk(c
, align
);
154 if (!c
|| (c
->begin
> c
->end
) || (c
->end
- c
->begin
< hint
)) {
155 /* allocate a new chunk */
157 hint
> (p
->chunk_size
- sizeof(struct chunk
)) ?
158 hint
+ sizeof(struct chunk
) + align
:
164 _align_chunk(c
, align
);
170 int dm_pool_grow_object(struct dm_pool
*p
, const void *extra
, size_t delta
)
172 struct chunk
*c
= p
->chunk
, *nc
;
175 delta
= strlen(extra
);
177 if (c
->end
- (c
->begin
+ p
->object_len
) < delta
) {
178 /* move into a new chunk */
179 if (p
->object_len
+ delta
> (p
->chunk_size
/ 2))
180 nc
= _new_chunk(p
, (p
->object_len
+ delta
) * 2);
182 nc
= _new_chunk(p
, p
->chunk_size
);
187 _align_chunk(p
->chunk
, p
->object_alignment
);
188 memcpy(p
->chunk
->begin
, c
->begin
, p
->object_len
);
192 memcpy(c
->begin
+ p
->object_len
, extra
, delta
);
193 p
->object_len
+= delta
;
197 void *dm_pool_end_object(struct dm_pool
*p
)
199 struct chunk
*c
= p
->chunk
;
201 c
->begin
+= p
->object_len
;
203 p
->object_alignment
= DEFAULT_ALIGNMENT
;
207 void dm_pool_abandon_object(struct dm_pool
*p
)
210 p
->object_alignment
= DEFAULT_ALIGNMENT
;
213 void _align_chunk(struct chunk
*c
, unsigned alignment
)
215 c
->begin
+= alignment
- ((unsigned long) c
->begin
& (alignment
- 1));
218 struct chunk
*_new_chunk(struct dm_pool
*p
, size_t s
)
222 if (p
->spare_chunk
&&
223 ((p
->spare_chunk
->end
- (char *) p
->spare_chunk
) >= s
)) {
224 /* reuse old chunk */
228 if (!(c
= dm_malloc(s
))) {
229 log_error("Out of memory. Requested %" PRIsize_t
234 c
->end
= (char *) c
+ s
;
238 c
->begin
= (char *) (c
+ 1);