Home | History | Annotate | Download | only in src
      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 <stdio.h>
     30 #include <assert.h>
     31 #include <errno.h>
     32 #include <sys/time.h>
     33 #include <string.h>
     34 #include <pthread.h>
     35 
     36 #include <rpc/rpc.h>
     37 #include <loc_api_rpc_glue.h>
     38 #include "loc_api_sync_call.h"
     39 
     40 /* Logging */
     41 #define LOG_TAG "LocSvc_api_rpc_glue"
     42 // #define LOG_NDDEBUG 0
     43 #ifndef USE_GLIB
     44 #include <utils/Log.h>
     45 #endif /* USE_GLIB */
     46 
     47 /***************************************************************************
     48  *                 DATA FOR ASYNCHRONOUS RPC PROCESSING
     49  **************************************************************************/
     50 loc_sync_call_slot_array_s_type loc_sync_data;
     51 
     52 pthread_mutex_t loc_sync_call_mutex = PTHREAD_MUTEX_INITIALIZER;
     53 boolean loc_sync_call_inited = 0;
     54 
     55 /*===========================================================================
     56 
     57 FUNCTION    loc_api_sync_call_init
     58 
     59 DESCRIPTION
     60    Initialize this module
     61 
     62 DEPENDENCIES
     63    N/A
     64 
     65 RETURN VALUE
     66    none
     67 
     68 SIDE EFFECTS
     69    N/A
     70 
     71 ===========================================================================*/
     72 void loc_api_sync_call_init()
     73 {
     74    pthread_mutex_lock(&loc_sync_call_mutex);
     75    if (loc_sync_call_inited == 1) {
     76        pthread_mutex_unlock(&loc_sync_call_mutex);
     77        return;
     78    }
     79    loc_sync_call_inited = 1;
     80 
     81    loc_sync_data.num_of_slots = LOC_SYNC_CALL_SLOTS_MAX;
     82 
     83    int i;
     84    for (i = 0; i < loc_sync_data.num_of_slots; i++)
     85    {
     86       loc_sync_call_slot_s_type *slot = &loc_sync_data.slots[i];
     87 
     88       pthread_mutex_init(&slot->lock, NULL);
     89       pthread_cond_init(&slot->loc_cb_arrived_cond, NULL);
     90 
     91       slot->not_available = 0;
     92       slot->in_use = 0;
     93       slot->loc_handle = -1;
     94       slot->loc_cb_wait_event_mask = 0;       /* event to wait   */
     95       slot->loc_cb_received_event_mask = 0;   /* received event   */
     96    }
     97 
     98    pthread_mutex_unlock(&loc_sync_call_mutex);
     99 }
    100 
    101 /*===========================================================================
    102 
    103 FUNCTION    loc_api_sync_call_destroy
    104 
    105 DESCRIPTION
    106    Initialize this module
    107 
    108 DEPENDENCIES
    109    N/A
    110 
    111 RETURN VALUE
    112    none
    113 
    114 SIDE EFFECTS
    115    N/A
    116 
    117 ===========================================================================*/
    118 void loc_api_sync_call_destroy()
    119 {
    120    int i;
    121 
    122    pthread_mutex_lock(&loc_sync_call_mutex);
    123    if (loc_sync_call_inited == 0) {
    124        pthread_mutex_unlock(&loc_sync_call_mutex);
    125        return;
    126    }
    127    loc_sync_call_inited = 0;
    128 
    129    for (i = 0; i < loc_sync_data.num_of_slots; i++)
    130    {
    131       loc_sync_call_slot_s_type *slot = &loc_sync_data.slots[i];
    132 
    133       pthread_mutex_lock(&slot->lock);
    134 
    135       slot->not_available = 1;
    136 
    137       pthread_mutex_unlock(&slot->lock);
    138 
    139       pthread_cond_destroy(&slot->loc_cb_arrived_cond);
    140       pthread_mutex_destroy(&slot->lock);
    141    }
    142 
    143    pthread_mutex_unlock(&loc_sync_call_mutex);
    144 }
    145 
    146 /*===========================================================================
    147 
    148 FUNCTION    loc_match_callback
    149 
    150 DESCRIPTION
    151    Checks if an awaited event has arrived
    152 
    153 RETURN VALUE
    154    TRUE                 arrived
    155    FALSE                not matching
    156 
    157 ===========================================================================*/
    158 static boolean loc_match_callback(
    159       rpc_loc_event_mask_type             wait_mask,
    160       rpc_loc_ioctl_e_type                wait_ioctl,
    161       rpc_loc_event_mask_type             event_mask,
    162       const rpc_loc_event_payload_u_type  *callback_payload
    163 )
    164 {
    165    if ((event_mask & wait_mask) == 0) return FALSE;
    166 
    167    if (event_mask != RPC_LOC_EVENT_IOCTL_REPORT || wait_ioctl == 0 ||
    168         ( (callback_payload != NULL) &&
    169          callback_payload->rpc_loc_event_payload_u_type_u.ioctl_report.type == wait_ioctl) )
    170       return TRUE;
    171 
    172    return FALSE;
    173 }
    174 
    175 /*===========================================================================
    176 
    177 FUNCTION    loc_api_callback_process_sync_call
    178 
    179 DESCRIPTION
    180    Wakes up blocked API calls to check if the needed callback has arrived
    181 
    182 DEPENDENCIES
    183    N/A
    184 
    185 RETURN VALUE
    186    none
    187 
    188 SIDE EFFECTS
    189    N/A
    190 
    191 ===========================================================================*/
    192 void loc_api_callback_process_sync_call(
    193       rpc_loc_client_handle_type            loc_handle,             /* handle of the client */
    194       rpc_loc_event_mask_type               loc_event,              /* event mask           */
    195       const rpc_loc_event_payload_u_type*   loc_event_payload       /* payload              */
    196 )
    197 {
    198    int i;
    199 
    200    ALOGV("loc_handle = 0x%lx, loc_event = 0x%lx", loc_handle, loc_event);
    201    for (i = 0; i < loc_sync_data.num_of_slots; i++)
    202    {
    203       loc_sync_call_slot_s_type *slot = &loc_sync_data.slots[i];
    204 
    205       pthread_mutex_lock(&slot->lock);
    206 
    207       if (slot->in_use &&
    208           slot->signal_sent == 0 &&
    209           slot->loc_handle == loc_handle &&
    210           loc_match_callback(slot->loc_cb_wait_event_mask, slot->ioctl_type, loc_event, loc_event_payload))
    211       {
    212          memcpy(&slot->loc_cb_received_payload, loc_event_payload, sizeof (rpc_loc_event_payload_u_type));
    213 
    214          slot->loc_cb_received_event_mask = loc_event;
    215 
    216          ALOGV("signal slot %d in_use %d, loc_handle 0x%lx, event_mask 0x%1x, ioctl_type %d", i, slot->in_use, slot->loc_handle, (int) slot->loc_cb_wait_event_mask, (int) slot->ioctl_type);
    217          pthread_cond_signal(&slot->loc_cb_arrived_cond);
    218          slot->signal_sent = 1;
    219 
    220          pthread_mutex_unlock(&slot->lock);
    221          break;
    222       } else {
    223          /* do nothing */
    224       }
    225 
    226       pthread_mutex_unlock(&slot->lock);
    227    }
    228 }
    229 
    230 /*===========================================================================
    231 
    232 FUNCTION    loc_lock_a_slot
    233 
    234 DESCRIPTION
    235    Allocates a buffer slot for the synchronous API call
    236 
    237 DEPENDENCIES
    238    N/A
    239 
    240 RETURN VALUE
    241    Select ID (>=0)     : successful
    242    -1                  : buffer full
    243 
    244 SIDE EFFECTS
    245    N/A
    246 
    247 ===========================================================================*/
    248 static int loc_lock_a_slot()
    249 {
    250    int i, select_id = -1; /* no free buffer */
    251 
    252    for (i = 0; i < loc_sync_data.num_of_slots; i++)
    253    {
    254       loc_sync_call_slot_s_type *slot = &loc_sync_data.slots[i];
    255       if (pthread_mutex_trylock(&slot->lock) == EBUSY)
    256       {
    257          ALOGV("trylock EBUSY : %d", i);
    258          continue;
    259       }
    260 
    261       if (!slot->in_use && !slot->not_available)
    262       {
    263          select_id = i;
    264          /* Return from here and leave the mutex locked.
    265           * will unlock it in loc_unlock_slot()
    266           */
    267          break;
    268       }
    269       /* ALOGV("slot %d in_use = %d, not_available = %d : %d", i, slot->in_use, slot->not_available, i); */
    270       pthread_mutex_unlock(&slot->lock);
    271    }
    272 
    273    return select_id;
    274 }
    275 
    276 /*===========================================================================
    277 
    278 FUNCTION    loc_unlock_slot
    279 
    280 DESCRIPTION
    281    Unlocks a buffer slot
    282 
    283 DEPENDENCIES
    284    N/A
    285 
    286 RETURN VALUE
    287    None
    288 
    289 SIDE EFFECTS
    290    N/A
    291 
    292 ===========================================================================*/
    293 static void loc_unlock_slot(int select_id)
    294 {
    295    pthread_mutex_unlock(&loc_sync_data.slots[select_id].lock);
    296 }
    297 
    298 /*===========================================================================
    299 
    300 FUNCTION    loc_lock_slot
    301 
    302 DESCRIPTION
    303    Locks a specific slot that was previously locked from loc_lock_a_slot
    304 
    305 DEPENDENCIES
    306    N/A
    307 
    308 RETURN VALUE
    309    None
    310 
    311 SIDE EFFECTS
    312    N/A
    313 
    314 ===========================================================================*/
    315 static void loc_lock_slot(int select_id)
    316 {
    317     pthread_mutex_lock(&loc_sync_data.slots[select_id].lock);
    318 }
    319 
    320 /*===========================================================================
    321 
    322 FUNCTION    loc_set_slot_in_use
    323 
    324 DESCRIPTION
    325    Sets the in_use flag of slot to true or false.
    326    Should be called only after the slot is locked
    327 
    328 DEPENDENCIES
    329    N/A
    330 
    331 RETURN VALUE
    332    None
    333 
    334 SIDE EFFECTS
    335    N/A
    336 
    337 ===========================================================================*/
    338 static void loc_set_slot_in_use(int select_id, boolean in_use)
    339 {
    340     loc_sync_data.slots[select_id].in_use = in_use;
    341     if (in_use == 1)
    342         loc_sync_data.slots[select_id].signal_sent = 0;
    343 }
    344 
    345 /*===========================================================================
    346 
    347 FUNCTION    loc_api_save_callback
    348 
    349 DESCRIPTION
    350    Selects which callback or IOCTL event to wait for.
    351 
    352    The event_mask specifies the event(s). If it is RPC_LOC_EVENT_IOCTL_REPORT,
    353    then ioctl_type specifies the IOCTL event.
    354 
    355    If ioctl_type is non-zero, RPC_LOC_EVENT_IOCTL_REPORT is automatically added.
    356 
    357 DEPENDENCIES
    358    N/A
    359 
    360 RETURN VALUE
    361    Select ID (>=0)     : successful
    362    -1                  : out of buffer
    363 
    364 SIDE EFFECTS
    365    N/A
    366 
    367 ===========================================================================*/
    368 static void loc_api_save_callback(
    369       int                              select_id,            /* Selected slot */
    370       rpc_loc_client_handle_type       loc_handle,           /* Client handle */
    371       rpc_loc_event_mask_type          event_mask,           /* Event mask to wait for */
    372       rpc_loc_ioctl_e_type             ioctl_type            /* IOCTL type to wait for */
    373 )
    374 {
    375    loc_sync_call_slot_s_type *slot = &loc_sync_data.slots[select_id];
    376 
    377    slot->loc_handle = loc_handle;
    378 
    379    slot->loc_cb_wait_event_mask = event_mask;
    380    slot->ioctl_type = ioctl_type;
    381    if (ioctl_type) slot->loc_cb_wait_event_mask |= RPC_LOC_EVENT_IOCTL_REPORT;
    382 
    383    return;
    384 }
    385 
    386 /*===========================================================================
    387 
    388 FUNCTION    loc_save_user_payload
    389 
    390 DESCRIPTION
    391    Saves received payload into user data structures
    392 
    393 RETURN VALUE
    394    None
    395 
    396 ===========================================================================*/
    397 static void loc_save_user_payload(
    398       rpc_loc_event_payload_u_type  *user_cb_payload,
    399       rpc_loc_ioctl_callback_s_type *user_ioctl_buffer,
    400       const rpc_loc_event_payload_u_type  *received_cb_payload
    401 )
    402 {
    403    if (user_cb_payload)
    404    {
    405       memcpy(user_cb_payload, received_cb_payload,
    406             sizeof (rpc_loc_event_payload_u_type));
    407    }
    408    if (user_ioctl_buffer)
    409    {
    410       memcpy(user_ioctl_buffer,
    411             &received_cb_payload->rpc_loc_event_payload_u_type_u.ioctl_report,
    412             sizeof *user_ioctl_buffer);
    413    }
    414 }
    415 
    416 /*===========================================================================
    417 
    418 FUNCTION    loc_api_wait_callback
    419 
    420 DESCRIPTION
    421    Waits for a selected callback. The wait expires in timeout_seconds seconds.
    422 
    423    If the function is called before an existing wait has finished, it will
    424    immediately return EBUSY.
    425 
    426 DEPENDENCIES
    427    N/A
    428 
    429 RETURN VALUE
    430    RPC_LOC_API_SUCCESS              if successful (0)
    431    RPC_LOC_API_TIMEOUT              if timed out
    432    RPC_LOC_API_ENGINE_BUSY          if already in a wait
    433    RPC_LOC_API_INVALID_PARAMETER    if callback is not yet selected
    434 
    435 SIDE EFFECTS
    436    N/A
    437 
    438 ===========================================================================*/
    439 static int loc_api_wait_callback(
    440       int select_id,        /* ID from loc_select_callback() */
    441       int timeout_seconds,  /* Timeout in this number of seconds  */
    442       rpc_loc_event_payload_u_type     *callback_payload,    /* Pointer to callback payload buffer, can be NULL */
    443       rpc_loc_ioctl_callback_s_type    *ioctl_payload        /* Pointer to IOCTL payload, can be NULL */
    444 )
    445 {
    446    int ret_val = RPC_LOC_API_SUCCESS;  /* the return value of this function: 0 = no error */
    447    int rc = 0;                         /* return code from pthread calls */
    448 
    449    struct timespec expire_time;
    450 
    451    loc_sync_call_slot_s_type *slot = &loc_sync_data.slots[select_id];
    452 
    453    clock_gettime(CLOCK_REALTIME, &expire_time);
    454    expire_time.tv_sec += timeout_seconds;
    455 
    456    /* Waiting */
    457    while (slot->signal_sent == 0 && rc != ETIMEDOUT) {
    458        rc = pthread_cond_timedwait(&slot->loc_cb_arrived_cond,
    459              &slot->lock, &expire_time);
    460    }
    461 
    462    if (rc == ETIMEDOUT)
    463    {
    464       ret_val = RPC_LOC_API_TIMEOUT; /* Timed out */
    465       ALOGE("TIMEOUT: %d", select_id);
    466    }
    467    else {
    468       /* Obtained the first awaited callback */
    469       ret_val = RPC_LOC_API_SUCCESS;       /* Successful */
    470       loc_save_user_payload(callback_payload, ioctl_payload, &slot->loc_cb_received_payload);
    471    }
    472 
    473    return ret_val;
    474 }
    475 
    476 /*===========================================================================
    477 
    478 FUNCTION    loc_api_sync_ioctl
    479 
    480 DESCRIPTION
    481    Synchronous IOCTL call (reentrant version)
    482 
    483 DEPENDENCIES
    484    N/A
    485 
    486 RETURN VALUE
    487    Loc API error code (0 = success)
    488 
    489 SIDE EFFECTS
    490    N/A
    491 
    492 ===========================================================================*/
    493 int loc_api_sync_ioctl
    494 (
    495       rpc_loc_client_handle_type           handle,
    496       rpc_loc_ioctl_e_type                 ioctl_type,
    497       rpc_loc_ioctl_data_u_type*           ioctl_data_ptr,
    498       uint32                               timeout_msec,
    499       rpc_loc_ioctl_callback_s_type       *cb_data_ptr
    500 )
    501 {
    502    int                              rc = -1;
    503    int                              select_id;
    504    rpc_loc_ioctl_callback_s_type    callback_data;
    505 
    506    select_id = loc_lock_a_slot();
    507 
    508    if (select_id < 0 || select_id >= loc_sync_data.num_of_slots)
    509    {
    510       ALOGE("slot not available ioctl_type = %s",
    511            loc_get_ioctl_type_name(ioctl_type));
    512       return rc;
    513    }
    514 
    515    loc_set_slot_in_use(select_id, 1); // set slot in use to true
    516 
    517    // Select the callback we are waiting for
    518    loc_api_save_callback(select_id, handle, 0, ioctl_type);
    519 
    520    loc_unlock_slot(select_id); // slot is unlocked, but in_use is still true
    521 
    522    // we want to avoid keeping the slot locked during the loc_ioctl because the rpc
    523    // framework will also lock a different mutex during this call, and typically
    524    // locking two different mutexes at the same time can lead to deadlock.
    525    rc =  loc_ioctl(handle, ioctl_type, ioctl_data_ptr);
    526 
    527    loc_lock_slot(select_id);
    528 
    529    if (rc != RPC_LOC_API_SUCCESS)
    530    {
    531       ALOGE("loc_ioctl failed select_id = %d, ioctl_type %s, returned %s",
    532            select_id, loc_get_ioctl_type_name(ioctl_type), loc_get_ioctl_status_name(rc));
    533    }
    534    else {
    535       ALOGV("select_id = %d, ioctl_type %d, returned RPC_LOC_API_SUCCESS",
    536           select_id, ioctl_type);
    537       // Wait for the callback of loc_ioctl
    538       if ((rc = loc_api_wait_callback(select_id, timeout_msec / 1000, NULL, &callback_data)) != 0)
    539       {
    540          // Callback waiting failed
    541          ALOGE("callback wait failed select_id = %d, ioctl_type %s, returned %s",
    542               select_id, loc_get_ioctl_type_name(ioctl_type), loc_get_ioctl_status_name(rc));
    543       }
    544       else
    545       {
    546          if (cb_data_ptr) memcpy(cb_data_ptr, &callback_data, sizeof *cb_data_ptr);
    547          if (callback_data.status != RPC_LOC_API_SUCCESS)
    548          {
    549             rc = callback_data.status;
    550             ALOGE("callback status failed select_id = %d, ioctl_type %s, returned %s",
    551                  select_id, loc_get_ioctl_type_name(ioctl_type), loc_get_ioctl_status_name(rc));
    552          } else {
    553             ALOGV("callback status success select_id = %d, ioctl_type %d, returned %d",
    554                 select_id, ioctl_type, rc);
    555          }
    556       } /* wait callback */
    557    } /* loc_ioctl */
    558 
    559    loc_set_slot_in_use(select_id, 0); // set slot in use to false
    560    loc_unlock_slot(select_id);
    561 
    562    return rc;
    563 }
    564 
    565 
    566