The GPS uses the message queue from the LOC_API layer to the LOC eng layer in the approximate format: sendmsg (new XXX), which will eventually be sent to the message queue, read in Loopmain, and then call MSG's log () and proc respectively ( ) to handle the corresponding message, so it is necessary to understand the general flow of this message queue
The GPS message Queue interprocess communication is divided between the sending side and the receiving end, so let's look at it separately.
API for the sending side:
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__);returnEmsg_q_invalid_handle; }if(Msg_obj = = NULL) {Loc_loge ("%s:invalid msg_obj parameter!\n", __function__);returnEmsg_q_invalid_parameter; }///Front Two is to judge the legality of Param //Convert Msg_q_data to msg queue the same type msg_q*msg_q* p_msg_q = (msg_q*) msg_q_data;//Lock P_msg_q Mutex,pthread_mutex_lock and PTHREAD_COND_XXX series functions are generally paired, preventing the competition between multi-threaded PTHREAD_COND_XXX series functionsPthread_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) {//If it is not locked, the MSG is not availableLoc_loge ("%s:message queue has been unblocked.\n", __function__); Pthread_mutex_unlock (&p_msg_q->list_mutex);returnEmsg_q_unavailable_resource; }//linked_list_add, from the name of the list should be the Insert actionRV = Convert_linked_list_err_type (Linked_list_add (p_msg_q->msg_list, Msg_obj, Dealloc));/ * Show data is in the message queue. * / //Wake the condition variable of the message queue, the Rcv end is blocked by this condition variable, please refer to manpage for specific usage.Pthread_cond_signal (&p_msg_q->list_cond);//Unlocks the MUTEX,RCV side of the message queue to extract data from the message queuePthread_mutex_unlock (&p_msg_q->list_mutex); LOC_LOGD ("%s:finished sending message with handle = 0x%08x\n", __function__, msg_obj);returnRV;}
The message queue, as the name implies, is inserted into the queue, and the following is the inserted action:
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__);returnElinked_list_invalid_handle; }if(Data_obj = = NULL) {Loc_loge ("%s:invalid input parameter!\n", __function__);returnElinked_list_invalid_parameter; }///Front Two is to judge the legality of Param //list_data is a pointer to the 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__);returnElinked_list_failure_general; }/ * Copy data to newly created element * / //Fill Elem, the incoming data_obj parameter is encapsulated into the Elem node, and then inserted into the MSG queueElem->data_ptr = Data_obj; Elem->next = NULL; Elem->prev = NULL; Elem->dealloc_func = Dealloc;/ * Replace Head element * / //Save list's head node to TMPlist_element* tmp = p_list->p_head;//list head node points to ElemP_list->p_head = Elem;/* Point next to the previous HEAD element * / The next node of//list's head node points to TMP, which is the previous head, so the elem becomes the new head node .P_list->p_head->next = tmp;if(tmp! = NULL) {//If the TMP node is not NULL for the previous head node, then the Prev pointer to the previous head node points to Elem (the new head node), which also shows that the previous head node becomes the next node of the head node .Tmp->prev = p_list->p_head; }Else{//If the TMP node is null, which is previously an empty doubly linked list, now the newly inserted elem node (p_list->p_head = Elem) is both the head node and the tail node .P_list->p_tail = p_list->p_head; }returnelinked_list_success;}
In terms of the function name, the return value of the linked list should be converted to the return value of the message queue:
Hardware/qcom/gps/utils/linked_list.c
StaticMsq_q_err_type Convert_linked_list_err_type (Linked_list_err_type linked_list_val) {Switch(Linked_list_val) { CaseElinked_list_success:returnemsg_q_success; CaseElinked_list_invalid_parameter:returnEmsg_q_invalid_parameter; CaseElinked_list_invalid_handle:returnEmsg_q_invalid_handle; CaseElinked_list_unavailable_resource:returnEmsg_q_unavailable_resource; CaseElinked_list_insufficient_buffer:returnEmsg_q_insufficient_buffer; CaseElinked_list_failure_general:default:returnEmsg_q_failure_general; }}
The message queue-related return value is defined as follows:
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;
Next look at the definition of msg_q:
Hardware/qcom/gps/utils/msg_q.c
typedefstruct 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;
For a doubly linked list that implements message queue, the data structure is as follows:
Hardware/qcom/gps/utils/linked_list.c
typedefstruct list_element { struct list_element* next; struct list_element* prev; void* data_ptr; void (*dealloc_func)(void*);}list_element;
List_state is defined as follows:
Hardware/qcom/gps/utils/linked_list.c
typedefstruct list_state { list_element* p_head; list_element* p_tail;} list_state;
API for the receiving end:
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__);returnEmsg_q_invalid_handle; }if(Msg_obj = = NULL) {Loc_loge ("%s:invalid msg_obj parameter!\n", __function__);returnEmsg_q_invalid_parameter; }///Front Two is to judge the legality of Param //msg_q_data is used to determine the message queuemsg_q* p_msg_q = (msg_q*) msg_q_data; LOC_LOGD ("%s:waiting on message\n", __function__);//Lock the mutex of message queue before operationPthread_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);returnEmsg_q_unavailable_resource; }/ * Wait for data in the message queue * / //Determine if message queue is empty and message queue is not destroyed while(Linked_list_empty (p_msg_q->msg_list) &&!p_msg_q->unblocked) {//If the message queue is empty and another thread has not "established" the condition variable, this will blockPthread_cond_wait (&p_msg_q->list_cond, &p_msg_q->list_mutex); }//If another thread "holds" the condition variable, remove the corresponding message from the message queueRV = Convert_linked_list_err_type (Linked_list_remove (P_msg_q->msg_list, msg_obj));unlock Message Queue mutex after run out//Pthread_mutex_unlock (&p_msg_q->list_mutex); LOC_LOGD ("%s:received message 0x%08X RV =%d\n", __function__, *msg_obj, RV);returnRV;}
The role of Linked_list_empty is to determine whether the linked list is empty, specifically implemented as follows:
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; return10; }}
The function of Lined_list_remove is to remove the message from the list and save it to the second parameter, and then delete the linked list node that is taken out, and implement the following:
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__);returnElinked_list_invalid_handle; }if(Data_obj = = NULL) {Loc_loge ("%s:invalid input parameter!\n", __function__);returnElinked_list_invalid_parameter; }///Front Two is to judge the legality of Param //Since it is removed from the message queue, returns Elinked_list_unavailable_resource if the message queue is emptylist_state* p_list = (list_state*) list_data;if(P_list->p_tail = = NULL) {returnElinked_list_unavailable_resource; }//Copy the contents of the tail node to TMP .list_element* tmp = p_list->p_tail;//The tail node pointer points to the previous node of the TMP (that is, the tail node of the previous step) (The new tail node) / * Replace Tail element * /P_list->p_tail = tmp->prev;if(P_list->p_tail! = NULL) {the next pointer of the new tail node points to null, so that the sub TMP falls out of the message queueP_list->p_tail->next = NULL; }Else{//The original message queue has only one node, then the head and tail both point to the null pointer, which means that there is no node in the message queue.P_list->p_head = p_list->p_tail; }//Assign the data_ptr of the extracted TMP node to the incoming parameter data_obj / * Copy data to output param * /*data_obj = tmp->data_ptr;/ * Free Allocated list element * / //Release out of the extracted nodes Free(TMP);returnelinked_list_success;}
After reading the whole process, the conclusion is that the sending and receiving ends are communicated through the message queue, and the specific message queue is implemented by a doubly linked list.
(GPS) GPS Message Queue parsing