proc_restartcore() only used for current_tf, etc
[akaros.git] / kern / src / process.c
index 6ff105f..af3c7ba 100644 (file)
@@ -332,10 +332,6 @@ error_t proc_alloc(struct proc **pp, struct proc *parent)
        p->open_files.max_fdset = NR_FILE_DESC_DEFAULT;
        p->open_files.fd = p->open_files.fd_array;
        p->open_files.open_fds = (struct fd_set*)&p->open_files.open_fds_init;
-       /* Connect to stdin, stdout, stderr */
-       assert(insert_file(&p->open_files, dev_stdin) == 0);
-       assert(insert_file(&p->open_files, dev_stdout) == 1);
-       assert(insert_file(&p->open_files, dev_stderr) == 2);
 
        atomic_inc(&num_envs);
        frontend_proc_init(p);
@@ -366,6 +362,10 @@ struct proc *proc_create(struct file *prog, char **argv, char **envp)
                panic("proc_create: %e", r);    /* one of 3 quaint usages of %e */
        procinfo_pack_args(p->procinfo, argv, envp);
        assert(load_elf(p, prog) == 0);
+       /* Connect to stdin, stdout, stderr */
+       assert(insert_file(&p->open_files, dev_stdin,  0) == 0);
+       assert(insert_file(&p->open_files, dev_stdout, 0) == 1);
+       assert(insert_file(&p->open_files, dev_stderr, 0) == 2);
        __proc_ready(p);
        return p;
 }
@@ -422,6 +422,28 @@ bool proc_controls(struct proc *actor, struct proc *target)
        return ((actor == target) || (target->ppid == actor->pid));
 }
 
+/* Helper, makes p the 'current' process, dropping the old current/cr3.  Don't
+ * incref - this assumes the passed in reference already counted 'current'. */
+static void __set_proc_current(struct proc *p)
+{
+       /* We use the pcpui to access 'current' to cut down on the core_id() calls,
+        * though who know how expensive/painful they are. */
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       /* If the process wasn't here, then we need to load its address space. */
+       if (p != pcpui->cur_proc) {
+               /* Do not incref here.  We were given the reference to current,
+                * pre-upped. */
+               lcr3(p->env_cr3);
+               /* This is "leaving the process context" of the previous proc.  The
+                * previous lcr3 unloaded the previous proc's context.  This should
+                * rarely happen, since we usually proactively leave process context,
+                * but this is the fallback. */
+               if (pcpui->cur_proc)
+                       kref_put(&pcpui->cur_proc->kref);
+               pcpui->cur_proc = p;
+       }
+}
+
 /* Dispatches a process to run, either on the current core in the case of a
  * RUNNABLE_S, or on its partition in the case of a RUNNABLE_M.  This should
  * never be called to "restart" a core.  This expects that the "instructions"
@@ -460,19 +482,19 @@ void proc_run(struct proc *p)
                        p->procinfo->num_vcores = 0;
                        __map_vcore(p, 0, core_id()); // sort of.  this needs work.
                        __seq_end_write(&p->procinfo->coremap_seqctr);
-                       /* __proc_startcore assumes the reference we give it is for current.
-                        * Decref if current is already properly set. */
+                       /* __set_proc_current assumes the reference we give it is for
+                        * current.  Decref if current is already properly set, otherwise
+                        * ensure current is set. */
                        if (p == current)
                                kref_put(&p->kref);
-                       /* We don't want to process routine messages here, since it's a bit
-                        * different than when we perform a syscall in this process's
-                        * context.  We want interrupts disabled so that if there was a
-                        * routine message on the way, we'll get the interrupt once we pop
-                        * back to userspace.  */
+                       else
+                               __set_proc_current(p);
+                       /* We restartcore, instead of startcore, since startcore is a bit
+                        * lower level and we want a chance to process kmsgs before starting
+                        * the process. */
                        spin_unlock(&p->proc_lock);
-                       disable_irq();
-
-                       __proc_startcore(p, &p->env_tf);
+                       current_tf = &p->env_tf;
+                       proc_restartcore();
                        break;
                case (PROC_RUNNABLE_M):
                        /* vcoremap[i] holds the coreid of the physical core allocated to
@@ -528,19 +550,7 @@ void proc_run(struct proc *p)
 static void __proc_startcore(struct proc *p, trapframe_t *tf)
 {
        assert(!irq_is_enabled());
-       /* If the process wasn't here, then we need to load its address space. */
-       if (p != current) {
-               /* Do not incref here.  We were given the reference to current,
-                * pre-upped. */
-               lcr3(p->env_cr3);
-               /* This is "leaving the process context" of the previous proc.  The
-                * previous lcr3 unloaded the previous proc's context.  This should
-                * rarely happen, since we usually proactively leave process context,
-                * but is the fallback. */
-               if (current)
-                       kref_put(&current->kref);
-               set_current_proc(p);
-       }
+       __set_proc_current(p);
        /* need to load our silly state, preferably somewhere other than here so we
         * can avoid the case where the context was just running here.  it's not
         * sufficient to do it in the "new process" if-block above (could be things
@@ -552,12 +562,13 @@ static void __proc_startcore(struct proc *p, trapframe_t *tf)
         * __startcore.  */
        if (p->state == PROC_RUNNING_S)
                env_pop_ancillary_state(p);
-       
+       /* Clear the current_tf, since it is no longer used */
+       current_tf = 0;
        env_pop_tf(tf);
 }
 
