/*=========================================================================== FUNCTION loc_sync_send_req DESCRIPTION Synchronous req call (thread safe) DEPENDENCIES N/A RETURN VALUE Loc API 2.0 status SIDE EFFECTS N/A ===========================================================================*/ locClientStatusEnumType loc_sync_send_req ( locClientHandleType client_handle, uint32_t req_id, /* req id */ locClientReqUnionType req_payload, uint32_t timeout_msec, uint32_t ind_id, //ind ID to block for, usually the same as req_id */ void *ind_payload_ptr /* can be NULL*/ ) { locClientStatusEnumType status = eLOC_CLIENT_SUCCESS ; int select_id; int rc = 0; // Select the callback we are waiting for select_id = loc_sync_select_ind(client_handle, ind_id, req_id, ind_payload_ptr); if (select_id >= 0) { status = locClientSendReq (client_handle, req_id, req_payload); LOC_LOGV("%s:%d]: select_id = %d,locClientSendReq returned %d\n", __func__, __LINE__, select_id, status); if (status != eLOC_CLIENT_SUCCESS ) { loc_free_slot(select_id); } else { // Wait for the indication callback if (( rc = loc_sync_wait_for_ind( select_id, timeout_msec / 1000, ind_id) ) < 0) { if ( rc == -ETIMEDOUT) status = eLOC_CLIENT_FAILURE_TIMEOUT; else status = eLOC_CLIENT_FAILURE_INTERNAL; // Callback waiting failed LOC_LOGE("%s:%d]: loc_api_wait_for_ind failed, err %d, " "select id %d, status %s", __func__, __LINE__, rc , select_id, loc_get_v02_client_status_name(status)); } else { status = eLOC_CLIENT_SUCCESS; LOC_LOGV("%s:%d]: success (select id %d)\n", __func__, __LINE__, select_id); } } } /* select id */ return status; }
/*=========================================================================== FUNCTION loc_api_sync_ioctl DESCRIPTION Synchronous IOCTL call (reentrant version) DEPENDENCIES N/A RETURN VALUE Loc API error code (0 = success) SIDE EFFECTS N/A ===========================================================================*/ int loc_api_sync_ioctl ( rpc_loc_client_handle_type handle, rpc_loc_ioctl_e_type ioctl_type, rpc_loc_ioctl_data_u_type* ioctl_data_ptr, uint32 timeout_msec, rpc_loc_ioctl_callback_s_type *cb_data_ptr ) { int rc = RPC_LOC_API_ENGINE_BUSY; int select_id; rpc_loc_ioctl_callback_s_type callback_data; // Select the callback we are waiting for select_id = loc_api_select_callback(handle, 0, ioctl_type); if (select_id >= 0) { pthread_mutex_lock(&loc_sync_data.lock); rc = loc_ioctl(handle, ioctl_type, ioctl_data_ptr); while (rc == RPC_LOC_API_ENGINE_BUSY) { /* TODO: Use timeout? */ ALOGD("loc_api_sync_ioctl: select_id = %d, engine busy, waiting...\n", select_id); pthread_cond_wait(&loc_sync_data.loc_cb_arrived_cond, &loc_sync_data.lock); rc = loc_ioctl(handle, ioctl_type, ioctl_data_ptr); } pthread_mutex_unlock(&loc_sync_data.lock); ALOGV("loc_api_sync_ioctl: select_id = %d, loc_ioctl returned %d\n", select_id, rc); if (rc != RPC_LOC_API_SUCCESS) { ALOGE("loc_api_sync_ioctl: select_id = %d, loc_ioctl returned %d\n", select_id, rc); loc_free_slot(select_id); } else { // Wait for the callback of loc_ioctl if ((rc = loc_api_wait_callback(select_id, timeout_msec / 1000, NULL, &callback_data)) != 0) { // Callback waiting failed ALOGE("loc_api_sync_ioctl: loc_api_wait_callback failed, returned %d (select id %d)\n", rc, select_id); } else { if (cb_data_ptr) memcpy(cb_data_ptr, &callback_data, sizeof *cb_data_ptr); if (callback_data.status != RPC_LOC_API_SUCCESS) { rc = callback_data.status; ALOGE("loc_api_sync_ioctl: IOCTL result failed, result: %d (select id %d)\n", rc, select_id); } } /* wait callback */ } /* loc_ioctl */ } /* select id */ return rc; }
/*=========================================================================== FUNCTION loc_sync_wait_for_ind DESCRIPTION Waits for a selected indication. The wait expires in timeout_seconds seconds. If the function is called before an existing wait has finished, it will immediately return error. DEPENDENCIES N/A RETURN VALUE 0 on SUCCESS, -ve value on failure SIDE EFFECTS N/A ===========================================================================*/ static int loc_sync_wait_for_ind( int select_id, /* ID from loc_sync_select_ind() */ int timeout_seconds, /* Timeout in this number of seconds */ uint32_t ind_id ) { if (select_id < 0 || select_id >= LOC_SYNC_REQ_BUFFER_SIZE || !loc_sync_array.slot_in_use[select_id]) { LOC_LOGE("%s:%d]: invalid select_id: %d \n", __func__, __LINE__, select_id); return (-EINVAL); } loc_sync_req_data_s_type *slot = &loc_sync_array.slots[select_id]; int ret_val = 0; /* the return value of this function: 0 = no error */ int rc; /* return code from pthread calls */ struct timeval present_time; struct timespec expire_time; pthread_mutex_lock(&slot->sync_req_lock); do { if (slot->ind_has_arrived) { ret_val = 0; /* success */ break; } if (slot->ind_is_waiting) { LOC_LOGW("%s:%d]: already waiting in this slot %d\n", __func__, __LINE__, select_id); ret_val = -EBUSY; // busy break; } /* Calculate absolute expire time */ gettimeofday(&present_time, NULL); expire_time.tv_sec = present_time.tv_sec; expire_time.tv_nsec = present_time.tv_usec * 1000; expire_time.tv_sec += timeout_seconds; /* Take new wait request */ slot->ind_is_waiting = true; /* Waiting */ rc = pthread_cond_timedwait(&slot->ind_arrived_cond, &slot->sync_req_lock, &expire_time); slot->ind_is_waiting = false; if(rc == ETIMEDOUT) { LOC_LOGE("%s:%d]: slot %d, timed out for ind_id %s\n", __func__, __LINE__, select_id, loc_get_v02_event_name(ind_id)); ret_val = -ETIMEDOUT; //time out } } while (0); pthread_mutex_unlock(&slot->sync_req_lock); loc_free_slot(select_id); return ret_val; }
/*=========================================================================== FUNCTION loc_api_wait_callback DESCRIPTION Waits for a selected callback. The wait expires in timeout_seconds seconds. If the function is called before an existing wait has finished, it will immediately return EBUSY. DEPENDENCIES N/A RETURN VALUE RPC_LOC_API_SUCCESS if successful (0) RPC_LOC_API_TIMEOUT if timed out RPC_LOC_API_ENGINE_BUSY if already in a wait RPC_LOC_API_INVALID_PARAMETER if callback is not yet selected SIDE EFFECTS N/A ===========================================================================*/ int loc_api_wait_callback( int select_id, /* ID from loc_select_callback() */ int timeout_seconds, /* Timeout in this number of seconds */ rpc_loc_event_payload_u_type *callback_payload, /* Pointer to callback payload buffer, can be NULL */ rpc_loc_ioctl_callback_s_type *ioctl_payload /* Pointer to IOCTL payload, can be NULL */ ) { if (select_id < 0 || select_id >= loc_sync_data.size || !loc_sync_data.slot_in_use[select_id]) { ALOGE("loc_wait_callback: invalid select_id: %d", select_id); return RPC_LOC_API_INVALID_PARAMETER; } loc_sync_call_data_s_type *slot = &loc_sync_data.slots[select_id]; int ret_val = RPC_LOC_API_SUCCESS; /* the return value of this function: 0 = no error */ int rc; /* return code from pthread calls */ struct timeval present_time; struct timespec expire_time; pthread_mutex_lock(&slot->lock); if (slot->loc_cb_has_arrived) { loc_save_user_payload(callback_payload, ioctl_payload, &slot->loc_cb_received_payload); pthread_mutex_unlock(&slot->lock); loc_free_slot(select_id); ret_val = RPC_LOC_API_SUCCESS; return ret_val; /* success */ } if (slot->loc_cb_is_waiting) { pthread_mutex_unlock(&slot->lock); loc_free_slot(select_id); ret_val = RPC_LOC_API_ENGINE_BUSY; /* busy, rejected */ ALOGE("loc_wait_callback: already waiting on select_id: %d\n", select_id); return ret_val; /* exit */ } /* Calculate absolute expire time */ gettimeofday(&present_time, NULL); expire_time.tv_sec = present_time.tv_sec; expire_time.tv_nsec = present_time.tv_usec * 1000; expire_time.tv_sec += timeout_seconds; /* Take new wait request */ slot->loc_cb_is_waiting = TRUE; /* Waiting */ rc = pthread_cond_timedwait(&slot->loc_cb_arrived_cond, &slot->lock, &expire_time); if (rc == ETIMEDOUT) { slot->loc_cb_is_waiting = FALSE; ret_val = RPC_LOC_API_TIMEOUT; /* Timed out */ } else { /* Obtained the first awaited callback */ slot->loc_cb_is_waiting = FALSE; /* stop waiting */ ret_val = RPC_LOC_API_SUCCESS; /* Successful */ loc_save_user_payload(callback_payload, ioctl_payload, &slot->loc_cb_received_payload); } pthread_mutex_unlock(&slot->lock); loc_free_slot(select_id); return ret_val; }