proc_restartcore() only used for current_tf, etc
[akaros.git] / kern / src / process.c
index 2a9bef5..af3c7ba 100644 (file)
@@ -26,6 +26,8 @@
 #include <monitor.h>
 #include <resource.h>
 #include <elf.h>
+#include <arsc_server.h>
+#include <devfs.h>
 
 /* Process Lists */
 struct proc_list proc_runnablelist = TAILQ_HEAD_INITIALIZER(proc_runnablelist);
@@ -106,6 +108,7 @@ int __proc_set_state(struct proc *p, uint32_t state)
        uint32_t curstate = p->state;
        /* Valid transitions:
         * C   -> RBS
+        * C   -> D
         * RBS -> RGS
         * RGS -> RBS
         * RGS -> W
@@ -120,14 +123,11 @@ int __proc_set_state(struct proc *p, uint32_t state)
         * These ought to be implemented later (allowed, not thought through yet).
         * RBS -> D
         * RBM -> D
-        *
-        * This isn't allowed yet, should be later.  Is definitely causable.
-        * C   -> D
         */
        #if 1 // some sort of correctness flag
        switch (curstate) {
                case PROC_CREATED:
-                       if (state != PROC_RUNNABLE_S)
+                       if (!(state & (PROC_RUNNABLE_S | PROC_DYING)))
                                panic("Invalid State Transition! PROC_CREATED to %02x", state);
                        break;
                case PROC_RUNNABLE_S:
@@ -162,17 +162,18 @@ int __proc_set_state(struct proc *p, uint32_t state)
 }
 
 /* Returns a pointer to the proc with the given pid, or 0 if there is none.
- * Note this makes a copy of the reference stored in the hash table (which is
- * the proc existing).  Need to do this while locking the table, in case someone
- * else subsequently removes it from the table, then kref_put()s it to 0 before
- * we can get it.  Don't push the locking into the hashtable without dealing
- * with this. */
+ * This uses get_not_zero, since it is possible the refcnt is 0, which means the
+ * process is dying and we should not have the ref (and thus return 0).  We need
+ * to lock to protect us from getting p, (someone else removes and frees p),
+ * then get_not_zero() on p.
+ * Don't push the locking into the hashtable without dealing with this. */
 struct proc *pid2proc(pid_t pid)
 {
        spin_lock(&pid_hash_lock);
        struct proc *p = hashtable_search(pid_hash, (void*)pid);
        if (p)
-               kref_get(&p->kref, 1);
+               if (!kref_get_not_zero(&p->kref, 1))
+                       p = 0;
        spin_unlock(&pid_hash_lock);
        return p;
 }
@@ -199,9 +200,16 @@ void proc_init(void)
        assert(!(num_cpus % 2));
        // TODO: consider checking x86 for machines that actually hyperthread
        num_idlecores = num_cpus >> 1;
+#ifdef __CONFIG_ARSC_SERVER__
+       // Dedicate one core (core 2) to sysserver, might be able to share wit NIC
+       num_mgmtcores++;
+       assert(num_cpus >= num_mgmtcores);
+       send_kernel_message(2, (amr_t)arsc_server, 0,0,0, KMSG_ROUTINE);
+#endif
        for (int i = 0; i < num_idlecores; i++)
                idlecoremap[i] = (i * 2) + 1;
 #else
+       // __CONFIG_DISABLE_SMT__
        #ifdef __CONFIG_NETWORKING__
        num_mgmtcores++; // Next core is dedicated to the NIC
        assert(num_cpus >= num_mgmtcores);
@@ -214,10 +222,17 @@ void proc_init(void)
        send_kernel_message(num_mgmtcores-1, (amr_t)monitor, 0,0,0, KMSG_ROUTINE);
        #endif
        #endif
+#ifdef __CONFIG_ARSC_SERVER__
+       // Dedicate one core (core 2) to sysserver, might be able to share wit NIC
+       num_mgmtcores++;
+       assert(num_cpus >= num_mgmtcores);
+       send_kernel_message(num_mgmtcores-1, (amr_t)arsc_server, 0,0,0, KMSG_ROUTINE);
+#endif
        num_idlecores = num_cpus - num_mgmtcores;
        for (int i = 0; i < num_idlecores; i++)
                idlecoremap[i] = i + num_mgmtcores;
 #endif /* __CONFIG_DISABLE_SMT__ */
+
        spin_unlock(&idle_lock);
        atomic_init(&num_envs, 0);
 }
