Home | History | Annotate | Download | only in loc_api_v02
      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 #include <stdio.h>
     29 #include <assert.h>
     30 #include <errno.h>
     31 #include <sys/time.h>
     32 #include <string.h>
     33 #include <pthread.h>
     34 #include <stdbool.h>
     35 #include <stdint.h>
     36 #include <loc_cfg.h>
     37 #include "loc_api_v02_client.h"
     38 #include "loc_api_sync_req.h"
     39 
     40 /* Logging */
     41 // Uncomment to log verbose logs
     42 #define LOG_NDEBUG 1
     43 
     44 // log debug logs
     45 #define LOG_NDDEBUG 1
     46 #define LOG_TAG "LocSvc_api_v02"
     47 #include "loc_util_log.h"
     48 
     49 #define LOC_SYNC_REQ_BUFFER_SIZE 8
     50 #define GPS_CONF_FILE "/etc/gps.conf"
     51 pthread_mutex_t  loc_sync_call_mutex = PTHREAD_MUTEX_INITIALIZER;
     52 
     53 static bool loc_sync_call_initialized = false;
     54 
     55 typedef struct {
     56    pthread_mutex_t         sync_req_lock;
     57 
     58    /* Client ID */
     59    locClientHandleType     client_handle;
     60 
     61    /*  waiting conditional variable */
     62    pthread_cond_t          ind_arrived_cond;
     63 
     64    /* Callback waiting data block, protected by loc_cb_data_mutex */
     65    bool                    ind_is_selected;              /* is cb selected? */
     66    bool                    ind_is_waiting;               /* is waiting?     */
     67    bool                    ind_has_arrived;              /* callback has arrived */
     68    uint32_t                req_id;                    /*  sync request */
     69    void                    *recv_ind_payload_ptr; /* received  payload */
     70    uint32_t                recv_ind_id;      /* received  ind   */
     71 
     72 } loc_sync_req_data_s_type;
     73 
     74 typedef struct {
     75    bool                        in_use;  /* at least one sync call is active */
     76    bool                        slot_in_use[LOC_SYNC_REQ_BUFFER_SIZE];
     77    loc_sync_req_data_s_type    slots[LOC_SYNC_REQ_BUFFER_SIZE];
     78 } loc_sync_req_array_s_type;
     79 
     80 /***************************************************************************
     81  *                 DATA FOR ASYNCHRONOUS RPC PROCESSING
     82  **************************************************************************/
     83 loc_sync_req_array_s_type loc_sync_array;
     84 
     85 /*===========================================================================
     86 
     87 FUNCTION   loc_sync_req_init
     88 
     89 DESCRIPTION
     90    Initialize this module
     91 
     92 DEPENDENCIES
     93    N/A
     94 
     95 RETURN VALUE
     96    none
     97 
     98 SIDE EFFECTS
     99    N/A
    100 
    101 ===========================================================================*/
    102 void loc_sync_req_init()
    103 {
    104    LOC_LOGV(" %s:%d]:\n", __func__, __LINE__);
    105    UTIL_READ_CONF_DEFAULT(GPS_CONF_FILE);
    106    pthread_mutex_lock(&loc_sync_call_mutex);
    107    if(true == loc_sync_call_initialized)
    108    {
    109       LOC_LOGD("%s:%d]:already initialized\n", __func__, __LINE__);
    110       pthread_mutex_unlock(&loc_sync_call_mutex);
    111       return;
    112    }
    113 
    114    loc_sync_array.in_use = false;
    115 
    116    memset(loc_sync_array.slot_in_use, 0, sizeof(loc_sync_array.slot_in_use));
    117 
    118    int i;
    119    for (i = 0; i < LOC_SYNC_REQ_BUFFER_SIZE; i++)
    120    {
    121       loc_sync_req_data_s_type *slot = &loc_sync_array.slots[i];
    122 
    123       pthread_mutex_init(&slot->sync_req_lock, NULL);
    124       pthread_cond_init(&slot->ind_arrived_cond, NULL);
    125 
    126       slot->client_handle = LOC_CLIENT_INVALID_HANDLE_VALUE;
    127       slot->ind_is_selected = false;       /* is ind selected? */
    128       slot->ind_is_waiting  = false;       /* is waiting?     */
    129       slot->ind_has_arrived = false;       /* callback has arrived */
    130       slot->recv_ind_id = 0;       /* ind to wait for   */
    131       slot->recv_ind_payload_ptr = NULL;
    132       slot->req_id =  0;   /* req id   */
    133    }
    134 
    135    loc_sync_call_initialized = true;
    136    pthread_mutex_unlock(&loc_sync_call_mutex);
    137 }
    138 
    139 
    140 /*===========================================================================
    141 
    142 FUNCTION    loc_sync_process_ind
    143 
    144 DESCRIPTION
    145    Wakes up blocked API calls to check if the needed callback has arrived
    146 
    147 DEPENDENCIES
    148    N/A
    149 
    150 RETURN VALUE
    151    none
    152 
    153 SIDE EFFECTS
    154    N/A
    155 
    156 ===========================================================================*/
    157 void loc_sync_process_ind(
    158       locClientHandleType    client_handle, /* handle of the client */
    159       uint32_t               ind_id ,      /* ind id */
    160       void                   *ind_payload_ptr /* payload              */
    161 )
    162 {
    163 
    164    LOC_LOGV("%s:%d]: received indication, handle = %p ind_id = %u \n",
    165                  __func__,__LINE__, client_handle, ind_id);
    166 
    167    pthread_mutex_lock(&loc_sync_call_mutex);
    168 
    169    if (!loc_sync_array.in_use)
    170    {
    171       LOC_LOGD("%s:%d]: loc_sync_array not in use \n",
    172                     __func__, __LINE__);
    173       pthread_mutex_unlock(&loc_sync_call_mutex);
    174       return;
    175    }
    176 
    177    bool in_use = false, consumed = false;
    178    int i;
    179 
    180    for (i = 0; i < LOC_SYNC_REQ_BUFFER_SIZE && !consumed; i++)
    181    {
    182       loc_sync_req_data_s_type *slot = &loc_sync_array.slots[i];
    183 
    184       in_use |= loc_sync_array.slot_in_use[i];
    185 
    186       pthread_mutex_lock(&slot->sync_req_lock);
    187 
    188       if ( (loc_sync_array.slot_in_use[i]) && (slot->client_handle == client_handle)
    189             && (ind_id == slot->recv_ind_id) && (!slot->ind_has_arrived))
    190       {
    191          // copy the payload to the slot waiting for this ind
    192          size_t payload_size = 0;
    193 
    194          LOC_LOGV("%s:%d]: found slot %d selected for ind %u \n",
    195                        __func__, __LINE__, i, ind_id);
    196 
    197          if(true == locClientGetSizeByRespIndId(ind_id, &payload_size) &&
    198             NULL != slot->recv_ind_payload_ptr && NULL != ind_payload_ptr)
    199          {
    200             LOC_LOGV("%s:%d]: copying ind payload size = %u \n",
    201                           __func__, __LINE__, payload_size);
    202 
    203             memcpy(slot->recv_ind_payload_ptr, ind_payload_ptr, payload_size);
    204 
    205             consumed = true;
    206 
    207          }
    208          /* Received a callback while waiting, wake up thread to check it */
    209          if (slot->ind_is_waiting)
    210          {
    211             slot->recv_ind_id = ind_id;
    212 
    213             pthread_cond_signal(&slot->ind_arrived_cond);
    214          }
    215          else
    216          {
    217             /* If callback arrives before wait, remember it */
    218             LOC_LOGV("%s:%d]: ind %u arrived before wait was called \n",
    219                           __func__, __LINE__, ind_id);
    220 
    221             slot->ind_has_arrived = true;
    222          }
    223       }
    224       pthread_mutex_unlock(&slot->sync_req_lock);
    225    }
    226 
    227    if (!in_use) {
    228       loc_sync_array.in_use = false;
    229    }
    230 
    231    pthread_mutex_unlock(&loc_sync_call_mutex);
    232 }
    233 
    234 /*===========================================================================
    235 
    236 FUNCTION    loc_alloc_slot
    237 
    238 DESCRIPTION
    239    Allocates a buffer slot for the synchronous API call
    240 
    241 DEPENDENCIES
    242    N/A
    243 
    244 RETURN VALUE
    245    Select ID (>=0)     : successful
    246    -1                  : buffer full
    247 
    248 SIDE EFFECTS
    249    N/A
    250 
    251 ===========================================================================*/
    252 static int loc_alloc_slot()
    253 {
    254    int i, select_id = -1; /* no free buffer */
    255 
    256    pthread_mutex_lock(&loc_sync_call_mutex);
    257 
    258    for (i = 0; i < LOC_SYNC_REQ_BUFFER_SIZE; i++)
    259    {
    260       if (!loc_sync_array.slot_in_use[i])
    261       {
    262          select_id = i;
    263          loc_sync_array.slot_in_use[i] = 1;
    264          loc_sync_array.in_use = true;
    265          break;
    266       }
    267    }
    268 
    269    pthread_mutex_unlock(&loc_sync_call_mutex);
    270    LOC_LOGV("%s:%d]: returning slot %d\n",
    271                  __func__, __LINE__, select_id);
    272    return select_id;
    273 }
    274 
    275 /*===========================================================================
    276 
    277 FUNCTION    loc_free_slot
    278 
    279 DESCRIPTION
    280    Frees a buffer slot after the synchronous API call
    281 
    282 DEPENDENCIES
    283    N/A
    284 
    285 RETURN VALUE
    286    None
    287 
    288 SIDE EFFECTS
    289    N/A
    290 
    291 ===========================================================================*/
    292 static void loc_free_slot(int select_id)
    293 {
    294    int i;
    295    loc_sync_req_data_s_type *slot;
    296 
    297    pthread_mutex_lock(&loc_sync_call_mutex);
    298 
    299    LOC_LOGD("%s:%d]: freeing slot %d\n", __func__, __LINE__, select_id);
    300 
    301    loc_sync_array.slot_in_use[select_id] = 0;
    302 
    303    slot = &loc_sync_array.slots[select_id];
    304 
    305    slot->client_handle = LOC_CLIENT_INVALID_HANDLE_VALUE;
    306    slot->ind_is_selected = false;       /* is ind selected? */
    307    slot->ind_is_waiting  = false;       /* is waiting?     */
    308    slot->ind_has_arrived = false;       /* callback has arrived */
    309    slot->recv_ind_id = 0;       /* ind to wait for   */
    310    slot->recv_ind_payload_ptr = NULL;
    311    slot->req_id =  0;
    312 
    313    // check if all slots are now free
    314    for (i = 0; i < LOC_SYNC_REQ_BUFFER_SIZE; i++)
    315    {
    316       if (loc_sync_array.slot_in_use[i]) break;
    317    }
    318 
    319    if (i >= LOC_SYNC_REQ_BUFFER_SIZE)
    320    {
    321       loc_sync_array.in_use = false;
    322    }
    323 
    324    pthread_mutex_unlock(&loc_sync_call_mutex);
    325 }
    326 
    327 /*===========================================================================
    328 
    329 FUNCTION    loc_sync_select_ind
    330 
    331 DESCRIPTION
    332    Selects which indication to wait for.
    333 
    334 
    335 DEPENDENCIES
    336    N/A
    337 
    338 RETURN VALUE
    339    Select ID (>=0)     : successful
    340    -ENOMEM                  : out of buffer
    341 
    342 SIDE EFFECTS
    343    N/A
    344 
    345 ===========================================================================*/
    346 static int loc_sync_select_ind(
    347       locClientHandleType       client_handle,   /* Client handle */
    348       uint32_t                  ind_id,  /* ind Id wait for */
    349       uint32_t                  req_id,   /* req id */
    350       void *                    ind_payload_ptr /* ptr where payload should be copied to*/
    351 )
    352 {
    353    int select_id = loc_alloc_slot();
    354 
    355    LOC_LOGV("%s:%d]: client handle %p, ind_id %u, req_id %u \n",
    356                  __func__, __LINE__, client_handle, ind_id, req_id);
    357 
    358    if (select_id < 0)
    359    {
    360       LOC_LOGE("%s:%d]: buffer full for this synchronous req %s \n",
    361                  __func__, __LINE__, loc_get_v02_event_name(req_id));
    362       return -ENOMEM;
    363    }
    364 
    365    loc_sync_req_data_s_type *slot = &loc_sync_array.slots[select_id];
    366 
    367    pthread_mutex_lock(&slot->sync_req_lock);
    368 
    369    slot->client_handle = client_handle;
    370    slot->ind_is_selected = true;
    371    slot->ind_is_waiting = false;
    372    slot->ind_has_arrived = false;
    373 
    374    slot->recv_ind_id = ind_id;
    375    slot->req_id      = req_id;
    376    slot->recv_ind_payload_ptr = ind_payload_ptr; //store the payload ptr
    377 
    378    pthread_mutex_unlock(&slot->sync_req_lock);
    379 
    380    return select_id;
    381 }
    382 
    383 
    384 /*===========================================================================
    385 
    386 FUNCTION    loc_sync_wait_for_ind
    387 
    388 DESCRIPTION
    389    Waits for a selected indication. The wait expires in timeout_seconds seconds.
    390    If the function is called before an existing wait has finished, it will
    391    immediately return error.
    392 
    393 DEPENDENCIES
    394    N/A
    395 
    396 RETURN VALUE
    397   0 on SUCCESS, -ve value on failure
    398 
    399 SIDE EFFECTS
    400    N/A
    401 
    402 ===========================================================================*/
    403 static int loc_sync_wait_for_ind(
    404       int select_id,        /* ID from loc_sync_select_ind() */
    405       int timeout_seconds,  /* Timeout in this number of seconds  */
    406       uint32_t ind_id
    407 )
    408 {
    409    if (select_id < 0 || select_id >= LOC_SYNC_REQ_BUFFER_SIZE || !loc_sync_array.slot_in_use[select_id])
    410    {
    411       LOC_LOGE("%s:%d]: invalid select_id: %d \n",
    412                     __func__, __LINE__, select_id);
    413 
    414       return (-EINVAL);
    415    }
    416 
    417    loc_sync_req_data_s_type *slot = &loc_sync_array.slots[select_id];
    418 
    419    int ret_val = 0;  /* the return value of this function: 0 = no error */
    420    int rc;          /* return code from pthread calls */
    421 
    422    struct timeval present_time;
    423    struct timespec expire_time;
    424 
    425    pthread_mutex_lock(&slot->sync_req_lock);
    426 
    427   do
    428   {
    429       if (slot->ind_has_arrived)
    430       {
    431          ret_val = 0;    /* success */
    432          break;
    433       }
    434 
    435       if (slot->ind_is_waiting)
    436       {
    437          LOC_LOGW("%s:%d]: already waiting in this slot %d\n", __func__,
    438                        __LINE__, select_id);
    439          ret_val = -EBUSY; // busy
    440          break;
    441       }
    442 
    443       /* Calculate absolute expire time */
    444       gettimeofday(&present_time, NULL);
    445       expire_time.tv_sec  = present_time.tv_sec;
    446       expire_time.tv_nsec = present_time.tv_usec * 1000;
    447       expire_time.tv_sec += timeout_seconds;
    448 
    449       /* Take new wait request */
    450       slot->ind_is_waiting = true;
    451 
    452       /* Waiting */
    453       rc = pthread_cond_timedwait(&slot->ind_arrived_cond,
    454             &slot->sync_req_lock, &expire_time);
    455 
    456       slot->ind_is_waiting = false;
    457 
    458       if(rc == ETIMEDOUT)
    459       {
    460          LOC_LOGE("%s:%d]: slot %d, timed out for ind_id %s\n",
    461                     __func__, __LINE__, select_id, loc_get_v02_event_name(ind_id));
    462          ret_val = -ETIMEDOUT; //time out
    463       }
    464 
    465   } while (0);
    466 
    467    pthread_mutex_unlock(&slot->sync_req_lock);
    468    loc_free_slot(select_id);
    469 
    470    return ret_val;
    471 }
    472 
    473 /*===========================================================================
    474 
    475 FUNCTION    loc_sync_send_req
    476 
    477 DESCRIPTION
    478    Synchronous req call (thread safe)
    479 
    480 DEPENDENCIES
    481    N/A
    482 
    483 RETURN VALUE
    484    Loc API 2.0 status
    485 
    486 SIDE EFFECTS
    487    N/A
    488 
    489 ===========================================================================*/
    490 locClientStatusEnumType loc_sync_send_req
    491 (
    492       locClientHandleType       client_handle,
    493       uint32_t                  req_id,        /* req id */
    494       locClientReqUnionType     req_payload,
    495       uint32_t                  timeout_msec,
    496       uint32_t                  ind_id,  //ind ID to block for, usually the same as req_id */
    497       void                      *ind_payload_ptr /* can be NULL*/
    498 )
    499 {
    500    locClientStatusEnumType status = eLOC_CLIENT_SUCCESS ;
    501    int select_id;
    502    int rc = 0;
    503 
    504    // Select the callback we are waiting for
    505    select_id = loc_sync_select_ind(client_handle, ind_id, req_id,
    506                                    ind_payload_ptr);
    507 
    508    if (select_id >= 0)
    509    {
    510       status =  locClientSendReq (client_handle, req_id, req_payload);
    511       LOC_LOGV("%s:%d]: select_id = %d,locClientSendReq returned %d\n",
    512                     __func__, __LINE__, select_id, status);
    513 
    514       if (status != eLOC_CLIENT_SUCCESS )
    515       {
    516          loc_free_slot(select_id);
    517       }
    518       else
    519       {
    520          // Wait for the indication callback
    521          if (( rc = loc_sync_wait_for_ind( select_id,
    522                                            timeout_msec / 1000,
    523                                            ind_id) ) < 0)
    524          {
    525             if ( rc == -ETIMEDOUT)
    526                status = eLOC_CLIENT_FAILURE_TIMEOUT;
    527             else
    528                status = eLOC_CLIENT_FAILURE_INTERNAL;
    529 
    530             // Callback waiting failed
    531             LOC_LOGE("%s:%d]: loc_api_wait_for_ind failed, err %d, "
    532                      "select id %d, status %s", __func__, __LINE__, rc ,
    533                      select_id, loc_get_v02_client_status_name(status));
    534          }
    535          else
    536          {
    537             status =  eLOC_CLIENT_SUCCESS;
    538             LOC_LOGV("%s:%d]: success (select id %d)\n",
    539                           __func__, __LINE__, select_id);
    540          }
    541       }
    542    } /* select id */
    543 
    544    return status;
    545 }
    546 
    547 
    548