-/* Restarts the given context (trapframe) of process p on the core this code
- * executes on.  Calls an internal function to do the work.
+/* Restarts/runs the current_tf, which must be for the current process, on the
+ * core this code executes on.  Calls an internal function to do the work.
  *
  * In case there are pending routine messages, like __death, __preempt, or
  * __notify, we need to run them.  Alternatively, if there are any, we could
@@ -567,16 +578,23 @@ static void __proc_startcore(struct proc *p, trapframe_t *tf)
  * Refcnting: this will not return, and it assumes that you've accounted for
  * your reference as if it was the ref for "current" (which is what happens when
  * returning from local traps and such. */
-void proc_restartcore(struct proc *p, trapframe_t *tf)
+void proc_restartcore(void)
 {
-       // TODO: proc_restartcore shouldn't ever be called with tf != current_tf,
-       // so the parameter should probably be removed outright.
-       assert(current_tf == tf);
-
+       struct per_cpu_info *pcpui = &per_cpu_info[core_id()];
+       /* If there is no cur_tf, it is because the old one was already restarted
+        * (and we weren't interrupting another one to finish).  In which case, we
+        * should just smp_idle() */
+       if (!pcpui->cur_tf) {
+               assert(!current);       /* might be wrong, but i want to know if it is */
+               smp_idle();
+       }
+       /* TODO: this is where we can decide to smp_idle() if there is no cur_tf */
        /* Need ints disabled when we return from processing (race) */
        disable_irq();
-       process_routine_kmsg();
-       __proc_startcore(p, tf);
+       /* Need to be current (set by the caller), in case a kmsg is there that
+        * tries to clobber us. */
+       process_routine_kmsg(pcpui->cur_tf);
+       __proc_startcore(pcpui->cur_proc, pcpui->cur_tf);
 }
 
 /*
@@ -722,6 +740,16 @@ static uint32_t get_pcoreid(struct proc *p, uint32_t vcoreid)
        return p->procinfo->vcoremap[vcoreid].pcoreid;
 }
 
+/* Helper function: yields / wraps up current_tf and schedules the _S */
+void __proc_yield_s(struct proc *p, struct trapframe *tf)
+{
+       assert(p->state == PROC_RUNNING_S);
+       p->env_tf= *tf;
+       env_push_ancillary_state(p);                    /* TODO: (HSS) */
+       __proc_set_state(p, PROC_RUNNABLE_S);
+       schedule_proc(p);
+}
+
 /* Yields the calling core.  Must be called locally (not async) for now.
  * - If RUNNING_S, you just give up your time slice and will eventually return.
  * - If RUNNING_M, you give up the current vcore (which never returns), and
@@ -762,10 +790,7 @@ void proc_yield(struct proc *SAFE p, bool being_nice)
 
        switch (p->state) {
                case (PROC_RUNNING_S):
-                       p->env_tf= *current_tf;
-                       env_push_ancillary_state(p); // TODO: (HSS)
-                       __proc_set_state(p, PROC_RUNNABLE_S);
-                       schedule_proc(p);
+                       __proc_yield_s(p, current_tf);  /* current_tf 0'd in abandon core */
                        break;
                case (PROC_RUNNING_M):
                        printd("[K] Process %d (%p) is yielding on vcore %d\n", p->pid, p,
@@ -805,6 +830,7 @@ void proc_yield(struct proc *SAFE p, bool being_nice)
        /* Clean up the core and idle.  For mgmt cores, they will ultimately call
         * manager, which will call schedule() and will repick the yielding proc. */
        abandon_core();
+       smp_idle();
 }
 
 /* If you expect to notify yourself, cleanup state and process_routine_kmsg() */
@@ -1266,7 +1292,7 @@ void __proc_kmsg_pending(struct proc *p, bool ipi_pending)
 {
        if (ipi_pending) {
                kref_put(&p->kref);
-               process_routine_kmsg();
+               process_routine_kmsg(0);
                panic("stack-killing kmsg not found in %s!!!", __FUNCTION__);
        }
 }
@@ -1294,9 +1320,10 @@ void __unmap_vcore(struct proc *p, uint32_t vcoreid)
  * process's context. */
 void abandon_core(void)
 {
-       if (current)
+       if (current) {
+               current_tf = 0;
                __abandon_core();
-       smp_idle();
+       }
 }
 
 /* Will send a TLB shootdown message to every vcore in the main address space
@@ -1445,6 +1472,7 @@ void __preempt(trapframe_t *tf, uint32_t srcid, void *a0, void *a1, void *a2)
        __seq_start_write(&vcpd->preempt_tf_valid);
        __unmap_vcore(p, vcoreid);
        abandon_core();
+       smp_idle();
 }
 
 /* Kernel message handler to clean up the core when a process is dying.
@@ -1462,6 +1490,7 @@ void __death(trapframe_t *tf, uint32_t srcid, void *SNT a0, void *SNT a1,
                __unmap_vcore(current, vcoreid);
        }
        abandon_core();
+       smp_idle();
 }
 
 /* Kernel message handler, usually sent IMMEDIATE, to shoot down virtual
@@ -1530,9 +1559,10 @@ void print_proc_info(pid_t pid)
        struct files_struct *files = &p->open_files;
        spin_lock(&files->lock);
        for (int i = 0; i < files->max_files; i++)
-               if (files->fd_array[i]) {
+               if (files->fd_array[i].fd_file) {
                        printk("\tFD: %02d, File: %08p, File name: %s\n", i,
-                              files->fd_array[i], file_name(files->fd_array[i]));
+                              files->fd_array[i].fd_file,
+                              file_name(files->fd_array[i].fd_file));
                }
        spin_unlock(&files->lock);
        /* No one cares, and it clutters the terminal */