Fixes spin_trylock()
[akaros.git] / kern / include / alarm.h
index dcf1f02..ac6c0f8 100644 (file)
  * 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.
  *
- * If you're using a global alarm timer_chain, you'll probably need to grab a
- * lock.  The only current user is pcpu tchains, though the code ought be able
- * to handle other uses.
+ * All tchains come with locks.  Originally, I left these out, since the pcpu
+ * tchains didn't need them (disable_irq was sufficient).  However, disabling
+ * alarms remotely (a valid use case) is a real pain without locks, so now
+ * everyone has locks.  As an added benefit, you can submit an alarm to another
+ * core's pcpu tchain (though it probably costs an extra IRQ).  Note there is a
+ * lock ordering, tchains before awaiters (when they are grabbed together).
  *
  * Quick howto, using the pcpu tchains:
  *     struct timer_chain *tchain = &per_cpu_info[core_id()].tchain;
- *     struct alarm_waiter a_waiter;
  * 1) To block your kthread on an alarm:
+ *     struct alarm_waiter a_waiter;
  *     init_awaiter(&a_waiter, 0);
  *     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:
- *     init_awaiter(&a_waiter, HANDLER);
- *     set_awaiter_rel(&a_waiter, USEC);
- *     set_alarm(tchain, &a_waiter);
- * If you want the HANDLER to run again, do this at the end of it::
+ *     struct alarm_waiter *waiter = kmalloc(sizeof(struct alarm_waiter), 0);
+ *     init_awaiter(waiter, HANDLER);
  *     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);
+ *     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.
  * */
 
 #ifndef ROS_KERN_ALARM_H
@@ -53,13 +62,17 @@ struct alarm_waiter {
        struct semaphore                        sem;                    /* kthread will sleep on this */
        void                                            *data;
        TAILQ_ENTRY(alarm_waiter)       next;
+       bool                                            has_fired;
 };
 TAILQ_HEAD(awaiters_tailq, alarm_waiter);              /* ideally not a LL */
 
-/* One of these per alarm source, such as a per-core timer.  Based on the
- * source, you may need a lock (such as for a global timer).  set_interrupt() is
- * a method for setting the interrupt source. */
+typedef void (*alarm_handler)(struct alarm_waiter *waiter);
+
+/* One of these per alarm source, such as a per-core timer.  All tchains come
+ * with a lock, even if its rarely needed (like the pcpu tchains).
+ * set_interrupt() is a method for setting the interrupt source. */
 struct timer_chain {
+       spinlock_t                                      lock;
        struct awaiters_tailq           waiters;
        uint64_t                                        earliest_time;
        uint64_t                                        latest_time;
@@ -75,9 +88,10 @@ void init_awaiter(struct alarm_waiter *waiter,
 /* Sets the time an awaiter goes off */
 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 */
 void set_alarm(struct timer_chain *tchain, struct alarm_waiter *waiter);
-void unset_alarm(struct timer_chain *tchain, struct alarm_waiter *waiter);
+bool unset_alarm(struct timer_chain *tchain, struct alarm_waiter *waiter);
 /* Blocks on the alarm waiter */
 int sleep_on_awaiter(struct alarm_waiter *waiter);
 /* Interrupt handlers needs to call this.  Don't call it directly. */
@@ -86,6 +100,7 @@ void trigger_tchain(struct timer_chain *tchain);
 void set_pcpu_alarm_interrupt(uint64_t time, struct timer_chain *tchain);
 
 /* Debugging */
+#define ALARM_POISON_TIME 12345                                /* could use some work */
 void print_chain(struct timer_chain *tchain);
 void print_pcpu_chains(void);