parlib: UTH_EXT_BLK_JUSTICE -> _MISC
[akaros.git] / kern / include / alarm.h
index 619f42d..1a7e387 100644 (file)
@@ -5,8 +5,7 @@
  * Alarms.  This includes various ways to sleep for a while or defer work on a
  * specific timer.  These can be per-core, global or whatever.  Deferred work
  * is a function pointer which runs in interrupt context when the alarm goes off
- * (picture running the ksched then).  The other style is to block/sleep on the
- * awaiter after the alarm is set.
+ * (picture running the ksched then).
  *
  * Like with most systems, you won't wake up til after the time you specify (for
  * now).  This might change, esp if we tweak things to coalesce alarms.
  * irqsave locks.
  *
  * Another important difference between IRQ and RKM alarms comes when cancelling
- * or unsetting an alarm.  When you cancel (unset or reset) an alarm, the alarm
- * is yanked off the tchain.  If the waiter was on the chain, then it will not
- * fire for both IRQ and RKM alarms.  If the waiter was not on the chain, then
- * for IRQ alarms, this means that the alarm has already fired.  However, for
- * RKM alarms, the alarm may have already fired or it may still be waiting to
- * fire (sitting in an RKM queue).  It will fire at some point, but perhaps it
- * has not fired yet.  It is also possibly (though extremely unlikely) that if
- * you reset an RKM alarm that the new alarm actually happens before the old one
- * (if the new RKM was sent to another core).  
- * 
+ * or unsetting an alarm.  When you cancel (unset or reset) an alarm, you may
+ * need to block until the RKM has run.  IRQ alarms run with the tchain lock
+ * held, so once the canceller grabs the lock, it has either run already or will
+ * not at all.  With RKMs, the handler runs outside of the lock.  Thus you may
+ * have to wait until the RKM has run, and the RKM might be waiting to run on
+ * your core.
+ *
+ * Note that RKM unset_alarm() has a waits-on dependency with the actual alarm
+ * handler, so be careful of deadlock.
+ *
  * To use an IRQ alarm, init the waiter with init_awaiter_irq().
  *
  * Quick howto, using the pcpu tchains:
  *     struct timer_chain *tchain = &per_cpu_info[core_id()].tchain;
- * 1) To block your kthread on an alarm:
- *     struct alarm_waiter a_waiter;
- *     init_awaiter(&a_waiter, 0); // or init_awaiter_irq() for IRQ ctx alarms
- *     set_awaiter_rel(&a_waiter, USEC);
- *     set_alarm(tchain, &a_waiter);
- *     sleep_on_awaiter(&a_waiter);
- * 2) To set a handler to run on an alarm:
+ * To block your kthread on an alarm:
  *     struct alarm_waiter *waiter = kmalloc(sizeof(struct alarm_waiter), 0);
- *     init_awaiter(waiter, HANDLER);
+ *     struct alarm_waiter a_waiter;   // or use the stack
+ *
+ *     init_awaiter(waiter, HANDLER); // or init_awaiter_irq() for IRQ ctx alarms
  *     set_awaiter_rel(waiter, USEC);
  *     set_alarm(tchain, waiter);
+ *
  * If you want the HANDLER to run again, do this at the end of it:
  *     set_awaiter_rel(waiter, USEC);  // or whenever you want it to fire
  *     set_alarm(tchain, waiter);
  * Don't forget to manage your memory at some (safe) point:
  *     kfree(waiter);
  * In the future, we might have a slab for these.  You can get it from wherever
- * you want, just don't use the stack for handler style, since you'll usually
- * return and pop up the stack after setting the alarm.
- * */
+ * you want, just be careful if you use the stack. */
 
-#ifndef ROS_KERN_ALARM_H
-#define ROS_KERN_ALARM_H
+#pragma once
 
 #include <ros/common.h>
 #include <sys/queue.h>
 #include <kthread.h>
 
-/* These structures allow code to block or defer work for a certain amount of
- * time.  Timer chains (like off a per-core timer) are made of lists/trees of
- * these. 
- *
- * If you have a func pointer, that handler will run when the alarm goes off.
- * If you don't have a func pointer, you sleep on the semaphore and block your
- * kthread.  In the latter case, you ought to allocate space for them on the
- * stack of the thread you're about to block on. */
+/* These structures allow code to defer work for a certain amount of time.
+ * Timer chains (like off a per-core timer) are made of lists/trees of these. */
 struct alarm_waiter {
        uint64_t                                        wake_up_time;   /* ugh, this is a TSC for now */
        union {
                void (*func) (struct alarm_waiter *waiter);
                void (*func_irq) (struct alarm_waiter *waiter,
                                  struct hw_trapframe *hw_tf);
-               struct semaphore                        sem;            /* kthread will sleep on this */
        };
        void                                            *data;
        TAILQ_ENTRY(alarm_waiter)       next;
        bool                                            on_tchain;
        bool                                            irq_ok;
        bool                                            holds_tchain_lock;
-       bool                                            has_func;
+       bool                                            rkm_pending;
+       struct cond_var                         rkm_cv;
 };
 TAILQ_HEAD(awaiters_tailq, alarm_waiter);              /* ideally not a LL */
 
@@ -122,16 +109,19 @@ void init_awaiter_irq(struct alarm_waiter *waiter,
 void set_awaiter_abs(struct alarm_waiter *waiter, uint64_t abs_time);
 void set_awaiter_rel(struct alarm_waiter *waiter, uint64_t usleep);
 void set_awaiter_inc(struct alarm_waiter *waiter, uint64_t usleep);
-/* Arms/disarms the alarm. */
+/* Arms/disarms the alarm.  Can be called from within a handler.*/
 void set_alarm(struct timer_chain *tchain, struct alarm_waiter *waiter);
+/* Unset and reset may block if the alarm is not IRQ.  Do not call from within a
+ * handler.  Returns TRUE if you stopped the alarm from firing. */
 bool unset_alarm(struct timer_chain *tchain, struct alarm_waiter *waiter);
+/* Convenience wrappers for unset, then set.  Slower, but easier than just
+ * setting, since you don't need to know if it fired.  Returns TRUE if the alarm
+ * did not fire before your reset. */
 bool reset_alarm_abs(struct timer_chain *tchain, struct alarm_waiter *waiter,
                      uint64_t abs_time);
 bool reset_alarm_rel(struct timer_chain *tchain, struct alarm_waiter *waiter,
                      uint64_t usleep);
 
-/* Blocks on the alarm waiter */
-int sleep_on_awaiter(struct alarm_waiter *waiter);
 /* Interrupt handlers need to call this.  Don't call it directly. */
 void __trigger_tchain(struct timer_chain *tchain, struct hw_trapframe *hw_tf);
 /* Sets the timer chain interrupt according to the next timer in the chain. */
@@ -141,5 +131,3 @@ void set_pcpu_alarm_interrupt(struct timer_chain *tchain);
 #define ALARM_POISON_TIME 12345                                /* could use some work */
 void print_chain(struct timer_chain *tchain);
 void print_pcpu_chains(void);
-
-#endif /* ROS_KERN_ALARM_H */