00001 00006 /* 00007 * The contents of this file are subject to the Mozilla Public License 00008 * Version 1.0 (the "License"); you may not use this file except in 00009 * compliance with the License. You may obtain a copy of the License at 00010 * http://www.mozilla.org/MPL/ 00011 * 00012 * Software distributed under the License is distributed on an "AS IS" 00013 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the 00014 * License for the specific language governing rights and limitations 00015 * under the License. 00016 * 00017 * The Original Code is legOS code, released October 17, 1999. 00018 * 00019 * The Initial Developer of the Original Code is Markus L. Noga. 00020 * Portions created by Markus L. Noga are Copyright (C) 1999 00021 * Markus L. Noga. All Rights Reserved. 00022 * 00023 * Contributor(s): Markus L. Noga <markus@noga.de> 00024 */ 00025 00026 #include <sys/mm.h> 00027 00028 #ifdef CONF_MM 00029 00030 #include <stdlib.h> 00031 #include <sys/tm.h> 00032 #include <sys/critsec.h> 00033 #include <string.h> 00034 00036 // 00037 // Variables 00038 // 00040 00041 size_t *mm_first_free; 00042 00043 #ifndef CONF_TM 00044 typedef size_t tid_t; 00045 00047 00050 const tid_t ctid=0x0001; 00051 #endif 00052 00054 // 00055 // Functions 00056 // 00058 00059 // 00060 // memory block structure: 00061 // 0 1 : pid of owner (0=empty) 00062 // 2 3 : size of data block >> 1 00063 // 4 ... 4+2n: data 00064 // 00065 00067 /* \param ptr pointer to size field of current block 00068 \return size of block 00069 */ 00070 size_t mm_try_join(size_t *ptr) { 00071 size_t *next=ptr+*ptr+1; 00072 size_t increase=0; 00073 00074 while(*next==MM_FREE && next>=&mm_start) { 00075 increase+=*(next+1) + MM_HEADER_SIZE; 00076 next +=*(next+1) + MM_HEADER_SIZE; 00077 } 00078 return (*ptr)+=increase; 00079 } 00080 00082 00084 void mm_defrag() { 00085 size_t *ptr = &mm_start; 00086 #ifdef CONF_TM 00087 ENTER_KERNEL_CRITICAL_SECTION(); 00088 #endif 00089 while(ptr >= &mm_start) { 00090 if(*ptr == MM_FREE) 00091 mm_try_join(ptr+1); 00092 ptr += *(ptr+1); 00093 ptr += MM_HEADER_SIZE; 00094 } 00095 #ifdef CONF_TM 00096 LEAVE_KERNEL_CRITICAL_SECTION(); 00097 #endif 00098 } 00099 00101 00103 void mm_update_first_free(size_t *start) { 00104 size_t *ptr=start; 00105 00106 while((*ptr!=MM_FREE) && (ptr>=&mm_start)) 00107 ptr+=*(ptr+1)+MM_HEADER_SIZE; 00108 00109 mm_first_free=ptr; 00110 } 00111 00112 00114 00116 void mm_init() { 00117 size_t *current,*next; 00118 00119 current=&mm_start; 00120 00121 // memory layout 00122 // 00123 MM_BLOCK_FREE (&mm_start); // ram 00124 00125 // something at 0xc000 ? 00126 00127 MM_BLOCK_RESERVED(0xef30); // lcddata 00128 MM_BLOCK_FREE (0xef50); // ram2 00129 MM_BLOCK_RESERVED(0xf000); // motor 00130 MM_BLOCK_FREE (0xfe00); // ram4 00131 MM_BLOCK_RESERVED(0xff00); // stack, onchip 00132 00133 // expand last block to encompass all available memory 00134 *current=(int)(((-(int) current)-2)>>1); 00135 00136 mm_update_first_free(&mm_start); 00137 } 00138 00139 00141 00144 void *malloc(size_t size) { 00145 size_t *ptr,*next; 00146 00147 size=(size+1)>>1; // only multiples of 2 00148 00149 #ifdef CONF_TM 00150 ENTER_KERNEL_CRITICAL_SECTION(); 00151 #endif 00152 ptr=mm_first_free; 00153 00154 while(ptr>=&mm_start) { 00155 if(*(ptr++)==MM_FREE) { // free block? 00156 #ifdef CONF_TM 00157 mm_try_join(ptr); // unite with later blocks 00158 #endif 00159 if(*ptr>=size) { // big enough? 00160 *(ptr-1)=(size_t)ctid; // set owner 00161 00162 // split this block? 00163 if((*ptr-size)>=MM_SPLIT_THRESH) { 00164 next=ptr+size+1; 00165 *(next++)=MM_FREE; 00166 *(next)=*ptr-size-MM_HEADER_SIZE; 00167 mm_try_join(next); 00168 00169 *ptr=size; 00170 } 00171 00172 // was it the first free one? 00173 if(ptr==mm_first_free+1) 00174 mm_update_first_free(ptr+*ptr+1); 00175 00176 #ifdef CONF_TM 00177 LEAVE_KERNEL_CRITICAL_SECTION(); 00178 #endif 00179 return (void*) (ptr+1); 00180 } 00181 } 00182 00183 ptr+=(*ptr)+1; // find next block. 00184 } 00185 00186 #ifdef CONF_TM 00187 LEAVE_KERNEL_CRITICAL_SECTION(); 00188 #endif 00189 return NULL; 00190 } 00191 00192 00194 00198 void free(void *the_ptr) { 00199 size_t *ptr=the_ptr; 00200 #ifndef CONF_TM 00201 size_t *p2,*next; 00202 #endif 00203 00204 if(ptr==NULL || (((size_t)ptr)&1) ) 00205 return; 00206 00207 ptr-=MM_HEADER_SIZE; 00208 *((size_t*) ptr)=MM_FREE; // mark as free 00209 00210 #ifdef CONF_TM 00211 // for task safe operations, free needs to be 00212 // atomic and nonblocking, because it may be 00213 // called by the scheduler. 00214 // 00215 // therefore, just update mm_first_free 00216 // 00217 if(ptr<mm_first_free || mm_first_free<&mm_start) 00218 mm_first_free=ptr; // update mm_first_free 00219 #else 00220 // without task management, we have the time to 00221 // unite neighboring memory blocks. 00222 // 00223 p2=&mm_start; 00224 while(p2!=ptr) { // we could make free 00225 next=p2+*(p2+1)+MM_HEADER_SIZE; // O(1) if we included 00226 if(*p2==MM_FREE && next==ptr) // a pointer to the 00227 break; // previous block. 00228 p2=next; // I don't want to. 00229 } 00230 mm_try_join(p2+1); // defragment free areas 00231 00232 if(ptr<mm_first_free || mm_first_free<&mm_start) 00233 mm_update_first_free(ptr); // update mm_first_free 00234 #endif 00235 } 00236 00237 00239 00243 void *calloc(size_t nmemb, size_t size) { 00244 void *ptr; 00245 size_t original_size = size; 00246 00247 if (nmemb == 0 || size == 0) 00248 return 0; 00249 00250 size*=nmemb; 00251 00252 // if an overflow occurred, size/nmemb will not equal original_size 00253 if (size/nmemb != original_size) 00254 return 0; 00255 00256 if((ptr=malloc(size))!=NULL) 00257 memset(ptr,0,size); 00258 00259 return ptr; 00260 } 00261 00263 00265 void mm_reaper() { 00266 size_t *ptr; 00267 00268 // pass 1: mark as free 00269 ptr=&mm_start; 00270 while(ptr>=&mm_start) { 00271 if(*ptr==(size_t)ctid) 00272 *ptr=MM_FREE; 00273 ptr+=*(ptr+1)+MM_HEADER_SIZE; 00274 } 00275 00276 // pass 2: defragment free areas 00277 // this may alter free blocks 00278 mm_defrag(); 00279 } 00280 00282 int mm_free_mem(void) { 00283 int free = 0; 00284 size_t *ptr; 00285 00286 #ifdef CONF_TM 00287 ENTER_KERNEL_CRITICAL_SECTION(); 00288 #endif 00289 00290 // Iterate through the free list 00291 for (ptr = mm_first_free; 00292 ptr >= &mm_start; 00293 ptr += *(ptr+1) + MM_HEADER_SIZE) 00294 free += *(ptr+1); 00295 00296 #ifdef CONF_TM 00297 LEAVE_KERNEL_CRITICAL_SECTION(); 00298 #endif 00299 return free*2; 00300 } 00301 00302 #endif
brickOS is released under the
Mozilla Public License.
Original code copyright 1998-2002 by the authors. |