@@ -256,33 +271,25 @@ error_t proc_alloc(struct proc **pp, struct proc *parent)
 
        { INITSTRUCT(*p)
 
+       /* one reference for the proc existing, and one for the ref we pass back. */
+       kref_init(&p->kref, __proc_free, 2);
        // Setup the default map of where to get cache colors from
        p->cache_colors_map = global_cache_colors_map;
        p->next_cache_color = 0;
-
        /* Initialize the address space */
        if ((r = env_setup_vm(p)) < 0) {
                kmem_cache_free(proc_cache, p);
                return r;
        }
-
-       /* Get a pid, then store a reference in the pid_hash */
        if (!(p->pid = get_free_pid())) {
                kmem_cache_free(proc_cache, p);
                return -ENOFREEPID;
        }
-       /* one reference for the proc existing (in the hash table),
-        * and one for the ref we pass back */
-       kref_init(&p->kref, __proc_free, 2);
-       spin_lock(&pid_hash_lock);
-       hashtable_insert(pid_hash, (void*)p->pid, p);
-       spin_unlock(&pid_hash_lock);
-
        /* Set the basic status variables. */
        spinlock_init(&p->proc_lock);
        p->exitcode = 0;
        p->ppid = parent ? parent->pid : 0;
-       p->state = PROC_CREATED; // shouldn't go through state machine for init
+       p->state = PROC_CREATED; /* shouldn't go through state machine for init */
        p->env_flags = 0;
        p->env_entry = 0; // cheating.  this really gets set later
        p->procinfo->heap_bottom = (void*)UTEXT;
@@ -311,35 +318,40 @@ error_t proc_alloc(struct proc **pp, struct proc *parent)
                        SYSEVENTRINGSIZE);
 
        /* Init FS structures TODO: cleanup (might pull this out) */
-       atomic_inc(&default_ns.refcnt);
+       kref_get(&default_ns.kref, 1);
        p->ns = &default_ns;
        spinlock_init(&p->fs_env.lock);
-       p->fs_env.umask = parent ? parent->fs_env.umask : 0002;
+       p->fs_env.umask = parent ? parent->fs_env.umask : S_IWGRP | S_IWOTH;
        p->fs_env.root = p->ns->root->mnt_root;
-       atomic_inc(&p->fs_env.root->d_refcnt);
+       kref_get(&p->fs_env.root->d_kref, 1);
        p->fs_env.pwd = parent ? parent->fs_env.pwd : p->fs_env.root;
-       atomic_inc(&p->fs_env.pwd->d_refcnt);
+       kref_get(&p->fs_env.pwd->d_kref, 1);
        memset(&p->open_files, 0, sizeof(p->open_files));       /* slightly ghetto */
        spinlock_init(&p->open_files.lock);
        p->open_files.max_files = NR_OPEN_FILES_DEFAULT;
        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;
-       /* 0, 1, and 2 are reserved, but prob shouldn't do it this way */
-       p->open_files.next_fd = 3;
-       for (int i = 0; i < 3; i++)
-               SET_BITMASK_BIT(p->open_files.open_fds->fds_bits, i);
 
-       *pp = p;
        atomic_inc(&num_envs);
-
        frontend_proc_init(p);
-
        printd("[%08x] new process %08x\n", current ? current->pid : 0, p->pid);
        } // INIT_STRUCT
+       *pp = p;
        return 0;
 }
 
+/* We have a bunch of different ways to make processes.  Call this once the
+ * process is ready to be used by the rest of the system.  For now, this just
+ * means when it is ready to be named via the pidhash.  In the future, we might
+ * push setting the state to CREATED into here. */
+void __proc_ready(struct proc *p)
+{
+       spin_lock(&pid_hash_lock);
+       hashtable_insert(pid_hash, (void*)p->pid, p);
+       spin_unlock(&pid_hash_lock);
+}
+
 /* Creates a process from the specified file, argvs, and envps.  Tempted to get
  * rid of proc_alloc's style, but it is so quaint... */
 struct proc *proc_create(struct file *prog, char **argv, char **envp)
@@ -350,6 +362,11 @@ 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;
 }
 
@@ -363,17 +380,24 @@ static void __proc_free(struct kref *kref)
 
        printd("[PID %d] freeing proc: %d\n", current ? current->pid : 0, p->pid);
        // All parts of the kernel should have decref'd before __proc_free is called
-       assert(atomic_read(&p->kref.refcount) == 0);
+       assert(kref_refcnt(&p->kref) == 0);
 
-       close_all_files(&p->open_files);
+       close_all_files(&p->open_files, FALSE);
+       kref_put(&p->fs_env.root->d_kref);
+       kref_put(&p->fs_env.pwd->d_kref);
+       destroy_vmrs(p);
        frontend_proc_free(p);  /* TODO: please remove me one day */
        /* Free any colors allocated to this process */
