alarm.cc revision b55040cc6448a8847490da807d2b6362aa8cb8d9
1f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati/****************************************************************************** 2f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * 3f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * Copyright (C) 2014 Google, Inc. 4f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * 5f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * Licensed under the Apache License, Version 2.0 (the "License"); 6f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * you may not use this file except in compliance with the License. 7f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * You may obtain a copy of the License at: 8f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * 9f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * http://www.apache.org/licenses/LICENSE-2.0 10f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * 11f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * Unless required by applicable law or agreed to in writing, software 12f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * distributed under the License is distributed on an "AS IS" BASIS, 13f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * See the License for the specific language governing permissions and 15f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * limitations under the License. 16f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * 17f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati ******************************************************************************/ 18f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 1910978011f286d20f10eb949e3557ad00a62c8424Pavlin Radoslavov#include "include/bt_target.h" 2010978011f286d20f10eb949e3557ad00a62c8424Pavlin Radoslavov 21f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati#define LOG_TAG "bt_osi_alarm" 22f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 2349a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen#include "osi/include/alarm.h" 2449a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen 25f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati#include <assert.h> 26f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati#include <errno.h> 2728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen#include <fcntl.h> 281afbe154a89ad462de739704ce70eed0e32cbc00Michael Wright#include <inttypes.h> 29b9164f414b4d8d414358d0146a8f911207af3122Elliott Hughes#include <malloc.h> 3049a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen#include <pthread.h> 31468e4b983dd59ea58a7518032fa6029b00c56dc4Ian Coolidge#include <signal.h> 3249a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen#include <string.h> 33f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati#include <time.h> 34f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 3549a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen#include <hardware/bluetooth.h> 3649a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen 37081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson#include "osi/include/allocator.h" 3878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov#include "osi/include/fixed_queue.h" 390f9b91e150e153229235c163861198e23600e636Sharvil Nanavati#include "osi/include/list.h" 4044802768c447ab480d4227b3a852a97d923b816dSharvil Nanavati#include "osi/include/log.h" 41081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson#include "osi/include/osi.h" 42081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson#include "osi/include/semaphore.h" 43081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson#include "osi/include/thread.h" 44d2e250824fca5c42b87b3b6f5fa19646ffa2d321Pavlin Radoslavov#include "osi/include/wakelock.h" 45f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 4641a91a52b06171140938a1aa503bab8fe15e12e4Andre Eisenbach// Make callbacks run at high thread priority. Some callbacks are used for audio 4741a91a52b06171140938a1aa503bab8fe15e12e4Andre Eisenbach// related timer tasks as well as re-transmissions etc. Since we at this point 4841a91a52b06171140938a1aa503bab8fe15e12e4Andre Eisenbach// cannot differentiate what callback we are dealing with, assume high priority 4941a91a52b06171140938a1aa503bab8fe15e12e4Andre Eisenbach// for now. 5041a91a52b06171140938a1aa503bab8fe15e12e4Andre Eisenbach// TODO(eisenbach): Determine correct thread priority (from parent?/per alarm?) 5141a91a52b06171140938a1aa503bab8fe15e12e4Andre Eisenbachstatic const int CALLBACK_THREAD_PRIORITY_HIGH = -19; 5241a91a52b06171140938a1aa503bab8fe15e12e4Andre Eisenbach 5378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovtypedef struct { 5478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov size_t count; 5578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t total_ms; 5678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t max_ms; 5778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} stat_t; 5878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 5978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// Alarm-related information and statistics 6078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovtypedef struct { 61b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson const char* name; 6278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov size_t scheduled_count; 6378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov size_t canceled_count; 6478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov size_t rescheduled_count; 6578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov size_t total_updates; 6678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t last_update_ms; 6778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stat_t callback_execution; 6878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stat_t overdue_scheduling; 6978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stat_t premature_scheduling; 7078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} alarm_stats_t; 7178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 72f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistruct alarm_t { 73f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati // The lock is held while the callback for this alarm is being executed. 7478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // It allows us to release the coarse-grained monitor lock while a 7578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // potentially long-running callback is executing. |alarm_cancel| uses this 7678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // lock to provide a guarantee to its caller that the callback will not be 7778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // in progress when it returns. 78f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati pthread_mutex_t callback_lock; 79f2bf2308e90386754080a4fd7cc2ee7751eeab46Sharvil Nanavati period_ms_t creation_time; 80e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson period_ms_t period; 81f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati period_ms_t deadline; 82b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson period_ms_t prev_deadline; // Previous deadline - used for accounting of 83b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson // periodic timers 84e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson bool is_periodic; 85b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson fixed_queue_t* queue; // The processing queue to add this alarm to 86f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm_callback_t callback; 87b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson void* data; 8878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_stats_t stats; 89f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati}; 90f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 91f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati// If the next wakeup time is less than this threshold, we should acquire 92f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati// a wakelock instead of setting a wake alarm so we're not bouncing in 93f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati// and out of suspend frequently. This value is externally visible to allow 94f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati// unit tests to run faster. It should not be modified by production code. 95f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatiint64_t TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 3000; 96f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic const clockid_t CLOCK_ID = CLOCK_BOOTTIME; 9710978011f286d20f10eb949e3557ad00a62c8424Pavlin Radoslavov 98d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen#if (KERNEL_MISSING_CLOCK_BOOTTIME_ALARM == TRUE) 9910978011f286d20f10eb949e3557ad00a62c8424Pavlin Radoslavovstatic const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME; 10010978011f286d20f10eb949e3557ad00a62c8424Pavlin Radoslavov#else 10128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssenstatic const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME_ALARM; 10210978011f286d20f10eb949e3557ad00a62c8424Pavlin Radoslavov#endif 103f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 104f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati// This mutex ensures that the |alarm_set|, |alarm_cancel|, and alarm callback 10578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// functions execute serially and not concurrently. As a result, this mutex 10678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// also protects the |alarms| list. 107f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic pthread_mutex_t monitor; 108b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic list_t* alarms; 109f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic timer_t timer; 11028bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssenstatic timer_t wakeup_timer; 111f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic bool timer_set; 112f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 11378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// All alarm callbacks are dispatched from |dispatcher_thread| 114b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic thread_t* dispatcher_thread; 11578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovstatic bool dispatcher_thread_active; 116b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic semaphore_t* alarm_expired; 117081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 11878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// Default alarm callback thread and queue 119b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic thread_t* default_callback_thread; 120b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic fixed_queue_t* default_callback_queue; 12178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 122b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic alarm_t* alarm_new_internal(const char* name, bool is_periodic); 123f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic bool lazy_initialize(void); 124f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic period_ms_t now(void); 125b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void alarm_set_internal(alarm_t* alarm, period_ms_t period, 126b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_callback_t cb, void* data, 127b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson fixed_queue_t* queue); 128b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void alarm_cancel_internal(alarm_t* alarm); 129b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void remove_pending_alarm(alarm_t* alarm); 130b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void schedule_next_instance(alarm_t* alarm); 131e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnsonstatic void reschedule_root_alarm(void); 132b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void alarm_queue_ready(fixed_queue_t* queue, void* context); 133b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void timer_callback(void* data); 134b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void callback_dispatch(void* context); 135b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic bool timer_create_internal(const clockid_t clock_id, timer_t* timer); 136b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void update_scheduling_stats(alarm_stats_t* stats, period_ms_t now_ms, 13778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t deadline_ms, 13878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t execution_delta_ms); 13978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 140b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void update_stat(stat_t* stat, period_ms_t delta) { 141b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (stat->max_ms < delta) stat->max_ms = delta; 14278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stat->total_ms += delta; 14378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stat->count++; 14478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 145f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 146b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonalarm_t* alarm_new(const char* name) { return alarm_new_internal(name, false); } 14778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 148b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonalarm_t* alarm_new_periodic(const char* name) { 14978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov return alarm_new_internal(name, true); 15078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 15178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 152b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic alarm_t* alarm_new_internal(const char* name, bool is_periodic) { 153f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati // Make sure we have a list we can insert alarms into. 15428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen if (!alarms && !lazy_initialize()) { 155b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson assert(false); // if initialization failed, we should not continue 156f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati return NULL; 15728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen } 158f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 159f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati pthread_mutexattr_t attr; 160f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati pthread_mutexattr_init(&attr); 161f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 162b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_t* ret = static_cast<alarm_t*>(osi_calloc(sizeof(alarm_t))); 163f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 164f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati // Make this a recursive mutex to make it safe to call |alarm_cancel| from 165f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati // within the callback function of the alarm. 166f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati int error = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 167f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati if (error) { 168b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_ERROR(LOG_TAG, "%s unable to create a recursive mutex: %s", __func__, 169b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson strerror(error)); 170f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati goto error; 171f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 172f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 173f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati error = pthread_mutex_init(&ret->callback_lock, &attr); 174f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati if (error) { 175b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_ERROR(LOG_TAG, "%s unable to initialize mutex: %s", __func__, 176b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson strerror(error)); 177f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati goto error; 178f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 179f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 18078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov ret->is_periodic = is_periodic; 181b2a292b5d8df2f359c38b0787bc01181225a9bc9Pavlin Radoslavov ret->stats.name = osi_strdup(name); 18278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // NOTE: The stats were reset by osi_calloc() above 18378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 184f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati pthread_mutexattr_destroy(&attr); 185f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati return ret; 186f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 18778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavoverror: 188f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati pthread_mutexattr_destroy(&attr); 189ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson osi_free(ret); 190f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati return NULL; 191f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 192f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 193b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid alarm_free(alarm_t* alarm) { 194b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!alarm) return; 195f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 196f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm_cancel(alarm); 197f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati pthread_mutex_destroy(&alarm->callback_lock); 198b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson osi_free((void*)alarm->stats.name); 199ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson osi_free(alarm); 200f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 201f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 202b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonperiod_ms_t alarm_get_remaining_ms(const alarm_t* alarm) { 20376356aee883af67898ddc1aa3b628195f396d42aVenkatRaghavan VijayaRaghavan assert(alarm != NULL); 204165332bc6795049754fafe35024c2c605796c96aAndre Eisenbach period_ms_t remaining_ms = 0; 20578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t just_now = now(); 206165332bc6795049754fafe35024c2c605796c96aAndre Eisenbach 207165332bc6795049754fafe35024c2c605796c96aAndre Eisenbach pthread_mutex_lock(&monitor); 208b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (alarm->deadline > just_now) remaining_ms = alarm->deadline - just_now; 209165332bc6795049754fafe35024c2c605796c96aAndre Eisenbach pthread_mutex_unlock(&monitor); 210165332bc6795049754fafe35024c2c605796c96aAndre Eisenbach 211165332bc6795049754fafe35024c2c605796c96aAndre Eisenbach return remaining_ms; 21276356aee883af67898ddc1aa3b628195f396d42aVenkatRaghavan VijayaRaghavan} 21376356aee883af67898ddc1aa3b628195f396d42aVenkatRaghavan VijayaRaghavan 214b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid alarm_set(alarm_t* alarm, period_ms_t interval_ms, alarm_callback_t cb, 215b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson void* data) { 21678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_set_on_queue(alarm, interval_ms, cb, data, default_callback_queue); 21771864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson} 21871864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson 219b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid alarm_set_on_queue(alarm_t* alarm, period_ms_t interval_ms, 220b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_callback_t cb, void* data, fixed_queue_t* queue) { 22178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov assert(queue != NULL); 22278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_set_internal(alarm, interval_ms, cb, data, queue); 22371864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson} 22471864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson 22571864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson// Runs in exclusion with alarm_cancel and timer_callback. 226b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void alarm_set_internal(alarm_t* alarm, period_ms_t period, 227b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_callback_t cb, void* data, 228b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson fixed_queue_t* queue) { 229f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati assert(alarms != NULL); 230f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati assert(alarm != NULL); 231f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati assert(cb != NULL); 232f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 233f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati pthread_mutex_lock(&monitor); 234f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 235f2bf2308e90386754080a4fd7cc2ee7751eeab46Sharvil Nanavati alarm->creation_time = now(); 236e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson alarm->period = period; 23778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->queue = queue; 238f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm->callback = cb; 239f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm->data = data; 240f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 24178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov schedule_next_instance(alarm); 24278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->stats.scheduled_count++; 243f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 244f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati pthread_mutex_unlock(&monitor); 245f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 246f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 247b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid alarm_cancel(alarm_t* alarm) { 248f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati assert(alarms != NULL); 249b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!alarm) return; 250f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 251f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati pthread_mutex_lock(&monitor); 252936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov alarm_cancel_internal(alarm); 253936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov pthread_mutex_unlock(&monitor); 254936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov 255936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov // If the callback for |alarm| is in progress, wait here until it completes. 256936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov pthread_mutex_lock(&alarm->callback_lock); 257936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov pthread_mutex_unlock(&alarm->callback_lock); 258936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov} 259f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 260936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov// Internal implementation of canceling an alarm. 261936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov// The caller must hold the |monitor| lock. 262b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void alarm_cancel_internal(alarm_t* alarm) { 263b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson bool needs_reschedule = 264b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson (!list_is_empty(alarms) && list_front(alarms) == alarm); 265f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 26678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov remove_pending_alarm(alarm); 26778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 268f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm->deadline = 0; 26978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->prev_deadline = 0; 270f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm->callback = NULL; 271f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm->data = NULL; 27278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->stats.canceled_count++; 273936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov alarm->queue = NULL; 274f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 275b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (needs_reschedule) reschedule_root_alarm(); 276f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 277f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 278b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonbool alarm_is_scheduled(const alarm_t* alarm) { 279b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if ((alarms == NULL) || (alarm == NULL)) return false; 28078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov return (alarm->callback != NULL); 28178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 28278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 2830933b4075e16589a073e85d8230677238b29b780Pavlin Radoslavovvoid alarm_cleanup(void) { 2841b2bd2c8b5b7be80cb4ce0ecf4e021ad16e4a540Marie Janssen // If lazy_initialize never ran there is nothing else to do 285b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!alarms) return; 286c6a1c261b87f194b298df01f002292d9e937ec75Zach Johnson 28778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dispatcher_thread_active = false; 288cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach semaphore_post(alarm_expired); 28978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_free(dispatcher_thread); 29078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dispatcher_thread = NULL; 29178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 29293342476cae97c085e3f274a8bf1339b523f7132Pavlin Radoslavov pthread_mutex_lock(&monitor); 29393342476cae97c085e3f274a8bf1339b523f7132Pavlin Radoslavov 29478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov fixed_queue_free(default_callback_queue, NULL); 29578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov default_callback_queue = NULL; 29678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_free(default_callback_thread); 29778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov default_callback_thread = NULL; 298cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach 29993342476cae97c085e3f274a8bf1339b523f7132Pavlin Radoslavov timer_delete(wakeup_timer); 30093342476cae97c085e3f274a8bf1339b523f7132Pavlin Radoslavov timer_delete(timer); 301cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach semaphore_free(alarm_expired); 302cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach alarm_expired = NULL; 30393342476cae97c085e3f274a8bf1339b523f7132Pavlin Radoslavov 304cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach list_free(alarms); 305cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach alarms = NULL; 306cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach 30706d3f477818b66ff1a113c8bf33f9f07f3950d32Pavlin Radoslavov pthread_mutex_unlock(&monitor); 308cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach pthread_mutex_destroy(&monitor); 309cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach} 310cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach 311f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic bool lazy_initialize(void) { 312f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati assert(alarms == NULL); 313f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 31428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // timer_t doesn't have an invalid value so we must track whether 31528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // the |timer| variable is valid ourselves. 31628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen bool timer_initialized = false; 31728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen bool wakeup_timer_initialized = false; 31828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 319f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati pthread_mutex_init(&monitor, NULL); 320f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 321f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarms = list_new(NULL); 322f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati if (!alarms) { 323db554581079863974af8e1289646f5deea6fc044Marie Janssen LOG_ERROR(LOG_TAG, "%s unable to allocate alarm list.", __func__); 32428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen goto error; 325f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 326f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 327b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!timer_create_internal(CLOCK_ID, &timer)) goto error; 32828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen timer_initialized = true; 32928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 330b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!timer_create_internal(CLOCK_ID_ALARM, &wakeup_timer)) goto error; 33128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen wakeup_timer_initialized = true; 332518a94e706a6602ad69245b0d760cd40595109ffZach Johnson 333081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson alarm_expired = semaphore_new(0); 334081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson if (!alarm_expired) { 335db554581079863974af8e1289646f5deea6fc044Marie Janssen LOG_ERROR(LOG_TAG, "%s unable to create alarm expired semaphore", __func__); 33628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen goto error; 337081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson } 338081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 339b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson default_callback_thread = 340b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson thread_new_sized("alarm_default_callbacks", SIZE_MAX); 34178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (default_callback_thread == NULL) { 34278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov LOG_ERROR(LOG_TAG, "%s unable to create default alarm callbacks thread.", 34378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov __func__); 34478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov goto error; 34578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 34678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_set_priority(default_callback_thread, CALLBACK_THREAD_PRIORITY_HIGH); 34778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov default_callback_queue = fixed_queue_new(SIZE_MAX); 34878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (default_callback_queue == NULL) { 34978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov LOG_ERROR(LOG_TAG, "%s unable to create default alarm callbacks queue.", 35078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov __func__); 35178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov goto error; 35278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 35378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_register_processing_queue(default_callback_queue, 35478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov default_callback_thread); 35578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 35678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dispatcher_thread_active = true; 35778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dispatcher_thread = thread_new("alarm_dispatcher"); 35878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (!dispatcher_thread) { 359db554581079863974af8e1289646f5deea6fc044Marie Janssen LOG_ERROR(LOG_TAG, "%s unable to create alarm callback thread.", __func__); 36028bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen goto error; 361f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 362f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 36378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_set_priority(dispatcher_thread, CALLBACK_THREAD_PRIORITY_HIGH); 36478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_post(dispatcher_thread, callback_dispatch, NULL); 365f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati return true; 36628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 36728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssenerror: 36878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov fixed_queue_free(default_callback_queue, NULL); 36978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov default_callback_queue = NULL; 37078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_free(default_callback_thread); 37178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov default_callback_thread = NULL; 37228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 37378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_free(dispatcher_thread); 37478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dispatcher_thread = NULL; 37578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 37678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dispatcher_thread_active = false; 37728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 37828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen semaphore_free(alarm_expired); 37928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen alarm_expired = NULL; 38028bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 381b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (wakeup_timer_initialized) timer_delete(wakeup_timer); 38228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 383b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (timer_initialized) timer_delete(timer); 38428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 38528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen list_free(alarms); 38628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen alarms = NULL; 38728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 38828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen pthread_mutex_destroy(&monitor); 38928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 39028bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen return false; 391f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 392f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 393f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic period_ms_t now(void) { 394f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati assert(alarms != NULL); 395f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 396f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati struct timespec ts; 397f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati if (clock_gettime(CLOCK_ID, &ts) == -1) { 398b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_ERROR(LOG_TAG, "%s unable to get current time: %s", __func__, 399b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson strerror(errno)); 400f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati return 0; 401f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 402f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 403f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati return (ts.tv_sec * 1000LL) + (ts.tv_nsec / 1000000LL); 404f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 405f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 40678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// Remove alarm from internal alarm list and the processing queue 40778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// The caller must hold the |monitor| lock. 408b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void remove_pending_alarm(alarm_t* alarm) { 40978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov list_remove(alarms, alarm); 41078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov while (fixed_queue_try_remove_from_queue(alarm->queue, alarm) != NULL) { 41178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // Remove all repeated alarm instances from the queue. 41278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // NOTE: We are defensive here - we shouldn't have repeated alarm instances 41378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 41478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 41578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 41671864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson// Must be called with monitor held 417b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void schedule_next_instance(alarm_t* alarm) { 41871864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson // If the alarm is currently set and it's at the start of the list, 41971864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson // we'll need to re-schedule since we've adjusted the earliest deadline. 420b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson bool needs_reschedule = 421b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson (!list_is_empty(alarms) && list_front(alarms) == alarm); 422b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (alarm->callback) remove_pending_alarm(alarm); 423f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 424e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson // Calculate the next deadline for this alarm 425e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson period_ms_t just_now = now(); 42678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t ms_into_period = 0; 427399f217fddd4ce195ada3b69575caeca74ca1314Pavlin Radoslavov if ((alarm->is_periodic) && (alarm->period != 0)) 42878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov ms_into_period = ((just_now - alarm->creation_time) % alarm->period); 429e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson alarm->deadline = just_now + (alarm->period - ms_into_period); 430f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 43171864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson // Add it into the timer list sorted by deadline (earliest deadline first). 43278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (list_is_empty(alarms) || 433b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson ((alarm_t*)list_front(alarms))->deadline > alarm->deadline) { 43471864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson list_prepend(alarms, alarm); 43578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } else { 436b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson for (list_node_t* node = list_begin(alarms); node != list_end(alarms); 437b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson node = list_next(node)) { 438b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson list_node_t* next = list_next(node); 439b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (next == list_end(alarms) || 440b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson ((alarm_t*)list_node(next))->deadline > alarm->deadline) { 44171864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson list_insert_after(alarms, node, alarm); 44271864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson break; 44371864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson } 44471864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson } 44578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 446f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 447b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson // If the new alarm has the earliest deadline, we need to re-evaluate our 448b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson // schedule. 44978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (needs_reschedule || 45078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov (!list_is_empty(alarms) && list_front(alarms) == alarm)) { 451e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson reschedule_root_alarm(); 45278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 453f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 454f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 455f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati// NOTE: must be called with monitor lock. 456e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnsonstatic void reschedule_root_alarm(void) { 457f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati assert(alarms != NULL); 458f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 45928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen const bool timer_was_set = timer_set; 460b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_t* next; 461b2a292b5d8df2f359c38b0787bc01181225a9bc9Pavlin Radoslavov int64_t next_expiration; 46228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 46328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // If used in a zeroed state, disarms the timer. 46428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen struct itimerspec timer_time; 46528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen memset(&timer_time, 0, sizeof(timer_time)); 466f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 467b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (list_is_empty(alarms)) goto done; 468f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 469b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson next = static_cast<alarm_t*>(list_front(alarms)); 470b2a292b5d8df2f359c38b0787bc01181225a9bc9Pavlin Radoslavov next_expiration = next->deadline - now(); 471518a94e706a6602ad69245b0d760cd40595109ffZach Johnson if (next_expiration < TIMER_INTERVAL_FOR_WAKELOCK_IN_MS) { 472518a94e706a6602ad69245b0d760cd40595109ffZach Johnson if (!timer_set) { 473d2e250824fca5c42b87b3b6f5fa19646ffa2d321Pavlin Radoslavov if (!wakelock_acquire()) { 47428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen LOG_ERROR(LOG_TAG, "%s unable to acquire wake lock", __func__); 475518a94e706a6602ad69245b0d760cd40595109ffZach Johnson goto done; 47671864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson } 477f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 478f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 47928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen timer_time.it_value.tv_sec = (next->deadline / 1000); 48028bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen timer_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL; 48128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 48278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // It is entirely unsafe to call timer_settime(2) with a zeroed timerspec 48378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // for timers with *_ALARM clock IDs. Although the man page states that the 48478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // timer would be canceled, the current behavior (as of Linux kernel 3.17) 48578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // is that the callback is issued immediately. The only way to cancel an 48678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // *_ALARM timer is to delete the timer. But unfortunately, deleting and 48778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // re-creating a timer is rather expensive; every timer_create(2) spawns a 48878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // new thread. So we simply set the timer to fire at the largest possible 48978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // time. 49028bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // 49178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // If we've reached this code path, we're going to grab a wake lock and 49278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // wait for the next timer to fire. In that case, there's no reason to 49378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // have a pending wakeup timer so we simply cancel it. 49428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen struct itimerspec end_of_time; 49528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen memset(&end_of_time, 0, sizeof(end_of_time)); 49628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen end_of_time.it_value.tv_sec = (time_t)(1LL << (sizeof(time_t) * 8 - 2)); 49728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen timer_settime(wakeup_timer, TIMER_ABSTIME, &end_of_time, NULL); 49828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen } else { 49928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // WARNING: do not attempt to use relative timers with *_ALARM clock IDs 50028bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // in kernels before 3.17 unless you have the following patch: 50128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // https://lkml.org/lkml/2014/7/7/576 50228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen struct itimerspec wakeup_time; 50328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen memset(&wakeup_time, 0, sizeof(wakeup_time)); 50428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 505f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati wakeup_time.it_value.tv_sec = (next->deadline / 1000); 506f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati wakeup_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL; 50728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen if (timer_settime(wakeup_timer, TIMER_ABSTIME, &wakeup_time, NULL) == -1) 508b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_ERROR(LOG_TAG, "%s unable to set wakeup timer: %s", __func__, 509b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson strerror(errno)); 510f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 511f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 512518a94e706a6602ad69245b0d760cd40595109ffZach Johnsondone: 513b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson timer_set = 514b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson timer_time.it_value.tv_sec != 0 || timer_time.it_value.tv_nsec != 0; 5154be4396c8e4dc4c308219bdf402447a7feefe73ePavlin Radoslavov if (timer_was_set && !timer_set) { 516d2e250824fca5c42b87b3b6f5fa19646ffa2d321Pavlin Radoslavov wakelock_release(); 517f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 518f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 51928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen if (timer_settime(timer, TIMER_ABSTIME, &timer_time, NULL) == -1) 520db554581079863974af8e1289646f5deea6fc044Marie Janssen LOG_ERROR(LOG_TAG, "%s unable to set timer: %s", __func__, strerror(errno)); 521081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 52278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // If next expiration was in the past (e.g. short timer that got context 52378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // switched) then the timer might have diarmed itself. Detect this case and 52478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // work around it by manually signalling the |alarm_expired| semaphore. 525081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson // 52678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // It is possible that the timer was actually super short (a few 52778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // milliseconds) and the timer expired normally before we called 52878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // |timer_gettime|. Worst case, |alarm_expired| is signaled twice for that 52978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // alarm. Nothing bad should happen in that case though since the callback 53078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // dispatch function checks to make sure the timer at the head of the list 53178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // actually expired. 532081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson if (timer_set) { 533081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson struct itimerspec time_to_expire; 534081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson timer_gettime(timer, &time_to_expire); 53578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (time_to_expire.it_value.tv_sec == 0 && 53678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov time_to_expire.it_value.tv_nsec == 0) { 537b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_DEBUG( 538b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_TAG, 539b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson "%s alarm expiration too close for posix timers, switching to guns", 540b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson __func__); 541081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson semaphore_post(alarm_expired); 542f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 543081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson } 544081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson} 545081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 546b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid alarm_register_processing_queue(fixed_queue_t* queue, thread_t* thread) { 54778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov assert(queue != NULL); 54878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov assert(thread != NULL); 54978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 55078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov fixed_queue_register_dequeue(queue, thread_get_reactor(thread), 55178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_queue_ready, NULL); 55278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 55378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 554b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid alarm_unregister_processing_queue(fixed_queue_t* queue) { 555936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov assert(alarms != NULL); 556936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov assert(queue != NULL); 557936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov 55878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov fixed_queue_unregister_dequeue(queue); 559936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov 560936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov // Cancel all alarms that are using this queue 561936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov pthread_mutex_lock(&monitor); 562b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson for (list_node_t* node = list_begin(alarms); node != list_end(alarms);) { 563b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_t* alarm = (alarm_t*)list_node(node); 564936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov node = list_next(node); 565936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov // TODO: Each module is responsible for tearing down its alarms; currently, 566936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov // this is not the case. In the future, this check should be replaced by 567936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov // an assert. 568b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (alarm->queue == queue) alarm_cancel_internal(alarm); 569936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov } 570936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov pthread_mutex_unlock(&monitor); 57178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 57278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 573b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void alarm_queue_ready(fixed_queue_t* queue, UNUSED_ATTR void* context) { 57478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov assert(queue != NULL); 57578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 57678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov pthread_mutex_lock(&monitor); 577b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_t* alarm = (alarm_t*)fixed_queue_try_dequeue(queue); 57878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (alarm == NULL) { 57978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov pthread_mutex_unlock(&monitor); 580b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson return; // The alarm was probably canceled 58178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 58278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 58378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // 58478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // If the alarm is not periodic, we've fully serviced it now, and can reset 58578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // some of its internal state. This is useful to distinguish between expired 58678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // alarms and active ones. 58778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // 58878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_callback_t callback = alarm->callback; 589b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson void* data = alarm->data; 59078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t deadline = alarm->deadline; 59178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (alarm->is_periodic) { 59278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // The periodic alarm has been rescheduled and alarm->deadline has been 59378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // updated, hence we need to use the previous deadline. 59478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov deadline = alarm->prev_deadline; 59578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } else { 59678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->deadline = 0; 59778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->callback = NULL; 59878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->data = NULL; 59978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 60078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 60178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov pthread_mutex_lock(&alarm->callback_lock); 60278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov pthread_mutex_unlock(&monitor); 60378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 60478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t t0 = now(); 60578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov callback(data); 60678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t t1 = now(); 60778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 60878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // Update the statistics 60978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov assert(t1 >= t0); 61078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t delta = t1 - t0; 61178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov update_scheduling_stats(&alarm->stats, t0, deadline, delta); 61278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 61378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov pthread_mutex_unlock(&alarm->callback_lock); 61478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 61578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 616081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson// Callback function for wake alarms and our posix timer 617b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void timer_callback(UNUSED_ATTR void* ptr) { 618081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson semaphore_post(alarm_expired); 619081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson} 620f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 62178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// Function running on |dispatcher_thread| that performs the following: 62278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// (1) Receives a signal using |alarm_exired| that the alarm has expired 62378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// (2) Dispatches the alarm callback for processing by the corresponding 62478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// thread for that alarm. 625b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void callback_dispatch(UNUSED_ATTR void* context) { 626081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson while (true) { 627081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson semaphore_wait(alarm_expired); 628b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!dispatcher_thread_active) break; 629081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 630cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach pthread_mutex_lock(&monitor); 631b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_t* alarm; 632081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 633081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson // Take into account that the alarm may get cancelled before we get to it. 634081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson // We're done here if there are no alarms or the alarm at the front is in 635081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson // the future. Release the monitor lock and exit right away since there's 636081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson // nothing left to do. 63778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (list_is_empty(alarms) || 638b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson (alarm = static_cast<alarm_t*>(list_front(alarms)))->deadline > now()) { 639081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson reschedule_root_alarm(); 640081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson pthread_mutex_unlock(&monitor); 641081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson continue; 642f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 643f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 644081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson list_remove(alarms, alarm); 645081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 646081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson if (alarm->is_periodic) { 64778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->prev_deadline = alarm->deadline; 64878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov schedule_next_instance(alarm); 64978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->stats.rescheduled_count++; 650f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 65178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov reschedule_root_alarm(); 652f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 65378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // Enqueue the alarm for processing 65478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov fixed_queue_enqueue(alarm->queue, alarm); 655081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 65678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov pthread_mutex_unlock(&monitor); 657f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 658cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach 659db554581079863974af8e1289646f5deea6fc044Marie Janssen LOG_DEBUG(LOG_TAG, "%s Callback thread exited", __func__); 660f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 66128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 662b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic bool timer_create_internal(const clockid_t clock_id, timer_t* timer) { 66328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen assert(timer != NULL); 66428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 66528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen struct sigevent sigevent; 66628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen memset(&sigevent, 0, sizeof(sigevent)); 66728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen sigevent.sigev_notify = SIGEV_THREAD; 66828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen sigevent.sigev_notify_function = (void (*)(union sigval))timer_callback; 66928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen if (timer_create(clock_id, &sigevent, timer) == -1) { 670b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_ERROR(LOG_TAG, "%s unable to create timer with clock %d: %s", __func__, 671b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson clock_id, strerror(errno)); 6724b7f560168f9e7523217d4b372fde4b0adba4d3bPavlin Radoslavov if (clock_id == CLOCK_BOOTTIME_ALARM) { 673b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_ERROR(LOG_TAG, 674b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson "The kernel might not have support for " 675b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson "timer_create(CLOCK_BOOTTIME_ALARM): " 676b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson "https://lwn.net/Articles/429925/"); 677b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_ERROR(LOG_TAG, 678b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson "See following patches: " 679b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson "https://git.kernel.org/cgit/linux/kernel/git/torvalds/" 680b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson "linux.git/log/?qt=grep&q=CLOCK_BOOTTIME_ALARM"); 6814b7f560168f9e7523217d4b372fde4b0adba4d3bPavlin Radoslavov } 68228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen return false; 68328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen } 68428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 68528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen return true; 68628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen} 68778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 688b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void update_scheduling_stats(alarm_stats_t* stats, period_ms_t now_ms, 68978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t deadline_ms, 690b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson period_ms_t execution_delta_ms) { 69178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stats->total_updates++; 69278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stats->last_update_ms = now_ms; 69378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 69478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov update_stat(&stats->callback_execution, execution_delta_ms); 69578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 69678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (deadline_ms < now_ms) { 69778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // Overdue scheduling 69878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t delta_ms = now_ms - deadline_ms; 69978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov update_stat(&stats->overdue_scheduling, delta_ms); 70078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } else if (deadline_ms > now_ms) { 70178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // Premature scheduling 70278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t delta_ms = deadline_ms - now_ms; 70378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov update_stat(&stats->premature_scheduling, delta_ms); 70478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 70578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 70678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 707b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void dump_stat(int fd, stat_t* stat, const char* description) { 708b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson period_ms_t average_time_ms = 0; 709b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (stat->count != 0) average_time_ms = stat->total_ms / stat->count; 710b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson 711b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson dprintf(fd, "%-51s: %llu / %llu / %llu\n", description, 712b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson (unsigned long long)stat->total_ms, (unsigned long long)stat->max_ms, 713b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson (unsigned long long)average_time_ms); 71478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 71578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 716b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid alarm_debug_dump(int fd) { 71778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dprintf(fd, "\nBluetooth Alarms Statistics:\n"); 71878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 71978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov pthread_mutex_lock(&monitor); 72078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 72178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (alarms == NULL) { 72278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov pthread_mutex_unlock(&monitor); 72378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dprintf(fd, " None\n"); 72478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov return; 72578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 72678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 72778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t just_now = now(); 72878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 72978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dprintf(fd, " Total Alarms: %zu\n\n", list_length(alarms)); 73078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 73178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // Dump info for each alarm 732b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson for (list_node_t* node = list_begin(alarms); node != list_end(alarms); 73378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov node = list_next(node)) { 734b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_t* alarm = (alarm_t*)list_node(node); 735b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_stats_t* stats = &alarm->stats; 73678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 73778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dprintf(fd, " Alarm : %s (%s)\n", stats->name, 73878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov (alarm->is_periodic) ? "PERIODIC" : "SINGLE"); 73978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 740eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker dprintf(fd, "%-51s: %zu / %zu / %zu / %zu\n", 741399f217fddd4ce195ada3b69575caeca74ca1314Pavlin Radoslavov " Action counts (sched/resched/exec/cancel)", 74278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stats->scheduled_count, stats->rescheduled_count, 74378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stats->callback_execution.count, stats->canceled_count); 74478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 745eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker dprintf(fd, "%-51s: %zu / %zu\n", 746eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker " Deviation counts (overdue/premature)", 747b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson stats->overdue_scheduling.count, stats->premature_scheduling.count); 74878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 749eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker dprintf(fd, "%-51s: %llu / %llu / %lld\n", 750eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker " Time in ms (since creation/interval/remaining)", 75178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov (unsigned long long)(just_now - alarm->creation_time), 752b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson (unsigned long long)alarm->period, 75378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov (long long)(alarm->deadline - just_now)); 75478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 755eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker dump_stat(fd, &stats->callback_execution, 756eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker " Callback execution time in ms (total/max/avg)"); 757eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker 758eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker dump_stat(fd, &stats->overdue_scheduling, 759eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker " Overdue scheduling time in ms (total/max/avg)"); 760eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker 76178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dump_stat(fd, &stats->premature_scheduling, 762eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker " Premature scheduling time in ms (total/max/avg)"); 76378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 76478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dprintf(fd, "\n"); 76578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 76678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov pthread_mutex_unlock(&monitor); 76778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 768