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 ===========================================================================*/
loc_api_sync_call_init()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 ===========================================================================*/
loc_api_sync_call_destroy()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 ===========================================================================*/
loc_match_callback(rpc_loc_event_mask_type wait_mask,rpc_loc_ioctl_e_type wait_ioctl,rpc_loc_event_mask_type event_mask,const rpc_loc_event_payload_u_type * callback_payload)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 ===========================================================================*/
loc_api_callback_process_sync_call(rpc_loc_client_handle_type loc_handle,rpc_loc_event_mask_type loc_event,const rpc_loc_event_payload_u_type * loc_event_payload)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 ===========================================================================*/
loc_lock_a_slot()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 ===========================================================================*/
loc_unlock_slot(int select_id)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 ===========================================================================*/
loc_lock_slot(int select_id)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 ===========================================================================*/
loc_set_slot_in_use(int select_id,boolean in_use)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 ===========================================================================*/
loc_api_save_callback(int select_id,rpc_loc_client_handle_type loc_handle,rpc_loc_event_mask_type event_mask,rpc_loc_ioctl_e_type ioctl_type)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 ===========================================================================*/
loc_save_user_payload(rpc_loc_event_payload_u_type * user_cb_payload,rpc_loc_ioctl_callback_s_type * user_ioctl_buffer,const rpc_loc_event_payload_u_type * received_cb_payload)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 ===========================================================================*/
loc_api_wait_callback(int select_id,int timeout_seconds,rpc_loc_event_payload_u_type * callback_payload,rpc_loc_ioctl_callback_s_type * ioctl_payload)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 ===========================================================================*/
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)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