0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Bluedroidの実装 GKIのバッファ管理を読む

Posted at

BluedroidのソースコードのGKI部分を読みました。

Bluedroidは、Android 4.x - Android 5.1 で使われていたBluedroidプロトコルスタックです。
Android 6.0以降は、BludrdoidをフォークしたFluorideに変更されています。

GKI (General Kernel Interface)はBluedroidのOS依存部分のコードです。

ソースコード

バッファ管理

解説

  • メモリプールでバッファを管理する
  • uITRONの固定長メモリプールと同様に、固定サイズのメモリブロックとして扱う。
  • メモリブロックの使用/空きの管理はqueueを用いて管理する。
  • 各メモリブロックの先頭には管理用のヘッダを持つ。

APIリスト

  • GKI_freebuf()はバッファの解放、GKI_getbuf()はサイズを指定してバッファの取得、GKI_get_buf_size()はバッファのサイズを取得、GKI_getpoolbuf()はプールを指定してバッファの取得。
  • GKI_poolcount()はプール内のバッファの個数を取得、GKI_poolfreecount()はプール内の空いているバッファの個数、GKI_poolutilization はプールのバッファ使用率を0-100で返す。
gki.h
/* To get and release buffers, change owner and get size
*/
GKI_API extern void    GKI_freebuf (void *);
GKI_API extern void   *GKI_getbuf (UINT16);
GKI_API extern UINT16  GKI_get_buf_size (void *);
GKI_API extern void   *GKI_getpoolbuf (UINT8);
GKI_API extern UINT16  GKI_poolcount (UINT8);
GKI_API extern UINT16  GKI_poolfreecount (UINT8);
GKI_API extern UINT16  GKI_poolutilization (UINT8);

バッファの初期化

  • gki_buffer.c の gki_buffer_init() でバッファの初期化を行います。

  • 制御用変数の初期化

gki_buffer.c
    for (tt = 0; tt < GKI_NUM_TOTAL_BUF_POOLS; tt++)
    {
        p_cb->pool_start[tt] = NULL;
        p_cb->pool_end[tt]   = NULL;
        p_cb->pool_size[tt]  = 0;
        p_cb->freeq[tt].p_first = 0;
        p_cb->freeq[tt].p_last  = 0;
        p_cb->freeq[tt].size    = 0;
        p_cb->freeq[tt].total   = 0;
        p_cb->freeq[tt].cur_cnt = 0;
        p_cb->freeq[tt].max_cnt = 0;
    }
  • GKI_USE_DYNAMIC_BUFFERS == TRUE ならmallocでプールを作成
gki_buffer.c
# if (GKI_NUM_FIXED_BUF_POOLS > 0)
    p_cb->bufpool0 = (UINT8 *)GKI_os_malloc ((GKI_BUF0_SIZE + BUFFER_PADDING_SIZE) * GKI_BUF0_MAX);
# endif
  • キューの初期化
gki_buffer.c
# if (GKI_NUM_FIXED_BUF_POOLS > 0)
    gki_init_free_queue(0, GKI_BUF0_SIZE, GKI_BUF0_MAX, p_cb->bufpool0);
# endif
  • バッファ制御用変数の更新
gki_buffer.c
    /* add pools to the pool_list which is arranged in the order of size */
    for(i=0; i < GKI_NUM_FIXED_BUF_POOLS ; i++)
    {
        p_cb->pool_list[i] = i;
    }
    p_cb->curr_total_no_of_pools = GKI_NUM_FIXED_BUF_POOLS;

静的バッファの初期化

  • GKI_USE_DYNAMIC_BUFFERS == FALSEならプールはgki_common.hで静的に確保
gki_common.h
# if (GKI_NUM_FIXED_BUF_POOLS > 0)
    UINT8 bufpool0[(ALIGN_POOL(GKI_BUF0_SIZE) + BUFFER_PADDING_SIZE) * GKI_BUF0_MAX];
# endif

バッファの取得

  • gki_buffer.c の GKI_getpoolbuf () の中身です。
