Ksched interface cleanup, smp_idle() cleanup
authorBarret Rhoden <brho@cs.berkeley.edu>
Thu, 8 Mar 2012 23:28:35 +0000 (15:28 -0800)
committerBarret Rhoden <brho@cs.berkeley.edu>
Fri, 9 Mar 2012 18:17:57 +0000 (10:17 -0800)
Moves the logic about what a core should do when having nothing to do to
the ksched.

kern/include/schedule.h
kern/src/schedule.c
kern/src/smp.c

index 0575957..228cc93 100644 (file)
 
 void schedule_init(void);
 
+/************** Process registration **************/
+/* _S procs will get 'scheduled' every time they become RUNNABLE.  MCPs will get
+ * registered on creation, and then that's it.  They will get removed from the
+ * lists 'naturally' when proc_destroy() sets their state to DYING.  The ksched
+ * needs to notice that, remove them from its lists, and decref. */
 /* _S is runnable, tell the ksched to try to run it. */
 void schedule_scp(struct proc *p);
 /* _M exists.  Tell the ksched about it. */
 void register_mcp(struct proc *p);
-/* to remove from these lists, simply proc_destroy - the ksched will notice */
 
+/************** Decision making **************/
+/* Call the main scheduling algorithm.  Not clear yet if the main kernel will
+ * ever call this directly. */
 void schedule(void);
 
-/* Take a look at proc's resource (temp interface) */
+/* Proc p's resource desires changed, it recently became RUNNABLE, or something
+ * in general that would lead to a new decision.  The process can directly poke
+ * the ksched via a syscall, so be careful of abuse. */
 void poke_ksched(struct proc *p, int res_type);
 
-/* Gets called when a pcore becomes idle (like in proc yield) */
+/* 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). */
+void cpu_bored(void);
+
+/* Gets called when a pcore becomes idle (like in proc yield).  These are 'cg'
+ * cores, given to MCPs, that have been async returned to the ksched.  If the
+ * ksched preempts a core, this won't get called (unless it yielded first).
+ * Note that this is called with a proc's lock held (for now). */
 void put_idle_core(uint32_t coreid);
+void put_idle_cores(uint32_t *pc_arr, uint32_t num);
+
+/* 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);
 
+/************** Proc's view of the world **************/
 /* How many vcores p will think it can have */
 uint32_t max_vcores(struct proc *p);
 
-/* Debugging */
+/************** Debugging **************/
 void sched_diag(void);
 void print_idlecoremap(void);
 void print_resources(struct proc *p);
index 1aff4ed..903fd77 100644 (file)
@@ -221,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);
@@ -231,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)
 {
index a3e051c..e500739 100644 (file)
@@ -17,7 +17,7 @@
 #include <assert.h>
 #include <pmap.h>
 #include <process.h>
-#include <manager.h>
+#include <schedule.h>
 #include <trap.h>
 
 struct per_cpu_info per_cpu_info[MAX_NUM_CPUS];
@@ -39,16 +39,14 @@ static void try_run_proc(void)
        }
 }
 
-/* All cores end up calling this whenever there is nothing left to do.  Non-zero
- * cores call it when they are done booting.  Other cases include after getting
- * a DEATH IPI.
- * - Management cores (core 0 for now) call manager, which should never return.
- * - Worker cores halt and wake up when interrupted, do any work on their work
- *   queue, then halt again.
- * TODO: think about unifying the manager into a workqueue function, so we don't
- * need to check mgmt_core in here.  it gets a little ugly, since there are
- * other places where we check for mgmt and might not smp_idle / call manager.
- */
+/* All cores end up calling this whenever there is nothing left to do or they
+ * don't know explicitly what to do.  Non-zero cores call it when they are done
+ * booting.  Other cases include after getting a DEATH IPI.
+ *
+ * All cores attempt to run the context of any owning proc.  Barring that, the
+ * cores enter a loop.  They halt and wake up when interrupted, do any work on
+ * their work queue, then halt again.  In between, the ksched gets a chance to
+ * tell it to do something else, or perhaps to halt in another manner. */
 static void __smp_idle(void)
 {
        int8_t state = 0;
@@ -60,29 +58,17 @@ static void __smp_idle(void)
        /* in the future, we may need to proactively leave process context here.
         * for now, it is possible to have a current loaded, even if we are idle
         * (and presumably about to execute a kmsg or fire up a vcore). */
-       if (!management_core()) {
-               while (1) {
-                       disable_irq();
-                       process_routine_kmsg(0);
-                       try_run_proc();
-                       /* cpu_halt() atomically turns on interrupts and halts the core.
-                        * Important to do this, since we could have a RKM come in via an
-                        * interrupt right while PRKM is returning, and we wouldn't catch
-                        * it. */
-                       cpu_halt();
-                       /* interrupts are back on now (given our current semantics) */
-               }
-       } else {
-               enable_irqsave(&state);
-               /* this makes us wait to enter the manager til any IO is done (totally
-                * arbitrary 10ms), so we can handle the routine message that we
-                * currently use to do the completion.  Note this also causes us to wait
-                * 10ms regardless of how long the IO takes.  This all needs work. */
-               //udelay(10000); /* done in the manager for now */
+       while (1) {
+               disable_irq();
                process_routine_kmsg(0);
                try_run_proc();
-               disable_irqsave(&state);
-               manager();
+               cpu_bored();            /* call out to the ksched */
+               /* cpu_halt() atomically turns on interrupts and halts the core.
+                * Important to do this, since we could have a RKM come in via an
+                * interrupt right while PRKM is returning, and we wouldn't catch
+                * it. */
+               cpu_halt();
+               /* interrupts are back on now (given our current semantics) */
        }
        assert(0);
 }