/** ** TALLOC.C ** ** lean_and_mean malloc()/free implementation ** by tom ehlert, te@drivesnapshot.de ** ** please be careful: ** ** this is only slightly tested and has NO ERRORCHECCKING AT ALL ** no internal checking. no stack checking. nothing !! ** ** use it only, if your programs are already debugged !! **/ #ifndef _MSC_VER /* MSC has no brk/sbrk */ #include #include #ifdef __TURBOC__ extern void *__brklvl; #define sbrk(x) __brklvl #define brk(newbrk) \ (((char *)(newbrk) > (char *)(&length) - 0x200) ? \ -1 : \ (__brklvl = (newbrk), 0)) #endif #ifdef __WATCOMC__ #include #define brk(newbrk) ((int)__brk((unsigned)(newbrk))) #endif #ifdef __GNUC__ #include #endif #define BUSY (sizeof(size_t)-1) /* Bit set if memory block in use*/ #define isbusy(x) ((x->length)&BUSY) /** *** _memavl() *** return max. memory available *** Q & D **/ #ifdef DEBUG extern int printf(const char *x, ...); #define dbprintf(x) printf x #else #define dbprintf(x) #endif /*#define printf getch() != ' ' ? exit(0) : printf*/ typedef union { size_t length; char data[1]; } block; void *malloc(size_t length) { static block *alloc_bottom = NULL; block *akt, *next; block *ltop = sbrk(0); if (alloc_bottom == NULL) alloc_bottom = ltop; length = (length + sizeof(size_t) + BUSY) & ~BUSY; akt = alloc_bottom; for (;;) { if (akt == ltop) { /* end of initialized memory */ next = (block *)&akt->data[length]; if (next < akt || brk(next) == -1) return NULL; break; } dbprintf(("follow [%x] = %x\n",akt, akt->length)); next = (block *)(&akt->data[akt->length & ~BUSY]); if (next == ltop || isbusy(akt)) { akt = next; /* next block */ } else if (isbusy(next)) { size_t size = akt->length; if (size >= length) /* try to split */ { if (size > length) /* split */ { ((block *)&akt->data[length])->length = size - length; } break; } akt = next; /* next block */ } else { /* merge 2 blocks */ akt->length += next->length; } } akt->length = length | BUSY; dbprintf(("set [%x] = %x\n",akt,akt->length)); return &akt->data[sizeof(size_t)]; } #ifdef __WATCOMC__ void *_nmalloc(unsigned length) { return malloc(length); } #endif /** ** reset busy-bit **/ void free(void *ptr) { if (ptr) ((char *) ptr)[-sizeof(size_t)] &= ~BUSY; } #ifdef TALLOC_NEED_REALLOC /* there isn't often need for realloc ;) */ void* realloc(void *ptr,size_t newlength) { size_t oldlength = ((size_t*)ptr)[-1] & ~BUSY; void *newptr; newptr = malloc(newlength); if (newptr == NULL) { if (newlength <= oldlength) return ptr; } else { memcpy(newptr,ptr,oldlength); } free(ptr); return newptr; } #endif #ifdef TEST #include int gallocated = 0; void *testalloc(size_t length) { void *p; printf("alloc %x bytes - ",length); p = malloc(length); if (p) gallocated += length,printf("at %x - sum=%x\n",p,gallocated); else printf("failed\n"); return p; } void testfree(void* p) { gallocated -= ((size_t*)p)[-1] & ~BUSY; printf("free %x \n",p); free(p); } main() { char *s1,*s2,*s3,*s4,*s5,*s6; unsigned size; s1 = testalloc(1); s2 = testalloc(2); s3 = testalloc(0x10); s4 = testalloc(0x100); s5 = testalloc(0x1000); s6 = testalloc(0xfff0); testfree(s3); s3 = testalloc(6); testfree(s2); testalloc(8); #ifdef __GNUC__ for(size = 0xe0000000; size;) #else for(size = 0xe000; size;) #endif { if (testalloc(size)) ; else size >>= 1; } testfree(s1); testfree(s5); testfree(s4); testfree(s6); return 1; } #endif #endif