3 * Store handling for Steel
5 * version 1.00 6 September 1993
7 * © 1993-1998 Straylight
10 /*----- Licensing note ----------------------------------------------------*
12 * This file is part of Straylight's Steel library.
14 * Steel is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2, or (at your option)
19 * Steel is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
24 * You should have received a copy of the GNU General Public License
25 * along with Steel. If not, write to the Free Software Foundation,
26 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
50 /* #define mem__DEBUG_MALLOC */
51 /* Uncomment previous line for memDebug */
53 #define mem__MAGIC 0x45464153 /* Says 'SAFE' */
54 #define mem__SENTINEL 0x59524442 /* Says 'BDRY' */
56 #define OS_Module 0x2001E
58 typedef struct mem__rmaListstr
60 struct mem__rmaListstr *next;
61 struct mem__rmaListstr *prev;
62 #ifdef mem__DEBUG_MALLOC
70 static BOOL mem__initedFlex;
71 static BOOL mem__initedHeap;
72 static int mem__currentAlloc=mem__MALLOC;
73 static mem__rmaListstr *mem__rmaList;
74 #ifdef mem__DEBUG_MALLOC
75 static mem__rmaListstr *mem__mallocList;
77 static BOOL mem__usedRMA;
79 static mem_allocProc mem__userAlloc;
80 static mem_freeProc mem__userFree;
83 * void mem_flexdInit(const char *name)
86 * Initialises flex system. If flex is already initialised, nothing
87 * happens. This call should be used in preference to flex_init().
90 void mem_flexdInit(const char *name, long max)
94 flex_dinit(name, max);
101 void (mem_flexInit)(void) { mem_flexInit(); }
105 * void mem_heapInit(void)
108 * Initialises heap system. If heap is already initialised, nothing
109 * happens. If flex is not initialised, it is initialised for you. This
110 * call should be used in preference to heap_init(). Note that unlike
111 * earlier versioms, this call will NOT set up ArmenLib to use heap by
112 * default. This would be duplicating the functionality of mem_useHeap().
115 void mem_heapInit(void)
117 if (!mem__initedHeap)
121 mem__initedHeap=TRUE;
126 * void mem_useMalloc(void)
129 * Makes ArmenLib use malloc() etc. for memory allocation.
132 void mem_useMalloc(void)
134 mem__currentAlloc=mem__MALLOC;
138 * void mem_useHeap(void)
141 * Makes ArmenLib use heap_alloc() etc. for memory allocation. It is
142 * initialised if necessary.
145 void mem_useHeap(void)
148 mem__currentAlloc=mem__HEAP;
152 * void mem_useUser(mem_allocProc alloc,mem_freeProc free)
155 * Makes ArmenLib use your own user-defined memory allocation procedures.
158 * mem_allocProc alloc == a routine to allocate a block of memory. If a
159 * block of sufficient size cannot be allocated, return 0. Problems
160 * about allocating blocks of 0 size are handled before your routine is
162 * mem_freeProc free == a routine to free a block of memory. A valid
163 * pointer will be passed to your routine.
166 void mem_useUser(mem_allocProc alloc,mem_freeProc free)
168 mem__currentAlloc=mem__USER;
169 mem__userAlloc=alloc;
174 * void mem_useRMA(void)
177 * Makes ArmenLib use the RMA for memory allocation.
180 void mem_useRMA(void)
182 mem__currentAlloc=mem__RMA;
186 * void mem__tidyRMA(void)
189 * Frees any blocks allocated from the RMA at the end of the program, to
190 * avoid any problems with blocks being non-deallocatable.
193 static void mem__tidyRMA(void)
195 mem__rmaListstr *l=mem__rmaList;
206 * void *mem_RMAalloc(size_t size)
209 * Allocates a block of memory from the relocatable module area.
212 * size_t size == the size of the block
215 * A pointer to the block (or 0)
218 void *mem_RMAalloc(size_t size)
222 if (mem__usedRMA==FALSE)
224 atexit(mem__tidyRMA);
228 r.r[3]=size+sizeof(mem__rmaListstr);
229 if (_kernel_swi(OS_Module,&r,&r))
233 l=(mem__rmaListstr *)r.r[2];
235 mem__rmaList->prev=l;
236 l->next=mem__rmaList;
239 return ((void *)(l+1));
244 * void mem_RMAfree(void *ptr)
247 * Frees a block allocated using RMAalloc.
250 * void *ptr == a pointer to the block.
253 void mem_RMAfree(void *ptr)
256 mem__rmaListstr *l=((mem__rmaListstr *)(ptr))-1;
258 l->prev->next=l->next;
260 mem__rmaList=l->next;
262 l->next->prev=l->prev;
265 wimpt_noerr((os_error *)_kernel_swi(OS_Module,&r,&r));
268 #ifdef mem__DEBUG_MALLOC
270 #define mem__PASS_TEST 1
271 #define mem__PASS_DONE 0
272 #define mem__PASS_BAD 2
273 #define mem__PASS_DUMP 3
275 #define mem__walkmsg(x) \
277 if (pass==mem__PASS_DUMP) \
280 pass=mem__PASS_BAD; \
284 * static void mem__walkMalloc(char *op)
287 * Part of checked malloc routines. Checks that all allocated blocks are
291 * char *op == are we allocating or deallocating?
294 static void mem__walkMalloc(char *op)
297 int pass=mem__PASS_TEST;
298 while (pass!=mem__PASS_DONE)
303 if (pass==mem__PASS_DUMP)
304 printf("\n%p %-8i ",(l+1),l->length);
305 if (l->check!=mem__MAGIC)
306 mem__walkmsg("Bad block header ");
307 if (*(l->sentinel)!=mem__SENTINEL)
308 mem__walkmsg("Block overflow ");
309 if ((int)l->next<0x8000 && l->next!=0)
310 mem__walkmsg("Bad forward link ");
313 if (l->next->prev!=l)
314 mem__walkmsg("Link corrupted ");
328 printf("Error found in malloc chain during %s\n",op);
329 printf(" malloc block dump follows\n\n");
330 printf("Address Length Faults");
331 /* 12345678 12345678 */
338 "Please report this error to Straylight.\n"
340 "If debugging, press SHIFT-F12 for backtrace, otherwise, press\n"
341 "any key to quit program.\n"
355 * void *mem__debugAlloc(size_t size)
358 * malloc debugging allocation routine.
361 * size_t size == the size of the block
364 * A pointer to the block (or 0)
367 static void *mem__debugAlloc(size_t size)
371 mem__walkMalloc("alloc");
372 if (l=malloc(size+sizeof(mem__rmaListstr)+4),!l)
377 mem__mallocList->prev=l;
378 l->next=mem__mallocList;
382 sent=(int)(l+1)+size;
385 l->sentinel=(int *)sent;
387 *(l->sentinel)=mem__SENTINEL;
388 return ((void *)(l+1));
393 * void mem__debugFree(void *ptr)
396 * Frees a block allocated using mem__debugAlloc
399 * void *ptr == a pointer to the block.
402 static void mem__debugFree(void *ptr)
404 mem__rmaListstr *l=((mem__rmaListstr *)(ptr))-1;
405 mem__walkMalloc("free");
407 l->prev->next=l->next;
409 mem__mallocList=l->next;
411 l->next->prev=l->prev;
418 * void *mem_alloc(size_t size)
421 * Allocates a block of memory using malloc (or heap if initialised). If
422 * size is zero, or allocation fails then a NULL pointer is returned.
425 * size_t size == how big you want the block.
428 * A pointer to the block allocated.
431 void *mem_alloc(size_t size)
437 switch (mem__currentAlloc)
440 ptr=heap_alloc(size);
443 #ifdef mem__DEBUG_MALLOC
444 ptr=mem__debugAlloc(size);
450 ptr=mem_RMAalloc(size);
453 ptr=mem__userAlloc(size);
458 ptr[0]=mem__currentAlloc;
460 return ((void *)(ptr+2));
464 * void mem_free(void *ptr)
467 * Frees a block of memory. It must have been allocated using mem_alloc().
468 * If ptr is NULL, then mem_free() does nothing.
471 * void *ptr == the pointer returned by mem_alloc()
474 void mem_free(void *ptr)
476 int *i=((int *)ptr)-2;
482 #ifdef mem__DEBUG_MALLOC
501 * size_t mem_sizeOfBlock(void *ptr)
504 * Returns the allocated size of the block.
507 * void *ptr == the pointer to the block
510 * The size of the block.
513 size_t mem_sizeOfBlock(void *ptr)
515 int *i=((int *)ptr)-2;
523 * void *mem_reAlloc(void *ptr,size_t newSize)
526 * Alters the size of the block given. If the block could not be resized,
527 * its contents are unchanged. Note that the block may move as a result of
531 * void *ptr == a pointer to the block. This may be NULL, in which case,
532 * this call behaves exactly like mem_alloc().
533 * size_t newSize == the new size to make the block. This may be zero, in
534 * which case the block is freed.
537 * A pointer to the block.
540 void *mem_reAlloc(void *ptr,size_t newSize)
543 int size=mem_sizeOfBlock(ptr);
545 return (mem_alloc(newSize));
546 if (newPtr=mem_alloc(newSize),newSize==0)
550 memcpy(newPtr,ptr,size);
556 * void mem_allowFlexBudge(BOOL allow)
559 * A slightly more sensible way to allow flex store to be shunted around.
562 * BOOL allow == whether you want flex store to be shifted around willy-
566 void mem_allowFlexBudge(BOOL allow)
568 _kernel_register_slotextend(allow ? flex_budge : flex_dont_budge);