GKI模块是Bluedroid中用于线程间通信的,我们知道蓝牙所有的操作最终都会交给Bluedroid处理,而调用方可能来自多个线程,Bluedroid中有大量的全局变量,为避免多线程导致的数据不一致问题,干脆统一切换到一个固定的工作线程中执行。类似于Java中的post Runnable,这里是给线程发送消息或事件。
接下来我们开始分析GKI源码,文件并不多,我们首先以gki模块的初始化为入口,在gki_ulinux.c中,如下:
void GKI_init(void)
{
pthread_mutexattr_t attr;
tGKI_OS *p_os;
memset (&gki_cb, 0, sizeof (gki_cb));
gki_buffer_init();
gki_timers_init();
alarm_service_init();
gki_cb.com.OSTicks = (UINT32) times(0);
pthread_mutexattr_init(&attr);
p_os = &gki_cb.os;
pthread_mutex_init(&p_os->GKI_mutex, &attr);
struct sigevent sigevent;
memset(&sigevent, 0, sizeof(sigevent));
sigevent.sigev_notify = SIGEV_THREAD;
sigevent.sigev_notify_function = (void (*)(union sigval))bt_alarm_cb;
sigevent.sigev_value.sival_ptr = NULL;
if (timer_create(CLOCK_REALTIME, &sigevent, &posix_timer) == -1) {
timer_created = false;
} else {
timer_created = true;
}
}
首先将gki_cb清零,这个变量非常重要,如下:
tGKI_CB gki_cb;
typedef struct
{
tGKI_OS os;
tGKI_COM_CB com;
} tGKI_CB;
typedef struct
{
pthread_mutex_t GKI_mutex;
pthread_t thread_id[GKI_MAX_TASKS];
pthread_mutex_t thread_evt_mutex[GKI_MAX_TASKS];
pthread_cond_t thread_evt_cond[GKI_MAX_TASKS];
pthread_mutex_t thread_timeout_mutex[GKI_MAX_TASKS];
pthread_cond_t thread_timeout_cond[GKI_MAX_TASKS];
} tGKI_OS;
typedef struct {
UINT8 *OSStack[GKI_MAX_TASKS]; /* pointer to beginning of stack */
UINT16 OSStackSize[GKI_MAX_TASKS]; /* stack size available to each task */
INT8 *OSTName[GKI_MAX_TASKS]; /* name of the task */
UINT8 OSRdyTbl[GKI_MAX_TASKS]; /* current state of the task */
UINT16 OSWaitEvt[GKI_MAX_TASKS]; /* events that have to be processed by the task */
UINT16 OSWaitForEvt[GKI_MAX_TASKS]; /* events the task is waiting for*/
UINT32 OSTicks; /* system ticks from start */
UINT32 OSIdleCnt; /* idle counter */
INT16 OSDisableNesting; /* counter to keep track of interrupt disable nesting */
INT16 OSLockNesting; /* counter to keep track of sched lock nesting */
INT16 OSIntNesting; /* counter to keep track of interrupt nesting */
/* Timer related variables
*/
INT32 OSTicksTilExp; /* Number of ticks till next timer expires */
INT32 OSNumOrigTicks; /* Number of ticks between last timer expiration to the next one */
INT32 OSWaitTmr [GKI_MAX_TASKS]; /* ticks the task has to wait, for specific events */
/* Buffer related variables
*/
BUFFER_HDR_T *OSTaskQFirst[GKI_MAX_TASKS][NUM_TASK_MBOX]; /* array of pointers to the first event in the task mailbox */
BUFFER_HDR_T *OSTaskQLast [GKI_MAX_TASKS][NUM_TASK_MBOX]; /* array of pointers to the last event in the task mailbox */
/* Define the buffer pool management variables
*/
FREE_QUEUE_T freeq[GKI_NUM_TOTAL_BUF_POOLS];
UINT16 pool_buf_size[GKI_NUM_TOTAL_BUF_POOLS];
UINT16 pool_max_count[GKI_NUM_TOTAL_BUF_POOLS];
UINT16 pool_additions[GKI_NUM_TOTAL_BUF_POOLS];
/* Define the buffer pool start addresses
*/
UINT8 *pool_start[GKI_NUM_TOTAL_BUF_POOLS]; /* array of pointers to the start of each buffer pool */
UINT8 *pool_end[GKI_NUM_TOTAL_BUF_POOLS]; /* array of pointers to the end of each buffer pool */
UINT16 pool_size[GKI_NUM_TOTAL_BUF_POOLS]; /* actual size of the buffers in a pool */
/* Define the buffer pool access control variables */
void *p_user_mempool; /* User O/S memory pool */
UINT16 pool_access_mask; /* Bits are set if the corresponding buffer pool is a restricted pool */
UINT8 pool_list[GKI_NUM_TOTAL_BUF_POOLS]; /* buffer pools arranged in the order of size */
UINT8 curr_total_no_of_pools; /* number of fixed buf pools + current number of dynamic pools */
BOOLEAN timer_nesting; /* flag to prevent timer interrupt nesting */
} tGKI_COM_CB;
tGKI_OS里有个GKI全局锁,一个线程池,还有关于evt和timeout的锁和条件变量。tGKI_COM_CB作为整个GKI的控制中心,里面的数据结构很复杂。
我们继续回到gki_init,在将gki_cb清零后,接下里先后初始化buffer, timer和alarm_service。然后初始化tGKI_OS中的GKI全局锁,最后创建一个定时器,当定时器到期时内核会启动一个线程执行bt_alarm_cb回调函数。
再来看gki_buffer_init是如何初始化缓冲区的,如下:
void gki_buffer_init(void)
{
UINT8 i, tt, mb;
tGKI_COM_CB *p_cb = &gki_cb.com;
/* Initialize mailboxes */
for (tt = 0; tt < GKI_MAX_TASKS; tt++)
{
for (mb = 0; mb < NUM_TASK_MBOX; mb++)
{
p_cb->OSTaskQFirst[tt][mb] = NULL;
p_cb->OSTaskQLast [tt][mb] = NULL;
}
}
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;
}
/* Use default from target.h */
p_cb->pool_access_mask = GKI_DEF_BUFPOOL_PERM_MASK;
/* 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;
return;
}
GKI缓冲区相关的控制数据结构都在tGKI_COM_CB中,如下:
/* Buffer related variables */
BUFFER_HDR_T *OSTaskQFirst[GKI_MAX_TASKS][NUM_TASK_MBOX]; /* array of pointers to the first event in the task mailbox */
BUFFER_HDR_T *OSTaskQLast [GKI_MAX_TASKS][NUM_TASK_MBOX]; /* array of pointers to the last event in the task mailbox */
typedef struct _buffer_hdr
{
struct _buffer_hdr *p_next; /* next buffer in the queue */
UINT8 q_id; /* id of the queue */
UINT8 task_id; /* task which allocated