Linux Slob分配器(三)

slob释放对象由函数slob_free()来完成,分为三种情况进行处理:

slob中已有的空闲单元加上释放对象块的空闲单元正好等于一个空闲的page,那么将直接将该page释放回伙伴系统 slob中已无空闲单元,那么这次释放将更新slob的信息 普通情况,即slob处于部分满状态,那么更新slob的信息的同时还要将释放的块插入到相应的位置,要注意插入后是否能和相邻块进行合并!

下面来看具体的代码

/*   * slob_free: entry point into the slob allocator.   */   static void slob_free(void *block, int size)   {       struct slob_page *sp;       slob_t *prev, *next, *b = (slob_t *)block;       slobidx_t units;       unsigned long flags;          if (unlikely(ZERO_OR_NULL_PTR(block)))           return;       BUG_ON(!size);          sp = slob_page(block);//获取slob地址        units = SLOB_UNITS(size);//计算释放的单元数           spin_lock_irqsave(&slob_lock, flags);          /*slob剩余的单元数加上待释放的单元数正好等于一个slob本有的总单元数,        直接将slob占用的页框释放回伙伴系统*/       if (sp->units + units == SLOB_UNITS(PAGE_SIZE)) {           /* Go directly to page allocator. Do not pass slob allocator */           if (slob_page_free(sp))               clear_slob_page_free(sp);           spin_unlock_irqrestore(&slob_lock, flags);           clear_slob_page(sp);           free_slob_page(sp);           slob_free_pages(b, 0);           return;       }          if (!slob_page_free(sp)) {//slob没有空闲块            /* This slob page is about to become partially free. Easy! */           sp->units = units;//设置slob的单元数为释放对象的单元数            sp->free = b;//设置首对象为释放对象            set_slob(b, units,//最后一个对象的空闲对象设置为下一个页的首个单元                (void *)((unsigned long)(b +                       SLOB_UNITS(PAGE_SIZE)) & PAGE_MASK));           set_slob_page_free(sp, &free_slob_small);//将slob链入free_slob_small链表            goto out;       }          /*       * Otherwise the page is already partially free, so find reinsertion       * point.       */       sp->units += units;//空闲单元总数增加units           if (b < sp->free) {//待释放块的地址小于sp->free            if (b + units == sp->free) {//可以合并                units += slob_units(sp->free);               sp->free = slob_next(sp->free);//取free的下一个空闲对象作为free            }           /*将释放块插入在free前面,并将其作为首个空闲块赋给free*/           set_slob(b, units, sp->free);           sp->free = b;       } else {           prev = sp->free;//取首个空闲块            next = slob_next(prev);//取第二个空闲块            while (b > next) {//扫描至待释放块处                prev = next;               next = slob_next(prev);           }              /*将b插在prev和next中间,prev-->b-->next,要考虑是否能够合并*/                 /*如果prev不是最后一个空闲块并且b可以和next合并,则进行合并*/           if (!slob_last(prev) && b + units == next) {               units += slob_units(next);               set_slob(b, units, slob_next(next));           } else//否则将b插入在next前面                set_slob(b, units, next);              if (prev + slob_units(prev) == b) {//如果prev可以和b合并,则进行合并                units = slob_units(b) + slob_units(prev);               set_slob(prev, units, slob_next(b));           } else//否则,将b插在prev后面                set_slob(prev, slob_units(prev), b);       }   out:       spin_unlock_irqrestore(&slob_lock, flags);   }  

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/psydp.html