alarm.c revision d2e250824fca5c42b87b3b6f5fa19646ffa2d321
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#define LOG_TAG "bt_osi_alarm" 20 21#include "osi/include/alarm.h" 22 23#include <assert.h> 24#include <errno.h> 25#include <fcntl.h> 26#include <inttypes.h> 27#include <malloc.h> 28#include <pthread.h> 29#include <signal.h> 30#include <string.h> 31#include <time.h> 32 33#include <hardware/bluetooth.h> 34 35#include "osi/include/allocator.h" 36#include "osi/include/list.h" 37#include "osi/include/log.h" 38#include "osi/include/osi.h" 39#include "osi/include/semaphore.h" 40#include "osi/include/thread.h" 41#include "osi/include/wakelock.h" 42 43// Make callbacks run at high thread priority. Some callbacks are used for audio 44// related timer tasks as well as re-transmissions etc. Since we at this point 45// cannot differentiate what callback we are dealing with, assume high priority 46// for now. 47// TODO(eisenbach): Determine correct thread priority (from parent?/per alarm?) 48static const int CALLBACK_THREAD_PRIORITY_HIGH = -19; 49 50struct alarm_t { 51 // The lock is held while the callback for this alarm is being executed. 52 // It allows us to release the coarse-grained monitor lock while a potentially 53 // long-running callback is executing. |alarm_cancel| uses this lock to provide 54 // a guarantee to its caller that the callback will not be in progress when it 55 // returns. 56 pthread_mutex_t callback_lock; 57 period_ms_t creation_time; 58 period_ms_t period; 59 period_ms_t deadline; 60 bool is_periodic; 61 alarm_callback_t callback; 62 void *data; 63}; 64 65 66// If the next wakeup time is less than this threshold, we should acquire 67// a wakelock instead of setting a wake alarm so we're not bouncing in 68// and out of suspend frequently. This value is externally visible to allow 69// unit tests to run faster. It should not be modified by production code. 70int64_t TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 3000; 71static const clockid_t CLOCK_ID = CLOCK_BOOTTIME; 72static const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME_ALARM; 73 74// This mutex ensures that the |alarm_set|, |alarm_cancel|, and alarm callback 75// functions execute serially and not concurrently. As a result, this mutex also 76// protects the |alarms| list. 77static pthread_mutex_t monitor; 78static list_t *alarms; 79static timer_t timer; 80static timer_t wakeup_timer; 81static bool timer_set; 82 83// All alarm callbacks are dispatched from |callback_thread| 84static thread_t *callback_thread; 85static bool callback_thread_active; 86static semaphore_t *alarm_expired; 87 88static bool lazy_initialize(void); 89static period_ms_t now(void); 90static void alarm_set_internal(alarm_t *alarm, period_ms_t deadline, alarm_callback_t cb, void *data, bool is_periodic); 91static void schedule_next_instance(alarm_t *alarm, bool force_reschedule); 92static void reschedule_root_alarm(void); 93static void timer_callback(void *data); 94static void callback_dispatch(void *context); 95static bool timer_create_internal(const clockid_t clock_id, timer_t *timer); 96 97alarm_t *alarm_new(void) { 98 // Make sure we have a list we can insert alarms into. 99 if (!alarms && !lazy_initialize()) { 100 assert(false); // if initialization failed, we should not continue 101 return NULL; 102 } 103 104 pthread_mutexattr_t attr; 105 pthread_mutexattr_init(&attr); 106 107 alarm_t *ret = osi_calloc(sizeof(alarm_t)); 108 if (!ret) { 109 LOG_ERROR(LOG_TAG, "%s unable to allocate memory for alarm.", __func__); 110 goto error; 111 } 112 113 // Make this a recursive mutex to make it safe to call |alarm_cancel| from 114 // within the callback function of the alarm. 115 int error = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 116 if (error) { 117 LOG_ERROR(LOG_TAG, "%s unable to create a recursive mutex: %s", __func__, strerror(error)); 118 goto error; 119 } 120 121 error = pthread_mutex_init(&ret->callback_lock, &attr); 122 if (error) { 123 LOG_ERROR(LOG_TAG, "%s unable to initialize mutex: %s", __func__, strerror(error)); 124 goto error; 125 } 126 127 pthread_mutexattr_destroy(&attr); 128 return ret; 129 130error:; 131 pthread_mutexattr_destroy(&attr); 132 osi_free(ret); 133 return NULL; 134} 135 136void alarm_free(alarm_t *alarm) { 137 if (!alarm) 138 return; 139 140 alarm_cancel(alarm); 141 pthread_mutex_destroy(&alarm->callback_lock); 142 osi_free(alarm); 143} 144 145period_ms_t alarm_get_remaining_ms(const alarm_t *alarm) { 146 assert(alarm != NULL); 147 period_ms_t remaining_ms = 0; 148 149 pthread_mutex_lock(&monitor); 150 if (alarm->deadline) 151 remaining_ms = alarm->deadline - now(); 152 pthread_mutex_unlock(&monitor); 153 154 return remaining_ms; 155} 156 157void alarm_set(alarm_t *alarm, period_ms_t deadline, alarm_callback_t cb, void *data) { 158 alarm_set_internal(alarm, deadline, cb, data, false); 159} 160 161void alarm_set_periodic(alarm_t *alarm, period_ms_t period, alarm_callback_t cb, void *data) { 162 alarm_set_internal(alarm, period, cb, data, true); 163} 164 165// Runs in exclusion with alarm_cancel and timer_callback. 166static void alarm_set_internal(alarm_t *alarm, period_ms_t period, alarm_callback_t cb, void *data, bool is_periodic) { 167 assert(alarms != NULL); 168 assert(alarm != NULL); 169 assert(cb != NULL); 170 171 pthread_mutex_lock(&monitor); 172 173 alarm->creation_time = now(); 174 alarm->is_periodic = is_periodic; 175 alarm->period = period; 176 alarm->callback = cb; 177 alarm->data = data; 178 179 schedule_next_instance(alarm, false); 180 181 pthread_mutex_unlock(&monitor); 182} 183 184void alarm_cancel(alarm_t *alarm) { 185 assert(alarms != NULL); 186 assert(alarm != NULL); 187 188 pthread_mutex_lock(&monitor); 189 190 bool needs_reschedule = (!list_is_empty(alarms) && list_front(alarms) == alarm); 191 192 list_remove(alarms, alarm); 193 alarm->deadline = 0; 194 alarm->callback = NULL; 195 alarm->data = NULL; 196 197 if (needs_reschedule) 198 reschedule_root_alarm(); 199 200 pthread_mutex_unlock(&monitor); 201 202 // If the callback for |alarm| is in progress, wait here until it completes. 203 pthread_mutex_lock(&alarm->callback_lock); 204 pthread_mutex_unlock(&alarm->callback_lock); 205} 206 207void alarm_cleanup(void) { 208 // If lazy_initialize never ran there is nothing else to do 209 if (!alarms) 210 return; 211 212 callback_thread_active = false; 213 semaphore_post(alarm_expired); 214 thread_free(callback_thread); 215 callback_thread = NULL; 216 217 semaphore_free(alarm_expired); 218 alarm_expired = NULL; 219 timer_delete(&timer); 220 list_free(alarms); 221 alarms = NULL; 222 223 pthread_mutex_destroy(&monitor); 224} 225 226static bool lazy_initialize(void) { 227 assert(alarms == NULL); 228 229 // timer_t doesn't have an invalid value so we must track whether 230 // the |timer| variable is valid ourselves. 231 bool timer_initialized = false; 232 bool wakeup_timer_initialized = false; 233 234 pthread_mutex_init(&monitor, NULL); 235 236 alarms = list_new(NULL); 237 if (!alarms) { 238 LOG_ERROR(LOG_TAG, "%s unable to allocate alarm list.", __func__); 239 goto error; 240 } 241 242 if (!timer_create_internal(CLOCK_ID, &timer)) 243 goto error; 244 timer_initialized = true; 245 246 if (!timer_create_internal(CLOCK_ID_ALARM, &wakeup_timer)) 247 goto error; 248 wakeup_timer_initialized = true; 249 250 alarm_expired = semaphore_new(0); 251 if (!alarm_expired) { 252 LOG_ERROR(LOG_TAG, "%s unable to create alarm expired semaphore", __func__); 253 goto error; 254 } 255 256 callback_thread_active = true; 257 callback_thread = thread_new("alarm_callbacks"); 258 if (!callback_thread) { 259 LOG_ERROR(LOG_TAG, "%s unable to create alarm callback thread.", __func__); 260 goto error; 261 } 262 263 thread_set_priority(callback_thread, CALLBACK_THREAD_PRIORITY_HIGH); 264 thread_post(callback_thread, callback_dispatch, NULL); 265 return true; 266 267error: 268 thread_free(callback_thread); 269 callback_thread = NULL; 270 271 callback_thread_active = false; 272 273 semaphore_free(alarm_expired); 274 alarm_expired = NULL; 275 276 if (wakeup_timer_initialized) 277 timer_delete(wakeup_timer); 278 279 if (timer_initialized) 280 timer_delete(timer); 281 282 list_free(alarms); 283 alarms = NULL; 284 285 pthread_mutex_destroy(&monitor); 286 287 return false; 288} 289 290static period_ms_t now(void) { 291 assert(alarms != NULL); 292 293 struct timespec ts; 294 if (clock_gettime(CLOCK_ID, &ts) == -1) { 295 LOG_ERROR(LOG_TAG, "%s unable to get current time: %s", __func__, strerror(errno)); 296 return 0; 297 } 298 299 return (ts.tv_sec * 1000LL) + (ts.tv_nsec / 1000000LL); 300} 301 302// Must be called with monitor held 303static void schedule_next_instance(alarm_t *alarm, bool force_reschedule) { 304 // If the alarm is currently set and it's at the start of the list, 305 // we'll need to re-schedule since we've adjusted the earliest deadline. 306 bool needs_reschedule = (!list_is_empty(alarms) && list_front(alarms) == alarm); 307 if (alarm->callback) 308 list_remove(alarms, alarm); 309 310 // Calculate the next deadline for this alarm 311 period_ms_t just_now = now(); 312 period_ms_t ms_into_period = alarm->is_periodic ? ((just_now - alarm->creation_time) % alarm->period) : 0; 313 alarm->deadline = just_now + (alarm->period - ms_into_period); 314 315 // Add it into the timer list sorted by deadline (earliest deadline first). 316 if (list_is_empty(alarms) || ((alarm_t *)list_front(alarms))->deadline >= alarm->deadline) 317 list_prepend(alarms, alarm); 318 else 319 for (list_node_t *node = list_begin(alarms); node != list_end(alarms); node = list_next(node)) { 320 list_node_t *next = list_next(node); 321 if (next == list_end(alarms) || ((alarm_t *)list_node(next))->deadline >= alarm->deadline) { 322 list_insert_after(alarms, node, alarm); 323 break; 324 } 325 } 326 327 // If the new alarm has the earliest deadline, we need to re-evaluate our schedule. 328 if (force_reschedule || needs_reschedule || (!list_is_empty(alarms) && list_front(alarms) == alarm)) 329 reschedule_root_alarm(); 330} 331 332// NOTE: must be called with monitor lock. 333static void reschedule_root_alarm(void) { 334 assert(alarms != NULL); 335 336 const bool timer_was_set = timer_set; 337 338 // If used in a zeroed state, disarms the timer. 339 struct itimerspec timer_time; 340 memset(&timer_time, 0, sizeof(timer_time)); 341 342 if (list_is_empty(alarms)) 343 goto done; 344 345 const alarm_t *next = list_front(alarms); 346 const int64_t next_expiration = next->deadline - now(); 347 if (next_expiration < TIMER_INTERVAL_FOR_WAKELOCK_IN_MS) { 348 if (!timer_set) { 349 if (!wakelock_acquire()) { 350 LOG_ERROR(LOG_TAG, "%s unable to acquire wake lock", __func__); 351 goto done; 352 } 353 } 354 355 timer_time.it_value.tv_sec = (next->deadline / 1000); 356 timer_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL; 357 358 // It is entirely unsafe to call timer_settime(2) with a zeroed timerspec for 359 // timers with *_ALARM clock IDs. Although the man page states that the timer 360 // would be canceled, the current behavior (as of Linux kernel 3.17) is that 361 // the callback is issued immediately. The only way to cancel an *_ALARM timer 362 // is to delete the timer. But unfortunately, deleting and re-creating a timer 363 // is rather expensive; every timer_create(2) spawns a new thread. So we simply 364 // set the timer to fire at the largest possible time. 365 // 366 // If we've reached this code path, we're going to grab a wake lock and wait for 367 // the next timer to fire. In that case, there's no reason to have a pending wakeup 368 // timer so we simply cancel it. 369 struct itimerspec end_of_time; 370 memset(&end_of_time, 0, sizeof(end_of_time)); 371 end_of_time.it_value.tv_sec = (time_t)(1LL << (sizeof(time_t) * 8 - 2)); 372 timer_settime(wakeup_timer, TIMER_ABSTIME, &end_of_time, NULL); 373 } else { 374 // WARNING: do not attempt to use relative timers with *_ALARM clock IDs 375 // in kernels before 3.17 unless you have the following patch: 376 // https://lkml.org/lkml/2014/7/7/576 377 struct itimerspec wakeup_time; 378 memset(&wakeup_time, 0, sizeof(wakeup_time)); 379 380 381 wakeup_time.it_value.tv_sec = (next->deadline / 1000); 382 wakeup_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL; 383 if (timer_settime(wakeup_timer, TIMER_ABSTIME, &wakeup_time, NULL) == -1) 384 LOG_ERROR(LOG_TAG, "%s unable to set wakeup timer: %s", 385 __func__, strerror(errno)); 386 } 387 388done: 389 timer_set = timer_time.it_value.tv_sec != 0 || timer_time.it_value.tv_nsec != 0; 390 if (timer_was_set && !timer_set) { 391 wakelock_release(); 392 } 393 394 if (timer_settime(timer, TIMER_ABSTIME, &timer_time, NULL) == -1) 395 LOG_ERROR(LOG_TAG, "%s unable to set timer: %s", __func__, strerror(errno)); 396 397 // If next expiration was in the past (e.g. short timer that got context switched) 398 // then the timer might have diarmed itself. Detect this case and work around it 399 // by manually signalling the |alarm_expired| semaphore. 400 // 401 // It is possible that the timer was actually super short (a few milliseconds) 402 // and the timer expired normally before we called |timer_gettime|. Worst case, 403 // |alarm_expired| is signaled twice for that alarm. Nothing bad should happen in 404 // that case though since the callback dispatch function checks to make sure the 405 // timer at the head of the list actually expired. 406 if (timer_set) { 407 struct itimerspec time_to_expire; 408 timer_gettime(timer, &time_to_expire); 409 if (time_to_expire.it_value.tv_sec == 0 && time_to_expire.it_value.tv_nsec == 0) { 410 LOG_ERROR(LOG_TAG, "%s alarm expiration too close for posix timers, switching to guns", __func__); 411 semaphore_post(alarm_expired); 412 } 413 } 414} 415 416// Callback function for wake alarms and our posix timer 417static void timer_callback(UNUSED_ATTR void *ptr) { 418 semaphore_post(alarm_expired); 419} 420 421// Function running on |callback_thread| that dispatches alarm callbacks upon 422// alarm expiration, which is signaled using |alarm_expired|. 423static void callback_dispatch(UNUSED_ATTR void *context) { 424 while (true) { 425 semaphore_wait(alarm_expired); 426 if (!callback_thread_active) 427 break; 428 429 pthread_mutex_lock(&monitor); 430 alarm_t *alarm; 431 432 // Take into account that the alarm may get cancelled before we get to it. 433 // We're done here if there are no alarms or the alarm at the front is in 434 // the future. Release the monitor lock and exit right away since there's 435 // nothing left to do. 436 if (list_is_empty(alarms) || (alarm = list_front(alarms))->deadline > now()) { 437 reschedule_root_alarm(); 438 pthread_mutex_unlock(&monitor); 439 continue; 440 } 441 442 list_remove(alarms, alarm); 443 444 alarm_callback_t callback = alarm->callback; 445 void *data = alarm->data; 446 447 if (alarm->is_periodic) { 448 schedule_next_instance(alarm, true); 449 } else { 450 reschedule_root_alarm(); 451 452 alarm->deadline = 0; 453 alarm->callback = NULL; 454 alarm->data = NULL; 455 } 456 457 // Downgrade lock. 458 pthread_mutex_lock(&alarm->callback_lock); 459 pthread_mutex_unlock(&monitor); 460 461 callback(data); 462 463 pthread_mutex_unlock(&alarm->callback_lock); 464 } 465 466 LOG_DEBUG(LOG_TAG, "%s Callback thread exited", __func__); 467} 468 469static bool timer_create_internal(const clockid_t clock_id, timer_t *timer) { 470 assert(timer != NULL); 471 472 struct sigevent sigevent; 473 memset(&sigevent, 0, sizeof(sigevent)); 474 sigevent.sigev_notify = SIGEV_THREAD; 475 sigevent.sigev_notify_function = (void (*)(union sigval))timer_callback; 476 if (timer_create(clock_id, &sigevent, timer) == -1) { 477 LOG_ERROR(LOG_TAG, "%s unable to create timer with clock %d: %s", 478 __func__, clock_id, strerror(errno)); 479 return false; 480 } 481 482 return true; 483} 484