DynAlloc.h 8.19 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
/*
             LUFA Library
     Copyright (C) Dean Camera, 2009.
              
  dean [at] fourwalledcubicle [dot] com
      www.fourwalledcubicle.com
*/

/*
  Copyright 2009  Dean Camera (dean [at] fourwalledcubicle [dot] com)

  Permission to use, copy, modify, and distribute this software
  and its documentation for any purpose and without fee is hereby
  granted, provided that the above copyright notice appear in all
  copies and that both that the copyright notice and this
  permission notice and warranty disclaimer appear in supporting
  documentation, and that the name of the author not be used in
  advertising or publicity pertaining to distribution of the
  software without specific, written prior permission.

  The author disclaim all warranties with regard to this
  software, including all implied warranties of merchantability
  and fitness.  In no event shall the author be liable for any
  special, indirect or consequential damages or any damages
  whatsoever resulting from loss of use, data or profits, whether
  in an action of contract, negligence or other tortious action,
  arising out of or in connection with the use or performance of
  this software.
*/

/** \file
 *
 *  Dynamic, auto-defragmenting block memory allocator library. This library provides a convenient replacement for
 *  the standard avr-libc dynamic memory allocation routines. Memory is handed out in block chunks, to reduce the
 *  management memory overhead.
 *
 *  Unlike the normal memory allocation routines, this library gives out handles to memory which must be dereferenced
 *  at the exact time of use, rather than handing back direct memory pointers. By using library managed handles
 *  instead of pointers, allocated memory blocks can be shifted around as needed transparently to defragment the
 *  memory as more blocks are requested.
 *
 *  The memory heap is static, thus the total memory usage of the compiled application (as reported by the avr-size
 *  tool of the AVR-GCC toolchain) includes the dynamic memory heap.
 *
 *  The constants NUM_BLOCKS, BLOCK_SIZE and NUM_HANDLES must be defined in the project makefile (and passed to the
 *  preprocessor via the -D GCC switch) for this library to compile.
 *
48
 *  NUM_BLOCKS indicates the number of memory blocks in the memory psudoheap which can be chained together and handed
49
 *  to the application via a memory handle. NUM_HANDLES is the maximum number of memory handles (pointing to one or
50
 *  more chained memory blocks) which can be handed out simultaneously before requiring a handle (and its associated
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
 *  memory) to be freed. BLOCK_SIZE gives the number of bytes in each memory block.
 */

