Ksched interface cleanup, smp_idle() cleanup
[akaros.git] / kern / src / schedule.c
index 01b9469..903fd77 100644 (file)
@@ -16,6 +16,7 @@
 #include <atomic.h>
 #include <smp.h>
 #include <manager.h>
+#include <alarm.h>
 #include <sys/queue.h>
 
 /* Process Lists */
@@ -39,10 +40,49 @@ uint32_t num_mgmtcores = 1;
 /* Helper, defined below */
 static void __core_request(struct proc *p);
 
+/* Alarm struct, for our example 'timer tick' */
+struct alarm_waiter ksched_waiter;
+
+#define TIMER_TICK_USEC 10000  /* 10msec */
+
+/* Helper: Sets up a timer tick on the calling core to go off 10 msec from now.
+ * This assumes the calling core is an LL core, etc. */
+static void set_ksched_alarm(void)
+{
+       set_awaiter_rel(&ksched_waiter, TIMER_TICK_USEC);
+       set_alarm(&per_cpu_info[core_id()].tchain, &ksched_waiter);
+}
+
+/* Kmsg, to run the scheduler tick (not in interrupt context) and reset the
+ * alarm.  Note that interrupts will be disabled, but this is not the same as
+ * interrupt context.  We're a routine kmsg, which means the core is in a
+ * quiescent state. */
+static void __ksched_tick(struct trapframe *tf, uint32_t srcid, long a0,
+                          long a1, long a2)
+{
+       /* TODO: imagine doing some accounting here */
+       schedule();
+       /* Set our alarm to go off, incrementing from our last tick (instead of
+        * setting it relative to now, since some time has passed since the alarm
+        * first went off.  Note, this may be now or in the past! */
+       set_awaiter_inc(&ksched_waiter, TIMER_TICK_USEC);
+       set_alarm(&per_cpu_info[core_id()].tchain, &ksched_waiter);
+}
+
+/* Interrupt/alarm handler: tells our core to run the scheduler (out of
+ * interrupt context). */
+static void __kalarm(struct alarm_waiter *waiter)
+{
+       send_kernel_message(core_id(), __ksched_tick, 0, 0, 0, KMSG_ROUTINE);
+}
+
 void schedule_init(void)
 {
        TAILQ_INIT(&runnable_scps);
        TAILQ_INIT(&all_mcps);
+       assert(!core_id());             /* want the alarm on core0 for now */
+       init_awaiter(&ksched_waiter, __kalarm);
+       set_ksched_alarm();
 
        /* Ghetto old idle core init */
        /* Init idle cores. Core 0 is the management core. */
@@ -181,9 +221,28 @@ void poke_ksched(struct proc *p, int res_type)
        spin_unlock(&sched_lock);
 }
 
+/* The calling cpu/core has nothing to do and plans to idle/halt.  This is an
+ * opportunity to pick the nature of that halting (low power state, etc), or
+ * provide some other work (_Ss on LL cores).  Note that interrupts are
+ * disabled, and if you return, the core will cpu_halt(). */
+void cpu_bored(void)
+{
+       if (!management_core())
+               return;
+       /* TODO: something smart.  For now, do what smp_idle did */
+       manager();
+       assert(0);
+       /* TODO run a process, and if none exist at all and we're core 0, bring up
+        * the monitor/manager */
+}
+
 /* Helper function to return a core to the idlemap.  It causes some more lock
  * acquisitions (like in a for loop), but it's a little easier.  Plus, one day
- * we might be able to do this without locks (for the putting). */
+ * we might be able to do this without locks (for the putting).
+ *
+ * TODO: this is a trigger, telling us we have more cores.  Could/should make a
+ * scheduling decision (or at least plan to).  Note that right now, the proc's
+ * lock is still being held, so we can't do anything in this context. */
 void put_idle_core(uint32_t coreid)
 {
        spin_lock(&idle_lock);
@@ -191,6 +250,24 @@ void put_idle_core(uint32_t coreid)
        spin_unlock(&idle_lock);
 }
 
+/* Bulk interface for put_idle */
+void put_idle_cores(uint32_t *pc_arr, uint32_t num)
+{
+       spin_lock(&idle_lock);
+       for (int i = 0; i < num; i++)
+               idlecoremap[num_idlecores++] = pc_arr[i];
+       spin_unlock(&idle_lock);
+}
+
+/* Available resources changed (plus or minus).  Some parts of the kernel may
+ * call this if a particular resource that is 'quantity-based' changes.  Things
+ * like available RAM to processes, bandwidth, etc.  Cores would probably be
+ * inappropriate, since we need to know which specific core is now free. */
+void avail_res_changed(int res_type, long change)
+{
+       printk("[kernel] ksched doesn't track any resources yet!\n");
+}
+
 /* Normally it'll be the max number of CG cores ever */
 uint32_t max_vcores(struct proc *p)
 {