proc_destroy() now starts in the ksched
authorBarret Rhoden <brho@cs.berkeley.edu>
Fri, 20 Apr 2012 00:07:32 +0000 (17:07 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 23 Apr 2012 23:03:27 +0000 (16:03 -0700)
This allows the kernel scheduler to lock first, which helps with some
other lock-ordering trickery we do, and allows the ksched to do
additional cleanup, other than just receiving the idle cores.

Additionally, we have less of a need for put_idle_cores() (the only
caller is an old preemption function, which might get sucked into the
ksched soon).

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

index 59c77db..ed15ea6 100644 (file)
@@ -13,6 +13,7 @@
 #include <trap.h>
 #include <atomic.h>
 #include <kref.h>
+#include <schedule.h>
 
 /* Process States.  Not 100% on the names yet.  RUNNABLE_* are waiting to go to
  * RUNNING_*.  For instance, RUNNABLE_M is expecting to go to RUNNING_M.  It
@@ -72,7 +73,7 @@ void proc_decref(struct proc *p);
 void proc_run_s(struct proc *p);
 void __proc_run_m(struct proc *p);
 void proc_restartcore(void);
-void proc_destroy(struct proc *SAFE p);
+bool __proc_destroy(struct proc *p, uint32_t *pc_arr, uint32_t *nr_revoked);
 void __proc_change_to_m(struct proc *p);
 void __proc_yield_s(struct proc *p, struct trapframe *tf);
 void proc_yield(struct proc *SAFE p, bool being_nice);
index 9b87499..5b5754c 100644 (file)
@@ -9,7 +9,9 @@
 #ifndef ROS_KERN_SCHEDULE_H
 #define ROS_KERN_SCHEDULE_H
 
-#include <process.h>
+#include <ros/common.h>
+
+struct proc;   /* process.h includes us, but we need pointers now */
 
 void schedule_init(void);
 
@@ -23,6 +25,10 @@ void schedule_scp(struct proc *p);
 /* _M exists.  Tell the ksched about it. */
 void register_mcp(struct proc *p);
 
+/* The ksched starts the death process (lock ordering issue), which calls back
+ * to proc.c's __proc_destroy while holding the locks (or whatever) */
+void proc_destroy(struct proc *p);
+
 /************** Decision making **************/
 /* Call the main scheduling algorithm.  Not clear yet if the main kernel will
  * ever call this directly. */
index 8fa0045..3ed127e 100644 (file)
@@ -655,10 +655,12 @@ void proc_restartcore(void)
        __proc_startcore(pcpui->owning_proc, pcpui->cur_tf);
 }
 
-/*
- * Destroys the given process.  This may be called from another process, a light
- * kernel thread (no real process context), asynchronously/cross-core, or from
- * the process on its own core.
+/* Destroys the process.  This should be called by the ksched, which needs to
+ * hold the lock.  It will destroy the process and return any cores allocated to
+ * the proc via pc_arr and nr_revoked.  It's up to the caller to have enough
+ * space for pc_arr.  This will return TRUE if we successfully killed it, FALSE
+ * otherwise.  Failure isn't a big deal either - it can happen due to concurrent
+ * calls to proc_destroy. 
  *
  * Here's the way process death works:
  * 0. grab the lock (protects state transition and core map)
@@ -678,21 +680,16 @@ void proc_restartcore(void)
  * come in, making you abandon_core, as if you weren't running.  It may be that
  * the only reference to p is the one you passed in, and when you decref, it'll
  * get __proc_free()d. */
