1848b8605Smrg/**************************************************************************
2848b8605Smrg *
3848b8605Smrg * Copyright (C) 1999 Wittawat Yamwong
4848b8605Smrg *
5848b8605Smrg * Permission is hereby granted, free of charge, to any person obtaining a
6848b8605Smrg * copy of this software and associated documentation files (the "Software"),
7848b8605Smrg * to deal in the Software without restriction, including without limitation
8848b8605Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9848b8605Smrg * and/or sell copies of the Software, and to permit persons to whom the
10848b8605Smrg * Software is furnished to do so, subject to the following conditions:
11848b8605Smrg *
12848b8605Smrg * The above copyright notice and this permission notice shall be included
13848b8605Smrg * in all copies or substantial portions of the Software.
14848b8605Smrg *
15848b8605Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16848b8605Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17848b8605Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18848b8605Smrg * WITTAWAT YAMWONG, OR ANY OTHER CONTRIBUTORS BE LIABLE FOR ANY CLAIM,
19848b8605Smrg * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
20848b8605Smrg * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE
21848b8605Smrg * OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22848b8605Smrg *
23848b8605Smrg **************************************************************************/
24848b8605Smrg
25848b8605Smrg
26848b8605Smrg#include "pipe/p_compiler.h"
27848b8605Smrg#include "util/u_debug.h"
28848b8605Smrg
29848b8605Smrg#include "util/u_memory.h"
30848b8605Smrg#include "util/u_mm.h"
31848b8605Smrg
32848b8605Smrg
33848b8605Smrgvoid
34848b8605Smrgu_mmDumpMemInfo(const struct mem_block *heap)
35848b8605Smrg{
36848b8605Smrg   debug_printf("Memory heap %p:\n", (void *) heap);
37b8e80941Smrg   if (heap == NULL) {
38848b8605Smrg      debug_printf("  heap == 0\n");
39848b8605Smrg   }
40848b8605Smrg   else {
41848b8605Smrg      const struct mem_block *p;
42848b8605Smrg      int total_used = 0, total_free = 0;
43848b8605Smrg
44848b8605Smrg      for (p = heap->next; p != heap; p = p->next) {
45848b8605Smrg	 debug_printf("  Offset:%08x, Size:%08x, %c%c\n", p->ofs, p->size,
46848b8605Smrg                      p->free ? 'F':'.',
47848b8605Smrg                      p->reserved ? 'R':'.');
48848b8605Smrg         if (p->free)
49848b8605Smrg            total_free += p->size;
50848b8605Smrg         else
51848b8605Smrg            total_used += p->size;
52848b8605Smrg      }
53848b8605Smrg
54848b8605Smrg      debug_printf("'\nMemory stats: total = %d, used = %d, free = %d\n",
55848b8605Smrg                   total_used + total_free, total_used, total_free);
56848b8605Smrg      debug_printf("\nFree list:\n");
57848b8605Smrg
58848b8605Smrg      for (p = heap->next_free; p != heap; p = p->next_free) {
59848b8605Smrg	 debug_printf(" FREE Offset:%08x, Size:%08x, %c%c\n", p->ofs, p->size,
60848b8605Smrg                      p->free ? 'F':'.',
61848b8605Smrg                      p->reserved ? 'R':'.');
62848b8605Smrg      }
63848b8605Smrg
64848b8605Smrg   }
65848b8605Smrg   debug_printf("End of memory blocks\n");
66848b8605Smrg}
67848b8605Smrg
68848b8605Smrg
69848b8605Smrgstruct mem_block *
70848b8605Smrgu_mmInit(int ofs, int size)
71848b8605Smrg{
72848b8605Smrg   struct mem_block *heap, *block;
73848b8605Smrg
74848b8605Smrg   if (size <= 0)
75848b8605Smrg      return NULL;
76848b8605Smrg
77848b8605Smrg   heap = CALLOC_STRUCT(mem_block);
78848b8605Smrg   if (!heap)
79848b8605Smrg      return NULL;
80848b8605Smrg
81848b8605Smrg   block = CALLOC_STRUCT(mem_block);
82848b8605Smrg   if (!block) {
83848b8605Smrg      FREE(heap);
84848b8605Smrg      return NULL;
85848b8605Smrg   }
86848b8605Smrg
87848b8605Smrg   heap->next = block;
88848b8605Smrg   heap->prev = block;
89848b8605Smrg   heap->next_free = block;
90848b8605Smrg   heap->prev_free = block;
91848b8605Smrg
92848b8605Smrg   block->heap = heap;
93848b8605Smrg   block->next = heap;
94848b8605Smrg   block->prev = heap;
95848b8605Smrg   block->next_free = heap;
96848b8605Smrg   block->prev_free = heap;
97848b8605Smrg
98848b8605Smrg   block->ofs = ofs;
99848b8605Smrg   block->size = size;
100848b8605Smrg   block->free = 1;
101848b8605Smrg
102848b8605Smrg   return heap;
103848b8605Smrg}
104848b8605Smrg
105848b8605Smrg
106848b8605Smrgstatic struct mem_block *
107848b8605SmrgSliceBlock(struct mem_block *p,
108848b8605Smrg           int startofs, int size,
109b8e80941Smrg           int reserved, UNUSED int alignment)
110848b8605Smrg{
111848b8605Smrg   struct mem_block *newblock;
112848b8605Smrg
113848b8605Smrg   /* break left  [p, newblock, p->next], then p = newblock */
114848b8605Smrg   if (startofs > p->ofs) {
115848b8605Smrg      newblock = CALLOC_STRUCT(mem_block);
116848b8605Smrg      if (!newblock)
117848b8605Smrg	 return NULL;
118848b8605Smrg      newblock->ofs = startofs;
119848b8605Smrg      newblock->size = p->size - (startofs - p->ofs);
120848b8605Smrg      newblock->free = 1;
121848b8605Smrg      newblock->heap = p->heap;
122848b8605Smrg
123848b8605Smrg      newblock->next = p->next;
124848b8605Smrg      newblock->prev = p;
125848b8605Smrg      p->next->prev = newblock;
126848b8605Smrg      p->next = newblock;
127848b8605Smrg
128848b8605Smrg      newblock->next_free = p->next_free;
129848b8605Smrg      newblock->prev_free = p;
130848b8605Smrg      p->next_free->prev_free = newblock;
131848b8605Smrg      p->next_free = newblock;
132848b8605Smrg
133848b8605Smrg      p->size -= newblock->size;
134848b8605Smrg      p = newblock;
135848b8605Smrg   }
136848b8605Smrg
137848b8605Smrg   /* break right, also [p, newblock, p->next] */
138848b8605Smrg   if (size < p->size) {
139848b8605Smrg      newblock = CALLOC_STRUCT(mem_block);
140848b8605Smrg      if (!newblock)
141848b8605Smrg	 return NULL;
142848b8605Smrg      newblock->ofs = startofs + size;
143848b8605Smrg      newblock->size = p->size - size;
144848b8605Smrg      newblock->free = 1;
145848b8605Smrg      newblock->heap = p->heap;
146848b8605Smrg
147848b8605Smrg      newblock->next = p->next;
148848b8605Smrg      newblock->prev = p;
149848b8605Smrg      p->next->prev = newblock;
150848b8605Smrg      p->next = newblock;
151848b8605Smrg
152848b8605Smrg      newblock->next_free = p->next_free;
153848b8605Smrg      newblock->prev_free = p;
154848b8605Smrg      p->next_free->prev_free = newblock;
155848b8605Smrg      p->next_free = newblock;
156848b8605Smrg
157848b8605Smrg      p->size = size;
158848b8605Smrg   }
159848b8605Smrg
160848b8605Smrg   /* p = middle block */
161848b8605Smrg   p->free = 0;
162848b8605Smrg
163848b8605Smrg   /* Remove p from the free list:
164848b8605Smrg    */
165848b8605Smrg   p->next_free->prev_free = p->prev_free;
166848b8605Smrg   p->prev_free->next_free = p->next_free;
167848b8605Smrg
168848b8605Smrg   p->next_free = 0;
169848b8605Smrg   p->prev_free = 0;
170848b8605Smrg
171848b8605Smrg   p->reserved = reserved;
172848b8605Smrg   return p;
173848b8605Smrg}
174848b8605Smrg
175848b8605Smrg
176848b8605Smrgstruct mem_block *
177848b8605Smrgu_mmAllocMem(struct mem_block *heap, int size, int align2, int startSearch)
178848b8605Smrg{
179848b8605Smrg   struct mem_block *p;
180848b8605Smrg   const int mask = (1 << align2)-1;
181848b8605Smrg   int startofs = 0;
182848b8605Smrg   int endofs;
183848b8605Smrg
184848b8605Smrg   assert(size >= 0);
185848b8605Smrg   assert(align2 >= 0);
186b8e80941Smrg   /* Make sure that a byte alignment isn't getting passed for our
187b8e80941Smrg    * power-of-two alignment arg.
188b8e80941Smrg    */
189b8e80941Smrg   assert(align2 < 32);
190848b8605Smrg
191848b8605Smrg   if (!heap || align2 < 0 || size <= 0)
192848b8605Smrg      return NULL;
193848b8605Smrg
194848b8605Smrg   for (p = heap->next_free; p != heap; p = p->next_free) {
195848b8605Smrg      assert(p->free);
196848b8605Smrg
197848b8605Smrg      startofs = (p->ofs + mask) & ~mask;
198848b8605Smrg      if ( startofs < startSearch ) {
199848b8605Smrg	 startofs = startSearch;
200848b8605Smrg      }
201848b8605Smrg      endofs = startofs+size;
202848b8605Smrg      if (endofs <= (p->ofs+p->size))
203848b8605Smrg	 break;
204848b8605Smrg   }
205848b8605Smrg
206848b8605Smrg   if (p == heap)
207848b8605Smrg      return NULL;
208848b8605Smrg
209848b8605Smrg   assert(p->free);
210848b8605Smrg   p = SliceBlock(p,startofs,size,0,mask+1);
211848b8605Smrg
212848b8605Smrg   return p;
213848b8605Smrg}
214848b8605Smrg
215848b8605Smrg
216848b8605Smrgstruct mem_block *
217848b8605Smrgu_mmFindBlock(struct mem_block *heap, int start)
218848b8605Smrg{
219848b8605Smrg   struct mem_block *p;
220848b8605Smrg
221848b8605Smrg   for (p = heap->next; p != heap; p = p->next) {
222848b8605Smrg      if (p->ofs == start)
223848b8605Smrg	 return p;
224848b8605Smrg   }
225848b8605Smrg
226848b8605Smrg   return NULL;
227848b8605Smrg}
228848b8605Smrg
229848b8605Smrg
230b8e80941Smrgstatic inline int
231848b8605SmrgJoin2Blocks(struct mem_block *p)
232848b8605Smrg{
233848b8605Smrg   /* XXX there should be some assertions here */
234848b8605Smrg
235848b8605Smrg   /* NOTE: heap->free == 0 */
236848b8605Smrg
237848b8605Smrg   if (p->free && p->next->free) {
238848b8605Smrg      struct mem_block *q = p->next;
239848b8605Smrg
240848b8605Smrg      assert(p->ofs + p->size == q->ofs);
241848b8605Smrg      p->size += q->size;
242848b8605Smrg
243848b8605Smrg      p->next = q->next;
244848b8605Smrg      q->next->prev = p;
245848b8605Smrg
246848b8605Smrg      q->next_free->prev_free = q->prev_free;
247848b8605Smrg      q->prev_free->next_free = q->next_free;
248848b8605Smrg
249848b8605Smrg      FREE(q);
250848b8605Smrg      return 1;
251848b8605Smrg   }
252848b8605Smrg   return 0;
253848b8605Smrg}
254848b8605Smrg
255848b8605Smrgint
256848b8605Smrgu_mmFreeMem(struct mem_block *b)
257848b8605Smrg{
258848b8605Smrg   if (!b)
259848b8605Smrg      return 0;
260848b8605Smrg
261848b8605Smrg   if (b->free) {
262848b8605Smrg      debug_printf("block already free\n");
263848b8605Smrg      return -1;
264848b8605Smrg   }
265848b8605Smrg   if (b->reserved) {
266848b8605Smrg      debug_printf("block is reserved\n");
267848b8605Smrg      return -1;
268848b8605Smrg   }
269848b8605Smrg
270848b8605Smrg   b->free = 1;
271848b8605Smrg   b->next_free = b->heap->next_free;
272848b8605Smrg   b->prev_free = b->heap;
273848b8605Smrg   b->next_free->prev_free = b;
274848b8605Smrg   b->prev_free->next_free = b;
275848b8605Smrg
276848b8605Smrg   Join2Blocks(b);
277848b8605Smrg   if (b->prev != b->heap)
278848b8605Smrg      Join2Blocks(b->prev);
279848b8605Smrg
280848b8605Smrg   return 0;
281848b8605Smrg}
282848b8605Smrg
283848b8605Smrg
284848b8605Smrgvoid
285848b8605Smrgu_mmDestroy(struct mem_block *heap)
286848b8605Smrg{
287848b8605Smrg   struct mem_block *p;
288848b8605Smrg
289848b8605Smrg   if (!heap)
290848b8605Smrg      return;
291848b8605Smrg
292848b8605Smrg   for (p = heap->next; p != heap; ) {
293848b8605Smrg      struct mem_block *next = p->next;
294848b8605Smrg      FREE(p);
295848b8605Smrg      p = next;
296848b8605Smrg   }
297848b8605Smrg
298848b8605Smrg   FREE(heap);
299848b8605Smrg}
300