Home | History | Annotate | Download | only in utils
      1 /* Copyright (c) 2011-2012, The Linux Foundation. All rights reserved.
      2  *
      3  * Redistribution and use in source and binary forms, with or without
      4  * modification, are permitted provided that the following conditions are
      5  * met:
      6  *     * Redistributions of source code must retain the above copyright
      7  *       notice, this list of conditions and the following disclaimer.
      8  *     * Redistributions in binary form must reproduce the above
      9  *       copyright notice, this list of conditions and the following
     10  *       disclaimer in the documentation and/or other materials provided
     11  *       with the distribution.
     12  *     * Neither the name of The Linux Foundation, nor the names of its
     13  *       contributors may be used to endorse or promote products derived
     14  *       from this software without specific prior written permission.
     15  *
     16  * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
     17  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
     18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
     19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
     20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
     23  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
     24  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
     25  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
     26  * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27  */
     28 
     29 #include "msg_q.h"
     30 
     31 #define LOG_TAG "LocSvc_utils_q"
     32 #include "log_util.h"
     33 #include "platform_lib_includes.h"
     34 #include "linked_list.h"
     35 #include <stdio.h>
     36 #include <stdlib.h>
     37 #include <pthread.h>
     38 
     39 typedef struct msg_q {
     40    void* msg_list;                  /* Linked list to store information */
     41    pthread_cond_t  list_cond;       /* Condition variable for waiting on msg queue */
     42    pthread_mutex_t list_mutex;      /* Mutex for exclusive access to message queue */
     43    int unblocked;                   /* Has this message queue been unblocked? */
     44 } msg_q;
     45 
     46 /*===========================================================================
     47 FUNCTION    convert_linked_list_err_type
     48 
     49 DESCRIPTION
     50    Converts from one set of enum values to another.
     51 
     52    linked_list_val: Value to convert to msg_q_enum_type
     53 
     54 DEPENDENCIES
     55    N/A
     56 
     57 RETURN VALUE
     58    Corresponding linked_list_enum_type in msg_q_enum_type
     59 
     60 SIDE EFFECTS
     61    N/A
     62 
     63 ===========================================================================*/
     64 static msq_q_err_type convert_linked_list_err_type(linked_list_err_type linked_list_val)
     65 {
     66    switch( linked_list_val )
     67    {
     68    case eLINKED_LIST_SUCCESS:
     69       return eMSG_Q_SUCCESS;
     70    case eLINKED_LIST_INVALID_PARAMETER:
     71       return eMSG_Q_INVALID_PARAMETER;
     72    case eLINKED_LIST_INVALID_HANDLE:
     73       return eMSG_Q_INVALID_HANDLE;
     74    case eLINKED_LIST_UNAVAILABLE_RESOURCE:
     75       return eMSG_Q_UNAVAILABLE_RESOURCE;
     76    case eLINKED_LIST_INSUFFICIENT_BUFFER:
     77       return eMSG_Q_INSUFFICIENT_BUFFER;
     78 
     79    case eLINKED_LIST_FAILURE_GENERAL:
     80    default:
     81       return eMSG_Q_FAILURE_GENERAL;
     82    }
     83 }
     84 
     85 /* ----------------------- END INTERNAL FUNCTIONS ---------------------------------------- */
     86 
     87 /*===========================================================================
     88 
     89   FUNCTION:   msg_q_init
     90 
     91   ===========================================================================*/
     92 msq_q_err_type msg_q_init(void** msg_q_data)
     93 {
     94    if( msg_q_data == NULL )
     95    {
     96       LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
     97       return eMSG_Q_INVALID_PARAMETER;
     98    }
     99 
    100    msg_q* tmp_msg_q;
    101    tmp_msg_q = (msg_q*)calloc(1, sizeof(msg_q));
    102    if( tmp_msg_q == NULL )
    103    {
    104       LOC_LOGE("%s: Unable to allocate space for message queue!\n", __FUNCTION__);
    105       return eMSG_Q_FAILURE_GENERAL;
    106    }
    107 
    108    if( linked_list_init(&tmp_msg_q->msg_list) != 0 )
    109    {
    110       LOC_LOGE("%s: Unable to initialize storage list!\n", __FUNCTION__);
    111       free(tmp_msg_q);
    112       return eMSG_Q_FAILURE_GENERAL;
    113    }
    114 
    115    if( pthread_mutex_init(&tmp_msg_q->list_mutex, NULL) != 0 )
    116    {
    117       LOC_LOGE("%s: Unable to initialize list mutex!\n", __FUNCTION__);
    118       linked_list_destroy(&tmp_msg_q->msg_list);
    119       free(tmp_msg_q);
    120       return eMSG_Q_FAILURE_GENERAL;
    121    }
    122 
    123    if( pthread_cond_init(&tmp_msg_q->list_cond, NULL) != 0 )
    124    {
    125       LOC_LOGE("%s: Unable to initialize msg q cond var!\n", __FUNCTION__);
    126       linked_list_destroy(&tmp_msg_q->msg_list);
    127       pthread_mutex_destroy(&tmp_msg_q->list_mutex);
    128       free(tmp_msg_q);
    129       return eMSG_Q_FAILURE_GENERAL;
    130    }
    131 
    132    tmp_msg_q->unblocked = 0;
    133 
    134    *msg_q_data = tmp_msg_q;
    135 
    136    return eMSG_Q_SUCCESS;
    137 }
    138 
    139 /*===========================================================================
    140 
    141   FUNCTION:   msg_q_init2
    142 
    143   ===========================================================================*/
    144 const void* msg_q_init2()
    145 {
    146   void* q = NULL;
    147   if (eMSG_Q_SUCCESS != msg_q_init(&q)) {
    148     q = NULL;
    149   }
    150   return q;
    151 }
    152 
    153 /*===========================================================================
    154 
    155   FUNCTION:   msg_q_destroy
    156 
    157   ===========================================================================*/
    158 msq_q_err_type msg_q_destroy(void** msg_q_data)
    159 {
    160    if( msg_q_data == NULL )
    161    {
    162       LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
    163       return eMSG_Q_INVALID_HANDLE;
    164    }
    165 
    166    msg_q* p_msg_q = (msg_q*)*msg_q_data;
    167 
    168    linked_list_destroy(&p_msg_q->msg_list);
    169    pthread_mutex_destroy(&p_msg_q->list_mutex);
    170    pthread_cond_destroy(&p_msg_q->list_cond);
    171 
    172    p_msg_q->unblocked = 0;
    173 
    174    free(*msg_q_data);
    175    *msg_q_data = NULL;
    176 
    177    return eMSG_Q_SUCCESS;
    178 }
    179 
    180 /*===========================================================================
    181 
    182   FUNCTION:   msg_q_snd
    183 
    184   ===========================================================================*/
    185 msq_q_err_type msg_q_snd(void* msg_q_data, void* msg_obj, void (*dealloc)(void*))
    186 {
    187    msq_q_err_type rv;
    188    if( msg_q_data == NULL )
    189    {
    190       LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
    191       return eMSG_Q_INVALID_HANDLE;
    192    }
    193    if( msg_obj == NULL )
    194    {
    195       LOC_LOGE("%s: Invalid msg_obj parameter!\n", __FUNCTION__);
    196       return eMSG_Q_INVALID_PARAMETER;
    197    }
    198 
    199    msg_q* p_msg_q = (msg_q*)msg_q_data;
    200 
    201    pthread_mutex_lock(&p_msg_q->list_mutex);
    202    LOC_LOGV("%s: Sending message with handle = 0x%08X\n", __FUNCTION__, msg_obj);
    203 
    204    if( p_msg_q->unblocked )
    205    {
    206       LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
    207       pthread_mutex_unlock(&p_msg_q->list_mutex);
    208       return eMSG_Q_UNAVAILABLE_RESOURCE;
    209    }
    210 
    211    rv = convert_linked_list_err_type(linked_list_add(p_msg_q->msg_list, msg_obj, dealloc));
    212 
    213    /* Show data is in the message queue. */
    214    pthread_cond_signal(&p_msg_q->list_cond);
    215 
    216    pthread_mutex_unlock(&p_msg_q->list_mutex);
    217 
    218    LOC_LOGV("%s: Finished Sending message with handle = 0x%08X\n", __FUNCTION__, msg_obj);
    219 
    220    return rv;
    221 }
    222 
    223 /*===========================================================================
    224 
    225   FUNCTION:   msg_q_rcv
    226 
    227   ===========================================================================*/
    228 msq_q_err_type msg_q_rcv(void* msg_q_data, void** msg_obj)
    229 {
    230    msq_q_err_type rv;
    231    if( msg_q_data == NULL )
    232    {
    233       LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
    234       return eMSG_Q_INVALID_HANDLE;
    235    }
    236 
    237    if( msg_obj == NULL )
    238    {
    239       LOC_LOGE("%s: Invalid msg_obj parameter!\n", __FUNCTION__);
    240       return eMSG_Q_INVALID_PARAMETER;
    241    }
    242 
    243    msg_q* p_msg_q = (msg_q*)msg_q_data;
    244 
    245    LOC_LOGV("%s: Waiting on message\n", __FUNCTION__);
    246 
    247    pthread_mutex_lock(&p_msg_q->list_mutex);
    248 
    249    if( p_msg_q->unblocked )
    250    {
    251       LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
    252       pthread_mutex_unlock(&p_msg_q->list_mutex);
    253       return eMSG_Q_UNAVAILABLE_RESOURCE;
    254    }
    255 
    256    /* Wait for data in the message queue */
    257    while( linked_list_empty(p_msg_q->msg_list) && !p_msg_q->unblocked )
    258    {
    259       pthread_cond_wait(&p_msg_q->list_cond, &p_msg_q->list_mutex);
    260    }
    261 
    262    rv = convert_linked_list_err_type(linked_list_remove(p_msg_q->msg_list, msg_obj));
    263 
    264    pthread_mutex_unlock(&p_msg_q->list_mutex);
    265 
    266    LOC_LOGV("%s: Received message 0x%08X rv = %d\n", __FUNCTION__, *msg_obj, rv);
    267 
    268    return rv;
    269 }
    270 
    271 /*===========================================================================
    272 
    273   FUNCTION:   msg_q_flush
    274 
    275   ===========================================================================*/
    276 msq_q_err_type msg_q_flush(void* msg_q_data)
    277 {
    278    msq_q_err_type rv;
    279    if ( msg_q_data == NULL )
    280    {
    281       LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
    282       return eMSG_Q_INVALID_HANDLE;
    283    }
    284 
    285    msg_q* p_msg_q = (msg_q*)msg_q_data;
    286 
    287    LOC_LOGD("%s: Flushing Message Queue\n", __FUNCTION__);
    288 
    289    pthread_mutex_lock(&p_msg_q->list_mutex);
    290 
    291    /* Remove all elements from the list */
    292    rv = convert_linked_list_err_type(linked_list_flush(p_msg_q->msg_list));
    293 
    294    pthread_mutex_unlock(&p_msg_q->list_mutex);
    295 
    296    LOC_LOGD("%s: Message Queue flushed\n", __FUNCTION__);
    297 
    298    return rv;
    299 }
    300 
    301 /*===========================================================================
    302 
    303   FUNCTION:   msg_q_unblock
    304 
    305   ===========================================================================*/
    306 msq_q_err_type msg_q_unblock(void* msg_q_data)
    307 {
    308    if ( msg_q_data == NULL )
    309    {
    310       LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
    311       return eMSG_Q_INVALID_HANDLE;
    312    }
    313 
    314    msg_q* p_msg_q = (msg_q*)msg_q_data;
    315    pthread_mutex_lock(&p_msg_q->list_mutex);
    316 
    317    if( p_msg_q->unblocked )
    318    {
    319       LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
    320       pthread_mutex_unlock(&p_msg_q->list_mutex);
    321       return eMSG_Q_UNAVAILABLE_RESOURCE;
    322    }
    323 
    324    LOC_LOGD("%s: Unblocking Message Queue\n", __FUNCTION__);
    325    /* Unblocking message queue */
    326    p_msg_q->unblocked = 1;
    327 
    328    /* Allow all the waiters to wake up */
    329    pthread_cond_broadcast(&p_msg_q->list_cond);
    330 
    331    pthread_mutex_unlock(&p_msg_q->list_mutex);
    332 
    333    LOC_LOGD("%s: Message Queue unblocked\n", __FUNCTION__);
    334 
    335    return eMSG_Q_SUCCESS;
    336 }
    337