-       if(p->cache_colors_map != global_cache_colors_map) {
-               for(int i=0; i<llc_cache->num_colors; i++)
+       if (p->cache_colors_map != global_cache_colors_map) {
+               for(int i = 0; i < llc_cache->num_colors; i++)
                        cache_color_free(llc_cache, p->cache_colors_map);
                cache_colors_map_free(p->cache_colors_map);
        }
-       /* Give our PID back */
+       /* Remove us from the pid_hash and give our PID back (in that order). */
+       spin_lock(&pid_hash_lock);
+       if (!hashtable_remove(pid_hash, (void*)p->pid))
+               panic("Proc not in the pid table in %s", __FUNCTION__);
+       spin_unlock(&pid_hash_lock);
        put_free_pid(p->pid);
        /* Flush all mapped pages in the user portion of the address space */
        env_user_mem_free(p, 0, UVPT);
@@ -398,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"
@@ -436,18 +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
@@ -503,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
@@ -527,11 +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
@@ -541,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);
 }
 
 /*
@@ -576,9 +620,8 @@ void proc_restartcore(struct proc *p, trapframe_t *tf)
 void proc_destroy(struct proc *p)
 {
        bool self_ipi_pending = FALSE;
-
+       
        spin_lock(&p->proc_lock);
-
        /* TODO: (DEATH) look at this again when we sort the __death IPI */
        if (current == p)
                self_ipi_pending = TRUE;
@@ -626,30 +669,22 @@ void proc_destroy(struct proc *p)
                        __proc_take_allcores(p, __death, (void *SNT)0, (void *SNT)0,
                                             (void *SNT)0);
                        break;
+               case PROC_CREATED:
+                       break;
                default:
                        panic("Weird state(%s) in %s()", procstate2str(p->state),
                              __FUNCTION__);
        }
        __proc_set_state(p, PROC_DYING);
-       /* This kref_put() is for the process in general (its existence in the hash
-        * table).  Note we do it after unlocking the hash table, since once it is
-        * gone, no one can get it to kref_get() it.  We also do it after unlocking,
-        * since it is possible that we are the releaser (though not when a
-        * self_ipi is pending, so only when death was remote (we're not current)).
-        *
-        * Also note that we don't give the PID back until __proc_free().  This is
-        * because not everyone is done with the process yet, although you won't
-        * find the proc in any lists, nor will it get reused anytime soon. */
-       spin_lock(&pid_hash_lock);
-       if (!hashtable_remove(pid_hash, (void*)p->pid))
-               panic("Proc not in the pid table in %s", __FUNCTION__);
-       spin_unlock(&pid_hash_lock);
+       /* This kref_put() is for the process's existence. */
+       kref_put(&p->kref);
        /* Unlock and possible decref and wait.  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);
-       kref_put(&p->kref);             /* for the hashtable ref */
+       /* at this point, we normally have one ref to be eaten in kmsg_pending and
+        * one for every 'current'.  and maybe one for a parent */
        __proc_kmsg_pending(p, self_ipi_pending);
        return;
 }
@@ -705,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
@@ -745,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,
@@ -788,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() */
@@ -1249,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__);
        }
 }
@@ -1277,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
@@ -1297,13 +1341,24 @@ void abandon_core(void)
 void __proc_tlbshootdown(struct proc *p, uintptr_t start, uintptr_t end)
 {
        uint32_t active_vcoreid = 0;
-       /* TODO: (TLB) sanity checks and rounding on the ranges */
-       for (int i = 0; i < p->procinfo->num_vcores; i++) {
-               /* find next active vcore */
-               active_vcoreid = get_busy_vcoreid(p, active_vcoreid);
-               send_kernel_message(get_pcoreid(p, active_vcoreid), __tlbshootdown,
-                                   (void*)start, (void*)end, 0, KMSG_IMMEDIATE);
-               active_vcoreid++; /* for the next loop, skip the one we just used */
+       switch (p->state) {
+               case (PROC_RUNNING_S):
+                       tlbflush();
+                       break;
+               case (PROC_RUNNING_M):
+                       /* TODO: (TLB) sanity checks and rounding on the ranges */
+                       for (int i = 0; i < p->procinfo->num_vcores; i++) {
+                               /* find next active vcore */
+                               active_vcoreid = get_busy_vcoreid(p, active_vcoreid);
+                               send_kernel_message(get_pcoreid(p, active_vcoreid),
+                                                   __tlbshootdown, (void*)start, (void*)end,
+                                                   0, KMSG_IMMEDIATE);
+                               active_vcoreid++; /* next loop, skip the one we just used */
+                       }
+                       break;
+               default:
+                       /* will probably get this when we have the short handlers */
+                       warn("Unexpected case in %s\n", __FUNCTION__);
        }
 }
 
@@ -1417,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.
@@ -1434,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
@@ -1502,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 */