├── .gitignore ├── LICENSE ├── README ├── files.mk ├── makefile └── src ├── default └── tinyheap_config.h ├── main.c ├── tinyheap.c └── tinyheap.h /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2012-2013 Peter Andersson (pelleplutt1976gmail.com) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | TINYHEAP 2 | 3 | Simple, linked-list implementation of a heap in pure C. 4 | 5 | See the tinyheap_config.h in the default/ folder for buildtime configurations. 6 | 7 | To be used in an embedded environment with small ram. 8 | 9 | Use the heap by doing something like this: 10 | 11 | #include "tinyheap.h" 12 | 13 | // use this space as heap 14 | static char heap_space[4096]; 15 | // this is the heap metainfo 16 | static tinyheap heap; 17 | 18 | // initiate heap, do this at startup 19 | void startup_heap_init(void) { 20 | th_init(&heap, heap_space, sizeof(heap_space)); 21 | } 22 | 23 | // use the heap 24 | void use_heap(void) { 25 | void *data = th_malloc(&heap, 100); 26 | if (data == 0) { 27 | .. out of memory .. 28 | } else { 29 | .. do something with those hundred bytes .. 30 | th_free(&heap, data); 31 | } 32 | } 33 | 34 | -------------------------------------------------------------------------------- /files.mk: -------------------------------------------------------------------------------- 1 | tinyheap = ../generic/tinyheap/src 2 | FLAGS += -DCONFIG_BUILD_TINYHEAP 3 | INC += -I${tinyheap} 4 | CPATH += ${tinyheap} 5 | CFILES += tinyheap.c 6 | 7 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | BINARY = linux_tinyheap 2 | 3 | ############ 4 | # 5 | # Paths 6 | # 7 | ############ 8 | 9 | sourcedir = src 10 | builddir = build 11 | 12 | 13 | ############# 14 | # 15 | # Build tools 16 | # 17 | ############# 18 | 19 | CC = gcc $(COMPILEROPTIONS) 20 | AS = gcc $(ASSEMBLEROPTIONS) 21 | LD = ld 22 | GDB = gdb 23 | OBJCOPY = objcopy 24 | OBJDUMP = objdump 25 | MKDIR = mkdir -p 26 | 27 | ############### 28 | # 29 | # Files and libs 30 | # 31 | ############### 32 | 33 | CFILES = main.c 34 | include files.mk 35 | INCLUDE_DIRECTIVES = -I./${sourcedir} -I./${sourcedir}/default 36 | COMPILEROPTIONS = $(INCLUDE_DIRECTIVES) 37 | 38 | ############ 39 | # 40 | # Tasks 41 | # 42 | ############ 43 | 44 | vpath %.c ${sourcedir} ${sourcedir}/default 45 | 46 | OBJFILES = $(CFILES:%.c=${builddir}/%.o) 47 | 48 | DEPFILES = $(CFILES:%.c=${builddir}/%.d) 49 | 50 | ALLOBJFILES += $(OBJFILES) 51 | 52 | DEPENDENCIES = $(DEPFILES) 53 | 54 | # link object files 55 | $(BINARY): $(ALLOBJFILES) 56 | @echo "... linking" 57 | @${CC} $(LINKEROPTIONS) -o ${builddir}/$(BINARY).elf $(ALLOBJFILES) $(LIBS) 58 | 59 | -include $(DEPENDENCIES) 60 | 61 | # compile c files 62 | $(OBJFILES) : ${builddir}/%.o:%.c 63 | @echo "... compile $@" 64 | @${CC} -c -Wall -o $@ $< 65 | 66 | # make dependencies 67 | $(DEPFILES) : ${builddir}/%.d:%.c 68 | @echo "... depend $@"; \ 69 | rm -f $@; \ 70 | ${CC} $(COMPILEROPTIONS) -M $< > $@.$$$$; \ 71 | sed 's,\($*\)\.o[ :]*, ${builddir}/\1.o $@ : ,g' < $@.$$$$ > $@; \ 72 | rm -f $@.$$$$ 73 | 74 | all: mkdirs $(BINARY) 75 | 76 | mkdirs: 77 | -@${MKDIR} ${builddir} 78 | 79 | clean: 80 | @echo ... removing build files in ${builddir} 81 | @rm -f ${builddir}/*.o 82 | @rm -f ${builddir}/*.d 83 | -------------------------------------------------------------------------------- /src/default/tinyheap_config.h: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright (c) 2012-2013 Peter Andersson (pelleplutt1976gmail.com) 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | 23 | /* 24 | * tinyheap_config.h 25 | * Copy and reconfigure this file to suit your own project. 26 | * 27 | * Created on: Oct 6, 2012 28 | * Author: petera 29 | */ 30 | 31 | #ifndef TINYHEAP_CONFIG_H_ 32 | #define TINYHEAP_CONFIG_H_ 33 | 34 | 35 | /* number of bytes in heap that can be addressed: 36 | TH_BLOCKSIZE * (2^(TH_ADDRESSING_BITS-1) - 1) */ 37 | /* number of address bits in each block header */ 38 | #ifndef TH_ADDRESSING_BITS 39 | #define TH_ADDRESSING_BITS 8 40 | #endif 41 | 42 | /* the minimum heap entity in bytes */ 43 | #ifndef TH_BLOCKSIZE 44 | #define TH_BLOCKSIZE 32 45 | #endif 46 | 47 | /* keep track of free number of bytes in heap */ 48 | #ifndef TH_CALC_FREE 49 | #define TH_CALC_FREE 1 50 | #endif 51 | 52 | /* safety check heap boundary during free block scan */ 53 | #ifndef TH_CHECK_BOUNDARY 54 | #define TH_CHECK_BOUNDARY 1 55 | #endif 56 | 57 | /* safety check if freeing a freed block */ 58 | #ifndef TH_CHECK_FREE_OF_FREE 59 | #define TH_CHECK_FREE_OF_FREE 1 60 | #endif 61 | 62 | /* calculate a parity bit in each block header, check for corruption, 63 | pretty bad algo, finds only 50% of overwrites */ 64 | #ifndef TH_USE_PARITY 65 | #define TH_USE_PARITY 0 66 | #endif 67 | 68 | /* when to check for parity */ 69 | #ifndef TH_PARITY_CHCEK_LEVEL 70 | #define TH_PARITY_CHECK_LEVEL TH_PARITY_CHECK_ALL 71 | #endif 72 | /* check parity when freeing a block */ 73 | #define TH_PARITY_CHECK_DURING_FREE 1 74 | /* check parity when mallocing and scanning for free blocks */ 75 | #define TH_PARITY_CHECK_DURING_MALLOC 2 76 | /* check parity whenever possible */ 77 | #define TH_PARITY_CHECK_ALL 3 78 | 79 | /* keep track of number of block search during free scan */ 80 | #ifndef TH_COUNT_SEARCH_CYCLES 81 | #define TH_COUNT_SEARCH_CYCLES 0 82 | #endif 83 | 84 | /* Free block tracking strategies */ 85 | 86 | /* simply starts looking for free blocks from start of heap */ 87 | #ifndef TH_SEEK_STRAT_NONE 88 | #define TH_SEEK_STRAT_NONE 0 89 | #endif 90 | 91 | /* keeps note of last seen free block, small overhead in code */ 92 | #ifndef TH_SEEK_STRAT_LAST_FREE 93 | #define TH_SEEK_STRAT_LAST_FREE 0 94 | #endif 95 | 96 | /* keeps pointers to min and max free blocks seen, split by 97 | TH_BLOCK_MEDIAN, somewhat bigger overhead */ 98 | #ifndef TH_SEEK_STRAT_MIN_MAX 99 | #define TH_SEEK_STRAT_MIN_MAX 1 100 | #endif 101 | #if TH_SEEK_STRAT_MIN_MAX 102 | /* smaller or equal requests indicates small block size, bigger 103 | requests big block size */ 104 | #define TH_BLOCK_MEDIAN 3 105 | #endif 106 | 107 | #if TH_SEEK_STRAT_NONE && (TH_SEEK_STRAT_LAST_FREE || TH_SEEK_STRAT_MIN_MAX) 108 | #error "only one tracking strategy can be enabled" 109 | #endif 110 | 111 | #if TH_SEEK_STRAT_LAST_FREE && (TH_SEEK_STRAT_NONE || TH_SEEK_STRAT_MIN_MAX) 112 | #error "only one tracking strategy can be enabled" 113 | #endif 114 | 115 | #if TH_SEEK_STRAT_MIN_MAX && (TH_SEEK_STRAT_LAST_FREE || TH_SEEK_STRAT_NONE) 116 | #error "only one tracking strategy can be enabled" 117 | #endif 118 | 119 | /* Free block picking strategies */ 120 | 121 | /* pick first free fitting block found */ 122 | #ifndef TH_PICK_STRAT_FIRST 123 | #define TH_PICK_STRAT_FIRST 0 124 | #endif 125 | 126 | /* pick the block that fits exactly or with minimum delta */ 127 | #ifndef TH_PICK_STRAT_BEST_FIT 128 | #define TH_PICK_STRAT_BEST_FIT 0 129 | #endif 130 | 131 | /* pick block that has a delta less than specified in 132 | TH_GOOD_ENOUGH_DELTA */ 133 | #ifndef TH_PICK_STRAT_GOOD_ENOUGH_FIT 134 | #define TH_PICK_STRAT_GOOD_ENOUGH_FIT 1 135 | #endif 136 | #if TH_PICK_STRAT_GOOD_ENOUGH_FIT 137 | /* if nbr of delta blocks is equal or less, the free block 138 | is taken (0 means the same as BEST_FIT) */ 139 | #define TH_GOOD_ENOUGH_DELTA 1 140 | #endif 141 | 142 | #if TH_PICK_STRAT_FIRST && (TH_PICK_STRAT_BEST_FIT || TH_PICK_STRAT_GOOD_ENOUGH_FIT) 143 | #error "only one picking strategy can be enabled" 144 | #endif 145 | 146 | #if TH_PICK_STRAT_BEST_FIT && (TH_PICK_STRAT_FIRST || TH_PICK_STRAT_GOOD_ENOUGH_FIT) 147 | #error "only one picking strategy can be enabled" 148 | #endif 149 | 150 | #if TH_PICK_STRAT_GOOD_ENOUGH_FIT && (TH_PICK_STRAT_FIRST || TH_PICK_STRAT_BEST_FIT) 151 | #error "only one picking strategy can be enabled" 152 | #endif 153 | 154 | /* in multithreading environments locking can be implemented here */ 155 | #ifndef TH_LOCK 156 | #define TH_LOCK(heapptr) 157 | #endif 158 | /* in multithreading environments unlocking can be implemented here */ 159 | #ifndef TH_UNLOCK 160 | #define TH_UNLOCK(heapptr) 161 | #endif 162 | 163 | /* called when a check fails, heap is corrupted */ 164 | #ifndef TH_ASSERT 165 | #define TH_ASSERT(mustBeTrue) if (!(mustBeTrue)) TH_PRINTF("assert"); 166 | #endif 167 | 168 | /* called when memory is freed */ 169 | #ifndef TH_ON_FREED 170 | #define TH_ON_FREED(addr, len) //memset(addr, 0xff, len) 171 | #endif 172 | /* called when memory is allocated */ 173 | #ifndef TH_ON_MALLOCED 174 | #define TH_ON_MALLOCED(addr, len) //memset(addr, 0xaa, len) 175 | #endif 176 | /* called for the remaining free part when free memory is allocated */ 177 | #ifndef TH_ON_SPLITFREED 178 | #define TH_ON_SPLITFREED(addr, len) //memset(addr, 0x55, len) 179 | #endif 180 | 181 | /* address alignment for returned pointers to heap */ 182 | #ifndef TH_ADDRESS_ALIGN 183 | /* align size, default to size of a pointer on target platform */ 184 | #define TH_ADDRESS_ALIGN sizeof(void *) 185 | #endif 186 | 187 | /* debug */ 188 | #ifndef TH_DUMP 189 | #define TH_DUMP 1 190 | #endif 191 | 192 | /* debug */ 193 | #ifndef TH_PRINTF 194 | #define TH_PRINTF(...) 195 | #endif 196 | 197 | 198 | #endif /* TINYHEAP_CONFIG_H_ */ 199 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | /* 2 | * main.c 3 | * 4 | * Created on: Oct 6, 2012 5 | * Author: petera 6 | */ 7 | 8 | 9 | int main (int argc, char **argv) { 10 | exit(0); 11 | } 12 | -------------------------------------------------------------------------------- /src/tinyheap.c: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright (c) 2012-2013 Peter Andersson (pelleplutt1976gmail.com) 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | 23 | /* 24 | * tinyheap.c 25 | * 26 | * Created on: Apr 5, 2012 27 | * Author: petera 28 | */ 29 | 30 | #include "tinyheap.h" 31 | 32 | #if TH_USE_PARITY 33 | #define TH_ASSERT_PAR_MALLOC(__x) \ 34 | if (TH_PARITY_CHECK_LEVEL >= TH_PARITY_CHECK_DURING_MALLOC) \ 35 | TH_ASSERT(th_checkParity(__x)); 36 | #else 37 | #define TH_ASSERT_PAR_MALLOC(__x) 38 | #endif 39 | 40 | #if TH_USE_PARITY 41 | #define TH_ASSERT_PAR_FREE(__x) \ 42 | if (TH_PARITY_CHECK_LEVEL >= TH_PARITY_CHECK_DURING_FREE) \ 43 | TH_ASSERT(th_checkParity(__x)); 44 | #else 45 | #define TH_ASSERT_PAR_FREE(__x) 46 | #endif 47 | 48 | #define TH_ASSERT_FREE_FREED(__x) \ 49 | if (TH_CHECK_FREE_OF_FREE) \ 50 | TH_ASSERT(!(__x)->free); 51 | 52 | #if TH_USE_PARITY 53 | #define TH_CALC_PARITY(__x) \ 54 | th_calcParity(__x); 55 | #else 56 | #define TH_CALC_PARITY(__x) 57 | #endif 58 | 59 | #if TH_USE_PARITY 60 | static void th_calcParity(th_block_h* h) { 61 | h->parity = ((~h->free) ^ h->next ^ h->prev); 62 | } 63 | 64 | static int th_checkParity(th_block_h* h) { 65 | return h->parity == (((~h->free) ^ h->next ^ h->prev) & 1); 66 | } 67 | #endif 68 | 69 | static th_block_h* th_prev(tinyheap* heap, th_block_h* block) { 70 | if (block->prev > 0) { 71 | return (th_block_h*)((char*)block - block->prev * TH_BLOCKSIZE); 72 | } else { 73 | // there was no first block 74 | return 0; 75 | } 76 | } 77 | 78 | static th_block_h* th_next(tinyheap* heap, th_block_h* block) { 79 | th_block_h* nblock = (th_block_h*)((void*)block + block->next * TH_BLOCKSIZE); 80 | if (((void*)nblock - (void*)heap->p) < heap->len * TH_BLOCKSIZE ) { 81 | return nblock; 82 | } else { 83 | // there was no next block 84 | return 0; 85 | } 86 | } 87 | 88 | void th_init(tinyheap* heap, void* buffer, int len) { 89 | heap->p = buffer; 90 | heap->len = len/TH_BLOCKSIZE; 91 | #if TH_CALC_FREE 92 | heap->free = heap->len; 93 | #endif 94 | #if TH_SEEK_STRAT_MIN_MAX 95 | heap->smallFree = 0; 96 | heap->bigFree = 0; 97 | #endif 98 | #if TH_SEEK_STRAT_LAST_FREE 99 | heap->lastFree = 0; 100 | #endif 101 | heap->p[0].free = 1; 102 | heap->p[0].next = len/TH_BLOCKSIZE; 103 | heap->p[0].prev = 0; 104 | TH_ON_FREED((void*)&heap->p[0] + sizeof(th_block_h), heap->len * TH_BLOCKSIZE - sizeof(th_block_h)); 105 | TH_CALC_PARITY(&heap->p[0]); 106 | } 107 | 108 | static th_block_h* th_findFree(tinyheap* heap, unsigned int bsize, th_block_h* block) { 109 | th_block_h* bcand = block; 110 | TH_ASSERT_PAR_MALLOC(bcand); 111 | #if TH_CHECK_BOUNDARY 112 | unsigned int testlen = 0; 113 | #endif 114 | #if TH_PICK_STRAT_BEST_FIT || TH_PICK_STRAT_GOOD_ENOUGH_FIT 115 | unsigned int minD = heap->len; 116 | th_block_h* minDBlock = 0; 117 | #endif 118 | do { 119 | #if TH_CHECK_BOUNDARY 120 | TH_ASSERT(bcand->next > 0); 121 | #endif 122 | if (bcand->free && bcand->next >= bsize) { 123 | // found one 124 | #if TH_PICK_STRAT_FIRST 125 | return bcand; 126 | #endif 127 | #if TH_PICK_STRAT_BEST_FIT || TH_PICK_STRAT_GOOD_ENOUGH_FIT 128 | unsigned int d = bcand->next - bsize; 129 | #if TH_PICK_STRAT_BEST_FIT 130 | if (d <= 0) 131 | #endif 132 | #if TH_PICK_STRAT_GOOD_ENOUGH_FIT 133 | if (d <= TH_GOOD_ENOUGH_DELTA) 134 | #endif 135 | { 136 | return bcand; 137 | } else if (d < minD) { 138 | minD = d; 139 | minDBlock = bcand; 140 | } 141 | #endif 142 | } 143 | #if TH_COUNT_SEARCH_CYCLES 144 | heap->count++; 145 | #endif 146 | // next block 147 | #if TH_CHECK_BOUNDARY 148 | testlen += bcand->next; 149 | TH_ASSERT(testlen <= heap->len); 150 | #endif 151 | bcand = th_next(heap, bcand); 152 | if (bcand == 0) { 153 | // wrap 154 | bcand = heap->p; 155 | } 156 | TH_ASSERT_PAR_MALLOC(bcand); 157 | } while (bcand != block); 158 | #if TH_PICK_STRAT_FIRST 159 | return 0; 160 | #endif 161 | #if TH_PICK_STRAT_BEST_FIT || TH_PICK_STRAT_GOOD_ENOUGH_FIT 162 | return minDBlock; 163 | #endif 164 | } 165 | 166 | static void th_internalAlloc(tinyheap* heap, unsigned int bsize, th_block_h* block) { 167 | unsigned int fullblocksize = block->next; 168 | block->free = 0; 169 | block->next = bsize; 170 | TH_CALC_PARITY(block); 171 | th_block_h* nblock = th_next(heap, block); 172 | #if TH_CALC_FREE 173 | heap->free -= bsize; 174 | #endif 175 | TH_ON_MALLOCED((void*)block + sizeof(th_block_h), block->next * TH_BLOCKSIZE - sizeof(th_block_h)); 176 | // split block if free is larger than requested 177 | if ((nblock - heap->p)/TH_BLOCKSIZE < heap->len && fullblocksize > bsize) { 178 | nblock->free = 1; 179 | nblock->next = fullblocksize - bsize; 180 | nblock->prev = bsize; 181 | TH_CALC_PARITY(nblock); 182 | #if TH_SEEK_STRAT_MIN_MAX 183 | if (nblock->next <= TH_BLOCK_MEDIAN) { 184 | if (heap->smallFree == 0 || !heap->smallFree->free) { 185 | heap->smallFree = nblock; 186 | } 187 | } else { 188 | if (heap->bigFree == 0 || !heap->bigFree->free) { 189 | heap->bigFree = nblock; 190 | } 191 | } 192 | #endif 193 | #if TH_SEEK_STRAT_LAST_FREE 194 | heap->lastFree = nblock; 195 | #endif 196 | TH_ON_SPLITFREED((void*)nblock + sizeof(th_block_h), nblock->next * TH_BLOCKSIZE - sizeof(th_block_h)); 197 | nblock = th_next(heap, nblock); 198 | if (nblock != 0) { 199 | nblock->prev = fullblocksize - bsize; 200 | TH_CALC_PARITY(nblock); 201 | } 202 | } 203 | } 204 | 205 | void* th_malloc(tinyheap* heap, unsigned int size) { 206 | if (size == 0) return 0; 207 | unsigned int bsize = (size + sizeof(th_block_h) + TH_ALIGNMENT + TH_BLOCKSIZE - 1) / TH_BLOCKSIZE; 208 | th_block_h* b = 0; 209 | 210 | TH_LOCK(heap); 211 | 212 | #if TH_SEEK_STRAT_MIN_MAX 213 | if (bsize <= TH_BLOCK_MEDIAN) { 214 | b = heap->smallFree; 215 | if (!b) { 216 | b = heap->bigFree; 217 | } 218 | } else { 219 | b = heap->bigFree; 220 | if (!b) { 221 | b = heap->smallFree; 222 | } 223 | } 224 | #endif 225 | #if TH_SEEK_STRAT_LAST_FREE 226 | b = heap->lastFree; 227 | #endif 228 | 229 | if (b == 0) { 230 | b = heap->p; 231 | } 232 | b = th_findFree(heap, bsize, b); 233 | if (b) { 234 | th_internalAlloc(heap, bsize, b); 235 | 236 | TH_UNLOCK(heap); 237 | 238 | return (void*)b + sizeof(th_block_h) + TH_ALIGNMENT; 239 | } else { 240 | TH_UNLOCK(heap); 241 | return 0; 242 | } 243 | } 244 | 245 | void th_free(tinyheap* heap, void* p) { 246 | th_block_h* block = (th_block_h*)(p - sizeof(th_block_h) - TH_ALIGNMENT); 247 | TH_ASSERT_PAR_FREE(block); 248 | TH_ASSERT_FREE_FREED(block); 249 | 250 | TH_LOCK(heap); 251 | 252 | #if TH_CALC_FREE 253 | heap->free += block->next; 254 | #endif 255 | th_block_h* nblock = th_next(heap, block); // next block 256 | th_block_h* pblock = th_prev(heap, block); // prev block 257 | // check next block, if not this is last 258 | if (nblock != 0) { 259 | TH_ASSERT_PAR_FREE(nblock); 260 | if (nblock->free) { 261 | // next was free, so bang this and next together 262 | block->next += nblock->next; 263 | #if TH_SEEK_STRAT_MIN_MAX 264 | if (nblock == heap->smallFree) heap->smallFree = 0; 265 | if (nblock == heap->bigFree) heap->bigFree = 0; 266 | #endif 267 | #if TH_SEEK_STRAT_LAST_FREE 268 | if (nblock == heap->lastFree) heap->lastFree = 0; 269 | #endif 270 | nblock = th_next(heap, nblock); // nblock is now next next block 271 | } 272 | } 273 | // check previous block, if not this is first 274 | if (pblock != 0 && pblock->free) { 275 | // prev was free, so bang previous and this together 276 | TH_ASSERT_PAR_FREE(pblock); 277 | pblock->next += block->next; 278 | TH_CALC_PARITY(pblock); 279 | #if TH_SEEK_STRAT_MIN_MAX 280 | if (block == heap->smallFree) heap->smallFree = 0; 281 | if (block == heap->bigFree) heap->bigFree = 0; 282 | #endif 283 | #if TH_SEEK_STRAT_LAST_FREE 284 | if (block == heap->lastFree) heap->lastFree = 0; 285 | #endif 286 | block = pblock; // current block is now previous 287 | } else { 288 | // previous wasn't free, so mark this one free now 289 | block->free = 1; 290 | TH_CALC_PARITY(block); 291 | } 292 | #if TH_SEEK_STRAT_MIN_MAX 293 | if (block->next <= TH_BLOCK_MEDIAN) { 294 | if (heap->smallFree == 0 || !heap->smallFree->free) { 295 | heap->smallFree = block; 296 | } 297 | } else { 298 | if (heap->bigFree == 0 || !heap->bigFree->free) { 299 | heap->bigFree = block; 300 | } 301 | } 302 | #endif 303 | #if TH_SEEK_STRAT_LAST_FREE 304 | heap->lastFree = block; 305 | #endif 306 | TH_ON_FREED((void*)block + sizeof(th_block_h), block->next * TH_BLOCKSIZE - sizeof(th_block_h)); 307 | // if block after this exists (might be next next if next was merged), update prev ptr 308 | if (nblock != 0) { 309 | TH_ASSERT_PAR_FREE(nblock); // might be doubled checked if there is a next ALLOCATED block 310 | nblock->prev = block->next; 311 | TH_CALC_PARITY(nblock); 312 | } 313 | 314 | TH_UNLOCK(heap); 315 | } 316 | 317 | #if TH_DUMP 318 | void th_dump(tinyheap* heap) { 319 | #if TH_SEEK_STRAT_MIN_MAX 320 | //heap->smallFree = 0; 321 | //heap->bigFree = 0; 322 | #endif 323 | #if TH_SEEK_STRAT_LAST_FREE 324 | //heap->lastFree = 0; 325 | #endif 326 | 327 | 328 | TH_PRINTF("heap data:%p size:%i blocksize:%i addr.bits:%i\n", 329 | heap->p, 330 | heap->len * TH_BLOCKSIZE, 331 | TH_BLOCKSIZE, 332 | TH_ADDRESSING_BITS); 333 | #if TH_CALC_FREE 334 | TH_PRINTF("heap free:%i\n", heap->free * TH_BLOCKSIZE); 335 | #endif 336 | #if TH_USE_PARITY 337 | TH_PRINTF("heap PARITY check enable, check "); 338 | #if TH_PARITY_CHECK_LEVEL == TH_PARITY_CHECK_DURING_FREE 339 | TH_PRINTF("during free\n"); 340 | #endif 341 | #if TH_PARITY_CHECK_LEVEL == TH_PARITY_CHECK_DURING_MALLOC 342 | TH_PRINTF("during malloc\n"); 343 | #endif 344 | #if TH_PARITY_CHECK_LEVEL == TH_PARITY_CHECK_ALL 345 | TH_PRINTF("always\n"); 346 | #endif 347 | 348 | #endif 349 | #if TH_SEEK_STRAT_MIN_MAX 350 | TH_PRINTF("heap seek stra:MIN_MAX smallFree:%p bigFree:%p med:%i\n", heap->smallFree, heap->bigFree, TH_BLOCK_MEDIAN * TH_BLOCKSIZE); 351 | #endif 352 | #if TH_SEEK_STRAT_LAST_FREE 353 | TH_PRINTF("heap seek stra:LAST_FREE lastFree:%p\n", heap->lastFree); 354 | #endif 355 | #if TH_SEEK_STRAT_NONE 356 | TH_PRINTF("heap seek stra:NONE\n"); 357 | #endif 358 | #if TH_PICK_STRAT_FIRST 359 | TH_PRINTF("heap pick stra:FIRST FOUND\n"); 360 | #endif 361 | #if TH_PICK_STRAT_BEST_FIT 362 | TH_PRINTF("heap pick stra:BEST FIT\n"); 363 | #endif 364 | #if TH_PICK_STRAT_GOOD_ENOUGH_FIT 365 | TH_PRINTF("heap pick stra:GOOD ENOUGH +-%i\n", TH_GOOD_ENOUGH_DELTA*TH_BLOCKSIZE); 366 | #endif 367 | 368 | TH_PRINTF("heap traverse:\n"); 369 | 370 | th_block_h* block = heap->p; 371 | TH_ASSERT_PAR_MALLOC(block); 372 | do { 373 | TH_PRINTF(" %p %s prv:%08i nxt:%08i len:%08i ", 374 | block, 375 | block->free ? "FREE" : "BUSY", 376 | block->prev, block->next, block->next * TH_BLOCKSIZE + TH_ALIGNMENT); 377 | #if TH_USE_PARITY 378 | TH_PRINTF("%s", th_checkParity(block) ? "OK" : "BAD"); 379 | #endif 380 | TH_PRINTF("\n "); 381 | { 382 | int len = block->next * TH_BLOCKSIZE; 383 | if (len > 16) len = 16; 384 | char *d = (char*)((void*)block + sizeof(th_block_h)); 385 | while (len--) { 386 | TH_PRINTF("%02x ", *d++); 387 | } 388 | } 389 | TH_PRINTF("\n"); 390 | // next block 391 | block = th_next(heap, block); 392 | } while (block != 0); 393 | } 394 | #endif 395 | 396 | #if TH_CALC_FREE 397 | unsigned int th_freecount(tinyheap* heap) { 398 | return heap->free * TH_BLOCKSIZE; 399 | } 400 | #endif 401 | -------------------------------------------------------------------------------- /src/tinyheap.h: -------------------------------------------------------------------------------- 1 | //The MIT License (MIT) 2 | // 3 | //Copyright (c) 2012-2013 Peter Andersson (pelleplutt1976gmail.com) 4 | // 5 | //Permission is hereby granted, free of charge, to any person obtaining a copy 6 | //of this software and associated documentation files (the "Software"), to deal 7 | //in the Software without restriction, including without limitation the rights 8 | //to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | //copies of the Software, and to permit persons to whom the Software is 10 | //furnished to do so, subject to the following conditions: 11 | // 12 | //The above copyright notice and this permission notice shall be included in 13 | //all copies or substantial portions of the Software. 14 | // 15 | //THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | //IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | //FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | //AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | //LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | //OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | //THE SOFTWARE. 22 | 23 | /* 24 | * tinyheap.h 25 | * 26 | * Created on: Apr 5, 2012 27 | * Author: petera 28 | */ 29 | 30 | #ifndef TINYHEAP_H_ 31 | #define TINYHEAP_H_ 32 | 33 | #include "tinyheap_config.h" 34 | 35 | /* heap block header */ 36 | typedef struct __attribute__((packed)) th_block_h { 37 | /* free flag */ 38 | unsigned int free : 1; 39 | /* pointer to next block header */ 40 | unsigned int next : TH_ADDRESSING_BITS-1; 41 | /* header parity bit */ 42 | unsigned int parity : 1; 43 | /* pointer to previous block header */ 44 | unsigned int prev : TH_ADDRESSING_BITS-1; 45 | } th_block_h; 46 | 47 | /* heap descriptor */ 48 | typedef struct tinyheap { 49 | th_block_h* p; 50 | int len; 51 | #if TH_SEEK_STRAT_MIN_MAX 52 | th_block_h* smallFree; 53 | th_block_h* bigFree; 54 | #endif 55 | #if TH_SEEK_STRAT_LAST_FREE 56 | th_block_h* lastFree; 57 | #endif 58 | #if TH_CALC_FREE 59 | unsigned int free; 60 | #endif 61 | #if TH_COUNT_SEARCH_CYCLES 62 | unsigned int count; 63 | #endif 64 | } tinyheap; 65 | 66 | #if TH_ADDRESS_ALIGN == 0 67 | #define TH_ALIGNMENT (0) 68 | #else 69 | #define TH_ALIGNMENT (TH_ADDRESS_ALIGN - (sizeof(th_block_h)&(TH_ADDRESS_ALIGN-1))) 70 | #endif 71 | 72 | /* initializes a heap of given size at given buffer address */ 73 | void th_init(tinyheap* heap, void* buffer, int len); 74 | /* allocates memory in heap */ 75 | void* th_malloc(tinyheap* heap, unsigned int size); 76 | /* frees memory in heap */ 77 | void th_free(tinyheap* heap, void* p); 78 | #if TH_CALC_FREE 79 | /* returns free amount of bytes in heap */ 80 | unsigned int th_freecount(tinyheap* heap); 81 | #endif 82 | 83 | #if TH_DUMP 84 | void th_dump(tinyheap* heap); 85 | #endif 86 | 87 | #endif /* TINYHEAP_H_ */ 88 | --------------------------------------------------------------------------------