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 2547616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski#include <base/cancelable_callback.h> 26f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He#include <base/logging.h> 2747616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski#include <base/message_loop/message_loop.h> 28f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati#include <errno.h> 2928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen#include <fcntl.h> 301afbe154a89ad462de739704ce70eed0e32cbc00Michael Wright#include <inttypes.h> 31b9164f414b4d8d414358d0146a8f911207af3122Elliott Hughes#include <malloc.h> 3296c42e70f5c6a74a737739aa9c297cd93540f43ePhilip Cuadra#include <pthread.h> 33468e4b983dd59ea58a7518032fa6029b00c56dc4Ian Coolidge#include <signal.h> 3449a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen#include <string.h> 35f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati#include <time.h> 36f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 3749a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen#include <hardware/bluetooth.h> 3849a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen 3921da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen#include <mutex> 4021da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen 41081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson#include "osi/include/allocator.h" 4278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov#include "osi/include/fixed_queue.h" 430f9b91e150e153229235c163861198e23600e636Sharvil Nanavati#include "osi/include/list.h" 4444802768c447ab480d4227b3a852a97d923b816dSharvil Nanavati#include "osi/include/log.h" 45081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson#include "osi/include/osi.h" 46081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson#include "osi/include/semaphore.h" 47081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson#include "osi/include/thread.h" 48d2e250824fca5c42b87b3b6f5fa19646ffa2d321Pavlin Radoslavov#include "osi/include/wakelock.h" 49f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 5047616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowskiusing base::Bind; 5147616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowskiusing base::CancelableClosure; 5247616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowskiusing base::MessageLoop; 5347616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski 5447616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowskiextern base::MessageLoop* get_message_loop(); 5547616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski 5696c42e70f5c6a74a737739aa9c297cd93540f43ePhilip Cuadra// Callback and timer threads should run at RT priority in order to ensure they 5796c42e70f5c6a74a737739aa9c297cd93540f43ePhilip Cuadra// meet audio deadlines. Use this priority for all audio/timer related thread. 5896c42e70f5c6a74a737739aa9c297cd93540f43ePhilip Cuadrastatic const int THREAD_RT_PRIORITY = 1; 5941a91a52b06171140938a1aa503bab8fe15e12e4Andre Eisenbach 6078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovtypedef struct { 6178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov size_t count; 6278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t total_ms; 6378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t max_ms; 6478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} stat_t; 6578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 6678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// Alarm-related information and statistics 6778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovtypedef struct { 68b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson const char* name; 6978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov size_t scheduled_count; 7078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov size_t canceled_count; 7178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov size_t rescheduled_count; 7278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov size_t total_updates; 7378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t last_update_ms; 7478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stat_t overdue_scheduling; 7578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stat_t premature_scheduling; 7678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} alarm_stats_t; 7778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 7847616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski/* Wrapper around CancellableClosure that let it be embedded in structs, without 7947616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski * need to define copy operator. */ 8047616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowskistruct CancelableClosureInStruct { 8147616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski base::CancelableClosure i; 8247616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski 8347616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski CancelableClosureInStruct& operator=(const CancelableClosureInStruct& in) { 8447616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski if (!in.i.callback().is_null()) i.Reset(in.i.callback()); 8547616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski return *this; 8647616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski } 8747616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski}; 8847616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski 89f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistruct alarm_t { 9021da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen // The mutex is held while the callback for this alarm is being executed. 9178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // It allows us to release the coarse-grained monitor lock while a 9278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // potentially long-running callback is executing. |alarm_cancel| uses this 9321da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen // mutex to provide a guarantee to its caller that the callback will not be 9478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // in progress when it returns. 9521da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen std::recursive_mutex* callback_mutex; 96f2bf2308e90386754080a4fd7cc2ee7751eeab46Sharvil Nanavati period_ms_t creation_time; 97e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson period_ms_t period; 98f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati period_ms_t deadline; 99b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson period_ms_t prev_deadline; // Previous deadline - used for accounting of 100b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson // periodic timers 101e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson bool is_periodic; 102b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson fixed_queue_t* queue; // The processing queue to add this alarm to 103f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm_callback_t callback; 104b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson void* data; 10578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_stats_t stats; 10647616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski 10747616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski bool for_msg_loop; // True, if the alarm should be processed on message loop 10847616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski CancelableClosureInStruct closure; // posted to message loop for processing 109f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati}; 110f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 111f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati// If the next wakeup time is less than this threshold, we should acquire 112f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati// a wakelock instead of setting a wake alarm so we're not bouncing in 113f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati// and out of suspend frequently. This value is externally visible to allow 114f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati// unit tests to run faster. It should not be modified by production code. 115f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatiint64_t TIMER_INTERVAL_FOR_WAKELOCK_IN_MS = 3000; 116f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic const clockid_t CLOCK_ID = CLOCK_BOOTTIME; 11710978011f286d20f10eb949e3557ad00a62c8424Pavlin Radoslavov 118d19e0785e662e640191a075eda07acce61c2aedaMarie Janssen#if (KERNEL_MISSING_CLOCK_BOOTTIME_ALARM == TRUE) 11910978011f286d20f10eb949e3557ad00a62c8424Pavlin Radoslavovstatic const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME; 12010978011f286d20f10eb949e3557ad00a62c8424Pavlin Radoslavov#else 12128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssenstatic const clockid_t CLOCK_ID_ALARM = CLOCK_BOOTTIME_ALARM; 12210978011f286d20f10eb949e3557ad00a62c8424Pavlin Radoslavov#endif 123f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 124f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati// This mutex ensures that the |alarm_set|, |alarm_cancel|, and alarm callback 12578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// functions execute serially and not concurrently. As a result, this mutex 12678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// also protects the |alarms| list. 12721da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssenstatic std::mutex alarms_mutex; 128b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic list_t* alarms; 129f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic timer_t timer; 13028bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssenstatic timer_t wakeup_timer; 131f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic bool timer_set; 132f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 13378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// All alarm callbacks are dispatched from |dispatcher_thread| 134b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic thread_t* dispatcher_thread; 13578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovstatic bool dispatcher_thread_active; 136b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic semaphore_t* alarm_expired; 137081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 13878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// Default alarm callback thread and queue 139b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic thread_t* default_callback_thread; 140b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic fixed_queue_t* default_callback_queue; 14178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 142b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic alarm_t* alarm_new_internal(const char* name, bool is_periodic); 143f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic bool lazy_initialize(void); 144f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic period_ms_t now(void); 145b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void alarm_set_internal(alarm_t* alarm, period_ms_t period, 146b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_callback_t cb, void* data, 14747616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski fixed_queue_t* queue, bool for_msg_loop); 148b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void alarm_cancel_internal(alarm_t* alarm); 149b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void remove_pending_alarm(alarm_t* alarm); 150b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void schedule_next_instance(alarm_t* alarm); 151e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnsonstatic void reschedule_root_alarm(void); 152b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void alarm_queue_ready(fixed_queue_t* queue, void* context); 153b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void timer_callback(void* data); 154b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void callback_dispatch(void* context); 155b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic bool timer_create_internal(const clockid_t clock_id, timer_t* timer); 156b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void update_scheduling_stats(alarm_stats_t* stats, period_ms_t now_ms, 1571a7856018ab1608a3d681caab4eecd2185ff51f2Pavlin Radoslavov period_ms_t deadline_ms); 15847616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski// Registers |queue| for processing alarm callbacks on |thread|. 15947616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski// |queue| may not be NULL. |thread| may not be NULL. 16047616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowskistatic void alarm_register_processing_queue(fixed_queue_t* queue, 16147616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski thread_t* thread); 16278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 163b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void update_stat(stat_t* stat, period_ms_t delta) { 164b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (stat->max_ms < delta) stat->max_ms = delta; 16578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stat->total_ms += delta; 16678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stat->count++; 16778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 168f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 169b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonalarm_t* alarm_new(const char* name) { return alarm_new_internal(name, false); } 17078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 171b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonalarm_t* alarm_new_periodic(const char* name) { 17278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov return alarm_new_internal(name, true); 17378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 17478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 175b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic alarm_t* alarm_new_internal(const char* name, bool is_periodic) { 176f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati // Make sure we have a list we can insert alarms into. 17728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen if (!alarms && !lazy_initialize()) { 178f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(false); // if initialization failed, we should not continue 179f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati return NULL; 18028bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen } 181f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 182b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_t* ret = static_cast<alarm_t*>(osi_calloc(sizeof(alarm_t))); 183f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 18421da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen ret->callback_mutex = new std::recursive_mutex; 18578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov ret->is_periodic = is_periodic; 186b2a292b5d8df2f359c38b0787bc01181225a9bc9Pavlin Radoslavov ret->stats.name = osi_strdup(name); 18747616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski 18847616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski ret->for_msg_loop = false; 18947616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski // placement new 19047616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski new (&ret->closure) CancelableClosureInStruct(); 19147616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski 19278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // NOTE: The stats were reset by osi_calloc() above 19378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 194f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati return ret; 195f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 196f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 197b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid alarm_free(alarm_t* alarm) { 198b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!alarm) return; 199f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 200f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm_cancel(alarm); 20121da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen delete alarm->callback_mutex; 202b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson osi_free((void*)alarm->stats.name); 20347616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski alarm->closure.~CancelableClosureInStruct(); 204ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson osi_free(alarm); 205f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 206f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 207b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonperiod_ms_t alarm_get_remaining_ms(const alarm_t* alarm) { 208f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(alarm != NULL); 209165332bc6795049754fafe35024c2c605796c96aAndre Eisenbach period_ms_t remaining_ms = 0; 21078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t just_now = now(); 211165332bc6795049754fafe35024c2c605796c96aAndre Eisenbach 21221da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen std::lock_guard<std::mutex> lock(alarms_mutex); 213b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (alarm->deadline > just_now) remaining_ms = alarm->deadline - just_now; 214165332bc6795049754fafe35024c2c605796c96aAndre Eisenbach 215165332bc6795049754fafe35024c2c605796c96aAndre Eisenbach return remaining_ms; 21676356aee883af67898ddc1aa3b628195f396d42aVenkatRaghavan VijayaRaghavan} 21776356aee883af67898ddc1aa3b628195f396d42aVenkatRaghavan VijayaRaghavan 218b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid alarm_set(alarm_t* alarm, period_ms_t interval_ms, alarm_callback_t cb, 219b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson void* data) { 22047616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski alarm_set_internal(alarm, interval_ms, cb, data, default_callback_queue, 22147616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski false); 22271864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson} 22371864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson 22447616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowskivoid alarm_set_on_mloop(alarm_t* alarm, period_ms_t interval_ms, 22547616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski alarm_callback_t cb, void* data) { 22647616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski alarm_set_internal(alarm, interval_ms, cb, data, NULL, true); 22771864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson} 22871864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson 22971864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson// Runs in exclusion with alarm_cancel and timer_callback. 230b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void alarm_set_internal(alarm_t* alarm, period_ms_t period, 231b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_callback_t cb, void* data, 23247616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski fixed_queue_t* queue, bool for_msg_loop) { 233f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(alarms != NULL); 234f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(alarm != NULL); 235f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(cb != NULL); 236f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 23721da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen std::lock_guard<std::mutex> lock(alarms_mutex); 238f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 239f2bf2308e90386754080a4fd7cc2ee7751eeab46Sharvil Nanavati alarm->creation_time = now(); 240e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson alarm->period = period; 24178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->queue = queue; 242f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm->callback = cb; 243f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm->data = data; 24447616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski alarm->for_msg_loop = for_msg_loop; 245f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 24678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov schedule_next_instance(alarm); 24778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->stats.scheduled_count++; 248f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 249f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 250b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid alarm_cancel(alarm_t* alarm) { 251f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(alarms != NULL); 252b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!alarm) return; 253f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 25421da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen { 25521da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen std::lock_guard<std::mutex> lock(alarms_mutex); 25621da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen alarm_cancel_internal(alarm); 25721da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen } 258936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov 259936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov // If the callback for |alarm| is in progress, wait here until it completes. 26021da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen std::lock_guard<std::recursive_mutex> lock(*alarm->callback_mutex); 261936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov} 262f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 263936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov// Internal implementation of canceling an alarm. 26421da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen// The caller must hold the |alarms_mutex| 265b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void alarm_cancel_internal(alarm_t* alarm) { 266b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson bool needs_reschedule = 267b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson (!list_is_empty(alarms) && list_front(alarms) == alarm); 268f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 26978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov remove_pending_alarm(alarm); 27078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 271f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm->deadline = 0; 27278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->prev_deadline = 0; 273f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm->callback = NULL; 274f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm->data = NULL; 27578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->stats.canceled_count++; 276936591634fe55f8ef0744ff0f4b17e87bed433dePavlin Radoslavov alarm->queue = NULL; 277f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 278b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (needs_reschedule) reschedule_root_alarm(); 279f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 280f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 281b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonbool alarm_is_scheduled(const alarm_t* alarm) { 282b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if ((alarms == NULL) || (alarm == NULL)) return false; 28378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov return (alarm->callback != NULL); 28478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 28578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 2860933b4075e16589a073e85d8230677238b29b780Pavlin Radoslavovvoid alarm_cleanup(void) { 2871b2bd2c8b5b7be80cb4ce0ecf4e021ad16e4a540Marie Janssen // If lazy_initialize never ran there is nothing else to do 288b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!alarms) return; 289c6a1c261b87f194b298df01f002292d9e937ec75Zach Johnson 29078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dispatcher_thread_active = false; 291cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach semaphore_post(alarm_expired); 29278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_free(dispatcher_thread); 29378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dispatcher_thread = NULL; 29478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 29521da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen std::lock_guard<std::mutex> lock(alarms_mutex); 29693342476cae97c085e3f274a8bf1339b523f7132Pavlin Radoslavov 29778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov fixed_queue_free(default_callback_queue, NULL); 29878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov default_callback_queue = NULL; 29978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_free(default_callback_thread); 30078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov default_callback_thread = NULL; 301cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach 30293342476cae97c085e3f274a8bf1339b523f7132Pavlin Radoslavov timer_delete(wakeup_timer); 30393342476cae97c085e3f274a8bf1339b523f7132Pavlin Radoslavov timer_delete(timer); 304cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach semaphore_free(alarm_expired); 305cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach alarm_expired = NULL; 30693342476cae97c085e3f274a8bf1339b523f7132Pavlin Radoslavov 307cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach list_free(alarms); 308cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach alarms = NULL; 309cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach} 310cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach 311f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic bool lazy_initialize(void) { 312f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(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 31921da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen std::lock_guard<std::mutex> lock(alarms_mutex); 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 } 34696c42e70f5c6a74a737739aa9c297cd93540f43ePhilip Cuadra thread_set_rt_priority(default_callback_thread, THREAD_RT_PRIORITY); 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 } 36296c42e70f5c6a74a737739aa9c297cd93540f43ePhilip Cuadra thread_set_rt_priority(dispatcher_thread, THREAD_RT_PRIORITY); 36378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_post(dispatcher_thread, callback_dispatch, NULL); 364f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati return true; 36528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 36628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssenerror: 36778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov fixed_queue_free(default_callback_queue, NULL); 36878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov default_callback_queue = NULL; 36978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_free(default_callback_thread); 37078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov default_callback_thread = NULL; 37128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 37278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_free(dispatcher_thread); 37378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dispatcher_thread = NULL; 37478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 37578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dispatcher_thread_active = false; 37628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 37728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen semaphore_free(alarm_expired); 37828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen alarm_expired = NULL; 37928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 380b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (wakeup_timer_initialized) timer_delete(wakeup_timer); 38128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 382b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (timer_initialized) timer_delete(timer); 38328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 38428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen list_free(alarms); 38528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen alarms = NULL; 38628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 38728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen return false; 388f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 389f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 390f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic period_ms_t now(void) { 391f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(alarms != NULL); 392f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 393f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati struct timespec ts; 394f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati if (clock_gettime(CLOCK_ID, &ts) == -1) { 395b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_ERROR(LOG_TAG, "%s unable to get current time: %s", __func__, 396b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson strerror(errno)); 397f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati return 0; 398f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 399f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 400f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati return (ts.tv_sec * 1000LL) + (ts.tv_nsec / 1000000LL); 401f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 402f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 40378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// Remove alarm from internal alarm list and the processing queue 40421da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen// The caller must hold the |alarms_mutex| 405b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void remove_pending_alarm(alarm_t* alarm) { 40678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov list_remove(alarms, alarm); 40747616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski 40847616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski if (alarm->for_msg_loop) { 40947616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski alarm->closure.i.Cancel(); 41047616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski } else { 41147616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski while (fixed_queue_try_remove_from_queue(alarm->queue, alarm) != NULL) { 41247616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski // Remove all repeated alarm instances from the queue. 41347616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski // NOTE: We are defensive here - we shouldn't have repeated alarm 41447616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski // instances 41547616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski } 41678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 41778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 41878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 41921da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen// Must be called with |alarms_mutex| held 420b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void schedule_next_instance(alarm_t* alarm) { 42171864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson // If the alarm is currently set and it's at the start of the list, 42271864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson // we'll need to re-schedule since we've adjusted the earliest deadline. 423b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson bool needs_reschedule = 424b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson (!list_is_empty(alarms) && list_front(alarms) == alarm); 425b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (alarm->callback) remove_pending_alarm(alarm); 426f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 427e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson // Calculate the next deadline for this alarm 428e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson period_ms_t just_now = now(); 42978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t ms_into_period = 0; 430399f217fddd4ce195ada3b69575caeca74ca1314Pavlin Radoslavov if ((alarm->is_periodic) && (alarm->period != 0)) 43178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov ms_into_period = ((just_now - alarm->creation_time) % alarm->period); 432e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson alarm->deadline = just_now + (alarm->period - ms_into_period); 433f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 43471864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson // Add it into the timer list sorted by deadline (earliest deadline first). 43578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (list_is_empty(alarms) || 436b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson ((alarm_t*)list_front(alarms))->deadline > alarm->deadline) { 43771864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson list_prepend(alarms, alarm); 43878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } else { 439b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson for (list_node_t* node = list_begin(alarms); node != list_end(alarms); 440b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson node = list_next(node)) { 441b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson list_node_t* next = list_next(node); 442b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (next == list_end(alarms) || 443b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson ((alarm_t*)list_node(next))->deadline > alarm->deadline) { 44471864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson list_insert_after(alarms, node, alarm); 44571864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson break; 44671864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson } 44771864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson } 44878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 449f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 450b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson // If the new alarm has the earliest deadline, we need to re-evaluate our 451b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson // schedule. 45278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (needs_reschedule || 45378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov (!list_is_empty(alarms) && list_front(alarms) == alarm)) { 454e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson reschedule_root_alarm(); 45578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 456f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 457f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 45821da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen// NOTE: must be called with |alarms_mutex| held 459e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnsonstatic void reschedule_root_alarm(void) { 460f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(alarms != NULL); 461f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 46228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen const bool timer_was_set = timer_set; 463b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_t* next; 464b2a292b5d8df2f359c38b0787bc01181225a9bc9Pavlin Radoslavov int64_t next_expiration; 46528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 46628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // If used in a zeroed state, disarms the timer. 46728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen struct itimerspec timer_time; 46828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen memset(&timer_time, 0, sizeof(timer_time)); 469f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 470b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (list_is_empty(alarms)) goto done; 471f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 472b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson next = static_cast<alarm_t*>(list_front(alarms)); 473b2a292b5d8df2f359c38b0787bc01181225a9bc9Pavlin Radoslavov next_expiration = next->deadline - now(); 474518a94e706a6602ad69245b0d760cd40595109ffZach Johnson if (next_expiration < TIMER_INTERVAL_FOR_WAKELOCK_IN_MS) { 475518a94e706a6602ad69245b0d760cd40595109ffZach Johnson if (!timer_set) { 476d2e250824fca5c42b87b3b6f5fa19646ffa2d321Pavlin Radoslavov if (!wakelock_acquire()) { 47728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen LOG_ERROR(LOG_TAG, "%s unable to acquire wake lock", __func__); 478518a94e706a6602ad69245b0d760cd40595109ffZach Johnson goto done; 47971864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson } 480f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 481f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 48228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen timer_time.it_value.tv_sec = (next->deadline / 1000); 48328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen timer_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL; 48428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 48578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // It is entirely unsafe to call timer_settime(2) with a zeroed timerspec 48678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // for timers with *_ALARM clock IDs. Although the man page states that the 48778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // timer would be canceled, the current behavior (as of Linux kernel 3.17) 48878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // is that the callback is issued immediately. The only way to cancel an 48978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // *_ALARM timer is to delete the timer. But unfortunately, deleting and 49078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // re-creating a timer is rather expensive; every timer_create(2) spawns a 49178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // new thread. So we simply set the timer to fire at the largest possible 49278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // time. 49328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // 49478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // If we've reached this code path, we're going to grab a wake lock and 49578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // wait for the next timer to fire. In that case, there's no reason to 49678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // have a pending wakeup timer so we simply cancel it. 49728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen struct itimerspec end_of_time; 49828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen memset(&end_of_time, 0, sizeof(end_of_time)); 49928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen end_of_time.it_value.tv_sec = (time_t)(1LL << (sizeof(time_t) * 8 - 2)); 50028bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen timer_settime(wakeup_timer, TIMER_ABSTIME, &end_of_time, NULL); 50128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen } else { 50228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // WARNING: do not attempt to use relative timers with *_ALARM clock IDs 50328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // in kernels before 3.17 unless you have the following patch: 50428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // https://lkml.org/lkml/2014/7/7/576 50528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen struct itimerspec wakeup_time; 50628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen memset(&wakeup_time, 0, sizeof(wakeup_time)); 50728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 508f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati wakeup_time.it_value.tv_sec = (next->deadline / 1000); 509f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati wakeup_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL; 51028bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen if (timer_settime(wakeup_timer, TIMER_ABSTIME, &wakeup_time, NULL) == -1) 511b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_ERROR(LOG_TAG, "%s unable to set wakeup timer: %s", __func__, 512b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson strerror(errno)); 513f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 514f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 515518a94e706a6602ad69245b0d760cd40595109ffZach Johnsondone: 516b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson timer_set = 517b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson timer_time.it_value.tv_sec != 0 || timer_time.it_value.tv_nsec != 0; 5184be4396c8e4dc4c308219bdf402447a7feefe73ePavlin Radoslavov if (timer_was_set && !timer_set) { 519d2e250824fca5c42b87b3b6f5fa19646ffa2d321Pavlin Radoslavov wakelock_release(); 520f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 521f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 52228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen if (timer_settime(timer, TIMER_ABSTIME, &timer_time, NULL) == -1) 523db554581079863974af8e1289646f5deea6fc044Marie Janssen LOG_ERROR(LOG_TAG, "%s unable to set timer: %s", __func__, strerror(errno)); 524081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 52578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // If next expiration was in the past (e.g. short timer that got context 52678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // switched) then the timer might have diarmed itself. Detect this case and 52778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // work around it by manually signalling the |alarm_expired| semaphore. 528081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson // 52978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // It is possible that the timer was actually super short (a few 53078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // milliseconds) and the timer expired normally before we called 53178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // |timer_gettime|. Worst case, |alarm_expired| is signaled twice for that 53278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // alarm. Nothing bad should happen in that case though since the callback 53378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // dispatch function checks to make sure the timer at the head of the list 53478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // actually expired. 535081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson if (timer_set) { 536081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson struct itimerspec time_to_expire; 537081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson timer_gettime(timer, &time_to_expire); 53878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (time_to_expire.it_value.tv_sec == 0 && 53978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov time_to_expire.it_value.tv_nsec == 0) { 540b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_DEBUG( 541b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_TAG, 542b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson "%s alarm expiration too close for posix timers, switching to guns", 543b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson __func__); 544081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson semaphore_post(alarm_expired); 545f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 546081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson } 547081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson} 548081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 54947616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowskistatic void alarm_register_processing_queue(fixed_queue_t* queue, 55047616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski thread_t* thread) { 551f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(queue != NULL); 552f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(thread != NULL); 55378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 55478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov fixed_queue_register_dequeue(queue, thread_get_reactor(thread), 55578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_queue_ready, NULL); 55678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 55778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 55847616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowskistatic void alarm_ready_generic(alarm_t* alarm, 55947616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski std::unique_lock<std::mutex>& lock) { 56078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (alarm == NULL) { 561b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson return; // The alarm was probably canceled 56278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 56378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // 56478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // If the alarm is not periodic, we've fully serviced it now, and can reset 56578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // some of its internal state. This is useful to distinguish between expired 56678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // alarms and active ones. 56778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // 56878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_callback_t callback = alarm->callback; 569b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson void* data = alarm->data; 57078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t deadline = alarm->deadline; 57178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (alarm->is_periodic) { 57278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // The periodic alarm has been rescheduled and alarm->deadline has been 57378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // updated, hence we need to use the previous deadline. 57478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov deadline = alarm->prev_deadline; 57578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } else { 57678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->deadline = 0; 57778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->callback = NULL; 57878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->data = NULL; 579a8215323a1e6f21c8442943f68f8fbe59a3f9ba6Kamal Negi alarm->queue = NULL; 58078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 58178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 58221da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen std::lock_guard<std::recursive_mutex> cb_lock(*alarm->callback_mutex); 58321da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen lock.unlock(); 58478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 58578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // Update the statistics 5861a7856018ab1608a3d681caab4eecd2185ff51f2Pavlin Radoslavov update_scheduling_stats(&alarm->stats, now(), deadline); 5871a7856018ab1608a3d681caab4eecd2185ff51f2Pavlin Radoslavov 5881a7856018ab1608a3d681caab4eecd2185ff51f2Pavlin Radoslavov // NOTE: Do NOT access "alarm" after the callback, as a safety precaution 5891a7856018ab1608a3d681caab4eecd2185ff51f2Pavlin Radoslavov // in case the callback itself deleted the alarm. 5901a7856018ab1608a3d681caab4eecd2185ff51f2Pavlin Radoslavov callback(data); 59178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 59278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 59347616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowskistatic void alarm_ready_mloop(alarm_t* alarm) { 59447616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski std::unique_lock<std::mutex> lock(alarms_mutex); 59547616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski alarm_ready_generic(alarm, lock); 59647616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski} 59747616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski 59847616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowskistatic void alarm_queue_ready(fixed_queue_t* queue, UNUSED_ATTR void* context) { 59947616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski CHECK(queue != NULL); 60047616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski 60147616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski std::unique_lock<std::mutex> lock(alarms_mutex); 60247616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski alarm_t* alarm = (alarm_t*)fixed_queue_try_dequeue(queue); 60347616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski alarm_ready_generic(alarm, lock); 60447616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski} 60547616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski 606081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson// Callback function for wake alarms and our posix timer 607b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void timer_callback(UNUSED_ATTR void* ptr) { 608081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson semaphore_post(alarm_expired); 609081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson} 610f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 61178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// Function running on |dispatcher_thread| that performs the following: 61278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// (1) Receives a signal using |alarm_exired| that the alarm has expired 61378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// (2) Dispatches the alarm callback for processing by the corresponding 61478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// thread for that alarm. 615b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void callback_dispatch(UNUSED_ATTR void* context) { 616081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson while (true) { 617081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson semaphore_wait(alarm_expired); 618b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (!dispatcher_thread_active) break; 619081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 62021da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen std::lock_guard<std::mutex> lock(alarms_mutex); 621b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_t* alarm; 622081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 623081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson // Take into account that the alarm may get cancelled before we get to it. 624081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson // We're done here if there are no alarms or the alarm at the front is in 62521da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen // the future. Exit right away since there's nothing left to do. 62678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (list_is_empty(alarms) || 627b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson (alarm = static_cast<alarm_t*>(list_front(alarms)))->deadline > now()) { 628081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson reschedule_root_alarm(); 629081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson continue; 630f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 631f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 632081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson list_remove(alarms, alarm); 633081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 634081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson if (alarm->is_periodic) { 63578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->prev_deadline = alarm->deadline; 63678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov schedule_next_instance(alarm); 63778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->stats.rescheduled_count++; 638f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 63978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov reschedule_root_alarm(); 640f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 64178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // Enqueue the alarm for processing 64247616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski if (alarm->for_msg_loop) { 64347616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski if (!get_message_loop()) { 64447616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski LOG_ERROR(LOG_TAG, "%s: message loop already NULL. Alarm: %s", __func__, 64547616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski alarm->stats.name); 64647616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski continue; 64747616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski } 64847616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski 64947616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski alarm->closure.i.Reset(Bind(alarm_ready_mloop, alarm)); 65047616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski get_message_loop()->PostTask(FROM_HERE, alarm->closure.i.callback()); 65147616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski } else { 65247616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski fixed_queue_enqueue(alarm->queue, alarm); 65347616530ceea2ea6432ffb35cd8a3fc0a56365b5Jakub Pawlowski } 654f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 655cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach 656db554581079863974af8e1289646f5deea6fc044Marie Janssen LOG_DEBUG(LOG_TAG, "%s Callback thread exited", __func__); 657f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 65828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 659b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic bool timer_create_internal(const clockid_t clock_id, timer_t* timer) { 660f2af1c42ccb2f642b241c2261b42d0be61d45438Jack He CHECK(timer != NULL); 66128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 66228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen struct sigevent sigevent; 66396c42e70f5c6a74a737739aa9c297cd93540f43ePhilip Cuadra // create timer with RT priority thread 66496c42e70f5c6a74a737739aa9c297cd93540f43ePhilip Cuadra pthread_attr_t thread_attr; 66596c42e70f5c6a74a737739aa9c297cd93540f43ePhilip Cuadra pthread_attr_init(&thread_attr); 66696c42e70f5c6a74a737739aa9c297cd93540f43ePhilip Cuadra pthread_attr_setschedpolicy(&thread_attr, SCHED_FIFO); 66796c42e70f5c6a74a737739aa9c297cd93540f43ePhilip Cuadra struct sched_param param; 66896c42e70f5c6a74a737739aa9c297cd93540f43ePhilip Cuadra param.sched_priority = THREAD_RT_PRIORITY; 66996c42e70f5c6a74a737739aa9c297cd93540f43ePhilip Cuadra pthread_attr_setschedparam(&thread_attr, ¶m); 67096c42e70f5c6a74a737739aa9c297cd93540f43ePhilip Cuadra 67128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen memset(&sigevent, 0, sizeof(sigevent)); 67228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen sigevent.sigev_notify = SIGEV_THREAD; 67328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen sigevent.sigev_notify_function = (void (*)(union sigval))timer_callback; 6742b59c4a0843c9f2782cf4163f921eddb31dd6ff9Jack He sigevent.sigev_notify_attributes = &thread_attr; 67528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen if (timer_create(clock_id, &sigevent, timer) == -1) { 676b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_ERROR(LOG_TAG, "%s unable to create timer with clock %d: %s", __func__, 677b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson clock_id, strerror(errno)); 6784b7f560168f9e7523217d4b372fde4b0adba4d3bPavlin Radoslavov if (clock_id == CLOCK_BOOTTIME_ALARM) { 679b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_ERROR(LOG_TAG, 680b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson "The kernel might not have support for " 681b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson "timer_create(CLOCK_BOOTTIME_ALARM): " 682b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson "https://lwn.net/Articles/429925/"); 683b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson LOG_ERROR(LOG_TAG, 684b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson "See following patches: " 685b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson "https://git.kernel.org/cgit/linux/kernel/git/torvalds/" 686b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson "linux.git/log/?qt=grep&q=CLOCK_BOOTTIME_ALARM"); 6874b7f560168f9e7523217d4b372fde4b0adba4d3bPavlin Radoslavov } 68828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen return false; 68928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen } 69028bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 69128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen return true; 69228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen} 69378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 694b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void update_scheduling_stats(alarm_stats_t* stats, period_ms_t now_ms, 6951a7856018ab1608a3d681caab4eecd2185ff51f2Pavlin Radoslavov period_ms_t deadline_ms) { 69678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stats->total_updates++; 69778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stats->last_update_ms = now_ms; 69878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 69978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (deadline_ms < now_ms) { 70078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // Overdue scheduling 70178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t delta_ms = now_ms - deadline_ms; 70278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov update_stat(&stats->overdue_scheduling, delta_ms); 70378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } else if (deadline_ms > now_ms) { 70478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // Premature scheduling 70578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t delta_ms = deadline_ms - now_ms; 70678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov update_stat(&stats->premature_scheduling, delta_ms); 70778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 70878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 70978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 710b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonstatic void dump_stat(int fd, stat_t* stat, const char* description) { 711b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson period_ms_t average_time_ms = 0; 712b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson if (stat->count != 0) average_time_ms = stat->total_ms / stat->count; 713b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson 714b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson dprintf(fd, "%-51s: %llu / %llu / %llu\n", description, 715b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson (unsigned long long)stat->total_ms, (unsigned long long)stat->max_ms, 716b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson (unsigned long long)average_time_ms); 71778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 71878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 719b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watsonvoid alarm_debug_dump(int fd) { 72078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dprintf(fd, "\nBluetooth Alarms Statistics:\n"); 72178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 72221da63773cb7734e699a4dad662b5b84d2f3dfa8Marie Janssen std::lock_guard<std::mutex> lock(alarms_mutex); 72378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 72478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (alarms == NULL) { 72578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dprintf(fd, " None\n"); 72678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov return; 72778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 72878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 72978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t just_now = now(); 73078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 73178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dprintf(fd, " Total Alarms: %zu\n\n", list_length(alarms)); 73278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 73378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // Dump info for each alarm 734b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson for (list_node_t* node = list_begin(alarms); node != list_end(alarms); 73578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov node = list_next(node)) { 736b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_t* alarm = (alarm_t*)list_node(node); 737b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson alarm_stats_t* stats = &alarm->stats; 73878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 73978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dprintf(fd, " Alarm : %s (%s)\n", stats->name, 74078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov (alarm->is_periodic) ? "PERIODIC" : "SINGLE"); 74178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 742eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker dprintf(fd, "%-51s: %zu / %zu / %zu / %zu\n", 743399f217fddd4ce195ada3b69575caeca74ca1314Pavlin Radoslavov " Action counts (sched/resched/exec/cancel)", 74478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stats->scheduled_count, stats->rescheduled_count, 7451a7856018ab1608a3d681caab4eecd2185ff51f2Pavlin Radoslavov stats->total_updates, stats->canceled_count); 74678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 747eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker dprintf(fd, "%-51s: %zu / %zu\n", 748eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker " Deviation counts (overdue/premature)", 749b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson stats->overdue_scheduling.count, stats->premature_scheduling.count); 75078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 751eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker dprintf(fd, "%-51s: %llu / %llu / %lld\n", 752eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker " Time in ms (since creation/interval/remaining)", 75378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov (unsigned long long)(just_now - alarm->creation_time), 754b55040cc6448a8847490da807d2b6362aa8cb8d9Myles Watson (unsigned long long)alarm->period, 75578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov (long long)(alarm->deadline - just_now)); 75678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 757eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker dump_stat(fd, &stats->overdue_scheduling, 758eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker " Overdue scheduling time in ms (total/max/avg)"); 759eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker 76078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dump_stat(fd, &stats->premature_scheduling, 761eeec3be3cc7a4fea6e551b6ffb060ed3841216e6Ajay Panicker " Premature scheduling time in ms (total/max/avg)"); 76278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 76378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dprintf(fd, "\n"); 76478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 76578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 766