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