Main Page | Alphabetical List | Data Structures | File List | Data Fields | Globals | Related Pages

mem.c

Go to the documentation of this file.
00001 /* 
00002  * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
00003  * All rights reserved. 
00004  * 
00005  * Redistribution and use in source and binary forms, with or without modification, 
00006  * are permitted provided that the following conditions are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright notice,
00009  *    this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright notice,
00011  *    this list of conditions and the following disclaimer in the documentation
00012  *    and/or other materials provided with the distribution.
00013  * 3. The name of the author may not be used to endorse or promote products
00014  *    derived from this software without specific prior written permission. 
00015  *
00016  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 
00017  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
00018  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT 
00019  * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
00020  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT 
00021  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
00022  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 
00023  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING 
00024  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY 
00025  * OF SUCH DAMAGE.
00026  *
00027  * This file is part of the lwIP TCP/IP stack.
00028  * 
00029  * Author: Adam Dunkels <adam@sics.se>
00030  *
00031  * CHANGELOG: this file has been modified by Sergio Perez Alcañiz <serpeal@disca.upv.es> 
00032  *            Departamento de Informática de Sistemas y Computadores          
00033  *            Universidad Politécnica de Valencia                             
00034  *            Valencia (Spain)    
00035  *            Date: April 2003                                          
00036  *  
00037  */
00038 
00039 /*-----------------------------------------------------------------------------------*/
00040 /* mem.c
00041  *
00042  * Memory manager.
00043  *
00044  */
00045 /*-----------------------------------------------------------------------------------*/
00046 
00047 #include "lwip/arch.h"
00048 #include "lwip/opt.h"
00049 #include "lwip/def.h"
00050 #include "lwip/mem.h"
00051 
00052 #include "lwip/sys.h"
00053 
00054 #include "lwip/stats.h"
00055 
00056 struct mem {
00057   mem_size_t next, prev;
00058 #if MEM_ALIGNMENT == 1
00059   u8_t used;
00060 #elif MEM_ALIGNMENT == 2
00061   u16_t used;
00062 #elif MEM_ALIGNMENT == 4
00063   u32_t used;
00064 #else
00065 #error "unhandled MEM_ALIGNMENT size"
00066 #endif /* MEM_ALIGNMENT */
00067 }; 
00068 
00069 static struct mem *ram_end;
00070 static u8_t ram[MEM_SIZE + sizeof(struct mem) + MEM_ALIGNMENT];
00071 
00072 #define MIN_SIZE 12
00073 #define SIZEOF_STRUCT_MEM MEM_ALIGN_SIZE(sizeof(struct mem))
00074 /*#define SIZEOF_STRUCT_MEM (sizeof(struct mem) + \
00075                           (((sizeof(struct mem) % MEM_ALIGNMENT) == 0)? 0 : \
00076                           (4 - (sizeof(struct mem) % MEM_ALIGNMENT))))*/
00077 
00078 
00079 static struct mem *lfree;   /* pointer to the lowest free block */
00080 
00081 static sys_sem_t mem_sem;
00082 
00083 /*-----------------------------------------------------------------------------------*/
00084 static void
00085 plug_holes(struct mem *mem)
00086 {
00087   struct mem *nmem;
00088   struct mem *pmem;
00089 
00090   LWIP_ASSERT("plug_holes: mem >= ram", (u8_t *)mem >= ram);
00091   LWIP_ASSERT("plug_holes: mem < ram_end", (u8_t *)mem < (u8_t *)ram_end);
00092   LWIP_ASSERT("plug_holes: mem->used == 0", mem->used == 0);
00093   
00094   /* plug hole forward */
00095   LWIP_ASSERT("plug_holes: mem->next <= MEM_SIZE", mem->next <= MEM_SIZE);
00096   
00097   nmem = (struct mem *)&ram[mem->next];
00098   if(mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {
00099     if(lfree == nmem) {
00100       lfree = mem;
00101     }
00102     mem->next = nmem->next;
00103     ((struct mem *)&ram[nmem->next])->prev = (u8_t *)mem - ram;
00104   }
00105 
00106   /* plug hole backward */
00107   pmem = (struct mem *)&ram[mem->prev];
00108   if(pmem != mem && pmem->used == 0) {
00109     if(lfree == mem) {
00110       lfree = pmem;
00111     }
00112     pmem->next = mem->next;
00113     ((struct mem *)&ram[mem->next])->prev = (u8_t *)pmem - ram;
00114   }
00115 
00116 }
00117 /*-----------------------------------------------------------------------------------*/
00118 void
00119 mem_init(void)
00120 {
00121   struct mem *mem;
00122 
00123   memset(ram, 0, MEM_SIZE);
00124   mem = (struct mem *)ram;
00125   mem->next = MEM_SIZE;
00126   mem->prev = 0;
00127   mem->used = 0;
00128   ram_end = (struct mem *)&ram[MEM_SIZE];
00129   ram_end->used = 1;
00130   ram_end->next = MEM_SIZE;
00131   ram_end->prev = MEM_SIZE;
00132 
00133   mem_sem = sys_sem_new(1);
00134 
00135   lfree = (struct mem *)ram;
00136 
00137 #ifdef MEM_STATS
00138   lwip_stats.mem.avail = MEM_SIZE;
00139 #endif /* MEM_STATS */
00140 }
00141 /*-----------------------------------------------------------------------------------*/
00142 void
00143 mem_free(void *rmem)
00144 {
00145   struct mem *mem;
00146 
00147   if(rmem == NULL) {
00148     return;
00149   }
00150   
00151   sys_sem_wait(mem_sem);
00152 
00153   LWIP_ASSERT("mem_free: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
00154          (u8_t *)rmem < (u8_t *)ram_end);
00155   
00156   
00157   if((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
00158     DEBUGF(MEM_DEBUG | 3, ("mem_free: illegal memory\n"));
00159 #ifdef MEM_STATS
00160     ++lwip_stats.mem.err;
00161 #endif /* MEM_STATS */
00162     return;
00163   }
00164   mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
00165 
00166   LWIP_ASSERT("mem_free: mem->used", mem->used);
00167   
00168   mem->used = 0;
00169 
00170   if(mem < lfree) {
00171     lfree = mem;
00172   }
00173   
00174 #ifdef MEM_STATS
00175   lwip_stats.mem.used -= mem->next - ((u8_t *)mem - ram) - SIZEOF_STRUCT_MEM;
00176   
00177 #endif /* MEM_STATS */
00178   plug_holes(mem);
00179   sys_sem_signal(mem_sem);
00180 }
00181 /*-----------------------------------------------------------------------------------*/
00182 void *
00183 mem_reallocm(void *rmem, mem_size_t newsize)
00184 {
00185   void *nmem;
00186   nmem = mem_malloc(newsize);
00187   if(nmem == NULL) {
00188     return mem_realloc(rmem, newsize);
00189   }
00190   memcpy(nmem, rmem, newsize);
00191   mem_free(rmem);
00192   return nmem;
00193 }
00194 /*-----------------------------------------------------------------------------------*/
00195 void *
00196 mem_realloc(void *rmem, mem_size_t newsize)
00197 {
00198   mem_size_t size;
00199   mem_size_t ptr, ptr2;
00200   struct mem *mem, *mem2;
00201 
00202   /* Expand the size of the allocated memory region so that we can
00203      adjust for alignment. */
00204   if((newsize % MEM_ALIGNMENT) != 0) {
00205    newsize += MEM_ALIGNMENT - ((newsize + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT);
00206   }
00207   
00208   if(newsize > MEM_SIZE) {
00209     return NULL;
00210   }
00211   
00212   sys_sem_wait(mem_sem);
00213   
00214   LWIP_ASSERT("mem_realloc: legal memory", (u8_t *)rmem >= (u8_t *)ram &&
00215          (u8_t *)rmem < (u8_t *)ram_end);
00216   
00217   if((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {
00218     DEBUGF(MEM_DEBUG | 3, ("mem_realloc: illegal memory\n"));
00219     return rmem;
00220   }
00221   mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);
00222 
00223   ptr = (u8_t *)mem - ram;
00224 
00225   size = mem->next - ptr - SIZEOF_STRUCT_MEM;
00226 #ifdef MEM_STATS
00227   lwip_stats.mem.used -= (size - newsize);
00228 #endif /* MEM_STATS */
00229   
00230   if(newsize + SIZEOF_STRUCT_MEM + MIN_SIZE < size) {
00231     ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;
00232     mem2 = (struct mem *)&ram[ptr2];
00233     mem2->used = 0;
00234     mem2->next = mem->next;
00235     mem2->prev = ptr;
00236     mem->next = ptr2;
00237     if(mem2->next != MEM_SIZE) {
00238       ((struct mem *)&ram[mem2->next])->prev = ptr2;
00239     }
00240 
00241     plug_holes(mem2);
00242   }
00243   sys_sem_signal(mem_sem);  
00244   return rmem;
00245 }
00246 /*-----------------------------------------------------------------------------------*/
00247 void *
00248 mem_malloc(mem_size_t size)
00249 {
00250   mem_size_t ptr, ptr2;
00251   struct mem *mem, *mem2;
00252 
00253   if(size == 0) {
00254     return NULL;
00255   }
00256 
00257   /* Expand the size of the allocated memory region so that we can
00258      adjust for alignment. */
00259   if((size % MEM_ALIGNMENT) != 0) {
00260     size += MEM_ALIGNMENT - ((size + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT);
00261   }
00262   
00263   if(size > MEM_SIZE) {
00264     return NULL;
00265   }
00266   
00267   sys_sem_wait(mem_sem);
00268 
00269   for(ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE; ptr = ((struct mem *)&ram[ptr])->next) {
00270     mem = (struct mem *)&ram[ptr];
00271     if(!mem->used &&
00272        mem->next - (ptr + SIZEOF_STRUCT_MEM) >= size + SIZEOF_STRUCT_MEM) {
00273       ptr2 = ptr + SIZEOF_STRUCT_MEM + size;
00274       mem2 = (struct mem *)&ram[ptr2];
00275 
00276       mem2->prev = ptr;      
00277       mem2->next = mem->next;
00278       mem->next = ptr2;      
00279       if(mem2->next != MEM_SIZE) {
00280         ((struct mem *)&ram[mem2->next])->prev = ptr2;
00281       }
00282       
00283       mem2->used = 0;      
00284       mem->used = 1;
00285 #ifdef MEM_STATS
00286       lwip_stats.mem.used += size;
00287       /*      if(lwip_stats.mem.max < lwip_stats.mem.used) {
00288         lwip_stats.mem.max = lwip_stats.mem.used;
00289         } */
00290       if(lwip_stats.mem.max < ptr2) {
00291         lwip_stats.mem.max = ptr2;
00292       }      
00293 #endif /* MEM_STATS */
00294 
00295       if(mem == lfree) {
00296         /* Find next free block after mem */
00297         while(lfree->used && lfree != ram_end) {
00298           lfree = (struct mem *)&ram[lfree->next];
00299         }
00300         LWIP_ASSERT("mem_malloc: !lfree->used", !lfree->used);
00301       }
00302       sys_sem_signal(mem_sem);
00303       LWIP_ASSERT("mem_malloc: allocated memory not above ram_end.",
00304              (u32_t)mem + SIZEOF_STRUCT_MEM + size <= (u32_t)ram_end);
00305       LWIP_ASSERT("mem_malloc: allocated memory properly aligned.",
00306              (unsigned long)((u8_t *)mem + SIZEOF_STRUCT_MEM) % MEM_ALIGNMENT == 0);
00307       return (u8_t *)mem + SIZEOF_STRUCT_MEM;
00308     }    
00309   }
00310   DEBUGF(MEM_DEBUG | 2, ("mem_malloc: could not allocate %d bytes\n", (int)size));
00311 #ifdef MEM_STATS
00312   ++lwip_stats.mem.err;
00313 #endif /* MEM_STATS */  
00314   sys_sem_signal(mem_sem);
00315   return NULL;
00316 }
00317 /*-----------------------------------------------------------------------------------*/

Generated on Wed Jan 14 12:58:56 2004 for RTL-lwIP-0.4 by doxygen 1.3.4