Processes can yield the entire process
authorBarret Rhoden <brho@cs.berkeley.edu>
Sun, 18 Sep 2011 02:44:40 +0000 (19:44 -0700)
committerKevin Klues <klueska@cs.berkeley.edu>
Thu, 3 Nov 2011 00:36:07 +0000 (17:36 -0700)
When yielding your last vcore, you'll now transition to WAITING, and be
woken up when an event comes in.  If you ever want to wake back up,
you'll need to have at least one ev_q marked FALLBACK/INDIR, and have
that ev_q trigger.

We don't support yielding just to be nice.  If you yield, you need an
event to wake you.  Otherwise, just do your work.

This also changes the ksched to be able to handle a RUNNABLE_M, albeit
not in a perfect manner.

kern/src/process.c
kern/src/resource.c
kern/src/schedule.c

index 448e3d2..f6390fa 100644 (file)
@@ -822,12 +822,6 @@ void proc_yield(struct proc *SAFE p, bool being_nice)
                case (PROC_RUNNING_M):
                        printd("[K] Process %d (%p) is yielding on vcore %d\n", p->pid, p,
                               get_vcoreid(p, core_id()));
-                       /* TODO: (RMS) the Scheduler cannot handle the Runnable Ms (RMS), so
-                        * don't yield the last vcore. */
-                       if (p->procinfo->num_vcores == 1) {
-                               spin_unlock(&p->proc_lock);
-                               return;
-                       }
                        /* Remove from the online list, add to the yielded list, and unmap
                         * the vcore, which gives up the core. */
                        TAILQ_REMOVE(&p->online_vcs, vc, list);
@@ -852,13 +846,12 @@ void proc_yield(struct proc *SAFE p, bool being_nice)
                                p->resources[RES_CORES].amt_wanted = p->procinfo->num_vcores;
                        __seq_end_write(&p->procinfo->coremap_seqctr);
                        // add to idle list
-                       put_idle_core(core_id());
+                       put_idle_core(core_id());       /* TODO: prod the ksched? */
                        // last vcore?  then we really want 1, and to yield the gang
-                       // TODO: (RMS) will actually do this.
                        if (p->procinfo->num_vcores == 0) {
                                p->resources[RES_CORES].amt_wanted = 1;
-                               __proc_set_state(p, PROC_RUNNABLE_M);
-                               schedule_proc(p);
+                               /* wait on an event (not supporting 'being nice' for now */
+                               __proc_set_state(p, PROC_WAITING);
                        }
                        break;
                case (PROC_DYING):
index a662344..e446e9d 100644 (file)
@@ -43,8 +43,6 @@ ssize_t core_request(struct proc *p)
        bool need_to_idle = FALSE;
        bool self_ipi_pending = FALSE;
 
-       /* There are a few things broken for now if you don't have a current_tf */
-       assert(current_tf);
        spin_lock(&p->proc_lock);
        if (p->state == PROC_DYING) {
                spin_unlock(&p->proc_lock);
@@ -53,8 +51,10 @@ ssize_t core_request(struct proc *p)
        /* check to see if this is a full deallocation.  for cores, it's a
         * transition from _M to _S.  Will be issues with handling this async. */
        if (!p->resources[RES_CORES].amt_wanted) {
+               printk("[kernel] trying to transition _M -> _S (deprecated)!\n");
                assert(p->state == PROC_RUNNING_M); // TODO: (ACR) async core req
                /* save the context, to be restarted in _S mode */
+               assert(current_tf);
                p->env_tf = *current_tf;
                current_tf = 0;                 /* Make sure it isn't used in the future */
                env_push_ancillary_state(p); // TODO: (HSS)
@@ -122,6 +122,7 @@ ssize_t core_request(struct proc *p)
                                 * it in the preempt slot so that we can also save the silly
                                 * state. */
                                struct preempt_data *vcpd = &p->procdata->vcore_preempt_data[0];
+                               assert(current_tf);
                                vcpd->preempt_tf = *current_tf;
                                save_fp_state(&vcpd->preempt_anc);
                                __seq_start_write(&vcpd->preempt_tf_valid);
@@ -164,7 +165,7 @@ ssize_t core_request(struct proc *p)
                /* if there's a race on state (like DEATH), it'll get handled by
                 * proc_run or proc_destroy */
                if (p->state == PROC_RUNNABLE_M)
-                       proc_run(p);
+                       proc_run(p);    /* I dislike this - caller should run it */
                /* if we are moving to a partitionable core from a RUNNING_S on a
                 * management core, the kernel needs to do something else on this core
                 * (just like in proc_destroy).  it also needs to decref, to consume the
index fe68161..1b0cccd 100644 (file)
@@ -16,6 +16,7 @@
 #include <stdio.h>
 #include <assert.h>
 #include <atomic.h>
+#include <resource.h>
 #include <sys/queue.h>
 
 // This could be useful for making scheduling decisions.  
@@ -71,8 +72,17 @@ void schedule(void)
                TAILQ_REMOVE(&proc_runnablelist, p, proc_link);
                spin_unlock_irqsave(&runnablelist_lock);
                printd("PID of proc i'm running: %d\n", p->pid);
+               /* We can safely read is_mcp without locking (i think). */
+               if (p->is_mcp) {
+                       /* _Ms need to get some cores, which will call proc_run() internally
+                        * (for now) */
+                       if (core_request(p) <= 0)
+                               schedule_proc(p);       /* got none, put it back on the queue */
+               } else {
+                       /* _S proc, just run it */
+                       proc_run(p);
+               }
                /* proc_run will either eat the ref, or we'll decref manually. */
-               proc_run(p);
                proc_decref(p);
        } else {
                spin_unlock_irqsave(&runnablelist_lock);