Main Page | Class Hierarchy | Alphabetical List | Class List | File List | Class Members | File Members | Related Pages

kernel/mm.c

Go to the documentation of this file.
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.

Generated on Mon Feb 16 21:02:10 2004 for brickOS Kernel Developer by doxygen 1.3.5