ISIX-RTOS - small operating system for ARM microcontrollers 1.2
|
00001 /*------------------------------------------------------*/ 00002 /* 00003 * memory.c 00004 * New heap allocator for the ISIX 00005 * Created on: 2009-11-11 00006 * Author: lucck 00007 */ 00008 /*------------------------------------------------------*/ 00009 //TODO: memory should not block interrupts 00010 #include <isix/memory.h> 00011 #include <isix/types.h> 00012 #include <isix/semaphore.h> 00013 #include <prv/semaphore.h> 00014 #include <prv/scheduler.h> 00015 00016 #ifndef ISIX_DEBUG_MEMORY 00017 #define ISIX_DEBUG_MEMORY ISIX_DBG_OFF 00018 #endif 00019 00020 00021 #if ISIX_DEBUG_MEMORY == ISIX_DBG_ON 00022 #include <isix/printk.h> 00023 #else 00024 #define isix_printk(...) 00025 #endif 00026 00027 /*------------------------------------------------------*/ 00028 00029 #define MAGIC 0x19790822 00030 #define ALIGN_TYPE void * 00031 #define ALIGN_MASK (sizeof(ALIGN_TYPE) - 1) 00032 #define ALIGN_SIZE(p) (((size_t)(p) + ALIGN_MASK) & ~ALIGN_MASK) 00033 00034 struct header 00035 { 00036 union 00037 { 00038 struct header *h_next; 00039 size_t h_magic; 00040 } h; 00041 size_t h_size; 00042 }; 00043 /*------------------------------------------------------*/ 00044 static struct 00045 { 00046 struct header free; /* Guaranteed to be not adjacent to the heap */ 00047 00048 } heap; 00049 00050 /*------------------------------------------------------*/ 00052 static sem_t mem_sem; 00053 00054 00055 /*------------------------------------------------------*/ 00057 static void mem_lock_init(void) 00058 { 00059 //Create unlocked semaphore 00060 isix_sem_create( &mem_sem, 1 ); 00061 } 00062 /*------------------------------------------------------*/ 00064 static void mem_lock(void) 00065 { 00066 if(isix_scheduler_running) 00067 isix_sem_wait( &mem_sem, ISIX_TIME_INFINITE ); 00068 } 00069 00070 /*------------------------------------------------------*/ 00072 static void mem_unlock(void) 00073 { 00074 if(isix_scheduler_running) 00075 isix_sem_signal( &mem_sem ); 00076 } 00077 00078 /*------------------------------------------------------*/ 00080 void isix_alloc_init(void) 00081 { 00082 struct header *hp; 00083 00084 extern char __heap_start; 00085 extern char __heap_end; 00086 00087 mem_lock_init(); 00088 00089 hp = (void *)&__heap_start; 00090 hp->h_size = &__heap_end - &__heap_start - sizeof(struct header); 00091 00092 hp->h.h_next = NULL; 00093 heap.free.h.h_next = hp; 00094 heap.free.h_size = 0; 00095 00096 } 00097 00098 /*------------------------------------------------------*/ 00099 void *isix_alloc(size_t size) 00100 { 00101 struct header *qp, *hp, *fp; 00102 00103 size = ALIGN_SIZE(size); 00104 qp = &heap.free; 00105 mem_lock(); 00106 00107 while (qp->h.h_next != NULL) { 00108 hp = qp->h.h_next; 00109 if (hp->h_size >= size) { 00110 if (hp->h_size < size + sizeof(struct header)) { 00111 /* Gets the whole block even if it is slightly bigger than the 00112 requested size because the fragment would be too small to be 00113 useful */ 00114 qp->h.h_next = hp->h.h_next; 00115 } 00116 else { 00117 /* Block bigger enough, must split it */ 00118 fp = (void *)((char *)(hp) + sizeof(struct header) + size); 00119 fp->h.h_next = hp->h.h_next; 00120 fp->h_size = hp->h_size - sizeof(struct header) - size; 00121 qp->h.h_next = fp; 00122 hp->h_size = size; 00123 } 00124 hp->h.h_magic = MAGIC; 00125 00126 mem_unlock(); 00127 return (void *)(hp + 1); 00128 } 00129 qp = hp; 00130 } 00131 00132 mem_unlock(); 00133 return NULL; 00134 } 00135 00136 /*------------------------------------------------------*/ 00137 #define LIMIT(p) (struct header *)((char *)(p) + \ 00138 sizeof(struct header) + \ 00139 (p)->h_size) 00140 00141 /*------------------------------------------------------*/ 00142 void isix_free(void *p) 00143 { 00144 struct header *qp, *hp; 00145 00146 00147 hp = (struct header *)p - 1; 00148 /*chDbgAssert(hp->h_magic == MAGIC, 00149 "chHeapFree(), #1", 00150 "it is not magic"); */ 00151 qp = &heap.free; 00152 mem_lock(); 00153 00154 while (1) { 00155 00156 /* chDbgAssert((hp < qp) || (hp >= LIMIT(qp)), 00157 "chHeapFree(), #2", 00158 "within free block"); */ 00159 00160 if (((qp == &heap.free) || (hp > qp)) && 00161 ((qp->h.h_next == NULL) || (hp < qp->h.h_next))) { 00162 /* Insertion after qp */ 00163 hp->h.h_next = qp->h.h_next; 00164 qp->h.h_next = hp; 00165 /* Verifies if the newly inserted block should be merged */ 00166 if (LIMIT(hp) == hp->h.h_next) { 00167 /* Merge with the next block */ 00168 hp->h_size += hp->h.h_next->h_size + sizeof(struct header); 00169 hp->h.h_next = hp->h.h_next->h.h_next; 00170 } 00171 if ((LIMIT(qp) == hp)) { /* Cannot happen when qp == &heap.free */ 00172 /* Merge with the previous block */ 00173 qp->h_size += hp->h_size + sizeof(struct header); 00174 qp->h.h_next = hp->h.h_next; 00175 } 00176 00177 mem_unlock(); 00178 return; 00179 } 00180 qp = qp->h.h_next; 00181 } 00182 mem_unlock(); 00183 } 00184 /*------------------------------------------------------*/ 00185 size_t isix_heap_free(int *fragments) 00186 { 00187 int frags = 0; size_t mem = 0; 00188 mem_lock(); 00189 for(struct header *qp=&heap.free; qp; qp=qp->h.h_next) 00190 { 00191 mem += qp->h_size; 00192 frags++; 00193 } 00194 mem_unlock(); 00195 if(fragments) 00196 *fragments = frags; 00197 return mem; 00198 } 00199 /*------------------------------------------------------*/