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

umalloc.c

Go to the documentation of this file.
00001 /*!     \file mm/umalloc.c
00002  *      \brief Virtual Memory Allocator for the User Space.
00003  *      \author Andrea Righi <drizzt@inwind.it>
00004  *      \date Last update: 2004-01-01
00005  *      \note Copyright (&copy;) 2003 Andrea Righi
00006  */
00007 
00008 #include <const.h>
00009 
00010 #include <arch/paging.h>
00011 
00012 #include <kernel/task.h>
00013 #include <kernel/video.h>
00014 
00015 #include <kernel/umalloc.h>
00016 
00017 //! \brief Initialize the user virtual memory area.
00018 //! \param heap_start The start of the user heap.
00019 //! \param heap_size The size of the user heap.
00020 void umalloc_init(size_t heap_start, size_t heap_size)
00021 {
00022         task_t *t;
00023         umem_block_t *p;
00024 
00025         t = get_curr_task();
00026         if( t==NULL )
00027                 return;
00028 
00029         // Setup the heap in the task structure.
00030         t->heap_start = heap_start;
00031         t->heap_size = heap_size;
00032 
00033         // Create only one hudge block.
00034         p = (umem_block_t *)heap_start;
00035         p->magic = UM_MAGIC;
00036         p->flags = UM_FREE;
00037         p->size = heap_size - sizeof(umem_block_t);
00038         p->owner = NULL;
00039 }
00040 
00041 //! \brief
00042 //!     Allocate a memory block from the user memory area.
00043 //!     This is a best-fit like allocator.
00044 //! \param size The size of the block you want to allocate.
00045 //! \exception NULL Out-of-memory.
00046 //! \return A pointer to a memory area.
00047 //! \note The memory area is not initialized when it's just allocated.
00048 void *umalloc(size_t size)
00049 {
00050         task_t *t;
00051         umem_block_t *p, *p_best=NULL;
00052 
00053         if ( !size ) return( NULL ); // Is the process crazy?! :-)
00054 
00055         // Get the current task structure.
00056         t = get_curr_task();
00057 
00058         // Round the size up to sizeof(umem_block_t); this is the unit
00059         // of allocation.
00060         size = ( size & -(sizeof(umem_block_t)) ) + sizeof(umem_block_t);
00061 
00062         // Explore the heap for the best-fit hole.
00063         p=(umem_block_t *)(t->heap_start);
00064         if( !p ) return( NULL );
00065         while(p < (umem_block_t *)(t->heap_start + t->heap_size))
00066         {
00067                 // Find a free block.
00068                 if (p->flags == UM_FREE)
00069                 {
00070                         // This block is free... let's proceed!
00071                         if (p->size == size)
00072                         {
00073                                 // Best fit block found! You're lucky!
00074                                 p_best = p;
00075                                 break;
00076                         }
00077                         if (p->size > size)
00078                         {
00079                                 // The hole is bigger than size...
00080                                 // ...check if it's the best-fit hole!
00081                                 if (p_best==NULL)
00082                                         p_best = p;
00083                                 else
00084                                         if (p_best->size > p->size)
00085                                                 p_best = p;
00086                         }
00087                 }
00088                 // Examine the next memory block.
00089                 p = (void *)p+p->size+sizeof(umem_block_t);
00090         }
00091 
00092         // Have you found a free block?!
00093         if (p_best == NULL)
00094         {
00095                 // No free memory :(
00096                 return( NULL );
00097         }
00098 
00099         // Found, now allocate it!
00100         p_best->magic = UM_MAGIC;
00101         p_best->flags = UM_ALLOC;
00102         p_best->owner = get_pid();
00103 
00104         if (p_best->size == size)
00105         {
00106                 p_best = (void *)p_best + sizeof(umem_block_t);
00107                 // The block cover the size perfectly.
00108                 return( (void *)p_best );
00109         }
00110 
00111         // Otherwise split the hole in two blocks.
00112         p = (void *)p_best + sizeof(umem_block_t) + size;
00113         p->magic = UM_MAGIC;
00114         p->flags = UM_FREE;
00115         p->size = p_best->size - size - sizeof(umem_block_t);
00116         p->owner = NULL;
00117 
00118         p_best->size = size;
00119         p_best = (void *)p_best + sizeof(umem_block_t);
00120 
00121         // Return the best-fit pointer.
00122         return ( (void *)p_best );
00123 }
00124 
00125 //! \brief Try to release physical frames occupied by the freed block.
00126 //! \param ptr The pointer to deallocate.
00127 static void deallocate(umem_block_t *ptr)
00128 {
00129         size_t start =
00130                 PAGE_ALIGN_UP((uint32_t)((void *)ptr + sizeof(umem_block_t)));
00131         size_t end =
00132                 PAGE_ALIGN((uint32_t)((void *)ptr + sizeof(umem_block_t) + ptr->size));
00133 
00134         while( start<end )
00135         {
00136                 if (*ADDR_TO_PDE(start) != NULL)
00137                 {
00138                         delete_page( start );
00139                         start += PAGE_SIZE;
00140                 }
00141                 else
00142                         start = PAGE_DIR_ALIGN_UP( start );
00143         }
00144 }
00145 
00146 //! \brief
00147 //!     Frees the memory space pointed by ptr, which must have
00148 //!     been returned by a previous call to umalloc(size_t size).
00149 //! \param ptr The pointer you want to free.
00150 void ufree(void *ptr)
00151 {
00152         task_t *t;
00153         umem_block_t *p, *p2;
00154 
00155         if (ptr == NULL) return;
00156 
00157         // Point to the header.
00158         p = (void *)ptr - sizeof(umem_block_t);
00159 
00160         if (p->magic != UM_MAGIC) return; // Is the process crazy?! :)
00161         if (p->flags != UM_ALLOC) return; // Crazy again?! :)
00162 
00163         // Get the current task structure.
00164         t = get_curr_task();
00165 
00166         // Free the block.
00167         p->flags = UM_FREE;
00168         p->owner = NULL;
00169 
00170         // Try to combine the block wih the next one...
00171         p2 = (void *)p + p->size + sizeof(umem_block_t);
00172 
00173         if (p2 < (umem_block_t *)(t->heap_start + t->heap_size))
00174                 if (p2->flags == UM_FREE)
00175                 {
00176                         // Let's merge the two blocks!
00177                         p->size += p2->size + sizeof(umem_block_t);
00178                         p2->magic = NULL;
00179                 }
00180 
00181         // Try to combine the block with the previous one...
00182         if (p != (umem_block_t *)(t->heap_start))
00183         {
00184                 // Find the previous block.
00185                 p2 = (void *)(t->heap_start);
00186                 for(;;)
00187                 {
00188                         if (((void *)p2 + p2->size + sizeof(umem_block_t)) == p)
00189                         {
00190                                 // Block found!
00191                                 // Check if it's a free block.
00192                                 if (p2->flags == UM_FREE)
00193                                 {
00194                                         // Let's merge the two blocks!
00195                                         p2->size += (p->size + sizeof(umem_block_t));
00196                                         p->magic = NULL;
00197                                         p = p2;
00198                                 }
00199                                 break;
00200                         }
00201                         p2 = (void *)p2 + p2->size + sizeof(umem_block_t);
00202                 }
00203         }
00204 
00205         // Release the physical space occupied by the block.
00206         deallocate( p );
00207 }

Generated on Fri Feb 20 15:32:17 2004 for Minirighi by doxygen1.2.18