标签:gps
gps从loc_api层到loc eng层用到了消息队列,大致格式是:sendMsg(new xxx),这个msg最终会发送到message queue中,在loopMain中读取出来然后分别调用msg的log()和proc()来处理相应的message,因此有必要了解一下这个message queue的大致flow
gps message queue进程间通信分为发送端和接收端,我们分开来看一下。
发送端的api:
hardware/qcom/gps/utils/msg_q.c
msq_q_err_type msg_q_snd(void* msg_q_data, void* msg_obj, void (*dealloc)(void*))
{
msq_q_err_type rv;
if( msg_q_data == NULL )
{
LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
return eMSG_Q_INVALID_HANDLE;
}
if( msg_obj == NULL )
{
LOC_LOGE("%s: Invalid msg_obj parameter!\n", __FUNCTION__);
return eMSG_Q_INVALID_PARAMETER;
}
//前面两个是判断param的合法性
//把msg_q_data转换为msg queue相同的类型msg_q*
msg_q* p_msg_q = (msg_q*)msg_q_data;
//锁定p_msg_q的mutex,pthread_mutex_lock跟pthread_cond_xxx系列函数一般是成对出现的,防止多线程的pthread_cond_xxx系列函数之间竞争
pthread_mutex_lock(&p_msg_q->list_mutex);
LOC_LOGD("%s: Sending message with handle = 0x%08X\n", __FUNCTION__, msg_obj);
if( p_msg_q->unblocked )
{
//如果不是锁定的,说明该msg是不可用的
LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
pthread_mutex_unlock(&p_msg_q->list_mutex);
return eMSG_Q_UNAVAILABLE_RESOURCE;
}
//linked_list_add,从名字来看应该是链表的插入动作
rv = convert_linked_list_err_type(linked_list_add(p_msg_q->msg_list, msg_obj, dealloc));
/* Show data is in the message queue. */
//唤醒message queue的条件变量,rcv端被这个条件变量block住了哦,具体用法可请参见manpage
pthread_cond_signal(&p_msg_q->list_cond);
//解锁message queue的mutex,rcv端才可以从message queue中取出数据
pthread_mutex_unlock(&p_msg_q->list_mutex);
LOC_LOGD("%s: Finished Sending message with handle = 0x%08X\n", __FUNCTION__, msg_obj);
return rv;
}
message queue,顾名思义message会插入到queue中,下面就是插入的动作:
hardware/qcom/gps/utils/linked_list.c
linked_list_err_type linked_list_add(void* list_data, void *data_obj, void (*dealloc)(void*))
{
LOC_LOGD("%s: Adding to list data_obj = 0x%08X\n", __FUNCTION__, data_obj);
if( list_data == NULL )
{
LOC_LOGE("%s: Invalid list parameter!\n", __FUNCTION__);
return eLINKED_LIST_INVALID_HANDLE;
}
if( data_obj == NULL )
{
LOC_LOGE("%s: Invalid input parameter!\n", __FUNCTION__);
return eLINKED_LIST_INVALID_PARAMETER;
}
//前面两个是判断param的合法性
//list_data是能确认msg queue的指针
list_state* p_list = (list_state*)list_data;
list_element* elem = (list_element*)malloc(sizeof(list_element));
if( elem == NULL )
{
LOC_LOGE("%s: Memory allocation failed\n", __FUNCTION__);
return eLINKED_LIST_FAILURE_GENERAL;
}
/* Copy data to newly created element */
//填充elem,传入的data_obj参数封装到elem结点,然后插入到msg queue
elem->data_ptr = data_obj;
elem->next = NULL;
elem->prev = NULL;
elem->dealloc_func = dealloc;
/* Replace head element */
//保存list的head结点到tmp
list_element* tmp = p_list->p_head;
//list的head结点指向elem
p_list->p_head = elem;
/* Point next to the previous head element */
//list的head结点的next结点指向tmp,也就是以前的head,这样子elem就成了新的head结点
p_list->p_head->next = tmp;
if( tmp != NULL )
{
//如果tmp结点,就是以前的head结点不是null,那么以前head结点的prev指针指向elem(新的head结点),这也说明了以前的head结点成了现在head结点的下一个结点
tmp->prev = p_list->p_head;
}
else
{
//如果tmp结点是null,也就是以前就是一个空的双向链表,现在新插入的elem结点(p_list->p_head = elem)既是head结点,也是tail结点
p_list->p_tail = p_list->p_head;
}
return eLINKED_LIST_SUCCESS;
}
从函数名来看,应该是把链表的返回值转换成message queue的返回值:
hardware/qcom/gps/utils/linked_list.c
static msq_q_err_type convert_linked_list_err_type(linked_list_err_type linked_list_val)
{
switch( linked_list_val )
{
case eLINKED_LIST_SUCCESS:
return eMSG_Q_SUCCESS;
case eLINKED_LIST_INVALID_PARAMETER:
return eMSG_Q_INVALID_PARAMETER;
case eLINKED_LIST_INVALID_HANDLE:
return eMSG_Q_INVALID_HANDLE;
case eLINKED_LIST_UNAVAILABLE_RESOURCE:
return eMSG_Q_UNAVAILABLE_RESOURCE;
case eLINKED_LIST_INSUFFICIENT_BUFFER:
return eMSG_Q_INSUFFICIENT_BUFFER;
case eLINKED_LIST_FAILURE_GENERAL:
default:
return eMSG_Q_FAILURE_GENERAL;
}
}
message queue相关的返回值定义如下:
hardware/qcom/gps/utils/msg_q.h
typedef enum
{
eMSG_Q_SUCCESS = 0,
/**< Request was successful. */
eMSG_Q_FAILURE_GENERAL = -1,
/**< Failed because of a general failure. */
eMSG_Q_INVALID_PARAMETER = -2,
/**< Failed because the request contained invalid parameters. */
eMSG_Q_INVALID_HANDLE = -3,
/**< Failed because an invalid handle was specified. */
eMSG_Q_UNAVAILABLE_RESOURCE = -4,
/**< Failed because an there were not enough resources. */
eMSG_Q_INSUFFICIENT_BUFFER = -5,
/**< Failed because an the supplied buffer was too small. */
}msq_q_err_type;
接下来看一下msg_q的定义:
hardware/qcom/gps/utils/msg_q.c
typedef struct msg_q {
void* msg_list; /* Linked list to store information */
pthread_cond_t list_cond; /* Condition variable for waiting on msg queue */
pthread_mutex_t list_mutex; /* Mutex for exclusive access to message queue */
int unblocked; /* Has this message queue been unblocked? */
} msg_q;
关于实现message queue的双向链表,数据结构如下:
hardware/qcom/gps/utils/linked_list.c
typedef struct list_element {
struct list_element* next;
struct list_element* prev;
void* data_ptr;
void (*dealloc_func)(void*);
}list_element;
list_state的定义如下:
hardware/qcom/gps/utils/linked_list.c
typedef struct list_state {
list_element* p_head;
list_element* p_tail;
} list_state;
接收端的api:
hardware/qcom/gps/utils/msg_q.c
msq_q_err_type msg_q_rcv(void* msg_q_data, void** msg_obj)
{
msq_q_err_type rv;
if( msg_q_data == NULL )
{
LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
return eMSG_Q_INVALID_HANDLE;
}
if( msg_obj == NULL )
{
LOC_LOGE("%s: Invalid msg_obj parameter!\n", __FUNCTION__);
return eMSG_Q_INVALID_PARAMETER;
}
//前面两个是判断param的合法性
//msg_q_data是用来确定message queue的
msg_q* p_msg_q = (msg_q*)msg_q_data;
LOC_LOGD("%s: Waiting on message\n", __FUNCTION__);
//在操作之前锁定message queue的mutex
pthread_mutex_lock(&p_msg_q->list_mutex);
if( p_msg_q->unblocked )
{
LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
pthread_mutex_unlock(&p_msg_q->list_mutex);
return eMSG_Q_UNAVAILABLE_RESOURCE;
}
/* Wait for data in the message queue */
//判断message queue是否为空,且message queue没有被销毁
while( linked_list_empty(p_msg_q->msg_list) && !p_msg_q->unblocked )
{
//如果message queue是空,且另一个线程还没有使条件变量“成立”,那么此处会阻塞住
pthread_cond_wait(&p_msg_q->list_cond, &p_msg_q->list_mutex);
}
//如果另一个线程使条件变量“成立”,那么从message queue中取出相应的message
rv = convert_linked_list_err_type(linked_list_remove(p_msg_q->msg_list, msg_obj));
//用完之后unlock message queue的mutex
pthread_mutex_unlock(&p_msg_q->list_mutex);
LOC_LOGD("%s: Received message 0x%08X rv = %d\n", __FUNCTION__, *msg_obj, rv);
return rv;
}
linked_list_empty的作用是判断链表是否为空,具体实现如下:
hardware/qcom/gps/utils/linked_list.c
int linked_list_empty(void* list_data)
{
//如果message queue的指针是NULL,那么返回eLINKED_LIST_INVALID_HANDLE
if( list_data == NULL )
{
LOC_LOGE("%s: Invalid list parameter!\n", __FUNCTION__);
return (int)eLINKED_LIST_INVALID_HANDLE;
}
//如果p_list的head结点是NULL,那么message queue是空的,否则非空
else
{
list_state* p_list = (list_state*)list_data;
return p_list->p_head == NULL ? 1 : 0;
}
}
lined_list_remove的作用是从链表中取出message保存到第二个参数中,然后删掉取出的链表结点,具体实现如下:
hardware/qcom/gps/utils/linked_list.c
linked_list_err_type linked_list_remove(void* list_data, void **data_obj)
{
LOC_LOGD("%s: Removing from list\n", __FUNCTION__);
if( list_data == NULL )
{
LOC_LOGE("%s: Invalid list parameter!\n", __FUNCTION__);
return eLINKED_LIST_INVALID_HANDLE;
}
if( data_obj == NULL )
{
LOC_LOGE("%s: Invalid input parameter!\n", __FUNCTION__);
return eLINKED_LIST_INVALID_PARAMETER;
}
//前面两个是判断param的合法性
//既然是从message queue中取出,那么如果message queue是空的,则返回eLINKED_LIST_UNAVAILABLE_RESOURCE
list_state* p_list = (list_state*)list_data;
if( p_list->p_tail == NULL )
{
return eLINKED_LIST_UNAVAILABLE_RESOURCE;
}
//把尾结点的内容拷贝到tmp中
list_element* tmp = p_list->p_tail;
//把尾结点指针指向tmp(也就是前一步的尾结点)的前一个结点(新的尾结点)
/* Replace tail element */
p_list->p_tail = tmp->prev;
if( p_list->p_tail != NULL )
{
//新的尾结点的next指针指向NULL,这样子tmp从message queue中脱落
p_list->p_tail->next = NULL;
}
else
{
//原来message queue中只有一个结点,那么取出之后head和tail都指向NULL指针,也就是message queue中没有任何结点了
p_list->p_head = p_list->p_tail;
}
//把取出的tmp结点的data_ptr赋值给传入的参数data_obj
/* Copy data to output param */
*data_obj = tmp->data_ptr;
/* Free allocated list element */
//释放掉取出来的结点
free(tmp);
return eLINKED_LIST_SUCCESS;
}
看完整个流程之后,得出的结论是:发送端和接收端是通过消息队列进行通信的,具体消息队列是用双向链表来实现的。
标签:gps
原文地址:http://blog.csdn.net/lele_cheny/article/details/44195017