Linux SLUB分配器之二(申请对象的代码分析)

static void __always_inline *slab_alloc(struct kmem_cache *s,

              gfp_t gfpflags, int node, void *addr)

{

       void **object;

       unsigned long flags;

       struct kmem_cache_cpu *c;

       local_irq_save(flags);

       c = get_cpu_slab(s, smp_processor_id());

       if (unlikely(!c->freelist || !node_match(c, node)))

              object = __slab_alloc(s, gfpflags, node, addr, c);

       else {

              object = c->freelist;/* 如果当前的 SLAB 里的对象没有用完,就从里面取 */

              c->freelist = object[c->offset]; /* 注意每个对象后面会多一块区域,指向下一个空闲对象,最后一个空闲对象的后面为 NULL ,表明此 SLAB 已经用完了 */

       }

       local_irq_restore(flags);

       if (unlikely((gfpflags & __GFP_ZERO) && object))

              memset(object, 0, c->objsize);

       return object;

}

 

static void *__slab_alloc(struct kmem_cache *s,

              gfp_t gfpflags, int node, void *addr, struct kmem_cache_cpu *c)

{

       void **object;

       struct page *new;

       if (!c->page)

              goto new_slab;

       slab_lock(c->page);

       if (unlikely(!node_match(c, node)))

              goto another_slab;

load_freelist:

       object = c->page->freelist;/* 因为有可能从下面 new_slab 标号处的分支跳转到这里,故而 freelist 可能不为空, new slab 会把 partial 或新的 slab 返回给这里 */

       if (unlikely(!object))/* 当前的 SLAB 用完了就会产生这个情况,那么就要把当前的 SLAB deactivate ,然后寻找一个新的 SLAB*/

              goto another_slab;

       if (unlikely(SlabDebug(c->page)))

              goto debug;

 

       object = c->page->freelist;/* 下面这一段取下当前的 SLAB freelist ,不管是新的还是 partial 的,将它放到 kmem_cache-> cpu_slab 上,请注意第一个空闲对象用于此次的分配,于是就被跳过去了 */

       c->freelist = object[c->offset];

       c->page->inuse = s->objects;

       c->page->freelist = NULL;

       c->node = page_to_nid(c->page);

       slab_unlock(c->page);

       return object;

another_slab:

       deactivate_slab(s, c);

new_slab:

       new = get_partial(s, gfpflags, node);/* 所有的 partial 都是放在 s->local_node 上的,即所有的 SLAB ,假设是一个 partial SLAB ,即该 SLAB 不是当前的 SLAB ,但上面有部分对象在用,都是放在 kmem_cache->local_node-> partial 上的,通过该 SLAB 的首页 (Page 数据结构 ) lru( 如果全部用完了,则被 deactivate 了,那么不在此 partial 链上 )*/

       if (new) {

              c->page = new;

              goto load_freelist;/* Partial SLAB 的情况 */

       }

       if (gfpflags & __GFP_WAIT)

              local_irq_enable();

       new = new_slab(s, gfpflags, node);/* 执行到这里, partial 也用完了,所以只能申请一个新的 SLAB */

       if (gfpflags & __GFP_WAIT)

              local_irq_disable();

       if (new) {

              c = get_cpu_slab(s, smp_processor_id());

              if (c->page)

                     flush_slab(s, c);

              slab_lock(new);

              SetSlabFrozen(new);

              c->page = new;

              goto load_freelist; /* New SLAB 的情况 */

       }

       return NULL;

debug:

       object = c->page->freelist;

       if (!alloc_debug_processing(s, c->page, object, addr))

              goto another_slab;

       c->page->inuse++;

       c->page->freelist = object[c->offset];

       c->node = -1;

       slab_unlock(c->page);

       return object;

}

 

static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)

{

       struct page *page;

       struct kmem_cache_node *n;

       void *start;

       void *last;

       void *p;

       BUG_ON(flags & GFP_SLAB_BUG_MASK);

       page = allocate_slab(s,

              flags & (GFP_RECLAIM_MASK | GFP_CONSTRAINT_MASK), node);/* 此函数只是 alloc_pages 的封装,在 NUMA 的情况下,及 node 不为 -1 的情况下,在 node 对应的内存上分配内存页,这是因为 NUMA 结构下买个内存的访问速度不一定一样,所以 CPU 都倾向于访问本地内存,这样最高效 */

       if (!page)

              goto out;

       n = get_node(s, page_to_nid(page));

       if (n)

              atomic_long_inc(&n->nr_slabs);

       page->slab = s;

       page->flags |= 1 << PG_slab;

       if (s->flags & (SLAB_DEBUG_FREE | SLAB_RED_ZONE | SLAB_POISON |

                     SLAB_STORE_USER | SLAB_TRACE))

              SetSlabDebug(page);

       start = page_address(page);

       if (unlikely(s->flags & SLAB_POISON))

              memset(start, POISON_INUSE, PAGE_SIZE << s->order);

       last = start;

       for_each_object(p, s, start) {/* 这一段代码将整个 free list 构建出来,每个 object 后面都有一个指针,指向下一个 object ,第一个 object 就是首 page 的起始地址;要注意的是,第一个 object 后面的指针,被赋值了两次,第一个指向自己,第二次才指向第二个 object ,这一点写的很恶心,让我不明白了一会儿 */

              setup_object(s, page, last);

              set_freepointer(s, last, p);

              last = p;

       }

       setup_object(s, page, last);

       set_freepointer(s, last, NULL);/* 将最后一个 object 后面的指针置为 NULL ,这也是函数 slab_alloc c->freelist 会最后为 NULL 的原因 */

       page->freelist = start;

       page->inuse = 0;

out:

       return page;

}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值