2 * Copyright 2006, Haiku Inc.
3 * Copyright 2002, Thomas Kurschel.
5 * Distributed under the terms of the MIT license.
8 /** Memory manager used for graphics mem
10 * It has the following features
11 * - doesn't access memory to be managed
12 * - memory block's owner is identified by tag,
13 * tag is verified during free, and all memory
14 * belonging to one tag can be freed at once
15 * - multi-threading save
18 #include "memory_manager.h"
20 #include <KernelExport.h>
24 //#define TRACE_MEMORY_MANAGER
25 #ifdef TRACE_MEMORY_MANAGER
26 # define TRACE(x) dprintf x
32 // allocated memory block
33 typedef struct mem_block
{
34 struct mem_block
*prev
, *next
;
53 /** merge "block" with successor */
56 merge(mem_info
*mem
, mem_block
*block
)
58 mem_block
*next
= block
->next
;
60 block
->size
+= next
->size
;
63 next
->next
->prev
= block
;
65 block
->next
= next
->next
;
66 next
->next
= mem
->unused
;
71 /** free memory block including merge */
74 freeblock(mem_info
*mem
, mem_block
*block
)
76 mem_block
*prev
, *next
;
78 block
->allocated
= false;
81 if (prev
&& !prev
->allocated
) {
88 if (next
&& !next
->allocated
)
98 /** Init memory manager.
100 * \param start start of address space
101 * \param length length of address space
102 * \param blockSize - granularity
103 * \param heapEntries - maximum number of blocks
107 mem_init(const char* name
, uint32 start
, uint32 length
,
108 uint32 blockSize
, uint32 heapEntries
)
115 TRACE(("mem_init(name=%s, start=%lx, length=%lx, blockSize=%lx, heapEntries=%ld)\n",
116 name
, start
, length
, blockSize
, heapEntries
));
118 mem
= malloc(sizeof(*mem
));
122 mem
->block_size
= blockSize
;
123 mem
->heap_entries
= heapEntries
;
124 mem
->lock
= create_sem(1, name
);
128 // align size to B_PAGE_SIZE
129 size
= heapEntries
* sizeof(mem_block
);
130 size
= (size
+ B_PAGE_SIZE
- 1) & ~(B_PAGE_SIZE
- 1);
132 mem
->heap_area
= create_area(name
, (void **)&mem
->heap
,
133 B_ANY_ADDRESS
, size
, B_FULL_LOCK
, B_READ_AREA
| B_WRITE_AREA
);
135 if (mem
->heap_area
< 0 || mem
->heap
== NULL
)
138 for (i
= 1; i
< heapEntries
; ++i
) {
139 mem
->heap
[i
- 1].next
= &mem
->heap
[i
];
142 mem
->heap
[heapEntries
- 1].next
= NULL
;
143 mem
->unused
= &mem
->heap
[1];
145 first
= &mem
->heap
[0];
149 first
->size
= length
;
150 first
->prev
= first
->next
= NULL
;
151 first
->allocated
= false;
156 delete_sem(mem
->lock
);
167 mem_destroy(mem_info
*mem
)
169 TRACE(("mem_destroy(mem %p)\n", mem
));
171 delete_area(mem
->heap_area
);
172 delete_sem(mem
->lock
);
177 /** Allocate memory block
179 * \param mem heap handle
180 * \param size size in bytes
181 * \param tag owner tag
183 * \param blockID - returns block id
184 * \param offset - returns start address of block
188 mem_alloc(mem_info
*mem
, uint32 size
, void *tag
, uint32
*blockID
, uint32
*offset
)
190 mem_block
*current
, *newEntry
;
193 TRACE(("mem_alloc(mem %p, size=%lx, tag=%p)\n", mem
, size
, tag
));
195 status
= acquire_sem(mem
->lock
);
199 // we assume block_size is power of two
200 size
= (size
+ mem
->block_size
- 1) & ~(mem
->block_size
- 1);
203 for (current
= mem
->first
; current
; current
= current
->next
) {
204 if (!current
->allocated
&& current
->size
>= size
)
208 if (current
== NULL
) {
209 TRACE(("mem_alloc: out of memory\n"));
213 if (size
!= current
->size
) {
214 newEntry
= mem
->unused
;
216 if (newEntry
== NULL
) {
217 TRACE(("mem_alloc: out of blocks\n"));
221 mem
->unused
= newEntry
->next
;
223 newEntry
->next
= current
->next
;
224 newEntry
->prev
= current
;
225 newEntry
->allocated
= false;
226 newEntry
->base
= current
->base
+ size
;
227 newEntry
->size
= current
->size
- size
;
230 current
->next
->prev
= newEntry
;
232 current
->next
= newEntry
;
233 current
->size
= size
;
236 current
->allocated
= true;
239 *blockID
= current
- mem
->heap
+ 1;
240 *offset
= current
->base
;
242 release_sem(mem
->lock
);
244 TRACE(("mem_alloc(block_id=%ld, offset=%lx)\n", *blockID
, *offset
));
248 release_sem(mem
->lock
);
254 * \param mem heap handle
255 * \param blockID block id
256 * \param tag owner tag (must match tag passed to mem_alloc())
260 mem_free(mem_info
*mem
, uint32 blockID
, void *tag
)
265 TRACE(("mem_free(mem %p, blockID=%ld, tag=%p)\n", mem
, blockID
, tag
));
267 status
= acquire_sem(mem
->lock
);
273 if (blockID
>= mem
->heap_entries
) {
274 TRACE(("mem_free: invalid ID %lu\n", blockID
));
278 block
= &mem
->heap
[blockID
];
279 if (!block
->allocated
|| block
->tag
!= tag
) {
280 TRACE(("mem_free: not owner\n"));
284 freeblock(mem
, block
);
286 release_sem(mem
->lock
);
290 release_sem(mem
->lock
);
295 /** Free all memory belonging to owner "tag" */
298 mem_freetag(mem_info
*mem
, void *tag
)
303 TRACE(("mem_freetag(mem %p, tag=%p)\n", mem
, tag
));
305 status
= acquire_sem(mem
->lock
);
309 for (current
= mem
->first
; current
; current
= current
->next
) {
310 if (current
->allocated
&& current
->tag
== tag
)
311 current
= freeblock(mem
, current
);
314 release_sem(mem
->lock
);