1 /* Copyright (C) 1995,1996 Robert de Bath <rdebath@cix.compulink.co.uk>
2 * This file is part of the Linux-8086 C library and is distributed
3 * under the GNU Library General Public License.
7 * This is a combined alloca/malloc package. It uses a classic algorithm
8 * and so may be seen to be quite slow compared to more modern routines
9 * with 'nasty' distributions.
15 #define MCHUNK 2048 /* Allocation unit in 'mem' elements */
16 #define XLAZY_FREE /* If set frees can be infinitly defered */
17 #define XMINALLOC 32 /* Smallest chunk to alloc in 'mem's */
18 #define XVERBOSE /* Lots of noise, debuging ? */
21 #define MAX_INT ((int)(((unsigned)-1)>>1))
29 typedef union mem_cell
31 union mem_cell
*next
; /* A pointer to the next mem */
32 unsigned int size
; /* An int >= sizeof pointer */
33 char *depth
; /* For the alloca hack */
37 #define m_size(p) ((p) [0].size) /* For malloc */
38 #define m_next(p) ((p) [1].next) /* For malloc and alloca */
39 #define m_deep(p) ((p) [0].depth) /* For alloca */
41 extern void *__mini_malloc
__P ((size_t));
42 extern void *(*__alloca_alloc
) __P ((size_t));
43 extern mem
*__freed_list
;
46 /* Start the alloca with just the dumb version of malloc */
48 void *(*__alloca_alloc
) __P ((size_t)) = __mini_malloc
;
49 mem
*__freed_list
= 0;
52 /* NB: Careful here, stdio may use malloc - so we can't */
56 static char hex
[] = "0123456789ABCDEF";
58 for (i
= sizeof(int)*8-4; i
>= 0; i
-= 4)
59 write(2, hex
+ ((val
>> i
) & 0xF), 1);
66 write(2, "Malloc ", 7);
69 if(x
) phex(m_size(x
)); else phex(0);
71 if(x
) phex(m_next(x
)); else phex(0);
73 write(2, y
, strlen(y
));
81 /* This alloca is based on the same concept as the EMACS fallback alloca.
82 * It should probably be considered Copyright the FSF under the GPL.
84 static mem
*alloca_stack
= 0;
90 auto char probe
; /* Probes stack depth: */
94 * Reclaim garbage, defined as all alloca'd storage that was allocated
95 * from deeper in the stack than currently.
98 for (hp
= alloca_stack
; hp
!= 0;)
99 if (m_deep(hp
) < &probe
)
101 register mem
*np
= m_next(hp
);
102 free((void *) hp
); /* Collect garbage. */
103 hp
= np
; /* -> next header. */
106 break; /* Rest are not deeper. */
108 alloca_stack
= hp
; /* -> last valid storage. */
110 return 0; /* No allocation required. */
112 hp
= (mem
*) (*__alloca_alloc
) (sizeof(mem
)*2 + size
);
116 m_next(hp
) = alloca_stack
;
120 /* User storage begins just after header. */
121 return (void *) (hp
+ 2);
123 #endif /* L_alloca */
131 register mem
*chk
= (mem
*) ptr
;
134 return; /* free(NULL) - be nice */
138 top
= (mem
*) sbrk(0);
139 if (chk
+ m_size(chk
) == top
)
141 noise("FREE brk", chk
);
142 brk(top
-m_size(chk
));
144 * Adding this code allow free to release blocks in any order; they
145 * can still only be allocated from the top of the heap tho.
147 #ifdef __MINI_MALLOC__
148 if (__alloca_alloc
== __mini_malloc
&& __freed_list
)
152 __freed_list
= m_next(__freed_list
);
158 { /* Nope, not sure where this goes, leave
159 * it for malloc to deal with */
160 #ifdef __MINI_MALLOC__
161 if( __freed_list
|| chk
> __freed_list
)
162 { m_next(chk
) = __freed_list
; __freed_list
= chk
; }
167 for(top
=__freed_list
; top
&& top
> chk
; prev
=top
, top
=m_next(top
))
173 m_next(chk
) = __freed_list
;
176 noise("ADD LIST", chk
);
185 register unsigned int sz
;
187 /* First time round this _might_ be odd, But we won't do that! */
188 sz
= (unsigned int) sbrk(0);
189 if (sz
& (sizeof(mem
) - 1))
190 sbrk(4 - (sz
& (sizeof(mem
) - 1)));
194 /* Minor oops here, sbrk has a signed argument */
195 if( size
> (((unsigned)-1)>>1)-sizeof(mem
)*3 )
201 size
+= sizeof(mem
) * 2 - 1; /* Round up and leave space for size field */
204 ptr
= (mem
*) sbrk(size
* sizeof(mem
));
209 noise("CREATE", ptr
);
217 * The chunk_list pointer is either NULL or points to a chunk in a
218 * circular list of all the free blocks in memory
221 #define Static static
223 static mem
*chunk_list
= 0;
224 Static
void __insert_chunk();
225 Static mem
*__search_chunk();
231 register mem
*ptr
= 0;
232 register unsigned int sz
;
235 return 0; /* ANSI STD */
237 sz
= size
+ sizeof(mem
) * 2 - 1;
249 noise("WANTED", arr
);
253 __alloca_alloc
= malloc
; /* We'll be messing with the heap now TVM */
256 ptr
= __search_chunk(sz
);
261 /* First deal with the freed list */
267 __freed_list
= m_next(__freed_list
);
269 if (m_size(ptr
) == sz
) /* Oh! Well that's lucky ain't it
272 noise("LUCKY MALLOC", ptr
);
278 ptr
= m_next(chunk_list
);
279 if (ptr
+ m_size(ptr
) == (void *) sbrk(0))
281 /* Time to free for real */
282 m_next(chunk_list
) = m_next(ptr
);
283 if (ptr
== m_next(ptr
))
288 ptr
= __search_chunk(sz
);
292 ptr
= __search_chunk(sz
);
298 alloc
= sizeof(mem
) * (MCHUNK
* ((sz
+ MCHUNK
- 1) / MCHUNK
) - 1);
299 ptr
= __mini_malloc(alloc
);
301 __insert_chunk(ptr
- 1);
302 else /* Oooo, near end of RAM */
304 unsigned int needed
= alloc
;
305 for(alloc
/=2; alloc
>256 && needed
; )
307 ptr
= __mini_malloc(alloc
);
310 if( alloc
> needed
) needed
= 0; else needed
-= alloc
;
311 __insert_chunk(ptr
- 1);
316 ptr
= __search_chunk(sz
);
321 ptr
= __mini_malloc(size
);
325 noise("MALLOC FAIL", 0);
327 noise("MALLOC NOW", ptr
- 1);
337 ptr
[1].size
= 0x55555555;
339 noise("MALLOC RET", ptr
);
344 * This function takes a pointer to a block of memory and inserts it into
345 * the chain of memory chunks
349 __insert_chunk(mem_chunk
)
352 register mem
*p1
, *p2
;
353 if (chunk_list
== 0) /* Simple case first */
355 m_next(mem_chunk
) = chunk_list
= mem_chunk
;
356 noise("FIRST CHUNK", mem_chunk
);
366 if (m_next(p2
) <= p2
)
367 { /* We're at the top of the chain, p1 is
370 if (p2
+ m_size(p2
) == p1
)
371 { /* Good, stick 'em together */
372 noise("INSERT CHUNK", mem_chunk
);
373 m_size(p2
) += m_size(p1
);
378 m_next(p1
) = m_next(p2
);
380 noise("INSERT CHUNK", mem_chunk
);
387 /* In chain, p1 between p2 and next */
389 m_next(p1
) = m_next(p2
);
391 noise("INSERT CHUNK", mem_chunk
);
394 /* Try to join above */
395 if (p1
+ m_size(p1
) == m_next(p1
))
397 m_size(p1
) += m_size(m_next(p1
));
398 m_next(p1
) = m_next(m_next(p1
));
401 /* Try to join below */
402 if (p2
+ m_size(p2
) == p1
)
404 m_size(p2
) += m_size(p1
);
405 m_next(p2
) = m_next(p1
);
408 chunk_list
= p2
; /* Make sure it's valid */
414 if (m_next(p2
) <= p2
&& p1
< m_next(p2
))
416 /* At top of chain, next is bottom of chain, p1 is below next */
418 m_next(p1
) = m_next(p2
);
420 noise("INSERT CHUNK", mem_chunk
);
424 if (p1
+ m_size(p1
) == m_next(p1
))
426 if (p2
== m_next(p1
))
428 m_size(p1
) += m_size(m_next(p1
));
429 m_next(p1
) = m_next(m_next(p1
));
435 chunk_list
= p2
; /* Save for search */
438 while (p2
!= chunk_list
);
440 /* If we get here we have a problem, ignore it, maybe it'll go away */
441 noise("DROPPED CHUNK", mem_chunk
);
445 * This function will search for a chunk in memory of at least 'mem_size'
446 * when found, if the chunk is too big it'll be split, and pointer to the
447 * chunk returned. If none is found NULL is returned.
451 __search_chunk(mem_size
)
452 unsigned int mem_size
;
454 register mem
*p1
, *p2
;
455 if (chunk_list
== 0) /* Simple case first */
458 /* Search for a block >= the size we want */
459 p1
= m_next(chunk_list
);
463 noise("CHECKED", p1
);
464 if (m_size(p1
) >= mem_size
)
470 while (p2
!= chunk_list
);
472 /* None found, exit */
473 if (m_size(p1
) < mem_size
)
476 /* If it's exactly right remove it */
477 if (m_size(p1
) < mem_size
+ 2)
479 noise("FOUND RIGHT", p1
);
480 chunk_list
= m_next(p2
) = m_next(p1
);
481 if (chunk_list
== p1
)
487 /* Otherwise split it */
488 m_next(p2
) = p1
+ mem_size
;
492 m_size(p2
) = m_size(p1
) - mem_size
;
493 m_next(p2
) = m_next(p1
);
494 m_size(p1
) = mem_size
;
495 if (chunk_list
== p1
)
498 p1
[1].size
= 0xAAAAAAAA;
500 noise("INSERT CHUNK", p2
);
501 noise("FOUND CHUNK", p1
);
502 noise("LIST IS", chunk_list
);
506 #endif /* L_malloc */
511 unsigned int elm
, sz
;
513 register unsigned int v
;
515 ptr
= malloc(v
= elm
* sz
);
520 #endif /* L_calloc */
533 osize
= (m_size(((mem
*) ptr
) - 1) - 1) * sizeof(mem
);
544 memcpy(nptr
, ptr
, osize
);
549 #endif /* L_realloc */