proc_change_to_m() is now a scheduler function
authorBarret Rhoden <brho@cs.berkeley.edu>
Mon, 23 Apr 2012 23:16:30 +0000 (16:16 -0700)
committerBarret Rhoden <brho@cs.berkeley.edu>
Mon, 23 Apr 2012 23:16:30 +0000 (16:16 -0700)
Due to issues of lock ordering.  We need to atomically change process
state and tell the ksched about it.  The way to do this without
deadlocking is to grab the ksched lock first.  Ultimately, we're going
to end up tying proc and ksched code together a bit, where proc code
does the bidding of sched code.

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

index 20fe682..0d28cff 100644 (file)
@@ -72,7 +72,7 @@ void proc_run_s(struct proc *p);
 void __proc_run_m(struct proc *p);
 void proc_restartcore(void);
 bool __proc_destroy(struct proc *p, uint32_t *pc_arr, uint32_t *nr_revoked);
-void __proc_change_to_m(struct proc *p);
+int __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);
 void proc_notify(struct proc *p, uint32_t vcoreid);
index 30f86a3..2465fe4 100644 (file)
@@ -30,13 +30,13 @@ void register_proc(struct proc *p);
 /* _S is now runnable, tell the ksched to try to run it. */
 void schedule_scp(struct proc *p);
 
-/* p is now an _M.  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);
 
+/* Changes the proc from an SCP to an MCP */
+int proc_change_to_m(struct proc *p);
+
 /************** Decision making **************/
 /* Call the main scheduling algorithm.  Not clear yet if the main kernel will
  * ever call this directly. */
index f034aec..9dc7fde 100644 (file)
@@ -750,11 +750,14 @@ bool __proc_destroy(struct proc *p, uint32_t *pc_arr, uint32_t *nr_revoked)
 }
 
 /* Turns *p into an MCP.  Needs to be called from a local syscall of a RUNNING_S
- * process.  Currently, this ignores whether or not you are an _M already.  You
- * should hold the lock before calling. */
-void __proc_change_to_m(struct proc *p)
+ * process.  Returns 0 if it succeeded, an error code otherwise.  You should
+ * hold the lock before calling. */
+int __proc_change_to_m(struct proc *p)
 {
        int8_t state = 0;
+       /* in case userspace erroneously tries to change more than once */
+       if (__proc_is_mcp(p))
+               return -EINVAL;
        switch (p->state) {
                case (PROC_RUNNING_S):
                        /* issue with if we're async or not (need to preempt it)
@@ -801,13 +804,15 @@ void __proc_change_to_m(struct proc *p)
                         * it, and not clearly thinking through how this would happen.
                         * Perhaps an async call that gets serviced after you're
                         * descheduled? */
-                       panic("Not supporting RUNNABLE_S -> RUNNABLE_M yet.\n");
-                       break;
+                       warn("Not supporting RUNNABLE_S -> RUNNABLE_M yet.\n");
+                       return -EINVAL;
                case (PROC_DYING):
                        warn("Dying, core request coming from %d\n", core_id());
+                       return -EINVAL;
                default:
-                       break;
+                       return -EINVAL;
        }
+       return 0;
 }
 
 /* Old code to turn a RUNNING_M to a RUNNING_S, with the calling context
index d32ce0c..27d63b6 100644 (file)
@@ -183,18 +183,36 @@ void schedule_scp(struct proc *p)
        spin_unlock(&sched_lock);
 }
 
-/* Tells us the proc is now an mcp.  Assuming it was RUNNING before */
-/* TODO: the proc lock is currently held for sched and register */
-void register_mcp(struct proc *p)
+/* Returns 0 if it succeeded, an error code otherwise. */
+int proc_change_to_m(struct proc *p)
 {
+       int retval;
        spin_lock(&sched_lock);
-       /* For now, this should only ever be called on an unrunnable.  It's probably
-        * a bug, at this stage in development, to do o/w. */
+       /* Should only be necessary to lock around the change_to_m call.  It's
+        * definitely necessary to hold the sched lock the whole time - need to
+        * atomically change the proc's state and have the ksched take action (and
+        * not squeeze a proc_destroy in there or something). */
+       spin_lock(&p->proc_lock);
+       retval = __proc_change_to_m(p);
+       spin_unlock(&p->proc_lock);
+       if (retval) {
+               /* Failed for some reason. */
+               spin_unlock(&sched_lock);
+               return retval;
+       }
+       /* Catch user bugs */
+       if (!p->procdata->res_req[RES_CORES].amt_wanted) {
+               printk("[kernel] process needs to specify amt_wanted\n");
+               p->procdata->res_req[RES_CORES].amt_wanted = 1;
+       }
+       /* For now, this should only ever be called on an unrunnable.  It's
+        * probably a bug, at this stage in development, to do o/w. */
        remove_from_list(p, &unrunnable_scps);
        //remove_from_any_list(p);      /* ^^ instead of this */
        add_to_list(p, &all_mcps);
        spin_unlock(&sched_lock);
        //poke_ksched(p, RES_CORES);
+       return retval;
 }
 
 /* Destroys the given process.  This may be called from another process, a light
index 1dffbb7..d90cb46 100644 (file)
@@ -739,22 +739,12 @@ static int sys_halt_core(struct proc *p, unsigned int usec)
  * but that's fine thanks to the async kernel interface. */
 static int sys_change_to_m(struct proc *p)
 {
-       int retval = 0;
-       spin_lock(&p->proc_lock);
-       if (!__proc_is_mcp(p)) {
-               /* Catch user bugs */
-               if (!p->procdata->res_req[RES_CORES].amt_wanted) {
-                       printk("[kernel] process needs to specify amt_wanted\n");
-                       p->procdata->res_req[RES_CORES].amt_wanted = 1;
-               }
-               __proc_change_to_m(p);
-               /* Tell the ksched about us */
-               register_mcp(p);
-       } else {
-               set_errno(EINVAL);
+       int retval = proc_change_to_m(p);
+       /* convert the kernel error code into (-1, errno) */
+       if (retval) {
+               set_errno(-retval);
                retval = -1;
        }
-       spin_unlock(&p->proc_lock);
        return retval;
 }