source: vis_dev/glu-2.3/src/mem/memblock.c @ 13

Last change on this file since 13 was 13, checked in by cecile, 13 years ago

library glu 2.3

File size: 9.5 KB
Line 
1/* Memory block management routines */
2
3
4#include "memint.h"
5
6
7#if STDC_HEADERS
8#  include <stdlib.h>
9#else
10#  if defined(__STDC__)
11extern void exit(int);
12#  else
13extern void exit();
14#  endif
15#endif
16
17
18/* Amount of memory allocated */
19
20static SIZE_T block_allocation;
21
22
23/* mem_copy(dest, src, size) copies a block of memory. */
24
25void
26#if defined(__STDC__)
27mem_copy(pointer dest, pointer src, SIZE_T size)
28#else
29mem_copy(dest, src, size)
30     pointer dest;
31     pointer src;
32     SIZE_T size;
33#endif
34{
35  MEM_COPY(dest, src, size);
36}
37
38
39/* mem_zero(ptr, size) zeros a block of memory. */
40
41void
42#if defined(__STDC__)
43mem_zero(pointer ptr, SIZE_T size)
44#else
45mem_zero(ptr, size)
46     pointer ptr;
47     SIZE_T size;
48#endif
49{
50  MEM_ZERO(ptr, size);
51}
52
53
54/* mem_fatal(message) prints an error message and exits. */
55
56void
57#if defined(__STDC__)
58mem_fatal(char *message)
59#else
60mem_fatal(message)
61     char *message;
62#endif
63{
64  fprintf(stderr, "Memory management library: error: %s\n", message);
65  exit(1);
66}
67
68
69SIZE_T
70#if defined(__STDC__)
71mem_allocation(void)
72#else
73mem_allocation()
74#endif
75{
76  /* This will always returns zero when we're using malloc and free, */
77  /* but you can maybe change it depending on your system. */
78  return (block_allocation);
79}
80
81
82/* This code used if we're going to do our own memory management. */
83
84#if !defined(USE_MALLOC_FREE)
85/* Free lists of various sizes */
86
87static block avail[MAX_SIZE_INDEX+1];
88
89
90/* Bogus segment for initialization */
91
92static struct segment_ dummy_seg={(pointer)0, (SIZE_T)0};
93
94
95/* Current segment */
96
97static segment curr_seg= &dummy_seg;
98
99
100static
101int
102#if defined(__STDC__)
103ceiling_log_2(SIZE_T i)
104#else
105ceiling_log_2(i)
106     SIZE_T i;
107#endif
108{
109  SIZE_T j;
110  int result;
111
112  for (result=0, j=1; j < i; ++result, j*=2);
113  return (result);
114}
115
116
117/* block_size_index(size) return the coded size for a block. */
118
119static
120int
121#if defined(__STDC__)
122block_size_index(SIZE_T size)
123#else
124block_size_index(size)
125     SIZE_T size;
126#endif
127{
128  if (size < 1)
129    return (-1);
130  if (size > MAX_SIZE)
131    mem_fatal("block_size_index: block size too large");
132  else
133    size+=HEADER_SIZE;
134  return (ceiling_log_2(size));
135}
136
137
138/* add_to_free_list(b) adds b to the appropriate free list. */
139
140static
141void
142#if defined(__STDC__)
143add_to_free_list(block b)
144#else
145add_to_free_list(b)
146     block b;
147#endif
148{
149  int i;
150
151  i=b->size_index;
152  if (!avail[i])
153    {
154      b->next=b;
155      b->prev=b;
156      avail[i]=b;
157    }
158  else
159    {
160      b->next=avail[i]->next;
161      avail[i]->next->prev=b;
162      avail[i]->next=b;
163      b->prev=avail[i];
164    }
165  b->used=0;
166}
167
168
169/* remove_from_free_list(b) removes b from the free list which it */
170/* is on. */
171
172static
173block
174#if defined(__STDC__)
175remove_from_free_list(block b)
176#else
177remove_from_free_list(b)
178     block b;
179#endif
180{
181  int i;
182
183  i=b->size_index;
184  if (b->next == b)
185    avail[i]=0;
186  else
187    {
188      b->next->prev=b->prev;
189      b->prev->next=b->next;
190      if (avail[i] == b)
191        avail[i]=b->next;
192    }
193  b->used=1;
194  return (b);
195}
196
197
198/* buddy(b) returns the buddy block of b, or null if there is no */
199/* buddy. */
200
201static
202block
203#if defined(__STDC__)
204buddy(block b)
205#else
206buddy(b)
207     block b;
208#endif
209{
210  SIZE_T buddy_offset;
211
212  buddy_offset=(SIZE_T)(((INT_PTR)b-(INT_PTR)b->seg->base_address) ^ ((SIZE_T)1 << b->size_index));
213  if (buddy_offset < b->seg->limit)
214    return ((block)((INT_PTR)b->seg->base_address+buddy_offset));
215  else
216    return ((block)0);
217}
218
219
220/* trim_to_size(b, size_index) repeatedly splits b until it has */
221/* the indicated size.  Blocks which are split off are added to the */
222/* appropriate free list. */
223
224static
225void
226#if defined(__STDC__)
227trim_to_size(block b, int size_index)
228#else
229trim_to_size(b, size_index)
230     block b;
231     int size_index;
232#endif
233{
234  block bb;
235
236  while (b->size_index > size_index)
237    {
238      b->size_index--;
239      bb=buddy(b);
240      bb->size_index=b->size_index;
241      bb->seg=b->seg;
242      add_to_free_list(bb);
243    }
244}
245
246
247/* merge_and_free(b) repeatedly merges b its buddy until b has no */
248/* buddy or the buddy isn't free, then adds the result to the */
249/* appropriate free list. */
250
251static
252void
253#if defined(__STDC__)
254merge_and_free(block b)
255#else
256merge_and_free(b)
257     block b;
258#endif
259{
260  block bb;
261
262  for (bb=buddy(b); bb && !bb->used && bb->size_index == b->size_index; bb=buddy(b))
263    {
264      remove_from_free_list(bb);
265      if ((INT_PTR)bb < (INT_PTR)b)
266        b=bb;
267      b->size_index++;
268    }
269  add_to_free_list(b);
270}
271
272
273/* mem_get_block(size) allocates a new block of the specified size. */
274
275pointer
276#if defined(__STDC__)
277mem_get_block(SIZE_T size)
278#else
279mem_get_block(size)
280     SIZE_T size;
281#endif
282{
283  int i;
284  int size_index;
285  int alloc_size_index;
286  int new_seg;
287  SIZE_T alloc_size;
288  pointer sbrk_ret;
289  block b;
290
291  if ((size_index=block_size_index(size)) < 0)
292    return ((pointer)0);
293  /* Find smallest free block which is large enough. */
294  for (i=size_index; i <= MAX_SIZE_INDEX && !avail[i]; ++i);
295  if (i > MAX_SIZE_INDEX)
296    {
297      /* We must get more storage; don't allocate less than */
298      /* 2^MIN_ALLOC_SIZE_INDEX. */
299      if (size_index < MIN_ALLOC_SIZE_INDEX)
300        alloc_size_index=MIN_ALLOC_SIZE_INDEX;
301      else
302        alloc_size_index=size_index;
303      alloc_size=((SIZE_T)1 << alloc_size_index);
304      /* Pad current segment to be a multiple of 2^alloc_size_index in */
305      /* length. */
306      alloc_size+=((curr_seg->limit+alloc_size-1) & ~(alloc_size-1))-curr_seg->limit;
307      if ((sbrk_ret=(pointer)SBRK(0)) != (pointer)((INT_PTR)curr_seg->base_address+curr_seg->limit) ||
308          alloc_size+curr_seg->limit > MAX_SEG_SIZE)
309        {
310          /* Segment is too large or someone else has moved the break. */
311          /* Pad to get to appropriate boundary. */
312          alloc_size=ROUNDUP((INT_PTR)sbrk_ret)-(INT_PTR)sbrk_ret;
313          /* Pad allocation request with storage for new segment */
314          /* information and indicate that a new segment must be */
315          /* created. */
316          alloc_size+=((SIZE_T)1 << alloc_size_index)+ROUNDUP(sizeof(struct segment_));
317          new_seg=1;
318        }
319      else
320        new_seg=0;
321      sbrk_ret=(pointer)SBRK(alloc_size);
322      if (sbrk_ret == (pointer)-1)
323        mem_fatal("mem_get_block: allocation failed");
324      block_allocation+=alloc_size;
325      if (new_seg)
326        {
327          curr_seg=(segment)ROUNDUP((INT_PTR)sbrk_ret);
328          curr_seg->base_address=(pointer)((INT_PTR)curr_seg+ROUNDUP(sizeof(struct segment_)));
329          curr_seg->limit=0;
330          /* Readjust allocation size. */
331          alloc_size=(1l << alloc_size_index);
332        }
333      /* Carve allocated space up into blocks and add to free lists. */
334      while (alloc_size)
335        {
336          size=alloc_size-(alloc_size & (alloc_size-1));
337          b=(block)((INT_PTR)curr_seg->base_address+curr_seg->limit);
338          b->size_index=ceiling_log_2(size);
339          b->seg=curr_seg;
340          add_to_free_list(b);
341          curr_seg->limit+=size;
342          alloc_size-=size;
343        }
344      /* Find free block of appropriate size. */
345      for (i=size_index; i <= MAX_SIZE_INDEX && !avail[i]; ++i);
346    }
347  b=remove_from_free_list(avail[i]);
348  trim_to_size(b, size_index);
349  return ((pointer)((INT_PTR)b+HEADER_SIZE));
350}
351
352
353/* mem_free_block(p) frees the block indicated by p. */
354
355void
356#if defined(__STDC__)
357mem_free_block(pointer p)
358#else
359mem_free_block(p)
360     pointer p;
361#endif
362{
363  block b;
364
365  if (!p)
366    return;
367  b=(block)((INT_PTR)p-HEADER_SIZE);
368  if (!b->used)
369    mem_fatal("mem_free_block: block not in use");
370  if (b->size_index < 0 || b->size_index > MAX_SIZE_INDEX)
371    mem_fatal("mem_free_block: invalid block header");
372  merge_and_free(b);
373}
374
375
376/* mem_resize_block(p, new_size) expands or contracts the block */
377/* indicated by p to a new size.  We try to avoid moving the block if */
378/* possible. */
379
380pointer
381#if defined(__STDC__)
382mem_resize_block(pointer p, SIZE_T new_size)
383#else
384mem_resize_block(p, new_size)
385     pointer p;
386     SIZE_T new_size;
387#endif
388{
389  int new_size_index;
390  block b;
391  block bb;
392  pointer q;
393  SIZE_T old_size;
394
395  if (!p)
396    return (mem_get_block(new_size));
397  b=(block)((INT_PTR)p-HEADER_SIZE);
398  if (!b->used)
399    mem_fatal("mem_resize_block: block not in use");
400  if (b->size_index < 0 || b->size_index > MAX_SIZE_INDEX)
401    mem_fatal("mem_resize_block: invalid block header");
402  if ((new_size_index=block_size_index(new_size)) < 0)
403    {
404      mem_free_block(p);
405      return ((pointer)0);
406    }
407  if (b->size_index >= new_size_index)
408    {
409      /* Shrink block. */
410      trim_to_size(b, new_size_index);
411      return (p);
412    }
413  old_size=(1l << b->size_index)-HEADER_SIZE;
414  /* Try to expand by adding buddies at higher addresses. */
415  for (bb=buddy(b);
416       bb && (INT_PTR)b < (INT_PTR)bb && !bb->used && bb->size_index == b->size_index;
417       bb=buddy(b))
418    {
419      remove_from_free_list(bb);
420      if (++(b->size_index) == new_size_index)
421        return (p);
422    }
423  /* Couldn't expand all the way to needed size; allocate a new block */
424  /* and move the contents of the old one. */
425  q=mem_get_block(new_size);
426  mem_copy(q, p, old_size);
427  merge_and_free(b);
428  return (q);
429}
430#endif
431
432
433/* This code used if we're using malloc and free. */
434
435#if defined(USE_MALLOC_FREE)
436pointer
437#if defined(__STDC__)
438mem_get_block(SIZE_T size)
439#else
440mem_get_block(size)
441     SIZE_T size;
442#endif
443{
444  pointer result;
445
446  if (size <= 0)
447    return ((pointer)0);
448  result=MALLOC(size);
449  if (!result)
450    mem_fatal("mem_get_block: allocation failed");
451  return (result);
452}
453
454
455void
456#if defined(__STDC__)
457mem_free_block(pointer p)
458#else
459mem_free_block(p)
460     pointer p;
461#endif
462{
463  if (!p)
464    return;
465  FREE(p);
466}
467
468
469pointer
470#if defined(__STDC__)
471mem_resize_block(pointer p, SIZE_T new_size)
472#else
473mem_resize_block(p, new_size)
474     pointer p;
475     SIZE_T new_size;
476#endif
477{
478  if (!p)
479    return (mem_get_block(new_size));
480  if (new_size <= 0)
481    {
482      mem_free_block(p);
483      return ((pointer)0);
484    }
485  return (REALLOC(p, new_size));
486}
487#endif
Note: See TracBrowser for help on using the repository browser.