1f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati/****************************************************************************** 2f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * 3f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * Copyright (C) 2014 Google, Inc. 4f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * 5f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * Licensed under the Apache License, Version 2.0 (the "License"); 6f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * you may not use this file except in compliance with the License. 7f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * You may obtain a copy of the License at: 8f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * 9f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * http://www.apache.org/licenses/LICENSE-2.0 10f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * 11f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * Unless required by applicable law or agreed to in writing, software 12f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * distributed under the License is distributed on an "AS IS" BASIS, 13f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * See the License for the specific language governing permissions and 15f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * limitations under the License. 16f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati * 17f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati ******************************************************************************/ 18f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 1910978011f286d20f10eb949e3557ad00a62c8424Pavlin Radoslavov#include "include/bt_target.h" 2010978011f286d20f10eb949e3557ad00a62c8424Pavlin Radoslavov 21f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati#define LOG_TAG "bt_osi_alarm" 22f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 2349a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen#include "osi/include/alarm.h" 2449a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen 25f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati#include <assert.h> 26f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati#include <errno.h> 2728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen#include <fcntl.h> 281afbe154a89ad462de739704ce70eed0e32cbc00Michael Wright#include <inttypes.h> 29b9164f414b4d8d414358d0146a8f911207af3122Elliott Hughes#include <malloc.h> 3049a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen#include <pthread.h> 31468e4b983dd59ea58a7518032fa6029b00c56dc4Ian Coolidge#include <signal.h> 3249a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen#include <string.h> 33f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati#include <time.h> 34f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 3549a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen#include <hardware/bluetooth.h> 3649a86709488e5cfd5e23759da18bf9613e15b04dMarie Janssen 37081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson#include "osi/include/allocator.h" 3878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov#include "osi/include/fixed_queue.h" 390f9b91e150e153229235c163861198e23600e636Sharvil Nanavati#include "osi/include/list.h" 4044802768c447ab480d4227b3a852a97d923b816dSharvil Nanavati#include "osi/include/log.h" 41081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson#include "osi/include/osi.h" 42081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson#include "osi/include/semaphore.h" 43081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson#include "osi/include/thread.h" 44d2e250824fca5c42b87b3b6f5fa19646ffa2d321Pavlin Radoslavov#include "osi/include/wakelock.h" 45f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 4641a91a52b06171140938a1aa503bab8fe15e12e4Andre Eisenbach// Make callbacks run at high thread priority. Some callbacks are used for audio 4741a91a52b06171140938a1aa503bab8fe15e12e4Andre Eisenbach// related timer tasks as well as re-transmissions etc. Since we at this point 4841a91a52b06171140938a1aa503bab8fe15e12e4Andre Eisenbach// cannot differentiate what callback we are dealing with, assume high priority 4941a91a52b06171140938a1aa503bab8fe15e12e4Andre Eisenbach// for now. 5041a91a52b06171140938a1aa503bab8fe15e12e4Andre Eisenbach// TODO(eisenbach): Determine correct thread priority (from parent?/per alarm?) 5141a91a52b06171140938a1aa503bab8fe15e12e4Andre Eisenbachstatic const int CALLBACK_THREAD_PRIORITY_HIGH = -19; 5241a91a52b06171140938a1aa503bab8fe15e12e4Andre Eisenbach 5378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovtypedef struct { 5478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov size_t count; 5578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t total_ms; 5678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t max_ms; 5778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} stat_t; 5878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 5978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// Alarm-related information and statistics 6078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovtypedef struct { 6178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov const char *name; 6278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov size_t scheduled_count; 6378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov size_t canceled_count; 6478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov size_t rescheduled_count; 6578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov size_t total_updates; 6678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t last_update_ms; 6778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stat_t callback_execution; 6878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stat_t overdue_scheduling; 6978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stat_t premature_scheduling; 7078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} alarm_stats_t; 7178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 72f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistruct alarm_t { 73f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati // The lock is held while the callback for this alarm is being executed. 7478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // It allows us to release the coarse-grained monitor lock while a 7578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // potentially long-running callback is executing. |alarm_cancel| uses this 7678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // lock to provide a guarantee to its caller that the callback will not be 7778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // in progress when it returns. 78f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati pthread_mutex_t callback_lock; 79f2bf2308e90386754080a4fd7cc2ee7751eeab46Sharvil Nanavati period_ms_t creation_time; 80e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson period_ms_t period; 81f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati period_ms_t deadline; 8278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t prev_deadline; // Previous deadline - used for accounting of 8378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // periodic timers 84e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson bool is_periodic; 8578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov fixed_queue_t *queue; // The processing queue to add this alarm to 86f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm_callback_t callback; 87f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati void *data; 8878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_stats_t stats; 89f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati}; 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 9910978011f286d20f10eb949e3557ad00a62c8424Pavlin Radoslavov#if defined(KERNEL_MISSING_CLOCK_BOOTTIME_ALARM) && (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. 108f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic pthread_mutex_t monitor; 109f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic 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| 11578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovstatic thread_t *dispatcher_thread; 11678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovstatic bool dispatcher_thread_active; 117081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnsonstatic semaphore_t *alarm_expired; 118081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 11978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// Default alarm callback thread and queue 12078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovstatic thread_t *default_callback_thread; 12178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovstatic fixed_queue_t *default_callback_queue; 12278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 12378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovstatic alarm_t *alarm_new_internal(const char *name, bool is_periodic); 124f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic bool lazy_initialize(void); 125f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic period_ms_t now(void); 12678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovstatic void alarm_set_internal(alarm_t *alarm, period_ms_t period, 12778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_callback_t cb, void *data, 12878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov fixed_queue_t *queue); 1291db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavovstatic void alarm_cancel_internal(alarm_t *alarm); 13078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovstatic void remove_pending_alarm(alarm_t *alarm); 13178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovstatic void schedule_next_instance(alarm_t *alarm); 132e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnsonstatic void reschedule_root_alarm(void); 13378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovstatic void alarm_queue_ready(fixed_queue_t *queue, void *context); 134f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic void timer_callback(void *data); 135081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnsonstatic void callback_dispatch(void *context); 13628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssenstatic bool timer_create_internal(const clockid_t clock_id, timer_t *timer); 13778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovstatic void update_scheduling_stats(alarm_stats_t *stats, 13878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t now_ms, 13978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t deadline_ms, 14078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t execution_delta_ms); 14178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 14278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovstatic void update_stat(stat_t *stat, period_ms_t delta) 14378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov{ 14478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (stat->max_ms < delta) 14578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stat->max_ms = delta; 14678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stat->total_ms += delta; 14778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stat->count++; 14878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 149f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 15078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovalarm_t *alarm_new(const char *name) { 15178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov return alarm_new_internal(name, false); 15278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 15378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 15478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovalarm_t *alarm_new_periodic(const char *name) { 15578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov return alarm_new_internal(name, true); 15678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 15778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 15878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovstatic alarm_t *alarm_new_internal(const char *name, bool is_periodic) { 159f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati // Make sure we have a list we can insert alarms into. 16028bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen if (!alarms && !lazy_initialize()) { 16128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen assert(false); // if initialization failed, we should not continue 162f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati return NULL; 16328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen } 164f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 165f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati pthread_mutexattr_t attr; 166f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati pthread_mutexattr_init(&attr); 167f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 168ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson alarm_t *ret = osi_calloc(sizeof(alarm_t)); 169f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 170f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati // Make this a recursive mutex to make it safe to call |alarm_cancel| from 171f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati // within the callback function of the alarm. 172f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati int error = pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE); 173f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati if (error) { 17478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov LOG_ERROR(LOG_TAG, "%s unable to create a recursive mutex: %s", 17578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov __func__, strerror(error)); 176f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati goto error; 177f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 178f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 179f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati error = pthread_mutex_init(&ret->callback_lock, &attr); 180f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati if (error) { 18178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov LOG_ERROR(LOG_TAG, "%s unable to initialize mutex: %s", 18278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov __func__, strerror(error)); 183f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati goto error; 184f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 185f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 18678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov ret->is_periodic = is_periodic; 18778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 18878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_stats_t *stats = &ret->stats; 18978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stats->name = osi_strdup(name); 19078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // NOTE: The stats were reset by osi_calloc() above 19178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 192f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati pthread_mutexattr_destroy(&attr); 193f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati return ret; 194f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 19578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavoverror: 196f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati pthread_mutexattr_destroy(&attr); 197ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson osi_free(ret); 198f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati return NULL; 199f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 200f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 201f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavativoid alarm_free(alarm_t *alarm) { 202f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati if (!alarm) 203f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati return; 204f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 205f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm_cancel(alarm); 206f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati pthread_mutex_destroy(&alarm->callback_lock); 20778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov osi_free((void *)alarm->stats.name); 208ee2aa45def216a3c4d6a23481fa96f1b02a5de8cZach Johnson osi_free(alarm); 209f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 210f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 211165332bc6795049754fafe35024c2c605796c96aAndre Eisenbachperiod_ms_t alarm_get_remaining_ms(const alarm_t *alarm) { 21276356aee883af67898ddc1aa3b628195f396d42aVenkatRaghavan VijayaRaghavan assert(alarm != NULL); 213165332bc6795049754fafe35024c2c605796c96aAndre Eisenbach period_ms_t remaining_ms = 0; 21478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t just_now = now(); 215165332bc6795049754fafe35024c2c605796c96aAndre Eisenbach 216165332bc6795049754fafe35024c2c605796c96aAndre Eisenbach pthread_mutex_lock(&monitor); 21778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (alarm->deadline > just_now) 21878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov remaining_ms = alarm->deadline - just_now; 219165332bc6795049754fafe35024c2c605796c96aAndre Eisenbach pthread_mutex_unlock(&monitor); 220165332bc6795049754fafe35024c2c605796c96aAndre Eisenbach 221165332bc6795049754fafe35024c2c605796c96aAndre Eisenbach return remaining_ms; 22276356aee883af67898ddc1aa3b628195f396d42aVenkatRaghavan VijayaRaghavan} 22376356aee883af67898ddc1aa3b628195f396d42aVenkatRaghavan VijayaRaghavan 22478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovvoid alarm_set(alarm_t *alarm, period_ms_t interval_ms, 22578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_callback_t cb, void *data) { 22678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_set_on_queue(alarm, interval_ms, cb, data, default_callback_queue); 22771864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson} 22871864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson 22978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovvoid alarm_set_on_queue(alarm_t *alarm, period_ms_t interval_ms, 23078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_callback_t cb, void *data, 23178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov fixed_queue_t *queue) { 23278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov assert(queue != NULL); 23378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_set_internal(alarm, interval_ms, cb, data, queue); 23471864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson} 23571864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson 23671864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson// Runs in exclusion with alarm_cancel and timer_callback. 23778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovstatic void alarm_set_internal(alarm_t *alarm, period_ms_t period, 23878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_callback_t cb, void *data, 23978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov fixed_queue_t *queue) { 240f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati assert(alarms != NULL); 241f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati assert(alarm != NULL); 242f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati assert(cb != NULL); 243f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 244f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati pthread_mutex_lock(&monitor); 245f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 246f2bf2308e90386754080a4fd7cc2ee7751eeab46Sharvil Nanavati alarm->creation_time = now(); 247e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson alarm->period = period; 24878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->queue = queue; 249f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm->callback = cb; 250f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm->data = data; 251f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 25278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov schedule_next_instance(alarm); 25378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->stats.scheduled_count++; 254f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 255f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati pthread_mutex_unlock(&monitor); 256f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 257f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 258f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavativoid alarm_cancel(alarm_t *alarm) { 259f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati assert(alarms != NULL); 260dd7aaec9e8ccfeee5cd3f3a5caa1cc35d7870bdePavlin Radoslavov if (!alarm) 261dd7aaec9e8ccfeee5cd3f3a5caa1cc35d7870bdePavlin Radoslavov return; 262f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 263f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati pthread_mutex_lock(&monitor); 2641db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov alarm_cancel_internal(alarm); 2651db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov pthread_mutex_unlock(&monitor); 2661db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov 2671db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov // If the callback for |alarm| is in progress, wait here until it completes. 2681db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov pthread_mutex_lock(&alarm->callback_lock); 2691db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov pthread_mutex_unlock(&alarm->callback_lock); 2701db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov} 271f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 2721db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov// Internal implementation of canceling an alarm. 2731db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov// The caller must hold the |monitor| lock. 2741db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavovstatic void alarm_cancel_internal(alarm_t *alarm) { 275f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati bool needs_reschedule = (!list_is_empty(alarms) && list_front(alarms) == alarm); 276f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 27778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov remove_pending_alarm(alarm); 27878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 279f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm->deadline = 0; 28078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->prev_deadline = 0; 281f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm->callback = NULL; 282f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarm->data = NULL; 28378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->stats.canceled_count++; 2841db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov alarm->queue = NULL; 285f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 286f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati if (needs_reschedule) 287e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson reschedule_root_alarm(); 288f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 289f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 29078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovbool alarm_is_scheduled(const alarm_t *alarm) { 29178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if ((alarms == NULL) || (alarm == NULL)) 29278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov return false; 29378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov return (alarm->callback != NULL); 29478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 29578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 2960933b4075e16589a073e85d8230677238b29b780Pavlin Radoslavovvoid alarm_cleanup(void) { 2971b2bd2c8b5b7be80cb4ce0ecf4e021ad16e4a540Marie Janssen // If lazy_initialize never ran there is nothing else to do 298c6a1c261b87f194b298df01f002292d9e937ec75Zach Johnson if (!alarms) 299c6a1c261b87f194b298df01f002292d9e937ec75Zach Johnson return; 300c6a1c261b87f194b298df01f002292d9e937ec75Zach Johnson 30178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dispatcher_thread_active = false; 302cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach semaphore_post(alarm_expired); 30378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_free(dispatcher_thread); 30478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dispatcher_thread = NULL; 30578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 30697ec0a56f5282ee8977bc1dcb60bb86980e757d6Pavlin Radoslavov pthread_mutex_lock(&monitor); 30797ec0a56f5282ee8977bc1dcb60bb86980e757d6Pavlin Radoslavov 30878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov fixed_queue_free(default_callback_queue, NULL); 30978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov default_callback_queue = NULL; 31078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_free(default_callback_thread); 31178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov default_callback_thread = NULL; 312cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach 31397ec0a56f5282ee8977bc1dcb60bb86980e757d6Pavlin Radoslavov timer_delete(wakeup_timer); 31497ec0a56f5282ee8977bc1dcb60bb86980e757d6Pavlin Radoslavov timer_delete(timer); 315cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach semaphore_free(alarm_expired); 316cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach alarm_expired = NULL; 31797ec0a56f5282ee8977bc1dcb60bb86980e757d6Pavlin Radoslavov 318cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach list_free(alarms); 319cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach alarms = NULL; 320cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach 321f338fb754e00d51c31c96f755b05d8daf6006168Pavlin Radoslavov pthread_mutex_unlock(&monitor); 322cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach pthread_mutex_destroy(&monitor); 323cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach} 324cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach 325f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic bool lazy_initialize(void) { 326f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati assert(alarms == NULL); 327f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 32828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // timer_t doesn't have an invalid value so we must track whether 32928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // the |timer| variable is valid ourselves. 33028bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen bool timer_initialized = false; 33128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen bool wakeup_timer_initialized = false; 33228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 333f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati pthread_mutex_init(&monitor, NULL); 334f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 335f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati alarms = list_new(NULL); 336f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati if (!alarms) { 337db554581079863974af8e1289646f5deea6fc044Marie Janssen LOG_ERROR(LOG_TAG, "%s unable to allocate alarm list.", __func__); 33828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen goto error; 339f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 340f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 34128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen if (!timer_create_internal(CLOCK_ID, &timer)) 34228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen goto error; 34328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen timer_initialized = true; 34428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 34528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen if (!timer_create_internal(CLOCK_ID_ALARM, &wakeup_timer)) 34628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen goto error; 34728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen wakeup_timer_initialized = true; 348518a94e706a6602ad69245b0d760cd40595109ffZach Johnson 349081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson alarm_expired = semaphore_new(0); 350081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson if (!alarm_expired) { 351db554581079863974af8e1289646f5deea6fc044Marie Janssen LOG_ERROR(LOG_TAG, "%s unable to create alarm expired semaphore", __func__); 35228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen goto error; 353081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson } 354081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 35578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov default_callback_thread = thread_new_sized("alarm_default_callbacks", 35678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov SIZE_MAX); 35778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (default_callback_thread == NULL) { 35878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov LOG_ERROR(LOG_TAG, "%s unable to create default alarm callbacks thread.", 35978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov __func__); 36078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov goto error; 36178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 36278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_set_priority(default_callback_thread, CALLBACK_THREAD_PRIORITY_HIGH); 36378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov default_callback_queue = fixed_queue_new(SIZE_MAX); 36478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (default_callback_queue == NULL) { 36578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov LOG_ERROR(LOG_TAG, "%s unable to create default alarm callbacks queue.", 36678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov __func__); 36778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov goto error; 36878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 36978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_register_processing_queue(default_callback_queue, 37078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov default_callback_thread); 37178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 37278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dispatcher_thread_active = true; 37378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dispatcher_thread = thread_new("alarm_dispatcher"); 37478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (!dispatcher_thread) { 375db554581079863974af8e1289646f5deea6fc044Marie Janssen LOG_ERROR(LOG_TAG, "%s unable to create alarm callback thread.", __func__); 37628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen goto error; 377f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 378f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 37978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_set_priority(dispatcher_thread, CALLBACK_THREAD_PRIORITY_HIGH); 38078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_post(dispatcher_thread, callback_dispatch, NULL); 381f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati return true; 38228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 38328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssenerror: 38478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov fixed_queue_free(default_callback_queue, NULL); 38578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov default_callback_queue = NULL; 38678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_free(default_callback_thread); 38778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov default_callback_thread = NULL; 38828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 38978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov thread_free(dispatcher_thread); 39078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dispatcher_thread = NULL; 39178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 39278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dispatcher_thread_active = false; 39328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 39428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen semaphore_free(alarm_expired); 39528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen alarm_expired = NULL; 39628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 39728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen if (wakeup_timer_initialized) 39828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen timer_delete(wakeup_timer); 39928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 40028bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen if (timer_initialized) 40128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen timer_delete(timer); 40228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 40328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen list_free(alarms); 40428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen alarms = NULL; 40528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 40628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen pthread_mutex_destroy(&monitor); 40728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 40828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen return false; 409f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 410f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 411f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavatistatic period_ms_t now(void) { 412f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati assert(alarms != NULL); 413f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 414f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati struct timespec ts; 415f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati if (clock_gettime(CLOCK_ID, &ts) == -1) { 41678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov LOG_ERROR(LOG_TAG, "%s unable to get current time: %s", 41778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov __func__, strerror(errno)); 418f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati return 0; 419f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 420f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 421f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati return (ts.tv_sec * 1000LL) + (ts.tv_nsec / 1000000LL); 422f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 423f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 42478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// Remove alarm from internal alarm list and the processing queue 42578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// The caller must hold the |monitor| lock. 42678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovstatic void remove_pending_alarm(alarm_t *alarm) { 42778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov list_remove(alarms, alarm); 42878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov while (fixed_queue_try_remove_from_queue(alarm->queue, alarm) != NULL) { 42978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // Remove all repeated alarm instances from the queue. 43078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // NOTE: We are defensive here - we shouldn't have repeated alarm instances 43178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 43278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 43378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 43471864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson// Must be called with monitor held 43578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovstatic void schedule_next_instance(alarm_t *alarm) { 43671864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson // If the alarm is currently set and it's at the start of the list, 43771864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson // we'll need to re-schedule since we've adjusted the earliest deadline. 43871864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson bool needs_reschedule = (!list_is_empty(alarms) && list_front(alarms) == alarm); 43971864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson if (alarm->callback) 44078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov remove_pending_alarm(alarm); 441f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 442e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson // Calculate the next deadline for this alarm 443e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson period_ms_t just_now = now(); 44478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t ms_into_period = 0; 4458e4577f7b48aad4c4a36a0d5787139a36ca2be94Pavlin Radoslavov if ((alarm->is_periodic) && (alarm->period != 0)) 44678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov ms_into_period = ((just_now - alarm->creation_time) % alarm->period); 447e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson alarm->deadline = just_now + (alarm->period - ms_into_period); 448f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 44971864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson // Add it into the timer list sorted by deadline (earliest deadline first). 45078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (list_is_empty(alarms) || 45178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov ((alarm_t *)list_front(alarms))->deadline > alarm->deadline) { 45271864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson list_prepend(alarms, alarm); 45378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } else { 45471864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson for (list_node_t *node = list_begin(alarms); node != list_end(alarms); node = list_next(node)) { 45571864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson list_node_t *next = list_next(node); 45678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (next == list_end(alarms) || ((alarm_t *)list_node(next))->deadline > alarm->deadline) { 45771864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson list_insert_after(alarms, node, alarm); 45871864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson break; 45971864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson } 46071864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson } 46178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 462f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 46371864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson // If the new alarm has the earliest deadline, we need to re-evaluate our schedule. 46478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (needs_reschedule || 46578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov (!list_is_empty(alarms) && list_front(alarms) == alarm)) { 466e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnson reschedule_root_alarm(); 46778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 468f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 469f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 470f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati// NOTE: must be called with monitor lock. 471e2c57aaba4fd0c029a8cb4c519f6ef11f041b4deZach Johnsonstatic void reschedule_root_alarm(void) { 472f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati assert(alarms != NULL); 473f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 47428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen const bool timer_was_set = timer_set; 47528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 47628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // If used in a zeroed state, disarms the timer. 47728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen struct itimerspec timer_time; 47828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen memset(&timer_time, 0, sizeof(timer_time)); 479f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 480518a94e706a6602ad69245b0d760cd40595109ffZach Johnson if (list_is_empty(alarms)) 481518a94e706a6602ad69245b0d760cd40595109ffZach Johnson goto done; 482f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 48328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen const alarm_t *next = list_front(alarms); 48428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen const int64_t next_expiration = next->deadline - now(); 485518a94e706a6602ad69245b0d760cd40595109ffZach Johnson if (next_expiration < TIMER_INTERVAL_FOR_WAKELOCK_IN_MS) { 486518a94e706a6602ad69245b0d760cd40595109ffZach Johnson if (!timer_set) { 487d2e250824fca5c42b87b3b6f5fa19646ffa2d321Pavlin Radoslavov if (!wakelock_acquire()) { 48828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen LOG_ERROR(LOG_TAG, "%s unable to acquire wake lock", __func__); 489518a94e706a6602ad69245b0d760cd40595109ffZach Johnson goto done; 49071864f490d4dc31857df0b31924cd62a337e9f1aZach Johnson } 491f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 492f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 49328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen timer_time.it_value.tv_sec = (next->deadline / 1000); 49428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen timer_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL; 49528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 49678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // It is entirely unsafe to call timer_settime(2) with a zeroed timerspec 49778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // for timers with *_ALARM clock IDs. Although the man page states that the 49878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // timer would be canceled, the current behavior (as of Linux kernel 3.17) 49978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // is that the callback is issued immediately. The only way to cancel an 50078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // *_ALARM timer is to delete the timer. But unfortunately, deleting and 50178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // re-creating a timer is rather expensive; every timer_create(2) spawns a 50278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // new thread. So we simply set the timer to fire at the largest possible 50378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // time. 50428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // 50578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // If we've reached this code path, we're going to grab a wake lock and 50678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // wait for the next timer to fire. In that case, there's no reason to 50778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // have a pending wakeup timer so we simply cancel it. 50828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen struct itimerspec end_of_time; 50928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen memset(&end_of_time, 0, sizeof(end_of_time)); 51028bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen end_of_time.it_value.tv_sec = (time_t)(1LL << (sizeof(time_t) * 8 - 2)); 51128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen timer_settime(wakeup_timer, TIMER_ABSTIME, &end_of_time, NULL); 51228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen } else { 51328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // WARNING: do not attempt to use relative timers with *_ALARM clock IDs 51428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // in kernels before 3.17 unless you have the following patch: 51528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen // https://lkml.org/lkml/2014/7/7/576 51628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen struct itimerspec wakeup_time; 51728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen memset(&wakeup_time, 0, sizeof(wakeup_time)); 51828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 51928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 520f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati wakeup_time.it_value.tv_sec = (next->deadline / 1000); 521f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati wakeup_time.it_value.tv_nsec = (next->deadline % 1000) * 1000000LL; 52228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen if (timer_settime(wakeup_timer, TIMER_ABSTIME, &wakeup_time, NULL) == -1) 52328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen LOG_ERROR(LOG_TAG, "%s unable to set wakeup timer: %s", 52428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen __func__, strerror(errno)); 525f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 526f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 527518a94e706a6602ad69245b0d760cd40595109ffZach Johnsondone: 52828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen timer_set = timer_time.it_value.tv_sec != 0 || timer_time.it_value.tv_nsec != 0; 5294be4396c8e4dc4c308219bdf402447a7feefe73ePavlin Radoslavov if (timer_was_set && !timer_set) { 530d2e250824fca5c42b87b3b6f5fa19646ffa2d321Pavlin Radoslavov wakelock_release(); 531f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 532f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 53328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen if (timer_settime(timer, TIMER_ABSTIME, &timer_time, NULL) == -1) 534db554581079863974af8e1289646f5deea6fc044Marie Janssen LOG_ERROR(LOG_TAG, "%s unable to set timer: %s", __func__, strerror(errno)); 535081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 53678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // If next expiration was in the past (e.g. short timer that got context 53778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // switched) then the timer might have diarmed itself. Detect this case and 53878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // work around it by manually signalling the |alarm_expired| semaphore. 539081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson // 54078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // It is possible that the timer was actually super short (a few 54178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // milliseconds) and the timer expired normally before we called 54278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // |timer_gettime|. Worst case, |alarm_expired| is signaled twice for that 54378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // alarm. Nothing bad should happen in that case though since the callback 54478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // dispatch function checks to make sure the timer at the head of the list 54578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // actually expired. 546081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson if (timer_set) { 547081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson struct itimerspec time_to_expire; 548081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson timer_gettime(timer, &time_to_expire); 54978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (time_to_expire.it_value.tv_sec == 0 && 55078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov time_to_expire.it_value.tv_nsec == 0) { 55178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov LOG_DEBUG(LOG_TAG, "%s alarm expiration too close for posix timers, switching to guns", __func__); 552081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson semaphore_post(alarm_expired); 553f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 554081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson } 555081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson} 556081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 55778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovvoid alarm_register_processing_queue(fixed_queue_t *queue, thread_t *thread) { 55878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov assert(queue != NULL); 55978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov assert(thread != NULL); 56078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 56178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov fixed_queue_register_dequeue(queue, thread_get_reactor(thread), 56278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_queue_ready, NULL); 56378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 56478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 56578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovvoid alarm_unregister_processing_queue(fixed_queue_t *queue) { 5661db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov assert(alarms != NULL); 5671db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov assert(queue != NULL); 5681db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov 56978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov fixed_queue_unregister_dequeue(queue); 5701db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov 5711db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov // Cancel all alarms that are using this queue 5721db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov pthread_mutex_lock(&monitor); 5731db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov for (list_node_t *node = list_begin(alarms); node != list_end(alarms); ) { 5741db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov alarm_t *alarm = (alarm_t *)list_node(node); 5751db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov node = list_next(node); 5761db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov // TODO: Each module is responsible for tearing down its alarms; currently, 5771db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov // this is not the case. In the future, this check should be replaced by 5781db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov // an assert. 5791db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov if (alarm->queue == queue) 5801db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov alarm_cancel_internal(alarm); 5811db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov } 5821db7f1b0a7d235977ac81623ab06c51df8b493dePavlin Radoslavov pthread_mutex_unlock(&monitor); 58378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 58478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 58578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovstatic void alarm_queue_ready(fixed_queue_t *queue, 58678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov UNUSED_ATTR void *context) { 58778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov assert(queue != NULL); 58878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 58978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov pthread_mutex_lock(&monitor); 59078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_t *alarm = (alarm_t *)fixed_queue_try_dequeue(queue); 59178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (alarm == NULL) { 59278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov pthread_mutex_unlock(&monitor); 59378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov return; // The alarm was probably canceled 59478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 59578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 59678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // 59778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // If the alarm is not periodic, we've fully serviced it now, and can reset 59878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // some of its internal state. This is useful to distinguish between expired 59978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // alarms and active ones. 60078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // 60178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_callback_t callback = alarm->callback; 60278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov void *data = alarm->data; 60378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t deadline = alarm->deadline; 60478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (alarm->is_periodic) { 60578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // The periodic alarm has been rescheduled and alarm->deadline has been 60678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // updated, hence we need to use the previous deadline. 60778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov deadline = alarm->prev_deadline; 60878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } else { 60978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->deadline = 0; 61078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->callback = NULL; 61178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->data = NULL; 61278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 61378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 61478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov pthread_mutex_lock(&alarm->callback_lock); 61578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov pthread_mutex_unlock(&monitor); 61678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 61778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t t0 = now(); 61878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov callback(data); 61978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t t1 = now(); 62078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 62178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // Update the statistics 62278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov assert(t1 >= t0); 62378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t delta = t1 - t0; 62478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov update_scheduling_stats(&alarm->stats, t0, deadline, delta); 62578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 62678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov pthread_mutex_unlock(&alarm->callback_lock); 62778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 62878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 629081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson// Callback function for wake alarms and our posix timer 630081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnsonstatic void timer_callback(UNUSED_ATTR void *ptr) { 631081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson semaphore_post(alarm_expired); 632081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson} 633f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 63478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// Function running on |dispatcher_thread| that performs the following: 63578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// (1) Receives a signal using |alarm_exired| that the alarm has expired 63678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// (2) Dispatches the alarm callback for processing by the corresponding 63778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov// thread for that alarm. 638081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnsonstatic void callback_dispatch(UNUSED_ATTR void *context) { 639081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson while (true) { 640081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson semaphore_wait(alarm_expired); 64178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (!dispatcher_thread_active) 642cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach break; 643081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 644cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach pthread_mutex_lock(&monitor); 645081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson alarm_t *alarm; 646081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 647081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson // Take into account that the alarm may get cancelled before we get to it. 648081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson // We're done here if there are no alarms or the alarm at the front is in 649081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson // the future. Release the monitor lock and exit right away since there's 650081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson // nothing left to do. 65178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (list_is_empty(alarms) || 65278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov (alarm = list_front(alarms))->deadline > now()) { 653081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson reschedule_root_alarm(); 654081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson pthread_mutex_unlock(&monitor); 655081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson continue; 656f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 657f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 658081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson list_remove(alarms, alarm); 659081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 660081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson if (alarm->is_periodic) { 66178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->prev_deadline = alarm->deadline; 66278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov schedule_next_instance(alarm); 66378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm->stats.rescheduled_count++; 664f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 66578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov reschedule_root_alarm(); 666f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati 66778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // Enqueue the alarm for processing 66878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov fixed_queue_enqueue(alarm->queue, alarm); 669081e4b67b44a5fd397c2d79a5566e11ae52d4acaZach Johnson 67078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov pthread_mutex_unlock(&monitor); 671f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati } 672cae219fe70124f1fc39cd7a78c239c4870422d5dAndre Eisenbach 673db554581079863974af8e1289646f5deea6fc044Marie Janssen LOG_DEBUG(LOG_TAG, "%s Callback thread exited", __func__); 674f0e7c8b895c61104ce962b7c5e3705a32943d711Sharvil Nanavati} 67528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 67628bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssenstatic bool timer_create_internal(const clockid_t clock_id, timer_t *timer) { 67728bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen assert(timer != NULL); 67828bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 67928bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen struct sigevent sigevent; 68028bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen memset(&sigevent, 0, sizeof(sigevent)); 68128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen sigevent.sigev_notify = SIGEV_THREAD; 68228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen sigevent.sigev_notify_function = (void (*)(union sigval))timer_callback; 68328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen if (timer_create(clock_id, &sigevent, timer) == -1) { 68428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen LOG_ERROR(LOG_TAG, "%s unable to create timer with clock %d: %s", 68528bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen __func__, clock_id, strerror(errno)); 6864b7f560168f9e7523217d4b372fde4b0adba4d3bPavlin Radoslavov if (clock_id == CLOCK_BOOTTIME_ALARM) { 6874b7f560168f9e7523217d4b372fde4b0adba4d3bPavlin Radoslavov LOG_ERROR(LOG_TAG, "The kernel might not have support for timer_create(CLOCK_BOOTTIME_ALARM): https://lwn.net/Articles/429925/"); 6884b7f560168f9e7523217d4b372fde4b0adba4d3bPavlin Radoslavov LOG_ERROR(LOG_TAG, "See following patches: https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/log/?qt=grep&q=CLOCK_BOOTTIME_ALARM"); 6894b7f560168f9e7523217d4b372fde4b0adba4d3bPavlin Radoslavov } 69028bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen return false; 69128bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen } 69228bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen 69328bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen return true; 69428bf007f7103ccd36d5fa2f87837947a27cc698dMarie Janssen} 69578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 69678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovstatic void update_scheduling_stats(alarm_stats_t *stats, 69778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t now_ms, 69878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t deadline_ms, 69978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t execution_delta_ms) 70078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov{ 70178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stats->total_updates++; 70278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stats->last_update_ms = now_ms; 70378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 70478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov update_stat(&stats->callback_execution, execution_delta_ms); 70578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 70678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (deadline_ms < now_ms) { 70778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // Overdue scheduling 70878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t delta_ms = now_ms - deadline_ms; 70978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov update_stat(&stats->overdue_scheduling, delta_ms); 71078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } else if (deadline_ms > now_ms) { 71178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // Premature scheduling 71278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t delta_ms = deadline_ms - now_ms; 71378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov update_stat(&stats->premature_scheduling, delta_ms); 71478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 71578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 71678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 71778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovstatic void dump_stat(int fd, stat_t *stat, const char *description) 71878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov{ 71925ddee0ed62c1a265362e107446d99613952b2b4Ajay Panicker period_ms_t average_time_ms = 0; 72025ddee0ed62c1a265362e107446d99613952b2b4Ajay Panicker if (stat->count != 0) 72125ddee0ed62c1a265362e107446d99613952b2b4Ajay Panicker average_time_ms = stat->total_ms / stat->count; 72278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 72325ddee0ed62c1a265362e107446d99613952b2b4Ajay Panicker dprintf(fd, "%-51s: %llu / %llu / %llu\n", 72478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov description, 72578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov (unsigned long long)stat->total_ms, 72678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov (unsigned long long)stat->max_ms, 72725ddee0ed62c1a265362e107446d99613952b2b4Ajay Panicker (unsigned long long)average_time_ms); 72878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 72978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 73078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavovvoid alarm_debug_dump(int fd) 73178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov{ 73278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dprintf(fd, "\nBluetooth Alarms Statistics:\n"); 73378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 73478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov pthread_mutex_lock(&monitor); 73578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 73678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov if (alarms == NULL) { 73778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov pthread_mutex_unlock(&monitor); 73878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dprintf(fd, " None\n"); 73978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov return; 74078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 74178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 74278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov period_ms_t just_now = now(); 74378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 74478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dprintf(fd, " Total Alarms: %zu\n\n", list_length(alarms)); 74578bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 74678bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov // Dump info for each alarm 74778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov for (list_node_t *node = list_begin(alarms); node != list_end(alarms); 74878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov node = list_next(node)) { 74978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_t *alarm = (alarm_t *)list_node(node); 75078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov alarm_stats_t *stats = &alarm->stats; 75178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 75278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dprintf(fd, " Alarm : %s (%s)\n", stats->name, 75378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov (alarm->is_periodic) ? "PERIODIC" : "SINGLE"); 75478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 75525ddee0ed62c1a265362e107446d99613952b2b4Ajay Panicker dprintf(fd, "%-51s: %zu / %zu / %zu / %zu\n", 7568e4577f7b48aad4c4a36a0d5787139a36ca2be94Pavlin Radoslavov " Action counts (sched/resched/exec/cancel)", 75778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stats->scheduled_count, stats->rescheduled_count, 75878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stats->callback_execution.count, stats->canceled_count); 75978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 76025ddee0ed62c1a265362e107446d99613952b2b4Ajay Panicker dprintf(fd, "%-51s: %zu / %zu\n", 76125ddee0ed62c1a265362e107446d99613952b2b4Ajay Panicker " Deviation counts (overdue/premature)", 76278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stats->overdue_scheduling.count, 76378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov stats->premature_scheduling.count); 76478bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 76525ddee0ed62c1a265362e107446d99613952b2b4Ajay Panicker dprintf(fd, "%-51s: %llu / %llu / %lld\n", 76625ddee0ed62c1a265362e107446d99613952b2b4Ajay Panicker " Time in ms (since creation/interval/remaining)", 76778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov (unsigned long long)(just_now - alarm->creation_time), 76878bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov (unsigned long long) alarm->period, 76978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov (long long)(alarm->deadline - just_now)); 77078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 77125ddee0ed62c1a265362e107446d99613952b2b4Ajay Panicker dump_stat(fd, &stats->callback_execution, 77225ddee0ed62c1a265362e107446d99613952b2b4Ajay Panicker " Callback execution time in ms (total/max/avg)"); 77325ddee0ed62c1a265362e107446d99613952b2b4Ajay Panicker 77425ddee0ed62c1a265362e107446d99613952b2b4Ajay Panicker dump_stat(fd, &stats->overdue_scheduling, 77525ddee0ed62c1a265362e107446d99613952b2b4Ajay Panicker " Overdue scheduling time in ms (total/max/avg)"); 77625ddee0ed62c1a265362e107446d99613952b2b4Ajay Panicker 77778bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dump_stat(fd, &stats->premature_scheduling, 77825ddee0ed62c1a265362e107446d99613952b2b4Ajay Panicker " Premature scheduling time in ms (total/max/avg)"); 77978bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov 78078bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov dprintf(fd, "\n"); 78178bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov } 78278bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov pthread_mutex_unlock(&monitor); 78378bcff79e1b1f0efce436b33bdd6da88745bfc8aPavlin Radoslavov} 784