Home | History | Annotate | Download | only in utils
      1 /* Copyright (c) 2011-2012, 2014, 2017 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 <platform_lib_includes.h>
     33 #include "linked_list.h"
     34 #include <stdio.h>
     35 #include <stdlib.h>
     36 #include <pthread.h>
     37 
     38 typedef struct msg_q {
     39    void* msg_list;                  /* Linked list to store information */
     40    pthread_cond_t  list_cond;       /* Condition variable for waiting on msg queue */
     41    pthread_mutex_t list_mutex;      /* Mutex for exclusive access to message queue */
     42    int unblocked;                   /* Has this message queue been unblocked? */
     43 } msg_q;
     44 
     45 /*===========================================================================
     46 FUNCTION    convert_linked_list_err_type
     47 
     48 DESCRIPTION
     49    Converts from one set of enum values to another.
     50 
     51    linked_list_val: Value to convert to msg_q_enum_type
     52 
     53 DEPENDENCIES
     54    N/A
     55 
     56 RETURN VALUE
     57    Corresponding linked_list_enum_type in msg_q_enum_type
     58 
     59 SIDE EFFECTS
     60    N/A
     61 
     62 ===========================================================================*/
     63 static msq_q_err_type convert_linked_list_err_type(linked_list_err_type linked_list_val)
     64 {
     65    switch( linked_list_val )
     66    {
     67    case eLINKED_LIST_SUCCESS:
     68       return eMSG_Q_SUCCESS;
     69    case eLINKED_LIST_INVALID_PARAMETER:
     70       return eMSG_Q_INVALID_PARAMETER;
     71    case eLINKED_LIST_INVALID_HANDLE:
     72       return eMSG_Q_INVALID_HANDLE;
     73    case eLINKED_LIST_UNAVAILABLE_RESOURCE:
     74       return eMSG_Q_UNAVAILABLE_RESOURCE;
     75    case eLINKED_LIST_INSUFFICIENT_BUFFER:
     76       return eMSG_Q_INSUFFICIENT_BUFFER;
     77 
     78    case eLINKED_LIST_FAILURE_GENERAL:
     79    default:
     80       return eMSG_Q_FAILURE_GENERAL;
     81    }
     82 }
     83 
     84 /* ----------------------- END INTERNAL FUNCTIONS ---------------------------------------- */
     85 
     86 /*===========================================================================
     87 
     88   FUNCTION:   msg_q_init
     89 
     90   ===========================================================================*/
     91 msq_q_err_type msg_q_init(void** msg_q_data)
     92 {
     93    if( msg_q_data == NULL )
     94    {
     95       LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
     96       return eMSG_Q_INVALID_PARAMETER;
     97    }
     98 
     99    msg_q* tmp_msg_q;
    100    tmp_msg_q = (msg_q*)calloc(1, sizeof(msg_q));
    101    if( tmp_msg_q == NULL )
    102    {
    103       LOC_LOGE("%s: Unable to allocate space for message queue!\n", __FUNCTION__);
    104       return eMSG_Q_FAILURE_GENERAL;
    105    }
    106 
    107    if( linked_list_init(&tmp_msg_q->msg_list) != 0 )
    108    {
    109       LOC_LOGE("%s: Unable to initialize storage list!\n", __FUNCTION__);
    110       free(tmp_msg_q);
    111       return eMSG_Q_FAILURE_GENERAL;
    112    }
    113 
    114    if( pthread_mutex_init(&tmp_msg_q->list_mutex, NULL) != 0 )
    115    {
    116       LOC_LOGE("%s: Unable to initialize list mutex!\n", __FUNCTION__);
    117       linked_list_destroy(&tmp_msg_q->msg_list);
    118       free(tmp_msg_q);
    119       return eMSG_Q_FAILURE_GENERAL;
    120    }
    121 
    122    if( pthread_cond_init(&tmp_msg_q->list_cond, NULL) != 0 )
    123    {
    124       LOC_LOGE("%s: Unable to initialize msg q cond var!\n", __FUNCTION__);
    125       linked_list_destroy(&tmp_msg_q->msg_list);
    126       pthread_mutex_destroy(&tmp_msg_q->list_mutex);
    127       free(tmp_msg_q);
    128       return eMSG_Q_FAILURE_GENERAL;
    129    }
    130 
    131    tmp_msg_q->unblocked = 0;
    132 
    133    *msg_q_data = tmp_msg_q;
    134 
    135    return eMSG_Q_SUCCESS;
    136 }
    137 
    138 /*===========================================================================
    139 
    140   FUNCTION:   msg_q_init2
    141 
    142   ===========================================================================*/
    143 const void* msg_q_init2()
    144 {
    145   void* q = NULL;
    146   if (eMSG_Q_SUCCESS != msg_q_init(&q)) {
    147     q = NULL;
    148   }
    149   return q;
    150 }
    151 
    152 /*===========================================================================
    153 
    154   FUNCTION:   msg_q_destroy
    155 
    156   ===========================================================================*/
    157 msq_q_err_type msg_q_destroy(void** msg_q_data)
    158 {
    159    if( msg_q_data == NULL )
    160    {
    161       LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
    162       return eMSG_Q_INVALID_HANDLE;
    163    }
    164 
    165    msg_q* p_msg_q = (msg_q*)*msg_q_data;
    166 
    167    linked_list_destroy(&p_msg_q->msg_list);
    168    pthread_mutex_destroy(&p_msg_q->list_mutex);
    169    pthread_cond_destroy(&p_msg_q->list_cond);
    170 
    171    p_msg_q->unblocked = 0;
    172 
    173    free(*msg_q_data);
    174    *msg_q_data = NULL;
    175 
    176    return eMSG_Q_SUCCESS;
    177 }
    178 
    179 /*===========================================================================
    180 
    181   FUNCTION:   msg_q_snd
    182 
    183   ===========================================================================*/
    184 msq_q_err_type msg_q_snd(void* msg_q_data, void* msg_obj, void (*dealloc)(void*))
    185 {
    186    msq_q_err_type rv;
    187    if( msg_q_data == NULL )
    188    {
    189       LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
    190       return eMSG_Q_INVALID_HANDLE;
    191    }
    192    if( msg_obj == NULL )
    193    {
    194       LOC_LOGE("%s: Invalid msg_obj parameter!\n", __FUNCTION__);
    195       return eMSG_Q_INVALID_PARAMETER;
    196    }
    197 
    198    msg_q* p_msg_q = (msg_q*)msg_q_data;
    199 
    200    pthread_mutex_lock(&p_msg_q->list_mutex);
    201    //LOC_LOGV("%s: Sending message with handle = 0x%08X\n", __FUNCTION__, msg_obj);
    202 
    203    if( p_msg_q->unblocked )
    204    {
    205       LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
    206       pthread_mutex_unlock(&p_msg_q->list_mutex);
    207       return eMSG_Q_UNAVAILABLE_RESOURCE;
    208    }
    209 
    210    rv = convert_linked_list_err_type(linked_list_add(p_msg_q->msg_list, msg_obj, dealloc));
    211 
    212    /* Show data is in the message queue. */
    213    pthread_cond_signal(&p_msg_q->list_cond);
    214 
    215    pthread_mutex_unlock(&p_msg_q->list_mutex);
    216 
    217    //LOC_LOGV("%s: Finished Sending message with handle = 0x%08X\n", __FUNCTION__, msg_obj);
    218 
    219    return rv;
    220 }
    221 
    222 /*===========================================================================
    223 
    224   FUNCTION:   msg_q_rcv
    225 
    226   ===========================================================================*/
    227 msq_q_err_type msg_q_rcv(void* msg_q_data, void** msg_obj)
    228 {
    229    msq_q_err_type rv;
    230    if( msg_q_data == NULL )
    231    {
    232       LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
    233       return eMSG_Q_INVALID_HANDLE;
    234    }
    235 
    236    if( msg_obj == NULL )
    237    {
    238       LOC_LOGE("%s: Invalid msg_obj parameter!\n", __FUNCTION__);
    239       return eMSG_Q_INVALID_PARAMETER;
    240    }
    241 
    242    msg_q* p_msg_q = (msg_q*)msg_q_data;
    243 
    244    //LOC_LOGV("%s: Waiting on message\n", __FUNCTION__);
    245 
    246    pthread_mutex_lock(&p_msg_q->list_mutex);
    247 
    248    if( p_msg_q->unblocked )
    249    {
    250       LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
    251       pthread_mutex_unlock(&p_msg_q->list_mutex);
    252       return eMSG_Q_UNAVAILABLE_RESOURCE;
    253    }
    254 
    255    /* Wait for data in the message queue */
    256    while( linked_list_empty(p_msg_q->msg_list) && !p_msg_q->unblocked )
    257    {
    258       pthread_cond_wait(&p_msg_q->list_cond, &p_msg_q->list_mutex);
    259    }
    260 
    261    rv = convert_linked_list_err_type(linked_list_remove(p_msg_q->msg_list, msg_obj));
    262 
    263    pthread_mutex_unlock(&p_msg_q->list_mutex);
    264 
    265    //LOC_LOGV("%s: Received message 0x%08X rv = %d\n", __FUNCTION__, *msg_obj, rv);
    266 
    267    return rv;
    268 }
    269 
    270 /*===========================================================================
    271 
    272   FUNCTION:   msg_q_flush
    273 
    274   ===========================================================================*/
    275 msq_q_err_type msg_q_flush(void* msg_q_data)
    276 {
    277    msq_q_err_type rv;
    278    if ( msg_q_data == NULL )
    279    {
    280       LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
    281       return eMSG_Q_INVALID_HANDLE;
    282    }
    283 
    284    msg_q* p_msg_q = (msg_q*)msg_q_data;
    285 
    286    LOC_LOGD("%s: Flushing Message Queue\n", __FUNCTION__);
    287 
    288    pthread_mutex_lock(&p_msg_q->list_mutex);
    289 
    290    /* Remove all elements from the list */
    291    rv = convert_linked_list_err_type(linked_list_flush(p_msg_q->msg_list));
    292 
    293    pthread_mutex_unlock(&p_msg_q->list_mutex);
    294 
    295    LOC_LOGD("%s: Message Queue flushed\n", __FUNCTION__);
    296 
    297    return rv;
    298 }
    299 
    300 /*===========================================================================
    301 
    302   FUNCTION:   msg_q_unblock
    303 
    304   ===========================================================================*/
    305 msq_q_err_type msg_q_unblock(void* msg_q_data)
    306 {
    307    if ( msg_q_data == NULL )
    308    {
    309       LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
    310       return eMSG_Q_INVALID_HANDLE;
    311    }
    312 
    313    msg_q* p_msg_q = (msg_q*)msg_q_data;
    314    pthread_mutex_lock(&p_msg_q->list_mutex);
    315 
    316    if( p_msg_q->unblocked )
    317    {
    318       LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
    319       pthread_mutex_unlock(&p_msg_q->list_mutex);
    320       return eMSG_Q_UNAVAILABLE_RESOURCE;
    321    }
    322 
    323    LOC_LOGD("%s: Unblocking Message Queue\n", __FUNCTION__);
    324    /* Unblocking message queue */
    325    p_msg_q->unblocked = 1;
    326 
    327    /* Allow all the waiters to wake up */
    328    pthread_cond_broadcast(&p_msg_q->list_cond);
    329 
    330    pthread_mutex_unlock(&p_msg_q->list_mutex);
    331 
    332    LOC_LOGD("%s: Message Queue unblocked\n", __FUNCTION__);
    333 
    334    return eMSG_Q_SUCCESS;
    335 }
    336