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?)
51static const int CALLBACK_THREAD_PRIORITY_HIGH = -19;
52
53typedef 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
60typedef 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
72struct 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.
96int64_t TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 3000;
97static const clockid_t CLOCK_ID = CLOCK_BOOTTIME;
98
99#if defined(KERNEL_MISSING_CLOCK_BOOTTIME_ALARM) && (KERNEL_MISSING_CLOCK_BOOTTIME_ALARM == TRUE)
100static const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME;
101#else
102static 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.
108static pthread_mutex_t monitor;
109static list_t *alarms;
110static timer_t timer;
111static timer_t wakeup_timer;
112static bool timer_set;
113
114// All alarm callbacks are dispatched from |dispatcher_thread|
115static thread_t *dispatcher_thread;
116static bool dispatcher_thread_active;
117static semaphore_t *alarm_expired;
118
119// Default alarm callback thread and queue
120static thread_t *default_callback_thread;
121static fixed_queue_t *default_callback_queue;
122
123static alarm_t *alarm_new_internal(const char *name, bool is_periodic);
124static bool lazy_initialize(void);
125static period_ms_t now(void);
126static void alarm_set_internal(alarm_t *alarm, period_ms_t period,
127                               alarm_callback_t cb, void *data,
128                               fixed_queue_t *queue);
129static void alarm_cancel_internal(alarm_t *alarm);
130static void remove_pending_alarm(alarm_t *alarm);
131static void schedule_next_instance(alarm_t *alarm);
132static void reschedule_root_alarm(void);
133static void alarm_queue_ready(fixed_queue_t *queue, void *context);
134static void timer_callback(void *data);
135static void callback_dispatch(void *context);
136static bool timer_create_internal(const clockid_t clock_id, timer_t *timer);
137static 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
142static 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
150alarm_t *alarm_new(const char *name) {
151  return alarm_new_internal(name, false);
152}
153
154alarm_t *alarm_new_periodic(const char *name) {
155  return alarm_new_internal(name, true);
156}
157
158static 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
195error:
196  pthread_mutexattr_destroy(&attr);
197  osi_free(ret);
198  return NULL;
199}
200
201void 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
211period_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
224void 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
229void 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.
237static 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
258void 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.
274static 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
290bool alarm_is_scheduled(const alarm_t *alarm) {
291  if ((alarms == NULL) || (alarm == NULL))
292    return false;
293  return (alarm->callback != NULL);
294}
295
296void 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
325static 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
383error:
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
411static 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.
426static 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
435static 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.
471static 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
527done:
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
557void 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
565void 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
585static 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
630static 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.
638static 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
676static 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
696static 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
717static 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
730void 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