Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | Download | RSS feed

  1.  
  2. #define BUDDY_SYSTEM_INNER_BLOCK  0xff
  3.  
  4. #define frame_index( frame ) \
  5.       (index_t)( (frame) - z_core.frames)
  6.  
  7. #define frame_initialize( frame ) \
  8.     (frame)->refcount = 1;          \
  9.     (frame)->buddy_order = 0
  10.  
  11. #define buddy_get_order( block) \
  12.     ((frame_t*)(block))->buddy_order
  13.  
  14. #define buddy_set_order( block, order) \
  15.      ((frame_t*)(block))->buddy_order = (order)
  16.  
  17. #define buddy_mark_busy( block ) \
  18.     ((frame_t*)(block))->refcount = 1
  19.  
  20. #define IS_BUDDY_LEFT_BLOCK(frame)  \
  21.   (((frame_index((frame)) >> (frame)->buddy_order) & 0x1) == 0)
  22.  
  23. #define IS_BUDDY_RIGHT_BLOCK(frame) \
  24.     (((frame_index((frame)) >> (frame)->buddy_order) & 0x1) == 1)
  25.  
  26. #define buddy_mark_available( block ) \
  27.     ((frame_t*)(block))->refcount = 0
  28.  
  29.  
  30. static __inline link_t * buddy_bisect(link_t *block)
  31. {
  32.     frame_t *frame_l, *frame_r;
  33.  
  34.     frame_l = (frame_t*)block;
  35.     frame_r = (frame_l + (1 << (frame_l->buddy_order - 1)));
  36.  
  37.     return &frame_r->buddy_link;
  38. }
  39.  
  40. static __inline link_t *buddy_coalesce(link_t *block_1, link_t *block_2)
  41. {
  42.     frame_t *frame1, *frame2;
  43.  
  44.     frame1 = (frame_t*)block_1;
  45.     frame2 = (frame_t*)block_2;
  46.  
  47.     return frame1 < frame2 ? block_1 : block_2;
  48. }
  49.  
  50. static link_t *find_buddy(link_t *block)
  51. {
  52.     frame_t  *frame;
  53.     index_t   index;
  54.     u32_t     is_left, is_right;
  55.  
  56.     frame = (frame_t*)block;
  57.  //   ASSERT(IS_BUDDY_ORDER_OK(frame_index_abs(zone, frame),frame->buddy_order));
  58.  
  59.     is_left = IS_BUDDY_LEFT_BLOCK( frame);
  60.     is_right = IS_BUDDY_RIGHT_BLOCK( frame);
  61.  
  62.  //   ASSERT(is_left ^ is_right);
  63.     if (is_left) {
  64.         index = (frame_index(frame)) + (1 << frame->buddy_order);
  65.     } else {  /* if (is_right) */
  66.         index = (frame_index(frame)) - (1 << frame->buddy_order);
  67.     }
  68.  
  69.     if ( index < z_core.count)
  70.     {
  71.         if (z_core.frames[index].buddy_order == frame->buddy_order &&
  72.             z_core.frames[index].refcount == 0) {
  73.             return &z_core.frames[index].buddy_link;
  74.       }
  75.     }
  76.  
  77.     return NULL;
  78. }
  79.  
  80.  
  81. static link_t *buddy_find_block(link_t *child, u32_t order)
  82. {
  83.     frame_t *frame;
  84.     index_t index;
  85.  
  86.     frame = (frame_t*)child;
  87.  
  88.     index = frame_index(frame);
  89.     do {
  90.         if (z_core.frames[index].buddy_order != order)
  91.             return &z_core.frames[index].buddy_link;
  92.  
  93.     } while(index-- > 0);
  94.     return NULL;
  95. }
  96.  
  97. static void buddy_system_free(link_t *block)
  98. {
  99.     link_t *buddy, *hlp;
  100.     u32_t i;
  101.  
  102.     /*
  103.          * Determine block's order.
  104.          */
  105.    i = buddy_get_order(block);
  106.  
  107.  //  ASSERT(i <= z->max_order);
  108.  
  109.    if (i != z_core.max_order)
  110.    {
  111.                 /*
  112.                  * See if there is any buddy in the list of order i.
  113.                  */
  114.        buddy = find_buddy( block );
  115.        if (buddy)
  116.                 {
  117.  
  118.        //    ASSERT(buddy_get_order(z, buddy) == i);
  119.                         /*
  120.                          * Remove buddy from the list of order i.
  121.                          */
  122.                         list_remove(buddy);
  123.  
  124.                         /*
  125.                          * Invalidate order of both block and buddy.
  126.                          */
  127.            buddy_set_order(block, BUDDY_SYSTEM_INNER_BLOCK);
  128.            buddy_set_order(buddy, BUDDY_SYSTEM_INNER_BLOCK);
  129.  
  130.                         /*
  131.                          * Coalesce block and buddy into one block.
  132.                          */
  133.            hlp = buddy_coalesce( block, buddy );
  134.  
  135.                         /*
  136.                          * Set order of the coalesced block to i + 1.
  137.                          */
  138.            buddy_set_order(hlp, i + 1);
  139.  
  140.                         /*
  141.                          * Recursively add the coalesced block to the list of order i + 1.
  142.                          */
  143.            buddy_system_free( hlp );
  144.                         return;
  145.                 }
  146.         }
  147.         /*
  148.          * Insert block into the list of order i.
  149.          */
  150.    list_append(block, &z_core.order[i]);
  151. }
  152.  
  153.  
  154. static link_t* buddy_alloc( u32_t i)
  155. {
  156.         link_t *res, *hlp;
  157.  
  158.    ASSERT(i <= z_core.max_order);
  159.  
  160.         /*
  161.          * If the list of order i is not empty,
  162.          * the request can be immediatelly satisfied.
  163.          */
  164.    if (!list_empty(&z_core.order[i])) {
  165.        res = z_core.order[i].next;
  166.                 list_remove(res);
  167.                 buddy_mark_busy(res);
  168.                 return res;
  169.         }
  170.         /*
  171.          * If order i is already the maximal order,
  172.          * the request cannot be satisfied.
  173.          */
  174.    if (i == z_core.max_order)
  175.                 return NULL;
  176.  
  177.         /*
  178.          * Try to recursively satisfy the request from higher order lists.
  179.          */
  180.    hlp = buddy_alloc( i + 1 );
  181.  
  182.         /*
  183.          * The request could not be satisfied
  184.          * from higher order lists.
  185.          */
  186.         if (!hlp)
  187.                 return NULL;
  188.  
  189.         res = hlp;
  190.  
  191.         /*
  192.          * Bisect the block and set order of both of its parts to i.
  193.          */
  194.         hlp = buddy_bisect( res );
  195.  
  196.         buddy_set_order(res, i);
  197.         buddy_set_order(hlp, i);
  198.  
  199.         /*
  200.          * Return the other half to buddy system. Mark the first part
  201.          * full, so that it won't coalesce again.
  202.          */
  203.         buddy_mark_busy(res);
  204.         buddy_system_free( hlp );
  205.  
  206.         return res;
  207. }
  208.  
  209. static link_t* buddy_alloc_block(link_t *block)
  210. {
  211.         link_t *left,*right, *tmp;
  212.     u32_t order;
  213.  
  214.     left = buddy_find_block(block, BUDDY_SYSTEM_INNER_BLOCK);
  215.     ASSERT(left);
  216.         list_remove(left);
  217.     while (1)
  218.    {
  219.         if ( !buddy_get_order(left))
  220.         {
  221.             buddy_mark_busy(left);
  222.                         return left;
  223.                 }
  224.  
  225.         order = buddy_get_order(left);
  226.  
  227.         right = buddy_bisect(left);
  228.         buddy_set_order(left, order-1);
  229.         buddy_set_order(right, order-1);
  230.  
  231.         tmp = buddy_find_block( block, BUDDY_SYSTEM_INNER_BLOCK);
  232.  
  233.         if (tmp == right) {
  234.             right = left;
  235.             left = tmp;
  236.         }
  237.         ASSERT(tmp == left);
  238.         buddy_mark_busy(left);
  239.         buddy_system_free(right);
  240.         buddy_mark_available(left);
  241.         }
  242. }
  243.  
  244. static void zone_create(zone_t *z, pfn_t start, count_t count)
  245. {
  246.     unsigned int i;
  247.  
  248.     spinlock_initialize(&z->lock);
  249.  
  250.     z->base = start;
  251.     z->count = count;
  252.     z->free_count = count;
  253.     z->busy_count = 0;
  254.  
  255.     z->max_order = fnzb(count);
  256.  
  257.     ASSERT(z->max_order < BUDDY_SYSTEM_INNER_BLOCK);
  258.  
  259.     for (i = 0; i <= z->max_order; i++)
  260.         list_initialize(&z->order[i]);
  261.  
  262.     z->frames = (frame_t *)balloc(count*sizeof(frame_t));
  263.  
  264.     for (i = 0; i < count; i++)
  265.                 frame_initialize(&z->frames[i]);
  266.  
  267. /*
  268.     for (i = 0; i < count; i++) {
  269.         z_core.frames[i].buddy_order=0;
  270.         z_core.frames[i].parent = NULL;
  271.         z_core.frames[i].refcount=1;
  272.         }
  273.  
  274.     for (i = 0; i < count; i++)
  275.     {
  276.         z_core.frames[i].refcount = 0;
  277.         buddy_system_free(&z_core.frames[i].buddy_link);
  278.     }
  279. */
  280.  
  281.     DBG("create zone: base %x count %x order %d\n",
  282.          start, count, z->max_order);
  283.  
  284. }
  285.  
  286. static void zone_mark_unavailable(zone_t *zone, index_t frame_idx)
  287. {
  288.         frame_t *frame;
  289.         link_t *link;
  290.  
  291.     ASSERT(frame_idx < zone->count);
  292.  
  293.     frame = &zone->frames[frame_idx];
  294.  
  295.         if (frame->refcount)
  296.                 return;
  297.     link = buddy_alloc_block( &frame->buddy_link);
  298.     ASSERT(link);
  299.         zone->free_count--;
  300. }
  301.  
  302. static void zone_reserve(zone_t *z, pfn_t base, count_t count)
  303. {
  304.     int i;
  305.     pfn_t top = base + count;
  306.  
  307.     if( (base+count < z->base)||(base > z->base+z->count))
  308.         return;
  309.  
  310.     if(base < z->base)
  311.         base = z->base;
  312.  
  313.     if(top > z->base+z->count)
  314.         top = z->base+z->count;
  315.  
  316.     DBG("zone reserve base %x top %x\n", base, top);
  317.  
  318.     for (i = base; i < top; i++)
  319.         zone_mark_unavailable(z, i - z->base);
  320.  
  321. };
  322.  
  323. static void zone_release(zone_t *z, pfn_t base, count_t count)
  324. {
  325.     int i;
  326.     pfn_t top = base+count;
  327.  
  328.     if( (base+count < z->base)||(base > z->base+z->count))
  329.         return;
  330.  
  331.     if(base < z->base)
  332.         base = z->base;
  333.  
  334.     if(top > z->base+z->count)
  335.         top = z->base+z->count;
  336.  
  337.     DBG("zone release base %x top %x\n", base, top);
  338.  
  339.     for (i = base; i < top; i++) {
  340.         z->frames[i-z->base].refcount = 0;
  341.         buddy_system_free(&z->frames[i-z->base].buddy_link);
  342.     }
  343. };
  344.  
  345. static inline frame_t * zone_get_frame(zone_t *zone, index_t frame_idx)
  346. {
  347.     ASSERT(frame_idx < zone->count);
  348.         return &zone->frames[frame_idx];
  349. }
  350.  
  351. void __fastcall frame_set_parent(pfn_t pfn, void *data)
  352. {
  353.   spinlock_lock(&z_core.lock);
  354.   zone_get_frame(&z_core, pfn-z_core.base)->parent = data;
  355.   spinlock_unlock(&z_core.lock);
  356. }
  357.  
  358. void* __fastcall frame_get_parent(pfn_t pfn)
  359. {
  360.         void *res;
  361.  
  362.     spinlock_lock(&z_core.lock);
  363.     res = zone_get_frame(&z_core, pfn)->parent;
  364.     spinlock_unlock(&z_core.lock);
  365.  
  366.         return res;
  367. }
  368.  
  369.