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_GET_PRIVATE(obj) \
28 (G_TYPE_INSTANCE_GET_PRIVATE((obj), PURPLE_TYPE_MEMORY_POOL, PurpleMemoryPoolPrivate))
29 #define PURPLE_MEMORY_POOL_BLOCK_PADDING (sizeof(guint64))
30 #define PURPLE_MEMORY_POINTER_SHIFT(pointer, value) \
31 (gpointer)((guintptr)(pointer) + (value))
32 #define PURPLE_MEMORY_PADDED(pointer, padding) \
33 (gpointer)((((guintptr)(pointer) - 1) / (padding) + 1) * padding)
35 #define PURPLE_MEMORY_POOL_DEFAULT_BLOCK_SIZE 1024
36 #define PURPLE_MEMORY_POOL_DISABLED FALSE
38 typedef struct _PurpleMemoryPoolBlock PurpleMemoryPoolBlock
;
45 PurpleMemoryPoolBlock
*first_block
;
46 PurpleMemoryPoolBlock
*last_block
;
47 } PurpleMemoryPoolPrivate
;
49 struct _PurpleMemoryPoolBlock
51 gpointer available_ptr
;
53 PurpleMemoryPoolBlock
*next
;
63 static GObjectClass
*parent_class
= NULL
;
64 static GParamSpec
*properties
[PROP_LAST
];
67 /*******************************************************************************
68 * Memory allocation/deallocation
69 ******************************************************************************/
71 static PurpleMemoryPoolBlock
*
72 purple_memory_pool_block_new(gulong block_size
)
75 PurpleMemoryPoolBlock
*block
;
78 /* ceil block struct size to the multipy of align */
79 total_size
= ((sizeof(PurpleMemoryPoolBlock
) - 1) /
80 PURPLE_MEMORY_POOL_BLOCK_PADDING
+ 1) *
81 sizeof(PurpleMemoryPoolBlock
);
82 g_return_val_if_fail(block_size
< G_MAXSIZE
- total_size
, NULL
);
83 total_size
+= block_size
;
85 block_raw
= g_try_malloc(total_size
);
86 g_return_val_if_fail(block_raw
!= NULL
, NULL
);
89 /* in fact, we don't set available_ptr padded to
90 * PURPLE_MEMORY_POOL_BLOCK_PADDING, but we guarantee, there is at least
91 * block_size long block if padded to that value. */
92 block
->available_ptr
= PURPLE_MEMORY_POINTER_SHIFT(block_raw
,
93 sizeof(PurpleMemoryPoolBlock
));
94 block
->end_ptr
= PURPLE_MEMORY_POINTER_SHIFT(block_raw
, total_size
);
101 purple_memory_pool_alloc_impl(PurpleMemoryPool
*pool
, gsize size
, guint alignment
)
103 PurpleMemoryPoolPrivate
*priv
= PURPLE_MEMORY_POOL_GET_PRIVATE(pool
);
104 PurpleMemoryPoolBlock
*blk
;
107 g_return_val_if_fail(priv
!= NULL
, NULL
);
109 if (priv
->disabled
) {
110 /* XXX: this may cause some leaks */
111 return g_try_malloc(size
);
114 g_return_val_if_fail(alignment
<= PURPLE_MEMORY_POOL_BLOCK_PADDING
, NULL
);
115 g_warn_if_fail(alignment
>= 1);
119 blk
= priv
->last_block
;
122 mem
= PURPLE_MEMORY_PADDED(blk
->available_ptr
, alignment
);
123 if (mem
>= blk
->end_ptr
)
125 else if (mem
< blk
->available_ptr
) /* gpointer overflow */
127 else if (PURPLE_MEMORY_POINTER_SHIFT(mem
, size
) >= blk
->end_ptr
)
132 gsize real_size
= priv
->block_size
;
133 if (real_size
< size
)
135 blk
= purple_memory_pool_block_new(real_size
);
136 g_return_val_if_fail(blk
!= NULL
, NULL
);
138 g_assert((priv
->first_block
== NULL
) ==
139 (priv
->last_block
== NULL
));
141 if (priv
->first_block
== NULL
) {
142 priv
->first_block
= blk
;
143 priv
->last_block
= blk
;
145 priv
->last_block
->next
= blk
;
146 priv
->last_block
= blk
;
149 mem
= PURPLE_MEMORY_PADDED(blk
->available_ptr
, alignment
);
150 g_assert((guintptr
)mem
+ size
< (guintptr
)blk
->end_ptr
);
151 g_assert(mem
>= blk
->available_ptr
); /* gpointer overflow */
154 g_assert(blk
!= NULL
);
155 g_assert(mem
!= NULL
);
157 blk
->available_ptr
= PURPLE_MEMORY_POINTER_SHIFT(mem
, size
);
158 g_assert(blk
->available_ptr
<= blk
->end_ptr
);
164 purple_memory_pool_cleanup_impl(PurpleMemoryPool
*pool
)
166 PurpleMemoryPoolPrivate
*priv
= PURPLE_MEMORY_POOL_GET_PRIVATE(pool
);
167 PurpleMemoryPoolBlock
*blk
;
169 g_return_if_fail(priv
!= NULL
);
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
= PURPLE_MEMORY_POOL_GET_PRIVATE(pool
);
191 g_return_if_fail(priv
!= NULL
);
193 priv
->block_size
= block_size
;
194 g_object_notify_by_pspec(G_OBJECT(pool
), properties
[PROP_BLOCK_SIZE
]);
198 purple_memory_pool_alloc(PurpleMemoryPool
*pool
, gsize size
, guint alignment
)
200 PurpleMemoryPoolClass
*klass
;
205 g_return_val_if_fail(PURPLE_IS_MEMORY_POOL(pool
), NULL
);
207 klass
= PURPLE_MEMORY_POOL_GET_CLASS(pool
);
208 g_return_val_if_fail(klass
!= NULL
, NULL
);
209 g_return_val_if_fail(klass
->palloc
!= NULL
, NULL
);
211 return klass
->palloc(pool
, size
, alignment
);
215 purple_memory_pool_alloc0(PurpleMemoryPool
*pool
, gsize size
, guint alignment
)
222 mem
= purple_memory_pool_alloc(pool
, size
, alignment
);
223 g_return_val_if_fail(mem
!= NULL
, NULL
);
225 memset(mem
, 0, size
);
231 purple_memory_pool_free(PurpleMemoryPool
*pool
, gpointer mem
)
233 PurpleMemoryPoolClass
*klass
;
238 g_return_if_fail(PURPLE_IS_MEMORY_POOL(pool
));
240 klass
= PURPLE_MEMORY_POOL_GET_CLASS(pool
);
241 g_return_if_fail(klass
!= NULL
);
244 klass
->pfree(pool
, mem
);
248 purple_memory_pool_cleanup(PurpleMemoryPool
*pool
)
250 PurpleMemoryPoolClass
*klass
;
252 g_return_if_fail(PURPLE_IS_MEMORY_POOL(pool
));
254 klass
= PURPLE_MEMORY_POOL_GET_CLASS(pool
);
255 g_return_if_fail(klass
!= NULL
);
257 klass
->cleanup(pool
);
261 /*******************************************************************************
263 ******************************************************************************/
266 purple_memory_pool_new(void)
268 return g_object_new(PURPLE_TYPE_MEMORY_POOL
, NULL
);
272 purple_memory_pool_init(GTypeInstance
*instance
, gpointer klass
)
274 PurpleMemoryPool
*pool
= PURPLE_MEMORY_POOL(instance
);
275 PurpleMemoryPoolPrivate
*priv
= PURPLE_MEMORY_POOL_GET_PRIVATE(pool
);
277 priv
->disabled
= PURPLE_MEMORY_POOL_DISABLED
;
281 purple_memory_pool_finalize(GObject
*obj
)
283 purple_memory_pool_cleanup(PURPLE_MEMORY_POOL(obj
));
285 G_OBJECT_CLASS(parent_class
)->finalize(obj
);
289 purple_memory_pool_get_property(GObject
*obj
, guint param_id
, GValue
*value
,
292 PurpleMemoryPool
*pool
= PURPLE_MEMORY_POOL(obj
);
293 PurpleMemoryPoolPrivate
*priv
= PURPLE_MEMORY_POOL_GET_PRIVATE(pool
);
296 case PROP_BLOCK_SIZE
:
297 g_value_set_ulong(value
, priv
->block_size
);
300 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
305 purple_memory_pool_set_property(GObject
*obj
, guint param_id
,
306 const GValue
*value
, GParamSpec
*pspec
)
308 PurpleMemoryPool
*pool
= PURPLE_MEMORY_POOL(obj
);
309 PurpleMemoryPoolPrivate
*priv
= PURPLE_MEMORY_POOL_GET_PRIVATE(pool
);
312 case PROP_BLOCK_SIZE
:
313 priv
->block_size
= g_value_get_ulong(value
);
316 G_OBJECT_WARN_INVALID_PROPERTY_ID(obj
, param_id
, pspec
);
321 purple_memory_pool_class_init(PurpleMemoryPoolClass
*klass
)
323 GObjectClass
*obj_class
= G_OBJECT_CLASS(klass
);
325 parent_class
= g_type_class_peek_parent(klass
);
327 g_type_class_add_private(klass
, sizeof(PurpleMemoryPoolPrivate
));
329 obj_class
->finalize
= purple_memory_pool_finalize
;
330 obj_class
->get_property
= purple_memory_pool_get_property
;
331 obj_class
->set_property
= purple_memory_pool_set_property
;
333 klass
->palloc
= purple_memory_pool_alloc_impl
;
334 klass
->cleanup
= purple_memory_pool_cleanup_impl
;
336 properties
[PROP_BLOCK_SIZE
] = g_param_spec_ulong("block-size",
337 "Block size", "The default size of each block of pool memory.",
338 0, G_MAXULONG
, PURPLE_MEMORY_POOL_DEFAULT_BLOCK_SIZE
,
339 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT
| G_PARAM_STATIC_STRINGS
);
341 g_object_class_install_properties(obj_class
, PROP_LAST
, properties
);
345 purple_memory_pool_get_type(void)
347 static GType type
= 0;
349 if (G_UNLIKELY(type
== 0)) {
350 static const GTypeInfo info
= {
351 .class_size
= sizeof(PurpleMemoryPoolClass
),
352 .class_init
= (GClassInitFunc
)purple_memory_pool_class_init
,
353 .instance_size
= sizeof(PurpleMemoryPool
),
354 .instance_init
= (GInstanceInitFunc
)purple_memory_pool_init
357 type
= g_type_register_static(G_TYPE_OBJECT
,
358 "PurpleMemoryPool", &info
, 0);
365 purple_memory_pool_strdup(PurpleMemoryPool
*pool
, const gchar
*str
)
373 g_return_val_if_fail(PURPLE_IS_MEMORY_POOL(pool
), NULL
);
375 str_len
= strlen(str
);
376 str_dup
= purple_memory_pool_alloc(pool
, str_len
+ 1, sizeof(gchar
));
377 g_return_val_if_fail(str_dup
!= NULL
, NULL
);
379 memcpy(str_dup
, str
, str_len
);
380 str_dup
[str_len
] = '\0';