gki_buffer.c
void *GKI_getpoolbuf (UINT8 pool_id)
{
    FREE_QUEUE_T  *Q;
    BUFFER_HDR_T  *p_hdr;
    tGKI_COM_CB *p_cb = &gki_cb.com;
  • pool_idのチェック
gki_buffer.c
    if (pool_id >= GKI_NUM_TOTAL_BUF_POOLS)
    {
        GKI_exception(GKI_ERROR_GETPOOLBUF_BAD_QID, "getpoolbuf bad pool");
        return (NULL);
    }
  • GKI_disable()とGKI_enable()で排他制御
  • p_cb->freeq[pool_id]で空きを確認
  • GKI_USE_DEFERED_ALLOC_BUF_POOLS ならpoolの拡張ができる
  • p_hdrが取得するバッファのヘッダの先頭
  • バッファのヘッダに、task_id status p_next Type を設定する
gki_buffer.c
    /* Make sure the buffers aren't disturbed til finished with allocation */
    GKI_disable();
    Q = &p_cb->freeq[pool_id];
    if(Q->cur_cnt < Q->total)
    {
// btla-specific ++
# ifdef GKI_USE_DEFERED_ALLOC_BUF_POOLS
        if(Q->p_first == 0 && gki_alloc_free_queue(pool_id) != TRUE)
        {
            GKI_enable();
            return NULL;
        }
# endif
// btla-specific --
        p_hdr = Q->p_first;
        Q->p_first = p_hdr->p_next;
        if (!Q->p_first)
            Q->p_last = NULL;
        if(++Q->cur_cnt > Q->max_cnt)
            Q->max_cnt = Q->cur_cnt;
        GKI_enable();
        p_hdr->task_id = GKI_get_taskid();
        p_hdr->status  = BUF_STATUS_UNLINKED;
        p_hdr->p_next  = NULL;
        p_hdr->Type    = 0;
        return ((void *) ((UINT8 *)p_hdr + BUFFER_HDR_SIZE));
    }
  • 指定したpoolが空いていなかったら、GKI_getbuf()を試す。
gki_buffer.c
    /* If here, no buffers in the specified pool */
    GKI_enable();
    /* try for free buffers in public pools */
    return (GKI_getbuf(p_cb->freeq[pool_id].size));
}

バッファの解放

  • gki_buffer.c の GKI_freebuf () の中身です。
gki_buffer.c
void GKI_freebuf (void *p_buf)
{
    FREE_QUEUE_T    *Q;
    BUFFER_HDR_T    *p_hdr;
  • バッファのヘッダをチェックし、問題があるなら、GKI_exception()を呼ぶ。
gki_buffer.c
# if (GKI_ENABLE_BUF_CORRUPTION_CHECK == TRUE)
    if (!p_buf || gki_chk_buf_damage(p_buf))
    {
        GKI_exception(GKI_ERROR_BUF_CORRUPTED, "Free - Buf Corrupted");
        return;
    }
# endif
    p_hdr = (BUFFER_HDR_T *) ((UINT8 *)p_buf - BUFFER_HDR_SIZE);
    if (p_hdr->status != BUF_STATUS_UNLINKED)
    {
        GKI_exception(GKI_ERROR_FREEBUF_BUF_LINKED, "Freeing Linked Buf");
        return;
    }
    if (p_hdr->q_id >= GKI_NUM_TOTAL_BUF_POOLS)
    {
        GKI_exception(GKI_ERROR_FREEBUF_BAD_QID, "Bad Buf QId");
        return;
    }
  • poolのquueueにバッファを追加する。
  • バッファのヘッダ p_next status task_id を更新する
gki_buffer.c
    GKI_disable();
    /*
    ** Release the buffer
    */
    Q  = &gki_cb.com.freeq[p_hdr->q_id];
    if (Q->p_last)
        Q->p_last->p_next = p_hdr;
    else
        Q->p_first = p_hdr;
    Q->p_last      = p_hdr;
    p_hdr->p_next  = NULL;
    p_hdr->status  = BUF_STATUS_FREE;
    p_hdr->task_id = GKI_INVALID_TASK;
    if (Q->cur_cnt > 0)
        Q->cur_cnt--;
    GKI_enable();
    return;
}
0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?