BluedroidのソースコードのGKI部分を読みました。
Bluedroidは、Android 4.x - Android 5.1 で使われていたBluedroidプロトコルスタックです。
Android 6.0以降は、BludrdoidをフォークしたFluorideに変更されています。
GKI (General Kernel Interface)はBluedroidのOS依存部分のコードです。
ソースコード
- https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/master
- https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/master/gki/common/gki_buffer.c
- https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/master/gki/common/gki.h
- https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/master/gki/common/gki_common.h
- https://android.googlesource.com/platform/external/bluetooth/bluedroid/+/master/gki/ulinux/gki_int.h
バッファ管理
解説
- メモリプールでバッファを管理する
- 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;
}