1 /* -*- Mode: C ; c-basic-offset: 2 -*- */
2 /*****************************************************************************
4 * Non-sleeping memory allocation
5 * This file is part of gmidimonitor
7 * Copyright (C) 2006,2007,2008,2011 Nedko Arnaudov <nedko@arnaudov.name>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; version 2 of the License
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU 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 St, Fifth Floor, Boston, MA 02110-1301 USA.
22 *****************************************************************************/
28 #include "memory_atomic.h"
30 //#define LOG_LEVEL LOG_LEVEL_DEBUG
33 struct rtsafe_memory_pool
36 size_t min_preallocated
;
37 size_t max_preallocated
;
39 struct list_head used
;
40 unsigned int used_count
;
42 struct list_head unused
;
43 unsigned int unused_count
;
46 #define RTSAFE_GROUPS_PREALLOCATE 1024
49 rtsafe_memory_pool_create(
51 size_t min_preallocated
,
52 size_t max_preallocated
,
53 rtsafe_memory_pool_handle
* pool_handle_ptr
)
55 struct rtsafe_memory_pool
* pool_ptr
;
57 assert(min_preallocated
<= max_preallocated
);
59 pool_ptr
= malloc(sizeof(struct rtsafe_memory_pool
));
65 pool_ptr
->data_size
= data_size
;
66 pool_ptr
->min_preallocated
= min_preallocated
;
67 pool_ptr
->max_preallocated
= max_preallocated
;
69 INIT_LIST_HEAD(&pool_ptr
->used
);
70 pool_ptr
->used_count
= 0;
72 INIT_LIST_HEAD(&pool_ptr
->unused
);
73 pool_ptr
->unused_count
= 0;
75 rtsafe_memory_pool_sleepy((rtsafe_memory_pool_handle
)pool_ptr
);
76 *pool_handle_ptr
= pool_ptr
;
81 #define pool_ptr ((struct rtsafe_memory_pool *)pool_handle)
84 rtsafe_memory_pool_destroy(
85 rtsafe_memory_pool_handle pool_handle
)
87 struct list_head
* node_ptr
;
89 assert(pool_ptr
->used_count
== 0); /* called should deallocate all chunks prior releasing pool itself */
90 assert(list_empty(&pool_ptr
->used
));
92 while (pool_ptr
->unused_count
!= 0)
94 assert(!list_empty(&pool_ptr
->unused
));
96 node_ptr
= pool_ptr
->unused
.next
;
99 pool_ptr
->unused_count
--;
104 assert(list_empty(&pool_ptr
->unused
));
109 /* adjust unused list size */
111 rtsafe_memory_pool_sleepy(
112 rtsafe_memory_pool_handle pool_handle
)
114 struct list_head
* node_ptr
;
116 while (pool_ptr
->unused_count
< pool_ptr
->min_preallocated
)
118 node_ptr
= malloc(sizeof(struct list_head
) + pool_ptr
->data_size
);
119 if (node_ptr
== NULL
)
124 list_add_tail(node_ptr
, &pool_ptr
->unused
);
125 pool_ptr
->unused_count
++;
128 while (pool_ptr
->unused_count
> pool_ptr
->max_preallocated
)
130 assert(!list_empty(&pool_ptr
->unused
));
132 node_ptr
= pool_ptr
->unused
.next
;
135 pool_ptr
->unused_count
--;
141 /* find entry in unused list, fail if it is empty */
143 rtsafe_memory_pool_allocate(
144 rtsafe_memory_pool_handle pool_handle
)
146 struct list_head
* node_ptr
;
148 if (list_empty(&pool_ptr
->unused
))
153 node_ptr
= pool_ptr
->unused
.next
;
155 pool_ptr
->unused_count
--;
156 pool_ptr
->used_count
++;
158 return (node_ptr
+ 1);
161 /* move from used to unused list */
163 rtsafe_memory_pool_deallocate(
164 rtsafe_memory_pool_handle pool_handle
,
167 list_add_tail((struct list_head
*)data
- 1, &pool_ptr
->unused
);
168 pool_ptr
->used_count
--;
169 pool_ptr
->unused_count
++;
173 rtsafe_memory_pool_allocate_sleepy(
174 rtsafe_memory_pool_handle pool_handle
)
180 rtsafe_memory_pool_sleepy(pool_handle
);
181 data
= rtsafe_memory_pool_allocate(pool_handle
);
183 while (data
== NULL
);
188 /* max alloc is DATA_MIN * (2 ^ POOLS_COUNT) - DATA_SUB */
189 #define DATA_MIN 1024
190 #define DATA_SUB 100 /* alloc slightly smaller chunks in hope to not allocating additional page for control data */
192 struct rtsafe_memory_pool_generic
195 rtsafe_memory_pool_handle pool
;
200 struct rtsafe_memory_pool_generic
* pools
;
209 rtsafe_memory_handle
* handle_ptr
)
213 struct rtsafe_memory
* memory_ptr
;
215 LOG_DEBUG("rtsafe_memory_init() called.");
217 memory_ptr
= malloc(sizeof(struct rtsafe_memory
));
218 if (memory_ptr
== NULL
)
224 memory_ptr
->pools_count
= 1;
226 while ((size
<< memory_ptr
->pools_count
) < max_size
+ DATA_SUB
)
228 memory_ptr
->pools_count
++;
230 if (memory_ptr
->pools_count
> sizeof(size_t) * 8)
232 assert(0); /* chances that caller really need such huge size are close to zero */
237 memory_ptr
->pools
= malloc(memory_ptr
->pools_count
* sizeof(struct rtsafe_memory_pool_generic
));
238 if (memory_ptr
->pools
== NULL
)
245 for (i
= 0 ; i
< memory_ptr
->pools_count
; i
++)
247 memory_ptr
->pools
[i
].size
= size
- DATA_SUB
;
249 if (!rtsafe_memory_pool_create(
250 memory_ptr
->pools
[i
].size
,
253 &memory_ptr
->pools
[i
].pool
))
258 rtsafe_memory_pool_destroy(memory_ptr
->pools
[i
].pool
);
261 goto fail_free_pools
;
267 *handle_ptr
= (rtsafe_memory_handle
)memory_ptr
;
272 free(memory_ptr
->pools
);
281 #define memory_ptr ((struct rtsafe_memory *)handle_ptr)
283 rtsafe_memory_uninit(
284 rtsafe_memory_handle handle_ptr
)
288 LOG_DEBUG("rtsafe_memory_uninit() called.");
290 for (i
= 0 ; i
< memory_ptr
->pools_count
; i
++)
292 LOG_DEBUG("Destroying pool for size %u", (unsigned int)memory_ptr
->pools
[i
].size
);
293 rtsafe_memory_pool_destroy(memory_ptr
->pools
[i
].pool
);
296 free(memory_ptr
->pools
);
302 rtsafe_memory_allocate(
303 rtsafe_memory_handle handle_ptr
,
306 rtsafe_memory_pool_handle
* data_ptr
;
309 LOG_DEBUG("rtsafe_memory_allocate() called.");
311 /* pool handle is stored just before user data to ease deallocation */
312 size
+= sizeof(rtsafe_memory_pool_handle
);
314 for (i
= 0 ; i
< memory_ptr
->pools_count
; i
++)
316 if (size
<= memory_ptr
->pools
[i
].size
)
318 LOG_DEBUG("Using chunk with size %u.", (unsigned int)memory_ptr
->pools
[i
].size
);
319 data_ptr
= rtsafe_memory_pool_allocate(memory_ptr
->pools
[i
].pool
);
320 if (data_ptr
== NULL
)
322 LOG_DEBUG("rtsafe_memory_pool_allocate() failed.");
326 *data_ptr
= memory_ptr
->pools
[i
].pool
;
328 LOG_DEBUG("rtsafe_memory_allocate() returning %p", (data_ptr
+ 1));
329 return (data_ptr
+ 1);
333 /* data size too big, increase POOLS_COUNT */
334 LOG_WARNING("Data size is too big");
339 rtsafe_memory_sleepy(
340 rtsafe_memory_handle handle_ptr
)
344 for (i
= 0 ; i
< memory_ptr
->pools_count
; i
++)
346 rtsafe_memory_pool_sleepy(memory_ptr
->pools
[i
].pool
);
351 rtsafe_memory_deallocate(
354 LOG_DEBUG("rtsafe_memory_deallocate(%p) called.", data
);
355 rtsafe_memory_pool_deallocate(
356 *((rtsafe_memory_pool_handle
*)data
-1),
357 (rtsafe_memory_pool_handle
*)data
- 1);