-void proc_destroy(struct proc *p)
+bool __proc_destroy(struct proc *p, uint32_t *pc_arr, uint32_t *nr_revoked)
 {
-       uint32_t num_revoked = 0;
        struct kthread *sleeper;
-       spin_lock(&p->proc_lock);
-       /* storage for pc_arr is alloced at decl, which is after grabbing the lock*/
-       uint32_t pc_arr[p->procinfo->num_vcores];
        switch (p->state) {
                case PROC_DYING: // someone else killed this already.
-                       spin_unlock(&p->proc_lock);
-                       return;
+                       return FALSE;
                case PROC_RUNNABLE_M:
                        /* Need to reclaim any cores this proc might have, even though it's
                         * not running yet. */
-                       num_revoked = __proc_take_allcores(p, pc_arr, FALSE);
+                       *nr_revoked = __proc_take_allcores(p, pc_arr, FALSE);
                        // fallthrough
                case PROC_RUNNABLE_S:
                        /* might need to pull from lists, though i'm currently a fan of the
@@ -724,14 +721,19 @@ void proc_destroy(struct proc *p)
                         * deallocate the cores.
                         * The rule is that the vcoremap is set before proc_run, and reset
                         * within proc_destroy */
-                       num_revoked = __proc_take_allcores(p, pc_arr, FALSE);
+                       *nr_revoked = __proc_take_allcores(p, pc_arr, FALSE);
                        break;
                case PROC_CREATED:
                        break;
                default:
-                       panic("Weird state(%s) in %s()", procstate2str(p->state),
-                             __FUNCTION__);
+                       warn("Weird state(%s) in %s()", procstate2str(p->state),
+                            __FUNCTION__);
+                       return FALSE;
        }
+       /* At this point, a death IPI should be on its way, either from the
+        * RUNNING_S one, or from proc_take_cores with a __death.  in general,
+        * interrupts should be on when you call proc_destroy locally, but currently
+        * aren't for all things (like traphandlers). */
        __proc_set_state(p, PROC_DYING);
        /* This prevents processes from accessing their old files while dying, and
         * will help if these files (or similar objects in the future) hold
@@ -743,15 +745,7 @@ void proc_destroy(struct proc *p)
        sleeper = __up_sem(&p->state_change, TRUE);
        if (sleeper)
                kthread_runnable(sleeper);
-       /* Unlock.  A death IPI should be on its way, either from the RUNNING_S one,
-        * or from proc_take_cores with a __death.  in general, interrupts should be
-        * on when you call proc_destroy locally, but currently aren't for all
-        * things (like traphandlers). */
-       spin_unlock(&p->proc_lock);
-       /* Return the cores to the ksched */
-       if (num_revoked)
-               put_idle_cores(pc_arr, num_revoked);
-       return;
+       return TRUE;
 }
 
 /* Turns *p into an MCP.  Needs to be called from a local syscall of a RUNNING_S
index 371fb7e..ff8d04e 100644 (file)
@@ -153,6 +153,35 @@ void register_mcp(struct proc *p)
        //poke_ksched(p, RES_CORES);
 }
 
+/* Destroys the given process.  This may be called from another process, a light
+ * kernel thread (no real process context), asynchronously/cross-core, or from
+ * the process on its own core.
+ *
+ * An external, edible ref is passed in.  when we return and they decref,
+ * __proc_free will be called */
+void proc_destroy(struct proc *p)
+{
+       uint32_t nr_cores_revoked = 0;
+       spin_lock(&sched_lock);
+       spin_lock(&p->proc_lock);
+       /* storage for pc_arr is alloced at decl, which is after grabbing the lock*/
+       uint32_t pc_arr[p->procinfo->num_vcores];
+       /* If this returns true, it means we successfully destroyed the proc */
+       if (__proc_destroy(p, pc_arr, &nr_cores_revoked)) {
+               /* Do our cleanup.  note that proc_free won't run since we have an
+                * external reference, passed in */
+               /* TODO: pull from lists (no list polling), free structs, etc. */
+
+               /* Put the cores back on the idlecore map.  For future changes, be
+                * careful with the idle_lock.  It's safe to call this here or outside
+                * the sched lock (for now). */
+               if (nr_cores_revoked) 
+                       put_idle_cores(pc_arr, nr_cores_revoked);
+       }
+       spin_unlock(&p->proc_lock);
+       spin_unlock(&sched_lock);
+}
+
 /* mgmt/LL cores should call this to schedule the calling core and give it to an
  * SCP.  will also prune the dead SCPs from the list.  hold the lock before
  * calling.  returns TRUE if it scheduled a proc. */
@@ -259,7 +288,8 @@ void poke_ksched(struct proc *p, int res_type)
 }
 
 /* Proc p just woke up (due to an event).  Our dumb ksched will just try to deal
- * with its core desires. */
+ * with its core desires. 
+ * TODO: this may get called multiple times per unblock */
 void ksched_proc_unblocked(struct proc *p)
 {
        /* TODO: this now gets called when an _S unblocks.  schedule_scp() also gets