(미완성)평범한 개발자의 C 프로그래밍 이야기

본 토픽은 현재 준비중입니다. 공동공부에 참여하시면 완성 되었을 때 알려드립니다.

linux kernel - ion의 system heap 소개

여러 타입의 힙 중에서 가장 간단한 ION_HEAP_TYPE_SYSTEM 타입의 힙에 대해서 좀더 보겠습니다. 

ion_heap_create() 함수를 보면 사용자가 작성한 ion_platform_heap 데이터에 ION_HEAP_TYPE_SYSTEM 항목이 있을 때 ion_system_heap_create()를 호출해서 힙을 만드는 코드가 있습니다.

 320struct ion_heap *ion_heap_create(struct ion_platform_heap *heap_data)
 321{
 322        struct ion_heap *heap = NULL;
 323
 324        switch (heap_data->type) {
 325        case ION_HEAP_TYPE_SYSTEM_CONTIG:
 326                heap = ion_system_contig_heap_create(heap_data);
 327                break;
 328        case ION_HEAP_TYPE_SYSTEM:
 329                heap = ion_system_heap_create(heap_data);
 330                break;

 

switch-case 문이 사용되었다는 것은 변화가 생겼을 때 수정되어야 한다는 것을 말합니다. 만약 새로운 타입의 힙이 개발된다면 여기에 새로운 case 문이 생겨야 할 것입니다. 변하는 부분과 변하지 않는 부분이 만나는 지점이 됩니다.

http://lxr.linux.no/linux+v3.16/drivers/staging/android/ion/ion_system_heap.c 이 파일에 ION_HEAP_TYPE_SYSTEM 타입의 힙의 내부 구현이 있습니다.

 281struct ion_heap *ion_system_heap_create(struct ion_platform_heap *unused)
 282{
 283        struct ion_system_heap *heap;
 284        int i;
 285
 286        heap = kzalloc(sizeof(struct ion_system_heap), GFP_KERNEL);
 287        if (!heap)
 288                return ERR_PTR(-ENOMEM);
 289        heap->heap.ops = &system_heap_ops;
 290        heap->heap.type = ION_HEAP_TYPE_SYSTEM;
 291        heap->heap.flags = ION_HEAP_FLAG_DEFER_FREE;
 292        heap->pools = kzalloc(sizeof(struct ion_page_pool *) * num_orders,
 293                              GFP_KERNEL);
 294        if (!heap->pools)
 295                goto free_heap;
 296        for (i = 0; i < num_orders; i++) {
 297                struct ion_page_pool *pool;
 298                gfp_t gfp_flags = low_order_gfp_flags;
 299
 300                if (orders[i] > 4)
 301                        gfp_flags = high_order_gfp_flags;
 302                pool = ion_page_pool_create(gfp_flags, orders[i]);
 303                if (!pool)
 304                        goto destroy_pools;
 305                heap->pools[i] = pool;
 306        }
 307
 308        heap->heap.debug_show = ion_system_heap_debug_show;
 309        return &heap->heap;
 310
 311destroy_pools:
 312        while (i--)
 313                ion_page_pool_destroy(heap->pools[i]);
 314        kfree(heap->pools);
 315free_heap:
 316        kfree(heap);
 317        return ERR_PTR(-ENOMEM);
 318}

ion_system_heap_create()에서 우리가 봐야할 부분은 ion_system_heap이라는 데이터 구조와 system_heap_ops라는 데이터입니다.

먼저 ion_system_heap이라는 데이터 구조를 보겠습니다.

  50struct ion_system_heap {
  51        struct ion_heap heap;
  52        struct ion_page_pool **pools;
  53};

ion_system_heap이라는 구조체 내부에는 ion_heap라는 공통 데이터가 있습니다. 모든 타입의 힙들이 공통으로 가지는 속성들은 ion_heap 구조체를 만들어서 관리하므로 상위 계층에서는 ion_heap 데이터만 알면 힙을 사용할 수 있습니다.

ion_heap 구조체에 ops라는 항목이 있는데 여기에 힙의 코드를 등록합니다. SYSTEM 타입 힙에서는 system_heap_ops를 등록합니다.

 248static struct ion_heap_ops system_heap_ops = {
 249        .allocate = ion_system_heap_allocate,
 250        .free = ion_system_heap_free,
 251        .map_dma = ion_system_heap_map_dma,
 252        .unmap_dma = ion_system_heap_unmap_dma,
 253        .map_kernel = ion_heap_map_kernel,
 254        .unmap_kernel = ion_heap_unmap_kernel,
 255        .map_user = ion_heap_map_user,
 256        .shrink = ion_system_heap_shrink,
 257};

모든 힙이 동일한 ion_heap_ops 데이터에 자신만의 인터페이스를 등록하게됩니다. SYSTEM 힙에서는 위와 같이 .allocate 인터페이스에 ion_system_heap_allocate() 함수를 등록합니다.

그리고 가장 상위 인터페이스인 ion_alloc() 함수에서 ion_buffer_create()함수를 호출하고, ion_buffer_create()에서 다음과 같이 allocate 인터페이스가 호출됩니다.

 176static struct ion_buffer *ion_buffer_create(struct ion_heap *heap,
 177                                     struct ion_device *dev,
 178                                     unsigned long len,
 179                                     unsigned long align,
 180                                     unsigned long flags)
 181{
 182        struct ion_buffer *buffer;
 183        struct sg_table *table;
 184        struct scatterlist *sg;
 185        int i, ret;
 186
 187        buffer = kzalloc(sizeof(struct ion_buffer), GFP_KERNEL);
 188        if (!buffer)
 189                return ERR_PTR(-ENOMEM);
 190
 191        buffer->heap = heap;
 192        buffer->flags = flags;
 193        kref_init(&buffer->ref);
 194
 195        ret = heap->ops->allocate(heap, buffer, len, align, flags);

힙마다 allocate 인터페이스에 등록하는 함수들이 다릅니다. SYSTEM 힙은 ion_system_heap_allocate함수를 등록하고, SYSTEM_CONTIG 타입의 힙은 ion_system_contig_heap_allocate 함수를 등록합니다.

이렇게 힙마다 변하는 코드들은 개별적으로 구현하되 변하지 않는 공통의 인터페이스를 만들면 상위 계층에서는 힙의 코드가 변하거나 새로운 힙이 추가되거나할때 영향을 받지 않습니다.

MYWAY라는 새로운 힙을 추가한다고 생각해보면 가장 먼저 할 일은 구현 부분을 만드는 일입니다. ion_myway_heap_create()함수를 만들고 ion_heap_ops 데이터를 만들어서 .allocate 등의 인터페이스를 정의합니다. 그리고 ion_heap_create에 case를 추가하고 ion_myway_heap_create()가 호출되도록 합니다.

그렇게 내부 구현이 완성되면 가장 윗 계층 ion_dummy_driver에서 dummy_heap에 새로 만든 힙 타입을 추가해주기만 하면 새로운 타입의 힙을 사용할 수 있습니다. ion이라는 프레임워크의 구현을 손대지 않고 손쉽게 새로운 타입의 힙을 추가할 수 있습니다.

 

댓글

댓글 본문
작성자
비밀번호
버전 관리
gurugio
현재 버전
선택 버전
graphittie 자세히 보기