Rework the Linux-compat timer code

Our alarm code is mostly sufficient to do the things Linux's timers do.
The old code was unable to cancel timers and was just a huge hack.  This
is just a moderate hack.

Signed-off-by: Barret Rhoden <brho@cs.berkeley.edu>
diff --git a/kern/include/linux/compat_todo.h b/kern/include/linux/compat_todo.h
index 32836ca..a1eed08 100644
--- a/kern/include/linux/compat_todo.h
+++ b/kern/include/linux/compat_todo.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 1991-2015, the Linux Kernel authors
+ * Copyright (C) 1991-2019, the Linux Kernel authors
  *
  * This source code is licensed under the GNU General Public License,
  * Version 2. See the file COPYING for more details.
@@ -300,7 +300,7 @@
 	return timeout;
 }
 
-#define jiffies tsc2msec(read_tsc())
+#define jiffies (unsigned long)tsc2msec(read_tsc())
 
 static inline unsigned long round_jiffies(unsigned long j)
 {
@@ -317,73 +317,88 @@
 	return m;
 }
 
-#define time_after_eq(a, b) ((b) <= (a))
+/* These time macros are from Linux 5.2 */
+#define time_after(a,b)         \
+        (typecheck(unsigned long, a) && \
+         typecheck(unsigned long, b) && \
+         ((long)((b) - (a)) < 0))
+#define time_before(a,b)        time_after(b,a)
+
+#define time_after_eq(a,b)      \
+        (typecheck(unsigned long, a) && \
+         typecheck(unsigned long, b) && \
+         ((long)((a) - (b)) >= 0))
+#define time_before_eq(a,b)     time_after_eq(b,a)
+
+#define time_is_before_jiffies(a) time_after(jiffies, a)
+#define time_is_after_jiffies(a) time_before(jiffies, a)
+#define time_is_before_eq_jiffies(a) time_after_eq(jiffies, a)
+#define time_is_after_eq_jiffies(a) time_before_eq(jiffies, a)
+
 
 struct timer_list {
-	spinlock_t lock;
-	bool scheduled;
-	unsigned long expires;
-	void (*function)(unsigned long);
+	struct alarm_waiter alarm;
+	unsigned long expires;	// jiffies
+	union {
+		void (*func_a)(unsigned long);
+		void (*func)(struct timer_list*);
+	};
+	bool has_arg;
 	unsigned long data;
 };
 
-static inline void init_timer(struct timer_list *timer)
+/* Intermediate layer that handles setup_timer-style functions with arguments,
+ * until we can change the older Linux drivers. */
+static inline void timer_fired(struct alarm_waiter *waiter)
 {
-	spinlock_init_irqsave(&timer->lock);
-	timer->scheduled = false;
-	timer->expires = -1;
-	timer->function = 0;
-	timer->data = 0;
+	struct timer_list *timer = container_of(waiter, struct timer_list,
+						alarm);
+	if (timer->has_arg)
+		timer->func_a(timer->data);
+	else
+		timer->func(timer);
 }
 
 static inline void setup_timer(struct timer_list *timer,
                                void (*func)(unsigned long), unsigned long data)
 {
-	init_timer(timer);
-	timer->function = func;
+	init_awaiter(&timer->alarm, timer_fired);
+
+	timer->func_a = func;
+	timer->has_arg = true;
 	timer->data = data;
 }
 
-static void __timer_wrapper(uint32_t srcid, long a0, long a1, long a2)
+static inline void timer_setup(struct timer_list *timer,
+			       void (*func)(struct timer_list *), int flags)
 {
-	struct timer_list *timer = (struct timer_list *)a0;
-	unsigned long expires, now_j;
+	init_awaiter(&timer->alarm, timer_fired);
 
-	spin_lock_irqsave(&timer->lock);
-	expires = timer->expires;
-	timer->scheduled = false;
-	spin_unlock_irqsave(&timer->lock);
-
-	now_j = jiffies;
-	if (expires > now_j)
-		kthread_usleep((expires - now_j) * 1000);
-	timer->function(timer->data);
+	timer->func = func;
+	timer->has_arg = false;
 }
 
 static inline void add_timer(struct timer_list *timer)
 {
-	timer->scheduled = true;
-	send_kernel_message(core_id(), __timer_wrapper, (long)timer, 0, 0,
-			    KMSG_ROUTINE);
+	struct timer_chain *tchain = &per_cpu_info[0].tchain;
+	struct alarm_waiter *waiter = &timer->alarm;
+
+	set_awaiter_abs(waiter, msec2tsc(timer->expires));
+	set_alarm(tchain, waiter);
 }
 
 static inline void mod_timer(struct timer_list *timer, unsigned long expires)
 {
-	spin_lock_irqsave(&timer->lock);
+	struct timer_chain *tchain = &per_cpu_info[0].tchain;
+	struct alarm_waiter *waiter = &timer->alarm;
+
 	timer->expires = expires;
-	if (timer->scheduled) {
-		spin_unlock_irqsave(&timer->lock);
-		return;
-	}
-	timer->scheduled = true;
-	spin_unlock_irqsave(&timer->lock);
-	send_kernel_message(core_id(), __timer_wrapper, (long)timer, 0, 0,
-			    KMSG_ROUTINE);
+	reset_alarm_abs(tchain, waiter, msec2tsc(expires));
 }
 
 static inline void del_timer_sync(struct timer_list *timer)
 {
-	panic("del_timer_sync unimplemented");
+	unset_alarm(&per_cpu_info[0].tchain, &timer->alarm);
 }
 
 static inline void setup_timer_on_stack(struct timer_list *timer,
@@ -397,14 +412,14 @@
 {
 }
 
-/* TODO: This is nasty (all of the timer stuff).  We don't know if a timer
- * actually finished or not.  Someone could mod_timer repeatedly and have the
- * same handler running concurrently.  */
 static inline bool timer_pending(struct timer_list *timer)
 {
-	return timer->expires >= jiffies;
+	return !alarm_expired(&timer->alarm);
 }
 
+#define from_timer(var, callback_timer, timer_fieldname) \
+	container_of(callback_timer, typeof(*var), timer_fieldname)
+
 struct cpu_rmap {
 };