码迷,mamicode.com
首页 > 其他好文 > 详细

(gps)gps消息队列解析

时间:2015-03-11 10:53:06      阅读:194      评论:0      收藏:0      [点我收藏+]

标签: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)gps消息队列解析

标签:gps

原文地址:http://blog.csdn.net/lele_cheny/article/details/44195017

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!