akaros/kern/include/alarm.h
<<
>>
Prefs
   1/* Copyright (c) 2011 The Regents of the University of California
   2 * Copyright (c) 2018 Google Inc.
   3 * Barret Rhoden <brho@cs.berkeley.edu>
   4 * See LICENSE for details.
   5 *
   6 * Alarms.  This includes various ways to sleep for a while or defer work on a
   7 * specific timer.  These can be per-core, global or whatever.  Deferred work
   8 * is a function pointer which runs in interrupt context when the alarm goes off
   9 * (picture running the ksched then).
  10 *
  11 * Like with most systems, you won't wake up til after the time you specify (for
  12 * now).  This might change, esp if we tweak things to coalesce alarms.
  13 *
  14 * All tchains come with locks.  Originally, I left these out, since the pcpu
  15 * tchains didn't need them (disable_irq was sufficient).  However, disabling
  16 * alarms remotely (a valid use case) is a real pain without locks, so now
  17 * everyone has locks.  As an added benefit, you can submit an alarm to another
  18 * core's pcpu tchain (though it probably costs an extra IRQ).  Note there is a
  19 * lock ordering, tchains before awaiters (when they are grabbed together).
  20 *
  21 * There are two options for pcpu alarms: hard IRQ and routine KMSG (RKM).
  22 * IRQ alarms are run directly in the timer interrupt handler and take a hw_tf
  23 * parameter in addition to the standard alarm_waiter.  RKM alarms are executed
  24 * when kernel messages are executed, which is out of IRQ context.  RKMs are
  25 * safer, since you can sleep (qlock, some kmalloc, etc) and you do not need
  26 * irqsave locks.
  27 *
  28 * Another important difference between IRQ and RKM alarms comes when cancelling
  29 * or unsetting an alarm.  When you cancel (unset or reset) an alarm, you may
  30 * need to block until the RKM has run.  IRQ alarms run with the tchain lock
  31 * held, so once the canceller grabs the lock, it has either run already or will
  32 * not at all.  With RKMs, the handler runs outside of the lock.  Thus you may
  33 * have to wait until the RKM has run, and the RKM might be waiting to run on
  34 * your core.
  35 *
  36 * Note that RKM unset_alarm() has a waits-on dependency with the actual alarm
  37 * handler, so be careful of deadlock.
  38 *
  39 * Quick howto, using the pcpu tchains:
  40 *      struct timer_chain *tchain = &per_cpu_info[core_id()].tchain;
  41 * To block your kthread on an alarm:
  42 *      struct alarm_waiter *waiter = kmalloc(sizeof(struct alarm_waiter), 0);
  43 *
  44 *      init_awaiter(waiter, HANDLER);
  45 *      set_awaiter_rel(waiter, USEC);
  46 *      set_alarm(tchain, waiter);
  47 *
  48 * If you want the HANDLER to run again, do this at the end of it:
  49 *      set_awaiter_rel(waiter, USEC);  // or whenever you want it to fire
  50 *      set_alarm(tchain, waiter);
  51 * or:
  52 *      reset_alarm_rel(tchain, waiter, USEC);
  53 *
  54 * Don't forget to manage your memory at some (safe) point:
  55 *      kfree(waiter);
  56 * In the future, we might have a slab for these.  You can get it from wherever
  57 * you want, just be careful if you use the stack. */
  58
  59#pragma once
  60
  61#include <ros/common.h>
  62#include <sys/queue.h>
  63#include <kthread.h>
  64
  65/* These structures allow code to defer work for a certain amount of time.
  66 * Timer chains (like off a per-core timer) are made of lists/trees of these. */
  67struct alarm_waiter {
  68        uint64_t                        wake_up_time;
  69        void (*func) (struct alarm_waiter *waiter);
  70        void                            *data;
  71        TAILQ_ENTRY(alarm_waiter)       next;
  72        bool                            on_tchain;
  73};
  74TAILQ_HEAD(awaiters_tailq, alarm_waiter);               /* ideally not a LL */
  75
  76typedef void (*alarm_handler)(struct alarm_waiter *waiter);
  77
  78/* One of these per alarm source, such as a per-core timer.  All tchains come
  79 * with a lock, even if its rarely needed (like the pcpu tchains).
  80 * set_interrupt() is a method for setting the interrupt source. */
  81struct timer_chain {
  82        spinlock_t                      lock;
  83        struct awaiters_tailq           waiters;
  84        struct alarm_waiter             *running;
  85        uint64_t                        earliest_time;
  86        uint64_t                        latest_time;
  87        struct cond_var                 cv;
  88        void (*set_interrupt)(struct timer_chain *);
  89};
  90
  91/* Called once per timer chain, currently in per_cpu_init() */
  92void init_timer_chain(struct timer_chain *tchain,
  93                      void (*set_interrupt)(struct timer_chain *));
  94/* For fresh alarm waiters.  func == 0 for kthreads */
  95void init_awaiter(struct alarm_waiter *waiter,
  96                  void (*func) (struct alarm_waiter *));
  97/* Sets the time an awaiter goes off */
  98void set_awaiter_abs(struct alarm_waiter *waiter, uint64_t abs_time);
  99void set_awaiter_rel(struct alarm_waiter *waiter, uint64_t usleep);
 100void set_awaiter_inc(struct alarm_waiter *waiter, uint64_t usleep);
 101/* Arms/disarms the alarm.  Can be called from within a handler.*/
 102void set_alarm(struct timer_chain *tchain, struct alarm_waiter *waiter);
 103/* Unset and reset may block if the alarm is not IRQ.  Do not call from within a
 104 * handler.  Returns TRUE if you stopped the alarm from firing. */
 105bool unset_alarm(struct timer_chain *tchain, struct alarm_waiter *waiter);
 106/* Convenience wrappers for unset, then set.  Slower, but easier than just
 107 * setting, since you don't need to know if it fired.  Returns TRUE if the alarm
 108 * did not fire before your reset. */
 109bool reset_alarm_abs(struct timer_chain *tchain, struct alarm_waiter *waiter,
 110                     uint64_t abs_time);
 111bool reset_alarm_rel(struct timer_chain *tchain, struct alarm_waiter *waiter,
 112                     uint64_t usleep);
 113
 114/* Interrupt handlers need to call this.  Don't call it directly. */
 115void __trigger_tchain(struct timer_chain *tchain, struct hw_trapframe *hw_tf);
 116/* Sets the timer chain interrupt according to the next timer in the chain. */
 117void set_pcpu_alarm_interrupt(struct timer_chain *tchain);
 118
 119static inline bool alarm_expired(struct alarm_waiter *awaiter)
 120{
 121        return awaiter->wake_up_time <= read_tsc();
 122}
 123
 124/* Debugging */
 125#define ALARM_POISON_TIME 12345         /* could use some work */
 126void print_chain(struct timer_chain *tchain);
 127void print_pcpu_chains(void);
 128