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    pthread_mutex_lock(&p_msg_q->list_mutex);
    245 
    246    if( p_msg_q->unblocked )
    247    {
    248       LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
    249       pthread_mutex_unlock(&p_msg_q->list_mutex);
    250       return eMSG_Q_UNAVAILABLE_RESOURCE;
    251    }
    252 
    253    /* Wait for data in the message queue */
    254    while( linked_list_empty(p_msg_q->msg_list) && !p_msg_q->unblocked )
    255    {
    256       pthread_cond_wait(&p_msg_q->list_cond, &p_msg_q->list_mutex);
    257    }
    258 
    259    rv = convert_linked_list_err_type(linked_list_remove(p_msg_q->msg_list, msg_obj));
    260 
    261    pthread_mutex_unlock(&p_msg_q->list_mutex);
    262 
    263    LOC_LOGV("%s: Received message 0x%08X rv = %d\n", __FUNCTION__, *msg_obj, rv);
    264 
    265    return rv;
    266 }
    267 
    268 /*===========================================================================
    269 
    270   FUNCTION:   msg_q_flush
    271 
    272   ===========================================================================*/
    273 msq_q_err_type msg_q_flush(void* msg_q_data)
    274 {
    275    msq_q_err_type rv;
    276    if ( msg_q_data == NULL )
    277    {
    278       LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
    279       return eMSG_Q_INVALID_HANDLE;
    280    }
    281 
    282    msg_q* p_msg_q = (msg_q*)msg_q_data;
    283 
    284    LOC_LOGD("%s: Flushing Message Queue\n", __FUNCTION__);
    285 
    286    pthread_mutex_lock(&p_msg_q->list_mutex);
    287 
    288    /* Remove all elements from the list */
    289    rv = convert_linked_list_err_type(linked_list_flush(p_msg_q->msg_list));
    290 
    291    pthread_mutex_unlock(&p_msg_q->list_mutex);
    292 
    293    LOC_LOGD("%s: Message Queue flushed\n", __FUNCTION__);
    294 
    295    return rv;
    296 }
    297 
    298 /*===========================================================================
    299 
    300   FUNCTION:   msg_q_unblock
    301 
    302   ===========================================================================*/
    303 msq_q_err_type msg_q_unblock(void* msg_q_data)
    304 {
    305    if ( msg_q_data == NULL )
    306    {
    307       LOC_LOGE("%s: Invalid msg_q_data parameter!\n", __FUNCTION__);
    308       return eMSG_Q_INVALID_HANDLE;
    309    }
    310 
    311    msg_q* p_msg_q = (msg_q*)msg_q_data;
    312    pthread_mutex_lock(&p_msg_q->list_mutex);
    313 
    314    if( p_msg_q->unblocked )
    315    {
    316       LOC_LOGE("%s: Message queue has been unblocked.\n", __FUNCTION__);
    317       pthread_mutex_unlock(&p_msg_q->list_mutex);
    318       return eMSG_Q_UNAVAILABLE_RESOURCE;
    319    }
    320 
    321    LOC_LOGD("%s: Unblocking Message Queue\n", __FUNCTION__);
    322    /* Unblocking message queue */
    323    p_msg_q->unblocked = 1;
    324 
    325    /* Allow all the waiters to wake up */
    326    pthread_cond_broadcast(&p_msg_q->list_cond);
    327 
    328    pthread_mutex_unlock(&p_msg_q->list_mutex);
    329 
    330    LOC_LOGD("%s: Message Queue unblocked\n", __FUNCTION__);
    331 
    332    return eMSG_Q_SUCCESS;
    333 }
    334