Subversion Repositories HelenOS

Rev

Rev 430 | Rev 490 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (C) 2005 Jakub Jermar
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * - Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  *   notice, this list of conditions and the following disclaimer in the
  13.  *   documentation and/or other materials provided with the distribution.
  14.  * - The name of the author may not be used to endorse or promote products
  15.  *   derived from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29. #include <mm/buddy.h>
  30. #include <mm/frame.h>
  31. #include <mm/heap.h>
  32. #include <arch/types.h>
  33. #include <typedefs.h>
  34. #include <list.h>
  35. #include <debug.h>
  36.  
  37. /** Create buddy system
  38.  *
  39.  * Allocate memory for and initialize new buddy system.
  40.  *
  41.  * @param max_order The biggest allocable size will be 2^max_order.
  42.  * @param op Operations for new buddy system.
  43.  * @param data Pointer to be used by implentation.
  44.  *
  45.  * @return New buddy system.
  46.  */
  47. buddy_system_t *buddy_system_create(__u8 max_order, buddy_system_operations_t *op, void *data)
  48. {
  49.     buddy_system_t *b;
  50.     int i;
  51.  
  52.     ASSERT(max_order < BUDDY_SYSTEM_INNER_BLOCK);
  53.  
  54.     ASSERT(op->find_buddy);
  55.     ASSERT(op->set_order);
  56.     ASSERT(op->get_order);
  57.     ASSERT(op->bisect);
  58.     ASSERT(op->coalesce);
  59.  
  60.     /*
  61.      * Allocate memory for structure describing the whole buddy system.
  62.      */
  63.     b = (buddy_system_t *) early_malloc(sizeof(buddy_system_t));
  64.    
  65.     if (b) {
  66.         /*
  67.          * Allocate memory for all orders this buddy system will work with.
  68.          */
  69.         b->order = (link_t *) early_malloc(max_order * sizeof(link_t));
  70.         if (!b->order) {
  71.             early_free(b);
  72.             return NULL;
  73.         }
  74.    
  75.         for (i = 0; i < max_order; i++)
  76.             list_initialize(&b->order[i]);
  77.    
  78.         b->max_order = max_order;
  79.         b->op = op;
  80.         b->data = data;
  81.     }
  82.    
  83.     return b;
  84. }
  85.  
  86. /** Allocate block from buddy system.
  87.  *
  88.  * Allocate block from buddy system.
  89.  *
  90.  * @param b Buddy system pointer.
  91.  * @param i Returned block will be 2^i big.
  92.  *
  93.  * @return Block of data represented by link_t.
  94.  */
  95. link_t *buddy_system_alloc(buddy_system_t *b, __u8 i)
  96. {
  97.     link_t *res, *hlp;
  98.  
  99.     ASSERT(i < b->max_order);
  100.  
  101.     /*
  102.      * If the list of order i is not empty,
  103.      * the request can be immediatelly satisfied.
  104.      */
  105.     if (!list_empty(&b->order[i])) {
  106.         res = b->order[i].next;
  107.         list_remove(res);
  108.         return res;
  109.     }
  110.    
  111.     /*
  112.      * If order i is already the maximal order,
  113.      * the request cannot be satisfied.
  114.      */
  115.     if (i == b->max_order - 1)
  116.         return NULL;
  117.  
  118.     /*
  119.      * Try to recursively satisfy the request from higher order lists.
  120.      */
  121.     hlp = buddy_system_alloc(b, i + 1);
  122.    
  123.     /*
  124.      * The request could not be satisfied
  125.      * from higher order lists.
  126.      */
  127.     if (!hlp)
  128.         return NULL;
  129.        
  130.     res = hlp;
  131.    
  132.     /*
  133.      * Bisect the block and set order of both of its parts to i.
  134.      */
  135.     hlp = b->op->bisect(b, res);
  136.     b->op->set_order(b, res, i);
  137.     b->op->set_order(b, hlp, i);
  138.    
  139.     /*
  140.      * Return the other half to buddy system.
  141.      */
  142.     buddy_system_free(b, hlp);
  143.    
  144.     return res;
  145.    
  146. }
  147.  
  148. /** Return block to buddy system.
  149.  *
  150.  * Return block to buddy system.
  151.  *
  152.  * @param b Buddy system pointer.
  153.  * @param block Block to return.
  154.  */
  155. void buddy_system_free(buddy_system_t *b, link_t *block)
  156. {
  157.     link_t *buddy, *hlp;
  158.     __u8 i;
  159.    
  160.     /*
  161.      * Determine block's order.
  162.      */
  163.     i = b->op->get_order(b, block);
  164.  
  165.     ASSERT(i < b->max_order);
  166.  
  167.     if (i != b->max_order - 1) {
  168.         /*
  169.          * See if there is any buddy in the list of order i.
  170.          */
  171.         buddy = b->op->find_buddy(b, block);
  172.         if (buddy) {
  173.  
  174.             ASSERT(b->op->get_order(b, buddy) == i);
  175.        
  176.             /*
  177.              * Remove buddy from the list of order i.
  178.              */
  179.             list_remove(buddy);
  180.        
  181.             /*
  182.              * Invalidate order of both block and buddy.
  183.              */
  184.             b->op->set_order(b, block, BUDDY_SYSTEM_INNER_BLOCK);
  185.             b->op->set_order(b, buddy, BUDDY_SYSTEM_INNER_BLOCK);
  186.        
  187.             /*
  188.              * Coalesce block and buddy into one block.
  189.              */
  190.             hlp = b->op->coalesce(b, block, buddy);
  191.  
  192.             /*
  193.              * Set order of the coalesced block to i + 1.
  194.              */
  195.             b->op->set_order(b, hlp, i + 1);
  196.  
  197.             /*
  198.              * Recursively add the coalesced block to the list of order i + 1.
  199.              */
  200.             buddy_system_free(b, hlp);
  201.             return;
  202.         }
  203.     }
  204.  
  205.     /*
  206.      * Insert block into the list of order i.
  207.      */
  208.     list_append(block, &b->order[i]);
  209.  
  210. }
  211.