Linux Slob分配器(三)--釋放對象

水平有限,描述不當之處還請指出,轉載請註明出處http://blog.csdn.net/vanbreaker/article/details/7705792


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);
}



發佈了59 篇原創文章 · 獲贊 33 · 訪問量 50萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章