1ccedee22SAxel Dörfler/*
2ccedee22SAxel Dörfler * Copyright 2009, Axel D��rfler, axeld@pinc-software.de.
3ccedee22SAxel Dörfler * Distributed under the terms of the MIT License.
4ccedee22SAxel Dörfler */
5ccedee22SAxel Dörfler
6ccedee22SAxel Dörfler
7ccedee22SAxel Dörfler/*!	A simple allocator that works directly on an area, based on the boot
8ccedee22SAxel Dörfler	loader's heap. See there for more information about its inner workings.
9ccedee22SAxel Dörfler*/
10ccedee22SAxel Dörfler
1152a38012Sejakowatz
1252a38012Sejakowatz#include <RealtimeAlloc.h>
13ccedee22SAxel Dörfler
14ccedee22SAxel Dörfler#include <pthread.h>
156e927a5fSIngo Weinhold#include <stdlib.h>
16ccedee22SAxel Dörfler#include <stdio.h>
174ae9d7d0SRene Gollent#include <string.h>
1852a38012Sejakowatz
19ccedee22SAxel Dörfler#include <OS.h>
2052a38012Sejakowatz
21ccedee22SAxel Dörfler#include <locks.h>
22ccedee22SAxel Dörfler#include <kernel/util/DoublyLinkedList.h>
23ccedee22SAxel Dörfler
24ccedee22SAxel Dörfler
25ccedee22SAxel Dörfler//#define TRACE_RTM
26ccedee22SAxel Dörfler#ifdef TRACE_RTM
27ccedee22SAxel Dörfler#	define TRACE(x...) printf(x);
28ccedee22SAxel Dörfler#else
29ccedee22SAxel Dörfler#	define TRACE(x...) ;
30ccedee22SAxel Dörfler#endif
31ccedee22SAxel Dörfler
32ccedee22SAxel Dörfler
33ccedee22SAxel Dörflerclass FreeChunk {
34ccedee22SAxel Dörflerpublic:
35ccedee22SAxel Dörfler			void				SetTo(size_t size, FreeChunk* next);
36ccedee22SAxel Dörfler
37ccedee22SAxel Dörfler			uint32				Size() const;
38ccedee22SAxel Dörfler			uint32				CompleteSize() const { return fSize; }
39ccedee22SAxel Dörfler
40ccedee22SAxel Dörfler			FreeChunk*			Next() const { return fNext; }
41ccedee22SAxel Dörfler			void				SetNext(FreeChunk* next) { fNext = next; }
42ccedee22SAxel Dörfler
43ccedee22SAxel Dörfler			FreeChunk*			Split(uint32 splitSize);
44ccedee22SAxel Dörfler			bool				IsTouching(FreeChunk* link);
45ccedee22SAxel Dörfler			FreeChunk*			Join(FreeChunk* link);
46ccedee22SAxel Dörfler			void				Remove(rtm_pool* pool,
47ccedee22SAxel Dörfler									FreeChunk* previous = NULL);
48ccedee22SAxel Dörfler			void				Enqueue(rtm_pool* pool);
49ccedee22SAxel Dörfler
50ccedee22SAxel Dörfler			void*				AllocatedAddress() const;
51ccedee22SAxel Dörfler	static	FreeChunk*			SetToAllocated(void* allocated);
521fe06744SJerome Duval	static	addr_t				NextOffset() { return sizeof(size_t); }
53ccedee22SAxel Dörfler
54ccedee22SAxel Dörflerprivate:
551fe06744SJerome Duval			size_t				fSize;
56ccedee22SAxel Dörfler			FreeChunk*			fNext;
5752a38012Sejakowatz};
5852a38012Sejakowatz
59ccedee22SAxel Dörfler
60ccedee22SAxel Dörflerstruct rtm_pool : DoublyLinkedListLinkImpl<rtm_pool> {
61ccedee22SAxel Dörfler	area_id		area;
62ccedee22SAxel Dörfler	void*		heap_base;
63ccedee22SAxel Dörfler	size_t		max_size;
64ccedee22SAxel Dörfler	size_t		available;
65ccedee22SAxel Dörfler	FreeChunk	free_anchor;
66ccedee22SAxel Dörfler	mutex		lock;
67ccedee22SAxel Dörfler
68ccedee22SAxel Dörfler	bool Contains(void* buffer) const;
69ccedee22SAxel Dörfler	void Free(void* buffer);
7052a38012Sejakowatz};
7152a38012Sejakowatz
72ccedee22SAxel Dörflertypedef DoublyLinkedList<rtm_pool> PoolList;
73ca087074SMarcus Overhagen
74ccedee22SAxel Dörfler
75ccedee22SAxel Dörflerconst static uint32 kAlignment = 256;
76ccedee22SAxel Dörfler	// all memory chunks will be a multiple of this
77ccedee22SAxel Dörfler
78f7127458SIngo Weinholdstatic mutex sPoolsLock = MUTEX_INITIALIZER("rtm pools");
79ccedee22SAxel Dörflerstatic PoolList sPools;
80ccedee22SAxel Dörfler
81ccedee22SAxel Dörfler
82ccedee22SAxel Dörflervoid
83ccedee22SAxel DörflerFreeChunk::SetTo(size_t size, FreeChunk* next)
8452a38012Sejakowatz{
85ccedee22SAxel Dörfler	fSize = size;
86ccedee22SAxel Dörfler	fNext = next;
8752a38012Sejakowatz}
8852a38012Sejakowatz
89ca087074SMarcus Overhagen
90ccedee22SAxel Dörfler/*!	Returns the amount of bytes that can be allocated
91ccedee22SAxel Dörfler	in this chunk.
92ccedee22SAxel Dörfler*/
93ccedee22SAxel Dörfleruint32
94ccedee22SAxel DörflerFreeChunk::Size() const
9552a38012Sejakowatz{
96ccedee22SAxel Dörfler	return fSize - FreeChunk::NextOffset();
9752a38012Sejakowatz}
9852a38012Sejakowatz
99ca087074SMarcus Overhagen
100ccedee22SAxel Dörfler/*!	Splits the upper half at the requested location
101ccedee22SAxel Dörfler	and returns it.
102ccedee22SAxel Dörfler*/
103ccedee22SAxel DörflerFreeChunk*
104ccedee22SAxel DörflerFreeChunk::Split(uint32 splitSize)
10552a38012Sejakowatz{
106ccedee22SAxel Dörfler	splitSize = (splitSize - 1 + kAlignment) & ~(kAlignment - 1);
107ccedee22SAxel Dörfler
108ccedee22SAxel Dörfler	FreeChunk* chunk
109ccedee22SAxel Dörfler		= (FreeChunk*)((uint8*)this + FreeChunk::NextOffset() + splitSize);
110ccedee22SAxel Dörfler	chunk->fSize = fSize - splitSize - FreeChunk::NextOffset();
111ccedee22SAxel Dörfler	chunk->fNext = fNext;
112ccedee22SAxel Dörfler
113ccedee22SAxel Dörfler	fSize = splitSize + FreeChunk::NextOffset();
114ccedee22SAxel Dörfler
115ccedee22SAxel Dörfler	return chunk;
11652a38012Sejakowatz}
11752a38012Sejakowatz
118ca087074SMarcus Overhagen
119ccedee22SAxel Dörfler/*!	Checks if the specified chunk touches this chunk, so
120ccedee22SAxel Dörfler	that they could be joined.
121ccedee22SAxel Dörfler*/
122ccedee22SAxel Dörflerbool
123ccedee22SAxel DörflerFreeChunk::IsTouching(FreeChunk* chunk)
12452a38012Sejakowatz{
125ccedee22SAxel Dörfler	return chunk
126ccedee22SAxel Dörfler		&& (((uint8*)this + fSize == (uint8*)chunk)
127ccedee22SAxel Dörfler			|| (uint8*)chunk + chunk->fSize == (uint8*)this);
12852a38012Sejakowatz}
12952a38012Sejakowatz
130ca087074SMarcus Overhagen
131ccedee22SAxel Dörfler/*!	Joins the chunk to this chunk and returns the pointer
132ccedee22SAxel Dörfler	to the new chunk - which will either be one of the
133ccedee22SAxel Dörfler	two chunks.
134ccedee22SAxel Dörfler	Note, the chunks must be joinable, or else this method
135ccedee22SAxel Dörfler	doesn't work correctly. Use FreeChunk::IsTouching()
136ccedee22SAxel Dörfler	to check if this method can be applied.
137ccedee22SAxel Dörfler*/
138ccedee22SAxel DörflerFreeChunk*
139ccedee22SAxel DörflerFreeChunk::Join(FreeChunk* chunk)
140ccedee22SAxel Dörfler{
141ccedee22SAxel Dörfler	if (chunk < this) {
142ccedee22SAxel Dörfler		chunk->fSize += fSize;
143ccedee22SAxel Dörfler		chunk->fNext = fNext;
144ccedee22SAxel Dörfler
145ccedee22SAxel Dörfler		return chunk;
146ccedee22SAxel Dörfler	}
147ccedee22SAxel Dörfler
148ccedee22SAxel Dörfler	fSize += chunk->fSize;
149ccedee22SAxel Dörfler	fNext = chunk->fNext;
150ccedee22SAxel Dörfler
151ccedee22SAxel Dörfler	return this;
152ccedee22SAxel Dörfler}
153ccedee22SAxel Dörfler
154ccedee22SAxel Dörfler
155ccedee22SAxel Dörflervoid
156ccedee22SAxel DörflerFreeChunk::Remove(rtm_pool* pool, FreeChunk* previous)
157ccedee22SAxel Dörfler{
158ccedee22SAxel Dörfler	if (previous == NULL) {
159ccedee22SAxel Dörfler		// find the previous chunk in the list
160ccedee22SAxel Dörfler		FreeChunk* chunk = pool->free_anchor.fNext;
161ccedee22SAxel Dörfler
162ccedee22SAxel Dörfler		while (chunk != NULL && chunk != this) {
163ccedee22SAxel Dörfler			previous = chunk;
164ccedee22SAxel Dörfler			chunk = chunk->fNext;
165ccedee22SAxel Dörfler		}
166ccedee22SAxel Dörfler
167ccedee22SAxel Dörfler		if (chunk == NULL)
168ccedee22SAxel Dörfler			return;
169ccedee22SAxel Dörfler	}
170ccedee22SAxel Dörfler
171ccedee22SAxel Dörfler	previous->fNext = fNext;
172ccedee22SAxel Dörfler	fNext = NULL;
173ccedee22SAxel Dörfler}
174ccedee22SAxel Dörfler
175ccedee22SAxel Dörfler
176ccedee22SAxel Dörflervoid
177ccedee22SAxel DörflerFreeChunk::Enqueue(rtm_pool* pool)
178ccedee22SAxel Dörfler{
179ccedee22SAxel Dörfler	FreeChunk* chunk = pool->free_anchor.fNext;
180ccedee22SAxel Dörfler	FreeChunk* last = &pool->free_anchor;
181ccedee22SAxel Dörfler	while (chunk && chunk->Size() < fSize) {
182ccedee22SAxel Dörfler		last = chunk;
183ccedee22SAxel Dörfler		chunk = chunk->fNext;
184ccedee22SAxel Dörfler	}
185ccedee22SAxel Dörfler
186ccedee22SAxel Dörfler	fNext = chunk;
187ccedee22SAxel Dörfler	last->fNext = this;
188ccedee22SAxel Dörfler}
189ccedee22SAxel Dörfler
190ccedee22SAxel Dörfler
191ccedee22SAxel Dörflervoid*
192ccedee22SAxel DörflerFreeChunk::AllocatedAddress() const
193ccedee22SAxel Dörfler{
194ccedee22SAxel Dörfler	return (void*)&fNext;
195ccedee22SAxel Dörfler}
196ccedee22SAxel Dörfler
197ccedee22SAxel Dörfler
198ccedee22SAxel DörflerFreeChunk*
199ccedee22SAxel DörflerFreeChunk::SetToAllocated(void* allocated)
200ccedee22SAxel Dörfler{
2011fe06744SJerome Duval	return (FreeChunk*)((addr_t)allocated - FreeChunk::NextOffset());
202ccedee22SAxel Dörfler}
203ccedee22SAxel Dörfler
204ccedee22SAxel Dörfler
205ccedee22SAxel Dörfler// #pragma mark - rtm_pool
206ccedee22SAxel Dörfler
207ccedee22SAxel Dörfler
208ccedee22SAxel Dörflerbool
209ccedee22SAxel Dörflerrtm_pool::Contains(void* buffer) const
210ccedee22SAxel Dörfler{
211ccedee22SAxel Dörfler	return (addr_t)heap_base <= (addr_t)buffer
212ccedee22SAxel Dörfler		&& (addr_t)heap_base - 1 + max_size >= (addr_t)buffer;
213ccedee22SAxel Dörfler}
214ccedee22SAxel Dörfler
215ccedee22SAxel Dörfler
216ccedee22SAxel Dörflervoid
217ccedee22SAxel Dörflerrtm_pool::Free(void* allocated)
218ccedee22SAxel Dörfler{
219ccedee22SAxel Dörfler	FreeChunk* freedChunk = FreeChunk::SetToAllocated(allocated);
220ccedee22SAxel Dörfler	available += freedChunk->CompleteSize();
221ccedee22SAxel Dörfler
222ccedee22SAxel Dörfler	// try to join the new free chunk with an existing one
223ccedee22SAxel Dörfler	// it may be joined with up to two chunks
224ccedee22SAxel Dörfler
225ccedee22SAxel Dörfler	FreeChunk* chunk = free_anchor.Next();
226ccedee22SAxel Dörfler	FreeChunk* last = &free_anchor;
227ccedee22SAxel Dörfler	int32 joinCount = 0;
228ccedee22SAxel Dörfler
229ccedee22SAxel Dörfler	while (chunk) {
230ccedee22SAxel Dörfler		if (chunk->IsTouching(freedChunk)) {
231ccedee22SAxel Dörfler			// almost "insert" it into the list before joining
232ccedee22SAxel Dörfler			// because the next pointer is inherited by the chunk
233ccedee22SAxel Dörfler			freedChunk->SetNext(chunk->Next());
234ccedee22SAxel Dörfler			freedChunk = chunk->Join(freedChunk);
235ccedee22SAxel Dörfler
236ccedee22SAxel Dörfler			// remove the joined chunk from the list
237ccedee22SAxel Dörfler			last->SetNext(freedChunk->Next());
238ccedee22SAxel Dörfler			chunk = last;
239ccedee22SAxel Dörfler
240ccedee22SAxel Dörfler			if (++joinCount == 2)
241ccedee22SAxel Dörfler				break;
242ccedee22SAxel Dörfler		}
243ccedee22SAxel Dörfler
244ccedee22SAxel Dörfler		last = chunk;
245ccedee22SAxel Dörfler		chunk = chunk->Next();
246ccedee22SAxel Dörfler	}
247ccedee22SAxel Dörfler
248ccedee22SAxel Dörfler	// enqueue the link at the right position; the
249ccedee22SAxel Dörfler	// free link queue is ordered by size
250ccedee22SAxel Dörfler
251ccedee22SAxel Dörfler	freedChunk->Enqueue(this);
252ccedee22SAxel Dörfler}
253ccedee22SAxel Dörfler
254ccedee22SAxel Dörfler
255ccedee22SAxel Dörfler// #pragma mark -
256ccedee22SAxel Dörfler
257ccedee22SAxel Dörfler
258ccedee22SAxel Dörflerstatic rtm_pool*
259ccedee22SAxel Dörflerpool_for(void* buffer)
260ccedee22SAxel Dörfler{
261ccedee22SAxel Dörfler	MutexLocker _(&sPoolsLock);
262ccedee22SAxel Dörfler
263ccedee22SAxel Dörfler	PoolList::Iterator iterator = sPools.GetIterator();
264ccedee22SAxel Dörfler	while (rtm_pool* pool = iterator.Next()) {
265ccedee22SAxel Dörfler		if (pool->Contains(buffer))
266ccedee22SAxel Dörfler			return pool;
267ccedee22SAxel Dörfler	}
268ccedee22SAxel Dörfler
269ccedee22SAxel Dörfler	return NULL;
270ccedee22SAxel Dörfler}
271ccedee22SAxel Dörfler
272ccedee22SAxel Dörfler
273ccedee22SAxel Dörfler// #pragma mark - public API
274ccedee22SAxel Dörfler
275ccedee22SAxel Dörfler
276ca087074SMarcus Overhagenstatus_t
277ccedee22SAxel Dörflerrtm_create_pool(rtm_pool** _pool, size_t totalSize, const char* name)
27852a38012Sejakowatz{
279ccedee22SAxel Dörfler	rtm_pool* pool = (rtm_pool*)malloc(sizeof(rtm_pool));
280ccedee22SAxel Dörfler	if (pool == NULL)
281ccedee22SAxel Dörfler		return B_NO_MEMORY;
282ccedee22SAxel Dörfler
283f7127458SIngo Weinhold	if (name != NULL)
284f7127458SIngo Weinhold		mutex_init_etc(&pool->lock, name, MUTEX_FLAG_CLONE_NAME);
285f7127458SIngo Weinhold	else
286f7127458SIngo Weinhold		mutex_init(&pool->lock, "realtime pool");
287ccedee22SAxel Dörfler
288a288c5a0SAxel Dörfler	// Allocate enough space for at least one allocation over \a totalSize
289a288c5a0SAxel Dörfler	pool->max_size = (totalSize + sizeof(FreeChunk) - 1 + B_PAGE_SIZE)
290a288c5a0SAxel Dörfler		& ~(B_PAGE_SIZE - 1);
291ccedee22SAxel Dörfler
292ccedee22SAxel Dörfler	area_id area = create_area(name, &pool->heap_base, B_ANY_ADDRESS,
293ccedee22SAxel Dörfler		pool->max_size, B_LAZY_LOCK, B_READ_AREA | B_WRITE_AREA);
294ccedee22SAxel Dörfler	if (area < 0) {
295ccedee22SAxel Dörfler		mutex_destroy(&pool->lock);
296ccedee22SAxel Dörfler		free(pool);
297ccedee22SAxel Dörfler		return area;
298ccedee22SAxel Dörfler	}
299ccedee22SAxel Dörfler
300ccedee22SAxel Dörfler	pool->area = area;
301ccedee22SAxel Dörfler	pool->available = pool->max_size - FreeChunk::NextOffset();
302ccedee22SAxel Dörfler
303ccedee22SAxel Dörfler	// declare the whole heap as one chunk, and add it
304ccedee22SAxel Dörfler	// to the free list
305ccedee22SAxel Dörfler
306ccedee22SAxel Dörfler	FreeChunk* chunk = (FreeChunk*)pool->heap_base;
307ccedee22SAxel Dörfler	chunk->SetTo(pool->max_size, NULL);
308ccedee22SAxel Dörfler
309ccedee22SAxel Dörfler	pool->free_anchor.SetTo(0, chunk);
310ccedee22SAxel Dörfler
311ccedee22SAxel Dörfler	*_pool = pool;
312ccedee22SAxel Dörfler
313ccedee22SAxel Dörfler	MutexLocker _(&sPoolsLock);
314ccedee22SAxel Dörfler	sPools.Add(pool);
315ccedee22SAxel Dörfler	return B_OK;
31652a38012Sejakowatz}
31752a38012Sejakowatz
318ca087074SMarcus Overhagen
319ca087074SMarcus Overhagenstatus_t
320ccedee22SAxel Dörflerrtm_delete_pool(rtm_pool* pool)
32152a38012Sejakowatz{
322a288c5a0SAxel Dörfler	if (pool == NULL)
323a288c5a0SAxel Dörfler		return B_BAD_VALUE;
324a288c5a0SAxel Dörfler
325a288c5a0SAxel Dörfler	mutex_lock(&pool->lock);
326a288c5a0SAxel Dörfler
327ccedee22SAxel Dörfler	{
328ccedee22SAxel Dörfler		MutexLocker _(&sPoolsLock);
329ccedee22SAxel Dörfler		sPools.Remove(pool);
330ccedee22SAxel Dörfler	}
331ccedee22SAxel Dörfler
332ccedee22SAxel Dörfler	delete_area(pool->area);
333ccedee22SAxel Dörfler	mutex_destroy(&pool->lock);
334ccedee22SAxel Dörfler	free(pool);
335ccedee22SAxel Dörfler
336ccedee22SAxel Dörfler	return B_OK;
33752a38012Sejakowatz}
33852a38012Sejakowatz
339ca087074SMarcus Overhagen
340ccedee22SAxel Dörflervoid*
341ccedee22SAxel Dörflerrtm_alloc(rtm_pool* pool, size_t size)
34252a38012Sejakowatz{
343ccedee22SAxel Dörfler	if (pool == NULL)
344ccedee22SAxel Dörfler		return malloc(size);
345ccedee22SAxel Dörfler
346ccedee22SAxel Dörfler	if (pool->heap_base == NULL || size == 0)
347ccedee22SAxel Dörfler		return NULL;
348ccedee22SAxel Dörfler
349a288c5a0SAxel Dörfler	MutexLocker _(&pool->lock);
350a288c5a0SAxel Dörfler
351ccedee22SAxel Dörfler	// align the size requirement to a kAlignment bytes boundary
352ccedee22SAxel Dörfler	size = (size - 1 + kAlignment) & ~(size_t)(kAlignment - 1);
353ccedee22SAxel Dörfler
354ccedee22SAxel Dörfler	if (size > pool->available) {
355ccedee22SAxel Dörfler		TRACE("malloc(): Out of memory!\n");
356ccedee22SAxel Dörfler		return NULL;
357ccedee22SAxel Dörfler	}
358ccedee22SAxel Dörfler
359ccedee22SAxel Dörfler	FreeChunk* chunk = pool->free_anchor.Next();
360ccedee22SAxel Dörfler	FreeChunk* last = &pool->free_anchor;
361ccedee22SAxel Dörfler	while (chunk && chunk->Size() < size) {
362ccedee22SAxel Dörfler		last = chunk;
363ccedee22SAxel Dörfler		chunk = chunk->Next();
364ccedee22SAxel Dörfler	}
365ccedee22SAxel Dörfler
366ccedee22SAxel Dörfler	if (chunk == NULL) {
367ccedee22SAxel Dörfler		// could not find a free chunk as large as needed
368ccedee22SAxel Dörfler		TRACE("malloc(): Out of memory!\n");
369ccedee22SAxel Dörfler		return NULL;
370ccedee22SAxel Dörfler	}
371ccedee22SAxel Dörfler
372ccedee22SAxel Dörfler	if (chunk->Size() > size + sizeof(FreeChunk) + kAlignment) {
373ccedee22SAxel Dörfler		// if this chunk is bigger than the requested size,
374ccedee22SAxel Dörfler		// we split it to form two chunks (with a minimal
375ccedee22SAxel Dörfler		// size of kAlignment allocatable bytes).
376ccedee22SAxel Dörfler
377ccedee22SAxel Dörfler		FreeChunk* freeChunk = chunk->Split(size);
378ccedee22SAxel Dörfler		last->SetNext(freeChunk);
379ccedee22SAxel Dörfler
380ccedee22SAxel Dörfler		// re-enqueue the free chunk at the correct position
381ccedee22SAxel Dörfler		freeChunk->Remove(pool, last);
382ccedee22SAxel Dörfler		freeChunk->Enqueue(pool);
383ccedee22SAxel Dörfler	} else {
384ccedee22SAxel Dörfler		// remove the chunk from the free list
385ccedee22SAxel Dörfler
386ccedee22SAxel Dörfler		last->SetNext(chunk->Next());
387ccedee22SAxel Dörfler	}
388ccedee22SAxel Dörfler
3891fe06744SJerome Duval	pool->available -= size + sizeof(size_t);
390ccedee22SAxel Dörfler
391ccedee22SAxel Dörfler	TRACE("malloc(%lu) -> %p\n", size, chunk->AllocatedAddress());
392ccedee22SAxel Dörfler	return chunk->AllocatedAddress();
39352a38012Sejakowatz}
39452a38012Sejakowatz
39552a38012Sejakowatz
396ccedee22SAxel Dörflerstatus_t
397ccedee22SAxel Dörflerrtm_free(void* allocated)
398ccedee22SAxel Dörfler{
399ccedee22SAxel Dörfler	if (allocated == NULL)
400ccedee22SAxel Dörfler		return B_OK;
40152a38012Sejakowatz
402ccedee22SAxel Dörfler	TRACE("rtm_free(%p)\n", allocated);
40352a38012Sejakowatz
404ccedee22SAxel Dörfler	// find pool
405ccedee22SAxel Dörfler	rtm_pool* pool = pool_for(allocated);
406ccedee22SAxel Dörfler	if (pool == NULL) {
407ccedee22SAxel Dörfler		free(allocated);
408ccedee22SAxel Dörfler		return B_OK;
409ccedee22SAxel Dörfler	}
410ccedee22SAxel Dörfler
411a288c5a0SAxel Dörfler	MutexLocker _(&pool->lock);
412ccedee22SAxel Dörfler	pool->Free(allocated);
413ccedee22SAxel Dörfler	return B_OK;
414ccedee22SAxel Dörfler}
41552a38012Sejakowatz
41652a38012Sejakowatz
417ccedee22SAxel Dörflerstatus_t
418ccedee22SAxel Dörflerrtm_realloc(void** _buffer, size_t newSize)
419ccedee22SAxel Dörfler{
420ccedee22SAxel Dörfler	if (_buffer == NULL)
421ccedee22SAxel Dörfler		return B_BAD_VALUE;
422ccedee22SAxel Dörfler
423ccedee22SAxel Dörfler	TRACE("rtm_realloc(%p, %lu)\n", *_buffer, newSize);
424ccedee22SAxel Dörfler
425ccedee22SAxel Dörfler	void* oldBuffer = *_buffer;
426ccedee22SAxel Dörfler
427ccedee22SAxel Dörfler	// find pool
428ccedee22SAxel Dörfler	rtm_pool* pool = pool_for(oldBuffer);
429ccedee22SAxel Dörfler	if (pool == NULL) {
430ccedee22SAxel Dörfler		void* buffer = realloc(oldBuffer, newSize);
431ccedee22SAxel Dörfler		if (buffer != NULL) {
432ccedee22SAxel Dörfler			*_buffer = buffer;
433ccedee22SAxel Dörfler			return B_OK;
434ccedee22SAxel Dörfler		}
435ccedee22SAxel Dörfler		return B_NO_MEMORY;
436ccedee22SAxel Dörfler	}
437ccedee22SAxel Dörfler
438a288c5a0SAxel Dörfler	MutexLocker _(&pool->lock);
439a288c5a0SAxel Dörfler
440ccedee22SAxel Dörfler	if (newSize == 0) {
441ccedee22SAxel Dörfler		TRACE("realloc(%p, %lu) -> NULL\n", oldBuffer, newSize);
442ccedee22SAxel Dörfler		pool->Free(oldBuffer);
443ccedee22SAxel Dörfler		*_buffer = NULL;
444ccedee22SAxel Dörfler		return B_OK;
445ccedee22SAxel Dörfler	}
446ccedee22SAxel Dörfler
447ccedee22SAxel Dörfler	size_t copySize = newSize;
448ccedee22SAxel Dörfler	if (oldBuffer != NULL) {
449ccedee22SAxel Dörfler		FreeChunk* oldChunk = FreeChunk::SetToAllocated(oldBuffer);
450ccedee22SAxel Dörfler
451ccedee22SAxel Dörfler		// Check if the old buffer still fits, and if it makes sense to keep it
452ccedee22SAxel Dörfler		if (oldChunk->Size() >= newSize && newSize > oldChunk->Size() / 3) {
453ccedee22SAxel Dörfler			TRACE("realloc(%p, %lu) old buffer is large enough\n",
454ccedee22SAxel Dörfler				oldBuffer, newSize);
455ccedee22SAxel Dörfler			return B_OK;
456ccedee22SAxel Dörfler		}
457ccedee22SAxel Dörfler
458ccedee22SAxel Dörfler		if (copySize > oldChunk->Size())
459ccedee22SAxel Dörfler			copySize = oldChunk->Size();
460ccedee22SAxel Dörfler	}
461ccedee22SAxel Dörfler
462ccedee22SAxel Dörfler	void* newBuffer = rtm_alloc(pool, newSize);
463ccedee22SAxel Dörfler	if (newBuffer == NULL)
464ccedee22SAxel Dörfler		return B_NO_MEMORY;
465ccedee22SAxel Dörfler
466ccedee22SAxel Dörfler	if (oldBuffer != NULL) {
467ccedee22SAxel Dörfler		memcpy(newBuffer, oldBuffer, copySize);
468ccedee22SAxel Dörfler		pool->Free(oldBuffer);
469ccedee22SAxel Dörfler	}
470ccedee22SAxel Dörfler
471ccedee22SAxel Dörfler	TRACE("realloc(%p, %lu) -> %p\n", oldBuffer, newSize, newBuffer);
472ccedee22SAxel Dörfler	*_buffer = newBuffer;
473ccedee22SAxel Dörfler	return B_OK;
47452a38012Sejakowatz}
47552a38012Sejakowatz
47652a38012Sejakowatz
477ccedee22SAxel Dörflerstatus_t
478ccedee22SAxel Dörflerrtm_size_for(void* buffer)
479ccedee22SAxel Dörfler{
480ccedee22SAxel Dörfler	if (buffer == NULL)
481ccedee22SAxel Dörfler		return 0;
482ccedee22SAxel Dörfler
483ccedee22SAxel Dörfler	FreeChunk* chunk = FreeChunk::SetToAllocated(buffer);
484ccedee22SAxel Dörfler	// TODO: we currently always return the actual chunk size, not the allocated
485ccedee22SAxel Dörfler	// one
486ccedee22SAxel Dörfler	return chunk->Size();
487ccedee22SAxel Dörfler}
48852a38012Sejakowatz
48952a38012Sejakowatz
490ca087074SMarcus Overhagenstatus_t
491ccedee22SAxel Dörflerrtm_phys_size_for(void* buffer)
492ccedee22SAxel Dörfler{
493ccedee22SAxel Dörfler	if (buffer == NULL)
494ccedee22SAxel Dörfler		return 0;
495ccedee22SAxel Dörfler
496ccedee22SAxel Dörfler	FreeChunk* chunk = FreeChunk::SetToAllocated(buffer);
497ccedee22SAxel Dörfler	return chunk->Size();
49852a38012Sejakowatz}
49952a38012Sejakowatz
50052a38012Sejakowatz
501ccedee22SAxel Dörflersize_t
502ccedee22SAxel Dörflerrtm_available(rtm_pool* pool)
503ccedee22SAxel Dörfler{
504ccedee22SAxel Dörfler	if (pool == NULL) {
505ccedee22SAxel Dörfler		// whatever - might want to use system_info instead
506ccedee22SAxel Dörfler		return 1024 * 1024;
507ccedee22SAxel Dörfler	}
508ccedee22SAxel Dörfler
509ccedee22SAxel Dörfler	return pool->available;
510ccedee22SAxel Dörfler}
511ccedee22SAxel Dörfler
512ccedee22SAxel Dörfler
513ccedee22SAxel Dörflerrtm_pool*
514ccedee22SAxel Dörflerrtm_default_pool()
51552a38012Sejakowatz{
516ccedee22SAxel Dörfler	// We always return NULL - the default pool will just use malloc()/free()
517ccedee22SAxel Dörfler	return NULL;
51852a38012Sejakowatz}
51952a38012Sejakowatz
520ccedee22SAxel Dörfler
521ccedee22SAxel Dörfler#if 0
522ccedee22SAxel Dörflerextern "C" {
523ccedee22SAxel Dörfler
524ccedee22SAxel Dörfler// undocumented symbols that BeOS exports
525ccedee22SAxel Dörflerstatus_t rtm_create_pool_etc(rtm_pool ** out_pool, size_t total_size, const char * name, int32 param4, int32 param5, ...);
526ccedee22SAxel Dörflervoid rtm_get_pool(rtm_pool *pool,void *data,int32 param3,int32 param4, ...);
527ccedee22SAxel Dörfler
528ccedee22SAxel Dörfler}
529ccedee22SAxel Dörfler#endif
530