4 * Purple is the legal property of its developers, whose names are too
5 * numerous to list here. Please refer to the COPYRIGHT file distributed
6 * with this source distribution
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or (at
11 * your option) any later version.
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1301 USA
23 #include "memorypool.h"
27 #define PURPLE_MEMORY_POOL_BLOCK_PADDING (sizeof(guint64))
28 #define PURPLE_MEMORY_POINTER_SHIFT(pointer, value) \
29 (gpointer)((guintptr)(pointer) + (value))
30 #define PURPLE_MEMORY_PADDED(pointer, padding) \
31 (gpointer)((((guintptr)(pointer) - 1) / (padding) + 1) * padding)
33 #define PURPLE_MEMORY_POOL_DEFAULT_BLOCK_SIZE 1024
34 #define PURPLE_MEMORY_POOL_DISABLED FALSE
36 typedef struct _PurpleMemoryPoolBlock PurpleMemoryPoolBlock
;
43 PurpleMemoryPoolBlock
*first_block
;
44 PurpleMemoryPoolBlock
*last_block
;
45 } PurpleMemoryPoolPrivate
;
47 struct _PurpleMemoryPoolBlock
49 gpointer available_ptr
;
51 PurpleMemoryPoolBlock
*next
;
61 static GParamSpec
*properties
[PROP_LAST
];
63 G_DEFINE_TYPE_WITH_PRIVATE(PurpleMemoryPool
, purple_memory_pool
,
66 /*******************************************************************************
67 * Memory allocation/deallocation
68 ******************************************************************************/
70 static PurpleMemoryPoolBlock
*
71 purple_memory_pool_block_new(gulong block_size
)
74 PurpleMemoryPoolBlock
*block
;
77 /* ceil block struct size to the multipy of align */
78 total_size
= ((sizeof(PurpleMemoryPoolBlock
) - 1) /
79 PURPLE_MEMORY_POOL_BLOCK_PADDING
+ 1) *
80 sizeof(PurpleMemoryPoolBlock
);
81 g_return_val_if_fail(block_size
< G_MAXSIZE
- total_size
, NULL
);
82 total_size
+= block_size
;
84 block_raw
= g_try_malloc(total_size
);
85 g_return_val_if_fail(block_raw
!= NULL
, NULL
);
88 /* in fact, we don't set available_ptr padded to
89 * PURPLE_MEMORY_POOL_BLOCK_PADDING, but we guarantee, there is at least
90 * block_size long block if padded to that value. */
91 block
->available_ptr
= PURPLE_MEMORY_POINTER_SHIFT(block_raw
,
92 sizeof(PurpleMemoryPoolBlock
));
93 block
->end_ptr
= PURPLE_MEMORY_POINTER_SHIFT(block_raw
, total_size
);
100 purple_memory_pool_alloc_impl(PurpleMemoryPool
*pool
, gsize size
, guint alignment
)
102 PurpleMemoryPoolPrivate
*priv
= NULL
;
103 PurpleMemoryPoolBlock
*blk
;
106 g_return_val_if_fail(PURPLE_IS_MEMORY_POOL(pool
), NULL
);
108 priv
= purple_memory_pool_get_instance_private(pool
);
110 if (priv
->disabled
) {
111 /* XXX: this may cause some leaks */
112 return g_try_malloc(size
);
115 g_return_val_if_fail(alignment
<= PURPLE_MEMORY_POOL_BLOCK_PADDING
, NULL
);
116 g_warn_if_fail(alignment
>= 1);
120 blk
= priv
->last_block
;
123 mem
= PURPLE_MEMORY_PADDED(blk
->available_ptr
, alignment
);
124 if (mem
>= blk
->end_ptr
)
126 else if (mem
< blk
->available_ptr
) /* gpointer overflow */
128 else if (PURPLE_MEMORY_POINTER_SHIFT(mem
, size
) >= blk
->end_ptr
)
133 gsize real_size
= priv
->block_size
;
134 if (real_size
< size
)
136 blk
= purple_memory_pool_block_new(real_size
);
137 g_return_val_if_fail(blk
!= NULL
, NULL
);
139 g_assert((priv
->first_block
== NULL
) ==
140 (priv
->last_block
== NULL
));
142 if (priv
->first_block
== NULL
) {
143 priv
->first_block
= blk
;
144 priv
->last_block
= blk
;
146 priv
->last_block
->next
= blk
;
147 priv
->last_block
= blk
;
150 mem
= PURPLE_MEMORY_PADDED(blk
->available_ptr
, alignment
);
151 g_assert((guintptr
)mem
+ size
< (guintptr
)blk
->end_ptr
);
152 g_assert(mem
>= blk
->available_ptr
); /* gpointer overflow */
155 g_assert(blk
!= NULL
);
156 g_assert(mem
!= NULL
);
158 blk
->available_ptr
= PURPLE_MEMORY_POINTER_SHIFT(mem
, size
);
159 g_assert(blk
->available_ptr
<= blk
->end_ptr
);
165 purple_memory_pool_cleanup_impl(PurpleMemoryPool
*pool
)
167 PurpleMemoryPoolPrivate
*priv
=
168 purple_memory_pool_get_instance_private(pool
);
169 PurpleMemoryPoolBlock
*blk
;
171 blk
= priv
->first_block
;
172 priv
->first_block
= NULL
;
173 priv
->last_block
= NULL
;
175 PurpleMemoryPoolBlock
*next
= blk
->next
;
182 /*******************************************************************************
184 ******************************************************************************/
187 purple_memory_pool_set_block_size(PurpleMemoryPool
*pool
, gulong block_size
)
189 PurpleMemoryPoolPrivate
*priv
= NULL
;
191 g_return_if_fail(PURPLE_IS_MEMORY_POOL(pool
));
193 priv
= purple_memory_pool_get_instance_private(pool
);
194 priv
->block_size
= block_size
;
195 g_object_notify_by_pspec(G_OBJECT(pool
), properties
[PROP_BLOCK_SIZE
]);
199 purple_memory_pool_alloc(PurpleMemoryPool
*pool
, gsize size
, guint alignment
)
201 PurpleMemoryPoolClass
*klass
;
206 g_return_val_if_fail(PURPLE_IS_MEMORY_POOL(pool
), NULL
);
208 klass
= PURPLE_MEMORY_POOL_GET_CLASS(pool
);
209 g_return_val_if_fail(klass
!= NULL
, NULL
);
210 g_return_val_if_fail(klass
->palloc
!= NULL
, NULL
);
212 return klass
->palloc(pool
, size
, alignment
);
216 purple_memory_pool_alloc0(PurpleMemoryPool
*pool
, gsize size
, guint alignment
)
223 mem
= purple_memory_pool_alloc(pool
, size
, alignment
);
224 g_return_val_if_fail(mem
!= NULL
, NULL
);
226 memset(mem
, 0, size
);
232 purple_memory_pool_free(PurpleMemoryPool
*pool
, gpointer mem
)
234 PurpleMemoryPoolClass
*klass
;
239 g_return_if_fail(PURPLE_IS_MEMORY_POOL(pool
));
241 klass
= PURPLE_MEMORY_POOL_GET_CLASS(pool
);
242 g_return_if_fail(klass
!= NULL
);
245 klass
->pfree(pool
, mem
);
249 purple_memory_pool_cleanup(PurpleMemoryPool
*pool
)
251 PurpleMemoryPoolClass
*klass
;
253 g_return_if_fail(PURPLE_IS_MEMORY_POOL(pool
));
255 klass
= PURPLE_MEMORY_POOL_GET_CLASS(pool
);
256 g_return_if_fail(klass
!= NULL
);
258 klass
->cleanup(pool
);
262 /*******************************************************************************
264 ******************************************************************************/
267 purple_memory_pool_new(void)
269 return g_object_new(PURPLE_TYPE_MEMORY_POOL
, NULL
);
273 purple_memory_pool_init(PurpleMemoryPool
*pool
)
275 PurpleMemoryPoolPrivate
*priv
=
276 purple_memory_pool_get_instance_private(pool
);
278 priv
->disabled
= PURPLE_MEMORY_POOL_DISABLED
;
282 purple_memory_pool_finalize(GObject
*obj
)
284 purple_memory_pool_cleanup(PURPLE_MEMORY_POOL(obj
));
286 G_OBJECT_CLASS(purple_memory_pool_parent_class
)->finalize(obj
);
290 purple_memory_pool_get_property(GObject
*obj
, guint param_id
, GValue
*value
,
293 PurpleMemoryPool
*pool
= PURPLE_MEMORY_POOL(obj
);
294 PurpleMemoryPoolPrivate
*priv
=
295 purple_memory_pool_get_instance_private(pool
);
298 case PROP_BLOCK_SIZE
:
299 g_value_set_ulong(value
, priv
->block_size
);
302 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
307 purple_memory_pool_set_property(GObject
*obj
, guint param_id
,
308 const GValue
*value
, GParamSpec
*pspec
)
310 PurpleMemoryPool
*pool
= PURPLE_MEMORY_POOL(obj
);
311 PurpleMemoryPoolPrivate
*priv
=
312 purple_memory_pool_get_instance_private(pool
);
315 case PROP_BLOCK_SIZE
:
316 priv
->block_size
= g_value_get_ulong(value
);
319 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
324 purple_memory_pool_class_init(PurpleMemoryPoolClass
*klass
)
326 GObjectClass
*obj_class
= G_OBJECT_CLASS(klass
);
328 obj_class
->finalize
= purple_memory_pool_finalize
;
329 obj_class
->get_property
= purple_memory_pool_get_property
;
330 obj_class
->set_property
= purple_memory_pool_set_property
;
332 klass
->palloc
= purple_memory_pool_alloc_impl
;
333 klass
->cleanup
= purple_memory_pool_cleanup_impl
;
335 properties
[PROP_BLOCK_SIZE
] = g_param_spec_ulong("block-size",
336 "Block size", "The default size of each block of pool memory.",
337 0, G_MAXULONG
, PURPLE_MEMORY_POOL_DEFAULT_BLOCK_SIZE
,
338 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
| G_PARAM_STATIC_STRINGS
);
340 g_object_class_install_properties(obj_class
, PROP_LAST
, properties
);
344 purple_memory_pool_strdup(PurpleMemoryPool
*pool
, const gchar
*str
)
352 g_return_val_if_fail(PURPLE_IS_MEMORY_POOL(pool
), NULL
);
354 str_len
= strlen(str
);
355 str_dup
= purple_memory_pool_alloc(pool
, str_len
+ 1, sizeof(gchar
));
356 g_return_val_if_fail(str_dup
!= NULL
, NULL
);
358 memcpy(str_dup
, str
, str_len
);
359 str_dup
[str_len
] = '\0';