• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /******************************************************************************
2  *
3  *  Copyright (C) 2014 Google, Inc.
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at:
8  *
9  *  http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  ******************************************************************************/
18 
19 #include "include/bt_target.h"
20 
21 #define LOG_TAG "bt_osi_alarm"
22 
23 #include "osi/include/alarm.h"
24 
25 #include <assert.h>
26 #include <errno.h>
27 #include <fcntl.h>
28 #include <inttypes.h>
29 #include <malloc.h>
30 #include <pthread.h>
31 #include <signal.h>
32 #include <string.h>
33 #include <time.h>
34 
35 #include <hardware/bluetooth.h>
36 
37 #include "osi/include/allocator.h"
38 #include "osi/include/fixed_queue.h"
39 #include "osi/include/list.h"
40 #include "osi/include/log.h"
41 #include "osi/include/osi.h"
42 #include "osi/include/semaphore.h"
43 #include "osi/include/thread.h"
44 #include "osi/include/wakelock.h"
45 
46 // Make callbacks run at high thread priority. Some callbacks are used for audio
47 // related timer tasks as well as re-transmissions etc. Since we at this point
48 // cannot differentiate what callback we are dealing with, assume high priority
49 // for now.
50 // TODO(eisenbach): Determine correct thread priority (from parent?/per alarm?)
51 static const int CALLBACK_THREAD_PRIORITY_HIGH = -19;
52 
53 typedef struct {
54   size_t count;
55   period_ms_t total_ms;
56   period_ms_t max_ms;
57 } stat_t;
58 
59 // Alarm-related information and statistics
60 typedef struct {
61   const char *name;
62   size_t scheduled_count;
63   size_t canceled_count;
64   size_t rescheduled_count;
65   size_t total_updates;
66   period_ms_t last_update_ms;
67   stat_t callback_execution;
68   stat_t overdue_scheduling;
69   stat_t premature_scheduling;
70 } alarm_stats_t;
71 
72 struct alarm_t {
73   // The lock is held while the callback for this alarm is being executed.
74   // It allows us to release the coarse-grained monitor lock while a
75   // potentially long-running callback is executing. |alarm_cancel| uses this
76   // lock to provide a guarantee to its caller that the callback will not be
77   // in progress when it returns.
78   pthread_mutex_t callback_lock;
79   period_ms_t creation_time;
80   period_ms_t period;
81   period_ms_t deadline;
82   period_ms_t prev_deadline;    // Previous deadline - used for accounting of
83                                 // periodic timers
84   bool is_periodic;
85   fixed_queue_t *queue;         // The processing queue to add this alarm to
86   alarm_callback_t callback;
87   void *data;
88   alarm_stats_t stats;
89 };
90 
91 
92 // If the next wakeup time is less than this threshold, we should acquire
93 // a wakelock instead of setting a wake alarm so we're not bouncing in
94 // and out of suspend frequently. This value is externally visible to allow
95 // unit tests to run faster. It should not be modified by production code.
96 int64_t TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 3000;
97 static const clockid_t CLOCK_ID = CLOCK_BOOTTIME;
98 
99 #if defined(KERNEL_MISSING_CLOCK_BOOTTIME_ALARM) && (KERNEL_MISSING_CLOCK_BOOTTIME_ALARM == TRUE)
100 static const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME;
101 #else
102 static const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME_ALARM;
103 #endif
104 
105 // This mutex ensures that the |alarm_set|, |alarm_cancel|, and alarm callback
106 // functions execute serially and not concurrently. As a result, this mutex
107 // also protects the |alarms| list.
108 static pthread_mutex_t monitor;
109 static list_t *alarms;
110 static timer_t timer;
111 static timer_t wakeup_timer;
112 static bool timer_set;
113 
114 // All alarm callbacks are dispatched from |dispatcher_thread|
115 static thread_t *dispatcher_thread;
116 static bool dispatcher_thread_active;
117 static semaphore_t *alarm_expired;
118 
119 // Default alarm callback thread and queue
120 static thread_t *default_callback_thread;
121 static fixed_queue_t *default_callback_queue;
122 
123 static alarm_t *alarm_new_internal(const char *name, bool is_periodic);
124 static bool lazy_initialize(void);
125 static period_ms_t now(void);
126 static void alarm_set_internal(alarm_t *alarm, period_ms_t period,
127                                alarm_callback_t cb, void *data,
128                                fixed_queue_t *queue);
129 static void alarm_cancel_internal(alarm_t *alarm);
130 static void remove_pending_alarm(alarm_t *alarm);
131 static void schedule_next_instance(alarm_t *alarm);
132 static void reschedule_root_alarm(void);
133 static void alarm_queue_ready(fixed_queue_t *queue, void *context);
134 static void timer_callback(void *data);
135 static void callback_dispatch(void *context);
136 static bool timer_create_internal(const clockid_t clock_id, timer_t *timer);
137 static void update_scheduling_stats(alarm_stats_t *stats,
138                                     period_ms_t now_ms,
139                                     period_ms_t deadline_ms,
140                                     period_ms_t execution_delta_ms);
141 
update_stat(stat_t * stat,period_ms_t delta)142 static void update_stat(stat_t *stat, period_ms_t delta)
143 {
144   if (stat->max_ms < delta)
145     stat->max_ms = delta;
146   stat->total_ms += delta;
147   stat->count++;
148 }
149 
alarm_new(const char * name)150 alarm_t *alarm_new(const char *name) {
151   return alarm_new_internal(name, false);
152 }
153 
alarm_new_periodic(const char * name)154 alarm_t *alarm_new_periodic(const char *name) {
155   return alarm_new_internal(name, true);
156 }
157 
alarm_new_internal(const char * name,bool is_periodic)158 static alarm_t *alarm_new_internal(const char *name, bool is_periodic) {
159   // Make sure we have a list we can insert alarms into.
160   if (!alarms && !lazy_initialize()) {
161     assert(false); // if initialization failed, we should not continue
162     return NULL;
163   }
164 
165   pthread_mutexattr_t attr;
166   pthread_mutexattr_init(&attr);
167 
168   alarm_t *ret = osi_calloc(sizeof(alarm_t));
169 
170   // Make this a recursive mutex to make it safe to call |alarm_cancel| from
171   // within the callback function of the alarm.
172   int error = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
173   if (error) {
174     LOG_ERROR(LOG_TAG, "%s unable to create a recursive mutex: %s",
175               __func__, strerror(error));
176     goto error;
177   }
178 
179   error = pthread_mutex_init(&ret->callback_lock, &attr);
180   if (error) {
181     LOG_ERROR(LOG_TAG, "%s unable to initialize mutex: %s",
182               __func__, strerror(error));
183     goto error;
184   }
185 
186   ret->is_periodic = is_periodic;
187 
188   alarm_stats_t *stats = &ret->stats;
189   stats->name = osi_strdup(name);
190   // NOTE: The stats were reset by osi_calloc() above
191 
192   pthread_mutexattr_destroy(&attr);
193   return ret;
194 
195 error:
196   pthread_mutexattr_destroy(&attr);
197   osi_free(ret);
198   return NULL;
199 }
200 
alarm_free(alarm_t * alarm)201 void alarm_free(alarm_t *alarm) {
202   if (!alarm)
203     return;
204 
205   alarm_cancel(alarm);
206   pthread_mutex_destroy(&alarm->callback_lock);
207   osi_free((void *)alarm->stats.name);
208   osi_free(alarm);
209 }
210 
alarm_get_remaining_ms(const alarm_t * alarm)211 period_ms_t alarm_get_remaining_ms(const alarm_t *alarm) {
212   assert(alarm != NULL);
213   period_ms_t remaining_ms = 0;
214   period_ms_t just_now = now();
215 
216   pthread_mutex_lock(&monitor);
217   if (alarm->deadline > just_now)
218     remaining_ms = alarm->deadline - just_now;
219   pthread_mutex_unlock(&monitor);
220 
221   return remaining_ms;
222 }
223 
alarm_set(alarm_t * alarm,period_ms_t interval_ms,alarm_callback_t cb,void * data)224 void alarm_set(alarm_t *alarm, period_ms_t interval_ms,
225                alarm_callback_t cb, void *data) {
226   alarm_set_on_queue(alarm, interval_ms, cb, data, default_callback_queue);
227 }
228 
alarm_set_on_queue(alarm_t * alarm,period_ms_t interval_ms,alarm_callback_t cb,void * data,fixed_queue_t * queue)229 void alarm_set_on_queue(alarm_t *alarm, period_ms_t interval_ms,
230                         alarm_callback_t cb, void *data,
231                         fixed_queue_t *queue) {
232   assert(queue != NULL);
233   alarm_set_internal(alarm, interval_ms, cb, data, queue);
234 }
235 
236 // Runs in exclusion with alarm_cancel and timer_callback.
alarm_set_internal(alarm_t * alarm,period_ms_t period,alarm_callback_t cb,void * data,fixed_queue_t * queue)237 static void alarm_set_internal(alarm_t *alarm, period_ms_t period,
238                                alarm_callback_t cb, void *data,
239                                fixed_queue_t *queue) {
240   assert(alarms != NULL);
241   assert(alarm != NULL);
242   assert(cb != NULL);
243 
244   pthread_mutex_lock(&monitor);
245 
246   alarm->creation_time = now();
247   alarm->period = period;
248   alarm->queue = queue;
249   alarm->callback = cb;
250   alarm->data = data;
251 
252   schedule_next_instance(alarm);
253   alarm->stats.scheduled_count++;
254 
255   pthread_mutex_unlock(&monitor);
256 }
257 
alarm_cancel(alarm_t * alarm)258 void alarm_cancel(alarm_t *alarm) {
259   assert(alarms != NULL);
260   if (!alarm)
261     return;
262 
263   pthread_mutex_lock(&monitor);
264   alarm_cancel_internal(alarm);
265   pthread_mutex_unlock(&monitor);
266 
267   // If the callback for |alarm| is in progress, wait here until it completes.
268   pthread_mutex_lock(&alarm->callback_lock);
269   pthread_mutex_unlock(&alarm->callback_lock);
270 }
271 
272 // Internal implementation of canceling an alarm.
273 // The caller must hold the |monitor| lock.
alarm_cancel_internal(alarm_t * alarm)274 static void alarm_cancel_internal(alarm_t *alarm) {
275   bool needs_reschedule = (!list_is_empty(alarms) && list_front(alarms) == alarm);
276 
277   remove_pending_alarm(alarm);
278 
279   alarm->deadline = 0;
280   alarm->prev_deadline = 0;
281   alarm->callback = NULL;
282   alarm->data = NULL;
283   alarm->stats.canceled_count++;
284   alarm->queue = NULL;
285 
286   if (needs_reschedule)
287     reschedule_root_alarm();
288 }
289 
alarm_is_scheduled(const alarm_t * alarm)290 bool alarm_is_scheduled(const alarm_t *alarm) {
291   if ((alarms == NULL) || (alarm == NULL))
292     return false;
293   return (alarm->callback != NULL);
294 }
295 
alarm_cleanup(void)296 void alarm_cleanup(void) {
297   // If lazy_initialize never ran there is nothing else to do
298   if (!alarms)
299     return;
300 
301   dispatcher_thread_active = false;
302   semaphore_post(alarm_expired);
303   thread_free(dispatcher_thread);
304   dispatcher_thread = NULL;
305 
306   pthread_mutex_lock(&monitor);
307 
308   fixed_queue_free(default_callback_queue, NULL);
309   default_callback_queue = NULL;
310   thread_free(default_callback_thread);
311   default_callback_thread = NULL;
312 
313   timer_delete(wakeup_timer);
314   timer_delete(timer);
315   semaphore_free(alarm_expired);
316   alarm_expired = NULL;
317 
318   list_free(alarms);
319   alarms = NULL;
320 
321   pthread_mutex_unlock(&monitor);
322   pthread_mutex_destroy(&monitor);
323 }
324 
lazy_initialize(void)325 static bool lazy_initialize(void) {
326   assert(alarms == NULL);
327 
328   // timer_t doesn't have an invalid value so we must track whether
329   // the |timer| variable is valid ourselves.
330   bool timer_initialized = false;
331   bool wakeup_timer_initialized = false;
332 
333   pthread_mutex_init(&monitor, NULL);
334 
335   alarms = list_new(NULL);
336   if (!alarms) {
337     LOG_ERROR(LOG_TAG, "%s unable to allocate alarm list.", __func__);
338     goto error;
339   }
340 
341   if (!timer_create_internal(CLOCK_ID, &timer))
342     goto error;
343   timer_initialized = true;
344 
345   if (!timer_create_internal(CLOCK_ID_ALARM, &wakeup_timer))
346     goto error;
347   wakeup_timer_initialized = true;
348 
349   alarm_expired = semaphore_new(0);
350   if (!alarm_expired) {
351     LOG_ERROR(LOG_TAG, "%s unable to create alarm expired semaphore", __func__);
352     goto error;
353   }
354 
355   default_callback_thread = thread_new_sized("alarm_default_callbacks",
356                                              SIZE_MAX);
357   if (default_callback_thread == NULL) {
358     LOG_ERROR(LOG_TAG, "%s unable to create default alarm callbacks thread.",
359               __func__);
360     goto error;
361   }
362   thread_set_priority(default_callback_thread, CALLBACK_THREAD_PRIORITY_HIGH);
363   default_callback_queue = fixed_queue_new(SIZE_MAX);
364   if (default_callback_queue == NULL) {
365     LOG_ERROR(LOG_TAG, "%s unable to create default alarm callbacks queue.",
366               __func__);
367     goto error;
368   }
369   alarm_register_processing_queue(default_callback_queue,
370                                   default_callback_thread);
371 
372   dispatcher_thread_active = true;
373   dispatcher_thread = thread_new("alarm_dispatcher");
374   if (!dispatcher_thread) {
375     LOG_ERROR(LOG_TAG, "%s unable to create alarm callback thread.", __func__);
376     goto error;
377   }
378 
379   thread_set_priority(dispatcher_thread, CALLBACK_THREAD_PRIORITY_HIGH);
380   thread_post(dispatcher_thread, callback_dispatch, NULL);
381   return true;
382 
383 error:
384   fixed_queue_free(default_callback_queue, NULL);
385   default_callback_queue = NULL;
386   thread_free(default_callback_thread);
387   default_callback_thread = NULL;
388 
389   thread_free(dispatcher_thread);
390   dispatcher_thread = NULL;
391 
392   dispatcher_thread_active = false;
393 
394   semaphore_free(alarm_expired);
395   alarm_expired = NULL;
396 
397   if (wakeup_timer_initialized)
398     timer_delete(wakeup_timer);
399 
400   if (timer_initialized)
401     timer_delete(timer);
402 
403   list_free(alarms);
404   alarms = NULL;
405 
406   pthread_mutex_destroy(&monitor);
407 
408   return false;
409 }
410 
now(void)411 static period_ms_t now(void) {
412   assert(alarms != NULL);
413 
414   struct timespec ts;
415   if (clock_gettime(CLOCK_ID, &ts) == -1) {
416     LOG_ERROR(LOG_TAG, "%s unable to get current time: %s",
417               __func__, strerror(errno));
418     return 0;
419   }
420 
421   return (ts.tv_sec * 1000LL) + (ts.tv_nsec / 1000000LL);
422 }
423 
424 // Remove alarm from internal alarm list and the processing queue
425 // The caller must hold the |monitor| lock.
remove_pending_alarm(alarm_t * alarm)426 static void remove_pending_alarm(alarm_t *alarm) {
427   list_remove(alarms, alarm);
428   while (fixed_queue_try_remove_from_queue(alarm->queue, alarm) != NULL) {
429     // Remove all repeated alarm instances from the queue.
430     // NOTE: We are defensive here - we shouldn't have repeated alarm instances
431   }
432 }
433 
434 // Must be called with monitor held
schedule_next_instance(alarm_t * alarm)435 static void schedule_next_instance(alarm_t *alarm) {
436   // If the alarm is currently set and it's at the start of the list,
437   // we'll need to re-schedule since we've adjusted the earliest deadline.
438   bool needs_reschedule = (!list_is_empty(alarms) && list_front(alarms) == alarm);
439   if (alarm->callback)
440     remove_pending_alarm(alarm);
441 
442   // Calculate the next deadline for this alarm
443   period_ms_t just_now = now();
444   period_ms_t ms_into_period = 0;
445   if ((alarm->is_periodic) && (alarm->period != 0))
446     ms_into_period = ((just_now - alarm->creation_time) % alarm->period);
447   alarm->deadline = just_now + (alarm->period - ms_into_period);
448 
449   // Add it into the timer list sorted by deadline (earliest deadline first).
450   if (list_is_empty(alarms) ||
451       ((alarm_t *)list_front(alarms))->deadline > alarm->deadline) {
452     list_prepend(alarms, alarm);
453   } else {
454     for (list_node_t *node = list_begin(alarms); node != list_end(alarms); node = list_next(node)) {
455       list_node_t *next = list_next(node);
456       if (next == list_end(alarms) || ((alarm_t *)list_node(next))->deadline > alarm->deadline) {
457         list_insert_after(alarms, node, alarm);
458         break;
459       }
460     }
461   }
462 
463   // If the new alarm has the earliest deadline, we need to re-evaluate our schedule.
464   if (needs_reschedule ||
465       (!list_is_empty(alarms) && list_front(alarms) == alarm)) {
466     reschedule_root_alarm();
467   }
468 }
469 
470 // NOTE: must be called with monitor lock.
reschedule_root_alarm(void)471 static void reschedule_root_alarm(void) {
472   assert(alarms != NULL);
473 
474   const bool timer_was_set = timer_set;
475 
476   // If used in a zeroed state, disarms the timer.
477   struct itimerspec timer_time;
478   memset(&timer_time, 0, sizeof(timer_time));
479 
480   if (list_is_empty(alarms))
481     goto done;
482 
483   const alarm_t *next = list_front(alarms);
484   const int64_t next_expiration = next->deadline - now();
485   if (next_expiration < TIMER_INTERVAL_FOR_WAKELOCK_IN_MS) {
486     if (!timer_set) {
487       if (!wakelock_acquire()) {
488         LOG_ERROR(LOG_TAG, "%s unable to acquire wake lock", __func__);
489         goto done;
490       }
491     }
492 
493     timer_time.it_value.tv_sec = (next->deadline / 1000);
494     timer_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL;
495 
496     // It is entirely unsafe to call timer_settime(2) with a zeroed timerspec
497     // for timers with *_ALARM clock IDs. Although the man page states that the
498     // timer would be canceled, the current behavior (as of Linux kernel 3.17)
499     // is that the callback is issued immediately. The only way to cancel an
500     // *_ALARM timer is to delete the timer. But unfortunately, deleting and
501     // re-creating a timer is rather expensive; every timer_create(2) spawns a
502     // new thread. So we simply set the timer to fire at the largest possible
503     // time.
504     //
505     // If we've reached this code path, we're going to grab a wake lock and
506     // wait for the next timer to fire. In that case, there's no reason to
507     // have a pending wakeup timer so we simply cancel it.
508     struct itimerspec end_of_time;
509     memset(&end_of_time, 0, sizeof(end_of_time));
510     end_of_time.it_value.tv_sec = (time_t)(1LL << (sizeof(time_t) * 8 - 2));
511     timer_settime(wakeup_timer, TIMER_ABSTIME, &end_of_time, NULL);
512   } else {
513     // WARNING: do not attempt to use relative timers with *_ALARM clock IDs
514     // in kernels before 3.17 unless you have the following patch:
515     // https://lkml.org/lkml/2014/7/7/576
516     struct itimerspec wakeup_time;
517     memset(&wakeup_time, 0, sizeof(wakeup_time));
518 
519 
520     wakeup_time.it_value.tv_sec = (next->deadline / 1000);
521     wakeup_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL;
522     if (timer_settime(wakeup_timer, TIMER_ABSTIME, &wakeup_time, NULL) == -1)
523       LOG_ERROR(LOG_TAG, "%s unable to set wakeup timer: %s",
524                 __func__, strerror(errno));
525   }
526 
527 done:
528   timer_set = timer_time.it_value.tv_sec != 0 || timer_time.it_value.tv_nsec != 0;
529   if (timer_was_set && !timer_set) {
530     wakelock_release();
531   }
532 
533   if (timer_settime(timer, TIMER_ABSTIME, &timer_time, NULL) == -1)
534     LOG_ERROR(LOG_TAG, "%s unable to set timer: %s", __func__, strerror(errno));
535 
536   // If next expiration was in the past (e.g. short timer that got context
537   // switched) then the timer might have diarmed itself. Detect this case and
538   // work around it by manually signalling the |alarm_expired| semaphore.
539   //
540   // It is possible that the timer was actually super short (a few
541   // milliseconds) and the timer expired normally before we called
542   // |timer_gettime|. Worst case, |alarm_expired| is signaled twice for that
543   // alarm. Nothing bad should happen in that case though since the callback
544   // dispatch function checks to make sure the timer at the head of the list
545   // actually expired.
546   if (timer_set) {
547     struct itimerspec time_to_expire;
548     timer_gettime(timer, &time_to_expire);
549     if (time_to_expire.it_value.tv_sec == 0 &&
550         time_to_expire.it_value.tv_nsec == 0) {
551       LOG_DEBUG(LOG_TAG, "%s alarm expiration too close for posix timers, switching to guns", __func__);
552       semaphore_post(alarm_expired);
553     }
554   }
555 }
556 
alarm_register_processing_queue(fixed_queue_t * queue,thread_t * thread)557 void alarm_register_processing_queue(fixed_queue_t *queue, thread_t *thread) {
558   assert(queue != NULL);
559   assert(thread != NULL);
560 
561   fixed_queue_register_dequeue(queue, thread_get_reactor(thread),
562                                alarm_queue_ready, NULL);
563 }
564 
alarm_unregister_processing_queue(fixed_queue_t * queue)565 void alarm_unregister_processing_queue(fixed_queue_t *queue) {
566   assert(alarms != NULL);
567   assert(queue != NULL);
568 
569   fixed_queue_unregister_dequeue(queue);
570 
571   // Cancel all alarms that are using this queue
572   pthread_mutex_lock(&monitor);
573   for (list_node_t *node = list_begin(alarms); node != list_end(alarms); ) {
574     alarm_t *alarm = (alarm_t *)list_node(node);
575     node = list_next(node);
576     // TODO: Each module is responsible for tearing down its alarms; currently,
577     // this is not the case. In the future, this check should be replaced by
578     // an assert.
579     if (alarm->queue == queue)
580       alarm_cancel_internal(alarm);
581   }
582   pthread_mutex_unlock(&monitor);
583 }
584 
alarm_queue_ready(fixed_queue_t * queue,UNUSED_ATTR void * context)585 static void alarm_queue_ready(fixed_queue_t *queue,
586                               UNUSED_ATTR void *context) {
587   assert(queue != NULL);
588 
589   pthread_mutex_lock(&monitor);
590   alarm_t *alarm = (alarm_t *)fixed_queue_try_dequeue(queue);
591   if (alarm == NULL) {
592     pthread_mutex_unlock(&monitor);
593     return;             // The alarm was probably canceled
594   }
595 
596   //
597   // If the alarm is not periodic, we've fully serviced it now, and can reset
598   // some of its internal state. This is useful to distinguish between expired
599   // alarms and active ones.
600   //
601   alarm_callback_t callback = alarm->callback;
602   void *data = alarm->data;
603   period_ms_t deadline = alarm->deadline;
604   if (alarm->is_periodic) {
605     // The periodic alarm has been rescheduled and alarm->deadline has been
606     // updated, hence we need to use the previous deadline.
607     deadline = alarm->prev_deadline;
608   } else {
609     alarm->deadline = 0;
610     alarm->callback = NULL;
611     alarm->data = NULL;
612   }
613 
614   pthread_mutex_lock(&alarm->callback_lock);
615   pthread_mutex_unlock(&monitor);
616 
617   period_ms_t t0 = now();
618   callback(data);
619   period_ms_t t1 = now();
620 
621   // Update the statistics
622   assert(t1 >= t0);
623   period_ms_t delta = t1 - t0;
624   update_scheduling_stats(&alarm->stats, t0, deadline, delta);
625 
626   pthread_mutex_unlock(&alarm->callback_lock);
627 }
628 
629 // Callback function for wake alarms and our posix timer
timer_callback(UNUSED_ATTR void * ptr)630 static void timer_callback(UNUSED_ATTR void *ptr) {
631   semaphore_post(alarm_expired);
632 }
633 
634 // Function running on |dispatcher_thread| that performs the following:
635 //   (1) Receives a signal using |alarm_exired| that the alarm has expired
636 //   (2) Dispatches the alarm callback for processing by the corresponding
637 // thread for that alarm.
callback_dispatch(UNUSED_ATTR void * context)638 static void callback_dispatch(UNUSED_ATTR void *context) {
639   while (true) {
640     semaphore_wait(alarm_expired);
641     if (!dispatcher_thread_active)
642       break;
643 
644     pthread_mutex_lock(&monitor);
645     alarm_t *alarm;
646 
647     // Take into account that the alarm may get cancelled before we get to it.
648     // We're done here if there are no alarms or the alarm at the front is in
649     // the future. Release the monitor lock and exit right away since there's
650     // nothing left to do.
651     if (list_is_empty(alarms) ||
652         (alarm = list_front(alarms))->deadline > now()) {
653       reschedule_root_alarm();
654       pthread_mutex_unlock(&monitor);
655       continue;
656     }
657 
658     list_remove(alarms, alarm);
659 
660     if (alarm->is_periodic) {
661       alarm->prev_deadline = alarm->deadline;
662       schedule_next_instance(alarm);
663       alarm->stats.rescheduled_count++;
664     }
665     reschedule_root_alarm();
666 
667     // Enqueue the alarm for processing
668     fixed_queue_enqueue(alarm->queue, alarm);
669 
670     pthread_mutex_unlock(&monitor);
671   }
672 
673   LOG_DEBUG(LOG_TAG, "%s Callback thread exited", __func__);
674 }
675 
timer_create_internal(const clockid_t clock_id,timer_t * timer)676 static bool timer_create_internal(const clockid_t clock_id, timer_t *timer) {
677   assert(timer != NULL);
678 
679   struct sigevent sigevent;
680   memset(&sigevent, 0, sizeof(sigevent));
681   sigevent.sigev_notify = SIGEV_THREAD;
682   sigevent.sigev_notify_function = (void (*)(union sigval))timer_callback;
683   if (timer_create(clock_id, &sigevent, timer) == -1) {
684     LOG_ERROR(LOG_TAG, "%s unable to create timer with clock %d: %s",
685               __func__, clock_id, strerror(errno));
686     if (clock_id == CLOCK_BOOTTIME_ALARM) {
687       LOG_ERROR(LOG_TAG, "The kernel might not have support for timer_create(CLOCK_BOOTTIME_ALARM): https://lwn.net/Articles/429925/");
688       LOG_ERROR(LOG_TAG, "See following patches: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/log/?qt=grep&q=CLOCK_BOOTTIME_ALARM");
689     }
690     return false;
691   }
692 
693   return true;
694 }
695 
update_scheduling_stats(alarm_stats_t * stats,period_ms_t now_ms,period_ms_t deadline_ms,period_ms_t execution_delta_ms)696 static void update_scheduling_stats(alarm_stats_t *stats,
697                                     period_ms_t now_ms,
698                                     period_ms_t deadline_ms,
699                                     period_ms_t execution_delta_ms)
700 {
701   stats->total_updates++;
702   stats->last_update_ms = now_ms;
703 
704   update_stat(&stats->callback_execution, execution_delta_ms);
705 
706   if (deadline_ms < now_ms) {
707     // Overdue scheduling
708     period_ms_t delta_ms = now_ms - deadline_ms;
709     update_stat(&stats->overdue_scheduling, delta_ms);
710   } else if (deadline_ms > now_ms) {
711     // Premature scheduling
712     period_ms_t delta_ms = deadline_ms - now_ms;
713     update_stat(&stats->premature_scheduling, delta_ms);
714   }
715 }
716 
dump_stat(int fd,stat_t * stat,const char * description)717 static void dump_stat(int fd, stat_t *stat, const char *description)
718 {
719     period_ms_t average_time_ms = 0;
720     if (stat->count != 0)
721       average_time_ms = stat->total_ms / stat->count;
722 
723     dprintf(fd, "%-51s: %llu / %llu / %llu\n",
724             description,
725             (unsigned long long)stat->total_ms,
726             (unsigned long long)stat->max_ms,
727             (unsigned long long)average_time_ms);
728 }
729 
alarm_debug_dump(int fd)730 void alarm_debug_dump(int fd)
731 {
732   dprintf(fd, "\nBluetooth Alarms Statistics:\n");
733 
734   pthread_mutex_lock(&monitor);
735 
736   if (alarms == NULL) {
737     pthread_mutex_unlock(&monitor);
738     dprintf(fd, "  None\n");
739     return;
740   }
741 
742   period_ms_t just_now = now();
743 
744   dprintf(fd, "  Total Alarms: %zu\n\n", list_length(alarms));
745 
746   // Dump info for each alarm
747   for (list_node_t *node = list_begin(alarms); node != list_end(alarms);
748        node = list_next(node)) {
749     alarm_t *alarm = (alarm_t *)list_node(node);
750     alarm_stats_t *stats = &alarm->stats;
751 
752     dprintf(fd, "  Alarm : %s (%s)\n", stats->name,
753             (alarm->is_periodic) ? "PERIODIC" : "SINGLE");
754 
755     dprintf(fd, "%-51s: %zu / %zu / %zu / %zu\n",
756             "    Action counts (sched/resched/exec/cancel)",
757             stats->scheduled_count, stats->rescheduled_count,
758             stats->callback_execution.count, stats->canceled_count);
759 
760     dprintf(fd, "%-51s: %zu / %zu\n",
761             "    Deviation counts (overdue/premature)",
762             stats->overdue_scheduling.count,
763             stats->premature_scheduling.count);
764 
765     dprintf(fd, "%-51s: %llu / %llu / %lld\n",
766             "    Time in ms (since creation/interval/remaining)",
767             (unsigned long long)(just_now - alarm->creation_time),
768             (unsigned long long) alarm->period,
769             (long long)(alarm->deadline - just_now));
770 
771     dump_stat(fd, &stats->callback_execution,
772               "    Callback execution time in ms (total/max/avg)");
773 
774     dump_stat(fd, &stats->overdue_scheduling,
775               "    Overdue scheduling time in ms (total/max/avg)");
776 
777     dump_stat(fd, &stats->premature_scheduling,
778               "    Premature scheduling time in ms (total/max/avg)");
779 
780     dprintf(fd, "\n");
781   }
782   pthread_mutex_unlock(&monitor);
783 }
784