alarm.cc revision f2af1c42ccb2f642b241c2261b42d0be61d45438
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 25f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He#include <base/logging.h> 26f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati#include <errno.h> 2728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen#include <fcntl.h> 281afbe154a89ad462de739704ce70eed0e32cbc00Michael Wright#include <inttypes.h> 29b9164f414b4d8d414358d0146a8f911207af3122Elliott Hughes#include <malloc.h> 30468e4b983dd59ea58a7518032fa6029b00c56dc4Ian Coolidge#include <signal.h> 3149a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen#include <string.h> 32f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati#include <time.h> 33f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 3449a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen#include <hardware/bluetooth.h> 3549a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen 3621da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen#include <mutex> 3721da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen 38081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson#include "osi/include/allocator.h" 3978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov#include "osi/include/fixed_queue.h" 400f9b91e150e153229235c163861198e23600e636Sharvil Nanavati#include "osi/include/list.h" 4144802768c447ab480d4227b3a852a97d923b816dSharvil Nanavati#include "osi/include/log.h" 42081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson#include "osi/include/osi.h" 43081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson#include "osi/include/semaphore.h" 44081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson#include "osi/include/thread.h" 45d2e250824fca5c42b87b3b6f5fa19646ffa2d321Pavlin Radoslavov#include "osi/include/wakelock.h" 46f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 4741a91a52b06171140938a1aa503bab8fe15e12e4Andre Eisenbach// Make callbacks run at high thread priority. Some callbacks are used for audio 4841a91a52b06171140938a1aa503bab8fe15e12e4Andre Eisenbach// related timer tasks as well as re-transmissions etc. Since we at this point 4941a91a52b06171140938a1aa503bab8fe15e12e4Andre Eisenbach// cannot differentiate what callback we are dealing with, assume high priority 5041a91a52b06171140938a1aa503bab8fe15e12e4Andre Eisenbach// for now. 5141a91a52b06171140938a1aa503bab8fe15e12e4Andre Eisenbach// TODO(eisenbach): Determine correct thread priority (from parent?/per alarm?) 5241a91a52b06171140938a1aa503bab8fe15e12e4Andre Eisenbachstatic const int CALLBACK_THREAD_PRIORITY_HIGH = -19; 5341a91a52b06171140938a1aa503bab8fe15e12e4Andre Eisenbach 5478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovtypedef struct { 5578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov size_t count; 5678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t total_ms; 5778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t max_ms; 5878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} stat_t; 5978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 6078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// Alarm-related information and statistics 6178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovtypedef struct { 62b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson const char* name; 6378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov size_t scheduled_count; 6478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov size_t canceled_count; 6578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov size_t rescheduled_count; 6678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov size_t total_updates; 6778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t last_update_ms; 6878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stat_t callback_execution; 6978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stat_t overdue_scheduling; 7078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stat_t premature_scheduling; 7178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} alarm_stats_t; 7278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 73f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistruct alarm_t { 7421da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen // The mutex is held while the callback for this alarm is being executed. 7578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // It allows us to release the coarse-grained monitor lock while a 7678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // potentially long-running callback is executing. |alarm_cancel| uses this 7721da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen // mutex to provide a guarantee to its caller that the callback will not be 7878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // in progress when it returns. 7921da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen std::recursive_mutex* callback_mutex; 80f2bf2308e90386754080a4fd7cc2ee7751eeab46Sharvil Nanavati period_ms_t creation_time; 81e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson period_ms_t period; 82f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati period_ms_t deadline; 83b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson period_ms_t prev_deadline; // Previous deadline - used for accounting of 84b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson // periodic timers 85e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson bool is_periodic; 86b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson fixed_queue_t* queue; // The processing queue to add this alarm to 87f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm_callback_t callback; 88b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson void* data; 8978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_stats_t stats; 90f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati}; 91f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 92f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati// If the next wakeup time is less than this threshold, we should acquire 93f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati// a wakelock instead of setting a wake alarm so we're not bouncing in 94f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati// and out of suspend frequently. This value is externally visible to allow 95f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati// unit tests to run faster. It should not be modified by production code. 96f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatiint64_t TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 3000; 97f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic const clockid_t CLOCK_ID = CLOCK_BOOTTIME; 9810978011f286d20f10eb949e3557ad00a62c8424Pavlin Radoslavov 99d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen#if (KERNEL_MISSING_CLOCK_BOOTTIME_ALARM == TRUE) 10010978011f286d20f10eb949e3557ad00a62c8424Pavlin Radoslavovstatic const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME; 10110978011f286d20f10eb949e3557ad00a62c8424Pavlin Radoslavov#else 10228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssenstatic const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME_ALARM; 10310978011f286d20f10eb949e3557ad00a62c8424Pavlin Radoslavov#endif 104f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 105f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati// This mutex ensures that the |alarm_set|, |alarm_cancel|, and alarm callback 10678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// functions execute serially and not concurrently. As a result, this mutex 10778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// also protects the |alarms| list. 10821da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssenstatic std::mutex alarms_mutex; 109b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic list_t* alarms; 110f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic timer_t timer; 11128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssenstatic timer_t wakeup_timer; 112f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic bool timer_set; 113f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 11478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// All alarm callbacks are dispatched from |dispatcher_thread| 115b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic thread_t* dispatcher_thread; 11678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovstatic bool dispatcher_thread_active; 117b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic semaphore_t* alarm_expired; 118081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 11978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// Default alarm callback thread and queue 120b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic thread_t* default_callback_thread; 121b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic fixed_queue_t* default_callback_queue; 12278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 123b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic alarm_t* alarm_new_internal(const char* name, bool is_periodic); 124f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic bool lazy_initialize(void); 125f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic period_ms_t now(void); 126b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void alarm_set_internal(alarm_t* alarm, period_ms_t period, 127b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_callback_t cb, void* data, 128b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson fixed_queue_t* queue); 129b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void alarm_cancel_internal(alarm_t* alarm); 130b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void remove_pending_alarm(alarm_t* alarm); 131b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void schedule_next_instance(alarm_t* alarm); 132e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnsonstatic void reschedule_root_alarm(void); 133b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void alarm_queue_ready(fixed_queue_t* queue, void* context); 134b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void timer_callback(void* data); 135b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void callback_dispatch(void* context); 136b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic bool timer_create_internal(const clockid_t clock_id, timer_t* timer); 137b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void update_scheduling_stats(alarm_stats_t* stats, period_ms_t now_ms, 13878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t deadline_ms, 13978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t execution_delta_ms); 14078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 141b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void update_stat(stat_t* stat, period_ms_t delta) { 142b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (stat->max_ms < delta) stat->max_ms = delta; 14378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stat->total_ms += delta; 14478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stat->count++; 14578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 146f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 147b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonalarm_t* alarm_new(const char* name) { return alarm_new_internal(name, false); } 14878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 149b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonalarm_t* alarm_new_periodic(const char* name) { 15078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov return alarm_new_internal(name, true); 15178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 15278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 153b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic alarm_t* alarm_new_internal(const char* name, bool is_periodic) { 154f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati // Make sure we have a list we can insert alarms into. 15528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen if (!alarms && !lazy_initialize()) { 156f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(false); // if initialization failed, we should not continue 157f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati return NULL; 15828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen } 159f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 160b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_t* ret = static_cast<alarm_t*>(osi_calloc(sizeof(alarm_t))); 161f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 16221da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen ret->callback_mutex = new std::recursive_mutex; 16378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov ret->is_periodic = is_periodic; 164b2a292b5d8df2f359c38b0787bc01181225a9bc9Pavlin Radoslavov ret->stats.name = osi_strdup(name); 16578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // NOTE: The stats were reset by osi_calloc() above 16678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 167f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati return ret; 168f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 169f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 170b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid alarm_free(alarm_t* alarm) { 171b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!alarm) return; 172f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 173f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm_cancel(alarm); 17421da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen delete alarm->callback_mutex; 175b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson osi_free((void*)alarm->stats.name); 176ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson osi_free(alarm); 177f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 178f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 179b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonperiod_ms_t alarm_get_remaining_ms(const alarm_t* alarm) { 180f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(alarm != NULL); 181165332bc6795049754fafe35024c2c605796c96aAndre Eisenbach period_ms_t remaining_ms = 0; 18278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t just_now = now(); 183165332bc6795049754fafe35024c2c605796c96aAndre Eisenbach 18421da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen std::lock_guard<std::mutex> lock(alarms_mutex); 185b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (alarm->deadline > just_now) remaining_ms = alarm->deadline - just_now; 186165332bc6795049754fafe35024c2c605796c96aAndre Eisenbach 187165332bc6795049754fafe35024c2c605796c96aAndre Eisenbach return remaining_ms; 18876356aee883af67898ddc1aa3b628195f396d42aVenkatRaghavan VijayaRaghavan} 18976356aee883af67898ddc1aa3b628195f396d42aVenkatRaghavan VijayaRaghavan 190b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid alarm_set(alarm_t* alarm, period_ms_t interval_ms, alarm_callback_t cb, 191b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson void* data) { 19278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_set_on_queue(alarm, interval_ms, cb, data, default_callback_queue); 19371864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson} 19471864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson 195b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid alarm_set_on_queue(alarm_t* alarm, period_ms_t interval_ms, 196b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_callback_t cb, void* data, fixed_queue_t* queue) { 197f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(queue != NULL); 19878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_set_internal(alarm, interval_ms, cb, data, queue); 19971864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson} 20071864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson 20171864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson// Runs in exclusion with alarm_cancel and timer_callback. 202b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void alarm_set_internal(alarm_t* alarm, period_ms_t period, 203b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_callback_t cb, void* data, 204b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson fixed_queue_t* queue) { 205f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(alarms != NULL); 206f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(alarm != NULL); 207f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(cb != NULL); 208f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 20921da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen std::lock_guard<std::mutex> lock(alarms_mutex); 210f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 211f2bf2308e90386754080a4fd7cc2ee7751eeab46Sharvil Nanavati alarm->creation_time = now(); 212e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson alarm->period = period; 21378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->queue = queue; 214f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm->callback = cb; 215f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm->data = data; 216f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 21778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov schedule_next_instance(alarm); 21878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->stats.scheduled_count++; 219f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 220f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 221b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid alarm_cancel(alarm_t* alarm) { 222f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(alarms != NULL); 223b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!alarm) return; 224f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 22521da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen { 22621da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen std::lock_guard<std::mutex> lock(alarms_mutex); 22721da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen alarm_cancel_internal(alarm); 22821da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen } 229936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov 230936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov // If the callback for |alarm| is in progress, wait here until it completes. 23121da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen std::lock_guard<std::recursive_mutex> lock(*alarm->callback_mutex); 232936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov} 233f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 234936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov// Internal implementation of canceling an alarm. 23521da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen// The caller must hold the |alarms_mutex| 236b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void alarm_cancel_internal(alarm_t* alarm) { 237b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson bool needs_reschedule = 238b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson (!list_is_empty(alarms) && list_front(alarms) == alarm); 239f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 24078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov remove_pending_alarm(alarm); 24178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 242f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm->deadline = 0; 24378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->prev_deadline = 0; 244f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm->callback = NULL; 245f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm->data = NULL; 24678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->stats.canceled_count++; 247936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov alarm->queue = NULL; 248f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 249b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (needs_reschedule) reschedule_root_alarm(); 250f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 251f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 252b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonbool alarm_is_scheduled(const alarm_t* alarm) { 253b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if ((alarms == NULL) || (alarm == NULL)) return false; 25478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov return (alarm->callback != NULL); 25578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 25678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 2570933b4075e16589a073e85d8230677238b29b780Pavlin Radoslavovvoid alarm_cleanup(void) { 2581b2bd2c8b5b7be80cb4ce0ecf4e021ad16e4a540Marie Janssen // If lazy_initialize never ran there is nothing else to do 259b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!alarms) return; 260c6a1c261b87f194b298df01f002292d9e937ec75Zach Johnson 26178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dispatcher_thread_active = false; 262cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach semaphore_post(alarm_expired); 26378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_free(dispatcher_thread); 26478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dispatcher_thread = NULL; 26578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 26621da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen std::lock_guard<std::mutex> lock(alarms_mutex); 26793342476cae97c085e3f274a8bf1339b523f7132Pavlin Radoslavov 26878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov fixed_queue_free(default_callback_queue, NULL); 26978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov default_callback_queue = NULL; 27078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_free(default_callback_thread); 27178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov default_callback_thread = NULL; 272cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach 27393342476cae97c085e3f274a8bf1339b523f7132Pavlin Radoslavov timer_delete(wakeup_timer); 27493342476cae97c085e3f274a8bf1339b523f7132Pavlin Radoslavov timer_delete(timer); 275cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach semaphore_free(alarm_expired); 276cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach alarm_expired = NULL; 27793342476cae97c085e3f274a8bf1339b523f7132Pavlin Radoslavov 278cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach list_free(alarms); 279cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach alarms = NULL; 280cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach} 281cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach 282f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic bool lazy_initialize(void) { 283f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(alarms == NULL); 284f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 28528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // timer_t doesn't have an invalid value so we must track whether 28628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // the |timer| variable is valid ourselves. 28728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen bool timer_initialized = false; 28828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen bool wakeup_timer_initialized = false; 28928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 29021da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen std::lock_guard<std::mutex> lock(alarms_mutex); 291f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 292f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarms = list_new(NULL); 293f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati if (!alarms) { 294db554581079863974af8e1289646f5deea6fc044Marie Janssen LOG_ERROR(LOG_TAG, "%s unable to allocate alarm list.", __func__); 29528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen goto error; 296f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 297f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 298b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!timer_create_internal(CLOCK_ID, &timer)) goto error; 29928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen timer_initialized = true; 30028bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 301b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!timer_create_internal(CLOCK_ID_ALARM, &wakeup_timer)) goto error; 30228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen wakeup_timer_initialized = true; 303518a94e706a6602ad69245b0d760cd40595109ffZach Johnson 304081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson alarm_expired = semaphore_new(0); 305081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson if (!alarm_expired) { 306db554581079863974af8e1289646f5deea6fc044Marie Janssen LOG_ERROR(LOG_TAG, "%s unable to create alarm expired semaphore", __func__); 30728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen goto error; 308081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson } 309081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 310b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson default_callback_thread = 311b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson thread_new_sized("alarm_default_callbacks", SIZE_MAX); 31278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (default_callback_thread == NULL) { 31378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov LOG_ERROR(LOG_TAG, "%s unable to create default alarm callbacks thread.", 31478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov __func__); 31578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov goto error; 31678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 31778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_set_priority(default_callback_thread, CALLBACK_THREAD_PRIORITY_HIGH); 31878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov default_callback_queue = fixed_queue_new(SIZE_MAX); 31978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (default_callback_queue == NULL) { 32078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov LOG_ERROR(LOG_TAG, "%s unable to create default alarm callbacks queue.", 32178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov __func__); 32278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov goto error; 32378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 32478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_register_processing_queue(default_callback_queue, 32578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov default_callback_thread); 32678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 32778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dispatcher_thread_active = true; 32878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dispatcher_thread = thread_new("alarm_dispatcher"); 32978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (!dispatcher_thread) { 330db554581079863974af8e1289646f5deea6fc044Marie Janssen LOG_ERROR(LOG_TAG, "%s unable to create alarm callback thread.", __func__); 33128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen goto error; 332f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 333f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 33478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_set_priority(dispatcher_thread, CALLBACK_THREAD_PRIORITY_HIGH); 33578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_post(dispatcher_thread, callback_dispatch, NULL); 336f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati return true; 33728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 33828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssenerror: 33978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov fixed_queue_free(default_callback_queue, NULL); 34078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov default_callback_queue = NULL; 34178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_free(default_callback_thread); 34278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov default_callback_thread = NULL; 34328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 34478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_free(dispatcher_thread); 34578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dispatcher_thread = NULL; 34678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 34778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dispatcher_thread_active = false; 34828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 34928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen semaphore_free(alarm_expired); 35028bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen alarm_expired = NULL; 35128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 352b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (wakeup_timer_initialized) timer_delete(wakeup_timer); 35328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 354b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (timer_initialized) timer_delete(timer); 35528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 35628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen list_free(alarms); 35728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen alarms = NULL; 35828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 35928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen return false; 360f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 361f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 362f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic period_ms_t now(void) { 363f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(alarms != NULL); 364f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 365f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati struct timespec ts; 366f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati if (clock_gettime(CLOCK_ID, &ts) == -1) { 367b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_ERROR(LOG_TAG, "%s unable to get current time: %s", __func__, 368b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson strerror(errno)); 369f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati return 0; 370f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 371f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 372f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati return (ts.tv_sec * 1000LL) + (ts.tv_nsec / 1000000LL); 373f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 374f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 37578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// Remove alarm from internal alarm list and the processing queue 37621da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen// The caller must hold the |alarms_mutex| 377b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void remove_pending_alarm(alarm_t* alarm) { 37878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov list_remove(alarms, alarm); 37978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov while (fixed_queue_try_remove_from_queue(alarm->queue, alarm) != NULL) { 38078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // Remove all repeated alarm instances from the queue. 38178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // NOTE: We are defensive here - we shouldn't have repeated alarm instances 38278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 38378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 38478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 38521da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen// Must be called with |alarms_mutex| held 386b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void schedule_next_instance(alarm_t* alarm) { 38771864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson // If the alarm is currently set and it's at the start of the list, 38871864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson // we'll need to re-schedule since we've adjusted the earliest deadline. 389b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson bool needs_reschedule = 390b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson (!list_is_empty(alarms) && list_front(alarms) == alarm); 391b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (alarm->callback) remove_pending_alarm(alarm); 392f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 393e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson // Calculate the next deadline for this alarm 394e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson period_ms_t just_now = now(); 39578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t ms_into_period = 0; 396399f217fddd4ce195ada3b69575caeca74ca1314Pavlin Radoslavov if ((alarm->is_periodic) && (alarm->period != 0)) 39778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov ms_into_period = ((just_now - alarm->creation_time) % alarm->period); 398e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson alarm->deadline = just_now + (alarm->period - ms_into_period); 399f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 40071864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson // Add it into the timer list sorted by deadline (earliest deadline first). 40178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (list_is_empty(alarms) || 402b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson ((alarm_t*)list_front(alarms))->deadline > alarm->deadline) { 40371864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson list_prepend(alarms, alarm); 40478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } else { 405b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson for (list_node_t* node = list_begin(alarms); node != list_end(alarms); 406b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson node = list_next(node)) { 407b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson list_node_t* next = list_next(node); 408b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (next == list_end(alarms) || 409b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson ((alarm_t*)list_node(next))->deadline > alarm->deadline) { 41071864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson list_insert_after(alarms, node, alarm); 41171864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson break; 41271864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson } 41371864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson } 41478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 415f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 416b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson // If the new alarm has the earliest deadline, we need to re-evaluate our 417b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson // schedule. 41878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (needs_reschedule || 41978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov (!list_is_empty(alarms) && list_front(alarms) == alarm)) { 420e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson reschedule_root_alarm(); 42178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 422f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 423f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 42421da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen// NOTE: must be called with |alarms_mutex| held 425e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnsonstatic void reschedule_root_alarm(void) { 426f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(alarms != NULL); 427f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 42828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen const bool timer_was_set = timer_set; 429b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_t* next; 430b2a292b5d8df2f359c38b0787bc01181225a9bc9Pavlin Radoslavov int64_t next_expiration; 43128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 43228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // If used in a zeroed state, disarms the timer. 43328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen struct itimerspec timer_time; 43428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen memset(&timer_time, 0, sizeof(timer_time)); 435f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 436b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (list_is_empty(alarms)) goto done; 437f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 438b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson next = static_cast<alarm_t*>(list_front(alarms)); 439b2a292b5d8df2f359c38b0787bc01181225a9bc9Pavlin Radoslavov next_expiration = next->deadline - now(); 440518a94e706a6602ad69245b0d760cd40595109ffZach Johnson if (next_expiration < TIMER_INTERVAL_FOR_WAKELOCK_IN_MS) { 441518a94e706a6602ad69245b0d760cd40595109ffZach Johnson if (!timer_set) { 442d2e250824fca5c42b87b3b6f5fa19646ffa2d321Pavlin Radoslavov if (!wakelock_acquire()) { 44328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen LOG_ERROR(LOG_TAG, "%s unable to acquire wake lock", __func__); 444518a94e706a6602ad69245b0d760cd40595109ffZach Johnson goto done; 44571864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson } 446f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 447f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 44828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen timer_time.it_value.tv_sec = (next->deadline / 1000); 44928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen timer_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL; 45028bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 45178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // It is entirely unsafe to call timer_settime(2) with a zeroed timerspec 45278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // for timers with *_ALARM clock IDs. Although the man page states that the 45378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // timer would be canceled, the current behavior (as of Linux kernel 3.17) 45478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // is that the callback is issued immediately. The only way to cancel an 45578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // *_ALARM timer is to delete the timer. But unfortunately, deleting and 45678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // re-creating a timer is rather expensive; every timer_create(2) spawns a 45778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // new thread. So we simply set the timer to fire at the largest possible 45878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // time. 45928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // 46078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // If we've reached this code path, we're going to grab a wake lock and 46178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // wait for the next timer to fire. In that case, there's no reason to 46278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // have a pending wakeup timer so we simply cancel it. 46328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen struct itimerspec end_of_time; 46428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen memset(&end_of_time, 0, sizeof(end_of_time)); 46528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen end_of_time.it_value.tv_sec = (time_t)(1LL << (sizeof(time_t) * 8 - 2)); 46628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen timer_settime(wakeup_timer, TIMER_ABSTIME, &end_of_time, NULL); 46728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen } else { 46828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // WARNING: do not attempt to use relative timers with *_ALARM clock IDs 46928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // in kernels before 3.17 unless you have the following patch: 47028bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // https://lkml.org/lkml/2014/7/7/576 47128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen struct itimerspec wakeup_time; 47228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen memset(&wakeup_time, 0, sizeof(wakeup_time)); 47328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 474f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati wakeup_time.it_value.tv_sec = (next->deadline / 1000); 475f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati wakeup_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL; 47628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen if (timer_settime(wakeup_timer, TIMER_ABSTIME, &wakeup_time, NULL) == -1) 477b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_ERROR(LOG_TAG, "%s unable to set wakeup timer: %s", __func__, 478b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson strerror(errno)); 479f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 480f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 481518a94e706a6602ad69245b0d760cd40595109ffZach Johnsondone: 482b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson timer_set = 483b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson timer_time.it_value.tv_sec != 0 || timer_time.it_value.tv_nsec != 0; 4844be4396c8e4dc4c308219bdf402447a7feefe73ePavlin Radoslavov if (timer_was_set && !timer_set) { 485d2e250824fca5c42b87b3b6f5fa19646ffa2d321Pavlin Radoslavov wakelock_release(); 486f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 487f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 48828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen if (timer_settime(timer, TIMER_ABSTIME, &timer_time, NULL) == -1) 489db554581079863974af8e1289646f5deea6fc044Marie Janssen LOG_ERROR(LOG_TAG, "%s unable to set timer: %s", __func__, strerror(errno)); 490081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 49178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // If next expiration was in the past (e.g. short timer that got context 49278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // switched) then the timer might have diarmed itself. Detect this case and 49378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // work around it by manually signalling the |alarm_expired| semaphore. 494081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson // 49578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // It is possible that the timer was actually super short (a few 49678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // milliseconds) and the timer expired normally before we called 49778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // |timer_gettime|. Worst case, |alarm_expired| is signaled twice for that 49878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // alarm. Nothing bad should happen in that case though since the callback 49978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // dispatch function checks to make sure the timer at the head of the list 50078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // actually expired. 501081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson if (timer_set) { 502081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson struct itimerspec time_to_expire; 503081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson timer_gettime(timer, &time_to_expire); 50478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (time_to_expire.it_value.tv_sec == 0 && 50578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov time_to_expire.it_value.tv_nsec == 0) { 506b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_DEBUG( 507b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_TAG, 508b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson "%s alarm expiration too close for posix timers, switching to guns", 509b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson __func__); 510081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson semaphore_post(alarm_expired); 511f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 512081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson } 513081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson} 514081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 515b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid alarm_register_processing_queue(fixed_queue_t* queue, thread_t* thread) { 516f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(queue != NULL); 517f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(thread != NULL); 51878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 51978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov fixed_queue_register_dequeue(queue, thread_get_reactor(thread), 52078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_queue_ready, NULL); 52178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 52278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 523b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid alarm_unregister_processing_queue(fixed_queue_t* queue) { 524f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(alarms != NULL); 525f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(queue != NULL); 526936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov 52778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov fixed_queue_unregister_dequeue(queue); 528936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov 529936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov // Cancel all alarms that are using this queue 53021da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen std::lock_guard<std::mutex> lock(alarms_mutex); 531b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson for (list_node_t* node = list_begin(alarms); node != list_end(alarms);) { 532b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_t* alarm = (alarm_t*)list_node(node); 533936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov node = list_next(node); 534936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov // TODO: Each module is responsible for tearing down its alarms; currently, 535936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov // this is not the case. In the future, this check should be replaced by 536936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov // an assert. 537b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (alarm->queue == queue) alarm_cancel_internal(alarm); 538936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov } 53978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 54078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 541b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void alarm_queue_ready(fixed_queue_t* queue, UNUSED_ATTR void* context) { 542f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(queue != NULL); 54378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 54421da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen std::unique_lock<std::mutex> lock(alarms_mutex); 545b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_t* alarm = (alarm_t*)fixed_queue_try_dequeue(queue); 54678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (alarm == NULL) { 547b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson return; // The alarm was probably canceled 54878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 54978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 55078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // 55178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // If the alarm is not periodic, we've fully serviced it now, and can reset 55278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // some of its internal state. This is useful to distinguish between expired 55378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // alarms and active ones. 55478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // 55578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_callback_t callback = alarm->callback; 556b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson void* data = alarm->data; 55778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t deadline = alarm->deadline; 55878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (alarm->is_periodic) { 55978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // The periodic alarm has been rescheduled and alarm->deadline has been 56078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // updated, hence we need to use the previous deadline. 56178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov deadline = alarm->prev_deadline; 56278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } else { 56378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->deadline = 0; 56478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->callback = NULL; 56578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->data = NULL; 56678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 56778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 56821da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen std::lock_guard<std::recursive_mutex> cb_lock(*alarm->callback_mutex); 56921da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen lock.unlock(); 57078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 57178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t t0 = now(); 57278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov callback(data); 57378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t t1 = now(); 57478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 57578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // Update the statistics 576f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(t1 >= t0); 57778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t delta = t1 - t0; 57878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov update_scheduling_stats(&alarm->stats, t0, deadline, delta); 57978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 58078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 581081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson// Callback function for wake alarms and our posix timer 582b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void timer_callback(UNUSED_ATTR void* ptr) { 583081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson semaphore_post(alarm_expired); 584081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson} 585f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 58678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// Function running on |dispatcher_thread| that performs the following: 58778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// (1) Receives a signal using |alarm_exired| that the alarm has expired 58878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// (2) Dispatches the alarm callback for processing by the corresponding 58978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// thread for that alarm. 590b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void callback_dispatch(UNUSED_ATTR void* context) { 591081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson while (true) { 592081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson semaphore_wait(alarm_expired); 593b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!dispatcher_thread_active) break; 594081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 59521da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen std::lock_guard<std::mutex> lock(alarms_mutex); 596b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_t* alarm; 597081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 598081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson // Take into account that the alarm may get cancelled before we get to it. 599081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson // We're done here if there are no alarms or the alarm at the front is in 60021da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen // the future. Exit right away since there's nothing left to do. 60178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (list_is_empty(alarms) || 602b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson (alarm = static_cast<alarm_t*>(list_front(alarms)))->deadline > now()) { 603081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson reschedule_root_alarm(); 604081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson continue; 605f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 606f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 607081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson list_remove(alarms, alarm); 608081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 609081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson if (alarm->is_periodic) { 61078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->prev_deadline = alarm->deadline; 61178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov schedule_next_instance(alarm); 61278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->stats.rescheduled_count++; 613f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 61478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov reschedule_root_alarm(); 615f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 61678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // Enqueue the alarm for processing 61778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov fixed_queue_enqueue(alarm->queue, alarm); 618f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 619cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach 620db554581079863974af8e1289646f5deea6fc044Marie Janssen LOG_DEBUG(LOG_TAG, "%s Callback thread exited", __func__); 621f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 62228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 623b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic bool timer_create_internal(const clockid_t clock_id, timer_t* timer) { 624f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(timer != NULL); 62528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 62628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen struct sigevent sigevent; 62728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen memset(&sigevent, 0, sizeof(sigevent)); 62828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen sigevent.sigev_notify = SIGEV_THREAD; 62928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen sigevent.sigev_notify_function = (void (*)(union sigval))timer_callback; 63028bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen if (timer_create(clock_id, &sigevent, timer) == -1) { 631b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_ERROR(LOG_TAG, "%s unable to create timer with clock %d: %s", __func__, 632b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson clock_id, strerror(errno)); 6334b7f560168f9e7523217d4b372fde4b0adba4d3bPavlin Radoslavov if (clock_id == CLOCK_BOOTTIME_ALARM) { 634b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_ERROR(LOG_TAG, 635b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson "The kernel might not have support for " 636b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson "timer_create(CLOCK_BOOTTIME_ALARM): " 637b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson "https://lwn.net/Articles/429925/"); 638b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_ERROR(LOG_TAG, 639b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson "See following patches: " 640b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson "https://git.kernel.org/cgit/linux/kernel/git/torvalds/" 641b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson "linux.git/log/?qt=grep&q=CLOCK_BOOTTIME_ALARM"); 6424b7f560168f9e7523217d4b372fde4b0adba4d3bPavlin Radoslavov } 64328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen return false; 64428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen } 64528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 64628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen return true; 64728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen} 64878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 649b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void update_scheduling_stats(alarm_stats_t* stats, period_ms_t now_ms, 65078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t deadline_ms, 651b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson period_ms_t execution_delta_ms) { 65278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stats->total_updates++; 65378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stats->last_update_ms = now_ms; 65478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 65578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov update_stat(&stats->callback_execution, execution_delta_ms); 65678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 65778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (deadline_ms < now_ms) { 65878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // Overdue scheduling 65978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t delta_ms = now_ms - deadline_ms; 66078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov update_stat(&stats->overdue_scheduling, delta_ms); 66178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } else if (deadline_ms > now_ms) { 66278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // Premature scheduling 66378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t delta_ms = deadline_ms - now_ms; 66478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov update_stat(&stats->premature_scheduling, delta_ms); 66578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 66678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 66778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 668b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void dump_stat(int fd, stat_t* stat, const char* description) { 669b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson period_ms_t average_time_ms = 0; 670b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (stat->count != 0) average_time_ms = stat->total_ms / stat->count; 671b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson 672b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson dprintf(fd, "%-51s: %llu / %llu / %llu\n", description, 673b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson (unsigned long long)stat->total_ms, (unsigned long long)stat->max_ms, 674b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson (unsigned long long)average_time_ms); 67578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 67678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 677b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid alarm_debug_dump(int fd) { 67878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dprintf(fd, "\nBluetooth Alarms Statistics:\n"); 67978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 68021da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen std::lock_guard<std::mutex> lock(alarms_mutex); 68178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 68278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (alarms == NULL) { 68378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dprintf(fd, " None\n"); 68478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov return; 68578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 68678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 68778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t just_now = now(); 68878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 68978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dprintf(fd, " Total Alarms: %zu\n\n", list_length(alarms)); 69078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 69178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // Dump info for each alarm 692b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson for (list_node_t* node = list_begin(alarms); node != list_end(alarms); 69378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov node = list_next(node)) { 694b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_t* alarm = (alarm_t*)list_node(node); 695b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_stats_t* stats = &alarm->stats; 69678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 69778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dprintf(fd, " Alarm : %s (%s)\n", stats->name, 69878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov (alarm->is_periodic) ? "PERIODIC" : "SINGLE"); 69978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 700eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker dprintf(fd, "%-51s: %zu / %zu / %zu / %zu\n", 701399f217fddd4ce195ada3b69575caeca74ca1314Pavlin Radoslavov " Action counts (sched/resched/exec/cancel)", 70278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stats->scheduled_count, stats->rescheduled_count, 70378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stats->callback_execution.count, stats->canceled_count); 70478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 705eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker dprintf(fd, "%-51s: %zu / %zu\n", 706eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker " Deviation counts (overdue/premature)", 707b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson stats->overdue_scheduling.count, stats->premature_scheduling.count); 70878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 709eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker dprintf(fd, "%-51s: %llu / %llu / %lld\n", 710eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker " Time in ms (since creation/interval/remaining)", 71178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov (unsigned long long)(just_now - alarm->creation_time), 712b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson (unsigned long long)alarm->period, 71378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov (long long)(alarm->deadline - just_now)); 71478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 715eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker dump_stat(fd, &stats->callback_execution, 716eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker " Callback execution time in ms (total/max/avg)"); 717eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker 718eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker dump_stat(fd, &stats->overdue_scheduling, 719eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker " Overdue scheduling time in ms (total/max/avg)"); 720eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker 72178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dump_stat(fd, &stats->premature_scheduling, 722eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker " Premature scheduling time in ms (total/max/avg)"); 72378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 72478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dprintf(fd, "\n"); 72578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 72678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 727