#ifndef __DYN_ALLOC__
#define __DYN_ALLOC__

	/* Includes : */
		#include <avr/io.h>
		#include <stdbool.h>
		#include <string.h>
	
	/* Preprocessor Checks: */
		#if (!defined(NUM_BLOCKS) || !defined(BLOCK_SIZE) || !defined(NUM_HANDLES))
			#error NUM_BLOCKS, BLOCK_SIZE and NUM_HANDLES must be defined before use via makefile.
		#endif

	/* Public Interface - May be used in end-application: */
		/* Macros: */
			/** Macro to dereference a given memory handle into the given type. The given type should be a pointer
70
			 *  if the memory is to contain an array of items, or should be a standard type (such as a primitive or
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
			 *  structure) if the memory is to hold a single item of a single type. */
			#define DEREF(handle, type)       (*(type*)handle)
			
			/** Constant, giving the total heap size in bytes. */
			#define ALLOCABLE_BYTES           (1UL * NUM_BLOCKS * BLOCK_SIZE)
		
		/* Type Defines: */
			/** Memory handle type, used to store handles given by the library functions. */
			typedef const void** Mem_Handle_t;
			
			#if (ALLOCABLE_BYTES > 0xFFFF) || defined(__DOXYGEN__)
				/** Type define for the size (in bytes) for an allocation for passing to the library functions.
				 *  The exact type width varies depending on the value of ALLOCABLE_BYTES to ensure that a single
				 *  allocation can request the entire heap if needed.
				 */
				typedef uint32_t Alloc_Size_t;
			#elif (ALLOCABLE_BYTES > 0xFF)
				typedef uint16_t Alloc_Size_t;
			#else			
				typedef uint8_t  Alloc_Size_t;
			#endif

			#if (NUM_BLOCKS > 0xFFFF) || defined(__DOXYGEN__)
				/** Type define for a block number in the heap. The exact type width varies depending on the
				 *   value of NUM_BLOCKS to ensure that the type can store an index to any block in the block pool.
				 */
				typedef uint32_t Block_Number_t;
			#elif (NUM_BLOCKS > 0xFF)
				typedef uint16_t Block_Number_t;
			#else
				typedef uint8_t  Block_Number_t;
			#endif

			#if (NUM_HANDLES > 0xFFFF) || defined(__DOXYGEN__)
				/** Type define for a handle number. The exact type width varies depending on the value of NUM_HANDLES
				 *  to ensure that the type can store the index of any handle in the handle pool.
				 */
				typedef uint32_t Handle_Number_t;
			#elif (NUM_HANDLES > 0xFF)
				typedef uint16_t Handle_Number_t;
			#else			
				typedef uint8_t  Handle_Number_t;
			#endif
			
		/* Function Prototypes: */
			/** Allocates a given number of blocks from the heap (calculated from the requested number of bytes) and
			 *  returns a handle to the newly allocated memory.
			 *
			 *  \param Bytes  The number of bytes requested to be allocated from the heap
			 *
			 *  \return NULL handle if the allocation fails, or handle to the allocated memory if the allocation succeeds
			 */
			Mem_Handle_t    Mem_Alloc(const Alloc_Size_t Bytes);
			
			/** Allocates a given number of blocks from the heap (calculated from the requested number of bytes) and
			 *  returns a handle to the newly allocated memory. Calloced memory is automatically cleared to all 0x00
			 *  values at the time of allocation.
			 *
			 *  \param Bytes  The number of pre-cleared bytes requested to be allocated from the heap
			 *
			 *  \return NULL handle if the allocation fails, or handle to the allocated memory if the allocation succeeds
			 */
			Mem_Handle_t    Mem_Calloc(const Alloc_Size_t Bytes);

			/** Deallocates a given memory handle, and attempts to allocates the given number of blocks from the heap
			 *  (calculated from the requested number of bytes) immediately following the deallocation. The new memory
			 *  may be located in the same area as the previous memory, but this is not guaranteed.
			 *
			 *  \param CurrAllocHdl  Handle to an already allocated section of memory in the heap to deallocate
			 *  \param Bytes         The number of bytes requested to be allocated from the heap following the
			 *                       deallocation
			 *
			 *  \return NULL handle if the allocation fails, or handle to the allocated memory if the allocation succeeds
			 *
			 *  \warning Even if the allocation fails, the deallocation will still occur. Care should be taken to ensure
			 *           that the previously allocated memory is not used following an unsuccessful realloc().
			 */
			Mem_Handle_t    Mem_Realloc(Mem_Handle_t CurrAllocHdl, const Alloc_Size_t Bytes);
			
			/** Deallocates a given previously allocated section of memory from the heap.
			 *
			 *  \param CurrAllocHdl  Handle to a previously allocated section of memory in the heap
			 */
			void            Mem_Free(Mem_Handle_t CurrAllocHdl);
			
			/** Returns the total number of unallocated blocks in the heap.
			 *
			 *  \return Number of free blocks in the heap, as a Block_Number_t integer
			 */
			Block_Number_t  Mem_TotalFreeBlocks(void);

			/** Returns the total number of unallocated handles in the handle pool.
			 *
			 *  \return Number of free handles in the handle pool, as a Handle_Number_t integer
			 */
			Handle_Number_t Mem_TotalFreeHandles(void);
		
	/* Private Interface - For use in library only: */
	#if !defined(__DOXYGEN__)
		/* Macros: */
			#define BLOCK_USED_MASK           (1 << 0)
			#define BLOCK_LINKED_MASK         (1 << 1)
			
		/* Function Prototypes: */
			#if defined(INCLUDE_FROM_DYNALLOC_C)
				static uint8_t Mem_GetBlockFlags(const Block_Number_t BlockNum);
				static void    Mem_SetBlockFlags(const Block_Number_t BlockNum, const uint8_t Flags);
				static void    Mem_Defrag(void);
			#endif
	#endif
	
#endif